Merge branch 'orgs' of https://bitbucket.org/yackob03/quay into orgs

This commit is contained in:
Joseph Schorr 2013-11-07 15:19:57 -05:00
commit 5858ba0ee0
18 changed files with 658 additions and 661 deletions

10
app.py
View file

@ -7,7 +7,8 @@ from flask.ext.principal import Principal
from flask.ext.login import LoginManager
from flask.ext.mail import Mail
from config import ProductionConfig, DebugConfig, LocalHostedConfig
from config import (ProductionConfig, DebugConfig, LocalHostedConfig,
TestConfig)
from util import analytics
@ -22,6 +23,9 @@ if stack.startswith('prod'):
elif stack.startswith('localhosted'):
logger.info('Running with debug config on production data.')
config = LocalHostedConfig()
elif stack.startswith('test'):
logger.info('Running with test config on ephemeral data.')
config = TestConfig()
else:
logger.info('Running with debug config.')
config = DebugConfig()
@ -36,6 +40,6 @@ login_manager.init_app(app)
mail = Mail()
mail.init_app(app)
stripe.api_key = app.config['STRIPE_SECRET_KEY']
stripe.api_key = app.config.get('STRIPE_SECRET_KEY', None)
mixpanel = analytics.init_app(app)
mixpanel = app.config['ANALYTICS'].init_app(app)

View file

@ -65,7 +65,8 @@ class ModifyRepositoryPermission(Permission):
admin_need = _RepositoryNeed(namespace, name, 'admin')
write_need = _RepositoryNeed(namespace, name, 'write')
org_admin_need = _OrganizationNeed(namespace, 'admin')
super(ModifyRepositoryPermission, self).__init__(admin_need, write_need)
super(ModifyRepositoryPermission, self).__init__(admin_need, write_need,
org_admin_need)
class ReadRepositoryPermission(Permission):

View file

