Skip to content

Commit be83aa8

Browse files
committed
Added unit test cases for api and webapp
Added unit tests using nock to mock responses from a real gitlab server. Steps for adding to the cases written in README.md in the test directory. Also, bumped up version for mocha and superagent, added dependency for nock in package.json
1 parent e36fa08 commit be83aa8

16 files changed

+2107
-4
lines changed

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@
3737
"inline_icon": "bitbucket"
3838
},
3939
"devDependencies": {
40-
"jshint": "~2.1.11",
4140
"expect.js": "~0.2.0",
42-
"mocha": "~1.13.0"
41+
"jshint": "~2.1.11",
42+
"mocha": "~2.2.3",
43+
"nock": "^2.10.0"
4344
},
4445
"dependencies": {
4546
"async": "~0.2.9",
@@ -48,7 +49,7 @@
4849
"lodash": "~2.2.0",
4950
"step": "0.0.5",
5051
"strider-git": "^0.2.4",
51-
"superagent": "~0.15.4"
52+
"superagent": "~1.3.0"
5253
},
5354
"bugs": {
5455
"url": "https://github.com/meric426/strider-gitlab/issues"

test/README.md

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,80 @@
11
strider-gitlab tests
22
====================
33

4-
The tests use mocha for testing and nock for mocking responses from a gitlab server.
4+
The tests use mocha for testing and [nock](https://github.com/pgte/nock) for mocking responses from a gitlab server.
5+
6+
Start out by writing an outline of what you want to test by adding pending tests to a .js file in the test directory,
7+
(inside the appropriate describe blocks)
8+
9+
like:
10+
11+
```
12+
it('should do xyz when abc happens');
13+
it('should do lmn when opq happens');
14+
... as many as necessary
15+
```
16+
17+
Now running npm test will show your tests as "pending" and marked with a "-".
18+
19+
Next, observe the "happy path", the existing behavior of the code by using util.inspect to log the parameters passed to
20+
the function to be tested when the codepath is run (ensure that the codepath is run by using the Strider web gui if needed),
21+
in order to understand what needs to be passed to the function you want to test in the test file.
22+
23+
In order to sniff and record the http traffic so that you can create a nock mock of the gitlab server,
24+
use code similar to the following inside the codepath that you want to test:
25+
26+
```
27+
In file lib/api.js ...
28+
29+
var nock = require('nock');
30+
...
31+
32+
//for example, inside the removeDeployKey function in lib/api.js
33+
var appendLogToFile = function(content) {
34+
fs.appendFile('/noderoot/gitlab_remove_deploykey.txt', content);
35+
};
36+
37+
nock.recorder.rec({
38+
logging: appendLogToFile,
39+
});
40+
```
41+
42+
In the above example, the file gitlab_remove_deploykey.txt file will contain the statements generated by nock.
43+
44+
Next write out the body of the pending tests, one at a time.
45+
After writing out the body of a test, do an 'npm test' run, with nock still recording.
46+
Before doing the npm test run, ensure that only the current describe() block is active by adding the .only suffix.
47+
Like so,
48+
```
49+
describe.only('parseRepo', function(){
50+
it('should correctly parse repo information as received from gitlab server into a repo object');
51+
it('should throw an error if it gets an empty parameter as repo ?');
52+
...
53+
54+
```
55+
This will ensure that only the tests for functionality currently under consideration will be run.
56+
Also, mark all tests other than the current one to be inactive by changing the "it('should ..." to "xit('should ...".
57+
Else, you can ensure that only the current test is run by changing 'it(' to 'it.only('
58+
59+
Before the run, you must also comment out any code that asks nock to intercept calls - the usual place for which is in
60+
the before, after or beforeEach/afterEach blocks. For example, comment out all the lines inside the following blocks
61+
```
62+
before('Setup the mock gitlab server', function setupNock() {
63+
nock.cleanAll(); //remove all interceptors
64+
nock.disableNetConnect(); //prevent all network call from going to the actual server
65+
require('./mocks/gitlab_add_key.js')(); //pull in the mock code to simulate the server for this block
66+
});
67+
68+
after('Tear down mock Gitlab server', function tearDownNock() {
69+
nock.cleanAll(); //remove all interceptors
70+
});
71+
```
72+
This will ensure that the actual interaction between our code and the gitlab server will be recorded by nock.
73+
Copy out the code generated by nock into a .js file in the mocks subdirectory (see existing files in mocks/ for example)
74+
75+
Before moving on to writing the next test, empty out the file used by nock for recording, and mark the test already
76+
written with a "xit(" or a "it.skip("
77+
78+
After you are done with writing the tests, remove or comment out the nock.recorder.rec code so that nock stops recording.
79+
Then, enable all the tests in the block and enable/de-comment out the code that asks nock to
80+
disableNetConnect and mock, and re-run "npm test" to see all your tests run with the gitlab server mocked out of the picture.

test/mocks/gitlab_add_key.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
Simulation of responses from server when we
3+
request the addition of a deploy key.
4+
5+
nock will simulate a gitlab server running at
6+
localhost:80, where Strider Tester, a user is
7+
registered with the name "stridertester", and
8+
has been registered with api token - zRtVsmeznn7ySatTrnrp
9+
stridertester is an "owner" of a group named "testunion"
10+
and has admin access to three projects -
11+
testunion / unionproject1
12+
Strider Tester / pubproject1
13+
Strider Tester / privproject1
14+
*/
15+
16+
var nock = require('nock');
17+
18+
module.exports = function () {
19+
//--------------------------------------------------------------------------------------
20+
//simulate a Created 201 response when we try to deploy ssh keys for a project
21+
nock('http://localhost:80')
22+
.post('/api/v3/projects/5/keys', {
23+
"title": "strider-stridertester/privproject1",
24+
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAMoSHhKfeE3/oXanAQEZO0Sq20SMjvjmJlTy+CaGz/1uk+glLXi9u2RKtfPRZDceAgyEtRUpqya9Uo1v9bjkIckGLhQwXdSo2G6O3QuzpE3gc6AXTDPQ0ZkkXbSdU9VGL1Zzr+maBnvfwK6IlsNz3fLa4lNV7vz1LaGCg9D1jP+nufZjuDiCAno7D607oG1iHQ3x/BqzphUATav3DFQFT2FBmmittQT0l0mMJ4XsQCQXkwNbDjkLYNon8FYPm9U3AOlzicOGteebt5mhsQtfl9+lL99B8+fk8b24pEEbOxZ4l0HcwMI1R5OLoTzPwSvVw+bp3YPhH2IzfFwK5NUk7 stridertester/[email protected]\n"
25+
})
26+
.query({"private_token": "zRtVsmeznn7ySatTrnrp"})
27+
.reply(201, {
28+
"id": 12,
29+
"title": "strider-stridertester/privproject1",
30+
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAMoSHhKfeE3/oXanAQEZO0Sq20SMjvjmJlTy+CaGz/1uk+glLXi9u2RKtfPRZDceAgyEtRUpqya9Uo1v9bjkIckGLhQwXdSo2G6O3QuzpE3gc6AXTDPQ0ZkkXbSdU9VGL1Zzr+maBnvfwK6IlsNz3fLa4lNV7vz1LaGCg9D1jP+nufZjuDiCAno7D607oG1iHQ3x/BqzphUATav3DFQFT2FBmmittQT0l0mMJ4XsQCQXkwNbDjkLYNon8FYPm9U3AOlzicOGteebt5mhsQtfl9+lL99B8+fk8b24pEEbOxZ4l0HcwMI1R5OLoTzPwSvVw+bp3YPhH2IzfFwK5NUk7 stridertester/[email protected]",
31+
"created_at": "2015-08-19T03:35:01.863Z"
32+
}, {
33+
server: 'nginx',
34+
date: 'Wed, 19 Aug 2015 03:35:01 GMT',
35+
'content-type': 'application/json',
36+
'content-length': '534',
37+
connection: 'close',
38+
status: '201 Created',
39+
etag: '"5a11f9a2bf20878df6e3de77364e297c"',
40+
'cache-control': 'max-age=0, private, must-revalidate',
41+
'x-request-id': '565d54e9-f03b-4077-8cf4-a93503060889',
42+
'x-runtime': '0.099917'
43+
});
44+
45+
//--------------------------------------------------------------------------------------
46+
//simulate a 400 Bad Request response when an invalid key is sent
47+
nock('http://localhost:80')
48+
.post('/api/v3/projects/5/keys', {"title": "strider-stridertester/privproject1", "key": "invalid-key"})
49+
.query({"private_token": "zRtVsmeznn7ySatTrnrp"})
50+
.reply(400, {"message": {"key": ["is invalid"], "fingerprint": ["cannot be generated"]}}, {
51+
server: 'nginx',
52+
date: 'Wed, 19 Aug 2015 04:35:26 GMT',
53+
'content-type': 'application/json',
54+
'content-length': '72',
55+
connection: 'close',
56+
status: '400 Bad Request',
57+
'cache-control': 'no-cache',
58+
'x-request-id': '907e7139-cb13-407a-864f-a91ce108e419',
59+
'x-runtime': '0.054109'
60+
});
61+
62+
//--------------------------------------------------------------------------------------
63+
//simulate a 401 Unauthorized response when invalid credentials are used
64+
nock('http://localhost:80')
65+
.post('/api/v3/projects/5/keys', {
66+
"title": "strider-stridertester/privproject1",
67+
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAMoSHhKfeE3/oXanAQEZO0Sq20SMjvjmJlTy+CaGz/1uk+glLXi9u2RKtfPRZDceAgyEtRUpqya9Uo1v9bjkIckGLhQwXdSo2G6O3QuzpE3gc6AXTDPQ0ZkkXbSdU9VGL1Zzr+maBnvfwK6IlsNz3fLa4lNV7vz1LaGCg9D1jP+nufZjuDiCAno7D607oG1iHQ3x/BqzphUATav3DFQFT2FBmmittQT0l0mMJ4XsQCQXkwNbDjkLYNon8FYPm9U3AOlzicOGteebt5mhsQtfl9+lL99B8+fk8b24pEEbOxZ4l0HcwMI1R5OLoTzPwSvVw+bp3YPhH2IzfFwK5NUk7 stridertester/[email protected]\n"
68+
})
69+
.query({"private_token": "zRtVsmeznn7ySatTrnra"})
70+
.reply(401, {"message": "401 Unauthorized"}, {
71+
server: 'nginx',
72+
date: 'Wed, 19 Aug 2015 05:03:45 GMT',
73+
'content-type': 'application/json',
74+
'content-length': '30',
75+
connection: 'close',
76+
status: '401 Unauthorized',
77+
'cache-control': 'no-cache',
78+
'x-request-id': '282a2411-dd11-4026-90b3-8a36560c0512',
79+
'x-runtime': '0.004726'
80+
});
81+
82+
//--------------------------------------------------------------------------------------
83+
//simulate a 404 response when project could not be found
84+
nock('http://localhost:80')
85+
.post('/api/v3/projects/wrong%20repo%20id/keys', {
86+
"title": "strider-stridertester/privproject1",
87+
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAMoSHhKfeE3/oXanAQEZO0Sq20SMjvjmJlTy+CaGz/1uk+glLXi9u2RKtfPRZDceAgyEtRUpqya9Uo1v9bjkIckGLhQwXdSo2G6O3QuzpE3gc6AXTDPQ0ZkkXbSdU9VGL1Zzr+maBnvfwK6IlsNz3fLa4lNV7vz1LaGCg9D1jP+nufZjuDiCAno7D607oG1iHQ3x/BqzphUATav3DFQFT2FBmmittQT0l0mMJ4XsQCQXkwNbDjkLYNon8FYPm9U3AOlzicOGteebt5mhsQtfl9+lL99B8+fk8b24pEEbOxZ4l0HcwMI1R5OLoTzPwSvVw+bp3YPhH2IzfFwK5NUk7 stridertester/[email protected]\n"
88+
})
89+
.query({"private_token": "zRtVsmeznn7ySatTrnrp"})
90+
.reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], {
91+
server: 'nginx',
92+
date: 'Wed, 19 Aug 2015 05:25:00 GMT',
93+
'content-type': 'application/json',
94+
'transfer-encoding': 'chunked',
95+
connection: 'close',
96+
status: '404 Not Found',
97+
'cache-control': 'no-cache',
98+
'x-request-id': '2c64ae26-d7b1-4caf-8efd-300893dedf37',
99+
'x-runtime': '0.005714',
100+
'content-encoding': 'gzip'
101+
});
102+
}

