c604dbd0f6
Fixes #1366
3612 lines
132 KiB
Python
3612 lines
132 KiB
Python
# coding=utf-8
|
|
|
|
import unittest
|
|
import datetime
|
|
import logging
|
|
import re
|
|
import json as py_json
|
|
|
|
from StringIO import StringIO
|
|
from urllib import urlencode
|
|
from urlparse import urlparse, urlunparse, parse_qs
|
|
|
|
from playhouse.test_utils import assert_query_count, _QueryLogHandler
|
|
from httmock import urlmatch, HTTMock
|
|
|
|
from endpoints.api import api_bp, api
|
|
from endpoints.building import PreparedBuild
|
|
from endpoints.webhooks import webhooks
|
|
from app import app, config_provider
|
|
from buildtrigger.basehandler import BuildTriggerHandler
|
|
from initdb import setup_database_for_testing, finished_database_for_testing
|
|
from data import database, model
|
|
from data.database import RepositoryActionCount
|
|
|
|
from endpoints.api.team import TeamMember, TeamMemberList, TeamMemberInvite, OrganizationTeam
|
|
from endpoints.api.tag import RepositoryTagImages, RepositoryTag, RevertTag, ListRepositoryTags
|
|
from endpoints.api.search import EntitySearch, ConductSearch
|
|
from endpoints.api.image import RepositoryImage, RepositoryImageList
|
|
from endpoints.api.build import RepositoryBuildStatus, RepositoryBuildList, RepositoryBuildResource
|
|
from endpoints.api.robot import (UserRobotList, OrgRobot, OrgRobotList, UserRobot,
|
|
RegenerateUserRobot, RegenerateOrgRobot)
|
|
from endpoints.api.trigger import (BuildTriggerActivate, BuildTriggerSources, BuildTriggerSubdirs,
|
|
TriggerBuildList, ActivateBuildTrigger, BuildTrigger,
|
|
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,
|
|
UserAuthorizationList, UserAuthorization, UserNotification,
|
|
UserNotificationList, StarredRepositoryList, StarredRepository)
|
|
|
|
from endpoints.api.repotoken import RepositoryToken, RepositoryTokenList
|
|
from endpoints.api.prototype import PermissionPrototype, PermissionPrototypeList
|
|
from endpoints.api.logs import UserLogs, OrgLogs, OrgAggregateLogs, UserAggregateLogs
|
|
from endpoints.api.billing import (UserCard, UserPlan, ListPlans, OrganizationCard,
|
|
OrganizationPlan)
|
|
from endpoints.api.discovery import DiscoveryResource
|
|
from endpoints.api.error import Error
|
|
from endpoints.api.organization import (OrganizationList, OrganizationMember,
|
|
OrgPrivateRepositories, OrganizationMemberList,
|
|
Organization, ApplicationInformation,
|
|
OrganizationApplications, OrganizationApplicationResource,
|
|
OrganizationApplicationResetClientSecret, Organization)
|
|
from endpoints.api.repository import RepositoryList, RepositoryVisibility, Repository
|
|
from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPermission,
|
|
RepositoryTeamPermissionList, RepositoryUserPermissionList)
|
|
from endpoints.api.superuser import SuperUserLogs, SuperUserList, SuperUserManagement
|
|
from endpoints.api.secscan import RepositoryImageSecurity
|
|
from endpoints.api.suconfig import (SuperUserRegistryStatus, SuperUserConfig, SuperUserConfigFile,
|
|
SuperUserCreateInitialSuperUser)
|
|
|
|
try:
|
|
app.register_blueprint(api_bp, url_prefix='/api')
|
|
except ValueError:
|
|
# This blueprint was already registered
|
|
pass
|
|
|
|
app.register_blueprint(webhooks, url_prefix='/webhooks')
|
|
|
|
# The number of queries we run for guests on API calls.
|
|
BASE_QUERY_COUNT = 0
|
|
|
|
# The number of queries we run for logged in users on API calls.
|
|
BASE_LOGGEDIN_QUERY_COUNT = BASE_QUERY_COUNT + 1
|
|
|
|
# The number of queries we run for logged in users on API calls that check
|
|
# access permissions.
|
|
BASE_PERM_ACCESS_QUERY_COUNT = BASE_LOGGEDIN_QUERY_COUNT + 2
|
|
|
|
NO_ACCESS_USER = 'freshuser'
|
|
READ_ACCESS_USER = 'reader'
|
|
ADMIN_ACCESS_USER = 'devtable'
|
|
PUBLIC_USER = 'public'
|
|
|
|
ADMIN_ACCESS_EMAIL = 'jschorr@devtable.com'
|
|
|
|
ORG_REPO = 'orgrepo'
|
|
|
|
ORGANIZATION = 'buynlarge'
|
|
|
|
NEW_USER_DETAILS = {
|
|
'username': 'bobby',
|
|
'password': 'password',
|
|
'email': 'bobby@tables.com',
|
|
}
|
|
|
|
FAKE_APPLICATION_CLIENT_ID = 'deadbeef'
|
|
|
|
CSRF_TOKEN_KEY = '_csrf_token'
|
|
CSRF_TOKEN = '123csrfforme'
|
|
|
|
class ApiTestCase(unittest.TestCase):
|
|
maxDiff = None
|
|
|
|
@staticmethod
|
|
def _add_csrf(without_csrf):
|
|
parts = urlparse(without_csrf)
|
|
query = parse_qs(parts[4])
|
|
query[CSRF_TOKEN_KEY] = CSRF_TOKEN
|
|
return urlunparse(list(parts[0:4]) + [urlencode(query)] + list(parts[5:]))
|
|
|
|
def url_for(self, resource_name, params={}):
|
|
url = api.url_for(resource_name, **params)
|
|
url = ApiTestCase._add_csrf(url)
|
|
return url
|
|
|
|
def setUp(self):
|
|
setup_database_for_testing(self)
|
|
self.app = app.test_client()
|
|
self.ctx = app.test_request_context()
|
|
self.ctx.__enter__()
|
|
self.setCsrfToken(CSRF_TOKEN)
|
|
|
|
def tearDown(self):
|
|
finished_database_for_testing(self)
|
|
config_provider.clear()
|
|
self.ctx.__exit__(True, None, None)
|
|
|
|
def setCsrfToken(self, token):
|
|
with self.app.session_transaction() as sess:
|
|
sess[CSRF_TOKEN_KEY] = token
|
|
|
|
def getJsonResponse(self, resource_name, params={}, expected_code=200):
|
|
rv = self.app.get(api.url_for(resource_name, **params))
|
|
self.assertEquals(expected_code, rv.status_code)
|
|
data = rv.data
|
|
parsed = py_json.loads(data)
|
|
return parsed
|
|
|
|
def postResponse(self, resource_name, params={}, data={}, file=None, expected_code=200):
|
|
data = py_json.dumps(data)
|
|
headers = {"Content-Type": "application/json"}
|
|
|
|
if file is not None:
|
|
data = {'file': file}
|
|
headers = None
|
|
|
|
rv = self.app.post(self.url_for(resource_name, params), data=data, headers=headers)
|
|
self.assertEquals(rv.status_code, expected_code)
|
|
return rv.data
|
|
|
|
def getResponse(self, resource_name, params={}, expected_code=200):
|
|
rv = self.app.get(api.url_for(resource_name, **params))
|
|
self.assertEquals(rv.status_code, expected_code)
|
|
return rv.data
|
|
|
|
def putResponse(self, resource_name, params={}, data={}, expected_code=200):
|
|
rv = self.app.put(self.url_for(resource_name, params),
|
|
data=py_json.dumps(data),
|
|
headers={"Content-Type": "application/json"})
|
|
self.assertEquals(rv.status_code, expected_code)
|
|
return rv.data
|
|
|
|
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
|
|
|
|
def postJsonResponse(self, resource_name, params={}, data={},
|
|
expected_code=200):
|
|
rv = self.app.post(self.url_for(resource_name, params),
|
|
data=py_json.dumps(data),
|
|
headers={"Content-Type": "application/json"})
|
|
|
|
if rv.status_code != expected_code:
|
|
print 'Mismatch data for resource POST %s: %s' % (resource_name, rv.data)
|
|
|
|
self.assertEquals(rv.status_code, expected_code)
|
|
data = rv.data
|
|
parsed = py_json.loads(data)
|
|
return parsed
|
|
|
|
def putJsonResponse(self, resource_name, params={}, data={},
|
|
expected_code=200):
|
|
rv = self.app.put(self.url_for(resource_name, params),
|
|
data=py_json.dumps(data),
|
|
headers={"Content-Type": "application/json"})
|
|
|
|
if rv.status_code != expected_code:
|
|
print 'Mismatch data for resource PUT %s: %s' % (resource_name, rv.data)
|
|
|
|
self.assertEquals(rv.status_code, expected_code)
|
|
data = rv.data
|
|
parsed = py_json.loads(data)
|
|
return parsed
|
|
|
|
|
|
def assertNotInTeam(self, data, membername):
|
|
for memberData in data['members']:
|
|
if memberData['name'] == membername:
|
|
self.fail(membername + ' found in team: ' + json.dumps(data))
|
|
|
|
def assertInTeam(self, data, membername):
|
|
for member_data in data['members']:
|
|
if member_data['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))
|
|
|
|
|
|
class TestCSRFFailure(ApiTestCase):
|
|
def test_csrf_failure(self):
|
|
self.login(READ_ACCESS_USER)
|
|
|
|
# Make sure a simple post call succeeds.
|
|
self.putJsonResponse(User,
|
|
data=dict(password='newpasswordiscool'))
|
|
|
|
# Change the session's CSRF token.
|
|
self.setCsrfToken('someinvalidtoken')
|
|
|
|
# Verify that the call now fails.
|
|
self.putJsonResponse(User,
|
|
data=dict(password='newpasswordiscool'),
|
|
expected_code=403)
|
|
|
|
|
|
class TestDiscovery(ApiTestCase):
|
|
def test_discovery(self):
|
|
json = self.getJsonResponse(DiscoveryResource)
|
|
assert 'paths' in json
|
|
|
|
|
|
class TestErrorDescription(ApiTestCase):
|
|
def test_get_error(self):
|
|
json = self.getJsonResponse(Error, params=dict(error_type='not_found'))
|
|
assert json['title'] == 'not_found'
|
|
assert 'type' in json
|
|
assert 'description' in json
|
|
|
|
|
|
class TestPlans(ApiTestCase):
|
|
def test_plans(self):
|
|
json = self.getJsonResponse(ListPlans)
|
|
found = set([])
|
|
for method_info in json['plans']:
|
|
found.add(method_info['stripeId'])
|
|
|
|
assert 'free' in found
|
|
|
|
|
|
class TestLoggedInUser(ApiTestCase):
|
|
def test_guest(self):
|
|
self.getJsonResponse(User, expected_code=401)
|
|
|
|
def test_user(self):
|
|
self.login(READ_ACCESS_USER)
|
|
json = self.getJsonResponse(User)
|
|
assert json['anonymous'] == False
|
|
assert json['username'] == READ_ACCESS_USER
|
|
|
|
|
|
class TestUserStarredRepositoryList(ApiTestCase):
|
|
def test_get_stars_guest(self):
|
|
self.getJsonResponse(StarredRepositoryList, expected_code=401)
|
|
|
|
def test_get_stars_user(self):
|
|
self.login(READ_ACCESS_USER)
|
|
|
|
# Queries: Base + the list query
|
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 1):
|
|
self.getJsonResponse(StarredRepositoryList, expected_code=200)
|
|
|
|
def test_star_repo_guest(self):
|
|
self.postJsonResponse(StarredRepositoryList,
|
|
data={
|
|
'namespace': 'public',
|
|
'repository': 'publicrepo',
|
|
},
|
|
expected_code=401)
|
|
|
|
def test_star_and_unstar_repo_user(self):
|
|
self.login(READ_ACCESS_USER)
|
|
|
|
# Queries: Base + the list query
|
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 1):
|
|
json = self.getJsonResponse(StarredRepositoryList)
|
|
assert json['repositories'] == []
|
|
|
|
json = self.postJsonResponse(StarredRepositoryList,
|
|
data={
|
|
'namespace': 'public',
|
|
'repository': 'publicrepo',
|
|
},
|
|
expected_code=201)
|
|
assert json['namespace'] == 'public'
|
|
assert json['repository'] == 'publicrepo'
|
|
|
|
self.deleteResponse(StarredRepository, params=dict(repository='public/publicrepo'),
|
|
expected_code=204)
|
|
|
|
json = self.getJsonResponse(StarredRepositoryList)
|
|
assert json['repositories'] == []
|
|
|
|
|
|
class TestUserNotification(ApiTestCase):
|
|
def test_get(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.getJsonResponse(UserNotificationList)
|
|
|
|
# Make sure each notification can be retrieved.
|
|
for notification in json['notifications']:
|
|
njson = self.getJsonResponse(UserNotification, params=dict(uuid=notification['id']))
|
|
self.assertEquals(notification['id'], njson['id'])
|
|
|
|
# Update a notification.
|
|
assert json['notifications']
|
|
assert not json['notifications'][0]['dismissed']
|
|
|
|
notification = json['notifications'][0]
|
|
pjson = self.putJsonResponse(UserNotification, params=dict(uuid=notification['id']),
|
|
data=dict(dismissed=True))
|
|
|
|
self.assertEquals(True, pjson['dismissed'])
|
|
|
|
def test_org_notifications(self):
|
|
# Create a notification on the organization.
|
|
org = model.user.get_user_or_org(ORGANIZATION)
|
|
model.notification.create_notification('test_notification', org, {'org': 'notification'})
|
|
|
|
# Ensure it is visible to the org admin.
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.getJsonResponse(UserNotificationList)
|
|
notification = json['notifications'][0]
|
|
|
|
self.assertEquals(notification['kind'], 'test_notification')
|
|
self.assertEquals(notification['metadata'], {'org': 'notification'})
|
|
|
|
# Ensure it is not visible to an org member.
|
|
self.login(READ_ACCESS_USER)
|
|
json = self.getJsonResponse(UserNotificationList)
|
|
self.assertEquals(0, len(json['notifications']))
|
|
|
|
|
|
class TestGetUserPrivateAllowed(ApiTestCase):
|
|
def test_nonallowed(self):
|
|
self.login(READ_ACCESS_USER)
|
|
json = self.getJsonResponse(PrivateRepositories)
|
|
assert json['privateCount'] == 0
|
|
assert not json['privateAllowed']
|
|
|
|
def test_allowed(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Change the subscription of the namespace.
|
|
self.putJsonResponse(UserPlan, data=dict(plan='personal-30'))
|
|
|
|
json = self.getJsonResponse(PrivateRepositories)
|
|
assert json['privateCount'] >= 6
|
|
assert not json['privateAllowed']
|
|
|
|
# Change the subscription of the namespace.
|
|
self.putJsonResponse(UserPlan, data=dict(plan='bus-large-30'))
|
|
|
|
json = self.getJsonResponse(PrivateRepositories)
|
|
assert json['privateAllowed']
|
|
|
|
|
|
class TestConvertToOrganization(ApiTestCase):
|
|
def test_sameadminuser(self):
|
|
self.login(READ_ACCESS_USER)
|
|
json = self.postJsonResponse(ConvertToOrganization,
|
|
data={'adminUser': READ_ACCESS_USER,
|
|
'adminPassword': 'password',
|
|
'plan': 'free'},
|
|
expected_code=400)
|
|
|
|
self.assertEqual('The admin user is not valid', json['detail'])
|
|
|
|
def test_sameadminuser_by_email(self):
|
|
self.login(READ_ACCESS_USER)
|
|
json = self.postJsonResponse(ConvertToOrganization,
|
|
data={'adminUser': 'no1@thanks.com',
|
|
'adminPassword': 'password',
|
|
'plan': 'free'},
|
|
expected_code=400)
|
|
|
|
self.assertEqual('The admin user is not valid', json['detail'])
|
|
|
|
def test_invalidadminuser(self):
|
|
self.login(READ_ACCESS_USER)
|
|
json = self.postJsonResponse(ConvertToOrganization,
|
|
data={'adminUser': 'unknownuser',
|
|
'adminPassword': 'password',
|
|
'plan': 'free'},
|
|
expected_code=400)
|
|
|
|
self.assertEqual('The admin user credentials are not valid',
|
|
json['detail'])
|
|
|
|
def test_invalidadminpassword(self):
|
|
self.login(READ_ACCESS_USER)
|
|
json = self.postJsonResponse(ConvertToOrganization,
|
|
data={'adminUser': ADMIN_ACCESS_USER,
|
|
'adminPassword': 'invalidpass',
|
|
'plan': 'free'},
|
|
expected_code=400)
|
|
|
|
self.assertEqual('The admin user credentials are not valid',
|
|
json['detail'])
|
|
|
|
def test_convert(self):
|
|
self.login(READ_ACCESS_USER)
|
|
|
|
# Add at least one permission for the read-user.
|
|
read_user = model.user.get_user(READ_ACCESS_USER)
|
|
simple_repo = model.repository.get_repository(ADMIN_ACCESS_USER, 'simple')
|
|
read_role = database.Role.get(name='read')
|
|
|
|
database.RepositoryPermission.create(user=read_user, repository=simple_repo, role=read_role)
|
|
|
|
# Convert the read user into an organization.
|
|
json = self.postJsonResponse(ConvertToOrganization,
|
|
data={'adminUser': ADMIN_ACCESS_USER,
|
|
'adminPassword': 'password',
|
|
'plan': 'free'})
|
|
|
|
self.assertEqual(True, json['success'])
|
|
|
|
# Verify the organization exists.
|
|
organization = model.organization.get_organization(READ_ACCESS_USER)
|
|
assert organization is not None
|
|
|
|
# Verify the admin user is the org's admin.
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.getJsonResponse(Organization,
|
|
params=dict(orgname=READ_ACCESS_USER))
|
|
|
|
self.assertEquals(READ_ACCESS_USER, json['name'])
|
|
self.assertEquals(True, json['is_admin'])
|
|
|
|
# Verify the now-org has no permissions.
|
|
count = (database.RepositoryPermission.select()
|
|
.where(database.RepositoryPermission.user == organization)
|
|
.count())
|
|
self.assertEquals(0, count)
|
|
|
|
def test_convert_via_email(self):
|
|
self.login(READ_ACCESS_USER)
|
|
json = self.postJsonResponse(ConvertToOrganization,
|
|
data={'adminUser': ADMIN_ACCESS_EMAIL,
|
|
'adminPassword': 'password',
|
|
'plan': 'free'})
|
|
|
|
self.assertEqual(True, json['success'])
|
|
|
|
# Verify the organization exists.
|
|
organization = model.organization.get_organization(READ_ACCESS_USER)
|
|
assert organization is not None
|
|
|
|
# Verify the admin user is the org's admin.
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.getJsonResponse(Organization,
|
|
params=dict(orgname=READ_ACCESS_USER))
|
|
|
|
self.assertEquals(READ_ACCESS_USER, json['name'])
|
|
self.assertEquals(True, json['is_admin'])
|
|
|
|
|
|
class TestChangeUserDetails(ApiTestCase):
|
|
def test_changepassword(self):
|
|
self.login(READ_ACCESS_USER)
|
|
self.putJsonResponse(User,
|
|
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)
|
|
|
|
self.putJsonResponse(User,
|
|
data=dict(email='test+foo@devtable.com'))
|
|
|
|
def test_changeinvoiceemail(self):
|
|
self.login(READ_ACCESS_USER)
|
|
|
|
json = self.putJsonResponse(User,
|
|
data=dict(invoice_email=True))
|
|
self.assertEquals(True, json['invoice_email'])
|
|
|
|
json = self.putJsonResponse(User,
|
|
data=dict(invoice_email=False))
|
|
self.assertEquals(False, json['invoice_email'])
|
|
|
|
|
|
class TestCreateNewUser(ApiTestCase):
|
|
def test_existingusername(self):
|
|
json = self.postJsonResponse(User,
|
|
data=dict(username=READ_ACCESS_USER,
|
|
password='password',
|
|
email='test@example.com'),
|
|
expected_code=400)
|
|
|
|
self.assertEquals('The username already exists', json['detail'])
|
|
|
|
def test_trycreatetooshort(self):
|
|
json = self.postJsonResponse(User,
|
|
data=dict(username='a',
|
|
password='password',
|
|
email='test@example.com'),
|
|
expected_code=400)
|
|
|
|
self.assertEquals('Invalid username a: Username must be between 4 and 30 characters in length',
|
|
json['detail'])
|
|
|
|
def test_trycreateregexmismatch(self):
|
|
json = self.postJsonResponse(User,
|
|
data=dict(username='auserName',
|
|
password='password',
|
|
email='test@example.com'),
|
|
expected_code=400)
|
|
|
|
self.assertEquals('Invalid username auserName: Username must match expression [a-z0-9_]+',
|
|
json['detail'])
|
|
|
|
def test_createuser(self):
|
|
data = self.postJsonResponse(User, data=NEW_USER_DETAILS, expected_code=200)
|
|
self.assertEquals(True, data['awaiting_verification'])
|
|
|
|
def test_createuser_withteaminvite(self):
|
|
inviter = model.user.get_user(ADMIN_ACCESS_USER)
|
|
team = model.team.get_organization_team(ORGANIZATION, 'owners')
|
|
invite = model.team.add_or_invite_to_team(inviter, team, None, NEW_USER_DETAILS['email'])
|
|
|
|
details = {
|
|
'invite_code': invite.invite_token
|
|
}
|
|
details.update(NEW_USER_DETAILS)
|
|
|
|
data = self.postJsonResponse(User, data=details, expected_code=200)
|
|
|
|
# Make sure the user is verified since the email address of the user matches
|
|
# that of the team invite.
|
|
self.assertFalse('awaiting_verification' in data)
|
|
|
|
# Make sure the user was not (yet) added to the team.
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.getJsonResponse(TeamMemberList,
|
|
params=dict(orgname=ORGANIZATION,
|
|
teamname='owners'))
|
|
self.assertNotInTeam(json, NEW_USER_DETAILS['username'])
|
|
|
|
|
|
def test_createuser_withteaminvite_differentemails(self):
|
|
inviter = model.user.get_user(ADMIN_ACCESS_USER)
|
|
team = model.team.get_organization_team(ORGANIZATION, 'owners')
|
|
invite = model.team.add_or_invite_to_team(inviter, team, None, 'differentemail@example.com')
|
|
|
|
details = {
|
|
'invite_code': invite.invite_token
|
|
}
|
|
details.update(NEW_USER_DETAILS)
|
|
|
|
data = self.postJsonResponse(User, data=details, expected_code=200)
|
|
|
|
# Make sure the user is *not* verified since the email address of the user
|
|
# does not match that of the team invite.
|
|
self.assertTrue(data['awaiting_verification'])
|
|
|
|
# Make sure the user was not (yet) added to the team.
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.getJsonResponse(TeamMemberList,
|
|
params=dict(orgname=ORGANIZATION,
|
|
teamname='owners'))
|
|
self.assertNotInTeam(json, NEW_USER_DETAILS['username'])
|
|
|
|
|
|
|
|
class TestSignin(ApiTestCase):
|
|
def test_signin_unicode(self):
|
|
self.postResponse(Signin, data=dict(username=u'\xe5\x8c\x97\xe4\xba\xac\xe5\xb8\x82',
|
|
password='password'), expected_code=403)
|
|
|
|
def test_signin_invitecode(self):
|
|
# Create a new user (unverified)
|
|
data = self.postJsonResponse(User, data=NEW_USER_DETAILS, expected_code=200)
|
|
self.assertTrue(data['awaiting_verification'])
|
|
|
|
# Try to sign in without an invite code.
|
|
data = self.postJsonResponse(Signin, data=NEW_USER_DETAILS, expected_code=403)
|
|
self.assertTrue(data['needsEmailVerification'])
|
|
|
|
# Try to sign in with an invalid invite code.
|
|
details = {
|
|
'invite_code': 'someinvalidcode'
|
|
}
|
|
details.update(NEW_USER_DETAILS)
|
|
|
|
data = self.postJsonResponse(Signin, data=details, expected_code=403)
|
|
self.assertTrue(data['needsEmailVerification'])
|
|
|
|
# Sign in with an invite code and ensure the user becomes verified.
|
|
inviter = model.user.get_user(ADMIN_ACCESS_USER)
|
|
team = model.team.get_organization_team(ORGANIZATION, 'owners')
|
|
invite = model.team.add_or_invite_to_team(inviter, team, None, NEW_USER_DETAILS['email'])
|
|
|
|
details = {
|
|
'invite_code': invite.invite_token
|
|
}
|
|
details.update(NEW_USER_DETAILS)
|
|
|
|
data = self.postJsonResponse(Signin, data=details, expected_code=200)
|
|
self.assertFalse('needsEmailVerification' in data)
|
|
|
|
|
|
|
|
class TestSignout(ApiTestCase):
|
|
def test_signout(self):
|
|
self.login(READ_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(User)
|
|
assert json['username'] == READ_ACCESS_USER
|
|
|
|
self.postResponse(Signout)
|
|
|
|
# Make sure we're now signed out.
|
|
self.getJsonResponse(User, expected_code=401)
|
|
|
|
|
|
class TestConductSearch(ApiTestCase):
|
|
def test_noaccess(self):
|
|
self.login(NO_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(ConductSearch,
|
|
params=dict(query='read'))
|
|
|
|
self.assertEquals(0, len(json['results']))
|
|
|
|
json = self.getJsonResponse(ConductSearch,
|
|
params=dict(query='owners'))
|
|
|
|
self.assertEquals(0, len(json['results']))
|
|
|
|
|
|
def test_nouser(self):
|
|
json = self.getJsonResponse(ConductSearch,
|
|
params=dict(query='read'))
|
|
|
|
self.assertEquals(0, len(json['results']))
|
|
|
|
json = self.getJsonResponse(ConductSearch,
|
|
params=dict(query='public'))
|
|
|
|
self.assertEquals(2, len(json['results']))
|
|
self.assertEquals(json['results'][0]['kind'], 'user')
|
|
self.assertEquals(json['results'][0]['name'], 'public')
|
|
|
|
self.assertEquals(json['results'][1]['kind'], 'repository')
|
|
self.assertEquals(json['results'][1]['name'], 'publicrepo')
|
|
|
|
json = self.getJsonResponse(ConductSearch,
|
|
params=dict(query='owners'))
|
|
|
|
self.assertEquals(0, len(json['results']))
|
|
|
|
|
|
def test_orgmember(self):
|
|
self.login(READ_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(ConductSearch,
|
|
params=dict(query='owners'))
|
|
|
|
self.assertEquals(0, len(json['results']))
|
|
|
|
json = self.getJsonResponse(ConductSearch,
|
|
params=dict(query='readers'))
|
|
|
|
self.assertEquals(1, len(json['results']))
|
|
self.assertEquals(json['results'][0]['kind'], 'team')
|
|
self.assertEquals(json['results'][0]['name'], 'readers')
|
|
|
|
|
|
def test_orgadmin(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(ConductSearch,
|
|
params=dict(query='owners'))
|
|
|
|
self.assertEquals(2, len(json['results']))
|
|
self.assertEquals(json['results'][0]['kind'], 'team')
|
|
self.assertEquals(json['results'][0]['name'], 'owners')
|
|
|
|
json = self.getJsonResponse(ConductSearch,
|
|
params=dict(query='readers'))
|
|
|
|
self.assertEquals(1, len(json['results']))
|
|
self.assertEquals(json['results'][0]['kind'], 'team')
|
|
self.assertEquals(json['results'][0]['name'], 'readers')
|
|
|
|
|
|
def test_explicit_permission(self):
|
|
self.login('reader')
|
|
|
|
json = self.getJsonResponse(ConductSearch,
|
|
params=dict(query='shared'))
|
|
|
|
self.assertEquals(1, len(json['results']))
|
|
self.assertEquals(json['results'][0]['kind'], 'repository')
|
|
self.assertEquals(json['results'][0]['name'], 'shared')
|
|
|
|
|
|
class TestGetMatchingEntities(ApiTestCase):
|
|
def test_notinorg(self):
|
|
self.login(NO_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(EntitySearch,
|
|
params=dict(prefix='o', namespace=ORGANIZATION,
|
|
includeTeams='true'))
|
|
|
|
names = set([r['name'] for r in json['results']])
|
|
assert 'outsideorg' in names
|
|
assert not 'owners' in names
|
|
|
|
def test_inorg(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(EntitySearch,
|
|
params=dict(prefix='o', namespace=ORGANIZATION,
|
|
includeTeams='true'))
|
|
|
|
names = set([r['name'] for r in json['results']])
|
|
assert 'outsideorg' in names
|
|
assert 'owners' in names
|
|
|
|
def test_inorg_withorgs(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(EntitySearch,
|
|
params=dict(prefix=ORGANIZATION[0], namespace=ORGANIZATION,
|
|
includeOrgs='true'))
|
|
|
|
names = set([r['name'] for r in json['results']])
|
|
assert ORGANIZATION in names
|
|
|
|
|
|
class TestCreateOrganization(ApiTestCase):
|
|
def test_existinguser(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.postJsonResponse(OrganizationList,
|
|
data=dict(name=ADMIN_ACCESS_USER, email='testorg@example.com'),
|
|
expected_code=400)
|
|
|
|
self.assertEquals('A user or organization with this name already exists',
|
|
json['detail'])
|
|
|
|
def test_existingorg(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.postJsonResponse(OrganizationList,
|
|
data=dict(name=ORGANIZATION, email='testorg@example.com'),
|
|
expected_code=400)
|
|
|
|
self.assertEquals('A user or organization with this name already exists',
|
|
json['detail'])
|
|
|
|
def test_createorg(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
data = self.postResponse(OrganizationList,
|
|
data=dict(name='neworg',
|
|
email='testorg@example.com'),
|
|
expected_code=201)
|
|
|
|
self.assertEquals('"Created"', data)
|
|
|
|
# Ensure the org was created.
|
|
organization = model.organization.get_organization('neworg')
|
|
assert organization is not None
|
|
|
|
# Verify the admin user is the org's admin.
|
|
json = self.getJsonResponse(Organization,
|
|
params=dict(orgname='neworg'))
|
|
self.assertEquals('neworg', json['name'])
|
|
self.assertEquals(True, json['is_admin'])
|
|
|
|
|
|
class TestGetOrganization(ApiTestCase):
|
|
def test_unknownorg(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
self.getResponse(Organization, params=dict(orgname='notvalid'), expected_code=404)
|
|
|
|
def test_cannotaccess(self):
|
|
self.login(NO_ACCESS_USER)
|
|
self.getResponse(Organization, params=dict(orgname=ORGANIZATION), expected_code=200)
|
|
|
|
def test_getorganization(self):
|
|
self.login(READ_ACCESS_USER)
|
|
json = self.getJsonResponse(Organization,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
self.assertEquals(ORGANIZATION, json['name'])
|
|
self.assertEquals(False, json['is_admin'])
|
|
|
|
def test_getorganization_asadmin(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.getJsonResponse(Organization,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
self.assertEquals(ORGANIZATION, json['name'])
|
|
self.assertEquals(True, json['is_admin'])
|
|
|
|
|
|
class TestChangeOrganizationDetails(ApiTestCase):
|
|
def test_changeinvoiceemail(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.putJsonResponse(Organization,
|
|
params=dict(orgname=ORGANIZATION),
|
|
data=dict(invoice_email=True))
|
|
|
|
self.assertEquals(True, json['invoice_email'])
|
|
|
|
json = self.putJsonResponse(Organization,
|
|
params=dict(orgname=ORGANIZATION),
|
|
data=dict(invoice_email=False))
|
|
self.assertEquals(False, json['invoice_email'])
|
|
|
|
|
|
def test_changemail(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.putJsonResponse(Organization,
|
|
params=dict(orgname=ORGANIZATION),
|
|
data=dict(email='newemail@example.com'))
|
|
|
|
self.assertEquals('newemail@example.com', json['email'])
|
|
|
|
|
|
class TestGetOrganizationPrototypes(ApiTestCase):
|
|
def test_getprototypes(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.getJsonResponse(PermissionPrototypeList,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
assert len(json['prototypes']) > 0
|
|
|
|
|
|
class TestCreateOrganizationPrototypes(ApiTestCase):
|
|
def test_invaliduser(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.postJsonResponse(PermissionPrototypeList,
|
|
params=dict(orgname=ORGANIZATION),
|
|
data=dict(activating_user={'name': 'unknownuser'},
|
|
role='read',
|
|
delegate={'kind': 'team', 'name': 'owners'}),
|
|
expected_code=400)
|
|
|
|
self.assertEquals('Unknown activating user', json['detail'])
|
|
|
|
|
|
def test_missingdelegate(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.postJsonResponse(PermissionPrototypeList,
|
|
params=dict(orgname=ORGANIZATION),
|
|
data=dict(role='read'),
|
|
expected_code=400)
|
|
|
|
|
|
def test_createprototype(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.postJsonResponse(PermissionPrototypeList,
|
|
params=dict(orgname=ORGANIZATION),
|
|
data=dict(role='read',
|
|
delegate={'kind': 'team',
|
|
'name': 'readers'}))
|
|
|
|
self.assertEquals('read', json['role'])
|
|
pid = json['id']
|
|
|
|
# Verify the prototype exists.
|
|
json = self.getJsonResponse(PermissionPrototypeList,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
ids = set([p['id'] for p in json['prototypes']])
|
|
assert pid in ids
|
|
|
|
|
|
class TestDeleteOrganizationPrototypes(ApiTestCase):
|
|
def test_deleteprototype(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Get the existing prototypes
|
|
json = self.getJsonResponse(PermissionPrototypeList,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
ids = [p['id'] for p in json['prototypes']]
|
|
pid = ids[0]
|
|
|
|
# Delete a prototype.
|
|
self.deleteResponse(PermissionPrototype,
|
|
params=dict(orgname=ORGANIZATION, prototypeid=pid))
|
|
|
|
# Verify the prototype no longer exists.
|
|
json = self.getJsonResponse(PermissionPrototypeList,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
newids = [p['id'] for p in json['prototypes']]
|
|
assert not pid in newids
|
|
|
|
|
|
class TestUpdateOrganizationPrototypes(ApiTestCase):
|
|
def test_updateprototype(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Get the existing prototypes
|
|
json = self.getJsonResponse(PermissionPrototypeList,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
ids = [p['id'] for p in json['prototypes']]
|
|
pid = ids[0]
|
|
|
|
# Update a prototype.
|
|
json = self.putJsonResponse(PermissionPrototype,
|
|
params=dict(orgname=ORGANIZATION, prototypeid=pid),
|
|
data=dict(role='admin'))
|
|
|
|
self.assertEquals('admin', json['role'])
|
|
|
|
|
|
class TestGetOrganizationMembers(ApiTestCase):
|
|
def test_getmembers(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(OrganizationMemberList,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
membernames = [member['name'] for member in json['members']]
|
|
assert ADMIN_ACCESS_USER in membernames
|
|
assert READ_ACCESS_USER in membernames
|
|
assert not NO_ACCESS_USER in membernames
|
|
|
|
for member in json['members']:
|
|
membername = member['name']
|
|
response = self.getJsonResponse(OrganizationMember,
|
|
params=dict(orgname=ORGANIZATION, membername=membername))
|
|
|
|
self.assertEquals(member, response)
|
|
|
|
|
|
class TestRemoveOrganizationMember(ApiTestCase):
|
|
def test_try_remove_only_admin(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.deleteResponse(OrganizationMember,
|
|
params=dict(orgname=ORGANIZATION, membername=ADMIN_ACCESS_USER),
|
|
expected_code=400)
|
|
|
|
def test_remove_member(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(OrganizationMemberList,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
membernames = [member['name'] for member in json['members']]
|
|
assert ADMIN_ACCESS_USER in membernames
|
|
assert READ_ACCESS_USER in membernames
|
|
|
|
self.deleteResponse(OrganizationMember,
|
|
params=dict(orgname=ORGANIZATION, membername=READ_ACCESS_USER))
|
|
|
|
json = self.getJsonResponse(OrganizationMemberList,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
membernames = [member['name'] for member in json['members']]
|
|
assert ADMIN_ACCESS_USER in membernames
|
|
assert not READ_ACCESS_USER in membernames
|
|
|
|
|
|
def test_remove_member_repo_permission(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Add read user as a direct permission on the admin user's repo.
|
|
model.permission.set_user_repo_permission(READ_ACCESS_USER, ADMIN_ACCESS_USER, 'simple', 'read')
|
|
|
|
# Verify the user has a permission on the admin user's repo.
|
|
admin_perms = [p.user.username
|
|
for p in model.user.get_all_repo_users(ADMIN_ACCESS_USER, 'simple')]
|
|
assert READ_ACCESS_USER in admin_perms
|
|
|
|
# Add read user as a direct permission on the org repo.
|
|
model.permission.set_user_repo_permission(READ_ACCESS_USER, ORGANIZATION, ORG_REPO, 'read')
|
|
|
|
# Verify the user has a permission on the org repo.
|
|
org_perms = [p.user.username for p in model.user.get_all_repo_users(ORGANIZATION, ORG_REPO)]
|
|
assert READ_ACCESS_USER in org_perms
|
|
|
|
# Remove the user from the org.
|
|
self.deleteResponse(OrganizationMember,
|
|
params=dict(orgname=ORGANIZATION, membername=READ_ACCESS_USER))
|
|
|
|
# Verify that the user's permission on the org repo is gone, but it is still
|
|
# present on the other repo.
|
|
org_perms = [p.user.username for p in model.user.get_all_repo_users(ORGANIZATION, ORG_REPO)]
|
|
assert not READ_ACCESS_USER in org_perms
|
|
|
|
admin_perms = [p.user.username
|
|
for p in model.user.get_all_repo_users(ADMIN_ACCESS_USER, 'simple')]
|
|
assert READ_ACCESS_USER in admin_perms
|
|
|
|
|
|
class TestGetOrganizationPrivateAllowed(ApiTestCase):
|
|
def test_existingorg(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(OrgPrivateRepositories,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
self.assertEquals(True, json['privateAllowed'])
|
|
assert not 'reposAllowed' in json
|
|
|
|
|
|
def test_neworg(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
data = self.postResponse(OrganizationList,
|
|
data=dict(name='neworg',
|
|
email='test@example.com'),
|
|
expected_code=201)
|
|
|
|
json = self.getJsonResponse(OrgPrivateRepositories,
|
|
params=dict(orgname='neworg'))
|
|
|
|
self.assertEquals(False, json['privateAllowed'])
|
|
|
|
|
|
class TestUpdateOrganizationTeam(ApiTestCase):
|
|
def test_updateexisting(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
data = self.putJsonResponse(OrganizationTeam,
|
|
params=dict(orgname=ORGANIZATION,
|
|
teamname='readers'),
|
|
data=dict(description='My cool team',
|
|
role='creator'))
|
|
|
|
self.assertEquals('My cool team', data['description'])
|
|
self.assertEquals('creator', data['role'])
|
|
|
|
def test_attemptchangeroleonowners(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.putJsonResponse(OrganizationTeam,
|
|
params=dict(orgname=ORGANIZATION, teamname='owners'),
|
|
data=dict(role='creator'),
|
|
expected_code=400)
|
|
|
|
def test_createnewteam(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
data = self.putJsonResponse(OrganizationTeam,
|
|
params=dict(orgname=ORGANIZATION,
|
|
teamname='newteam'),
|
|
data=dict(description='My cool team',
|
|
role='member'))
|
|
|
|
self.assertEquals('My cool team', data['description'])
|
|
self.assertEquals('member', data['role'])
|
|
|
|
# Verify the team was created.
|
|
json = self.getJsonResponse(Organization,
|
|
params=dict(orgname=ORGANIZATION))
|
|
assert 'newteam' in json['teams']
|
|
|
|
|
|
class TestDeleteOrganizationTeam(ApiTestCase):
|
|
def test_deleteteam(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.deleteResponse(OrganizationTeam,
|
|
params=dict(orgname=ORGANIZATION, teamname='readers'))
|
|
|
|
# Make sure the team was deleted
|
|
json = self.getJsonResponse(Organization,
|
|
params=dict(orgname=ORGANIZATION))
|
|
assert not 'readers' in json['teams']
|
|
|
|
def test_attemptdeleteowners(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.deleteResponse(OrganizationTeam, params=dict(orgname=ORGANIZATION, teamname='owners'),
|
|
expected_code=400)
|
|
|
|
|
|
class TestGetOrganizationTeamMembers(ApiTestCase):
|
|
def test_invalidteam(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.getResponse(TeamMemberList,
|
|
params=dict(orgname=ORGANIZATION, teamname='notvalid'),
|
|
expected_code=404)
|
|
|
|
def test_getmembers(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(TeamMemberList,
|
|
params=dict(orgname=ORGANIZATION,
|
|
teamname='readers'))
|
|
|
|
self.assertEquals(READ_ACCESS_USER, json['members'][1]['name'])
|
|
|
|
|
|
class TestUpdateOrganizationTeamMember(ApiTestCase):
|
|
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=membername))
|
|
|
|
|
|
# Verify the user was added to the team.
|
|
json = self.getJsonResponse(TeamMemberList,
|
|
params=dict(orgname=ORGANIZATION,
|
|
teamname='readers'))
|
|
|
|
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 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.user.get_user(membername)
|
|
invites = list(model.team.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.user.get_user(membername)
|
|
invites = list(model.team.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.user.get_user(membername)
|
|
invites = list(model.team.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)
|
|
|
|
# Verify the initial member count
|
|
json = self.getJsonResponse(TeamMemberList,
|
|
params=dict(orgname=ORGANIZATION,
|
|
teamname='readers',
|
|
includePending=True))
|
|
|
|
self.assertEquals(len(json['members']), 3)
|
|
|
|
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))
|
|
|
|
self.assertEquals(len(json['members']), 4)
|
|
|
|
# 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))
|
|
|
|
self.assertEquals(len(json['members']), 3)
|
|
|
|
|
|
def test_deletemember(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.deleteResponse(TeamMember,
|
|
params=dict(orgname=ORGANIZATION, teamname='readers',
|
|
membername=READ_ACCESS_USER))
|
|
|
|
|
|
# Verify the user was removed from the team.
|
|
json = self.getJsonResponse(TeamMemberList,
|
|
params=dict(orgname=ORGANIZATION,
|
|
teamname='readers'))
|
|
|
|
self.assertEquals(len(json['members']), 1)
|
|
|
|
|
|
class TestCreateRepo(ApiTestCase):
|
|
def test_invalidreponame(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.postJsonResponse(RepositoryList,
|
|
data=dict(repository='some/repo',
|
|
visibility='public',
|
|
description=''),
|
|
expected_code=400)
|
|
|
|
self.assertEquals('Invalid repository name', json['detail'])
|
|
|
|
def test_duplicaterepo(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.postJsonResponse(RepositoryList,
|
|
data=dict(repository='simple',
|
|
visibility='public',
|
|
description=''),
|
|
expected_code=400)
|
|
|
|
self.assertEquals('Repository already exists', json['detail'])
|
|
|
|
|
|
def test_createrepo(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.postJsonResponse(RepositoryList,
|
|
data=dict(repository='newrepo',
|
|
visibility='public',
|
|
description=''),
|
|
expected_code=201)
|
|
|
|
|
|
self.assertEquals(ADMIN_ACCESS_USER, json['namespace'])
|
|
self.assertEquals('newrepo', json['name'])
|
|
|
|
|
|
def test_createrepo_underorg(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.postJsonResponse(RepositoryList,
|
|
data=dict(namespace=ORGANIZATION,
|
|
repository='newrepo',
|
|
visibility='private',
|
|
description=''),
|
|
expected_code=201)
|
|
|
|
self.assertEquals(ORGANIZATION, json['namespace'])
|
|
self.assertEquals('newrepo', json['name'])
|
|
|
|
|
|
class TestListRepos(ApiTestCase):
|
|
def test_listrepos_asguest(self):
|
|
# Queries: Base + the list query
|
|
with assert_query_count(BASE_QUERY_COUNT + 1):
|
|
json = self.getJsonResponse(RepositoryList, params=dict(public=True))
|
|
|
|
self.assertEquals(len(json['repositories']), 1)
|
|
|
|
def test_listrepos_asorgmember(self):
|
|
self.login(READ_ACCESS_USER)
|
|
|
|
# Queries: Base + the list query
|
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 2):
|
|
json = self.getJsonResponse(RepositoryList, params=dict(public=True))
|
|
|
|
self.assertGreater(len(json['repositories']), 0)
|
|
|
|
def test_listrepos_filter(self):
|
|
self.login(READ_ACCESS_USER)
|
|
json = self.getJsonResponse(RepositoryList,
|
|
params=dict(namespace=ORGANIZATION,
|
|
public=False))
|
|
|
|
self.assertTrue(len(json['repositories']) > 0)
|
|
|
|
for repo in json['repositories']:
|
|
self.assertEquals(ORGANIZATION, repo['namespace'])
|
|
|
|
def test_listrepos_allparams(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Queries: Base + the list query + the popularity and last modified queries + full perms load
|
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 4):
|
|
json = self.getJsonResponse(RepositoryList,
|
|
params=dict(namespace=ORGANIZATION,
|
|
public=False,
|
|
last_modified=True,
|
|
popularity=True))
|
|
|
|
self.assertTrue(len(json['repositories']) > 0)
|
|
|
|
for repo in json['repositories']:
|
|
self.assertEquals(ORGANIZATION, repo['namespace'])
|
|
|
|
def test_listrepos_starred_nouser(self):
|
|
self.getResponse(RepositoryList,
|
|
params=dict(last_modified=True,
|
|
popularity=True,
|
|
starred=True),
|
|
expected_code=400)
|
|
|
|
def test_listrepos_starred(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(RepositoryList,
|
|
params=dict(last_modified=True,
|
|
popularity=True,
|
|
starred=True))
|
|
|
|
self.assertTrue(len(json['repositories']) > 0)
|
|
|
|
for repo in json['repositories']:
|
|
self.assertTrue(repo['is_starred'])
|
|
|
|
def test_listrepos_asguest_allparams(self):
|
|
json = self.getJsonResponse(RepositoryList,
|
|
params=dict(namespace=ORGANIZATION,
|
|
public=False,
|
|
last_modified=True))
|
|
|
|
for repo in json['repositories']:
|
|
self.assertEquals(ORGANIZATION, repo['namespace'])
|
|
|
|
|
|
class TestViewPublicRepository(ApiTestCase):
|
|
def test_normalview(self):
|
|
self.getJsonResponse(Repository, params=dict(repository='public/publicrepo'))
|
|
|
|
def test_anon_access_disabled(self):
|
|
import features
|
|
features.ANONYMOUS_ACCESS = False
|
|
try:
|
|
self.getResponse(Repository, params=dict(repository='public/publicrepo'), expected_code=401)
|
|
finally:
|
|
features.ANONYMOUS_ACCESS = True
|
|
|
|
|
|
class TestUpdateRepo(ApiTestCase):
|
|
SIMPLE_REPO = ADMIN_ACCESS_USER + '/simple'
|
|
def test_updatedescription(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.putJsonResponse(Repository,
|
|
params=dict(repository=self.SIMPLE_REPO),
|
|
data=dict(description='Some cool repo'))
|
|
|
|
# Verify the repo description was updated.
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=self.SIMPLE_REPO))
|
|
|
|
self.assertEquals('Some cool repo', json['description'])
|
|
|
|
|
|
class TestChangeRepoVisibility(ApiTestCase):
|
|
SIMPLE_REPO = ADMIN_ACCESS_USER + '/simple'
|
|
|
|
def test_trychangevisibility(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Make public.
|
|
self.postJsonResponse(RepositoryVisibility,
|
|
params=dict(repository=self.SIMPLE_REPO),
|
|
data=dict(visibility='public'))
|
|
|
|
# Verify the visibility.
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=self.SIMPLE_REPO))
|
|
|
|
self.assertEquals(True, json['is_public'])
|
|
|
|
# Change the subscription of the namespace.
|
|
self.putJsonResponse(UserPlan, data=dict(plan='personal-30'))
|
|
|
|
# Try to make private.
|
|
self.postJsonResponse(RepositoryVisibility,
|
|
params=dict(repository=self.SIMPLE_REPO),
|
|
data=dict(visibility='private'),
|
|
expected_code=402)
|
|
|
|
# Verify the visibility.
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=self.SIMPLE_REPO))
|
|
|
|
self.assertEquals(True, json['is_public'])
|
|
|
|
def test_changevisibility(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Make public.
|
|
self.postJsonResponse(RepositoryVisibility,
|
|
params=dict(repository=self.SIMPLE_REPO),
|
|
data=dict(visibility='public'))
|
|
|
|
# Verify the visibility.
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=self.SIMPLE_REPO))
|
|
|
|
self.assertEquals(True, json['is_public'])
|
|
|
|
# Make private.
|
|
self.postJsonResponse(RepositoryVisibility,
|
|
params=dict(repository=self.SIMPLE_REPO),
|
|
data=dict(visibility='private'))
|
|
|
|
# Verify the visibility.
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=self.SIMPLE_REPO))
|
|
|
|
self.assertEquals(False, json['is_public'])
|
|
|
|
|
|
|
|
|
|
class log_queries(object):
|
|
def __init__(self, query_filter=None):
|
|
self.filter = query_filter
|
|
|
|
def get_queries(self):
|
|
queries = [q.msg[0] for q in self._handler.queries]
|
|
if self.filter:
|
|
queries = [q for q in queries if re.match(self.filter, q)]
|
|
|
|
return queries
|
|
|
|
def __enter__(self):
|
|
logger = logging.getLogger('peewee')
|
|
self._handler = _QueryLogHandler()
|
|
logger.setLevel(logging.DEBUG)
|
|
logger.addHandler(self._handler)
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
logger = logging.getLogger('peewee')
|
|
logger.removeHandler(self._handler)
|
|
|
|
|
|
class check_transitive_deletes(log_queries):
|
|
def __init__(self):
|
|
super(check_transitive_deletes, self).__init__(query_filter=r'^DELETE.+IN \(SELECT.+$')
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
super(check_transitive_deletes, self).__exit__(exc_type, exc_val, exc_tb)
|
|
queries = self.get_queries()
|
|
if queries:
|
|
raise Exception('Detected transitive deletion in queries: %s' % queries)
|
|
|
|
|
|
class TestDeleteRepository(ApiTestCase):
|
|
SIMPLE_REPO = ADMIN_ACCESS_USER + '/simple'
|
|
COMPLEX_REPO = ADMIN_ACCESS_USER + '/complex'
|
|
|
|
def test_deleterepo(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Verify the repo exists.
|
|
self.getResponse(Repository,
|
|
params=dict(repository=self.SIMPLE_REPO))
|
|
|
|
self.deleteResponse(Repository, params=dict(repository=self.SIMPLE_REPO))
|
|
|
|
# Verify the repo was deleted.
|
|
self.getResponse(Repository,
|
|
params=dict(repository=self.SIMPLE_REPO),
|
|
expected_code=404)
|
|
|
|
def test_deleterepo2(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Verify the repo exists.
|
|
self.getResponse(Repository,
|
|
params=dict(repository=self.COMPLEX_REPO))
|
|
|
|
self.deleteResponse(Repository, params=dict(repository=self.COMPLEX_REPO))
|
|
|
|
# Verify the repo was deleted.
|
|
self.getResponse(Repository,
|
|
params=dict(repository=self.COMPLEX_REPO),
|
|
expected_code=404)
|
|
|
|
def test_populate_and_delete_repo(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Verify the repo exists.
|
|
self.getResponse(Repository,
|
|
params=dict(repository=self.COMPLEX_REPO))
|
|
|
|
# Make sure the repository has some images and tags.
|
|
self.assertTrue(len(list(model.image.get_repository_images(ADMIN_ACCESS_USER, 'complex'))) > 0)
|
|
self.assertTrue(len(list(model.tag.list_repository_tags(ADMIN_ACCESS_USER, 'complex'))) > 0)
|
|
|
|
# Add some data for the repository, in addition to is already existing images and tags.
|
|
repository = model.repository.get_repository(ADMIN_ACCESS_USER, 'complex')
|
|
|
|
# Create some access tokens.
|
|
access_token = model.token.create_access_token(repository, 'read')
|
|
model.token.create_access_token(repository, 'write')
|
|
|
|
delegate_token = model.token.create_delegate_token(ADMIN_ACCESS_USER, 'complex', 'sometoken',
|
|
'read')
|
|
model.token.create_delegate_token(ADMIN_ACCESS_USER, 'complex', 'sometoken', 'write')
|
|
|
|
# Create some repository builds.
|
|
model.build.create_repository_build(repository, access_token, {}, 'someid', 'foobar')
|
|
model.build.create_repository_build(repository, delegate_token, {}, 'someid2', 'foobar2')
|
|
|
|
# Create some notifications.
|
|
model.notification.create_repo_notification(repository, 'repo_push', 'hipchat', {}, {})
|
|
model.notification.create_repo_notification(repository, 'build_queued', 'slack', {}, {})
|
|
|
|
# Create some logs.
|
|
model.log.log_action('push_repo', ADMIN_ACCESS_USER, repository=repository)
|
|
model.log.log_action('push_repo', ADMIN_ACCESS_USER, repository=repository)
|
|
|
|
# Create some build triggers.
|
|
user = model.user.get_user(ADMIN_ACCESS_USER)
|
|
model.build.create_build_trigger(repository, 'github', 'sometoken', user)
|
|
model.build.create_build_trigger(repository, 'github', 'anothertoken', user)
|
|
|
|
# Create some email authorizations.
|
|
model.repository.create_email_authorization_for_repo(ADMIN_ACCESS_USER, 'complex', 'a@b.com')
|
|
model.repository.create_email_authorization_for_repo(ADMIN_ACCESS_USER, 'complex', 'b@c.com')
|
|
|
|
# Create some repository action count entries.
|
|
RepositoryActionCount.create(repository=repository, date=datetime.datetime.now(), count=1)
|
|
RepositoryActionCount.create(repository=repository,
|
|
date=datetime.datetime.now() - datetime.timedelta(days=2), count=2)
|
|
RepositoryActionCount.create(repository=repository,
|
|
date=datetime.datetime.now() - datetime.timedelta(days=5), count=6)
|
|
|
|
# Delete the repository.
|
|
with check_transitive_deletes():
|
|
self.deleteResponse(Repository, params=dict(repository=self.COMPLEX_REPO))
|
|
|
|
# Verify the repo was deleted.
|
|
self.getResponse(Repository,
|
|
params=dict(repository=self.COMPLEX_REPO),
|
|
expected_code=404)
|
|
|
|
|
|
class TestGetRepository(ApiTestCase):
|
|
PUBLIC_REPO = PUBLIC_USER + '/publicrepo'
|
|
|
|
def test_getrepo_badnames(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
bad_names = ['logs', 'build', 'tokens', 'foo.bar', 'foo-bar', 'foo_bar']
|
|
|
|
# For each bad name, create the repo.
|
|
for bad_name in bad_names:
|
|
json = self.postJsonResponse(RepositoryList, expected_code=201,
|
|
data=dict(repository=bad_name, visibility='public',
|
|
description=''))
|
|
|
|
# Make sure we can retrieve its information.
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/' + bad_name))
|
|
|
|
self.assertEquals(ADMIN_ACCESS_USER, json['namespace'])
|
|
self.assertEquals(bad_name, json['name'])
|
|
self.assertEquals(True, json['is_public'])
|
|
|
|
|
|
def test_getrepo_public_asguest(self):
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=self.PUBLIC_REPO))
|
|
|
|
self.assertEquals(PUBLIC_USER, json['namespace'])
|
|
self.assertEquals('publicrepo', json['name'])
|
|
|
|
self.assertEquals(True, json['is_public'])
|
|
self.assertEquals(False, json['is_organization'])
|
|
|
|
self.assertEquals(False, json['can_write'])
|
|
self.assertEquals(False, json['can_admin'])
|
|
|
|
assert 'latest' in json['tags']
|
|
|
|
def test_getrepo_public_asowner(self):
|
|
self.login(PUBLIC_USER)
|
|
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=self.PUBLIC_REPO))
|
|
|
|
self.assertEquals(False, json['is_organization'])
|
|
self.assertEquals(True, json['can_write'])
|
|
self.assertEquals(True, json['can_admin'])
|
|
|
|
def test_getrepo_building(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/building'))
|
|
|
|
self.assertEquals(True, json['can_write'])
|
|
self.assertEquals(True, json['can_admin'])
|
|
self.assertEquals(False, json['is_organization'])
|
|
|
|
def test_getrepo_org_asnonmember(self):
|
|
self.getResponse(Repository,
|
|
params=dict(repository=ORGANIZATION + '/' + ORG_REPO),
|
|
expected_code=401)
|
|
|
|
def test_getrepo_org_asreader(self):
|
|
self.login(READ_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=ORGANIZATION + '/' + ORG_REPO))
|
|
|
|
self.assertEquals(ORGANIZATION, json['namespace'])
|
|
self.assertEquals(ORG_REPO, json['name'])
|
|
|
|
self.assertEquals(False, json['can_write'])
|
|
self.assertEquals(False, json['can_admin'])
|
|
|
|
self.assertEquals(True, json['is_organization'])
|
|
|
|
def test_getrepo_org_asadmin(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(Repository,
|
|
params=dict(repository=ORGANIZATION + '/' + ORG_REPO))
|
|
|
|
self.assertEquals(True, json['can_write'])
|
|
self.assertEquals(True, json['can_admin'])
|
|
|
|
self.assertEquals(True, json['is_organization'])
|
|
|
|
|
|
class TestRepositoryBuildResource(ApiTestCase):
|
|
def test_cancel_invalidbuild(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.deleteResponse(RepositoryBuildResource,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', build_uuid='invalid'),
|
|
expected_code=404)
|
|
|
|
def test_cancel_waitingbuild(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Request a (fake) build.
|
|
json = self.postJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(file_id='foobarbaz'),
|
|
expected_code=201)
|
|
|
|
uuid = json['id']
|
|
|
|
# Check for the build.
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
self.assertEquals(1, len(json['builds']))
|
|
self.assertEquals(uuid, json['builds'][0]['id'])
|
|
|
|
# Find the build's queue item.
|
|
build_ref = database.RepositoryBuild.get(uuid=uuid)
|
|
queue_item = database.QueueItem.get(id=build_ref.queue_id)
|
|
|
|
self.assertTrue(queue_item.available)
|
|
self.assertTrue(queue_item.retries_remaining > 0)
|
|
|
|
# Cancel the build.
|
|
self.deleteResponse(RepositoryBuildResource,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', build_uuid=uuid),
|
|
expected_code=201)
|
|
|
|
# Check for the build.
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
self.assertEquals(0, len(json['builds']))
|
|
|
|
# Check for the build's queue item.
|
|
try:
|
|
database.QueueItem.get(id=build_ref.queue_id)
|
|
self.fail('QueueItem still exists for build')
|
|
except database.QueueItem.DoesNotExist:
|
|
pass
|
|
|
|
def test_attemptcancel_scheduledbuild(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Request a (fake) build.
|
|
json = self.postJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(file_id='foobarbaz'),
|
|
expected_code=201)
|
|
|
|
uuid = json['id']
|
|
|
|
# Check for the build.
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
self.assertEquals(1, len(json['builds']))
|
|
self.assertEquals(uuid, json['builds'][0]['id'])
|
|
|
|
# Set queue item to be picked up.
|
|
build_ref = database.RepositoryBuild.get(uuid=uuid)
|
|
qi = database.QueueItem.get(id=build_ref.queue_id)
|
|
qi.available = False
|
|
qi.save()
|
|
|
|
# Try to cancel the build.
|
|
self.deleteResponse(RepositoryBuildResource,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', build_uuid=uuid),
|
|
expected_code=400)
|
|
|
|
|
|
def test_attemptcancel_workingbuild(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Request a (fake) build.
|
|
json = self.postJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(file_id='foobarbaz'),
|
|
expected_code=201)
|
|
|
|
uuid = json['id']
|
|
|
|
# Check for the build.
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
self.assertEquals(1, len(json['builds']))
|
|
self.assertEquals(uuid, json['builds'][0]['id'])
|
|
|
|
# Set the build to a different phase.
|
|
rb = database.RepositoryBuild.get(uuid=uuid)
|
|
rb.phase = database.BUILD_PHASE.BUILDING
|
|
rb.save()
|
|
|
|
# Try to cancel the build.
|
|
self.deleteResponse(RepositoryBuildResource,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', build_uuid=uuid),
|
|
expected_code=400)
|
|
|
|
|
|
class TestRepoBuilds(ApiTestCase):
|
|
def test_getrepo_nobuilds(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Queries: Permission + the list query
|
|
with assert_query_count(2):
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
assert len(json['builds']) == 0
|
|
|
|
def test_getrepobuilds(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Queries: Permission + the list query
|
|
with assert_query_count(2):
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/building'))
|
|
|
|
assert len(json['builds']) > 0
|
|
build = json['builds'][-1]
|
|
|
|
assert 'id' in build
|
|
assert 'status' in build
|
|
|
|
# Check the status endpoint.
|
|
status_json = self.getJsonResponse(RepositoryBuildStatus,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/building',
|
|
build_uuid=build['id']))
|
|
|
|
self.assertEquals(status_json['id'], build['id'])
|
|
self.assertEquals(status_json['resource_key'], build['resource_key'])
|
|
self.assertEquals(status_json['trigger'], build['trigger'])
|
|
|
|
|
|
class TestRequestRepoBuild(ApiTestCase):
|
|
def test_requestbuild_noidurl(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Request a (fake) build without a file ID or URL.
|
|
self.postResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(),
|
|
expected_code=400)
|
|
|
|
def test_requestbuild_invalidurls(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Request a (fake) build with and invalid URL.
|
|
self.postResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(archive_url='foobarbaz'),
|
|
expected_code=400)
|
|
|
|
self.postResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(archive_url='file://foobarbaz'),
|
|
expected_code=400)
|
|
|
|
def test_requestrepobuild_withurl(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Ensure we are not yet building.
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
assert len(json['builds']) == 0
|
|
|
|
# Request a (fake) build.
|
|
self.postResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(archive_url='http://quay.io/robots.txt'),
|
|
expected_code=201)
|
|
|
|
# Check for the build.
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
assert len(json['builds']) > 0
|
|
self.assertEquals('http://quay.io/robots.txt', json['builds'][0]['archive_url'])
|
|
|
|
|
|
def test_requestrepobuild_withfile(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Ensure we are not yet building.
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
assert len(json['builds']) == 0
|
|
|
|
# Request a (fake) build.
|
|
self.postResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(file_id='foobarbaz'),
|
|
expected_code=201)
|
|
|
|
# Check for the build.
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
assert len(json['builds']) > 0
|
|
|
|
def test_requestrepobuild_with_robot(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Ensure we are not yet building.
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
assert len(json['builds']) == 0
|
|
|
|
# Request a (fake) build.
|
|
pull_robot = ADMIN_ACCESS_USER + '+dtrobot'
|
|
self.postResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(file_id='foobarbaz', pull_robot=pull_robot),
|
|
expected_code=201)
|
|
|
|
# Check for the build.
|
|
json = self.getJsonResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/building'))
|
|
|
|
assert len(json['builds']) > 0
|
|
|
|
|
|
def test_requestrepobuild_with_invalid_robot(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Request a (fake) build.
|
|
pull_robot = ADMIN_ACCESS_USER + '+invalidrobot'
|
|
self.postResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(file_id='foobarbaz', pull_robot=pull_robot),
|
|
expected_code=404)
|
|
|
|
def test_requestrepobuild_with_unauthorized_robot(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Request a (fake) build.
|
|
pull_robot = 'freshuser+anotherrobot'
|
|
self.postResponse(RepositoryBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(file_id='foobarbaz', pull_robot=pull_robot),
|
|
expected_code=403)
|
|
|
|
|
|
class TestRepositoryEmail(ApiTestCase):
|
|
def test_emailnotauthorized(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Verify the e-mail address is not authorized.
|
|
self.getResponse(RepositoryAuthorizedEmail,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
email='test@example.com'),
|
|
expected_code=404)
|
|
|
|
def test_emailnotauthorized_butsent(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Verify the e-mail address is not authorized.
|
|
json = self.getJsonResponse(RepositoryAuthorizedEmail,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
email='jschorr+other@devtable.com'))
|
|
|
|
self.assertEquals(False, json['confirmed'])
|
|
self.assertEquals(ADMIN_ACCESS_USER, json['namespace'])
|
|
self.assertEquals('simple', json['repository'])
|
|
|
|
|
|
def test_emailauthorized(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Verify the e-mail address is authorized.
|
|
json = self.getJsonResponse(RepositoryAuthorizedEmail,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
email='jschorr@devtable.com'))
|
|
|
|
self.assertEquals(True, json['confirmed'])
|
|
self.assertEquals(ADMIN_ACCESS_USER, json['namespace'])
|
|
self.assertEquals('simple', json['repository'])
|
|
|
|
|
|
def test_send_email_authorization(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Send the email.
|
|
json = self.postJsonResponse(RepositoryAuthorizedEmail,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
email='jschorr+foo@devtable.com'))
|
|
|
|
self.assertEquals(False, json['confirmed'])
|
|
self.assertEquals(ADMIN_ACCESS_USER, json['namespace'])
|
|
self.assertEquals('simple', json['repository'])
|
|
|
|
|
|
class TestRepositoryNotifications(ApiTestCase):
|
|
def test_webhooks(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Add a notification.
|
|
json = self.postJsonResponse(RepositoryNotificationList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(config={'url': 'http://example.com'}, event='repo_push',
|
|
method='webhook', eventConfig={}),
|
|
expected_code=201)
|
|
|
|
self.assertEquals('repo_push', json['event'])
|
|
self.assertEquals('webhook', json['method'])
|
|
self.assertEquals('http://example.com', json['config']['url'])
|
|
self.assertIsNone(json['title'])
|
|
|
|
wid = json['uuid']
|
|
|
|
# Get the notification.
|
|
json = self.getJsonResponse(RepositoryNotification,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', uuid=wid))
|
|
|
|
self.assertEquals(wid, json['uuid'])
|
|
self.assertEquals('repo_push', json['event'])
|
|
self.assertEquals('webhook', json['method'])
|
|
self.assertIsNone(json['title'])
|
|
|
|
# Verify the notification is listed.
|
|
json = self.getJsonResponse(RepositoryNotificationList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
ids = [w['uuid'] for w in json['notifications']]
|
|
assert wid in ids
|
|
|
|
# Delete the notification.
|
|
self.deleteResponse(RepositoryNotification,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', uuid=wid),
|
|
expected_code=204)
|
|
|
|
# Verify the notification is gone.
|
|
self.getResponse(RepositoryNotification,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', uuid=wid),
|
|
expected_code=404)
|
|
|
|
# Add another notification.
|
|
json = self.postJsonResponse(RepositoryNotificationList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(config={'url': 'http://example.com'}, event='repo_push',
|
|
method='webhook', title='Some Notification',
|
|
eventConfig={}),
|
|
expected_code=201)
|
|
|
|
self.assertEquals('repo_push', json['event'])
|
|
self.assertEquals('webhook', json['method'])
|
|
self.assertEquals('http://example.com', json['config']['url'])
|
|
self.assertEquals('Some Notification', json['title'])
|
|
|
|
wid = json['uuid']
|
|
|
|
# Get the notification.
|
|
json = self.getJsonResponse(RepositoryNotification,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', uuid=wid))
|
|
|
|
self.assertEquals(wid, json['uuid'])
|
|
self.assertEquals('repo_push', json['event'])
|
|
self.assertEquals('webhook', json['method'])
|
|
self.assertEquals('Some Notification', json['title'])
|
|
|
|
|
|
class TestListAndGetImage(ApiTestCase):
|
|
def test_listandgetimages(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(RepositoryImageList,
|
|
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
|
|
assert 'created' in image
|
|
assert 'comment' in image
|
|
assert 'command' in image
|
|
assert 'ancestors' in image
|
|
assert 'size' in image
|
|
|
|
ijson = self.getJsonResponse(RepositoryImage,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
image_id=image['id']))
|
|
|
|
self.assertEquals(image['id'], ijson['id'])
|
|
|
|
|
|
class TestGetImageChanges(ApiTestCase):
|
|
def test_getimagechanges(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Find an image to check.
|
|
json = self.getJsonResponse(RepositoryImageList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
|
|
image_id = json['images'][0]['id']
|
|
|
|
# Lookup the image's changes.
|
|
# TODO: Fix me once we can get fake changes into the test data
|
|
#self.getJsonResponse(RepositoryImageChanges,
|
|
# params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
# image_id=image_id))
|
|
|
|
|
|
class TestRevertTag(ApiTestCase):
|
|
def test_reverttag_invalidtag(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.postResponse(RevertTag,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/history', tag='invalidtag'),
|
|
data=dict(image='invalid_image'),
|
|
expected_code=404)
|
|
|
|
def test_reverttag_invalidimage(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
self.postResponse(RevertTag,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/history', tag='latest'),
|
|
data=dict(image='invalid_image'),
|
|
expected_code=400)
|
|
|
|
def test_reverttag(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(ListRepositoryTags,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/history',
|
|
tag='latest'))
|
|
|
|
self.assertEquals(2, len(json['tags']))
|
|
self.assertFalse('end_ts' in json['tags'][0])
|
|
|
|
previous_image_id = json['tags'][1]['docker_image_id']
|
|
|
|
self.postJsonResponse(RevertTag, params=dict(repository=ADMIN_ACCESS_USER + '/history',
|
|
tag='latest'),
|
|
data=dict(image=previous_image_id))
|
|
|
|
json = self.getJsonResponse(ListRepositoryTags,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/history',
|
|
tag='latest'))
|
|
self.assertEquals(3, len(json['tags']))
|
|
self.assertFalse('end_ts' in json['tags'][0])
|
|
self.assertEquals(previous_image_id, json['tags'][0]['docker_image_id'])
|
|
|
|
|
|
|
|
class TestListAndDeleteTag(ApiTestCase):
|
|
def test_listdeletecreateandmovetag(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# List the images for prod.
|
|
json = self.getJsonResponse(RepositoryTagImages,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex', tag='prod'))
|
|
|
|
prod_images = json['images']
|
|
assert len(prod_images) > 0
|
|
|
|
# List the images for staging.
|
|
json = self.getJsonResponse(RepositoryTagImages,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex',
|
|
tag='staging'))
|
|
|
|
staging_images = json['images']
|
|
assert len(prod_images) == len(staging_images) + 1
|
|
|
|
# Delete prod.
|
|
self.deleteResponse(RepositoryTag,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex', tag='prod'),
|
|
expected_code=204)
|
|
|
|
# Make sure the tag is gone.
|
|
self.getResponse(RepositoryTagImages,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex', tag='prod'),
|
|
expected_code=404)
|
|
|
|
# Make the sure the staging images are still there.
|
|
json = self.getJsonResponse(RepositoryTagImages,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex',
|
|
tag='staging'))
|
|
|
|
self.assertEquals(staging_images, json['images'])
|
|
|
|
# Require a valid tag name.
|
|
self.putResponse(RepositoryTag,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex', tag='-fail'),
|
|
data=dict(image=staging_images[0]['id']),
|
|
expected_code=400)
|
|
|
|
# Add a new tag to the staging image.
|
|
self.putResponse(RepositoryTag,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex', tag='sometag'),
|
|
data=dict(image=staging_images[0]['id']),
|
|
expected_code=201)
|
|
|
|
# Make sure the tag is present.
|
|
json = self.getJsonResponse(RepositoryTagImages,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex',
|
|
tag='sometag'))
|
|
|
|
sometag_images = json['images']
|
|
self.assertEquals(sometag_images, staging_images)
|
|
|
|
# Move the tag.
|
|
self.putResponse(RepositoryTag,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex', tag='sometag'),
|
|
data=dict(image=staging_images[-1]['id']),
|
|
expected_code=201)
|
|
|
|
# Make sure the tag has moved.
|
|
json = self.getJsonResponse(RepositoryTagImages,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex',
|
|
tag='sometag'))
|
|
|
|
sometag_new_images = json['images']
|
|
self.assertEquals(1, len(sometag_new_images))
|
|
self.assertEquals(staging_images[-1], sometag_new_images[0])
|
|
|
|
|
|
def test_deletesubtag(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# List the images for prod.
|
|
json = self.getJsonResponse(RepositoryTagImages,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex', tag='prod'))
|
|
|
|
prod_images = json['images']
|
|
assert len(prod_images) > 0
|
|
|
|
# Delete staging.
|
|
self.deleteResponse(RepositoryTag,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex', tag='staging'),
|
|
expected_code=204)
|
|
|
|
# Make sure the prod images are still around.
|
|
json = self.getJsonResponse(RepositoryTagImages,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex', tag='prod'))
|
|
|
|
self.assertEquals(prod_images, json['images'])
|
|
|
|
def test_listtagpagination(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
latest_image = model.tag.get_tag_image(ADMIN_ACCESS_USER, "complex", "prod")
|
|
|
|
for i in xrange(1, 100):
|
|
model.tag.create_or_update_tag(ADMIN_ACCESS_USER, "complex", "tag" + str(i), latest_image.docker_image_id)
|
|
|
|
json = self.getJsonResponse(ListRepositoryTags,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/complex', page=2))
|
|
|
|
# Make sure that we're able to see the second page of results.
|
|
assert json['page'] == 2
|
|
assert len(json['tags']) == 50
|
|
|
|
class TestRepoPermissions(ApiTestCase):
|
|
def listUserPermissions(self, namespace=ADMIN_ACCESS_USER, repo='simple'):
|
|
return self.getJsonResponse(RepositoryUserPermissionList,
|
|
params=dict(repository=namespace + '/' + repo))['permissions']
|
|
|
|
def listTeamPermissions(self):
|
|
response = self.getJsonResponse(RepositoryTeamPermissionList,
|
|
params=dict(repository=ORGANIZATION + '/' + ORG_REPO))
|
|
return response['permissions']
|
|
|
|
def test_userpermissions_underorg(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
permissions = self.listUserPermissions(namespace=ORGANIZATION, repo=ORG_REPO)
|
|
|
|
self.assertEquals(1, len(permissions))
|
|
assert 'outsideorg' in permissions
|
|
self.assertEquals('read', permissions['outsideorg']['role'])
|
|
self.assertEquals(False, permissions['outsideorg']['is_org_member'])
|
|
|
|
# Add another user.
|
|
self.putJsonResponse(RepositoryUserPermission,
|
|
params=dict(repository=ORGANIZATION + '/' + ORG_REPO,
|
|
username=ADMIN_ACCESS_USER),
|
|
data=dict(role='admin'))
|
|
|
|
# Verify the user is present.
|
|
permissions = self.listUserPermissions(namespace=ORGANIZATION, repo=ORG_REPO)
|
|
|
|
self.assertEquals(2, len(permissions))
|
|
assert ADMIN_ACCESS_USER in permissions
|
|
self.assertEquals('admin', permissions[ADMIN_ACCESS_USER]['role'])
|
|
self.assertEquals(True, permissions[ADMIN_ACCESS_USER]['is_org_member'])
|
|
|
|
|
|
def test_userpermissions(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# The repo should start with just the admin as a user perm.
|
|
permissions = self.listUserPermissions()
|
|
|
|
self.assertEquals(1, len(permissions))
|
|
assert ADMIN_ACCESS_USER in permissions
|
|
self.assertEquals('admin', permissions[ADMIN_ACCESS_USER]['role'])
|
|
self.assertFalse('is_org_member' in permissions[ADMIN_ACCESS_USER])
|
|
|
|
# Add another user.
|
|
self.putJsonResponse(RepositoryUserPermission,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
username=NO_ACCESS_USER),
|
|
data=dict(role='read'))
|
|
|
|
# Verify the user is present.
|
|
permissions = self.listUserPermissions()
|
|
|
|
self.assertEquals(2, len(permissions))
|
|
assert NO_ACCESS_USER in permissions
|
|
self.assertEquals('read', permissions[NO_ACCESS_USER]['role'])
|
|
self.assertFalse('is_org_member' in permissions[NO_ACCESS_USER])
|
|
|
|
json = self.getJsonResponse(RepositoryUserPermission,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
username=NO_ACCESS_USER))
|
|
self.assertEquals('read', json['role'])
|
|
|
|
# Change the user's permissions.
|
|
self.putJsonResponse(RepositoryUserPermission,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
username=NO_ACCESS_USER),
|
|
data=dict(role='admin'))
|
|
|
|
# Verify.
|
|
permissions = self.listUserPermissions()
|
|
|
|
self.assertEquals(2, len(permissions))
|
|
assert NO_ACCESS_USER in permissions
|
|
self.assertEquals('admin', permissions[NO_ACCESS_USER]['role'])
|
|
|
|
# Delete the user's permission.
|
|
self.deleteResponse(RepositoryUserPermission,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
username=NO_ACCESS_USER))
|
|
|
|
# Verify.
|
|
permissions = self.listUserPermissions()
|
|
|
|
self.assertEquals(1, len(permissions))
|
|
assert not NO_ACCESS_USER in permissions
|
|
|
|
|
|
def test_teampermissions(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# The repo should start with just the readers as a team perm.
|
|
permissions = self.listTeamPermissions()
|
|
|
|
self.assertEquals(1, len(permissions))
|
|
assert 'readers' in permissions
|
|
self.assertEquals('read', permissions['readers']['role'])
|
|
|
|
# Add another team.
|
|
self.putJsonResponse(RepositoryTeamPermission,
|
|
params=dict(repository=ORGANIZATION + '/' + ORG_REPO, teamname='owners'),
|
|
data=dict(role='write'))
|
|
|
|
# Verify the team is present.
|
|
permissions = self.listTeamPermissions()
|
|
|
|
self.assertEquals(2, len(permissions))
|
|
assert 'owners' in permissions
|
|
self.assertEquals('write', permissions['owners']['role'])
|
|
|
|
json = self.getJsonResponse(RepositoryTeamPermission,
|
|
params=dict(repository=ORGANIZATION + '/' + ORG_REPO,
|
|
teamname='owners'))
|
|
self.assertEquals('write', json['role'])
|
|
|
|
# Change the team's permissions.
|
|
self.putJsonResponse(RepositoryTeamPermission,
|
|
params=dict(repository=ORGANIZATION + '/' + ORG_REPO, teamname='owners'),
|
|
data=dict(role='admin'))
|
|
|
|
# Verify.
|
|
permissions = self.listTeamPermissions()
|
|
|
|
self.assertEquals(2, len(permissions))
|
|
assert 'owners' in permissions
|
|
self.assertEquals('admin', permissions['owners']['role'])
|
|
|
|
# Delete the team's permission.
|
|
self.deleteResponse(RepositoryTeamPermission,
|
|
params=dict(repository=ORGANIZATION + '/' + ORG_REPO, teamname='owners'))
|
|
|
|
# Verify.
|
|
permissions = self.listTeamPermissions()
|
|
|
|
self.assertEquals(1, len(permissions))
|
|
assert not 'owners' in permissions
|
|
|
|
|
|
class TestApiTokens(ApiTestCase):
|
|
def listTokens(self):
|
|
return self.getJsonResponse(RepositoryTokenList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))['tokens']
|
|
|
|
def test_tokens(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Create a new token.
|
|
json = self.postJsonResponse(RepositoryTokenList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
|
data=dict(role='read', friendlyName='mytoken'),
|
|
expected_code=201)
|
|
|
|
self.assertEquals('mytoken', json['friendlyName'])
|
|
self.assertEquals('read', json['role'])
|
|
token_code = json['code']
|
|
|
|
# Verify.
|
|
tokens = self.listTokens()
|
|
assert token_code in tokens
|
|
self.assertEquals('mytoken', tokens[token_code]['friendlyName'])
|
|
|
|
json = self.getJsonResponse(RepositoryToken,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
code=token_code))
|
|
self.assertEquals(tokens[token_code], json)
|
|
|
|
# Change the token's permission.
|
|
self.putJsonResponse(RepositoryToken,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', code=token_code),
|
|
data=dict(role='write'))
|
|
|
|
# Verify.
|
|
json = self.getJsonResponse(RepositoryToken,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
code=token_code))
|
|
self.assertEquals('write', json['role'])
|
|
|
|
# Delete the token.
|
|
self.deleteResponse(RepositoryToken,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', code=token_code))
|
|
|
|
# Verify.
|
|
self.getResponse(RepositoryToken,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', code=token_code),
|
|
expected_code=404)
|
|
|
|
|
|
class TestUserCard(ApiTestCase):
|
|
def test_getusercard(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.getJsonResponse(UserCard)
|
|
|
|
self.assertEquals('4242', json['card']['last4'])
|
|
self.assertEquals('Visa', json['card']['type'])
|
|
|
|
def test_setusercard_error(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.postJsonResponse(UserCard,
|
|
data=dict(token='sometoken'),
|
|
expected_code=402)
|
|
assert 'carderror' in json
|
|
|
|
|
|
class TestOrgCard(ApiTestCase):
|
|
def test_getorgcard(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
json = self.getJsonResponse(OrganizationCard,
|
|
params=dict(orgname=ORGANIZATION))
|
|
|
|
self.assertEquals('4242', json['card']['last4'])
|
|
self.assertEquals('Visa', json['card']['type'])
|
|
|
|
|
|
class TestUserSubscription(ApiTestCase):
|
|
def getSubscription(self):
|
|
return self.getJsonResponse(UserPlan)
|
|
|
|
def test_updateplan(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Change the plan.
|
|
self.putJsonResponse(UserPlan,
|
|
data=dict(plan='free'))
|
|
|
|
# Verify
|
|
sub = self.getSubscription()
|
|
self.assertEquals('free', sub['plan'])
|
|
|
|
# Change the plan.
|
|
self.putJsonResponse(UserPlan,
|
|
data=dict(plan='bus-large-30'))
|
|
|
|
# Verify
|
|
sub = self.getSubscription()
|
|
self.assertEquals('bus-large-30', sub['plan'])
|
|
|
|
|
|
class TestOrgSubscription(ApiTestCase):
|
|
def getSubscription(self):
|
|
return self.getJsonResponse(OrganizationPlan, params=dict(orgname=ORGANIZATION))
|
|
|
|
def test_updateplan(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Change the plan.
|
|
self.putJsonResponse(OrganizationPlan,
|
|
params=dict(orgname=ORGANIZATION),
|
|
data=dict(plan='free'))
|
|
|
|
# Verify
|
|
sub = self.getSubscription()
|
|
self.assertEquals('free', sub['plan'])
|
|
|
|
# Change the plan.
|
|
self.putJsonResponse(OrganizationPlan,
|
|
params=dict(orgname=ORGANIZATION),
|
|
data=dict(plan='bus-large-30'))
|
|
|
|
# Verify
|
|
sub = self.getSubscription()
|
|
self.assertEquals('bus-large-30', sub['plan'])
|
|
|
|
|
|
class TestUserRobots(ApiTestCase):
|
|
def getRobotNames(self):
|
|
return [r['name'] for r in self.getJsonResponse(UserRobotList)['robots']]
|
|
|
|
def test_robot_list(self):
|
|
self.login(NO_ACCESS_USER)
|
|
|
|
# Create some robots.
|
|
self.putJsonResponse(UserRobot,
|
|
params=dict(robot_shortname='bender'),
|
|
expected_code=201)
|
|
|
|
self.putJsonResponse(UserRobot,
|
|
params=dict(robot_shortname='goldy'),
|
|
expected_code=201)
|
|
|
|
self.putJsonResponse(UserRobot,
|
|
params=dict(robot_shortname='coolbot'),
|
|
expected_code=201)
|
|
|
|
# Queries: Base + the lookup query
|
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 1):
|
|
self.getJsonResponse(UserRobotList)
|
|
|
|
# Queries: Base + the lookup query
|
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 1):
|
|
self.getJsonResponse(UserRobotList, params=dict(permissions=True))
|
|
|
|
|
|
def test_robots(self):
|
|
self.login(NO_ACCESS_USER)
|
|
|
|
# Create a robot.
|
|
json = self.putJsonResponse(UserRobot,
|
|
params=dict(robot_shortname='bender'),
|
|
expected_code=201)
|
|
|
|
self.assertEquals(NO_ACCESS_USER + '+bender', json['name'])
|
|
|
|
# Verify.
|
|
robots = self.getRobotNames()
|
|
assert NO_ACCESS_USER + '+bender' in robots
|
|
|
|
# Delete the robot.
|
|
self.deleteResponse(UserRobot,
|
|
params=dict(robot_shortname='bender'))
|
|
|
|
# Verify.
|
|
robots = self.getRobotNames()
|
|
assert not NO_ACCESS_USER + '+bender' in robots
|
|
|
|
def test_regenerate(self):
|
|
self.login(NO_ACCESS_USER)
|
|
|
|
# Create a robot.
|
|
json = self.putJsonResponse(UserRobot,
|
|
params=dict(robot_shortname='bender'),
|
|
expected_code=201)
|
|
|
|
token = json['token']
|
|
|
|
# Regenerate the robot.
|
|
json = self.postJsonResponse(RegenerateUserRobot, params=dict(robot_shortname='bender'),
|
|
expected_code=200)
|
|
|
|
# Verify the token changed.
|
|
self.assertNotEquals(token, json['token'])
|
|
|
|
json2 = self.getJsonResponse(UserRobot,
|
|
params=dict(robot_shortname='bender'),
|
|
expected_code=200)
|
|
|
|
self.assertEquals(json['token'], json2['token'])
|
|
|
|
|
|
class TestOrgRobots(ApiTestCase):
|
|
def getRobotNames(self):
|
|
return [r['name'] for r in self.getJsonResponse(OrgRobotList,
|
|
params=dict(orgname=ORGANIZATION))['robots']]
|
|
|
|
def test_create_robot_with_underscores(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Create the robot.
|
|
self.putJsonResponse(OrgRobot,
|
|
params=dict(orgname=ORGANIZATION, robot_shortname='mr_bender'),
|
|
expected_code=201)
|
|
|
|
# Add the robot to a team.
|
|
membername = ORGANIZATION + '+mr_bender'
|
|
self.putJsonResponse(TeamMember,
|
|
params=dict(orgname=ORGANIZATION, teamname='readers',
|
|
membername=membername))
|
|
|
|
# Retrieve the robot's details.
|
|
self.getJsonResponse(OrgRobot,
|
|
params=dict(orgname=ORGANIZATION, robot_shortname='mr_bender'),
|
|
expected_code=200)
|
|
|
|
|
|
def test_delete_robot_after_use(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Create the robot.
|
|
self.putJsonResponse(OrgRobot,
|
|
params=dict(orgname=ORGANIZATION, robot_shortname='bender'),
|
|
expected_code=201)
|
|
|
|
# Add the robot to a team.
|
|
membername = ORGANIZATION + '+bender'
|
|
self.putJsonResponse(TeamMember,
|
|
params=dict(orgname=ORGANIZATION, teamname='readers',
|
|
membername=membername))
|
|
|
|
# Add a repository permission.
|
|
self.putJsonResponse(RepositoryUserPermission,
|
|
params=dict(repository=ORGANIZATION + '/' + ORG_REPO, username=membername),
|
|
data=dict(role='read'))
|
|
|
|
# Add a permission prototype with the robot as the activating user.
|
|
self.postJsonResponse(PermissionPrototypeList, params=dict(orgname=ORGANIZATION),
|
|
data=dict(role='read',
|
|
activating_user={'name': membername},
|
|
delegate={'kind': 'user',
|
|
'name': membername}))
|
|
|
|
# Add a permission prototype with the robot as the delegating user.
|
|
self.postJsonResponse(PermissionPrototypeList, params=dict(orgname=ORGANIZATION),
|
|
data=dict(role='read',
|
|
delegate={'kind': 'user',
|
|
'name': membername}))
|
|
|
|
# Add a build trigger with the robot as the pull robot.
|
|
database.BuildTriggerService.create(name='fakeservice')
|
|
|
|
# Add a new fake trigger.
|
|
repo = model.repository.get_repository(ORGANIZATION, ORG_REPO)
|
|
user = model.user.get_user(ADMIN_ACCESS_USER)
|
|
pull_robot = model.user.get_user(membername)
|
|
trigger = model.build.create_build_trigger(repo, 'fakeservice', 'sometoken', user,
|
|
pull_robot=pull_robot)
|
|
|
|
# Add a fake build of the fake build trigger.
|
|
token = model.token.create_access_token(repo, 'write', kind='build-worker',
|
|
friendly_name='Repository Build Token')
|
|
|
|
build = model.build.create_repository_build(repo, token, {}, 'fake-dockerfile', 'fake-name',
|
|
trigger, pull_robot_name=membername)
|
|
|
|
# Add some log entries for the robot.
|
|
model.log.log_action('pull_repo', ORGANIZATION, performer=pull_robot, repository=repo)
|
|
|
|
# Delete the robot and verify it works.
|
|
self.deleteResponse(OrgRobot,
|
|
params=dict(orgname=ORGANIZATION, robot_shortname='bender'))
|
|
|
|
# Verify the build is still present.
|
|
self.assertIsNotNone(model.build.get_repository_build(build.uuid))
|
|
|
|
# All the above records should now be deleted, along with the robot. We verify a few of the
|
|
# critical ones below.
|
|
|
|
# Check the team.
|
|
team = model.team.get_organization_team(ORGANIZATION, 'readers')
|
|
members = [member.username
|
|
for member in model.organization.get_organization_team_members(team.id)]
|
|
self.assertFalse(membername in members)
|
|
|
|
# Check the robot itself.
|
|
self.assertIsNone(model.user.get_user(membername))
|
|
|
|
|
|
def test_robots(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Create a robot.
|
|
json = self.putJsonResponse(OrgRobot,
|
|
params=dict(orgname=ORGANIZATION, robot_shortname='bender'),
|
|
expected_code=201)
|
|
|
|
self.assertEquals(ORGANIZATION + '+bender', json['name'])
|
|
|
|
# Verify.
|
|
robots = self.getRobotNames()
|
|
assert ORGANIZATION + '+bender' in robots
|
|
|
|
# Delete the robot.
|
|
self.deleteResponse(OrgRobot,
|
|
params=dict(orgname=ORGANIZATION, robot_shortname='bender'))
|
|
|
|
# Verify.
|
|
robots = self.getRobotNames()
|
|
assert not ORGANIZATION + '+bender' in robots
|
|
|
|
|
|
def test_regenerate(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Create a robot.
|
|
json = self.putJsonResponse(OrgRobot,
|
|
params=dict(orgname=ORGANIZATION, robot_shortname='bender'),
|
|
expected_code=201)
|
|
|
|
token = json['token']
|
|
|
|
# Regenerate the robot.
|
|
json = self.postJsonResponse(RegenerateOrgRobot,
|
|
params=dict(orgname=ORGANIZATION, robot_shortname='bender'),
|
|
expected_code=200)
|
|
|
|
# Verify the token changed.
|
|
self.assertNotEquals(token, json['token'])
|
|
|
|
json2 = self.getJsonResponse(OrgRobot,
|
|
params=dict(orgname=ORGANIZATION, robot_shortname='bender'),
|
|
expected_code=200)
|
|
|
|
self.assertEquals(json['token'], json2['token'])
|
|
|
|
|
|
class TestLogs(ApiTestCase):
|
|
def test_user_logs(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(UserLogs)
|
|
assert 'logs' in json
|
|
assert 'start_time' in json
|
|
assert 'end_time' in json
|
|
|
|
def test_org_logs(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(OrgLogs, params=dict(orgname=ORGANIZATION))
|
|
assert 'logs' in json
|
|
assert 'start_time' in json
|
|
assert 'end_time' in json
|
|
|
|
def test_user_aggregate_logs(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(UserAggregateLogs)
|
|
assert 'aggregated' in json
|
|
|
|
|
|
def test_org_logs(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(OrgAggregateLogs, params=dict(orgname=ORGANIZATION))
|
|
assert 'aggregated' in json
|
|
|
|
|
|
def test_performer(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(OrgLogs, params=dict(orgname=ORGANIZATION))
|
|
all_logs = json['logs']
|
|
|
|
json = self.getJsonResponse(OrgLogs,
|
|
params=dict(performer=READ_ACCESS_USER, orgname=ORGANIZATION))
|
|
|
|
assert len(json['logs']) < len(all_logs)
|
|
for log in json['logs']:
|
|
self.assertEquals(READ_ACCESS_USER, log['performer']['name'])
|
|
|
|
|
|
class TestApplicationInformation(ApiTestCase):
|
|
def test_get_info(self):
|
|
json = self.getJsonResponse(ApplicationInformation,
|
|
params=dict(client_id=FAKE_APPLICATION_CLIENT_ID))
|
|
assert 'name' in json
|
|
assert 'uri' in json
|
|
assert 'organization' in json
|
|
|
|
def test_get_invalid_info(self):
|
|
self.getJsonResponse(ApplicationInformation, params=dict(client_id='invalid-code'),
|
|
expected_code=404)
|
|
|
|
|
|
class TestOrganizationApplications(ApiTestCase):
|
|
def test_list_create_applications(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(OrganizationApplications, params=dict(orgname=ORGANIZATION))
|
|
|
|
self.assertEquals(2, len(json['applications']))
|
|
|
|
found = False
|
|
for application in json['applications']:
|
|
if application['client_id'] == FAKE_APPLICATION_CLIENT_ID:
|
|
found = True
|
|
break
|
|
|
|
self.assertTrue(found)
|
|
|
|
# Add a new application.
|
|
json = self.postJsonResponse(OrganizationApplications, params=dict(orgname=ORGANIZATION),
|
|
data=dict(name="Some cool app", description="foo"))
|
|
|
|
self.assertEquals("Some cool app", json['name'])
|
|
self.assertEquals("foo", json['description'])
|
|
|
|
# Retrieve the apps list again
|
|
list_json = self.getJsonResponse(OrganizationApplications, params=dict(orgname=ORGANIZATION))
|
|
self.assertEquals(3, len(list_json['applications']))
|
|
|
|
|
|
class TestOrganizationApplicationResource(ApiTestCase):
|
|
def test_get_edit_delete_application(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Retrieve the application.
|
|
json = self.getJsonResponse(OrganizationApplicationResource,
|
|
params=dict(orgname=ORGANIZATION,
|
|
client_id=FAKE_APPLICATION_CLIENT_ID))
|
|
|
|
self.assertEquals(FAKE_APPLICATION_CLIENT_ID, json['client_id'])
|
|
|
|
# Edit the application.
|
|
edit_json = self.putJsonResponse(OrganizationApplicationResource,
|
|
params=dict(orgname=ORGANIZATION,
|
|
client_id=FAKE_APPLICATION_CLIENT_ID),
|
|
data=dict(name="Some App", description="foo",
|
|
application_uri="bar", redirect_uri="baz",
|
|
avatar_email="meh"))
|
|
|
|
self.assertEquals(FAKE_APPLICATION_CLIENT_ID, edit_json['client_id'])
|
|
self.assertEquals("Some App", edit_json['name'])
|
|
self.assertEquals("foo", edit_json['description'])
|
|
self.assertEquals("bar", edit_json['application_uri'])
|
|
self.assertEquals("baz", edit_json['redirect_uri'])
|
|
self.assertEquals("meh", edit_json['avatar_email'])
|
|
|
|
# Retrieve the application again.
|
|
json = self.getJsonResponse(OrganizationApplicationResource,
|
|
params=dict(orgname=ORGANIZATION,
|
|
client_id=FAKE_APPLICATION_CLIENT_ID))
|
|
|
|
self.assertEquals(json, edit_json)
|
|
|
|
# Delete the application.
|
|
self.deleteResponse(OrganizationApplicationResource,
|
|
params=dict(orgname=ORGANIZATION, client_id=FAKE_APPLICATION_CLIENT_ID))
|
|
|
|
# Make sure the application is gone.
|
|
self.getJsonResponse(OrganizationApplicationResource,
|
|
params=dict(orgname=ORGANIZATION, client_id=FAKE_APPLICATION_CLIENT_ID),
|
|
expected_code=404)
|
|
|
|
|
|
class TestOrganization(ApiTestCase):
|
|
def test_change_send_billing_invoice(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
self.putJsonResponse(Organization, params=dict(orgname=ORGANIZATION),
|
|
data=dict(invoice_email=False, invoice_email_address=None))
|
|
|
|
|
|
class TestOrganizationApplicationResetClientSecret(ApiTestCase):
|
|
def test_reset_client_secret(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Retrieve the application.
|
|
json = self.getJsonResponse(OrganizationApplicationResource,
|
|
params=dict(orgname=ORGANIZATION,
|
|
client_id=FAKE_APPLICATION_CLIENT_ID))
|
|
|
|
self.assertEquals(FAKE_APPLICATION_CLIENT_ID, json['client_id'])
|
|
|
|
# Reset the client secret.
|
|
reset_json = self.postJsonResponse(OrganizationApplicationResetClientSecret,
|
|
params=dict(orgname=ORGANIZATION,
|
|
client_id=FAKE_APPLICATION_CLIENT_ID))
|
|
|
|
self.assertEquals(FAKE_APPLICATION_CLIENT_ID, reset_json['client_id'])
|
|
self.assertNotEquals(reset_json['client_secret'], json['client_secret'])
|
|
|
|
# Verify it was changed in the DB.
|
|
json = self.getJsonResponse(OrganizationApplicationResource,
|
|
params=dict(orgname=ORGANIZATION,
|
|
client_id=FAKE_APPLICATION_CLIENT_ID))
|
|
self.assertEquals(reset_json['client_secret'], json['client_secret'])
|
|
|
|
|
|
|
|
class FakeBuildTrigger(BuildTriggerHandler):
|
|
@classmethod
|
|
def service_name(cls):
|
|
return 'fakeservice'
|
|
|
|
def list_build_sources(self):
|
|
return [{'first': 'source'}, {'second': self.auth_token}]
|
|
|
|
def list_build_subdirs(self):
|
|
return [self.auth_token, 'foo', 'bar', self.config['somevalue']]
|
|
|
|
def handle_trigger_request(self, request):
|
|
prepared = PreparedBuild(self.trigger)
|
|
prepared.build_name = 'build-name'
|
|
prepared.tags = ['bar']
|
|
prepared.dockerfile_id = 'foo'
|
|
prepared.subdirectory = 'subdir'
|
|
prepared.metadata = {'foo': 'bar'}
|
|
prepared.is_manual = False
|
|
return prepared
|
|
|
|
def is_active(self):
|
|
return 'active' in self.config and self.config['active']
|
|
|
|
def activate(self, standard_webhook_url):
|
|
self.config['active'] = True
|
|
return self.config, {}
|
|
|
|
def deactivate(self):
|
|
self.config['active'] = False
|
|
return self.config
|
|
|
|
def manual_start(self, run_parameters=None):
|
|
prepared = PreparedBuild(self.trigger)
|
|
prepared.build_name = 'build-name'
|
|
prepared.tags = ['bar']
|
|
prepared.dockerfile_id = 'foo'
|
|
prepared.subdirectory = 'subdir'
|
|
prepared.metadata = {'foo': 'bar'}
|
|
prepared.is_manual = True
|
|
return prepared
|
|
|
|
def get_repository_url(self):
|
|
return 'http://foo/' + self.config['build_source']
|
|
|
|
def load_dockerfile_contents(self):
|
|
if not 'dockerfile' in self.config:
|
|
return None
|
|
|
|
return self.config['dockerfile']
|
|
|
|
def list_field_values(self, field_name, limit=None):
|
|
if field_name == 'test_field':
|
|
return [1, 2, 3]
|
|
|
|
return None
|
|
|
|
|
|
class TestBuildTriggers(ApiTestCase):
|
|
def test_list_build_triggers(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Check a repo with no known triggers.
|
|
json = self.getJsonResponse(BuildTriggerList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
self.assertEquals(0, len(json['triggers']))
|
|
|
|
# Check a repo with one known trigger.
|
|
json = self.getJsonResponse(BuildTriggerList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/building'))
|
|
self.assertEquals(1, len(json['triggers']))
|
|
|
|
trigger = json['triggers'][0]
|
|
|
|
assert 'id' in trigger
|
|
assert 'is_active' in trigger
|
|
assert 'config' in trigger
|
|
assert 'service' in trigger
|
|
|
|
# Verify the get trigger method.
|
|
trigger_json = self.getJsonResponse(BuildTrigger,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/building',
|
|
trigger_uuid=trigger['id']))
|
|
|
|
self.assertEquals(trigger, trigger_json)
|
|
|
|
# Check the recent builds for the trigger.
|
|
builds_json = self.getJsonResponse(TriggerBuildList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/building',
|
|
trigger_uuid=trigger['id']))
|
|
|
|
assert 'builds' in builds_json
|
|
|
|
def test_delete_build_trigger(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(BuildTriggerList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/building'))
|
|
self.assertEquals(1, len(json['triggers']))
|
|
trigger = json['triggers'][0]
|
|
|
|
# Delete the trigger.
|
|
self.deleteResponse(BuildTrigger, params=dict(repository=ADMIN_ACCESS_USER + '/building',
|
|
trigger_uuid=trigger['id']))
|
|
|
|
# Verify it was deleted.
|
|
json = self.getJsonResponse(BuildTriggerList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/building'))
|
|
self.assertEquals(0, len(json['triggers']))
|
|
|
|
|
|
def test_analyze_fake_trigger(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
database.BuildTriggerService.create(name='fakeservice')
|
|
|
|
# Add a new fake trigger.
|
|
repo = model.repository.get_repository(ADMIN_ACCESS_USER, 'simple')
|
|
user = model.user.get_user(ADMIN_ACCESS_USER)
|
|
trigger = model.build.create_build_trigger(repo, 'fakeservice', 'sometoken', user)
|
|
|
|
# Analyze the trigger's dockerfile: First, no dockerfile.
|
|
trigger_config = {}
|
|
analyze_json = self.postJsonResponse(BuildTriggerAnalyze,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config': trigger_config})
|
|
|
|
self.assertEquals('error', analyze_json['status'])
|
|
self.assertEquals('Could not read the Dockerfile for the trigger', analyze_json['message'])
|
|
|
|
# Analyze the trigger's dockerfile: Second, missing FROM in dockerfile.
|
|
trigger_config = {'dockerfile': 'MAINTAINER me'}
|
|
analyze_json = self.postJsonResponse(BuildTriggerAnalyze,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config': trigger_config})
|
|
|
|
self.assertEquals('warning', analyze_json['status'])
|
|
self.assertEquals('No FROM line found in the Dockerfile', analyze_json['message'])
|
|
|
|
# Analyze the trigger's dockerfile: Third, dockerfile with public repo.
|
|
trigger_config = {'dockerfile': 'FROM somerepo'}
|
|
analyze_json = self.postJsonResponse(BuildTriggerAnalyze,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config': trigger_config})
|
|
|
|
self.assertEquals('publicbase', analyze_json['status'])
|
|
|
|
# Analyze the trigger's dockerfile: Fourth, dockerfile with private repo with an invalid path.
|
|
trigger_config = {'dockerfile': 'FROM localhost:5000/somepath'}
|
|
analyze_json = self.postJsonResponse(BuildTriggerAnalyze,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config': trigger_config})
|
|
|
|
self.assertEquals('warning', analyze_json['status'])
|
|
self.assertEquals('"localhost:5000/somepath" is not a valid Quay repository path',
|
|
analyze_json['message'])
|
|
|
|
# Analyze the trigger's dockerfile: Fifth, dockerfile with private repo that does not exist.
|
|
trigger_config = {'dockerfile': 'FROM localhost:5000/nothere/randomrepo'}
|
|
analyze_json = self.postJsonResponse(BuildTriggerAnalyze,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config': trigger_config})
|
|
|
|
self.assertEquals('error', analyze_json['status'])
|
|
nofound = 'Repository "localhost:5000/%s/randomrepo" referenced by the Dockerfile was not found'
|
|
self.assertEquals(nofound % 'nothere', analyze_json['message'])
|
|
|
|
# Analyze the trigger's dockerfile: Sixth, dockerfile with private repo that the user cannot see
|
|
trigger_config = {'dockerfile': 'FROM localhost:5000/randomuser/randomrepo'}
|
|
analyze_json = self.postJsonResponse(BuildTriggerAnalyze,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config': trigger_config})
|
|
|
|
self.assertEquals('error', analyze_json['status'])
|
|
self.assertEquals(nofound % 'randomuser', analyze_json['message'])
|
|
|
|
# Analyze the trigger's dockerfile: Seventh, dockerfile with private repo that the user see.
|
|
trigger_config = {'dockerfile': 'FROM localhost:5000/devtable/complex'}
|
|
analyze_json = self.postJsonResponse(BuildTriggerAnalyze,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config': trigger_config})
|
|
|
|
self.assertEquals('analyzed', analyze_json['status'])
|
|
self.assertEquals('devtable', analyze_json['namespace'])
|
|
self.assertEquals('complex', analyze_json['name'])
|
|
self.assertEquals(False, analyze_json['is_public'])
|
|
self.assertEquals(ADMIN_ACCESS_USER + '+dtrobot', analyze_json['robots'][0]['name'])
|
|
|
|
|
|
def test_fake_trigger(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
database.BuildTriggerService.create(name='fakeservice')
|
|
|
|
# Add a new fake trigger.
|
|
repo = model.repository.get_repository(ADMIN_ACCESS_USER, 'simple')
|
|
user = model.user.get_user(ADMIN_ACCESS_USER)
|
|
trigger = model.build.create_build_trigger(repo, 'fakeservice', 'sometoken', user)
|
|
|
|
# Verify the trigger.
|
|
json = self.getJsonResponse(BuildTriggerList,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'))
|
|
self.assertEquals(1, len(json['triggers']))
|
|
self.assertEquals(trigger.uuid, json['triggers'][0]['id'])
|
|
self.assertEquals(trigger.service.name, json['triggers'][0]['service'])
|
|
self.assertEquals(False, json['triggers'][0]['is_active'])
|
|
|
|
# List the trigger's sources.
|
|
source_json = self.getJsonResponse(BuildTriggerSources,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid))
|
|
self.assertEquals([{'first': 'source'}, {'second': 'sometoken'}], source_json['sources'])
|
|
|
|
# List the trigger's subdirs.
|
|
subdir_json = self.postJsonResponse(BuildTriggerSubdirs,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'somevalue': 'meh'})
|
|
|
|
self.assertEquals({'status': 'success', 'subdir': ['sometoken', 'foo', 'bar', 'meh']},
|
|
subdir_json)
|
|
|
|
# Activate the trigger.
|
|
trigger_config = {
|
|
'build_source': 'somesource'
|
|
}
|
|
activate_json = self.postJsonResponse(BuildTriggerActivate,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config': trigger_config})
|
|
|
|
self.assertEquals(True, activate_json['is_active'])
|
|
|
|
# Make sure the trigger has a write token.
|
|
trigger = model.build.get_build_trigger(trigger.uuid)
|
|
self.assertNotEquals(None, trigger.write_token)
|
|
self.assertEquals(True, py_json.loads(trigger.config)['active'])
|
|
|
|
# Make sure we cannot activate again.
|
|
self.postResponse(BuildTriggerActivate,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config': trigger_config},
|
|
expected_code=400)
|
|
|
|
# Retrieve values for a field.
|
|
result = self.postJsonResponse(BuildTriggerFieldValues,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid, field_name="test_field"))
|
|
|
|
self.assertEquals(result['values'], [1, 2, 3])
|
|
|
|
self.postResponse(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
|
|
self.assertEquals("build-name", start_json['display_name'])
|
|
self.assertEquals(['bar'], start_json['tags'])
|
|
self.assertEquals('subdir', start_json['subdirectory'])
|
|
self.assertEquals('somesource', start_json['trigger']['build_source'])
|
|
|
|
# Verify the metadata was added.
|
|
build_obj = database.RepositoryBuild.get(database.RepositoryBuild.uuid == start_json['id'])
|
|
self.assertEquals('bar', py_json.loads(build_obj.job_config)['trigger_metadata']['foo'])
|
|
|
|
# Start another manual build, with a ref.
|
|
start_json = self.postJsonResponse(ActivateBuildTrigger,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data=dict(refs={'kind': 'branch', 'name': 'foobar'}),
|
|
expected_code=201)
|
|
|
|
def test_invalid_robot_account(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
database.BuildTriggerService.create(name='fakeservice')
|
|
|
|
# Add a new fake trigger.
|
|
repo = model.repository.get_repository(ADMIN_ACCESS_USER, 'simple')
|
|
user = model.user.get_user(ADMIN_ACCESS_USER)
|
|
trigger = model.build.create_build_trigger(repo, 'fakeservice', 'sometoken', user)
|
|
|
|
# Try to activate it with an invalid robot account.
|
|
trigger_config = {}
|
|
self.postJsonResponse(BuildTriggerActivate,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config': trigger_config, 'pull_robot': 'someinvalidrobot'},
|
|
expected_code=404)
|
|
|
|
def test_unauthorized_robot_account(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
database.BuildTriggerService.create(name='fakeservice')
|
|
|
|
# Add a new fake trigger.
|
|
repo = model.repository.get_repository(ADMIN_ACCESS_USER, 'simple')
|
|
user = model.user.get_user(ADMIN_ACCESS_USER)
|
|
trigger = model.build.create_build_trigger(repo, 'fakeservice', 'sometoken', user)
|
|
|
|
# Try to activate it with a robot account in the wrong namespace.
|
|
trigger_config = {}
|
|
self.postJsonResponse(BuildTriggerActivate,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config':trigger_config, 'pull_robot':'freshuser+anotherrobot'},
|
|
expected_code=403)
|
|
|
|
def test_robot_account(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
database.BuildTriggerService.create(name='fakeservice')
|
|
|
|
# Add a new fake trigger.
|
|
repo = model.repository.get_repository(ADMIN_ACCESS_USER, 'simple')
|
|
user = model.user.get_user(ADMIN_ACCESS_USER)
|
|
trigger = model.build.create_build_trigger(repo, 'fakeservice', 'sometoken', user)
|
|
|
|
# Try to activate it with a robot account.
|
|
trigger_config = {}
|
|
activate_json = self.postJsonResponse(BuildTriggerActivate,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data={'config':trigger_config,
|
|
'pull_robot':ADMIN_ACCESS_USER + '+dtrobot'})
|
|
|
|
# Verify that the robot was saved.
|
|
self.assertEquals(True, activate_json['is_active'])
|
|
self.assertEquals(ADMIN_ACCESS_USER + '+dtrobot', activate_json['pull_robot']['name'])
|
|
|
|
# Start a manual build.
|
|
start_json = self.postJsonResponse(ActivateBuildTrigger,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
trigger_uuid=trigger.uuid),
|
|
data=dict(refs=dict(kind='branch', name='foobar')),
|
|
expected_code=201)
|
|
|
|
assert 'id' in start_json
|
|
self.assertEquals("build-name", start_json['display_name'])
|
|
self.assertEquals(['bar'], start_json['tags'])
|
|
|
|
|
|
class TestUserAuthorizations(ApiTestCase):
|
|
def test_list_get_delete_user_authorizations(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(UserAuthorizationList)
|
|
|
|
self.assertEquals(1, len(json['authorizations']))
|
|
|
|
authorization = json['authorizations'][0]
|
|
|
|
assert 'uuid' in authorization
|
|
assert 'scopes' in authorization
|
|
assert 'application' in authorization
|
|
|
|
# Retrieve the authorization.
|
|
get_json = self.getJsonResponse(UserAuthorization,
|
|
params=dict(access_token_uuid=authorization['uuid']))
|
|
self.assertEquals(authorization, get_json)
|
|
|
|
# Delete the authorization.
|
|
self.deleteResponse(UserAuthorization, params=dict(access_token_uuid=authorization['uuid']))
|
|
|
|
# Verify it has been deleted.
|
|
self.getJsonResponse(UserAuthorization, params=dict(access_token_uuid=authorization['uuid']),
|
|
expected_code=404)
|
|
|
|
|
|
class TestSuperUserLogs(ApiTestCase):
|
|
def test_get_logs(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(SuperUserLogs)
|
|
|
|
assert 'logs' in json
|
|
assert len(json['logs']) > 0
|
|
|
|
|
|
class TestSuperUserList(ApiTestCase):
|
|
def test_get_users(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(SuperUserList)
|
|
|
|
assert 'users' in json
|
|
assert len(json['users']) > 0
|
|
|
|
|
|
class TestSuperUserCreateInitialSuperUser(ApiTestCase):
|
|
def test_create_superuser(self):
|
|
data = {
|
|
'username': 'newsuper',
|
|
'password': 'password',
|
|
'email': 'jschorr+fake@devtable.com',
|
|
}
|
|
|
|
# Try to write before some config. Should 403.
|
|
self.postResponse(SuperUserCreateInitialSuperUser, data=data, expected_code=403)
|
|
|
|
# Add some fake config.
|
|
fake_config = {
|
|
'AUTHENTICATION_TYPE': 'Database',
|
|
'SECRET_KEY': 'fakekey',
|
|
}
|
|
|
|
self.putJsonResponse(SuperUserConfig, data=dict(config=fake_config, hostname='fakehost'))
|
|
|
|
# Try to write with config. Should 403 since there are users in the DB.
|
|
self.postResponse(SuperUserCreateInitialSuperUser, data=data, expected_code=403)
|
|
|
|
# Delete all users in the DB.
|
|
for user in list(database.User.select()):
|
|
user.delete_instance(recursive=True)
|
|
|
|
# Create the superuser.
|
|
self.postJsonResponse(SuperUserCreateInitialSuperUser, data=data)
|
|
|
|
# Ensure the user exists in the DB.
|
|
self.assertIsNotNone(model.user.get_user('newsuper'))
|
|
|
|
# Ensure that the current user is newsuper.
|
|
json = self.getJsonResponse(User)
|
|
self.assertEquals('newsuper', json['username'])
|
|
|
|
# Ensure that the current user is a superuser in the config.
|
|
json = self.getJsonResponse(SuperUserConfig)
|
|
self.assertEquals(['newsuper'], json['config']['SUPER_USERS'])
|
|
|
|
# Ensure that the current user is a superuser in memory by trying to call an API
|
|
# that will fail otherwise.
|
|
self.getResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'))
|
|
|
|
|
|
class TestSuperUserConfig(ApiTestCase):
|
|
def test_get_status_update_config(self):
|
|
# With no config the status should be 'config-db'.
|
|
json = self.getJsonResponse(SuperUserRegistryStatus)
|
|
self.assertEquals('config-db', json['status'])
|
|
|
|
# And the config should 401.
|
|
self.getResponse(SuperUserConfig, expected_code=401)
|
|
|
|
# Add some fake config.
|
|
fake_config = {
|
|
'AUTHENTICATION_TYPE': 'Database',
|
|
'SECRET_KEY': 'fakekey',
|
|
}
|
|
|
|
json = self.putJsonResponse(SuperUserConfig, data=dict(config=fake_config, hostname='fakehost'))
|
|
self.assertEquals('fakekey', json['config']['SECRET_KEY'])
|
|
self.assertEquals('fakehost', json['config']['SERVER_HOSTNAME'])
|
|
self.assertEquals('Database', json['config']['AUTHENTICATION_TYPE'])
|
|
|
|
# With config the status should be 'setup-db'.
|
|
json = self.getJsonResponse(SuperUserRegistryStatus)
|
|
self.assertEquals('setup-db', json['status'])
|
|
|
|
def test_config_file(self):
|
|
# Try without an account. Should 403.
|
|
self.getResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'), expected_code=403)
|
|
|
|
# Login to a superuser.
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Try for an invalid file. Should 404.
|
|
self.getResponse(SuperUserConfigFile, params=dict(filename='foobar'), expected_code=404)
|
|
|
|
# Try for a valid filename. Should not exist.
|
|
json = self.getJsonResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'))
|
|
self.assertFalse(json['exists'])
|
|
|
|
# Add the file.
|
|
self.postResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'),
|
|
file=(StringIO('my file contents'), 'ssl.cert'))
|
|
|
|
# Should now exist.
|
|
json = self.getJsonResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'))
|
|
self.assertTrue(json['exists'])
|
|
|
|
|
|
|
|
@urlmatch(netloc=r'(.*\.)?mockclairservice', path=r'/v1/layers/(.+)')
|
|
def get_layer_success_mock(url, request):
|
|
vulnerabilities = [
|
|
{
|
|
"Name": "CVE-2014-9471",
|
|
"Namespace": "debian:8",
|
|
"Description": "The parse_datetime function in GNU coreutils allows remote attackers to cause a denial of service (crash) or possibly execute arbitrary code via a crafted date string, as demonstrated by the \"--date=TZ=\"123\"345\" @1\" string to the touch or date command.",
|
|
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
|
"Severity": "Low",
|
|
"FixedBy": "9.23-5"
|
|
}
|
|
]
|
|
|
|
features = [
|
|
{
|
|
"Name": "coreutils",
|
|
"Namespace": "debian:8",
|
|
"Version": "8.23-4",
|
|
"Vulnerabilities": vulnerabilities,
|
|
}
|
|
]
|
|
|
|
if not request.url.index('vulnerabilities') > 0:
|
|
vulnerabilities = []
|
|
|
|
if not request.url.index('features') > 0:
|
|
features = []
|
|
|
|
return py_json.dumps({
|
|
"Layer": {
|
|
"Name": "17675ec01494d651e1ccf81dc9cf63959ebfeed4f978fddb1666b6ead008ed52",
|
|
"Namespace": "debian:8",
|
|
"ParentName": "140f9bdfeb9784cf8730e9dab5dd12fbd704151cf555ac8cae650451794e5ac2",
|
|
"IndexedByVersion": 1,
|
|
"Features": features
|
|
}
|
|
})
|
|
|
|
|
|
|
|
class TestRepositoryImageSecurity(ApiTestCase):
|
|
def test_get_vulnerabilities(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
layer = model.tag.get_tag_image(ADMIN_ACCESS_USER, 'simple', 'latest')
|
|
|
|
# Grab the security info for the tag. It should be queued.
|
|
response = self.getJsonResponse(RepositoryImageSecurity,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
imageid=layer.docker_image_id,
|
|
vulnerabilities='true'))
|
|
self.assertEquals('queued', response['status'])
|
|
|
|
# Mark the layer as indexed.
|
|
layer.security_indexed = True
|
|
layer.security_indexed_engine = app.config['SECURITY_SCANNER']['ENGINE_VERSION_TARGET']
|
|
layer.save()
|
|
|
|
# Grab the security info again.
|
|
with HTTMock(get_layer_success_mock):
|
|
response = self.getJsonResponse(RepositoryImageSecurity,
|
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
|
imageid=layer.docker_image_id,
|
|
vulnerabilities='true'))
|
|
self.assertEquals('scanned', response['status'])
|
|
self.assertEquals(1, response['data']['Layer']['IndexedByVersion'])
|
|
|
|
|
|
class TestSuperUserManagement(ApiTestCase):
|
|
def test_get_user(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
json = self.getJsonResponse(SuperUserManagement, params=dict(username='freshuser'))
|
|
self.assertEquals('freshuser', json['username'])
|
|
self.assertEquals('jschorr+test@devtable.com', json['email'])
|
|
self.assertEquals(False, json['super_user'])
|
|
|
|
def test_delete_user(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Verify the user exists.
|
|
json = self.getJsonResponse(SuperUserManagement, params=dict(username='freshuser'))
|
|
self.assertEquals('freshuser', json['username'])
|
|
|
|
# Delete the user.
|
|
self.deleteResponse(SuperUserManagement, params=dict(username='freshuser'), expected_code=204)
|
|
|
|
# Verify the user no longer exists.
|
|
self.getResponse(SuperUserManagement, params=dict(username='freshuser'), expected_code=404)
|
|
|
|
def test_change_user_password(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Verify the user exists.
|
|
json = self.getJsonResponse(SuperUserManagement, params=dict(username='freshuser'))
|
|
self.assertEquals('freshuser', json['username'])
|
|
self.assertEquals('jschorr+test@devtable.com', json['email'])
|
|
|
|
# Update the user.
|
|
json = self.putJsonResponse(SuperUserManagement, params=dict(username='freshuser'),
|
|
data=dict(password='somepassword'))
|
|
self.assertTrue('encrypted_password' in json)
|
|
|
|
def test_update_user(self):
|
|
self.login(ADMIN_ACCESS_USER)
|
|
|
|
# Verify the user exists.
|
|
json = self.getJsonResponse(SuperUserManagement, params=dict(username='freshuser'))
|
|
self.assertEquals('freshuser', json['username'])
|
|
self.assertEquals('jschorr+test@devtable.com', json['email'])
|
|
|
|
# Update the user.
|
|
json = self.putJsonResponse(SuperUserManagement, params=dict(username='freshuser'),
|
|
data=dict(email='foo@bar.com'))
|
|
self.assertFalse('encrypted_password' in json)
|
|
|
|
# Verify the user was updated.
|
|
json = self.getJsonResponse(SuperUserManagement, params=dict(username='freshuser'))
|
|
self.assertEquals('freshuser', json['username'])
|
|
self.assertEquals('foo@bar.com', json['email'])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|