@ -2,6 +2,13 @@ import logging
import sys
from peewee import MySQLDatabase, SqliteDatabase
from storage.s3 import S3Storage
from storage.local import LocalStorage
from data.userfiles import UserRequestFiles
from util import analytics
from test.teststorage import FakeStorage, FakeUserfiles
from test import analytics as fake_analytics
LOG_FORMAT = '%(asctime)-15s - %(levelname)s - %(pathname)s - ' + \
@ -31,6 +38,12 @@ class SQLiteDB(object):
DB_DRIVER = SqliteDatabase
class EphemeralDB(object):
DB_NAME = ':memory:'
DB_CONNECTION_ARGS = {}
DB_DRIVER = SqliteDatabase
class RDSMySQL(object):
DB_NAME = 'quay'
DB_CONNECTION_ARGS = {
@ -49,12 +62,27 @@ class AWSCredentials(object):
class S3Storage(AWSCredentials):
STORAGE_KIND = 's3'
STORAGE = S3Storage('', AWSCredentials.AWS_ACCESS_KEY,
AWSCredentials.AWS_SECRET_KEY,
AWSCredentials.REGISTRY_S3_BUCKET)
class LocalStorage(object):
STORAGE_KIND = 'local'
LOCAL_STORAGE_DIR = 'test/data/registry'
STORAGE = LocalStorage('test/data/registry')
class FakeStorage(object):
STORAGE = FakeStorage()
class FakeUserfiles(object):
USERFILES = FakeUserfiles()
class S3Userfiles(AWSCredentials):
USERFILES = UserRequestFiles(AWSCredentials.AWS_ACCESS_KEY,
AWSCredentials.AWS_SECRET_KEY,
AWSCredentials.REGISTRY_S3_BUCKET)
class StripeTestConfig(object):
@ -67,11 +95,16 @@ class StripeLiveConfig(object):
STRIPE_PUBLISHABLE_KEY = 'pk_live_P5wLU0vGdHnZGyKnXlFG4oiu'
class FakeAnalytics(object):
ANALYTICS = fake_analytics
class MixpanelTestConfig(object):
ANALYTICS = analytics
MIXPANEL_KEY = '38014a0f27e7bdc3ff8cc7cc29c869f9'
class MixpanelProdConfig(object):
class MixpanelProdConfig(MixpanelTestConfig):
MIXPANEL_KEY = '50ff2b2569faa3a51c8f5724922ffb7e'
@ -100,9 +133,20 @@ class BuildNodeConfig(object):
BUILD_NODE_PULL_TOKEN = 'F02O2E86CQLKZUQ0O81J8XDHQ6F0N1V36L9JTOEEK6GKKMT1GI8PTJQT4OU88Y6G'
class TestConfig(FlaskConfig, FakeStorage, EphemeralDB, FakeUserfiles,
FakeAnalytics):
LOGGING_CONFIG = {
'level': logging.DEBUG,
'format': LOG_FORMAT
}
POPULATE_DB_TEST_DATA = True
TESTING = True
INCLUDE_TEST_ENDPOINTS = True
class DebugConfig(FlaskConfig, MailConfig, LocalStorage, SQLiteDB,
StripeTestConfig, MixpanelTestConfig, GitHubTestConfig,
DigitalOceanConfig, AWSCredentials, BuildNodeConfig):
DigitalOceanConfig, BuildNodeConfig, S3Userfiles):
LOGGING_CONFIG = {
'level': logging.DEBUG,
'format': LOG_FORMAT
@ -115,7 +159,7 @@ class DebugConfig(FlaskConfig, MailConfig, LocalStorage, SQLiteDB,
class LocalHostedConfig(FlaskConfig, MailConfig, S3Storage, RDSMySQL,
StripeLiveConfig, MixpanelTestConfig,
GitHubProdConfig, DigitalOceanConfig,
BuildNodeConfig):
BuildNodeConfig, S3Userfiles):
LOGGING_CONFIG = {
'level': logging.DEBUG,
'format': LOG_FORMAT
@ -125,7 +169,8 @@ class LocalHostedConfig(FlaskConfig, MailConfig, S3Storage, RDSMySQL,
class ProductionConfig(FlaskConfig, MailConfig, S3Storage, RDSMySQL,
StripeLiveConfig, MixpanelProdConfig,
GitHubProdConfig, DigitalOceanConfig, BuildNodeConfig):
GitHubProdConfig, DigitalOceanConfig, BuildNodeConfig,
S3Userfiles):
LOGGING_CONFIG = {
'stream': sys.stderr,
'level': logging.DEBUG,

View file

@ -149,7 +149,11 @@ def remove_team(org_name, team_name, removed_by_username):
def add_user_to_team(user, team):
return TeamMember.create(user=user, team=team)
try:
return TeamMember.create(user=user, team=team)
except Exception:
raise DataModelException('Unable to add user \'%s\' to team: \'%s\'' %
(user.username, team.name))
def remove_user_from_team(org_name, team_name, username, removed_by_username):
@ -164,7 +168,7 @@ def remove_user_from_team(org_name, team_name, username, removed_by_username):
if not found:
raise DataModelException('User %s does not belong to team %s' %
(username, teamname))
(username, team_name))
if username == removed_by_username:
admin_team_query = __get_user_admin_teams(org_name, team_name, username)
@ -722,15 +726,13 @@ def delete_team_permission(team_name, namespace_name, repository_name):
fetched[0].delete_instance()
def __set_entity_repo_permission(entity_id, entity_table, entity_id_property,
permission_entity_property, namespace_name,
repository_name, role_name):
entity = entity_table.get(entity_id_property == entity_id)
def __set_entity_repo_permission(entity, permission_entity_property,
namespace_name, repository_name, role_name):
repo = Repository.get(Repository.name == repository_name,
Repository.namespace == namespace_name)
new_role = Role.get(Role.name == role_name)
# Fetch any existing permission for this user on the repo
# Fetch any existing permission for this entity on the repo
try:
entity_attr = getattr(RepositoryPermission, permission_entity_property)
perm = RepositoryPermission.get(entity_attr == entity,
@ -750,16 +752,21 @@ def set_user_repo_permission(username, namespace_name, repository_name,
if username == namespace_name:
raise DataModelException('Namespace owner must always be admin.')
return __set_entity_repo_permission(username, User, User.username, 'user',
namespace_name, repository_name,
role_name)
user = User.get(User.username == username)
return __set_entity_repo_permission(user, 'user', namespace_name,
repository_name, role_name)
def set_team_repo_permission(team_name, namespace_name, repository_name,
role_name):
return __set_entity_repo_permission(team_name, Team, Team.name, 'team',
namespace_name, repository_name,
role_name)
team = list(Team.select().join(User).where(Team.name == team_name,
User.username == namespace_name))
if not team:
raise DataModelException('No team \'%s\' in organization \'%s\'.' %
(team_name, namespace_name))
return __set_entity_repo_permission(team[0], 'team', namespace_name,
repository_name, role_name)
def purge_repository(namespace_name, repository_name):

View file

@ -11,10 +11,7 @@ from flask.ext.principal import identity_changed, AnonymousIdentity
from functools import wraps
from collections import defaultdict
import storage
from data import model
from data.userfiles import UserRequestFiles
from data.queue import dockerfile_build_queue
from data.plans import USER_PLANS, BUSINESS_PLANS, get_plan
from app import app
@ -33,7 +30,8 @@ from endpoints.web import common_login
from util.cache import cache_control
store = storage.load()
store = app.config['STORAGE']
user_files = app.config['USERFILES']
logger = logging.getLogger(__name__)
@ -46,24 +44,16 @@ def api_login_required(f):
return decorated_view
def required_json_args(*required_args):
def wrap(f):
@wraps(f)
def wrapped(*args, **kwargs):
request_data = request.get_json()
for arg in required_args:
if arg not in request_data:
abort(400)
return f(*args, **kwargs)
return wrapped
return wrap
@app.errorhandler(model.DataModelException)
def handle_dme(ex):
return make_response(ex.message, 400)
@app.errorhandler(KeyError)
def handle_dme(ex):
return make_response(ex.message, 400)
@app.route('/api/')
def welcome():
return make_response('welcome', 200)
@ -135,7 +125,6 @@ def change_user_details():
@app.route('/api/user/', methods=['POST'])
@required_json_args('username', 'password', 'email')
def create_user_api():
user_data = request.get_json()
@ -162,7 +151,6 @@ def create_user_api():
@app.route('/api/signin', methods=['POST'])
@required_json_args('username', 'password')
def signin_api():
signin_data = request.get_json()
@ -202,7 +190,6 @@ def logout():
@app.route("/api/recovery", methods=['POST'])
@required_json_args('email')
def send_recovery():
email = request.get_json()['email']
code = model.create_reset_password_email_code(email)
@ -265,11 +252,6 @@ def get_matching_entities(prefix):
})
user_files = UserRequestFiles(app.config['AWS_ACCESS_KEY'],
app.config['AWS_SECRET_KEY'],
app.config['REGISTRY_S3_BUCKET'])
def team_view(orgname, t):
view_permission = ViewTeamPermission(orgname, t.name)
role = model.get_team_org_role(t).name
@ -526,7 +508,7 @@ def create_repo_api():
if existing:
return make_response('Repository already exists', 400)
visibility = request.get_json()['visibility']
visibility = json['visibility']
repo = model.create_repository(namespace_name, repository_name, owner,
visibility)
@ -621,7 +603,7 @@ def update_repo_api(namespace, repository):
'success': True
})
abort(404)
abort(403)
@app.route('/api/repository/<path:repository>/changevisibility',
@ -750,7 +732,6 @@ def get_repo_builds(namespace, repository):
@app.route('/api/filedrop/', methods=['POST'])
@api_login_required
@required_json_args('mimeType')
def get_filedrop_url():
mime_type = request.get_json()['mimeType']
(url, file_id) = user_files.prepare_for_drop(mime_type)
@ -778,9 +759,11 @@ def request_repo_build(namespace, repository):
tag)
dockerfile_build_queue.put(json.dumps({'build_id': build_request.id}))
return jsonify({
resp = jsonify({
'started': True
})
resp.status_code = 201
return resp
abort(403) # Permissions denied
@ -961,7 +944,7 @@ def get_team_permissions(namespace, repository, teamname):
(namespace, repository, teamname))
permission = AdministerRepositoryPermission(namespace, repository)
if permission.can():
perm = model.get_team_reponame_permission(username, namespace, repository)
perm = model.get_team_reponame_permission(teamname, namespace, repository)
return jsonify(role_view(perm))
abort(403) # Permission denied
@ -979,13 +962,8 @@ def change_user_permissions(namespace, repository, username):
logger.debug('Setting permission to: %s for user %s' %
(new_permission['role'], username))
try:
perm = model.set_user_repo_permission(username, namespace, repository,
new_permission['role'])
except model.DataModelException:
logger.warning('User tried to remove themselves as admin.')
abort(409)
perm = model.set_user_repo_permission(username, namespace, repository,
new_permission['role'])
perm_view = role_view(perm)
try:
@ -1017,12 +995,8 @@ def change_team_permissions(namespace, repository, teamname):
logger.debug('Setting permission to: %s for team %s' %
(new_permission['role'], teamname))
try:
perm = model.set_team_repo_permission(teamname, namespace, repository,
new_permission['role'])
except model.DataModelException:
logger.warning('User tried to remove themselves as admin.')
abort(409)
perm = model.set_team_repo_permission(teamname, namespace, repository,
new_permission['role'])
resp = jsonify(role_view(perm))
if request.method == 'POST':
@ -1039,12 +1013,7 @@ def change_team_permissions(namespace, repository, teamname):
def delete_user_permissions(namespace, repository, username):
permission = AdministerRepositoryPermission(namespace, repository)
if permission.can():
try:
model.delete_user_permission(username, namespace, repository)
except model.DataModelException:
logger.warning('User tried to remove themselves as admin.')
abort(409)
model.delete_user_permission(username, namespace, repository)
return make_response('Deleted', 204)
abort(403) # Permission denied
@ -1057,12 +1026,7 @@ def delete_user_permissions(namespace, repository, username):
def delete_team_permissions(namespace, repository, teamname):
permission = AdministerRepositoryPermission(namespace, repository)
if permission.can():
try:
model.delete_team_permission(teamname, namespace, repository)
except model.DataModelException:
logger.warning('User tried to remove themselves as admin.')
abort(409)
model.delete_team_permission(teamname, namespace, repository)
return make_response('Deleted', 204)
abort(403) # Permission denied

View file

@ -6,7 +6,6 @@ from functools import wraps
from datetime import datetime
from time import time
import storage
from data.queue import image_diff_queue
from app import app
@ -17,7 +16,7 @@ from auth.permissions import (ReadRepositoryPermission,
from data import model
store = storage.load()
store = app.config['STORAGE']
logger = logging.getLogger(__name__)

View file

@ -4,8 +4,6 @@ import json
from flask import abort, request, jsonify, make_response
import storage
from app import app
from util.names import parse_repository_name
from auth.auth import process_auth
@ -14,7 +12,6 @@ from auth.permissions import (ReadRepositoryPermission,
from data import model
store = storage.load()
logger = logging.getLogger(__name__)

View file

@ -8,15 +8,13 @@ from datetime import datetime, timedelta
from flask import url_for
from peewee import SqliteDatabase, create_model_tables, drop_model_tables
import storage
from data.database import *
from data import model
from app import app
logger = logging.getLogger(__name__)
store = storage.load()
store = app.config['STORAGE']
SAMPLE_DIFFS = ['test/data/sample/diffs/diffs%s.json' % i
for i in range(1, 10)]
@ -141,6 +139,10 @@ def populate_database():
new_user_3.verified = True
new_user_3.save()
reader = model.create_user('reader', 'password', 'no1@thanks.com')
reader.verified = True
reader.save()
__generate_repository(new_user_1, 'simple', 'Simple repository.', False,
[], (4, [], ['latest', 'prod']))
@ -168,7 +170,8 @@ def populate_database():
__generate_repository(new_user_1, 'shared',
'Shared repository, another user can write.', False,
[(new_user_2, 'write')], (5, [], 'latest'))
[(new_user_2, 'write'), (reader, 'read')],
(5, [], 'latest'))
building = __generate_repository(new_user_1, 'building',
'Empty repository which is building.',
@ -186,6 +189,7 @@ def populate_database():
model.set_team_repo_permission(reader_team.name, org_repo.namespace,
org_repo.name, 'read')
model.add_user_to_team(new_user_2, reader_team)
model.add_user_to_team(reader, reader_team)
token = model.create_access_token(building, 'write')
tag = 'ci.devtable.com:5000/%s/%s' % (building.namespace, building.name)

View file

@ -1,147 +0,0 @@
import logging
import contextlib
import tempfile
from app import app
__all__ = ['load']
logger = logging.getLogger(__name__)
class Storage(object):
"""Storage is organized as follow:
$ROOT/images/<image_id>/json
$ROOT/images/<image_id>/layer
$ROOT/repositories/<namespace>/<repository_name>/<tag_name>
"""
# Useful if we want to change those locations later without rewriting
# the code which uses Storage
repositories = 'repositories'
images = 'images'
# Set the IO buffer to 64kB
buffer_size = 64 * 1024
#FIXME(samalba): Move all path resolver in each module (out of the base)
def images_list_path(self, namespace, repository):
return '{0}/{1}/{2}/_images_list'.format(self.repositories,
namespace,
repository)
def image_json_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/json'.format(self.images, namespace,
repository, image_id)
def image_mark_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/_inprogress'.format(self.images, namespace,
repository, image_id)
def image_checksum_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/_checksum'.format(self.images, namespace,
repository, image_id)
def image_layer_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/layer'.format(self.images, namespace,
repository, image_id)
def image_ancestry_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/ancestry'.format(self.images, namespace,
repository, image_id)
def repository_namespace_path(self, namespace, repository):
return '{0}/{1}/{2}/'.format(self.images, namespace, repository)
def image_file_trie_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/files.trie'.format(self.images, namespace,
repository, image_id)
def image_file_diffs_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/diffs.json'.format(self.images, namespace,
repository, image_id)
def get_content(self, path):
raise NotImplementedError
def put_content(self, path, content):
raise NotImplementedError
def stream_read(self, path):
raise NotImplementedError
def stream_read_file(self, path):
raise NotImplementedError
def stream_write(self, path, fp):
raise NotImplementedError
def list_directory(self, path=None):
raise NotImplementedError
def exists(self, path):
raise NotImplementedError
def remove(self, path):
raise NotImplementedError
def get_size(self, path):
raise NotImplementedError
@contextlib.contextmanager
def store_stream(stream):
"""Stores the entire stream to a temporary file."""
tmpf = tempfile.TemporaryFile()
while True:
try:
buf = stream.read(4096)
if not buf:
break
tmpf.write(buf)
except IOError:
break
tmpf.seek(0)
yield tmpf
tmpf.close()
def temp_store_handler():
tmpf = tempfile.TemporaryFile()
def fn(buf):
try:
tmpf.write(buf)
except IOError:
pass
return tmpf, fn
from local import LocalStorage
from s3 import S3Storage
_storage = {}
def load(kind=None):
"""Returns the right storage class according to the configuration."""
global _storage
kind = app.config['STORAGE_KIND']
if kind in _storage:
return _storage[kind]
if kind == 's3':
logger.debug('Using s3 storage.')
store = S3Storage('', app.config['AWS_ACCESS_KEY'],
app.config['AWS_SECRET_KEY'],
app.config['REGISTRY_S3_BUCKET'])
elif kind == 'local':
logger.debug('Using local storage.')
store = LocalStorage(app.config['LOCAL_STORAGE_DIR'])
else:
raise ValueError('Not supported storage \'{0}\''.format(kind))
_storage[kind] = store
return store