test/mocks/gitlab_create_hooks.js

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
Simulation of responses from a server when we
3+
request the creation of hooks.
4+
5+
nock will simulate a gitlab server running at
6+
localhost:80, where Strider Tester, a user is
7+
registered with the name "stridertester", and
8+
has been registered with api token - zRtVsmeznn7ySatTrnrp
9+
stridertester is an "owner" of a group named "testunion"
10+
and has admin access to three projects -
11+
testunion / unionproject1
12+
Strider Tester / pubproject1
13+
Strider Tester / privproject1
14+
*/
15+
var nock = require('nock');
16+
17+
module.exports = function () {
18+
19+
//--------------------------------------------------------------------------------------
20+
//Simulate 201 replies when we request the addition of a new project
21+
//(adding hooks and keys)
22+
nock('http://localhost:80')
23+
.post('/api/v3/projects/5/hooks', {
24+
"url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook",
25+
"push_events": true
26+
})
27+
.query({"private_token": "zRtVsmeznn7ySatTrnrp"})
28+
.reply(201, {
29+
"id": 18,
30+
"url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook",
31+
"created_at": "2015-08-21T14:11:54.922Z",
32+
"project_id": 5,
33+
"push_events": true,
34+
"issues_events": false,
35+
"merge_requests_events": false,
36+
"tag_push_events": false
37+
}, {
38+
server: 'nginx',
39+
date: 'Fri, 21 Aug 2015 14:11:54 GMT',
40+
'content-type': 'application/json',
41+
'content-length': '235',
42+
connection: 'close',
43+
status: '201 Created',
44+
etag: '"3b0821c3d2fa5d74684be993bfba7805"',
45+
'cache-control': 'max-age=0, private, must-revalidate',
46+
'x-request-id': '0f470a71-564f-4dcc-ae1f-743b73c98473',
47+
'x-runtime': '0.021008'
48+
});
49+
50+
nock('http://localhost:80')
51+
.post('/api/v3/projects/5/keys', {
52+
"title": "strider-stridertester/privproject1",
53+
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5CS04M9YZAoOkl9suZuKdBR643lB9Kv2AigyqcCfljhnFK3tWPLEnlsLE7ZnunTC3VcPPesdC8MeWC95EvQgNGH6Y5oXrGcaxZKiVDunk4xxKpJQjzMbp753B4R7i28NyZVShCyYG0+wkqAYlJ4NFWn6PMEOouinY8Z3/JD/e9luq4QgyyrI9s+e7VWKBBof9f6FtaGWXwpaWt7Peud3/AWKkhPELQmDDBEcZ5jxFneLsO0KEQ3qqGlEhQbtYLblgjWvuekd0CAReyUNjyJQG+rfDyVVadAQNHiri7c8cj6Y766FdfRskCKiA7E5IPfnysUcRx8657u6DG4PC6guV stridertester/[email protected]\n"
54+
})
55+
.query({"private_token": "zRtVsmeznn7ySatTrnrp"})
56+
.reply(201, {
57+
"id": 22,
58+
"title": "strider-stridertester/privproject1",
59+
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5CS04M9YZAoOkl9suZuKdBR643lB9Kv2AigyqcCfljhnFK3tWPLEnlsLE7ZnunTC3VcPPesdC8MeWC95EvQgNGH6Y5oXrGcaxZKiVDunk4xxKpJQjzMbp753B4R7i28NyZVShCyYG0+wkqAYlJ4NFWn6PMEOouinY8Z3/JD/e9luq4QgyyrI9s+e7VWKBBof9f6FtaGWXwpaWt7Peud3/AWKkhPELQmDDBEcZ5jxFneLsO0KEQ3qqGlEhQbtYLblgjWvuekd0CAReyUNjyJQG+rfDyVVadAQNHiri7c8cj6Y766FdfRskCKiA7E5IPfnysUcRx8657u6DG4PC6guV stridertester/[email protected]",
60+
"created_at": "2015-08-21T14:11:54.986Z"
61+
}, {
62+
server: 'nginx',
63+
date: 'Fri, 21 Aug 2015 14:11:55 GMT',
64+
'content-type': 'application/json',
65+
'content-length': '534',
66+
connection: 'close',
67+
status: '201 Created',
68+
etag: '"13f3437db289c9c485011a1201db884f"',
69+
'cache-control': 'max-age=0, private, must-revalidate',
70+
'x-request-id': '0e829475-9fda-458e-8b34-08c7e8c4c0f5',
71+
'x-runtime': '0.099567'
72+
});
73+
74+
//--------------------------------------------------------------------------------------
75+
//Simulate a 401 reply if api key is not sent
76+
nock('http://localhost:80')
77+
.post('/api/v3/projects/5/hooks', {
78+
"url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook",
79+
"push_events": true
80+
})
81+
.reply(401, {"message": "401 Unauthorized"}, {
82+
server: 'nginx',
83+
date: 'Fri, 21 Aug 2015 14:42:46 GMT',
84+
'content-type': 'application/json',
85+
'content-length': '30',
86+
connection: 'close',
87+
status: '401 Unauthorized',
88+
'cache-control': 'no-cache',
89+
'x-request-id': '052eafeb-0028-4e69-b951-95925efdc232',
90+
'x-runtime': '0.004600'
91+
});
92+
93+
//--------------------------------------------------------------------------------------
94+
//Simulate a 404 if we passed an incorrect repo id
95+
nock('http://localhost:80')
96+
.post('/api/v3/projects/invalid-repo/hooks', {
97+
"url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook",
98+
"push_events": true
99+
})
100+
.query({"private_token": "zRtVsmeznn7ySatTrnrp"})
101+
.reply(404, ["1f8b0800000000000003ab56ca4d2d2e4e4c4f55b252323130510828cacf4a4d2e51f0cb2f5170cb2fcd4b51aa050037095a2823000000"], {
102+
server: 'nginx',
103+
date: 'Fri, 21 Aug 2015 14:47:42 GMT',
104+
'content-type': 'application/json',
105+
'transfer-encoding': 'chunked',
106+
connection: 'close',
107+
status: '404 Not Found',
108+
'cache-control': 'no-cache',
109+
'x-request-id': 'b35510b5-8f3b-434c-bc63-e77ed6a5dc74',
110+
'x-runtime': '0.006681',
111+
'content-encoding': 'gzip'
112+
});
113+
114+
//--------------------------------------------------------------------------------------
115+
//Simulate a 400 if we passed a bad URL
116+
nock('http://localhost:80')
117+
.post('/api/v3/projects/5/hooks', {"url": false, "push_events": true})
118+
.query({"private_token": "zRtVsmeznn7ySatTrnrp"})
119+
.reply(400, {"message": "400 (Bad request) \"url\" not given"}, {
120+
server: 'nginx',
121+
date: 'Fri, 21 Aug 2015 14:52:41 GMT',
122+
'content-type': 'application/json',
123+
'content-length': '49',
124+
connection: 'close',
125+
status: '400 Bad Request',
126+
'cache-control': 'no-cache',
127+
'x-request-id': '823fd96a-3829-4dbe-b7ff-75ab89b50455',
128+
'x-runtime': '0.010701'
129+
});
130+
131+
//--------------------------------------------------------------------------------------
132+
//Simulate a 401 if wrong credentials were sent
133+
nock('http://localhost:80')
134+
.post('/api/v3/projects/5/hooks', {
135+
"url": "http://localhost:3000/stridertester/privproject1/api/gitlab/webhook",
136+
"push_events": true
137+
})
138+
.query({"private_token": "zRtVsmeznn7ySatTrnra"})
139+
.reply(401, {"message": "401 Unauthorized"}, {
140+
server: 'nginx',
141+
date: 'Fri, 21 Aug 2015 16:38:40 GMT',
142+
'content-type': 'application/json',
143+
'content-length': '30',
144+
connection: 'close',
145+
status: '401 Unauthorized',
146+
'cache-control': 'no-cache',
147+
'x-request-id': '0f3180af-8f43-495f-91fb-8455313eff9a',
148+
'x-runtime': '0.004978'
149+
});
150+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
Simulation of responses from server when we
3+
ask for deleting hooks when no hooks are present
4+
5+
nock will simulate a gitlab server running at
6+
localhost:80, where Strider Tester, a user is
7+
registered with the name "stridertester", and
8+
has been registered with api token - zRtVsmeznn7ySatTrnrp
9+
stridertester is an "owner" of a group named "testunion"
10+
and has admin access to three projects -
11+
testunion / unionproject1
12+
Strider Tester / pubproject1
13+
Strider Tester / privproject1
14+
*/
15+
var nock = require('nock');
16+
17+
module.exports = function () {
18+
//--------------------------------------------------------------------------------------
19+
//Empty array as list of hooks in response
20+
nock('http://localhost:80')
21+
.get('/api/v3/projects/5/hooks')
22+
.query({"private_token": "zRtVsmeznn7ySatTrnrp"})
23+
.reply(200, [], {
24+
server: 'nginx',
25+
date: 'Fri, 21 Aug 2015 16:08:18 GMT',
26+
'content-type': 'application/json',
27+
'content-length': '2',
28+
connection: 'close',
29+
status: '200 OK',
30+
link: '<http://localhost/api/v3/projects/5/hooks?page=1&per_page=0>; rel="first", <http://localhost/api/v3/projects/5/hooks?page=0&per_page=0>; rel="last"',
31+
etag: '"d751713988987e9331980363e24189ce"',
32+
'cache-control': 'max-age=0, private, must-revalidate',
33+
'x-request-id': 'de64f599-b582-4bcb-b68d-552c2441028e',
34+
'x-runtime': '0.019459'
35+
});
36+
};

0 commit comments

Comments
 (0)