Commit 30b9d9e6 authored by Martin Sefcik's avatar Martin Sefcik

Rewritten tests

parent 07bee06b
...@@ -187,9 +187,6 @@ func (c *Client) SetBaseURL(urlStr string) error { ...@@ -187,9 +187,6 @@ func (c *Client) SetBaseURL(urlStr string) error {
return err return err
} }
// Set the encoded opaque data
c.baseURL.Opaque = c.baseURL.Path
return nil return nil
} }
...@@ -199,8 +196,12 @@ func (c *Client) SetBaseURL(urlStr string) error { ...@@ -199,8 +196,12 @@ func (c *Client) SetBaseURL(urlStr string) error {
// specified, the value pointed to by body is JSON encoded and included as the // specified, the value pointed to by body is JSON encoded and included as the
// request body. // request body.
func (c *Client) NewRequest(method, path string, opt interface{}) (*http.Request, error) { func (c *Client) NewRequest(method, path string, opt interface{}) (*http.Request, error) {
u := *c.baseURL rel, err := url.Parse(path)
u.Opaque += path if err != nil {
return nil, err
}
u := *c.baseURL.ResolveReference(rel)
q, err := query.Values(opt) q, err := query.Values(opt)
if err != nil { if err != nil {
...@@ -351,11 +352,9 @@ type ErrorResponse struct { ...@@ -351,11 +352,9 @@ type ErrorResponse struct {
} }
func (r *ErrorResponse) Error() string { func (r *ErrorResponse) Error() string {
path, _ := url.QueryUnescape(r.Response.Request.URL.Opaque) return fmt.Sprintf("%v %v: %d %v %+v",
ru := fmt.Sprintf("%s://%s%s", r.Response.Request.URL.Scheme, r.Response.Request.URL.Host, path) r.Response.Request.Method, r.Response.Request.URL,
r.Response.StatusCode, r.Message, r.Errors)
return fmt.Sprintf("%v %s: %d %v %+v",
r.Response.Request.Method, ru, r.Response.StatusCode, r.Message, r.Errors)
} }
// An Error reports more details on an individual error in an ErrorResponse. // An Error reports more details on an individual error in an ErrorResponse.
......
package gitlab
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"strings"
"testing"
)
var (
// mux is the HTTP request multiplexer used with the test server.
mux *http.ServeMux
// client is the Gitlab client being tested.
client *Client
// server is a test HTTP server used to provide mock API responses.
server *httptest.Server
)
// setup sets up a test HTTP server along with a gitlab.Client that is
// configured to talk to that test server. Tests should register handlers on
// mux which provide mock responses for the API method being tested.
func setup() {
// test server
mux = http.NewServeMux()
server = httptest.NewServer(mux)
// gitlab client configured to use test server
client = NewClient(nil, "")
client.SetBaseURL(server.URL)
}
// teardown closes the test HTTP server.
func teardown() {
server.Close()
}
func testMethod(t *testing.T, r *http.Request, want string) {
if got := r.Method; got != want {
t.Errorf("Request method: %v, want %v", got, want)
}
}
type values map[string]string
func testFormValues(t *testing.T, r *http.Request, values values) {
want := url.Values{}
for k, v := range values {
want.Add(k, v)
}
r.ParseForm()
if got := r.Form; !reflect.DeepEqual(got, want) {
t.Errorf("Request parameters: %v, want %v", got, want)
}
}
func testHeader(t *testing.T, r *http.Request, header string, want string) {
if got := r.Header.Get(header); got != want {
t.Errorf("Header.Get(%q) returned %s, want %s", header, got, want)
}
}
func testBody(t *testing.T, r *http.Request, want string) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
t.Errorf("Error reading request body: %v", err)
}
if got := string(b); got != want {
t.Errorf("request Body is %s, want %s", got, want)
}
}
func responseBody(w http.ResponseWriter, filename string) {
body, _ := ioutil.ReadFile(filename)
w.Write([]byte(body))
}
func TestNewClient(t *testing.T) {
c := NewClient(nil, "")
if got, want := c.BaseURL().String(), defaultBaseURL; got != want {
t.Errorf("NewClient BaseURL is %v, want %v", got, want)
}
if got, want := c.UserAgent, userAgent; got != want {
t.Errorf("NewClient UserAgent is %v, want %v", got, want)
}
}
func TestCheckResponse(t *testing.T) {
res := &http.Response{
Request: &http.Request{},
StatusCode: http.StatusBadRequest,
Body: ioutil.NopCloser(strings.NewReader(`{"message":"m",
"errors": [{"resource": "r", "field": "f", "code": "c"}]}`)),
}
err := CheckResponse(res).(*ErrorResponse)
if err == nil {
t.Errorf("Expected error response.")
}
want := &ErrorResponse{
Response: res,
Message: "m",
Errors: []Error{{Resource: "r", Field: "f", Code: "c"}},
}
if !reflect.DeepEqual(err, want) {
t.Errorf("Error = %#v, want %#v", err, want)
}
}
\ No newline at end of file
package gitlab
import (
"io/ioutil"
"net/http"
"net/http/httptest"
)
func Stub(filename string) (*httptest.Server, *Client) {
stub, _ := ioutil.ReadFile(filename)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(stub))
}))
client := NewClient(nil, "")
client.SetBaseURL(ts.URL)
return ts, client
}
...@@ -34,38 +34,56 @@ type ProjectsService struct { ...@@ -34,38 +34,56 @@ type ProjectsService struct {
// //
// GitLab API docs: http://doc.gitlab.com/ce/api/projects.html // GitLab API docs: http://doc.gitlab.com/ce/api/projects.html
type Project struct { type Project struct {
ID int `json:"id"` ID *int `json:"id"`
Description interface{} `json:"description"` Description *string `json:"description"`
DefaultBranch string `json:"default_branch"` DefaultBranch *string `json:"default_branch"`
Public bool `json:"public"` Public *bool `json:"public"`
VisibilityLevel VisibilityLevel `json:"visibility_level"` VisibilityLevel *VisibilityLevel `json:"visibility_level"`
SSHURLToRepo string `json:"ssh_url_to_repo"` SSHURLToRepo *string `json:"ssh_url_to_repo"`
HTTPURLToRepo string `json:"http_url_to_repo"` HTTPURLToRepo *string `json:"http_url_to_repo"`
WebURL string `json:"web_url"` WebURL *string `json:"web_url"`
TagList []string `json:"tag_list"` TagList *[]string `json:"tag_list"`
Owner *User `json:"owner"` Owner *User `json:"owner"`
Name string `json:"name"` Name *string `json:"name"`
NameWithNamespace string `json:"name_with_namespace"` NameWithNamespace *string `json:"name_with_namespace"`
Path string `json:"path"` Path *string `json:"path"`
PathWithNamespace string `json:"path_with_namespace"` PathWithNamespace *string `json:"path_with_namespace"`
IssuesEnabled bool `json:"issues_enabled"` IssuesEnabled *bool `json:"issues_enabled"`
MergeRequestsEnabled bool `json:"merge_requests_enabled"` MergeRequestsEnabled *bool `json:"merge_requests_enabled"`
WikiEnabled bool `json:"wiki_enabled"` WikiEnabled *bool `json:"wiki_enabled"`
SnippetsEnabled bool `json:"snippets_enabled"` SnippetsEnabled *bool `json:"snippets_enabled"`
CreatedAt time.Time `json:"created_at"` CreatedAt *time.Time `json:"created_at,omitempty"`
LastActivityAt time.Time `json:"last_activity_at"` LastActivityAt *time.Time `json:"last_activity_at,omitempty"`
CreatorID int `json:"creator_id"` CreatorID *int `json:"creator_id"`
Namespace struct { Namespace *ProjectNamespace `json:"namespace"`
CreatedAt time.Time `json:"created_at"` Archived *bool `json:"archived"`
Description string `json:"description"` AvatarURL *string `json:"avatar_url"`
ID int `json:"id"` Permissions *Permissions `json:"permissions"`
Name string `json:"name"` }
OwnerID int `json:"owner_id"`
Path string `json:"path"` type ProjectNamespace struct {
UpdatedAt time.Time `json:"updated_at"` CreatedAt *time.Time `json:"created_at"`
} `json:"namespace"` Description *string `json:"description"`
Archived bool `json:"archived"` ID *int `json:"id"`
AvatarURL string `json:"avatar_url"` Name *string `json:"name"`
OwnerID *int `json:"owner_id"`
Path *string `json:"path"`
UpdatedAt *time.Time `json:"updated_at"`
}
type Permissions struct {
ProjectAccess *ProjectAccess `json:"project_access"`
GroupAccess *GroupAccess `json:"group_access"`
}
type ProjectAccess struct {
AccessLevel AccessLevel `json:"access_level"`
NotificationLevel NotificationLevel `json:"notification_level"`
}
type GroupAccess struct {
AccessLevel AccessLevel `json:"access_level"`
NotificationLevel NotificationLevel `json:"notification_level"`
} }
func (s Project) String() string { func (s Project) String() string {
...@@ -142,36 +160,12 @@ func (s *ProjectsService) ListAllProjects(opt *ListProjectsOptions) ([]*Project, ...@@ -142,36 +160,12 @@ func (s *ProjectsService) ListAllProjects(opt *ListProjectsOptions) ([]*Project,
return p, resp, err return p, resp, err
} }
// ProjectWithAccess represents a GitLab project with permissions attributes.
//
// GitLab API docs:
// http://doc.gitlab.com/ce/api/projects.html#get-single-project
type ProjectWithAccess struct {
Project
Permissions *Permissions `json:"permissions"`
}
type Permissions struct {
ProjectAccess *ProjectAccess `json:"project_access"`
GroupAccess *GroupAccess `json:"group_access"`
}
type ProjectAccess struct {
AccessLevel AccessLevel `json:"access_level"`
NotificationLevel NotificationLevel `json:"notification_level"`
}
type GroupAccess struct {
AccessLevel AccessLevel `json:"access_level"`
NotificationLevel NotificationLevel `json:"notification_level"`
}
// GetProject gets a specific project, identified by project ID or // GetProject gets a specific project, identified by project ID or
// NAMESPACE/PROJECT_NAME, which is owned by the authenticated user. // NAMESPACE/PROJECT_NAME, which is owned by the authenticated user.
// //
// GitLab API docs: // GitLab API docs:
// http://doc.gitlab.com/ce/api/projects.html#get-single-project // http://doc.gitlab.com/ce/api/projects.html#get-single-project
func (s *ProjectsService) GetProject(pid interface{}) (*ProjectWithAccess, *Response, error) { func (s *ProjectsService) GetProject(pid interface{}) (*Project, *Response, error) {
project, err := parseID(pid) project, err := parseID(pid)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
...@@ -183,7 +177,7 @@ func (s *ProjectsService) GetProject(pid interface{}) (*ProjectWithAccess, *Resp ...@@ -183,7 +177,7 @@ func (s *ProjectsService) GetProject(pid interface{}) (*ProjectWithAccess, *Resp
return nil, nil, err return nil, nil, err
} }
p := new(ProjectWithAccess) p := new(Project)
resp, err := s.client.Do(req, p) resp, err := s.client.Do(req, p)
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
......
package gitlab package gitlab
import ( import (
"fmt"
"net/http"
"reflect"
"testing" "testing"
) )
func TestListAllProjects(t *testing.T) { func TestListProjects(t *testing.T) {
ts, client := Stub("stubs/projects/index.json") setup()
defer ts.Close() defer teardown()
opt := &ListProjectsOptions{} mux.HandleFunc("/projects", func(w http.ResponseWriter, r *http.Request) {
projects, _, err := client.Projects.ListAllProjects(opt) testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
"per_page": "3",
"archived": "true",
"order_by": "name",
"sort": "asc",
"search": "query",
"ci_enabled_first": "true",
})
fmt.Fprint(w, `[{"id":1},{"id":2}]`)
})
opt := &ListProjectsOptions{ListOptions{2, 3}, true, "name", "asc", "query", true}
projects, _, err := client.Projects.ListProjects(opt)
if err != nil { if err != nil {
t.Fatalf("Expected error nil, got: %v", err) t.Errorf("Projects.ListProjects returned error: %v", err)
} }
count := len(projects) want := []*Project{{ID: Int(1)},{ID: Int(2)}}
if count != 2 { if !reflect.DeepEqual(want, projects) {
t.Errorf("Expected number of projects %q, got %q", 2, count) t.Errorf("Projects.ListProjects returned %+v, want %+v", projects, want)
} }
if projects[0].Name != "project" { }
t.Errorf("Expected project name %q, got %q", "project", projects[0].Name)
func TestListOwnedProjects(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/projects/owned", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
"per_page": "3",
"archived": "true",
"order_by": "name",
"sort": "asc",
"search": "query",
"ci_enabled_first": "true",
})
fmt.Fprint(w, `[{"id":1},{"id":2}]`)
})
opt := &ListProjectsOptions{ListOptions{2, 3}, true, "name", "asc", "query", true}
projects, _, err := client.Projects.ListOwnedProjects(opt)
if err != nil {
t.Errorf("Projects.ListOwnedProjects returned error: %v", err)
} }
if projects[1].Name != "project2" {
t.Errorf("Expected project name %q, got %q", "project2", projects[1].Name) want := []*Project{{ID: Int(1)},{ID: Int(2)}}
if !reflect.DeepEqual(want, projects) {
t.Errorf("Projects.ListOwnedProjects returned %+v, want %+v", projects, want)
}
}
func TestListAllProjects(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/projects/all", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
"per_page": "3",
"archived": "true",
"order_by": "name",
"sort": "asc",
"search": "query",
"ci_enabled_first": "true",
})
fmt.Fprint(w, `[{"id":1},{"id":2}]`)
})
opt := &ListProjectsOptions{ListOptions{2, 3}, true, "name", "asc", "query", true}
projects, _, err := client.Projects.ListAllProjects(opt)
if err != nil {
t.Errorf("Projects.ListAllProjects returned error: %v", err)
}
want := []*Project{{ID: Int(1)},{ID: Int(2)}}
if !reflect.DeepEqual(want, projects) {
t.Errorf("Projects.ListAllProjects returned %+v, want %+v", projects, want)
} }
} }
func TestGetProject(t *testing.T) { func TestGetProject(t *testing.T) {
ts, client := Stub("stubs/projects/show.json") setup()
defer ts.Close() defer teardown()
mux.HandleFunc("/projects/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id":1}`)
})
want := &Project{ID: Int(1)}
project, _, err := client.Projects.GetProject(1) project, _, err := client.Projects.GetProject(1)
if err != nil { if err != nil {
t.Fatalf("Expected error nil, got: %v", err) t.Fatalf("Projects.GetProject returns an error: %v", err)
} }
if project.Name != "project" { if !reflect.DeepEqual(want, project) {
t.Errorf("Expected project name %q, got %q", "project", project.Name) t.Errorf("Projects.GetProject returned %+v, want %+v", project, want)
}
if project.Namespace.Name != "group" {
t.Errorf("Expected namespace name %q, got %q", "group", project.Namespace.Name)
} }
if project.Permissions.ProjectAccess.AccessLevel != MasterPermissions { }
t.Errorf("Expected project access level %q, got %q", MasterPermissions, project.Permissions.ProjectAccess.AccessLevel)
func TestSearchProjects(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/projects/search/query", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "2",
"per_page": "3",
"order_by": "name",
"sort": "asc",
})
fmt.Fprint(w, `[{"id":1},{"id":2}]`)
})
opt := &SearchProjectsOptions{ListOptions{2, 3}, "name", "asc"}
projects, _, err := client.Projects.SearchProjects("query", opt)
if err != nil {
t.Errorf("Projects.SearchProjects returned error: %v", err)
} }
if project.Permissions.GroupAccess != nil {
t.Errorf("Expected project group access nil, got %q", project.Permissions.GroupAccess) want := []*Project{{ID: Int(1)},{ID: Int(2)}}
if !reflect.DeepEqual(want, projects) {
t.Errorf("Projects.SearchProjects returned %+v, want %+v", projects, want)
} }
} }
func TestCreateProject(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/projects", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
testFormValues(t, r, values{
"name": "n",
})
fmt.Fprint(w, `{"id":1}`)
})
opt := &CreateProjectOptions{Name: "n"}
project, _, err := client.Projects.CreateProject(opt)
if err != nil {
t.Errorf("Projects.CreateProject returned error: %v", err)
}
want := &Project{ID: Int(1)}
if !reflect.DeepEqual(want, project) {
t.Errorf("Projects.CreateProject returned %+v, want %+v", project, want)
}
}
\ No newline at end of file
[
{
"id": 12,
"description": "",
"default_branch": "master",
"tag_list": [],
"public": false,
"archived": false,
"visibility_level": 0,
"ssh_url_to_repo": "git@gitlab.example.com:group/project",
"http_url_to_repo": "https://gitlab.example.com/group/project.git",
"web_url": "https://gitlab.example.com/group/project",
"name": "project",
"name_with_namespace": "group / project",
"path": "project",
"path_with_namespace": "group/project",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": false,
"snippets_enabled": false,
"created_at": "2015-10-26T14:32:44.103+01:00",
"last_activity_at": "2015-11-01T22:07:47.456+01:00",
"creator_id": 1,
"namespace": {
"id": 7,
"name": "group",
"path": "group",
"owner_id": null,
"created_at": "2015-10-26T13:36:40.147+01:00",
"updated_at": "2015-10-27T08:57:55.199+01:00",
"description": "group desc",
"avatar": {
"url": "/uploads/group/avatar/7/group-logo.png"
}
},
"avatar_url": "https://gitlab.example.com/uploads/project/avatar/12/group-logo.png",
"star_count": 0,
"forks_count": 0
},
{
"id": 11,
"description": "",
"default_branch": "master",
"tag_list": [],
"public": false,
"archived": false,
"visibility_level": 0,
"ssh_url_to_repo": "git@gitlab.example.com:johndoe/project2.git",
"http_url_to_repo": "https://gitlab.example.com/johndoe/project2.git",
"web_url": "https://gitlab.example.com/johndoe/project2",
"owner": {
"name": "John Doe",
"username": "johndoe",
"id": 1,
"state": "active",
"avatar_url": "https://secure.gravatar.com/avatar/123",
"web_url": "https://gitlab.example.com/u/johndoe"
},
"name": "project2",
"name_with_namespace": "John Doe / project2",
"path": "project2",
"path_with_namespace": "johndoe/project2",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"snippets_enabled": true,
"created_at": "2015-03-18T19:33:20.166+01:00",
"last_activity_at": "2015-11-01T19:48:32.793+01:00",
"creator_id": 1,
"namespace": {
"id": 1,
"name": "John Doe",
"path": "johndoe",
"owner_id": 1,
"created_at": "2014-01-05T22:01:51.000+01:00",
"updated_at": "2014-01-05T22:51:08.000+01:00",
"description": "",
"avatar": null
},
"avatar_url": null,
"star_count": 0,
"forks_count": 0
}
]
{
"id": 11,
"description": "",
"default_branch": "master",
"tag_list": [],
"public": false,
"archived": false,
"visibility_level": 0,
"ssh_url_to_repo": "git@gitlab.example.com:group/project.git",
"http_url_to_repo": "https://gitlab.example.com/group/project.git",
"web_url": "https://gitlab.example.com/group/project",
"owner": {
"name": "John Doe",
"username": "johndoe",
"id": 1,
"state": "active",
"avatar_url": "https://secure.gravatar.com/avatar/123",
"web_url": "https://gitlab.example.com/u/johndoe"
},
"name": "project",
"name_with_namespace": "Group / project",
"path": "project",
"path_with_namespace": "group/project",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"snippets_enabled": true,
"created_at": "2015-03-18T19:33:20.166+01:00",
"last_activity_at": "2015-11-01T19:48:32.793+01:00",
"creator_id": 1,
"namespace": {
"id": 1,
"name": "group",
"path": "group",
"owner_id": 1,
"created_at": "2014-01-05T22:01:51.000+01:00",
"updated_at": "2014-01-05T22:51:08.000+01:00",
"description": "",
"avatar": null
},
"avatar_url": null,
"star_count": 0,
"forks_count": 0,
"permissions": {
"project_access": {
"access_level": 40,
"notification_level": 3
},
"group_access": null
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment