Skip to content

Commit b6fb5ca

Browse files
committedJun 1, 2017
Add tests for the PhabricatorClient and /revisions/{id} endpoint
This commit adds unit tests for the PhabricatorClient and /revisions/{id} endpoint using the requests_mock library to stub out Phabricator's API responses. A new folder, `canned_responses` is added to contain example responses returned by the different services we depend on in our unit tests.
1 parent e38cdf2 commit b6fb5ca

File tree

7 files changed

+347
-23
lines changed

7 files changed

+347
-23
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
# yapf: disable
5+
6+
CANNED_LANDO_REVISION_1 = {
7+
"author": {
8+
"image_url": "https://d2kb8dptaglwte.cloudfront.net/file/data/oywgsrq6rtv5rdfbjvdv/PHID-FILE-632bsum6ksnpu77kymbq/alphanumeric_lato-dark_I.png-_5e622c-255%2C255%2C255%2C0.4.png",
9+
"phid": "PHID-USER-imaduemeadmin",
10+
"real_name": "Israel Madueme",
11+
"url": "https://mozphab.dev.mozaws.net/p/imadueme_admin/",
12+
"username": "imadueme_admin"
13+
},
14+
"date_created": 1495638270,
15+
"date_modifed": 1496239141,
16+
"id": 1,
17+
"parent_revisions": [],
18+
"phid": "PHID-DREV-1",
19+
"repo": {
20+
"full_name": "rMOZILLACENTRAL mozilla-central",
21+
"phid": "PHID-REPO-mozillacentral",
22+
"short_name": "rMOZILLACENTRAL",
23+
"url": "https://mozphab.dev.mozaws.net/source/mozilla-central/"
24+
},
25+
"status": 1,
26+
"status_name": "Needs Revision",
27+
"summary": "Summary 1",
28+
"test_plan": "Test Plan 1",
29+
"url": "https://mozphab.dev.mozaws.net/D1"
30+
}
31+
32+
33+
CANNED_LANDO_REVISION_2 = {
34+
"author": {
35+
"image_url": "https://d2kb8dptaglwte.cloudfront.net/file/data/oywgsrq6rtv5rdfbjvdv/PHID-FILE-632bsum6ksnpu77kymbq/alphanumeric_lato-dark_I.png-_5e622c-255%2C255%2C255%2C0.4.png",
36+
"phid": "PHID-USER-imaduemeadmin",
37+
"real_name": "Israel Madueme",
38+
"url": "https://mozphab.dev.mozaws.net/p/imadueme_admin/",
39+
"username": "imadueme_admin"
40+
},
41+
"date_created": 1495638280,
42+
"date_modifed": 1496239151,
43+
"id": 2,
44+
"parent_revisions": [
45+
CANNED_LANDO_REVISION_1
46+
],
47+
"phid": "PHID-DREV-2",
48+
"repo": {
49+
"full_name": "rMOZILLACENTRAL mozilla-central",
50+
"phid": "PHID-REPO-mozillacentral",
51+
"short_name": "rMOZILLACENTRAL",
52+
"url": "https://mozphab.dev.mozaws.net/source/mozilla-central/"
53+
},
54+
"status": 1,
55+
"status_name": "Needs Revision",
56+
"summary": "Summary 2",
57+
"test_plan": "Test Plan 2",
58+
"url": "https://mozphab.dev.mozaws.net/D2"
59+
}
60+
61+
CANNED_LANDO_REVISION_NOT_FOUND = {
62+
"detail": "The requested revision does not exist",
63+
"status": 404,
64+
"title": "Revision not found",
65+
"type": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404"
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
# yapf: disable
5+
6+
CANNED_ERROR_1 = {
7+
"result": None,
8+
"error_code": "ERR-CONDUIT-CORE",
9+
"error_info": "The value for parameter 'responsibleUsers' is not valid JSON. All parameters must be encoded as JSON values, including strings (which means you need to surround them in double quotes). Check your syntax. Value was: dsfdsf."
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
# yapf: disable
5+
6+
CANNED_REPO_MOZCENTRAL = {
7+
"result": {
8+
"PHID-REPO-mozillacentral": {
9+
"phid": "PHID-REPO-mozillacentral",
10+
"uri": "https://mozphab.dev.mozaws.net/source/mozilla-central/",
11+
"typeName": "Repository",
12+
"type": "REPO",
13+
"name": "rMOZILLACENTRAL",
14+
"fullName": "rMOZILLACENTRAL mozilla-central",
15+
"status": "open"
16+
}
17+
},
18+
"error_code": None,
19+
"error_info": None
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
# yapf: disable
5+
6+
CANNED_REVISION_1 = {
7+
"result": [
8+
{
9+
"id": "1",
10+
"phid": "PHID-DREV-1",
11+
"title": "My test diff 1",
12+
"uri": "https://mozphab.dev.mozaws.net/D1",
13+
"dateCreated": "1495638270",
14+
"dateModified": "1496239141",
15+
"authorPHID": "PHID-USER-imaduemeadmin",
16+
"status": "1",
17+
"statusName": "Needs Revision",
18+
"properties": [],
19+
"branch": None,
20+
"summary": "Summary 1",
21+
"testPlan": "Test Plan 1",
22+
"lineCount": "2",
23+
"activeDiffPHID": "PHID-DIFF-rpzpm5wuhiuly2ujurlu",
24+
"diffs": ["2"],
25+
"commits": [],
26+
"reviewers": {
27+
"PHID-USER-egtmqukxexnsgko4dhkm": "PHID-USER-egtmqukxexnsgko4dhkm"
28+
},
29+
"ccs": [],
30+
"hashes": [],
31+
"auxiliary": {
32+
"phabricator:projects": [],
33+
"phabricator:depends-on": []
34+
},
35+
"repositoryPHID": "PHID-REPO-mozillacentral",
36+
"sourcePath": None,
37+
}
38+
],
39+
"error_code": None,
40+
"error_info": None,
41+
}
42+
43+
44+
CANNED_REVISION_2 = {
45+
"result": [
46+
{
47+
"id": "2",
48+
"phid": "PHID-DREV-2",
49+
"title": "My test diff 2",
50+
"uri": "https://mozphab.dev.mozaws.net/D2",
51+
"dateCreated": "1495638280",
52+
"dateModified": "1496239151",
53+
"authorPHID": "PHID-USER-imaduemeadmin",
54+
"status": "1",
55+
"statusName": "Needs Revision",
56+
"properties": [],
57+
"branch": None,
58+
"summary": "Summary 2",
59+
"testPlan": "Test Plan 2",
60+
"lineCount": "2",
61+
"activeDiffPHID": "PHID-DIFF-kd928flk230lkidwayij",
62+
"diffs": ["2"],
63+
"commits": [],
64+
"reviewers": {
65+
"PHID-USER-egtmqukxexnsgko4dhkm": "PHID-USER-egtmqukxexnsgko4dhkm"
66+
},
67+
"ccs": [],
68+
"hashes": [],
69+
"auxiliary": {
70+
"phabricator:projects": [],
71+
"phabricator:depends-on": ["PHID-DREV-1"]
72+
},
73+
"repositoryPHID": "PHID-REPO-mozillacentral",
74+
"sourcePath": None,
75+
}
76+
],
77+
"error_code": None,
78+
"error_info": None,
79+
}
80+
81+
CANNED_REVISION_EMPTY = {
82+
"result": [],
83+
"error_code": None,
84+
"error_info": None
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
# yapf: disable
5+
6+
CANNED_USER_1 = {
7+
"result": [
8+
{
9+
"phid": "PHID-USER-imaduemeadmin",
10+
"userName": "imadueme_admin",
11+
"realName": "Israel Madueme",
12+
"image": "https://d2kb8dptaglwte.cloudfront.net/file/data/oywgsrq6rtv5rdfbjvdv/PHID-FILE-632bsum6ksnpu77kymbq/alphanumeric_lato-dark_I.png-_5e622c-255%2C255%2C255%2C0.4.png",
13+
"uri": "https://mozphab.dev.mozaws.net/p/imadueme_admin/",
14+
"roles": [
15+
"admin",
16+
"verified",
17+
"approved",
18+
"activated"
19+
]
20+
}
21+
],
22+
"error_code": None,
23+
"error_info": None
24+
}
25+
26+
CANNED_USER_WHOAMI_1 = {
27+
"result": {
28+
"phid": "PHID-USER-zlfme42o3yewh5v4k6ry",
29+
"userName": "imadueme_admin",
30+
"realName": "Israel Madueme",
31+
"image": "https://d2kb8dptaglwte.cloudfront.net/file/data/oywgsrq6rtv5rdfbjvdv/PHID-FILE-632bsum6ksnpu77kymbq/alphanumeric_lato-dark_I.png-_5e622c-255%2C255%2C255%2C0.4.png",
32+
"uri": "https://mozphab.dev.mozaws.net/p/imadueme_admin/",
33+
"roles": [
34+
"admin",
35+
"verified",
36+
"approved",
37+
"activated"
38+
],
39+
"primaryEmail": "imadueme@mozilla.com"
40+
},
41+
"error_code": None,
42+
"error_info": None
43+
}

‎tests/test_phabricator_client.py

+54-23
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,75 @@
1-
# # This Source Code Form is subject to the terms of the Mozilla Public
2-
# # License, v. 2.0. If a copy of the MPL was not distributed with this
3-
# # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4-
#
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
"""
5+
Tests for the PhabricatorClient
6+
"""
57
import os
6-
import json
8+
import pytest
79
import requests_mock
810

9-
from tests.utils import versionfile, app
10-
1111
from landoapi.phabricator_client import PhabricatorClient, \
1212
PhabricatorAPIException
1313

14+
from tests.utils import versionfile, app
15+
from tests.canned_responses.phabricator.revisions import *
16+
from tests.canned_responses.phabricator.users import *
17+
from tests.canned_responses.phabricator.repos import *
18+
from tests.canned_responses.phabricator.errors import *
1419

15-
def test_get_revision_returns_200():
20+
21+
def test_get_revision_with_200_response():
1622
phab = PhabricatorClient(api_key='api-key')
1723
api_url = '%s/api/differential.query' % os.getenv('PHABRICATOR_URL')
1824

1925
with requests_mock.mock() as m:
20-
# TODO finish testing response with actual data
21-
result = {'result': [{}], 'error_code': None, 'error_info': None}
22-
m.get(api_url, text=json.dumps(result))
23-
response = phab.get_revision(id='D123')
24-
assert response == {}
26+
m.get(api_url, status_code=200, json=CANNED_REVISION_1)
27+
revision = phab.get_revision(id=CANNED_REVISION_1['result'][0]['id'])
28+
assert revision == CANNED_REVISION_1['result'][0]
2529

2630

27-
def test_get_current_user_returns_200():
28-
pass
31+
def test_get_current_user_with_200_response():
32+
phab = PhabricatorClient(api_key='api-key')
33+
api_url = '%s/api/user.whoami' % os.getenv('PHABRICATOR_URL')
2934

35+
with requests_mock.mock() as m:
36+
m.get(api_url, status_code=200, json=CANNED_USER_WHOAMI_1)
37+
user = phab.get_current_user()
38+
assert user == CANNED_USER_WHOAMI_1['result']
3039

31-
def test_get_user_returns_200():
32-
pass
3340

41+
def test_get_user_returns_with_200_response():
42+
phab = PhabricatorClient(api_key='api-key')
43+
api_url = '%s/api/user.query' % os.getenv('PHABRICATOR_URL')
3444

35-
def test_get_repo_returns_200():
36-
pass
45+
with requests_mock.mock() as m:
46+
m.get(api_url, status_code=200, json=CANNED_USER_1)
47+
user = phab.get_user(phid=CANNED_USER_1['result'][0]['phid'])
48+
assert user == CANNED_USER_1['result'][0]
3749

3850

39-
def test_phabricator_exception():
40-
pass
51+
def test_get_repo_returns_with_200_response():
52+
phab = PhabricatorClient(api_key='api-key')
53+
api_url = '%s/api/phid.query' % os.getenv('PHABRICATOR_URL')
54+
55+
with requests_mock.mock() as m:
56+
m.get(api_url, status_code=200, json=CANNED_REPO_MOZCENTRAL)
57+
canned_response_repo = \
58+
list(CANNED_REPO_MOZCENTRAL['result'].values())[0]
59+
repo = phab.get_repo(phid=canned_response_repo['phid'])
60+
assert repo == canned_response_repo
61+
4162

63+
def test_phabricator_exception():
64+
""" Ensures that the PhabricatorClient converts JSON errors from Phabricator
65+
into proper exceptions with the error_code and error_message in tact.
66+
"""
67+
phab = PhabricatorClient(api_key='api-key')
68+
api_url = '%s/api/differential.query' % os.getenv('PHABRICATOR_URL')
4269

43-
def test_request_exception():
44-
pass
70+
with requests_mock.mock() as m:
71+
m.get(api_url, status_code=200, json=CANNED_ERROR_1)
72+
with pytest.raises(PhabricatorAPIException) as e_info:
73+
phab.get_revision(id=CANNED_REVISION_1['result'][0]['id'])
74+
assert e_info.value.error_code == CANNED_ERROR_1['error_code']
75+
assert e_info.value.error_info == CANNED_ERROR_1['error_info']

‎tests/test_revisions.py

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
import os
5+
from urllib.parse import parse_qs
6+
7+
import requests_mock
8+
9+
from tests.utils import versionfile, app
10+
from tests.canned_responses.phabricator.revisions import *
11+
from tests.canned_responses.phabricator.users import *
12+
from tests.canned_responses.phabricator.repos import *
13+
from tests.canned_responses.lando_api.revisions import *
14+
15+
16+
def test_get_revision_with_no_parents(client):
17+
revision_url = '%s/api/differential.query' % os.getenv('PHABRICATOR_URL')
18+
user_url = '%s/api/user.query' % os.getenv('PHABRICATOR_URL')
19+
repo_url = '%s/api/phid.query' % os.getenv('PHABRICATOR_URL')
20+
21+
with requests_mock.mock() as m:
22+
m.get(revision_url, status_code=200, json=__phabricator_revision_stub)
23+
m.get(user_url, status_code=200, json=CANNED_USER_1)
24+
m.get(repo_url, status_code=200, json=CANNED_REPO_MOZCENTRAL)
25+
response = client.get('/revisions/D1?api_key=api-key')
26+
assert response.status_code == 200
27+
assert response.content_type == 'application/json'
28+
assert response.json == CANNED_LANDO_REVISION_1
29+
30+
31+
def test_get_revision_with_parents(client):
32+
revision_url = '%s/api/differential.query' % os.getenv('PHABRICATOR_URL')
33+
user_url = '%s/api/user.query' % os.getenv('PHABRICATOR_URL')
34+
repo_url = '%s/api/phid.query' % os.getenv('PHABRICATOR_URL')
35+
36+
with requests_mock.mock() as m:
37+
m.get(revision_url, status_code=200, json=__phabricator_revision_stub)
38+
m.get(user_url, status_code=200, json=CANNED_USER_1)
39+
m.get(repo_url, status_code=200, json=CANNED_REPO_MOZCENTRAL)
40+
response = client.get('/revisions/D2?api_key=api-key')
41+
assert response.status_code == 200
42+
assert response.content_type == 'application/json'
43+
assert response.json == CANNED_LANDO_REVISION_2
44+
45+
46+
def test_get_revision_returns_404(client):
47+
revision_url = '%s/api/differential.query' % os.getenv('PHABRICATOR_URL')
48+
49+
with requests_mock.mock() as m:
50+
m.get(revision_url, status_code=200, json=CANNED_REVISION_EMPTY)
51+
response = client.get('/revisions/D9000?api_key=api-key')
52+
assert response.status_code == 404
53+
assert response.content_type == 'application/problem+json'
54+
assert response.json == CANNED_LANDO_REVISION_NOT_FOUND
55+
56+
57+
def __phabricator_revision_stub(request, context):
58+
form = parse_qs(request.text)
59+
if form.get('ids[]') and form['ids[]'][0]:
60+
if form['ids[]'][0] == '1':
61+
return CANNED_REVISION_1
62+
elif form['ids[]'][0] == '2':
63+
return CANNED_REVISION_2
64+
elif form.get('phids[]') and form['phids[]'][0]:
65+
if form['phids[]'][0] == 'PHID-DREV-1':
66+
return CANNED_REVISION_1
67+
elif form['phids[]'][0] == 'PHID-DREV-2':
68+
return CANNED_REVISION_2
69+
assert False

0 commit comments

Comments
 (0)
Failed to load comments.