78
storage/basestorage.py Normal file
View file

@ -0,0 +1,78 @@
class Storage(object):
"""Storage is organized as follow:
$ROOT/images/<image_id>/json
$ROOT/images/<image_id>/layer
$ROOT/repositories/<namespace>/<repository_name>/<tag_name>
"""
# Useful if we want to change those locations later without rewriting
# the code which uses Storage
repositories = 'repositories'
images = 'images'
# Set the IO buffer to 64kB
buffer_size = 64 * 1024
#FIXME(samalba): Move all path resolver in each module (out of the base)
def images_list_path(self, namespace, repository):
return '{0}/{1}/{2}/_images_list'.format(self.repositories,
namespace,
repository)
def image_json_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/json'.format(self.images, namespace,
repository, image_id)
def image_mark_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/_inprogress'.format(self.images, namespace,
repository, image_id)
def image_checksum_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/_checksum'.format(self.images, namespace,
repository, image_id)
def image_layer_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/layer'.format(self.images, namespace,
repository, image_id)
def image_ancestry_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/ancestry'.format(self.images, namespace,
repository, image_id)
def repository_namespace_path(self, namespace, repository):
return '{0}/{1}/{2}/'.format(self.images, namespace, repository)
def image_file_trie_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/files.trie'.format(self.images, namespace,
repository, image_id)
def image_file_diffs_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/diffs.json'.format(self.images, namespace,
repository, image_id)
def get_content(self, path):
raise NotImplementedError
def put_content(self, path, content):
raise NotImplementedError
def stream_read(self, path):
raise NotImplementedError
def stream_read_file(self, path):
raise NotImplementedError
def stream_write(self, path, fp):
raise NotImplementedError
def list_directory(self, path=None):
raise NotImplementedError
def exists(self, path):
raise NotImplementedError
def remove(self, path):
raise NotImplementedError
def get_size(self, path):
raise NotImplementedError

View file

@ -2,7 +2,7 @@
import os
import shutil
from . import Storage
from basestorage import Storage
class LocalStorage(Storage):

View file

@ -5,7 +5,7 @@ import logging
import boto.s3.connection
import boto.s3.key
from . import Storage
from basestorage import Storage
logger = logging.getLogger(__name__)

6
test/analytics.py Normal file
View file

@ -0,0 +1,6 @@
class FakeMixpanel(object):
def send(self, endpoint, json_message):
pass
def init_app(app):
return FakeMixpanel()

Binary file not shown.

View file

