Skip to content

Commit dc67e9b

Browse files
authored
Merge pull request #29 from ActiveState/master
Added tests endpoint and added TriggerInfo to Builds
2 parents 377e9ee + 339cc80 commit dc67e9b

File tree

4 files changed

+373
-0
lines changed

4 files changed

+373
-0
lines changed

azuredevops/azuredevops.go

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type Client struct {
3838
Iterations *IterationsService
3939
PullRequests *PullRequestsService
4040
Teams *TeamsService
41+
Tests *TestsService
4142
WorkItems *WorkItemsService
4243
}
4344

@@ -59,6 +60,7 @@ func NewClient(account string, project string, token string) *Client {
5960
c.PullRequests = &PullRequestsService{client: c}
6061
c.WorkItems = &WorkItemsService{client: c}
6162
c.Teams = &TeamsService{client: c}
63+
c.Tests = &TestsService{client: c}
6264
c.DeliveryPlans = &DeliveryPlansService{client: c}
6365

6466
return c

azuredevops/builds.go

+5
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ type Build struct {
8888
TriggerBuild *Build `json:"triggeredByBuild,omitempty"`
8989
URI string `json:"uri,omitempty"`
9090
URL string `json:"url,omitempty"`
91+
TriggerInfo struct {
92+
CiSourceBranch string `json:"ci.sourceBranch"`
93+
CiSourceSha string `json:"ci.sourceSha"`
94+
CiMessage string `json:"ci.message"`
95+
} `json:"triggerInfo"`
9196
}
9297

9398
// BuildListOrder is enum type for build list order

azuredevops/tests.go

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package azuredevops
2+
3+
import (
4+
"fmt"
5+
"time"
6+
)
7+
8+
// TestsService handles communication with the Tests methods on the API
9+
// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/test
10+
type TestsService struct {
11+
client *Client
12+
}
13+
14+
// TestListResponse is the wrapper around the main response for the List of Tests
15+
type TestListResponse struct {
16+
Tests []Test `json:"value"`
17+
}
18+
19+
// Test represents a test
20+
type Test struct {
21+
ID int `json:"id"`
22+
Name string `json:"name"`
23+
URL string `json:"url"`
24+
IsAutomated bool `json:"isAutomated"`
25+
Iteration string `json:"iteration"`
26+
Owner *struct {
27+
ID string `json:"id"`
28+
DisplayName string `json:"displayName"`
29+
} `json:"owner,omitempty"`
30+
StartedDate string `json:"startedDate"`
31+
CompletedDate string `json:"completedDate"`
32+
State string `json:"state"`
33+
Plan *struct {
34+
ID string `json:"id"`
35+
} `json:"plan,omitempty"`
36+
Revision int `json:"revision"`
37+
}
38+
39+
// TestsListOptions describes what the request to the API should look like
40+
type TestsListOptions struct {
41+
Count int `url:"$top,omitempty"`
42+
BuildURI string `url:"buildUri,omitempty"`
43+
}
44+
45+
// List returns list of the tests
46+
// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/test/runs/list
47+
func (s *TestsService) List(opts *TestsListOptions) ([]Test, error) {
48+
URL := fmt.Sprintf("_apis/test/runs?api-version=4.1")
49+
URL, err := addOptions(URL, opts)
50+
51+
request, err := s.client.NewRequest("GET", URL, nil)
52+
if err != nil {
53+
return nil, err
54+
}
55+
var response TestListResponse
56+
_, err = s.client.Execute(request, &response)
57+
58+
return response.Tests, err
59+
}
60+
61+
// TestResultsListResponse is the wrapper around the main response for the List of Tests
62+
type TestResultsListResponse struct {
63+
Results []TestResult `json:"value"`
64+
}
65+
66+
// TestResult represents a test result
67+
type TestResult struct {
68+
ID int `json:"id"`
69+
Project struct {
70+
ID string `json:"id"`
71+
Name string `json:"name"`
72+
URL string `json:"url"`
73+
} `json:"project"`
74+
StartedDate time.Time `json:"startedDate"`
75+
CompletedDate time.Time `json:"completedDate"`
76+
DurationInMs float64 `json:"durationInMs"`
77+
Outcome string `json:"outcome"`
78+
Revision int `json:"revision"`
79+
RunBy struct {
80+
ID string `json:"id"`
81+
DisplayName string `json:"displayName"`
82+
UniqueName string `json:"uniqueName"`
83+
URL string `json:"url"`
84+
ImageURL string `json:"imageUrl"`
85+
} `json:"runBy"`
86+
State string `json:"state"`
87+
TestCase struct {
88+
ID string `json:"id"`
89+
Name string `json:"name"`
90+
} `json:"testCase"`
91+
TestRun struct {
92+
ID string `json:"id"`
93+
Name string `json:"name"`
94+
URL string `json:"url"`
95+
} `json:"testRun"`
96+
LastUpdatedDate time.Time `json:"lastUpdatedDate"`
97+
LastUpdatedBy struct {
98+
ID string `json:"id"`
99+
DisplayName string `json:"displayName"`
100+
UniqueName string `json:"uniqueName"`
101+
URL string `json:"url"`
102+
ImageURL string `json:"imageUrl"`
103+
} `json:"lastUpdatedBy"`
104+
Priority int `json:"priority"`
105+
ComputerName string `json:"computerName"`
106+
Build struct {
107+
ID string `json:"id"`
108+
Name string `json:"name"`
109+
URL string `json:"url"`
110+
} `json:"build"`
111+
CreatedDate time.Time `json:"createdDate"`
112+
URL string `json:"url"`
113+
FailureType string `json:"failureType"`
114+
AutomatedTestStorage string `json:"automatedTestStorage"`
115+
AutomatedTestType string `json:"automatedTestType"`
116+
AutomatedTestTypeID string `json:"automatedTestTypeId"`
117+
AutomatedTestID string `json:"automatedTestId"`
118+
Area struct {
119+
ID string `json:"id"`
120+
Name string `json:"name"`
121+
URL string `json:"url"`
122+
} `json:"area"`
123+
TestCaseTitle string `json:"testCaseTitle"`
124+
CustomFields []interface{} `json:"customFields"`
125+
AutomatedTestName string `json:"automatedTestName"`
126+
StackTrace string `json:"stackTrace"`
127+
}
128+
129+
// TestResultsListOptions describes what the request to the API should look like
130+
type TestResultsListOptions struct {
131+
Count int `url:"$top,omitempty"`
132+
RunID string `url:"runId,omitempty"`
133+
}
134+
135+
// ResultsList returns list of the test results
136+
// utilising https://docs.microsoft.com/en-gb/rest/api/vsts/test/runs/list
137+
func (s *TestsService) ResultsList(opts *TestResultsListOptions) ([]TestResult, error) {
138+
URL := fmt.Sprintf("_apis/test/Runs/%s/results?api-version=4.1", opts.RunID)
139+
opts.RunID = ""
140+
URL, err := addOptions(URL, opts)
141+
142+
request, err := s.client.NewRequest("GET", URL, nil)
143+
if err != nil {
144+
return nil, err
145+
}
146+
var response TestResultsListResponse
147+
_, err = s.client.Execute(request, &response)
148+
149+
return response.Results, err
150+
}

azuredevops/tests_test.go

+216
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
package azuredevops_test
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/benmatselby/go-azuredevops/azuredevops"
9+
)
10+
11+
const (
12+
testListURL = "/AZURE_DEVOPS_Project/_apis/test/runs"
13+
testListResponse = `{
14+
"value": [
15+
{
16+
"id": 1,
17+
"name": "NewTestRun2",
18+
"url": "https://dev.azure.com/fabrikam/fabrikam-fiber-tfvc/_apis/test/Runs/1",
19+
"isAutomated": false,
20+
"iteration": "Fabrikam-Fiber-TFVC\\Release 1\\Sprint 1",
21+
"owner": {
22+
"id": "e5a5f7f8-6507-4c34-b397-6c4818e002f4",
23+
"displayName": "Fabrikam Fiber"
24+
},
25+
"startedDate": "2014-05-04T12:50:33.17Z",
26+
"completedDate": "2014-05-04T12:50:31.953Z",
27+
"state": "Completed",
28+
"plan": {
29+
"id": "1"
30+
},
31+
"revision": 4
32+
},
33+
{
34+
"id": 2,
35+
"name": "sprint1 (Manual)",
36+
"url": "https://dev.azure.com/fabrikam/fabrikam-fiber-tfvc/_apis/test/Runs/2",
37+
"isAutomated": false,
38+
"iteration": "Fabrikam-Fiber-TFVC\\Release 1\\Sprint 1",
39+
"owner": {
40+
"id": "e5a5f7f8-6507-4c34-b397-6c4818e002f4",
41+
"displayName": "Fabrikam Fiber"
42+
},
43+
"startedDate": "2014-05-04T12:58:36.907Z",
44+
"completedDate": "2014-05-04T12:58:36.47Z",
45+
"state": "Completed",
46+
"plan": {
47+
"id": "1"
48+
},
49+
"revision": 3
50+
}
51+
],
52+
"count": 2
53+
}`
54+
55+
testResultsListURL = "/AZURE_DEVOPS_Project/_apis/test/Runs/1/results"
56+
testResultsListResponse = `{
57+
"count": 1,
58+
"value": [
59+
{
60+
"id": 100000,
61+
"project": {
62+
"id": "5c3d39df-a0cb-49da-be01-42e53792c0e1",
63+
"name": "Fabrikam-Fiber-TFVC",
64+
"url": "https://dev.azure.com/fabrikam/_apis/projects/Fabrikam-Fiber-TFVC"
65+
},
66+
"startedDate": "2016-07-13T11:12:48.487Z",
67+
"completedDate": "2016-07-13T11:12:48.493Z",
68+
"durationInMs": 4,
69+
"outcome": "Passed",
70+
"revision": 1,
71+
"runBy": {
72+
"id": "a5cbf24d-799f-452e-82be-f049a85b5895",
73+
"displayName": "Fabrikam",
74+
"uniqueName": "[email protected]",
75+
"url": "https://dev.azure.com/fabrikam/_apis/Identities/a5cbf24d-799f-452e-82be-f049a85b5895",
76+
"imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=a5cbf24d-799f-452e-82be-f049a85b5895"
77+
},
78+
"state": "Completed",
79+
"testCase": {
80+
"name": "Pass1"
81+
},
82+
"testRun": {
83+
"id": "16",
84+
"name": "VSTest Test Run release any cpu",
85+
"url": "https://dev.azure.com/fabrikam/Fabrikam-Fiber-TFVC/_apis/test/Runs/16"
86+
},
87+
"lastUpdatedDate": "2016-07-13T11:12:49.123Z",
88+
"lastUpdatedBy": {
89+
"id": "375baa5b-5148-4e89-a549-ec202b722d89",
90+
"displayName": "Project Collection Build Service (fabrikam)",
91+
"uniqueName": "Build\\78b5727d-4a24-4ec8-9caf-704685572174",
92+
"url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/375baa5b-5148-4e89-a549-ec202b722d89",
93+
"imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=375baa5b-5148-4e89-a549-ec202b722d89"
94+
},
95+
"priority": 0,
96+
"computerName": "TASKAGENT5-0055",
97+
"build": {
98+
"id": "5",
99+
"name": "20160713.2",
100+
"url": "https://dev.azure.com/fabrikam/_apis/build/Builds/5"
101+
},
102+
"createdDate": "2016-07-13T11:12:49.123Z",
103+
"url": "https://dev.azure.com/fabrikam/Fabrikam-Fiber-TFVC/_apis/test/Runs/16/Results/100000",
104+
"failureType": "None",
105+
"automatedTestStorage": "unittestproject1.dll",
106+
"automatedTestType": "UnitTest",
107+
"automatedTestTypeId": "13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b",
108+
"automatedTestId": "aefba017-ab06-be36-6b92-de4e29836f72",
109+
"area": {
110+
"id": "37528",
111+
"name": "Fabrikam-Fiber-TFVC",
112+
"url": "vstfs:///Classification/Node/ebe8ac79-8d9f-4a5b-8d0a-c3095c81e70e"
113+
},
114+
"testCaseTitle": "Pass1",
115+
"customFields": [],
116+
"automatedTestName": "UnitTestProject1.UnitTest1.Pass1"
117+
}
118+
]
119+
}`
120+
)
121+
122+
func TestTestsService_List(t *testing.T) {
123+
tt := []struct {
124+
name string
125+
URL string
126+
response string
127+
count int
128+
index int
129+
state string
130+
revision int
131+
}{
132+
{name: "return two tests", URL: testListURL, response: testListResponse, count: 2, index: 0, state: "Completed", revision: 4},
133+
{name: "can handle no builds returned", URL: testListURL, response: "{}", count: 0, index: -1},
134+
}
135+
136+
for _, tc := range tt {
137+
t.Run(tc.name, func(t *testing.T) {
138+
c, mux, _, teardown := setup()
139+
defer teardown()
140+
141+
mux.HandleFunc(tc.URL, func(w http.ResponseWriter, r *http.Request) {
142+
testMethod(t, r, "GET")
143+
json := tc.response
144+
fmt.Fprint(w, json)
145+
})
146+
147+
options := &azuredevops.TestsListOptions{}
148+
tests, err := c.Tests.List(options)
149+
if err != nil {
150+
t.Fatalf("returned error: %v", err)
151+
}
152+
153+
if tc.index > -1 {
154+
if tests[tc.index].State != tc.state {
155+
t.Fatalf("expected state %s, got %s", tc.state, tests[tc.index].State)
156+
}
157+
158+
if tests[tc.index].Revision != tc.revision {
159+
t.Fatalf("expected revision %d, got %d", tc.revision, tests[tc.index].Revision)
160+
}
161+
}
162+
163+
if len(tests) != tc.count {
164+
t.Fatalf("expected length of tests to be %d; got %d", tc.count, len(tests))
165+
}
166+
})
167+
}
168+
}
169+
170+
func TestTestsService_ResultsList(t *testing.T) {
171+
tt := []struct {
172+
name string
173+
URL string
174+
response string
175+
count int
176+
index int
177+
outcome string
178+
testcase string
179+
}{
180+
{name: "return one result", URL: testResultsListURL, response: testResultsListResponse, count: 1, index: 0, outcome: "Passed", testcase: "Pass1"},
181+
{name: "can handle no results returned", URL: testResultsListURL, response: "{}", count: 0, index: -1},
182+
}
183+
184+
for _, tc := range tt {
185+
t.Run(tc.name, func(t *testing.T) {
186+
c, mux, _, teardown := setup()
187+
defer teardown()
188+
189+
mux.HandleFunc(tc.URL, func(w http.ResponseWriter, r *http.Request) {
190+
testMethod(t, r, "GET")
191+
json := tc.response
192+
fmt.Fprint(w, json)
193+
})
194+
195+
options := &azuredevops.TestResultsListOptions{RunID: "1"}
196+
tests, err := c.Tests.ResultsList(options)
197+
if err != nil {
198+
t.Fatalf("returned error: %v", err)
199+
}
200+
201+
if tc.index > -1 {
202+
if tests[tc.index].Outcome != tc.outcome {
203+
t.Fatalf("expected outcome %s, got %s", tc.outcome, tests[tc.index].Outcome)
204+
}
205+
206+
if tests[tc.index].TestCase.Name != tc.testcase {
207+
t.Fatalf("expected testcase %s got %s", tc.testcase, tests[tc.index].TestCase.Name)
208+
}
209+
}
210+
211+
if len(tests) != tc.count {
212+
t.Fatalf("expected length of tests to be %d; got %d", tc.count, len(tests))
213+
}
214+
})
215+
}
216+
}

0 commit comments

Comments
 (0)