Merge master into laffa

This commit is contained in:
Joseph Schorr 2014-10-07 14:03:17 -04:00
commit f38ce51943
94 changed files with 3132 additions and 871 deletions

Binary file not shown.

View file

@ -1,14 +1,16 @@
import unittest
import json
import datetime
from urllib import urlencode
from urlparse import urlparse, urlunparse, parse_qs
from app import app
from data import model
from initdb import setup_database_for_testing, finished_database_for_testing
from endpoints.api import api_bp, api
from endpoints.api.team import TeamMember, TeamMemberList, OrganizationTeam
from endpoints.api.team import TeamMember, TeamMemberList, OrganizationTeam, TeamMemberInvite
from endpoints.api.tag import RepositoryTagImages, RepositoryTag
from endpoints.api.search import FindRepositories, EntitySearch
from endpoints.api.image import RepositoryImageChanges, RepositoryImage, RepositoryImageList
@ -19,7 +21,7 @@ from endpoints.api.robot import (UserRobotList, OrgRobot, OrgRobotList, UserRobo
from endpoints.api.trigger import (BuildTriggerActivate, BuildTriggerSources, BuildTriggerSubdirs,
TriggerBuildList, ActivateBuildTrigger, BuildTrigger,
BuildTriggerList, BuildTriggerAnalyze)
BuildTriggerList, BuildTriggerAnalyze, BuildTriggerFieldValues)
from endpoints.api.repoemail import RepositoryAuthorizedEmail
from endpoints.api.repositorynotification import RepositoryNotification, RepositoryNotificationList
from endpoints.api.user import (PrivateRepositories, ConvertToOrganization, Recovery, Signout,
@ -40,7 +42,8 @@ from endpoints.api.repository import RepositoryList, RepositoryVisibility, Repos
from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPermission,
RepositoryTeamPermissionList, RepositoryUserPermissionList)
from endpoints.api.superuser import SuperUserLogs, SuperUserList, SuperUserManagement
from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserManagement,
SuperUserSendRecoveryEmail)
try:
@ -75,7 +78,9 @@ class ApiTestCase(unittest.TestCase):
with client.session_transaction() as sess:
if auth_username:
sess['user_id'] = auth_username
loaded = model.get_user(auth_username)
sess['user_id'] = loaded.id
sess['login_time'] = datetime.datetime.now()
sess[CSRF_TOKEN_KEY] = CSRF_TOKEN
# Restore the teardown functions
@ -510,13 +515,13 @@ class TestUser(ApiTestCase):
self._run_test('PUT', 401, None, {})
def test_put_freshuser(self):
self._run_test('PUT', 401, 'freshuser', {})
self._run_test('PUT', 200, 'freshuser', {})
def test_put_reader(self):
self._run_test('PUT', 401, 'reader', {})
self._run_test('PUT', 200, 'reader', {})
def test_put_devtable(self):
self._run_test('PUT', 401, 'devtable', {})
self._run_test('PUT', 200, 'devtable', {})
def test_post_anonymous(self):
self._run_test('POST', 400, None, {u'username': 'T946', u'password': '0SG4', u'email': 'MENT'})
@ -1061,6 +1066,62 @@ class TestBuildTriggerActivateSwo1BuynlargeOrgrepo(ApiTestCase):
def test_post_devtable(self):
self._run_test('POST', 404, 'devtable', {'config': {}})
class TestBuildTriggerFieldValuesSwo1PublicPublicrepo(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(BuildTriggerFieldValues, trigger_uuid="SWO1", repository="public/publicrepo",
field_name="test_field")
def test_get_anonymous(self):
self._run_test('GET', 401, None, {})
def test_get_freshuser(self):
self._run_test('GET', 403, 'freshuser', {})
def test_get_reader(self):
self._run_test('GET', 403, 'reader', {})
def test_get_devtable(self):
self._run_test('GET', 403, 'devtable', {})
class TestBuildTriggerFieldValuesSwo1DevtableShared(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(BuildTriggerFieldValues, trigger_uuid="SWO1", repository="devtable/shared",
field_name="test_field")
def test_get_anonymous(self):
self._run_test('GET', 401, None, {})
def test_get_freshuser(self):
self._run_test('GET', 403, 'freshuser', {})
def test_get_reader(self):
self._run_test('GET', 403, 'reader', {})
def test_get_devtable(self):
self._run_test('GET', 404, 'devtable', {'config': {}})
class TestBuildTriggerFieldValuesSwo1BuynlargeOrgrepo(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(BuildTriggerFieldValues, trigger_uuid="SWO1", repository="buynlarge/orgrepo",
field_name="test_field")
def test_get_anonymous(self):
self._run_test('GET', 401, None, {})
def test_get_freshuser(self):
self._run_test('GET', 403, 'freshuser', {})
def test_get_reader(self):
self._run_test('GET', 403, 'reader', {})
def test_get_devtable(self):
self._run_test('GET', 404, 'devtable', {'config': {}})
class TestBuildTriggerSources831cPublicPublicrepo(ApiTestCase):
def setUp(self):
@ -1292,7 +1353,7 @@ class TestActivateBuildTrigger0byeDevtableShared(ApiTestCase):
self._run_test('POST', 403, 'reader', None)
def test_post_devtable(self):
self._run_test('POST', 404, 'devtable', None)
self._run_test('POST', 404, 'devtable', {})
class TestActivateBuildTrigger0byeBuynlargeOrgrepo(ApiTestCase):
@ -1310,7 +1371,7 @@ class TestActivateBuildTrigger0byeBuynlargeOrgrepo(ApiTestCase):
self._run_test('POST', 403, 'reader', None)
def test_post_devtable(self):
self._run_test('POST', 404, 'devtable', None)
self._run_test('POST', 404, 'devtable', {})
class TestBuildTriggerAnalyze0byePublicPublicrepo(ApiTestCase):
@ -3527,13 +3588,61 @@ class TestSuperUserLogs(ApiTestCase):
self._run_test('GET', 200, 'devtable', None)
class TestSuperUserSendRecoveryEmail(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(SuperUserSendRecoveryEmail, username='someuser')
def test_post_anonymous(self):
self._run_test('POST', 401, None, None)
def test_post_freshuser(self):
self._run_test('POST', 403, 'freshuser', None)
def test_post_reader(self):
self._run_test('POST', 403, 'reader', None)
def test_post_devtable(self):
self._run_test('POST', 404, 'devtable', None)
class TestTeamMemberInvite(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(TeamMemberInvite, code='foobarbaz')
def test_put_anonymous(self):
self._run_test('PUT', 401, None, None)
def test_put_freshuser(self):
self._run_test('PUT', 400, 'freshuser', None)
def test_put_reader(self):
self._run_test('PUT', 400, 'reader', None)
def test_put_devtable(self):
self._run_test('PUT', 400, 'devtable', None)
def test_delete_anonymous(self):
self._run_test('DELETE', 401, None, None)
def test_delete_freshuser(self):
self._run_test('DELETE', 400, 'freshuser', None)
def test_delete_reader(self):
self._run_test('DELETE', 400, 'reader', None)
def test_delete_devtable(self):
self._run_test('DELETE', 400, 'devtable', None)
class TestSuperUserList(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(SuperUserList)
def test_get_anonymous(self):
self._run_test('GET', 403, None, None)
self._run_test('GET', 401, None, None)
def test_get_freshuser(self):
self._run_test('GET', 403, 'freshuser', None)
@ -3545,14 +3654,13 @@ class TestSuperUserList(ApiTestCase):
self._run_test('GET', 200, 'devtable', None)
class TestSuperUserManagement(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(SuperUserManagement, username='freshuser')
def test_get_anonymous(self):
self._run_test('GET', 403, None, None)
self._run_test('GET', 401, None, None)
def test_get_freshuser(self):
self._run_test('GET', 403, 'freshuser', None)
@ -3565,7 +3673,7 @@ class TestSuperUserManagement(ApiTestCase):
def test_put_anonymous(self):
self._run_test('PUT', 403, None, {})
self._run_test('PUT', 401, None, {})
def test_put_freshuser(self):
self._run_test('PUT', 403, 'freshuser', {})
@ -3578,7 +3686,7 @@ class TestSuperUserManagement(ApiTestCase):
def test_delete_anonymous(self):
self._run_test('DELETE', 403, None, None)
self._run_test('DELETE', 401, None, None)
def test_delete_freshuser(self):
self._run_test('DELETE', 403, 'freshuser', None)

View file

@ -1,3 +1,5 @@
# coding=utf-8
import unittest
import json as py_json
@ -11,7 +13,7 @@ from app import app
from initdb import setup_database_for_testing, finished_database_for_testing
from data import model, database
from endpoints.api.team import TeamMember, TeamMemberList, OrganizationTeam
from endpoints.api.team import TeamMember, TeamMemberList, TeamMemberInvite, OrganizationTeam
from endpoints.api.tag import RepositoryTagImages, RepositoryTag
from endpoints.api.search import FindRepositories, EntitySearch
from endpoints.api.image import RepositoryImage, RepositoryImageList
@ -20,7 +22,7 @@ from endpoints.api.robot import (UserRobotList, OrgRobot, OrgRobotList, UserRobo
RegenerateUserRobot, RegenerateOrgRobot)
from endpoints.api.trigger import (BuildTriggerActivate, BuildTriggerSources, BuildTriggerSubdirs,
TriggerBuildList, ActivateBuildTrigger, BuildTrigger,
BuildTriggerList, BuildTriggerAnalyze)
BuildTriggerList, BuildTriggerAnalyze, BuildTriggerFieldValues)
from endpoints.api.repoemail import RepositoryAuthorizedEmail
from endpoints.api.repositorynotification import RepositoryNotification, RepositoryNotificationList
from endpoints.api.user import (PrivateRepositories, ConvertToOrganization, Signout, Signin, User,
@ -131,6 +133,10 @@ class ApiTestCase(unittest.TestCase):
def deleteResponse(self, resource_name, params={}, expected_code=204):
rv = self.app.delete(self.url_for(resource_name, params))
if rv.status_code != expected_code:
print 'Mismatch data for resource DELETE %s: %s' % (resource_name, rv.data)
self.assertEquals(rv.status_code, expected_code)
return rv.data
@ -162,6 +168,13 @@ class ApiTestCase(unittest.TestCase):
parsed = py_json.loads(data)
return parsed
def assertInTeam(self, data, membername):
for memberData in data['members']:
if memberData['name'] == membername:
return
self.fail(membername + ' not found in team: ' + py_json.dumps(data))
def login(self, username, password='password'):
return self.postJsonResponse(Signin, data=dict(username=username, password=password))
@ -328,6 +341,12 @@ class TestChangeUserDetails(ApiTestCase):
data=dict(password='newpasswordiscool'))
self.login(READ_ACCESS_USER, password='newpasswordiscool')
def test_changepassword_unicode(self):
self.login(READ_ACCESS_USER)
self.putJsonResponse(User,
data=dict(password=u'someunicode北京市pass'))
self.login(READ_ACCESS_USER, password=u'someunicode北京市pass')
def test_changeeemail(self):
self.login(READ_ACCESS_USER)
@ -375,10 +394,30 @@ class TestCreateNewUser(ApiTestCase):
self.assertEquals('Invalid username auserName: Username must match expression [a-z0-9_]+', json['error_description'])
def test_createuser(self):
data = self.postResponse(User,
data = self.postJsonResponse(User,
data=NEW_USER_DETAILS,
expected_code=201)
self.assertEquals('"Created"', data)
expected_code=200)
self.assertEquals(True, data['awaiting_verification'])
def test_createuser_withteaminvite(self):
inviter = model.get_user(ADMIN_ACCESS_USER)
team = model.get_organization_team(ORGANIZATION, 'owners')
invite = model.add_or_invite_to_team(inviter, team, None, 'foo@example.com')
details = {
'invite_code': invite.invite_token
}
details.update(NEW_USER_DETAILS);
data = self.postJsonResponse(User, data=details, expected_code=200)
self.assertEquals(True, data['awaiting_verification'])
# Make sure the user was added to the team.
self.login(ADMIN_ACCESS_USER)
json = self.getJsonResponse(TeamMemberList,
params=dict(orgname=ORGANIZATION,
teamname='owners'))
self.assertInTeam(json, NEW_USER_DETAILS['username'])
class TestSignout(ApiTestCase):
@ -741,16 +780,43 @@ class TestGetOrganizationTeamMembers(ApiTestCase):
params=dict(orgname=ORGANIZATION,
teamname='readers'))
assert READ_ACCESS_USER in json['members']
self.assertEquals(READ_ACCESS_USER, json['members'][1]['name'])
class TestUpdateOrganizationTeamMember(ApiTestCase):
def test_addmember(self):
def test_addmember_alreadyteammember(self):
self.login(ADMIN_ACCESS_USER)
membername = READ_ACCESS_USER
self.putResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='readers',
membername=membername),
expected_code=400)
def test_addmember_orgmember(self):
self.login(ADMIN_ACCESS_USER)
membername = READ_ACCESS_USER
self.putJsonResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='owners',
membername=membername))
# Verify the user was added to the team.
json = self.getJsonResponse(TeamMemberList,
params=dict(orgname=ORGANIZATION,
teamname='owners'))
self.assertInTeam(json, membername)
def test_addmember_robot(self):
self.login(ADMIN_ACCESS_USER)
membername = ORGANIZATION + '+coolrobot'
self.putJsonResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='readers',
membername=NO_ACCESS_USER))
membername=membername))
# Verify the user was added to the team.
@ -758,10 +824,168 @@ class TestUpdateOrganizationTeamMember(ApiTestCase):
params=dict(orgname=ORGANIZATION,
teamname='readers'))
assert NO_ACCESS_USER in json['members']
self.assertInTeam(json, membername)
def test_addmember_invalidrobot(self):
self.login(ADMIN_ACCESS_USER)
membername = 'freshuser+anotherrobot'
self.putResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='readers',
membername=membername),
expected_code=400)
def test_addmember_nonorgmember(self):
self.login(ADMIN_ACCESS_USER)
membername = NO_ACCESS_USER
response = self.putJsonResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='owners',
membername=membername))
self.assertEquals(True, response['invited'])
# Make sure the user is not (yet) part of the team.
json = self.getJsonResponse(TeamMemberList,
params=dict(orgname=ORGANIZATION,
teamname='readers'))
for member in json['members']:
self.assertNotEqual(membername, member['name'])
class TestAcceptTeamMemberInvite(ApiTestCase):
def assertInTeam(self, data, membername):
for memberData in data['members']:
if memberData['name'] == membername:
return
self.fail(membername + ' not found in team: ' + json.dumps(data))
def test_accept(self):
self.login(ADMIN_ACCESS_USER)
# Create the invite.
membername = NO_ACCESS_USER
response = self.putJsonResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='owners',
membername=membername))
self.assertEquals(True, response['invited'])
# Login as the user.
self.login(membername)
# Accept the invite.
user = model.get_user(membername)
invites = list(model.lookup_team_invites(user))
self.assertEquals(1, len(invites))
self.putJsonResponse(TeamMemberInvite,
params=dict(code=invites[0].invite_token))
# Verify the user is now on the team.
json = self.getJsonResponse(TeamMemberList,
params=dict(orgname=ORGANIZATION,
teamname='owners'))
self.assertInTeam(json, membername)
# Verify the accept now fails.
self.putResponse(TeamMemberInvite,
params=dict(code=invites[0].invite_token),
expected_code=400)
class TestDeclineTeamMemberInvite(ApiTestCase):
def test_decline_wronguser(self):
self.login(ADMIN_ACCESS_USER)
# Create the invite.
membername = NO_ACCESS_USER
response = self.putJsonResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='owners',
membername=membername))
self.assertEquals(True, response['invited'])
# Try to decline the invite.
user = model.get_user(membername)
invites = list(model.lookup_team_invites(user))
self.assertEquals(1, len(invites))
self.deleteResponse(TeamMemberInvite,
params=dict(code=invites[0].invite_token),
expected_code=400)
def test_decline(self):
self.login(ADMIN_ACCESS_USER)
# Create the invite.
membername = NO_ACCESS_USER
response = self.putJsonResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='owners',
membername=membername))
self.assertEquals(True, response['invited'])
# Login as the user.
self.login(membername)
# Decline the invite.
user = model.get_user(membername)
invites = list(model.lookup_team_invites(user))
self.assertEquals(1, len(invites))
self.deleteResponse(TeamMemberInvite,
params=dict(code=invites[0].invite_token))
# Make sure the invite was deleted.
self.deleteResponse(TeamMemberInvite,
params=dict(code=invites[0].invite_token),
expected_code=400)
class TestDeleteOrganizationTeamMember(ApiTestCase):
def test_deletememberinvite(self):
self.login(ADMIN_ACCESS_USER)
membername = NO_ACCESS_USER
response = self.putJsonResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='readers',
membername=membername))
self.assertEquals(True, response['invited'])
# Verify the invite was added.
json = self.getJsonResponse(TeamMemberList,
params=dict(orgname=ORGANIZATION,
teamname='readers',
includePending=True))
assert len(json['members']) == 3
# Delete the invite.
self.deleteResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='readers',
membername=membername))
# Verify the user was removed from the team.
json = self.getJsonResponse(TeamMemberList,
params=dict(orgname=ORGANIZATION,
teamname='readers',
includePending=True))
assert len(json['members']) == 2
def test_deletemember(self):
self.login(ADMIN_ACCESS_USER)
@ -775,7 +999,7 @@ class TestDeleteOrganizationTeamMember(ApiTestCase):
params=dict(orgname=ORGANIZATION,
teamname='readers'))
assert not READ_ACCESS_USER in json['members']
assert len(json['members']) == 1
class TestCreateRepo(ApiTestCase):
@ -1205,6 +1429,7 @@ class TestListAndGetImage(ApiTestCase):
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
assert len(json['images']) > 0
for image in json['images']:
assert 'id' in image
assert 'tags' in image
@ -1212,7 +1437,6 @@ class TestListAndGetImage(ApiTestCase):
assert 'comment' in image
assert 'command' in image
assert 'ancestors' in image
assert 'dbid' in image
assert 'size' in image
ijson = self.getJsonResponse(RepositoryImage,
@ -1810,7 +2034,7 @@ class FakeBuildTrigger(BuildTriggerBase):
config['active'] = False
return config
def manual_start(self, auth_token, config):
def manual_start(self, auth_token, config, run_parameters=None):
return ('foo', ['bar'], 'build-name', 'subdir')
def dockerfile_url(self, auth_token, config):
@ -1822,6 +2046,12 @@ class FakeBuildTrigger(BuildTriggerBase):
return config['dockerfile']
def list_field_values(self, auth_token, config, field_name):
if field_name == 'test_field':
return [1, 2, 3]
return None
class TestBuildTriggers(ApiTestCase):
def test_list_build_triggers(self):
@ -1994,9 +2224,22 @@ class TestBuildTriggers(ApiTestCase):
data={'config': trigger_config},
expected_code=400)
# Retrieve values for a field.
result = self.getJsonResponse(BuildTriggerFieldValues,
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
trigger_uuid=trigger.uuid, field_name="test_field"))
self.assertEquals(result['values'], [1, 2, 3])
self.getResponse(BuildTriggerFieldValues,
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
trigger_uuid=trigger.uuid, field_name="another_field"),
expected_code = 404)
# Start a manual build.
start_json = self.postJsonResponse(ActivateBuildTrigger,
params=dict(repository=ADMIN_ACCESS_USER + '/simple', trigger_uuid=trigger.uuid),
data=dict(),
expected_code=201)
assert 'id' in start_json
@ -2061,6 +2304,7 @@ class TestBuildTriggers(ApiTestCase):
# Start a manual build.
start_json = self.postJsonResponse(ActivateBuildTrigger,
params=dict(repository=ADMIN_ACCESS_USER + '/simple', trigger_uuid=trigger.uuid),
data=dict(),
expected_code=201)
assert 'id' in start_json
@ -2120,7 +2364,7 @@ class TestSuperUserManagement(ApiTestCase):
json = self.getJsonResponse(SuperUserManagement, params=dict(username = 'freshuser'))
self.assertEquals('freshuser', json['username'])
self.assertEquals('no@thanks.com', json['email'])
self.assertEquals('jschorr+test@devtable.com', json['email'])
self.assertEquals(False, json['super_user'])
def test_delete_user(self):
@ -2143,7 +2387,7 @@ class TestSuperUserManagement(ApiTestCase):
# Verify the user exists.
json = self.getJsonResponse(SuperUserManagement, params=dict(username = 'freshuser'))
self.assertEquals('freshuser', json['username'])
self.assertEquals('no@thanks.com', json['email'])
self.assertEquals('jschorr+test@devtable.com', json['email'])
# Update the user.
self.putJsonResponse(SuperUserManagement, params=dict(username='freshuser'), data=dict(email='foo@bar.com'))

View file

@ -34,6 +34,7 @@ class TestConfig(DefaultConfig):
FEATURE_SUPER_USERS = True
FEATURE_BILLING = True
FEATURE_MAILING = True
SUPER_USERS = ['devtable']
LICENSE_USER_LIMIT = 500

View file

@ -45,8 +45,8 @@ class TestBuildLogs(RedisBuildLogs):
'pull_completion': 0.0,
}
def __init__(self, redis_host, namespace, repository, test_build_id, allow_delegate=True):
super(TestBuildLogs, self).__init__(redis_host)
def __init__(self, redis_config, namespace, repository, test_build_id, allow_delegate=True):
super(TestBuildLogs, self).__init__(redis_config)
self.namespace = namespace
self.repository = repository
self.test_build_id = test_build_id