@ -7,423 +7,379 @@ from uuid import uuid4
PUBLIC_REPO = 'public/publicrepo'
PRIVATE_REPO = 'devtable/complex'
PRIVATE_REPO = 'devtable/shared'
ORG = 'devtableorg'
ORG_REPO = ORG + '/orgrepo'
ORG_OWNERS = 'owners'
ORG_READERS = 'readers'
ORG_OWNER = 'devtable'
ORG_OWNERS = 'owners'
ORG_READERS = 'readers'
FAKE_IMAGE_ID = uuid4()
FAKE_TAG_NAME = uuid4()
FAKE_USERNAME = uuid4()
FAKE_TEAMNAME = uuid4()
FAKE_TOKEN = uuid4()
FAKE_IMAGE_ID = str(uuid4())
FAKE_TAG_NAME = str(uuid4())
FAKE_USERNAME = str(uuid4())
FAKE_TOKEN = str(uuid4())
NEW_ORG_REPO_DETAILS = {
'repository': str(uuid4()),
'visibility': 'private',
'description': '',
'namespace': ORG,
}
def open_kwargs(method='GET', json_object=None):
kwargs = {
'method': method,
}
NEW_USER_DETAILS = {
'username': 'bob',
'password': 'password',
'email': 'jake@devtable.com',
}
if json_object is not None:
kwargs['data'] = json.dumps(json_object)
kwargs['content_type'] = 'application/json'
SEND_RECOVERY_DETAILS = {
'email': 'jacob.moshenko@gmail.com',
}
elif method == 'POST' or method == 'PUT':
kwargs['data'] = json.dumps({
'fake': 'json',
'data': 'here',
})
kwargs['content_type'] = 'application/json'
SIGNIN_DETAILS = {
'username': 'devtable',
'password': 'password',
}
return kwargs
FILE_DROP_DETAILS = {
'mimeType': 'application/zip',
}
CHANGE_PERMISSION_DETAILS = {
'role': 'admin',
}
def build_anon_spec():
return OrderedDict([
(url_for('welcome'), (200, open_kwargs())),
CREATE_BUILD_DETAILS = {
'file_id': str(uuid4()),
}
(url_for('plans_list'), (200, open_kwargs())),
CHANGE_VISIBILITY_DETAILS = {
'visibility': 'public',
}
(url_for('get_logged_in_user'), (200, open_kwargs())),
CREATE_TOKEN_DETAILS = {
'friendlyName': 'A new token',
}
(url_for('change_user_details'), (401, open_kwargs('PUT'))),
UPDATE_REPO_DETAILS = {
'description': 'A new description',
}
(url_for('create_user_api'), (400, open_kwargs('POST'))),
(url_for('signin_api'), (400, open_kwargs('POST'))),
class TestSpec(object):
def __init__(self, url, anon_code=401, no_access_code=403, read_code=403,
admin_code=200):
self._url = url
self._data = None
self._method = 'GET'
(url_for('send_recovery'), (400, open_kwargs('POST'))),
self.anon_code = anon_code
self.no_access_code = no_access_code
self.read_code = read_code
self.admin_code = admin_code
(url_for('get_matching_users', prefix='dev'), (401, open_kwargs())),
(url_for('get_matching_entities', prefix='dev'), (401, open_kwargs())),
(url_for('get_organization', orgname=ORG), (401, open_kwargs())),
(url_for('get_organization_private_allowed', orgname=ORG),
(401, open_kwargs())),
(url_for('update_organization_team', orgname=ORG, teamname=ORG_OWNERS),
(401, open_kwargs('PUT'))),
(url_for('delete_organization_team', orgname=ORG, teamname=ORG_OWNERS),
(401, open_kwargs('DELETE'))),
(url_for('get_organization_team_members', orgname=ORG,
teamname=ORG_OWNERS), (401, open_kwargs())),
(url_for('update_organization_team_member', orgname=ORG,
teamname=ORG_OWNERS, membername=ORG_OWNER),
(401, open_kwargs('PUT'))),
(url_for('delete_organization_team_member', orgname=ORG,
teamname=ORG_OWNERS, membername=ORG_OWNER),
(401, open_kwargs('DELETE'))),
(url_for('create_repo_api'), (401, open_kwargs('POST'))),
(url_for('match_repos_api'), (200, open_kwargs())),
(url_for('list_repos_api'), (200, open_kwargs())),
(url_for('update_repo_api', repository=PUBLIC_REPO),
(401, open_kwargs('PUT'))),
(url_for('update_repo_api', repository=ORG_REPO),
(401, open_kwargs('PUT'))),
(url_for('update_repo_api', repository=PRIVATE_REPO),
(401, open_kwargs('PUT'))),
(url_for('change_repo_visibility_api', repository=PUBLIC_REPO),
(401, open_kwargs('POST'))),
(url_for('change_repo_visibility_api', repository=ORG_REPO),
(401, open_kwargs('POST'))),
(url_for('change_repo_visibility_api', repository=PRIVATE_REPO),
(401, open_kwargs('POST'))),
(url_for('delete_repository', repository=PUBLIC_REPO),
(401, open_kwargs('DELETE'))),
(url_for('delete_repository', repository=ORG_REPO),
(401, open_kwargs('DELETE'))),
(url_for('delete_repository', repository=PRIVATE_REPO),
(401, open_kwargs('DELETE'))),
(url_for('get_repo_api', repository=PUBLIC_REPO),(200, open_kwargs())),
(url_for('get_repo_api', repository=ORG_REPO), (403, open_kwargs())),
(url_for('get_repo_api', repository=PRIVATE_REPO), (403, open_kwargs())),
(url_for('get_repo_builds', repository=PUBLIC_REPO),
(401, open_kwargs())),
(url_for('get_repo_builds', repository=ORG_REPO), (401, open_kwargs())),
(url_for('get_repo_builds', repository=PRIVATE_REPO),
(401, open_kwargs())),
(url_for('get_filedrop_url'), (401, open_kwargs('POST'))),
(url_for('request_repo_build', repository=PUBLIC_REPO),
(401, open_kwargs('POST'))),
(url_for('request_repo_build', repository=ORG_REPO),
(401, open_kwargs('POST'))),
(url_for('request_repo_build', repository=PRIVATE_REPO),
(401, open_kwargs('POST'))),
(url_for('list_repository_images', repository=PUBLIC_REPO),
(200, open_kwargs())),
(url_for('list_repository_images', repository=ORG_REPO),
(403, open_kwargs())),
(url_for('list_repository_images', repository=PRIVATE_REPO),
(403, open_kwargs())),
(url_for('get_image', repository=PUBLIC_REPO, image_id=FAKE_IMAGE_ID),
(404, open_kwargs())),
(url_for('get_image', repository=ORG_REPO, image_id=FAKE_IMAGE_ID),
(403, open_kwargs())),
(url_for('get_image', repository=PRIVATE_REPO, image_id=FAKE_IMAGE_ID),
(403, open_kwargs())),
(url_for('get_image_changes', repository=PUBLIC_REPO,
image_id=FAKE_IMAGE_ID), (404, open_kwargs())),
(url_for('get_image_changes', repository=ORG_REPO,
image_id=FAKE_IMAGE_ID), (403, open_kwargs())),
(url_for('get_image_changes', repository=PRIVATE_REPO,
image_id=FAKE_IMAGE_ID), (403, open_kwargs())),
(url_for('list_tag_images', repository=PUBLIC_REPO, tag=FAKE_TAG_NAME),
(404, open_kwargs())),
(url_for('list_tag_images', repository=ORG_REPO, tag=FAKE_TAG_NAME),
(403, open_kwargs())),
(url_for('list_tag_images', repository=PRIVATE_REPO, tag=FAKE_TAG_NAME),
(403, open_kwargs())),
(url_for('list_repo_team_permissions', repository=PUBLIC_REPO),
(401, open_kwargs())),
(url_for('list_repo_team_permissions', repository=ORG_REPO),
(401, open_kwargs())),
(url_for('list_repo_team_permissions', repository=PRIVATE_REPO),
(401, open_kwargs())),
(url_for('list_repo_user_permissions', repository=PUBLIC_REPO),
(401, open_kwargs())),
(url_for('list_repo_user_permissions', repository=ORG_REPO),
(401, open_kwargs())),
(url_for('list_repo_user_permissions', repository=PRIVATE_REPO),
(401, open_kwargs())),
(url_for('get_user_permissions', repository=PUBLIC_REPO,
username=FAKE_USERNAME), (401, open_kwargs())),
(url_for('get_user_permissions', repository=ORG_REPO,
username=FAKE_USERNAME), (401, open_kwargs())),
(url_for('get_user_permissions', repository=PRIVATE_REPO,
username=FAKE_USERNAME), (401, open_kwargs())),
(url_for('get_team_permissions', repository=PUBLIC_REPO,
teamname=FAKE_TEAMNAME), (401, open_kwargs())),
(url_for('get_team_permissions', repository=ORG_REPO,
teamname=FAKE_TEAMNAME), (401, open_kwargs())),
(url_for('get_team_permissions', repository=PRIVATE_REPO,
teamname=FAKE_TEAMNAME), (401, open_kwargs())),
(url_for('change_user_permissions', repository=PUBLIC_REPO,
username=FAKE_USERNAME), (401, open_kwargs('PUT'))),
(url_for('change_user_permissions', repository=ORG_REPO,
username=FAKE_USERNAME), (401, open_kwargs('PUT'))),
(url_for('change_user_permissions', repository=PRIVATE_REPO,
username=FAKE_USERNAME), (401, open_kwargs('PUT'))),
(url_for('change_team_permissions', repository=PUBLIC_REPO,
teamname=FAKE_TEAMNAME), (401, open_kwargs('PUT'))),
(url_for('change_team_permissions', repository=ORG_REPO,
teamname=FAKE_TEAMNAME), (401, open_kwargs('PUT'))),
(url_for('change_team_permissions', repository=PRIVATE_REPO,
teamname=FAKE_TEAMNAME), (401, open_kwargs('PUT'))),
(url_for('delete_user_permissions', repository=PUBLIC_REPO,
username=FAKE_USERNAME), (401, open_kwargs('DELETE'))),
(url_for('delete_user_permissions', repository=ORG_REPO,
username=FAKE_USERNAME), (401, open_kwargs('DELETE'))),
(url_for('delete_user_permissions', repository=PRIVATE_REPO,
username=FAKE_USERNAME), (401, open_kwargs('DELETE'))),
(url_for('delete_team_permissions', repository=PUBLIC_REPO,
teamname=FAKE_TEAMNAME), (401, open_kwargs('DELETE'))),
(url_for('delete_team_permissions', repository=ORG_REPO,
teamname=FAKE_TEAMNAME), (401, open_kwargs('DELETE'))),
(url_for('delete_team_permissions', repository=PRIVATE_REPO,
teamname=FAKE_TEAMNAME), (401, open_kwargs('DELETE'))),
(url_for('list_repo_tokens', repository=PUBLIC_REPO),
(401, open_kwargs())),
(url_for('list_repo_tokens', repository=ORG_REPO), (401, open_kwargs())),
(url_for('list_repo_tokens', repository=PRIVATE_REPO),
(401, open_kwargs())),
(url_for('get_tokens', repository=PUBLIC_REPO, code=FAKE_TOKEN),
(401, open_kwargs())),
(url_for('get_tokens', repository=ORG_REPO, code=FAKE_TOKEN),
(401, open_kwargs())),
(url_for('get_tokens', repository=PRIVATE_REPO, code=FAKE_TOKEN),
(401, open_kwargs())),
(url_for('create_token', repository=PUBLIC_REPO),
(401, open_kwargs('POST'))),
(url_for('create_token', repository=ORG_REPO),
(401, open_kwargs('POST'))),
(url_for('create_token', repository=PRIVATE_REPO),
(401, open_kwargs('POST'))),
(url_for('change_token', repository=PUBLIC_REPO, code=FAKE_TOKEN),
(401, open_kwargs('PUT'))),
(url_for('change_token', repository=ORG_REPO, code=FAKE_TOKEN),
(401, open_kwargs('PUT'))),
(url_for('change_token', repository=PRIVATE_REPO, code=FAKE_TOKEN),
(401, open_kwargs('PUT'))),
(url_for('delete_token', repository=PUBLIC_REPO, code=FAKE_TOKEN),
(401, open_kwargs('DELETE'))),
(url_for('delete_token', repository=ORG_REPO, code=FAKE_TOKEN),
(401, open_kwargs('DELETE'))),
(url_for('delete_token', repository=PRIVATE_REPO, code=FAKE_TOKEN),
(401, open_kwargs('DELETE'))),
(url_for('subscribe_api'), (401, open_kwargs('PUT'))),
(url_for('subscribe_org_api', orgname=ORG), (401, open_kwargs('PUT'))),
(url_for('get_subscription'), (401, open_kwargs())),
(url_for('get_org_subscription', orgname=ORG), (401, open_kwargs())),
])
def build_no_access_spec():
changes = OrderedDict([
(url_for('change_user_details'), (200, open_kwargs('PUT'))),
(url_for('get_matching_users', prefix='dev'), (200, open_kwargs())),
(url_for('get_matching_entities', prefix='dev'), (200, open_kwargs())),
(url_for('get_organization', orgname=ORG), (403, open_kwargs())),
(url_for('get_organization_private_allowed', orgname=ORG),
(403, open_kwargs())),
(url_for('update_organization_team', orgname=ORG, teamname=ORG_OWNERS),
(403, open_kwargs('PUT'))),
(url_for('delete_organization_team', orgname=ORG, teamname=ORG_OWNERS),
(403, open_kwargs('DELETE'))),
(url_for('get_organization_team_members', orgname=ORG,
teamname=ORG_OWNERS), (403, open_kwargs())),
(url_for('update_organization_team_member', orgname=ORG,
teamname=ORG_OWNERS, membername=ORG_OWNER),
(403, open_kwargs('PUT'))),
(url_for('delete_organization_team_member', orgname=ORG,
teamname=ORG_OWNERS, membername=ORG_OWNER),
(403, open_kwargs('DELETE'))),
(url_for('create_repo_api'), (403, open_kwargs('POST'))),
(url_for('update_repo_api', repository=PUBLIC_REPO),
(403, open_kwargs('PUT'))),
(url_for('update_repo_api', repository=ORG_REPO),
(403, open_kwargs('PUT'))),
(url_for('update_repo_api', repository=PRIVATE_REPO),
(403, open_kwargs('PUT'))),
(url_for('change_repo_visibility_api', repository=PUBLIC_REPO),
(403, open_kwargs('POST'))),
(url_for('change_repo_visibility_api', repository=ORG_REPO),
(403, open_kwargs('POST'))),
(url_for('change_repo_visibility_api', repository=PRIVATE_REPO),
(403, open_kwargs('POST'))),
(url_for('delete_repository', repository=PUBLIC_REPO),
(403, open_kwargs('DELETE'))),
(url_for('delete_repository', repository=ORG_REPO),
(403, open_kwargs('DELETE'))),
(url_for('delete_repository', repository=PRIVATE_REPO),
(403, open_kwargs('DELETE'))),
(url_for('get_repo_builds', repository=PUBLIC_REPO),
(403, open_kwargs())),
(url_for('get_repo_builds', repository=ORG_REPO), (403, open_kwargs())),
(url_for('get_repo_builds', repository=PRIVATE_REPO),
(403, open_kwargs())),
(url_for('get_filedrop_url'), (400, open_kwargs('POST'))),
(url_for('request_repo_build', repository=PUBLIC_REPO),
(403, open_kwargs('POST'))),
(url_for('request_repo_build', repository=ORG_REPO),
(403, open_kwargs('POST'))),
(url_for('request_repo_build', repository=PRIVATE_REPO),
(403, open_kwargs('POST'))),
(url_for('list_repo_team_permissions', repository=PUBLIC_REPO),
(403, open_kwargs())),
(url_for('list_repo_team_permissions', repository=ORG_REPO),
(403, open_kwargs())),
(url_for('list_repo_team_permissions', repository=PRIVATE_REPO),
(403, open_kwargs())),
(url_for('list_repo_user_permissions', repository=PUBLIC_REPO),
(403, open_kwargs())),
(url_for('list_repo_user_permissions', repository=ORG_REPO),
(403, open_kwargs())),
(url_for('list_repo_user_permissions', repository=PRIVATE_REPO),
(403, open_kwargs())),
(url_for('get_user_permissions', repository=PUBLIC_REPO,
username=FAKE_USERNAME), (403, open_kwargs())),
(url_for('get_user_permissions', repository=ORG_REPO,
username=FAKE_USERNAME), (403, open_kwargs())),
(url_for('get_user_permissions', repository=PRIVATE_REPO,
username=FAKE_USERNAME), (403, open_kwargs())),
(url_for('get_team_permissions', repository=PUBLIC_REPO,
teamname=FAKE_TEAMNAME), (403, open_kwargs())),
(url_for('get_team_permissions', repository=ORG_REPO,
teamname=FAKE_TEAMNAME), (403, open_kwargs())),
(url_for('get_team_permissions', repository=PRIVATE_REPO,
teamname=FAKE_TEAMNAME), (403, open_kwargs())),
(url_for('change_user_permissions', repository=PUBLIC_REPO,
username=FAKE_USERNAME), (403, open_kwargs('PUT'))),
(url_for('change_user_permissions', repository=ORG_REPO,
username=FAKE_USERNAME), (403, open_kwargs('PUT'))),
(url_for('change_user_permissions', repository=PRIVATE_REPO,
username=FAKE_USERNAME), (403, open_kwargs('PUT'))),
(url_for('change_team_permissions', repository=PUBLIC_REPO,
teamname=FAKE_TEAMNAME), (403, open_kwargs('PUT'))),
(url_for('change_team_permissions', repository=ORG_REPO,
teamname=FAKE_TEAMNAME), (403, open_kwargs('PUT'))),
(url_for('change_team_permissions', repository=PRIVATE_REPO,
teamname=FAKE_TEAMNAME), (403, open_kwargs('PUT'))),
(url_for('delete_user_permissions', repository=PUBLIC_REPO,
username=FAKE_USERNAME), (403, open_kwargs('DELETE'))),
(url_for('delete_user_permissions', repository=ORG_REPO,
username=FAKE_USERNAME), (403, open_kwargs('DELETE'))),
(url_for('delete_user_permissions', repository=PRIVATE_REPO,
username=FAKE_USERNAME), (403, open_kwargs('DELETE'))),
(url_for('delete_team_permissions', repository=PUBLIC_REPO,
teamname=FAKE_TEAMNAME), (403, open_kwargs('DELETE'))),
(url_for('delete_team_permissions', repository=ORG_REPO,
teamname=FAKE_TEAMNAME), (403, open_kwargs('DELETE'))),
(url_for('delete_team_permissions', repository=PRIVATE_REPO,
teamname=FAKE_TEAMNAME), (403, open_kwargs('DELETE'))),
(url_for('list_repo_tokens', repository=PUBLIC_REPO),
(403, open_kwargs())),
(url_for('list_repo_tokens', repository=ORG_REPO), (403, open_kwargs())),
(url_for('list_repo_tokens', repository=PRIVATE_REPO),
(403, open_kwargs())),
(url_for('get_tokens', repository=PUBLIC_REPO, code=FAKE_TOKEN),
(403, open_kwargs())),
(url_for('get_tokens', repository=ORG_REPO, code=FAKE_TOKEN),
(403, open_kwargs())),
(url_for('get_tokens', repository=PRIVATE_REPO, code=FAKE_TOKEN),
(403, open_kwargs())),
(url_for('create_token', repository=PUBLIC_REPO),
(403, open_kwargs('POST'))),
(url_for('create_token', repository=ORG_REPO),
(403, open_kwargs('POST'))),
(url_for('create_token', repository=PRIVATE_REPO),
(403, open_kwargs('POST'))),
(url_for('change_token', repository=PUBLIC_REPO, code=FAKE_TOKEN),
(403, open_kwargs('PUT'))),
(url_for('change_token', repository=ORG_REPO, code=FAKE_TOKEN),
(403, open_kwargs('PUT'))),
(url_for('change_token', repository=PRIVATE_REPO, code=FAKE_TOKEN),
(403, open_kwargs('PUT'))),
(url_for('delete_token', repository=PUBLIC_REPO, code=FAKE_TOKEN),
(403, open_kwargs('DELETE'))),
(url_for('delete_token', repository=ORG_REPO, code=FAKE_TOKEN),
(403, open_kwargs('DELETE'))),
(url_for('delete_token', repository=PRIVATE_REPO, code=FAKE_TOKEN),
(403, open_kwargs('DELETE'))),
(url_for('subscribe_api'), (403, open_kwargs('PUT'))),
(url_for('subscribe_org_api', orgname=ORG), (403, open_kwargs('PUT'))),
(url_for('get_subscription'), (200, open_kwargs())),
(url_for('get_org_subscription', orgname=ORG), (403, open_kwargs())),
])
to_update = build_anon_spec()
to_update.update(changes)
return to_update
def set_data_from_obj(self, json_serializable):
self._data = json.dumps(json_serializable)
return self
def set_method(self, method):
self._method = method
return self
def get_client_args(self):
kwargs = {
'method': self._method
}
if self._data or self._method == 'POST' or self._method == 'PUT':
kwargs['data'] = self._data if self._data else '{}'
kwargs['content_type'] = 'application/json'
return self._url, kwargs
def build_specs():
return [
TestSpec(url_for('welcome'), 200, 200, 200, 200),
TestSpec(url_for('plans_list'), 200, 200, 200, 200),
TestSpec(url_for('get_logged_in_user'), 200, 200, 200, 200),
TestSpec(url_for('change_user_details'),
401, 200, 200, 200).set_method('PUT'),
TestSpec(url_for('create_user_api'), 201, 201, 201,
201).set_method('POST').set_data_from_obj(NEW_USER_DETAILS),
TestSpec(url_for('signin_api'), 200, 200, 200,
200).set_method('POST').set_data_from_obj(SIGNIN_DETAILS),
TestSpec(url_for('send_recovery'), 201, 201, 201,
201).set_method('POST').set_data_from_obj(SEND_RECOVERY_DETAILS),
TestSpec(url_for('get_matching_users', prefix='dev'), 401, 200, 200, 200),
TestSpec(url_for('get_matching_entities', prefix='dev'), 401, 200, 200,
200),
TestSpec(url_for('get_organization', orgname=ORG), 401, 403, 200, 200),
TestSpec(url_for('get_organization_private_allowed', orgname=ORG)),
TestSpec(url_for('update_organization_team', orgname=ORG,
teamname=ORG_OWNERS)).set_method('PUT'),
TestSpec(url_for('update_organization_team', orgname=ORG,
teamname=ORG_READERS)).set_method('PUT'),
TestSpec(url_for('delete_organization_team', orgname=ORG,
teamname=ORG_OWNERS),
admin_code=400).set_method('DELETE'),
TestSpec(url_for('delete_organization_team', orgname=ORG,
teamname=ORG_READERS),
admin_code=204).set_method('DELETE'),
TestSpec(url_for('get_organization_team_members', orgname=ORG,
teamname=ORG_OWNERS)),
TestSpec(url_for('get_organization_team_members', orgname=ORG,
teamname=ORG_READERS), read_code=200),
TestSpec(url_for('update_organization_team_member', orgname=ORG,
teamname=ORG_OWNERS, membername=ORG_OWNER),
admin_code=400).set_method('PUT'),
TestSpec(url_for('update_organization_team_member', orgname=ORG,
teamname=ORG_READERS,
membername=ORG_OWNER)).set_method('PUT'),
TestSpec(url_for('delete_organization_team_member', orgname=ORG,
teamname=ORG_OWNERS, membername=ORG_OWNER),
admin_code=400).set_method('DELETE'),
TestSpec(url_for('delete_organization_team_member', orgname=ORG,
teamname=ORG_READERS, membername=ORG_OWNER),
admin_code=400).set_method('DELETE'),
(TestSpec(url_for('create_repo_api'))
.set_method('POST')
.set_data_from_obj(NEW_ORG_REPO_DETAILS)),
TestSpec(url_for('match_repos_api'), 200, 200, 200, 200),
TestSpec(url_for('list_repos_api'), 200, 200, 200, 200),
TestSpec(url_for('update_repo_api', repository=PUBLIC_REPO),
admin_code=403).set_method('PUT'),
(TestSpec(url_for('update_repo_api', repository=ORG_REPO))
.set_method('PUT')
.set_data_from_obj(UPDATE_REPO_DETAILS)),
(TestSpec(url_for('update_repo_api', repository=PRIVATE_REPO))
.set_method('PUT')
.set_data_from_obj(UPDATE_REPO_DETAILS)),
(TestSpec(url_for('change_repo_visibility_api', repository=PUBLIC_REPO),
admin_code=403).set_method('POST')
.set_data_from_obj(CHANGE_VISIBILITY_DETAILS)),
(TestSpec(url_for('change_repo_visibility_api', repository=ORG_REPO))
.set_method('POST').set_data_from_obj(CHANGE_VISIBILITY_DETAILS)),
(TestSpec(url_for('change_repo_visibility_api', repository=PRIVATE_REPO))
.set_method('POST').set_data_from_obj(CHANGE_VISIBILITY_DETAILS)),
TestSpec(url_for('delete_repository', repository=PUBLIC_REPO),
admin_code=403).set_method('DELETE'),
TestSpec(url_for('delete_repository', repository=ORG_REPO),
admin_code=204).set_method('DELETE'),
TestSpec(url_for('delete_repository', repository=PRIVATE_REPO),
admin_code=204).set_method('DELETE'),
TestSpec(url_for('get_repo_api', repository=PUBLIC_REPO),
200, 200, 200,200),
TestSpec(url_for('get_repo_api', repository=ORG_REPO),
403, 403, 200, 200),
TestSpec(url_for('get_repo_api', repository=PRIVATE_REPO),
403, 403, 200, 200),
TestSpec(url_for('get_repo_builds', repository=PUBLIC_REPO),
admin_code=403),
TestSpec(url_for('get_repo_builds', repository=ORG_REPO)),
TestSpec(url_for('get_repo_builds', repository=PRIVATE_REPO)),
TestSpec(url_for('get_filedrop_url'), 401, 200, 200,
200).set_method('POST').set_data_from_obj(FILE_DROP_DETAILS),
(TestSpec(url_for('request_repo_build', repository=PUBLIC_REPO),
admin_code=403).set_method('POST')
.set_data_from_obj(CREATE_BUILD_DETAILS)),
(TestSpec(url_for('request_repo_build', repository=ORG_REPO),
admin_code=201).set_method('POST')
.set_data_from_obj(CREATE_BUILD_DETAILS)),
(TestSpec(url_for('request_repo_build', repository=PRIVATE_REPO),
admin_code=201).set_method('POST')
.set_data_from_obj(CREATE_BUILD_DETAILS)),
TestSpec(url_for('list_repository_images', repository=PUBLIC_REPO),
200, 200, 200, 200),
TestSpec(url_for('list_repository_images', repository=ORG_REPO),
403, 403, 200, 200),
TestSpec(url_for('list_repository_images', repository=PRIVATE_REPO),
403, 403, 200, 200),
TestSpec(url_for('get_image', repository=PUBLIC_REPO,
image_id=FAKE_IMAGE_ID), 404, 404, 404, 404),
TestSpec(url_for('get_image', repository=ORG_REPO,
image_id=FAKE_IMAGE_ID), 403, 403, 404, 404),
TestSpec(url_for('get_image', repository=PRIVATE_REPO,
image_id=FAKE_IMAGE_ID), 403, 403, 404, 404),
TestSpec(url_for('get_image_changes', repository=PUBLIC_REPO,
image_id=FAKE_IMAGE_ID), 404, 404, 404, 404),
TestSpec(url_for('get_image_changes', repository=ORG_REPO,
image_id=FAKE_IMAGE_ID), 403, 403, 404, 404),
TestSpec(url_for('get_image_changes', repository=PRIVATE_REPO,
image_id=FAKE_IMAGE_ID), 403, 403, 404, 404),
TestSpec(url_for('list_tag_images', repository=PUBLIC_REPO,
tag=FAKE_TAG_NAME), 404, 404, 404, 404),
TestSpec(url_for('list_tag_images', repository=ORG_REPO,
tag=FAKE_TAG_NAME), 403, 403, 404, 404),
TestSpec(url_for('list_tag_images', repository=PRIVATE_REPO,
tag=FAKE_TAG_NAME), 403, 403, 404, 404),
TestSpec(url_for('list_repo_team_permissions', repository=PUBLIC_REPO),
admin_code=403),
TestSpec(url_for('list_repo_team_permissions', repository=ORG_REPO)),
TestSpec(url_for('list_repo_team_permissions', repository=PRIVATE_REPO)),
TestSpec(url_for('list_repo_user_permissions', repository=PUBLIC_REPO),
admin_code=403),
TestSpec(url_for('list_repo_user_permissions', repository=ORG_REPO)),
TestSpec(url_for('list_repo_user_permissions', repository=PRIVATE_REPO)),
TestSpec(url_for('get_user_permissions', repository=PUBLIC_REPO,
username=FAKE_USERNAME), admin_code=403),
TestSpec(url_for('get_user_permissions', repository=ORG_REPO,
username=FAKE_USERNAME), admin_code=400),
TestSpec(url_for('get_user_permissions', repository=PRIVATE_REPO,
username=FAKE_USERNAME), admin_code=400),
TestSpec(url_for('get_team_permissions', repository=PUBLIC_REPO,
teamname=ORG_OWNERS), admin_code=403),
TestSpec(url_for('get_team_permissions', repository=PUBLIC_REPO,
teamname=ORG_READERS), admin_code=403),
TestSpec(url_for('get_team_permissions', repository=ORG_REPO,
teamname=ORG_OWNERS), admin_code=400),
TestSpec(url_for('get_team_permissions', repository=ORG_REPO,
teamname=ORG_READERS)),
TestSpec(url_for('get_team_permissions', repository=PRIVATE_REPO,
teamname=ORG_OWNERS), admin_code=400),
TestSpec(url_for('get_team_permissions', repository=PRIVATE_REPO,
teamname=ORG_READERS), admin_code=400),
TestSpec(url_for('change_user_permissions', repository=PUBLIC_REPO,
username=FAKE_USERNAME),
admin_code=403).set_method('PUT'),
TestSpec(url_for('change_user_permissions', repository=ORG_REPO,
username=FAKE_USERNAME),
admin_code=400).set_method('PUT'),
TestSpec(url_for('change_user_permissions', repository=PRIVATE_REPO,
username=FAKE_USERNAME),
admin_code=400).set_method('PUT'),
(TestSpec(url_for('change_team_permissions', repository=PUBLIC_REPO,
teamname=ORG_OWNERS), admin_code=403)
.set_method('PUT')
.set_data_from_obj(CHANGE_PERMISSION_DETAILS)),
(TestSpec(url_for('change_team_permissions', repository=PUBLIC_REPO,
teamname=ORG_READERS), admin_code=403)
.set_method('PUT')
.set_data_from_obj(CHANGE_PERMISSION_DETAILS)),
(TestSpec(url_for('change_team_permissions', repository=ORG_REPO,
teamname=ORG_OWNERS))
.set_method('PUT')
.set_data_from_obj(CHANGE_PERMISSION_DETAILS)),
(TestSpec(url_for('change_team_permissions', repository=ORG_REPO,
teamname=ORG_READERS))
.set_method('PUT')
.set_data_from_obj(CHANGE_PERMISSION_DETAILS)),
(TestSpec(url_for('change_team_permissions', repository=PRIVATE_REPO,
teamname=ORG_OWNERS), admin_code=400)
.set_method('PUT')
.set_data_from_obj(CHANGE_PERMISSION_DETAILS)),
(TestSpec(url_for('change_team_permissions', repository=PRIVATE_REPO,
teamname=ORG_READERS), admin_code=400)
.set_method('PUT')
.set_data_from_obj(CHANGE_PERMISSION_DETAILS)),
TestSpec(url_for('delete_user_permissions', repository=PUBLIC_REPO,
username=FAKE_USERNAME),
admin_code=403).set_method('DELETE'),
TestSpec(url_for('delete_user_permissions', repository=ORG_REPO,
username=FAKE_USERNAME),
admin_code=400).set_method('DELETE'),
TestSpec(url_for('delete_user_permissions', repository=PRIVATE_REPO,
username=FAKE_USERNAME),
admin_code=400).set_method('DELETE'),
TestSpec(url_for('delete_team_permissions', repository=PUBLIC_REPO,
teamname=ORG_OWNERS),
admin_code=403).set_method('DELETE'),
TestSpec(url_for('delete_team_permissions', repository=PUBLIC_REPO,
teamname=ORG_READERS),
admin_code=403).set_method('DELETE'),
TestSpec(url_for('delete_team_permissions', repository=ORG_REPO,
teamname=ORG_OWNERS),
admin_code=400).set_method('DELETE'),
TestSpec(url_for('delete_team_permissions', repository=ORG_REPO,
teamname=ORG_READERS),
admin_code=204).set_method('DELETE'),
TestSpec(url_for('delete_team_permissions', repository=PRIVATE_REPO,
teamname=ORG_OWNERS),
admin_code=400).set_method('DELETE'),
TestSpec(url_for('delete_team_permissions', repository=PRIVATE_REPO,
teamname=ORG_READERS),
admin_code=400).set_method('DELETE'),
TestSpec(url_for('list_repo_tokens', repository=PUBLIC_REPO),
admin_code=403),
TestSpec(url_for('list_repo_tokens', repository=ORG_REPO)),
TestSpec(url_for('list_repo_tokens', repository=PRIVATE_REPO)),
TestSpec(url_for('get_tokens', repository=PUBLIC_REPO, code=FAKE_TOKEN),
admin_code=403),
TestSpec(url_for('get_tokens', repository=ORG_REPO, code=FAKE_TOKEN),
admin_code=400),
TestSpec(url_for('get_tokens', repository=PRIVATE_REPO, code=FAKE_TOKEN),
admin_code=400),
TestSpec(url_for('create_token', repository=PUBLIC_REPO),
admin_code=403).set_method('POST'),
(TestSpec(url_for('create_token', repository=ORG_REPO),
admin_code=201).set_method('POST')
.set_data_from_obj(CREATE_TOKEN_DETAILS)),
(TestSpec(url_for('create_token', repository=PRIVATE_REPO),
admin_code=201).set_method('POST')
.set_data_from_obj(CREATE_TOKEN_DETAILS)),
TestSpec(url_for('change_token', repository=PUBLIC_REPO, code=FAKE_TOKEN),
admin_code=403).set_method('PUT'),
TestSpec(url_for('change_token', repository=ORG_REPO, code=FAKE_TOKEN),
admin_code=400).set_method('PUT'),
TestSpec(url_for('change_token', repository=PRIVATE_REPO,
code=FAKE_TOKEN), admin_code=400).set_method('PUT'),
TestSpec(url_for('delete_token', repository=PUBLIC_REPO, code=FAKE_TOKEN),
admin_code=403).set_method('DELETE'),
TestSpec(url_for('delete_token', repository=ORG_REPO, code=FAKE_TOKEN),
admin_code=400).set_method('DELETE'),
TestSpec(url_for('delete_token', repository=PRIVATE_REPO,
code=FAKE_TOKEN), admin_code=400).set_method('DELETE'),
TestSpec(url_for('subscribe_api'), 401, 400, 400, 400).set_method('PUT'),
TestSpec(url_for('subscribe_org_api', orgname=ORG),
401, 403, 403, 400).set_method('PUT'),
TestSpec(url_for('get_subscription'), 401, 200, 200, 200),
TestSpec(url_for('get_org_subscription', orgname=ORG)),
]

View file

@ -6,10 +6,12 @@ import endpoints.api
from app import app
from data import model
from initdb import wipe_database, initialize_database, populate_database
from specs import build_anon_spec, build_no_access_spec
from specs import build_specs
NO_ACCESS_USER = 'freshuser'
READ_ACCESS_USER = 'reader'
ADMIN_ACCESS_USER = 'devtable'
class ApiTestCase(unittest.TestCase):
@ -19,31 +21,78 @@ class ApiTestCase(unittest.TestCase):
populate_database()
class SpecTestBuilder(type):
@staticmethod
def _test_generator(url, expected_status, open_kwargs, auth_username=None):
def test(self):
with app.test_client() as c:
if auth_username:
# Temporarily remove the teardown functions
teardown_funcs = app.teardown_request_funcs[None]
app.teardown_request_funcs[None] = []
with c.session_transaction() as sess:
sess['user_id'] = auth_username
sess['identity.id'] = auth_username
sess['identity.auth_type'] = 'username'
# Restore the teardown functions
app.teardown_request_funcs[None] = teardown_funcs
rv = c.open(url, **open_kwargs)
msg = '%s %s: %s expected: %s' % (open_kwargs['method'], url,
rv.status_code, expected_status)
if rv.status_code != expected_status:
print msg
self.assertEqual(rv.status_code, expected_status, msg)
return test
def __new__(cls, name, bases, attrs):
with app.test_request_context() as ctx:
specs = attrs['spec_func']()
for test_spec in specs:
url, open_kwargs = test_spec.get_client_args()
expected_status = getattr(test_spec, attrs['result_attr'])
test = SpecTestBuilder._test_generator(url, expected_status,
open_kwargs,
attrs['auth_username'])
test_name_url = url.replace('/', '_').replace('-', '_')
test_name = 'test_%s_%s' % (open_kwargs['method'].lower(),
test_name_url)
attrs[test_name] = test
return type(name, bases, attrs)
class TestAnonymousAccess(ApiTestCase):
def __runspec(self, client, spec):
for url, (expected_status, open_kwargs) in spec.items():
rv = client.open(url, **open_kwargs)
msg = '%s %s: %s expected: %s' % (open_kwargs['method'], url,
rv.status_code, expected_status)
self.assertEqual(rv.status_code, expected_status, msg)
__metaclass__ = SpecTestBuilder
spec_func = build_specs
result_attr = 'anon_code'
auth_username = None
def test_anonymous_public_access(self):
with app.test_request_context() as ctx:
spec = build_anon_spec()
with app.test_client() as c:
self.__runspec(c, spec)
class TestNoAccess(ApiTestCase):
__metaclass__ = SpecTestBuilder
spec_func = build_specs
result_attr = 'no_access_code'
auth_username = NO_ACCESS_USER
def test_authenticated_but_not_authorized(self):
with app.test_request_context() as ctx:
spec = build_no_access_spec()
with app.test_client() as c:
with c.session_transaction() as sess:
sess['user_id'] = NO_ACCESS_USER
class TestReadAccess(ApiTestCase):
__metaclass__ = SpecTestBuilder
spec_func = build_specs
result_attr = 'read_code'
auth_username = READ_ACCESS_USER
self.__runspec(c, spec)
class TestAdminAccess(ApiTestCase):
__metaclass__ = SpecTestBuilder
spec_func = build_specs
result_attr = 'admin_code'
auth_username = ADMIN_ACCESS_USER
if __name__ == '__main__':
unittest.main()
unittest.main()

37
test/teststorage.py Normal file
View file

@ -0,0 +1,37 @@
from uuid import uuid4
from storage.basestorage import Storage
class FakeStorage(Storage):
def _init_path(self, path=None, create=False):
return path
def get_content(self, path):
raise IOError('Fake files are fake!')
def put_content(self, path, content):
return path
def stream_read(self, path):
yield ''
def stream_write(self, path, fp):
pass
def remove(self, path):
pass
def exists(self, path):
return True
class FakeUserfiles(object):
def prepare_for_drop(self, mime_type):
return ('http://fake/url', uuid4())
def store_file(self, flask_file):
raise NotImplementedError()
def get_file_url(self, file_id, expires_in=300):
return ('http://fake/url')

View file

@ -13,7 +13,6 @@ from base64 import b64encode
from requests.exceptions import ConnectionError
from data.queue import dockerfile_build_queue
from data.userfiles import UserRequestFiles
from data import model
from data.database import db as db_connection
from app import app
@ -151,9 +150,7 @@ def babysit_builder(request):
ssh_client.exec_command(remove_auth_cmd)
# Prepare the signed resource url the build node can fetch the job from
user_files = UserRequestFiles(app.config['AWS_ACCESS_KEY'],
app.config['AWS_SECRET_KEY'],
app.config['REGISTRY_S3_BUCKET'])
user_files = app.config['USERFILES']
resource_url = user_files.get_file_url(repository_build.resource_key)
# Start the build server