Introducing Pillar Framework
Refactor of pillar-server and pillar-web into a single python package. This simplifies the overall architecture of pillar applications. Special thanks @sybren and @venomgfx
This commit is contained in:
@@ -1,315 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import json
|
||||
import copy
|
||||
import sys
|
||||
import logging
|
||||
import datetime
|
||||
import os
|
||||
import base64
|
||||
|
||||
try:
|
||||
from urllib.parse import urlencode
|
||||
except ImportError:
|
||||
from urllib import urlencode
|
||||
|
||||
from bson import ObjectId, tz_util
|
||||
|
||||
# Override Eve settings before importing eve.tests.
|
||||
import common_test_settings
|
||||
|
||||
common_test_settings.override_eve()
|
||||
|
||||
from eve.tests import TestMinimal
|
||||
import pymongo.collection
|
||||
from flask.testing import FlaskClient
|
||||
import responses
|
||||
|
||||
from common_test_data import EXAMPLE_PROJECT, EXAMPLE_FILE
|
||||
|
||||
# from six:
|
||||
PY3 = sys.version_info[0] == 3
|
||||
if PY3:
|
||||
string_type = str
|
||||
text_type = str
|
||||
else:
|
||||
string_type = basestring
|
||||
text_type = unicode
|
||||
|
||||
MY_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
TEST_EMAIL_USER = 'koro'
|
||||
TEST_EMAIL_ADDRESS = '%s@testing.blender.org' % TEST_EMAIL_USER
|
||||
TEST_FULL_NAME = u'врач Сергей'
|
||||
TEST_SUBCLIENT_TOKEN = 'my-subclient-token-for-pillar'
|
||||
BLENDER_ID_TEST_USERID = 1896
|
||||
BLENDER_ID_USER_RESPONSE = {'status': 'success',
|
||||
'user': {'email': TEST_EMAIL_ADDRESS,
|
||||
'full_name': TEST_FULL_NAME,
|
||||
'id': BLENDER_ID_TEST_USERID},
|
||||
'token_expires': 'Mon, 1 Jan 2018 01:02:03 GMT'}
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format='%(asctime)-15s %(levelname)8s %(name)s %(message)s')
|
||||
|
||||
|
||||
class AbstractPillarTest(TestMinimal):
|
||||
def setUp(self, **kwargs):
|
||||
eve_settings_file = os.path.join(MY_PATH, 'common_test_settings.py')
|
||||
pillar_config_file = os.path.join(MY_PATH, 'config_testing.py')
|
||||
kwargs['settings_file'] = eve_settings_file
|
||||
os.environ['EVE_SETTINGS'] = eve_settings_file
|
||||
os.environ['PILLAR_CONFIG'] = pillar_config_file
|
||||
super(AbstractPillarTest, self).setUp(**kwargs)
|
||||
|
||||
from application import app
|
||||
|
||||
logging.getLogger('').setLevel(logging.DEBUG)
|
||||
logging.getLogger('application').setLevel(logging.DEBUG)
|
||||
logging.getLogger('werkzeug').setLevel(logging.DEBUG)
|
||||
logging.getLogger('eve').setLevel(logging.DEBUG)
|
||||
|
||||
from eve.utils import config
|
||||
config.DEBUG = True
|
||||
|
||||
self.app = app
|
||||
self.client = app.test_client()
|
||||
assert isinstance(self.client, FlaskClient)
|
||||
|
||||
def tearDown(self):
|
||||
super(AbstractPillarTest, self).tearDown()
|
||||
|
||||
# Not only delete self.app (like the superclass does),
|
||||
# but also un-import the application.
|
||||
del sys.modules['application']
|
||||
remove = [modname for modname in sys.modules
|
||||
if modname.startswith('application.')]
|
||||
for modname in remove:
|
||||
del sys.modules[modname]
|
||||
|
||||
def ensure_file_exists(self, file_overrides=None):
|
||||
self.ensure_project_exists()
|
||||
with self.app.test_request_context():
|
||||
files_collection = self.app.data.driver.db['files']
|
||||
assert isinstance(files_collection, pymongo.collection.Collection)
|
||||
|
||||
file = copy.deepcopy(EXAMPLE_FILE)
|
||||
if file_overrides is not None:
|
||||
file.update(file_overrides)
|
||||
if '_id' in file and file['_id'] is None:
|
||||
del file['_id']
|
||||
|
||||
result = files_collection.insert_one(file)
|
||||
file_id = result.inserted_id
|
||||
|
||||
# Re-fetch from the database, so that we're sure we return the same as is stored.
|
||||
# This is necessary as datetimes are rounded by MongoDB.
|
||||
from_db = files_collection.find_one(file_id)
|
||||
return file_id, from_db
|
||||
|
||||
def ensure_project_exists(self, project_overrides=None):
|
||||
with self.app.test_request_context():
|
||||
projects_collection = self.app.data.driver.db['projects']
|
||||
assert isinstance(projects_collection, pymongo.collection.Collection)
|
||||
|
||||
project = copy.deepcopy(EXAMPLE_PROJECT)
|
||||
if project_overrides is not None:
|
||||
project.update(project_overrides)
|
||||
|
||||
found = projects_collection.find_one(project['_id'])
|
||||
if found is None:
|
||||
result = projects_collection.insert_one(project)
|
||||
return result.inserted_id, project
|
||||
|
||||
return found['_id'], found
|
||||
|
||||
def create_user(self, user_id='cafef00dc379cf10c4aaceaf', roles=('subscriber',),
|
||||
groups=None):
|
||||
from application.utils.authentication import make_unique_username
|
||||
|
||||
with self.app.test_request_context():
|
||||
users = self.app.data.driver.db['users']
|
||||
assert isinstance(users, pymongo.collection.Collection)
|
||||
|
||||
result = users.insert_one({
|
||||
'_id': ObjectId(user_id),
|
||||
'_updated': datetime.datetime(2016, 4, 15, 13, 15, 11, tzinfo=tz_util.utc),
|
||||
'_created': datetime.datetime(2016, 4, 15, 13, 15, 11, tzinfo=tz_util.utc),
|
||||
'username': make_unique_username('tester'),
|
||||
'groups': groups or [],
|
||||
'roles': list(roles),
|
||||
'settings': {'email_communications': 1},
|
||||
'auth': [{'token': '',
|
||||
'user_id': unicode(BLENDER_ID_TEST_USERID),
|
||||
'provider': 'blender-id'}],
|
||||
'full_name': u'คนรักของผัดไทย',
|
||||
'email': TEST_EMAIL_ADDRESS
|
||||
})
|
||||
|
||||
return result.inserted_id
|
||||
|
||||
def create_valid_auth_token(self, user_id, token='token'):
|
||||
now = datetime.datetime.now(tz_util.utc)
|
||||
future = now + datetime.timedelta(days=1)
|
||||
|
||||
with self.app.test_request_context():
|
||||
from application.utils import authentication as auth
|
||||
|
||||
token_data = auth.store_token(user_id, token, future, None)
|
||||
|
||||
return token_data
|
||||
|
||||
def badger(self, user_email, roles, action, srv_token=None):
|
||||
"""Creates a service account, and uses it to grant or revoke a role to the user.
|
||||
|
||||
To skip creation of the service account, pass a srv_token.
|
||||
|
||||
:returns: the authentication token of the created service account.
|
||||
:rtype: str
|
||||
"""
|
||||
|
||||
if isinstance(roles, str):
|
||||
roles = {roles}
|
||||
|
||||
# Create a service account if needed.
|
||||
if srv_token is None:
|
||||
from application.modules.service import create_service_account
|
||||
with self.app.test_request_context():
|
||||
_, srv_token_doc = create_service_account('service@example.com',
|
||||
{'badger'},
|
||||
{'badger': list(roles)})
|
||||
srv_token = srv_token_doc['token']
|
||||
|
||||
for role in roles:
|
||||
resp = self.client.post('/service/badger',
|
||||
headers={'Authorization': self.make_header(srv_token),
|
||||
'Content-Type': 'application/json'},
|
||||
data=json.dumps({'action': action,
|
||||
'role': role,
|
||||
'user_email': user_email}))
|
||||
self.assertEqual(204, resp.status_code, resp.data)
|
||||
|
||||
return srv_token
|
||||
|
||||
def mock_blenderid_validate_unhappy(self):
|
||||
"""Sets up Responses to mock unhappy validation flow."""
|
||||
|
||||
responses.add(responses.POST,
|
||||
'%s/u/validate_token' % self.app.config['BLENDER_ID_ENDPOINT'],
|
||||
json={'status': 'fail'},
|
||||
status=403)
|
||||
|
||||
def mock_blenderid_validate_happy(self):
|
||||
"""Sets up Responses to mock happy validation flow."""
|
||||
|
||||
responses.add(responses.POST,
|
||||
'%s/u/validate_token' % self.app.config['BLENDER_ID_ENDPOINT'],
|
||||
json=BLENDER_ID_USER_RESPONSE,
|
||||
status=200)
|
||||
|
||||
def make_header(self, username, subclient_id=''):
|
||||
"""Returns a Basic HTTP Authentication header value."""
|
||||
|
||||
return 'basic ' + base64.b64encode('%s:%s' % (username, subclient_id))
|
||||
|
||||
def create_standard_groups(self, additional_groups=()):
|
||||
"""Creates standard admin/demo/subscriber groups, plus any additional.
|
||||
|
||||
:returns: mapping from group name to group ID
|
||||
"""
|
||||
from application.modules import service
|
||||
|
||||
with self.app.test_request_context():
|
||||
group_ids = {}
|
||||
groups_coll = self.app.data.driver.db['groups']
|
||||
|
||||
for group_name in ['admin', 'demo', 'subscriber'] + list(additional_groups):
|
||||
result = groups_coll.insert_one({'name': group_name})
|
||||
group_ids[group_name] = result.inserted_id
|
||||
|
||||
service.fetch_role_to_group_id_map()
|
||||
|
||||
return group_ids
|
||||
|
||||
@staticmethod
|
||||
def join_url_params(params):
|
||||
"""Constructs a query string from a dictionary and appends it to a url.
|
||||
|
||||
Usage::
|
||||
|
||||
>>> AbstractPillarTest.join_url_params("pillar:5000/shots",
|
||||
{"page-id": 2, "NodeType": "Shot Group"})
|
||||
'pillar:5000/shots?page-id=2&NodeType=Shot+Group'
|
||||
"""
|
||||
|
||||
if params is None:
|
||||
return None
|
||||
|
||||
if not isinstance(params, dict):
|
||||
return params
|
||||
|
||||
def convert_to_string(param):
|
||||
if isinstance(param, dict):
|
||||
return json.dumps(param, sort_keys=True)
|
||||
if isinstance(param, text_type):
|
||||
return param.encode('utf-8')
|
||||
return param
|
||||
|
||||
# Pass as (key, value) pairs, so that the sorted order is maintained.
|
||||
jsonified_params = [
|
||||
(key, convert_to_string(params[key]))
|
||||
for key in sorted(params.keys())]
|
||||
return urlencode(jsonified_params)
|
||||
|
||||
def client_request(self, method, path, qs=None, expected_status=200, auth_token=None, json=None,
|
||||
data=None, headers=None, files=None, content_type=None):
|
||||
"""Performs a HTTP request to the server."""
|
||||
|
||||
from application.utils import dumps
|
||||
import json as mod_json
|
||||
|
||||
headers = headers or {}
|
||||
if auth_token is not None:
|
||||
headers['Authorization'] = self.make_header(auth_token)
|
||||
|
||||
if json is not None:
|
||||
data = dumps(json)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
if files:
|
||||
data = data or {}
|
||||
content_type = 'multipart/form-data'
|
||||
data.update(files)
|
||||
|
||||
resp = self.client.open(path=path, method=method, data=data, headers=headers,
|
||||
content_type=content_type,
|
||||
query_string=self.join_url_params(qs))
|
||||
self.assertEqual(expected_status, resp.status_code,
|
||||
'Expected status %i but got %i. Response: %s' % (
|
||||
expected_status, resp.status_code, resp.data
|
||||
))
|
||||
|
||||
def json():
|
||||
if resp.mimetype != 'application/json':
|
||||
raise TypeError('Unable to load JSON from mimetype %r' % resp.mimetype)
|
||||
return mod_json.loads(resp.data)
|
||||
|
||||
resp.json = json
|
||||
|
||||
return resp
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
return self.client_request('GET', *args, **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
return self.client_request('POST', *args, **kwargs)
|
||||
|
||||
def put(self, *args, **kwargs):
|
||||
return self.client_request('PUT', *args, **kwargs)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
return self.client_request('DELETE', *args, **kwargs)
|
||||
|
||||
def patch(self, *args, **kwargs):
|
||||
return self.client_request('PATCH', *args, **kwargs)
|
@@ -1,264 +0,0 @@
|
||||
import datetime
|
||||
|
||||
from bson import tz_util, ObjectId
|
||||
|
||||
EXAMPLE_ADMIN_GROUP_ID = ObjectId('5596e975ea893b269af85c0e')
|
||||
|
||||
EXAMPLE_PROJECT_ID = ObjectId('5672beecc0261b2005ed1a33')
|
||||
|
||||
EXAMPLE_FILE = {u'_id': ObjectId('5672e2c1c379cf0007b31995'),
|
||||
u'_updated': datetime.datetime(2016, 3, 25, 10, 28, 24, tzinfo=tz_util.utc),
|
||||
u'height': 2048,
|
||||
u'name': 'c2a5c897769ce1ef0eb10f8fa1c472bcb8e2d5a4.png', u'format': 'png',
|
||||
u'variations': [
|
||||
{u'format': 'jpg', u'height': 160, u'width': 160, u'length': 8558,
|
||||
u'link': 'http://localhost:8002/file-variant-h', u'content_type': 'image/jpeg',
|
||||
u'md5': '--', u'file_path': 'c2a5c897769ce1ef0eb10f8fa1c472bcb8e2d5a4-b.jpg',
|
||||
u'size': 'b'},
|
||||
{u'format': 'jpg', u'height': 2048, u'width': 2048, u'length': 819569,
|
||||
u'link': 'http://localhost:8002/file-variant-h', u'content_type': 'image/jpeg',
|
||||
u'md5': '--', u'file_path': 'c2a5c897769ce1ef0eb10f8fa1c472bcb8e2d5a4-h.jpg',
|
||||
u'size': 'h'},
|
||||
{u'format': 'jpg', u'height': 64, u'width': 64, u'length': 8195,
|
||||
u'link': 'http://localhost:8002/file-variant-t', u'content_type': 'image/jpeg',
|
||||
u'md5': '--', u'file_path': 'c2a5c897769ce1ef0eb10f8fa1c472bcb8e2d5a4-t.jpg',
|
||||
u'size': 't'},
|
||||
],
|
||||
u'filename': 'brick_dutch_soft_bump.png',
|
||||
u'project': EXAMPLE_PROJECT_ID,
|
||||
u'width': 2048, u'length': 6227670,
|
||||
u'user': ObjectId('56264fc4fa3a250344bd10c5'),
|
||||
u'content_type': 'image/png',
|
||||
u'_etag': '044ce3aede2e123e261c0d8bd77212f264d4f7b0',
|
||||
u'_created': datetime.datetime(2015, 12, 17, 16, 28, 49, tzinfo=tz_util.utc),
|
||||
u'md5': '',
|
||||
u'file_path': 'c2a5c897769ce1ef0eb10f8fa1c472bcb8e2d5a4.png',
|
||||
u'backend': 'pillar',
|
||||
u'link': 'http://localhost:8002/file',
|
||||
u'link_expires': datetime.datetime(2016, 3, 22, 9, 28, 22, tzinfo=tz_util.utc)}
|
||||
|
||||
EXAMPLE_PROJECT = {
|
||||
u'_created': datetime.datetime(2015, 12, 17, 13, 22, 56, tzinfo=tz_util.utc),
|
||||
u'_etag': u'cc4643e98d3606f87bbfaaa200bfbae941b642f3',
|
||||
u'_id': EXAMPLE_PROJECT_ID,
|
||||
u'_updated': datetime.datetime(2016, 1, 7, 18, 59, 4, tzinfo=tz_util.utc),
|
||||
u'category': u'assets',
|
||||
u'description': u'Welcome to this curated collection of Blender Institute textures and image resources. This collection is an on-going project, as with each project we create a number of textures based on our own resources (photographs, scans, etc.) or made completely from scratch. At the moment you can find all the textures from the past Open Projects that were deemed re-usable. \r\n\r\nPeople who have contributed to these textures:\r\n\r\nAndrea Weikert, Andy Goralczyk, Basse Salmela, Ben Dansie, Campbell Barton, Enrico Valenza, Ian Hubert, Kjartan Tysdal, Manu J\xe4rvinen, Massimiliana Pulieso, Matt Ebb, Pablo Vazquez, Rob Tuytel, Roland Hess, Sarah Feldlaufer, S\xf6nke M\xe4ter',
|
||||
u'is_private': False,
|
||||
u'name': u'Textures',
|
||||
u'node_types': [{u'description': u'Group for texture node type',
|
||||
u'dyn_schema': {u'order': {u'type': u'integer'},
|
||||
u'status': {u'allowed': [u'published', u'pending'],
|
||||
u'type': u'string'},
|
||||
u'url': {u'type': u'string'}},
|
||||
u'form_schema': {u'order': {}, u'status': {}, u'url': {}},
|
||||
u'name': u'group_texture',
|
||||
u'parent': [u'group_texture', u'project'],
|
||||
u'permissions': {}},
|
||||
{u'description': u'Generic group node type edited',
|
||||
u'dyn_schema': {u'notes': {u'maxlength': 256, u'type': u'string'},
|
||||
u'order': {u'type': u'integer'},
|
||||
u'status': {u'allowed': [u'published', u'pending'],
|
||||
u'type': u'string'},
|
||||
u'url': {u'type': u'string'}},
|
||||
u'form_schema': {u'notes': {}, u'order': {}, u'status': {}, u'url': {}},
|
||||
u'name': u'group',
|
||||
u'parent': [u'group', u'project'],
|
||||
u'permissions': {}},
|
||||
{u'description': u'Basic Asset Type',
|
||||
u'dyn_schema': {
|
||||
u'attachments': {u'schema': {u'schema': {u'field': {u'type': u'string'},
|
||||
u'files': {u'schema': {
|
||||
u'schema': {u'file': {
|
||||
u'data_relation': {
|
||||
u'embeddable': True,
|
||||
u'field': u'_id',
|
||||
u'resource': u'files'},
|
||||
u'type': u'objectid'},
|
||||
u'size': {
|
||||
u'type': u'string'},
|
||||
u'slug': {
|
||||
u'minlength': 1,
|
||||
u'type': u'string'}},
|
||||
u'type': u'dict'},
|
||||
u'type': u'list'}},
|
||||
u'type': u'dict'},
|
||||
u'type': u'list'},
|
||||
u'categories': {u'type': u'string'},
|
||||
u'content_type': {u'type': u'string'},
|
||||
u'file': {u'data_relation': {u'embeddable': True,
|
||||
u'field': u'_id',
|
||||
u'resource': u'files'},
|
||||
u'type': u'objectid'},
|
||||
u'order': {u'type': u'integer'},
|
||||
u'status': {u'allowed': [u'published',
|
||||
u'pending',
|
||||
u'processing'],
|
||||
u'type': u'string'},
|
||||
u'tags': {u'schema': {u'type': u'string'}, u'type': u'list'}},
|
||||
u'form_schema': {u'attachments': {u'visible': False},
|
||||
u'categories': {},
|
||||
u'content_type': {u'visible': False},
|
||||
u'file': {u'visible': False},
|
||||
u'order': {},
|
||||
u'status': {},
|
||||
u'tags': {}},
|
||||
u'name': u'asset',
|
||||
u'parent': [u'group'],
|
||||
u'permissions': {}},
|
||||
{u'description': u'Entrypoint to a remote or local storage solution',
|
||||
u'dyn_schema': {u'backend': {u'type': u'string'},
|
||||
u'subdir': {u'type': u'string'}},
|
||||
u'form_schema': {u'backend': {}, u'subdir': {}},
|
||||
u'name': u'storage',
|
||||
u'parent': [u'group', u'project'],
|
||||
u'permissions': {u'groups': [{u'group': EXAMPLE_ADMIN_GROUP_ID,
|
||||
u'methods': [u'GET', u'PUT', u'POST']},
|
||||
{u'group': ObjectId('5596e975ea893b269af85c0f'),
|
||||
u'methods': [u'GET']},
|
||||
{u'group': ObjectId('564733b56dcaf85da2faee8a'),
|
||||
u'methods': [u'GET']}],
|
||||
u'users': [],
|
||||
u'world': []}},
|
||||
{u'description': u'Comments for asset nodes, pages, etc.',
|
||||
u'dyn_schema': {u'confidence': {u'type': u'float'},
|
||||
u'content': {u'minlength': 5, u'type': u'string'},
|
||||
u'is_reply': {u'type': u'boolean'},
|
||||
u'rating_negative': {u'type': u'integer'},
|
||||
u'rating_positive': {u'type': u'integer'},
|
||||
u'ratings': {u'schema': {
|
||||
u'schema': {u'is_positive': {u'type': u'boolean'},
|
||||
u'user': {u'type': u'objectid'},
|
||||
u'weight': {u'type': u'integer'}},
|
||||
u'type': u'dict'},
|
||||
u'type': u'list'},
|
||||
u'status': {u'allowed': [u'published', u'flagged', u'edited'],
|
||||
u'type': u'string'}},
|
||||
u'form_schema': {u'confidence': {},
|
||||
u'content': {},
|
||||
u'is_reply': {},
|
||||
u'rating_negative': {},
|
||||
u'rating_positive': {},
|
||||
u'ratings': {},
|
||||
u'status': {}},
|
||||
u'name': u'comment',
|
||||
u'parent': [u'asset', u'comment'],
|
||||
u'permissions': {}},
|
||||
{u'description': u'Container for node_type post.',
|
||||
u'dyn_schema': {u'categories': {u'schema': {u'type': u'string'},
|
||||
u'type': u'list'},
|
||||
u'template': {u'type': u'string'}},
|
||||
u'form_schema': {u'categories': {}, u'template': {}},
|
||||
u'name': u'blog',
|
||||
u'parent': [u'project'],
|
||||
u'permissions': {}},
|
||||
{u'description': u'A blog post, for any project',
|
||||
u'dyn_schema': {
|
||||
u'attachments': {u'schema': {u'schema': {u'field': {u'type': u'string'},
|
||||
u'files': {u'schema': {
|
||||
u'schema': {u'file': {
|
||||
u'data_relation': {
|
||||
u'embeddable': True,
|
||||
u'field': u'_id',
|
||||
u'resource': u'files'},
|
||||
u'type': u'objectid'},
|
||||
u'size': {
|
||||
u'type': u'string'},
|
||||
u'slug': {
|
||||
u'minlength': 1,
|
||||
u'type': u'string'}},
|
||||
u'type': u'dict'},
|
||||
u'type': u'list'}},
|
||||
u'type': u'dict'},
|
||||
u'type': u'list'},
|
||||
u'category': {u'type': u'string'},
|
||||
u'content': {u'maxlength': 90000,
|
||||
u'minlength': 5,
|
||||
u'required': True,
|
||||
u'type': u'string'},
|
||||
u'status': {u'allowed': [u'published', u'pending'],
|
||||
u'default': u'pending',
|
||||
u'type': u'string'},
|
||||
u'url': {u'type': u'string'}},
|
||||
u'form_schema': {u'attachments': {u'visible': False},
|
||||
u'category': {},
|
||||
u'content': {},
|
||||
u'status': {},
|
||||
u'url': {}},
|
||||
u'name': u'post',
|
||||
u'parent': [u'blog'],
|
||||
u'permissions': {}},
|
||||
{u'description': u'Image Texture',
|
||||
u'dyn_schema': {u'aspect_ratio': {u'type': u'float'},
|
||||
u'categories': {u'type': u'string'},
|
||||
u'files': {u'schema': {u'schema': {
|
||||
u'file': {u'data_relation': {u'embeddable': True,
|
||||
u'field': u'_id',
|
||||
u'resource': u'files'},
|
||||
u'type': u'objectid'},
|
||||
u'is_tileable': {u'type': u'boolean'},
|
||||
u'map_type': {u'allowed': [u'color',
|
||||
u'specular',
|
||||
u'bump',
|
||||
u'normal',
|
||||
u'translucency',
|
||||
u'emission',
|
||||
u'alpha'],
|
||||
u'type': u'string'}},
|
||||
u'type': u'dict'},
|
||||
u'type': u'list'},
|
||||
u'is_landscape': {u'type': u'boolean'},
|
||||
u'is_tileable': {u'type': u'boolean'},
|
||||
u'order': {u'type': u'integer'},
|
||||
u'resolution': {u'type': u'string'},
|
||||
u'status': {u'allowed': [u'published',
|
||||
u'pending',
|
||||
u'processing'],
|
||||
u'type': u'string'},
|
||||
u'tags': {u'schema': {u'type': u'string'}, u'type': u'list'}},
|
||||
u'form_schema': {u'aspect_ratio': {},
|
||||
u'categories': {},
|
||||
u'content_type': {u'visible': False},
|
||||
u'files': {u'visible': False},
|
||||
u'is_landscape': {},
|
||||
u'is_tileable': {},
|
||||
u'order': {},
|
||||
u'resolution': {},
|
||||
u'status': {},
|
||||
u'tags': {}},
|
||||
u'name': u'texture',
|
||||
u'parent': [u'group'],
|
||||
u'permissions': {}}],
|
||||
u'nodes_blog': [],
|
||||
u'nodes_featured': [],
|
||||
u'nodes_latest': [],
|
||||
u'organization': ObjectId('55a99fb43004867fb9934f01'),
|
||||
u'owners': {u'groups': [], u'users': []},
|
||||
u'permissions': {u'groups': [{u'group': EXAMPLE_ADMIN_GROUP_ID,
|
||||
u'methods': [u'GET', u'POST', u'PUT', u'DELETE']}],
|
||||
u'users': [],
|
||||
u'world': [u'GET']},
|
||||
u'picture_header': ObjectId('5673f260c379cf0007b31bc4'),
|
||||
u'picture_square': ObjectId('5673f256c379cf0007b31bc3'),
|
||||
u'status': u'published',
|
||||
u'summary': u'Texture collection from all Blender Institute open projects.',
|
||||
u'url': u'textures',
|
||||
u'user': ObjectId('552b066b41acdf5dec4436f2')}
|
||||
|
||||
EXAMPLE_NODE = {
|
||||
u'_id': ObjectId('572761099837730efe8e120d'),
|
||||
u'picture': ObjectId('572761f39837730efe8e1210'),
|
||||
u'description': u'',
|
||||
u'node_type': u'asset',
|
||||
u'user': ObjectId('57164ca1983773118cbaf779'),
|
||||
u'properties': {
|
||||
u'status': u'published',
|
||||
u'content_type': u'image',
|
||||
u'file': ObjectId('572761129837730efe8e120e')
|
||||
},
|
||||
u'_updated': datetime.datetime(2016, 5, 2, 14, 19, 58, 0, tzinfo=tz_util.utc),
|
||||
u'name': u'Image test',
|
||||
u'project': EXAMPLE_PROJECT_ID,
|
||||
u'_created': datetime.datetime(2016, 5, 2, 14, 19, 37, 0, tzinfo=tz_util.utc),
|
||||
u'_etag': u'6b8589b42c880e3626f43f3e82a5c5b946742687'
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
from settings import *
|
||||
|
||||
from eve.tests.test_settings import MONGO_DBNAME
|
||||
|
||||
|
||||
def override_eve():
|
||||
from eve.tests import test_settings
|
||||
from eve import tests
|
||||
|
||||
test_settings.MONGO_HOST = MONGO_HOST
|
||||
test_settings.MONGO_PORT = MONGO_PORT
|
||||
tests.MONGO_HOST = MONGO_HOST
|
||||
tests.MONGO_PORT = MONGO_PORT
|
@@ -1,11 +0,0 @@
|
||||
"""Flask configuration file for unit testing."""
|
||||
|
||||
BLENDER_ID_ENDPOINT = 'http://127.0.0.1:8001' # nonexistant server, no trailing slash!
|
||||
|
||||
DEBUG = False
|
||||
TESTING = True
|
||||
|
||||
CDN_STORAGE_USER = 'u41508580125621'
|
||||
|
||||
FILESIZE_LIMIT_BYTES_NONSUBS = 20 * 2 ** 10
|
||||
ROLES_FOR_UNLIMITED_UPLOADS = {u'subscriber', u'demo', u'admin'}
|
@@ -2,16 +2,15 @@
|
||||
|
||||
import copy
|
||||
import datetime
|
||||
import responses
|
||||
import json
|
||||
|
||||
import pillar.tests.common_test_data as ctd
|
||||
import responses
|
||||
from bson import tz_util, ObjectId
|
||||
from pillar.tests import AbstractPillarTest, TEST_EMAIL_USER, TEST_EMAIL_ADDRESS
|
||||
from pillar.tests.common_test_data import EXAMPLE_NODE
|
||||
from werkzeug.exceptions import Forbidden
|
||||
|
||||
from common_test_class import AbstractPillarTest, TEST_EMAIL_USER, TEST_EMAIL_ADDRESS
|
||||
from common_test_data import EXAMPLE_NODE
|
||||
import common_test_data as ctd
|
||||
|
||||
PUBLIC_USER_FIELDS = {'full_name', 'email'}
|
||||
|
||||
# Use the example project with some additional permissions for these tests.
|
||||
@@ -32,7 +31,7 @@ _asset_nt['permissions']['groups'] = [
|
||||
|
||||
class AuthenticationTests(AbstractPillarTest):
|
||||
def test_make_unique_username(self):
|
||||
from application.utils import authentication as auth
|
||||
from pillar.api.utils import authentication as auth
|
||||
|
||||
with self.app.test_request_context():
|
||||
# This user shouldn't exist yet.
|
||||
@@ -44,7 +43,7 @@ class AuthenticationTests(AbstractPillarTest):
|
||||
|
||||
@responses.activate
|
||||
def test_validate_token__not_logged_in(self):
|
||||
from application.utils import authentication as auth
|
||||
from pillar.api.utils import authentication as auth
|
||||
|
||||
with self.app.test_request_context():
|
||||
self.assertFalse(auth.validate_token())
|
||||
@@ -53,7 +52,7 @@ class AuthenticationTests(AbstractPillarTest):
|
||||
def test_validate_token__unknown_token(self):
|
||||
"""Test validating of invalid token, unknown both to us and Blender ID."""
|
||||
|
||||
from application.utils import authentication as auth
|
||||
from pillar.api.utils import authentication as auth
|
||||
|
||||
self.mock_blenderid_validate_unhappy()
|
||||
with self.app.test_request_context(
|
||||
@@ -64,7 +63,7 @@ class AuthenticationTests(AbstractPillarTest):
|
||||
def test_validate_token__unknown_but_valid_token(self):
|
||||
"""Test validating of valid token, unknown to us but known to Blender ID."""
|
||||
|
||||
from application.utils import authentication as auth
|
||||
from pillar.api.utils import authentication as auth
|
||||
|
||||
self.mock_blenderid_validate_happy()
|
||||
with self.app.test_request_context(
|
||||
@@ -75,7 +74,7 @@ class AuthenticationTests(AbstractPillarTest):
|
||||
def test_find_token(self):
|
||||
"""Test finding of various tokens."""
|
||||
|
||||
from application.utils import authentication as auth
|
||||
from pillar.api.utils import authentication as auth
|
||||
|
||||
user_id = self.create_user()
|
||||
|
||||
@@ -123,8 +122,8 @@ class AuthenticationTests(AbstractPillarTest):
|
||||
def test_save_own_user(self):
|
||||
"""Tests that a user can't change their own fields."""
|
||||
|
||||
from application.utils import authentication as auth
|
||||
from application.utils import PillarJSONEncoder, remove_private_keys
|
||||
from pillar.api.utils import authentication as auth
|
||||
from pillar.api.utils import PillarJSONEncoder, remove_private_keys
|
||||
|
||||
user_id = self.create_user(roles=[u'subscriber'])
|
||||
|
||||
@@ -145,25 +144,25 @@ class AuthenticationTests(AbstractPillarTest):
|
||||
updated_fields['roles'] = ['admin', 'subscriber', 'demo'] # Try to elevate our roles.
|
||||
|
||||
# POSTing updated info to a specific user URL is not allowed by Eve.
|
||||
resp = self.client.post('/users/%s' % user_id,
|
||||
resp = self.client.post('/api/users/%s' % user_id,
|
||||
data=json.dumps(updated_fields, cls=PillarJSONEncoder),
|
||||
headers={'Authorization': self.make_header('nonexpired-main'),
|
||||
'Content-Type': 'application/json'})
|
||||
self.assertEqual(405, resp.status_code)
|
||||
|
||||
# PUT and PATCH should not be allowed.
|
||||
resp = self.client.put('/users/%s' % user_id,
|
||||
resp = self.client.put('/api/users/%s' % user_id,
|
||||
data=json.dumps(updated_fields, cls=PillarJSONEncoder),
|
||||
headers={'Authorization': self.make_header('nonexpired-main'),
|
||||
'Content-Type': 'application/json'})
|
||||
self.assertEqual(403, resp.status_code)
|
||||
|
||||
updated_fields = {'roles': ['admin', 'subscriber', 'demo']}
|
||||
resp = self.client.patch('/users/%s' % user_id,
|
||||
resp = self.client.patch('/api/users/%s' % user_id,
|
||||
data=json.dumps(updated_fields, cls=PillarJSONEncoder),
|
||||
headers={'Authorization': self.make_header('nonexpired-main'),
|
||||
'Content-Type': 'application/json'})
|
||||
self.assertEqual(405, resp.status_code)
|
||||
self.assertEqual(403, resp.status_code)
|
||||
|
||||
# After all of this, the roles should be the same.
|
||||
with self.app.test_request_context(
|
||||
@@ -183,7 +182,7 @@ class AuthenticationTests(AbstractPillarTest):
|
||||
now = datetime.datetime.now(tz_util.utc)
|
||||
|
||||
with self.app.test_request_context():
|
||||
from application.utils import authentication as auth
|
||||
from pillar.api.utils import authentication as auth
|
||||
|
||||
auth.store_token(user_id, 'long-expired',
|
||||
now - datetime.timedelta(days=365), None)
|
||||
@@ -193,7 +192,7 @@ class AuthenticationTests(AbstractPillarTest):
|
||||
now + datetime.timedelta(days=1), None)
|
||||
|
||||
# Validation should clean up old tokens.
|
||||
auth.validate_token()
|
||||
auth.validate_this_token('je', 'moeder')
|
||||
|
||||
token_coll = self.app.data.driver.db['tokens']
|
||||
self.assertEqual({'short-expired', 'not-expired'},
|
||||
@@ -216,12 +215,12 @@ class UserListTests(AbstractPillarTest):
|
||||
|
||||
def test_list_all_users_anonymous(self):
|
||||
# Listing all users should be forbidden
|
||||
resp = self.client.get('/users')
|
||||
resp = self.client.get('/api/users')
|
||||
self.assertEqual(403, resp.status_code)
|
||||
|
||||
def test_list_all_users_subscriber(self):
|
||||
# Regular access should result in only your own info.
|
||||
resp = self.client.get('/users', headers={'Authorization': self.make_header('token')})
|
||||
resp = self.client.get('/api/users', headers={'Authorization': self.make_header('token')})
|
||||
users = json.loads(resp.data)
|
||||
|
||||
self.assertEqual(200, resp.status_code)
|
||||
@@ -233,7 +232,7 @@ class UserListTests(AbstractPillarTest):
|
||||
|
||||
def test_list_all_users_admin(self):
|
||||
# Admin access should result in all users
|
||||
resp = self.client.get('/users', headers={'Authorization': self.make_header('admin-token')})
|
||||
resp = self.client.get('/api/users', headers={'Authorization': self.make_header('admin-token')})
|
||||
users = json.loads(resp.data)
|
||||
|
||||
self.assertEqual(200, resp.status_code)
|
||||
@@ -246,7 +245,7 @@ class UserListTests(AbstractPillarTest):
|
||||
def test_list_all_users_admin_explicit_projection(self):
|
||||
# Admin access should result in all users
|
||||
projection = json.dumps({'auth': 1})
|
||||
resp = self.client.get('/users?projection=%s' % projection,
|
||||
resp = self.client.get('/api/users?projection=%s' % projection,
|
||||
headers={'Authorization': self.make_header('admin-token')})
|
||||
users = json.loads(resp.data)
|
||||
|
||||
@@ -258,10 +257,10 @@ class UserListTests(AbstractPillarTest):
|
||||
self.assertNotIn('auth', user_info)
|
||||
|
||||
def test_user_anonymous(self):
|
||||
from application.utils import remove_private_keys
|
||||
from pillar.api.utils import remove_private_keys
|
||||
|
||||
# Getting a user should be limited to certain fields
|
||||
resp = self.client.get('/users/123456789abc123456789abc')
|
||||
resp = self.client.get('/api/users/123456789abc123456789abc')
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
user_info = json.loads(resp.data)
|
||||
@@ -270,7 +269,7 @@ class UserListTests(AbstractPillarTest):
|
||||
|
||||
def test_own_user_subscriber(self):
|
||||
# Regular access should result in only your own info.
|
||||
resp = self.client.get('/users/123456789abc123456789abc',
|
||||
resp = self.client.get('/api/users/123456789abc123456789abc',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
user_info = json.loads(resp.data)
|
||||
|
||||
@@ -280,7 +279,7 @@ class UserListTests(AbstractPillarTest):
|
||||
def test_own_user_subscriber_explicit_projection(self):
|
||||
# With a custom projection requesting the auth list
|
||||
projection = json.dumps({'auth': 1})
|
||||
resp = self.client.get('/users/%s?projection=%s' % ('123456789abc123456789abc', projection),
|
||||
resp = self.client.get('/api/users/%s?projection=%s' % ('123456789abc123456789abc', projection),
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
user_info = json.loads(resp.data)
|
||||
|
||||
@@ -288,10 +287,10 @@ class UserListTests(AbstractPillarTest):
|
||||
self.assertNotIn('auth', user_info)
|
||||
|
||||
def test_other_user_subscriber(self):
|
||||
from application.utils import remove_private_keys
|
||||
from pillar.api.utils import remove_private_keys
|
||||
|
||||
# Requesting another user should be limited to full name and email.
|
||||
resp = self.client.get('/users/%s' % '223456789abc123456789abc',
|
||||
resp = self.client.get('/api/users/%s' % '223456789abc123456789abc',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
user_info = json.loads(resp.data)
|
||||
|
||||
@@ -302,15 +301,15 @@ class UserListTests(AbstractPillarTest):
|
||||
self.assertEqual(PUBLIC_USER_FIELDS, set(regular_info.keys()))
|
||||
|
||||
def test_put_user(self):
|
||||
from application.utils import remove_private_keys
|
||||
from pillar.api.utils import remove_private_keys
|
||||
|
||||
# PUTting a user should work, and not mess up the auth field.
|
||||
resp = self.client.get('/users/123456789abc123456789abc',
|
||||
resp = self.client.get('/api/users/123456789abc123456789abc',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
user_info = json.loads(resp.data)
|
||||
put_user = remove_private_keys(user_info)
|
||||
|
||||
resp = self.client.put('/users/123456789abc123456789abc',
|
||||
resp = self.client.put('/api/users/123456789abc123456789abc',
|
||||
headers={'Authorization': self.make_header('token'),
|
||||
'Content-Type': 'application/json',
|
||||
'If-Match': user_info['_etag']},
|
||||
@@ -324,15 +323,15 @@ class UserListTests(AbstractPillarTest):
|
||||
self.assertIn('auth', db_user)
|
||||
|
||||
def test_put_other_user(self):
|
||||
from application.utils import remove_private_keys
|
||||
from pillar.api.utils import remove_private_keys
|
||||
|
||||
# PUTting the user as another user should fail.
|
||||
resp = self.client.get('/users/123456789abc123456789abc',
|
||||
resp = self.client.get('/api/users/123456789abc123456789abc',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
user_info = json.loads(resp.data)
|
||||
put_user = remove_private_keys(user_info)
|
||||
|
||||
resp = self.client.put('/users/123456789abc123456789abc',
|
||||
resp = self.client.put('/api/users/123456789abc123456789abc',
|
||||
headers={'Authorization': self.make_header('other-token'),
|
||||
'Content-Type': 'application/json',
|
||||
'If-Match': user_info['_etag']},
|
||||
@@ -340,15 +339,15 @@ class UserListTests(AbstractPillarTest):
|
||||
self.assertEqual(403, resp.status_code, resp.data)
|
||||
|
||||
def test_put_admin(self):
|
||||
from application.utils import remove_private_keys
|
||||
from pillar.api.utils import remove_private_keys
|
||||
|
||||
# PUTting a user should work, and not mess up the auth field.
|
||||
resp = self.client.get('/users/123456789abc123456789abc',
|
||||
resp = self.client.get('/api/users/123456789abc123456789abc',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
user_info = json.loads(resp.data)
|
||||
put_user = remove_private_keys(user_info)
|
||||
|
||||
resp = self.client.put('/users/123456789abc123456789abc',
|
||||
resp = self.client.put('/api/users/123456789abc123456789abc',
|
||||
headers={'Authorization': self.make_header('admin-token'),
|
||||
'Content-Type': 'application/json',
|
||||
'If-Match': user_info['_etag']},
|
||||
@@ -374,13 +373,13 @@ class UserListTests(AbstractPillarTest):
|
||||
'email': TEST_EMAIL_ADDRESS,
|
||||
}
|
||||
|
||||
resp = self.client.post('/users',
|
||||
resp = self.client.post('/api/users',
|
||||
headers={'Authorization': self.make_header('token'),
|
||||
'Content-Type': 'application/json'},
|
||||
data=json.dumps(post_user))
|
||||
self.assertEqual(405, resp.status_code, resp.data)
|
||||
|
||||
resp = self.client.post('/users',
|
||||
resp = self.client.post('/api/users',
|
||||
headers={'Authorization': self.make_header('admin-token'),
|
||||
'Content-Type': 'application/json'},
|
||||
data=json.dumps(post_user))
|
||||
@@ -389,11 +388,11 @@ class UserListTests(AbstractPillarTest):
|
||||
def test_delete(self):
|
||||
"""DELETING a user should fail for subscribers and admins alike."""
|
||||
|
||||
resp = self.client.delete('/users/323456789abc123456789abc',
|
||||
resp = self.client.delete('/api/users/323456789abc123456789abc',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(405, resp.status_code, resp.data)
|
||||
|
||||
resp = self.client.delete('/users/323456789abc123456789abc',
|
||||
resp = self.client.delete('/api/users/323456789abc123456789abc',
|
||||
headers={'Authorization': self.make_header('admin-token')})
|
||||
self.assertEqual(405, resp.status_code, resp.data)
|
||||
|
||||
@@ -402,7 +401,7 @@ class PermissionComputationTest(AbstractPillarTest):
|
||||
maxDiff = None
|
||||
|
||||
def test_merge_permissions(self):
|
||||
from application.utils.authorization import merge_permissions
|
||||
from pillar.api.utils.authorization import merge_permissions
|
||||
|
||||
with self.app.test_request_context():
|
||||
self.assertEqual({}, merge_permissions())
|
||||
@@ -453,11 +452,11 @@ class PermissionComputationTest(AbstractPillarTest):
|
||||
def sort(self, permissions):
|
||||
"""Returns a sorted copy of the permissions."""
|
||||
|
||||
from application.utils.authorization import merge_permissions
|
||||
from pillar.api.utils.authorization import merge_permissions
|
||||
return merge_permissions(permissions, {})
|
||||
|
||||
def test_effective_permissions(self):
|
||||
from application.utils.authorization import compute_aggr_permissions
|
||||
from pillar.api.utils.authorization import compute_aggr_permissions
|
||||
|
||||
with self.app.test_request_context():
|
||||
# Test project permissions.
|
||||
@@ -518,7 +517,7 @@ class PermissionComputationTest(AbstractPillarTest):
|
||||
class RequireRolesTest(AbstractPillarTest):
|
||||
def test_no_roles_required(self):
|
||||
from flask import g
|
||||
from application.utils.authorization import require_login
|
||||
from pillar.api.utils.authorization import require_login
|
||||
|
||||
called = [False]
|
||||
|
||||
@@ -535,7 +534,7 @@ class RequireRolesTest(AbstractPillarTest):
|
||||
|
||||
def test_some_roles_required(self):
|
||||
from flask import g
|
||||
from application.utils.authorization import require_login
|
||||
from pillar.api.utils.authorization import require_login
|
||||
|
||||
called = [False]
|
||||
|
||||
@@ -557,7 +556,7 @@ class RequireRolesTest(AbstractPillarTest):
|
||||
|
||||
def test_all_roles_required(self):
|
||||
from flask import g
|
||||
from application.utils.authorization import require_login
|
||||
from pillar.api.utils.authorization import require_login
|
||||
|
||||
called = [False]
|
||||
|
||||
@@ -591,7 +590,7 @@ class RequireRolesTest(AbstractPillarTest):
|
||||
self.assertTrue(called[0])
|
||||
|
||||
def test_user_has_role(self):
|
||||
from application.utils.authorization import user_has_role
|
||||
from pillar.api.utils.authorization import user_has_role
|
||||
|
||||
with self.app.test_request_context():
|
||||
self.assertTrue(user_has_role('subscriber', {'roles': ['aap', 'noot', 'subscriber']}))
|
@@ -8,10 +8,9 @@ import logging
|
||||
import responses
|
||||
from bson import ObjectId
|
||||
from flask import url_for
|
||||
from pillar.tests import AbstractPillarTest, TEST_EMAIL_ADDRESS
|
||||
from werkzeug import exceptions as wz_exceptions
|
||||
|
||||
from common_test_class import AbstractPillarTest, TEST_EMAIL_ADDRESS
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -32,8 +31,8 @@ class AbstractHomeProjectTest(AbstractPillarTest):
|
||||
|
||||
class HomeProjectTest(AbstractHomeProjectTest):
|
||||
def test_create_home_project(self):
|
||||
from application.modules.blender_cloud import home_project
|
||||
from application.utils.authentication import validate_token
|
||||
from pillar.api.blender_cloud import home_project
|
||||
from pillar.api.utils.authentication import validate_token
|
||||
|
||||
user_id = self._create_user_with_token(roles={u'subscriber'}, token='token')
|
||||
|
||||
@@ -66,13 +65,13 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
def test_autocreate_home_project_with_subscriber_role(self):
|
||||
# Implicitly create user by token validation.
|
||||
self.mock_blenderid_validate_happy()
|
||||
resp = self.client.get('/users/me', headers={'Authorization': self.make_header('token')})
|
||||
resp = self.client.get('/api/users/me', headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code, resp)
|
||||
|
||||
# Grant subscriber and homeproject roles, and fetch the home project.
|
||||
self.badger(TEST_EMAIL_ADDRESS, {'subscriber', 'homeproject'}, 'grant')
|
||||
|
||||
resp = self.client.get('/bcloud/home-project',
|
||||
resp = self.client.get('/api/bcloud/home-project',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
@@ -90,39 +89,17 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
})
|
||||
self.assertIsNotNone(node)
|
||||
|
||||
# @responses.activate
|
||||
# def test_home_project_ab_testing(self):
|
||||
# self.mock_blenderid_validate_happy()
|
||||
# resp = self.client.get('/users/me', headers={'Authorization': self.make_header('token')})
|
||||
# self.assertEqual(200, resp.status_code, resp)
|
||||
#
|
||||
# # Grant subscriber and but NOT homeproject role, and fetch the home project.
|
||||
# self.badger(TEST_EMAIL_ADDRESS, {'subscriber'}, 'grant')
|
||||
#
|
||||
# resp = self.client.get('/bcloud/home-project',
|
||||
# headers={'Authorization': self.make_header('token')})
|
||||
# self.assertEqual(404, resp.status_code)
|
||||
#
|
||||
# resp = self.client.get('/users/me',
|
||||
# headers={'Authorization': self.make_header('token')})
|
||||
# self.assertEqual(200, resp.status_code)
|
||||
# me = json.loads(resp.data)
|
||||
#
|
||||
# with self.app.test_request_context():
|
||||
# from application.modules.blender_cloud import home_project
|
||||
# self.assertFalse(home_project.has_home_project(me['_id']))
|
||||
|
||||
@responses.activate
|
||||
def test_autocreate_home_project_with_demo_role(self):
|
||||
# Implicitly create user by token validation.
|
||||
self.mock_blenderid_validate_happy()
|
||||
resp = self.client.get('/users/me', headers={'Authorization': self.make_header('token')})
|
||||
resp = self.client.get('/api/users/me', headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code, resp)
|
||||
|
||||
# Grant demo and homeproject role, which should allow creation of the home project.
|
||||
self.badger(TEST_EMAIL_ADDRESS, {'demo', 'homeproject'}, 'grant')
|
||||
|
||||
resp = self.client.get('/bcloud/home-project',
|
||||
resp = self.client.get('/api/bcloud/home-project',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
@@ -142,18 +119,18 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
|
||||
@responses.activate
|
||||
def test_autocreate_home_project_with_succubus_role(self):
|
||||
from application.utils import dumps
|
||||
from pillar.api.utils import dumps
|
||||
|
||||
# Implicitly create user by token validation.
|
||||
self.mock_blenderid_validate_happy()
|
||||
resp = self.client.get('/users/me', headers={'Authorization': self.make_header('token')})
|
||||
resp = self.client.get('/api/users/me', headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
user_id = ObjectId(json.loads(resp.data)['_id'])
|
||||
|
||||
# Grant succubus role, which should allow creation of a read-only home project.
|
||||
self.badger(TEST_EMAIL_ADDRESS, {'succubus', 'homeproject'}, 'grant')
|
||||
|
||||
resp = self.client.get('/bcloud/home-project',
|
||||
resp = self.client.get('/api/bcloud/home-project',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code)
|
||||
json_proj = json.loads(resp.data)
|
||||
@@ -194,7 +171,7 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
'description': 'Sync folder for Blender 2.77',
|
||||
'properties': {'status': 'published'},
|
||||
}
|
||||
resp = self.client.post('/nodes', data=dumps(sub_sync_node),
|
||||
resp = self.client.post('/api/nodes', data=dumps(sub_sync_node),
|
||||
headers={'Authorization': self.make_header('token'),
|
||||
'Content-Type': 'application/json'}
|
||||
)
|
||||
@@ -211,8 +188,8 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
self.assertEqual(node_perms, expected_node_permissions)
|
||||
|
||||
def test_has_home_project(self):
|
||||
from application.modules.blender_cloud import home_project
|
||||
from application.utils.authentication import validate_token
|
||||
from pillar.api.blender_cloud import home_project
|
||||
from pillar.api.utils.authentication import validate_token
|
||||
|
||||
user_id = self._create_user_with_token(roles={u'subscriber'}, token='token')
|
||||
|
||||
@@ -225,7 +202,7 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
self.assertTrue(home_project.has_home_project(user_id))
|
||||
|
||||
# Delete the project.
|
||||
resp = self.client.delete('/projects/%s' % proj['_id'],
|
||||
resp = self.client.delete('/api/projects/%s' % proj['_id'],
|
||||
headers={'Authorization': self.make_header('token'),
|
||||
'If-Match': proj['_etag']})
|
||||
self.assertEqual(204, resp.status_code, resp.data)
|
||||
@@ -237,13 +214,13 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
|
||||
# Implicitly create user by token validation.
|
||||
self.mock_blenderid_validate_happy()
|
||||
resp = self.client.get('/users/me', headers={'Authorization': self.make_header('token')})
|
||||
resp = self.client.get('/api/users/me', headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code, resp)
|
||||
|
||||
# Grant subscriber role, and fetch the home project.
|
||||
self.badger(TEST_EMAIL_ADDRESS, {'subscriber', 'homeproject'}, 'grant')
|
||||
|
||||
resp = self.client.get('/bcloud/home-project',
|
||||
resp = self.client.get('/api/bcloud/home-project',
|
||||
query_string={'projection': json.dumps(
|
||||
{'permissions': 1,
|
||||
'category': 1,
|
||||
@@ -262,13 +239,13 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
|
||||
# Implicitly create user by token validation.
|
||||
self.mock_blenderid_validate_happy()
|
||||
resp = self.client.get('/users/me', headers={'Authorization': self.make_header('token')})
|
||||
resp = self.client.get('/api/users/me', headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code, resp)
|
||||
|
||||
# Grant subscriber role, and fetch the home project.
|
||||
self.badger(TEST_EMAIL_ADDRESS, {'subscriber', 'homeproject'}, 'grant')
|
||||
|
||||
resp = self.client.get('/bcloud/home-project',
|
||||
resp = self.client.get('/api/bcloud/home-project',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
|
||||
@@ -277,8 +254,8 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
|
||||
@responses.activate
|
||||
def test_multiple_users_with_home_project(self):
|
||||
from application.modules.blender_cloud import home_project
|
||||
from application.utils.authentication import validate_token
|
||||
from pillar.api.blender_cloud import home_project
|
||||
from pillar.api.utils.authentication import validate_token
|
||||
|
||||
uid1 = self._create_user_with_token(roles={u'subscriber'}, token='token1', user_id=24 * 'a')
|
||||
uid2 = self._create_user_with_token(roles={u'subscriber'}, token='token2', user_id=24 * 'b')
|
||||
@@ -295,9 +272,9 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
db_proj2 = self.app.data.driver.db['projects'].find_one(proj2['_id'])
|
||||
|
||||
# Test availability at end-point
|
||||
resp1 = self.client.get('/bcloud/home-project',
|
||||
resp1 = self.client.get('/api/bcloud/home-project',
|
||||
headers={'Authorization': self.make_header('token1')})
|
||||
resp2 = self.client.get('/bcloud/home-project',
|
||||
resp2 = self.client.get('/api/bcloud/home-project',
|
||||
headers={'Authorization': self.make_header('token2')})
|
||||
self.assertEqual(200, resp1.status_code)
|
||||
self.assertEqual(200, resp2.status_code)
|
||||
@@ -318,19 +295,19 @@ class HomeProjectTest(AbstractHomeProjectTest):
|
||||
self._create_user_with_token(roles={u'subscriber'}, token='token')
|
||||
|
||||
# Create home project by getting it.
|
||||
resp = self.client.get('/bcloud/home-project',
|
||||
resp = self.client.get('/api/bcloud/home-project',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
before_delete_json_proj = json.loads(resp.data)
|
||||
|
||||
# Delete the project.
|
||||
resp = self.client.delete('/projects/%s' % before_delete_json_proj['_id'],
|
||||
resp = self.client.delete('/api/projects/%s' % before_delete_json_proj['_id'],
|
||||
headers={'Authorization': self.make_header('token'),
|
||||
'If-Match': before_delete_json_proj['_etag']})
|
||||
self.assertEqual(204, resp.status_code, resp.data)
|
||||
|
||||
# Recreate home project by getting it.
|
||||
resp = self.client.get('/bcloud/home-project',
|
||||
resp = self.client.get('/api/bcloud/home-project',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
after_delete_json_proj = json.loads(resp.data)
|
||||
@@ -345,7 +322,7 @@ class HomeProjectUserChangedRoleTest(AbstractPillarTest):
|
||||
self.create_standard_groups()
|
||||
|
||||
def test_without_home_project(self):
|
||||
from application.modules.blender_cloud import home_project
|
||||
from pillar.api.blender_cloud import home_project
|
||||
|
||||
self.user_id = self.create_user()
|
||||
|
||||
@@ -356,8 +333,8 @@ class HomeProjectUserChangedRoleTest(AbstractPillarTest):
|
||||
# Shouldn't do anything, shouldn't crash either.
|
||||
|
||||
def test_already_subscriber_role(self):
|
||||
from application.modules.blender_cloud import home_project
|
||||
from application.utils.authentication import validate_token
|
||||
from pillar.api.blender_cloud import home_project
|
||||
from pillar.api.utils.authentication import validate_token
|
||||
|
||||
self.user_id = self.create_user(roles=set('subscriber'))
|
||||
self.create_valid_auth_token(self.user_id, 'token')
|
||||
@@ -374,8 +351,8 @@ class HomeProjectUserChangedRoleTest(AbstractPillarTest):
|
||||
self.create_test_node(home_proj['_id'])
|
||||
|
||||
def test_granting_subscriber_role(self):
|
||||
from application.modules.blender_cloud import home_project
|
||||
from application.utils.authentication import validate_token
|
||||
from pillar.api.blender_cloud import home_project
|
||||
from pillar.api.utils.authentication import validate_token
|
||||
|
||||
self.user_id = self.create_user(roles=set())
|
||||
self.create_valid_auth_token(self.user_id, 'token')
|
||||
@@ -392,8 +369,8 @@ class HomeProjectUserChangedRoleTest(AbstractPillarTest):
|
||||
self.create_test_node(home_proj['_id'])
|
||||
|
||||
def test_revoking_subscriber_role(self):
|
||||
from application.modules.blender_cloud import home_project
|
||||
from application.utils.authentication import validate_token
|
||||
from pillar.api.blender_cloud import home_project
|
||||
from pillar.api.utils.authentication import validate_token
|
||||
|
||||
self.user_id = self.create_user(roles=set('subscriber'))
|
||||
self.create_valid_auth_token(self.user_id, 'token')
|
||||
@@ -410,7 +387,7 @@ class HomeProjectUserChangedRoleTest(AbstractPillarTest):
|
||||
self.create_test_node(home_proj['_id'], 403)
|
||||
|
||||
def create_test_node(self, project_id, status_code=201):
|
||||
from application.utils import dumps
|
||||
from pillar.api.utils import dumps
|
||||
|
||||
node = {
|
||||
'project': project_id,
|
||||
@@ -420,7 +397,7 @@ class HomeProjectUserChangedRoleTest(AbstractPillarTest):
|
||||
'properties': {},
|
||||
}
|
||||
|
||||
resp = self.client.post('/nodes', data=dumps(node),
|
||||
resp = self.client.post('/api/nodes', data=dumps(node),
|
||||
headers={'Authorization': self.make_header('token'),
|
||||
'Content-Type': 'application/json'})
|
||||
self.assertEqual(status_code, resp.status_code, resp.data)
|
||||
@@ -465,7 +442,7 @@ class TextureLibraryTest(AbstractHomeProjectTest):
|
||||
)
|
||||
|
||||
def test_blender_cloud_addon_version(self):
|
||||
from application.modules.blender_cloud import blender_cloud_addon_version
|
||||
from pillar.api.blender_cloud import blender_cloud_addon_version
|
||||
|
||||
# Three-digit version
|
||||
with self.app.test_request_context(headers={'Blender-Cloud-Addon': '1.3.3'}):
|
||||
@@ -484,7 +461,7 @@ class TextureLibraryTest(AbstractHomeProjectTest):
|
||||
self.assertRaises(wz_exceptions.BadRequest, blender_cloud_addon_version)
|
||||
|
||||
def test_hdri_library__no_bcloud_version(self):
|
||||
resp = self.get('/bcloud/texture-libraries', auth_token='token')
|
||||
resp = self.get('/api/bcloud/texture-libraries', auth_token='token')
|
||||
libs = resp.json()['_items']
|
||||
library_project_ids = {proj['_id'] for proj in libs}
|
||||
|
||||
@@ -492,7 +469,7 @@ class TextureLibraryTest(AbstractHomeProjectTest):
|
||||
self.assertIn(unicode(self.tex_proj_id), library_project_ids)
|
||||
|
||||
def test_hdri_library__old_bcloud_addon(self):
|
||||
resp = self.get('/bcloud/texture-libraries',
|
||||
resp = self.get('/api/bcloud/texture-libraries',
|
||||
auth_token='token',
|
||||
headers={'Blender-Cloud-Addon': '1.3.3'})
|
||||
libs = resp.json()['_items']
|
||||
@@ -501,7 +478,7 @@ class TextureLibraryTest(AbstractHomeProjectTest):
|
||||
self.assertIn(unicode(self.tex_proj_id), library_project_ids)
|
||||
|
||||
def test_hdri_library__new_bcloud_addon(self):
|
||||
resp = self.get('/bcloud/texture-libraries',
|
||||
resp = self.get('/api/bcloud/texture-libraries',
|
||||
auth_token='token',
|
||||
headers={'Blender-Cloud-Addon': '1.4.0'})
|
||||
libs = resp.json()['_items']
|
||||
@@ -512,9 +489,9 @@ class TextureLibraryTest(AbstractHomeProjectTest):
|
||||
|
||||
class HdriSortingTest(AbstractHomeProjectTest):
|
||||
def setUp(self, **kwargs):
|
||||
from manage_extra.node_types.hdri import node_type_hdri
|
||||
from pillar.api.node_types.hdri import node_type_hdri
|
||||
|
||||
AbstractHomeProjectTest.setUp(self, **kwargs)
|
||||
super(HdriSortingTest, self).setUp(**kwargs)
|
||||
|
||||
self.user_id = self._create_user_with_token({u'subscriber'}, 'token')
|
||||
self.hdri_proj_id, proj = self.ensure_project_exists(project_overrides={
|
||||
@@ -571,11 +548,11 @@ class HdriSortingTest(AbstractHomeProjectTest):
|
||||
},
|
||||
'name': 'Symmetrical Garden'
|
||||
}
|
||||
resp = self.post('/nodes', json=node, expected_status=201, auth_token='token')
|
||||
resp = self.post('/api/nodes', json=node, expected_status=201, auth_token='token')
|
||||
node_info = resp.json()
|
||||
|
||||
# Check that the node's files are in the right order
|
||||
resp = self.get('/nodes/%s' % node_info['_id'], auth_token='token')
|
||||
resp = self.get('/api/nodes/%s' % node_info['_id'], auth_token='token')
|
||||
get_node = resp.json()
|
||||
|
||||
self.assertEqual(['256p', '1k', '2k'],
|
||||
@@ -597,7 +574,7 @@ class HdriSortingTest(AbstractHomeProjectTest):
|
||||
},
|
||||
'name': 'Symmetrical Garden'
|
||||
}
|
||||
resp = self.post('/nodes', json=node, expected_status=201, auth_token='token')
|
||||
resp = self.post('/api/nodes', json=node, expected_status=201, auth_token='token')
|
||||
node_info = resp.json()
|
||||
|
||||
# Mess up the node's order
|
||||
@@ -606,11 +583,11 @@ class HdriSortingTest(AbstractHomeProjectTest):
|
||||
{'resolution': '1k', 'file': self.file_1k},
|
||||
{'resolution': '256p', 'file': self.file_256p},
|
||||
]
|
||||
self.put('/nodes/%s' % node_info['_id'], json=node, auth_token='token',
|
||||
self.put('/api/nodes/%s' % node_info['_id'], json=node, auth_token='token',
|
||||
headers={'If-Match': node_info['_etag']})
|
||||
|
||||
# Check that the node's files are in the right order
|
||||
resp = self.get('/nodes/%s' % node_info['_id'], auth_token='token')
|
||||
resp = self.get('/api/nodes/%s' % node_info['_id'], auth_token='token')
|
||||
get_node = resp.json()
|
||||
|
||||
self.assertEqual(['256p', '1k', '2k'],
|
@@ -1,13 +1,12 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import responses
|
||||
import json
|
||||
|
||||
import responses
|
||||
from bson import ObjectId
|
||||
from flask import g
|
||||
|
||||
from common_test_class import (AbstractPillarTest, TEST_EMAIL_ADDRESS, BLENDER_ID_TEST_USERID,
|
||||
TEST_SUBCLIENT_TOKEN, TEST_EMAIL_USER, TEST_FULL_NAME)
|
||||
from pillar.tests import (AbstractPillarTest, TEST_EMAIL_ADDRESS, BLENDER_ID_TEST_USERID,
|
||||
TEST_SUBCLIENT_TOKEN, TEST_EMAIL_USER, TEST_FULL_NAME)
|
||||
|
||||
|
||||
class BlenderIdSubclientTest(AbstractPillarTest):
|
||||
@@ -34,7 +33,7 @@ class BlenderIdSubclientTest(AbstractPillarTest):
|
||||
@responses.activate
|
||||
def test_store_scst_existing_user(self):
|
||||
# Make sure the user exists in our database.
|
||||
from application.utils.authentication import create_new_user
|
||||
from pillar.api.utils.authentication import create_new_user
|
||||
with self.app.test_request_context():
|
||||
create_new_user(TEST_EMAIL_ADDRESS, 'apekoppie', BLENDER_ID_TEST_USERID)
|
||||
|
||||
@@ -63,7 +62,7 @@ class BlenderIdSubclientTest(AbstractPillarTest):
|
||||
db_user = self._common_user_test(201)
|
||||
|
||||
# Make a call that's authenticated with the SCST
|
||||
from application.utils import authentication as auth
|
||||
from pillar.api.utils import authentication as auth
|
||||
|
||||
subclient_id = self.app.config['BLENDER_ID_SUBCLIENT_ID']
|
||||
auth_header = self.make_header(TEST_SUBCLIENT_TOKEN, subclient_id)
|
||||
@@ -80,7 +79,7 @@ class BlenderIdSubclientTest(AbstractPillarTest):
|
||||
self.mock_blenderid_validate_happy()
|
||||
|
||||
subclient_id = self.app.config['BLENDER_ID_SUBCLIENT_ID']
|
||||
resp = self.client.post('/blender_id/store_scst',
|
||||
resp = self.client.post('/api/blender_id/store_scst',
|
||||
data={'user_id': BLENDER_ID_TEST_USERID,
|
||||
'subclient_id': subclient_id,
|
||||
'token': scst})
|
@@ -1,19 +1,19 @@
|
||||
"""Test cases for the zencoder notifications."""
|
||||
import json
|
||||
|
||||
from common_test_class import AbstractPillarTest
|
||||
from pillar.tests import AbstractPillarTest
|
||||
|
||||
|
||||
class ZencoderNotificationTest(AbstractPillarTest):
|
||||
|
||||
def test_missing_secret(self):
|
||||
with self.app.test_request_context():
|
||||
resp = self.client.post('/encoding/zencoder/notifications')
|
||||
resp = self.client.post('/api/encoding/zencoder/notifications')
|
||||
self.assertEqual(401, resp.status_code)
|
||||
|
||||
def test_wrong_secret(self):
|
||||
with self.app.test_request_context():
|
||||
resp = self.client.post('/encoding/zencoder/notifications',
|
||||
resp = self.client.post('/api/encoding/zencoder/notifications',
|
||||
headers={'X-Zencoder-Notification-Secret': 'koro'})
|
||||
self.assertEqual(401, resp.status_code)
|
||||
|
||||
@@ -26,7 +26,7 @@ class ZencoderNotificationTest(AbstractPillarTest):
|
||||
|
||||
with self.app.test_request_context():
|
||||
secret = self.app.config['ZENCODER_NOTIFICATIONS_SECRET']
|
||||
resp = self.client.post('/encoding/zencoder/notifications',
|
||||
resp = self.client.post('/api/encoding/zencoder/notifications',
|
||||
data=json.dumps({'job': {'id': 'koro-007',
|
||||
'state': 'done'},
|
||||
'outputs': [{
|
@@ -4,20 +4,20 @@ import bson.tz_util
|
||||
import datetime
|
||||
from eve import RFC1123_DATE_FORMAT
|
||||
|
||||
from common_test_class import AbstractPillarTest
|
||||
from pillar.tests import AbstractPillarTest
|
||||
|
||||
|
||||
class FileCachingTest(AbstractPillarTest):
|
||||
|
||||
def test_nonexistant_file(self):
|
||||
with self.app.test_request_context():
|
||||
resp = self.client.get('/files/12345')
|
||||
resp = self.client.get('/api/files/12345')
|
||||
self.assertEqual(404, resp.status_code)
|
||||
|
||||
def test_existing_file(self):
|
||||
file_id, _ = self.ensure_file_exists()
|
||||
|
||||
resp = self.client.get('/files/%s' % file_id)
|
||||
resp = self.client.get('/api/files/%s' % file_id)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
def test_if_modified_304(self):
|
||||
@@ -29,7 +29,7 @@ class FileCachingTest(AbstractPillarTest):
|
||||
})
|
||||
|
||||
updated = file_doc['_updated'].strftime(RFC1123_DATE_FORMAT)
|
||||
resp = self.client.get('/files/%s' % file_id,
|
||||
resp = self.client.get('/api/files/%s' % file_id,
|
||||
headers={'if_modified_since': updated})
|
||||
self.assertEqual(304, resp.status_code)
|
||||
|
||||
@@ -40,7 +40,7 @@ class FileCachingTest(AbstractPillarTest):
|
||||
|
||||
with self.app.test_request_context():
|
||||
updated = (file_doc['_updated'] + delta).strftime(RFC1123_DATE_FORMAT)
|
||||
resp = self.client.get('/files/%s' % file_id,
|
||||
resp = self.client.get('/api/files/%s' % file_id,
|
||||
headers={'if_modified_since': updated})
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
@@ -53,6 +53,6 @@ class FileCachingTest(AbstractPillarTest):
|
||||
})
|
||||
|
||||
updated = file_doc['_updated'].strftime(RFC1123_DATE_FORMAT)
|
||||
resp = self.client.get('/files/%s' % file_id,
|
||||
resp = self.client.get('/api/files/%s' % file_id,
|
||||
headers={'if_modified_since': updated})
|
||||
self.assertEqual(200, resp.status_code)
|
@@ -1,14 +1,13 @@
|
||||
import json
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import pillar.tests.common_test_data as ctd
|
||||
import rsa.randnum
|
||||
from pillar.tests import AbstractPillarTest, TEST_EMAIL_ADDRESS
|
||||
from werkzeug.datastructures import FileStorage
|
||||
|
||||
from common_test_class import AbstractPillarTest, TEST_EMAIL_ADDRESS
|
||||
import common_test_data as ctd
|
||||
|
||||
|
||||
class FileStorageTest(AbstractPillarTest):
|
||||
def fake_file(self, filename, content_type):
|
||||
@@ -17,7 +16,7 @@ class FileStorageTest(AbstractPillarTest):
|
||||
content_type=content_type)
|
||||
|
||||
def test_override_content_type(self):
|
||||
from application.modules.file_storage import override_content_type
|
||||
from pillar.api.file_storage import override_content_type
|
||||
|
||||
fake = self.fake_file('compressed.blend', 'jemoeder')
|
||||
override_content_type(fake)
|
||||
@@ -125,7 +124,7 @@ class FileAccessTest(AbstractPillarTest):
|
||||
headers = {'Authorization': self.make_header(token)}
|
||||
else:
|
||||
headers = None
|
||||
resp = self.client.get('/files/%s' % file_id, headers=headers)
|
||||
resp = self.client.get('/api/files/%s' % file_id, headers=headers)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
file_info = json.loads(resp.data)
|
||||
|
||||
@@ -189,7 +188,7 @@ class FileMaxSizeTest(AbstractPillarTest):
|
||||
file_size = 10 * 2 ** 10
|
||||
test_file = self.create_test_file(file_size)
|
||||
|
||||
resp = self.post('/storage/stream/%s' % self.project_id,
|
||||
resp = self.post('/api/storage/stream/%s' % self.project_id,
|
||||
expected_status=201,
|
||||
auth_token='token',
|
||||
files={'file': (test_file, 'test_file.bin')})
|
||||
@@ -202,7 +201,7 @@ class FileMaxSizeTest(AbstractPillarTest):
|
||||
file_size = 30 * 2 ** 10
|
||||
test_file = self.create_test_file(file_size)
|
||||
|
||||
self.post('/storage/stream/%s' % self.project_id,
|
||||
self.post('/api/storage/stream/%s' % self.project_id,
|
||||
expected_status=413,
|
||||
auth_token='token',
|
||||
files={'file': (test_file, 'test_file.bin')})
|
||||
@@ -213,7 +212,7 @@ class FileMaxSizeTest(AbstractPillarTest):
|
||||
file_size = 30 * 2 ** 10
|
||||
test_file = self.create_test_file(file_size)
|
||||
|
||||
resp = self.post('/storage/stream/%s' % self.project_id,
|
||||
resp = self.post('/api/storage/stream/%s' % self.project_id,
|
||||
expected_status=201,
|
||||
auth_token='token',
|
||||
files={'file': (test_file, 'test_file.bin')})
|
||||
@@ -224,7 +223,7 @@ class FileMaxSizeTest(AbstractPillarTest):
|
||||
|
||||
def assert_file_doc_ok(self, file_id, file_size):
|
||||
with self.app.test_request_context():
|
||||
from application.utils import str2id
|
||||
from pillar.api.utils import str2id
|
||||
|
||||
# Check that the file exists in MongoDB
|
||||
files_coll = self.app.data.driver.db['files']
|
@@ -2,7 +2,7 @@
|
||||
import json
|
||||
|
||||
from bson import ObjectId, tz_util
|
||||
from common_test_class import AbstractPillarTest
|
||||
from pillar.tests import AbstractPillarTest
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class LinkRefreshTest(AbstractPillarTest):
|
||||
refreshed_lower_limit = self.now + timedelta(seconds=0.9 * validity_seconds)
|
||||
|
||||
with self.app.test_request_context():
|
||||
from application.modules import file_storage
|
||||
from pillar.api import file_storage
|
||||
|
||||
# First run: refresh files 0 and 1, don't touch 2-4 (due to chunking).
|
||||
file_storage.refresh_links_for_project(self.project_id, 2, hour_from_now)
|
||||
@@ -102,7 +102,7 @@ class LinkRefreshTest(AbstractPillarTest):
|
||||
validity_seconds = self.app.config['FILE_LINK_VALIDITY']['unittest']
|
||||
refreshed_lower_limit = self.now + timedelta(seconds=0.9 * validity_seconds)
|
||||
|
||||
resp = self.client.get('/files/%s' % self.file_id[0])
|
||||
resp = self.client.get('/api/files/%s' % self.file_id[0])
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
# Test the returned document.
|
@@ -3,12 +3,12 @@ import datetime
|
||||
|
||||
from bson import tz_util
|
||||
|
||||
from common_test_class import AbstractPillarTest
|
||||
from pillar.tests import AbstractPillarTest
|
||||
|
||||
|
||||
class LocalAuthTest(AbstractPillarTest):
|
||||
def create_test_user(self):
|
||||
from application.modules import local_auth
|
||||
from pillar.api import local_auth
|
||||
with self.app.test_request_context():
|
||||
user_id = local_auth.create_local_user('koro@example.com', 'oti')
|
||||
return user_id
|
||||
@@ -24,7 +24,7 @@ class LocalAuthTest(AbstractPillarTest):
|
||||
def test_login_existing_user(self):
|
||||
user_id = self.create_test_user()
|
||||
|
||||
resp = self.client.post('/auth/make-token',
|
||||
resp = self.client.post('/api/auth/make-token',
|
||||
data={'username': 'koro',
|
||||
'password': 'oti'})
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
@@ -33,14 +33,14 @@ class LocalAuthTest(AbstractPillarTest):
|
||||
token = token_info['token']
|
||||
|
||||
headers = {'Authorization': self.make_header(token)}
|
||||
resp = self.client.get('/users/%s' % user_id,
|
||||
resp = self.client.get('/api/users/%s' % user_id,
|
||||
headers=headers)
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
|
||||
def test_login_expired_token(self):
|
||||
user_id = self.create_test_user()
|
||||
|
||||
resp = self.client.post('/auth/make-token',
|
||||
resp = self.client.post('/api/auth/make-token',
|
||||
data={'username': 'koro',
|
||||
'password': 'oti'})
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
@@ -58,19 +58,19 @@ class LocalAuthTest(AbstractPillarTest):
|
||||
|
||||
# Do something restricted.
|
||||
headers = {'Authorization': self.make_header(token)}
|
||||
resp = self.client.put('/users/%s' % user_id,
|
||||
resp = self.client.put('/api/users/%s' % user_id,
|
||||
headers=headers)
|
||||
self.assertEqual(403, resp.status_code, resp.data)
|
||||
|
||||
def test_login_nonexistant_user(self):
|
||||
resp = self.client.post('/auth/make-token',
|
||||
resp = self.client.post('/api/auth/make-token',
|
||||
data={'username': 'proog',
|
||||
'password': 'oti'})
|
||||
|
||||
self.assertEqual(403, resp.status_code, resp.data)
|
||||
|
||||
def test_login_bad_pwd(self):
|
||||
resp = self.client.post('/auth/make-token',
|
||||
resp = self.client.post('/api/auth/make-token',
|
||||
data={'username': 'koro',
|
||||
'password': 'koro'})
|
||||
|
@@ -1,15 +1,14 @@
|
||||
import json
|
||||
|
||||
from mock import mock
|
||||
import pillar.tests.common_test_data as ctd
|
||||
from bson import ObjectId
|
||||
from eve.methods.post import post_internal
|
||||
from eve.methods.put import put_internal
|
||||
from flask import g
|
||||
from mock import mock
|
||||
from pillar.tests import AbstractPillarTest
|
||||
from werkzeug.exceptions import UnprocessableEntity
|
||||
|
||||
from common_test_class import AbstractPillarTest
|
||||
import common_test_data as ctd
|
||||
|
||||
|
||||
class NodeContentTypeTest(AbstractPillarTest):
|
||||
def mkfile(self, file_id, content_type):
|
||||
@@ -78,14 +77,14 @@ class NodeContentTypeTest(AbstractPillarTest):
|
||||
self.create_valid_auth_token(user_id, 'token')
|
||||
project_id, _ = self.ensure_project_exists()
|
||||
|
||||
resp = self.client.get('/projects/%s?node_type=asset' % project_id)
|
||||
resp = self.client.get('/api/projects/%s?node_type=asset' % project_id)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
data = json.loads(resp.data)
|
||||
self.assertEqual([u'GET'], data['allowed_methods'])
|
||||
|
||||
def test_default_picture_image_asset(self):
|
||||
from application.utils import dumps
|
||||
from pillar.api.utils import dumps
|
||||
|
||||
file_id_image = self.mkfile(24 * 'a', 'image/jpeg')
|
||||
file_id_video = self.mkfile(24 * 'b', 'video/matroska')
|
||||
@@ -98,7 +97,7 @@ class NodeContentTypeTest(AbstractPillarTest):
|
||||
|
||||
def test_for(node, expected_picture_id):
|
||||
# Create the node
|
||||
resp = self.client.post('/nodes',
|
||||
resp = self.client.post('/api/nodes',
|
||||
data=dumps(node),
|
||||
headers={'Authorization': self.make_header('token'),
|
||||
'Content-Type': 'application/json'})
|
||||
@@ -106,7 +105,7 @@ class NodeContentTypeTest(AbstractPillarTest):
|
||||
node_id = json.loads(resp.data)['_id']
|
||||
|
||||
# Test that the node has the attached file as picture.
|
||||
resp = self.client.get('/nodes/%s' % node_id,
|
||||
resp = self.client.get('/api/nodes/%s' % node_id,
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(resp.status_code, 200, resp.data)
|
||||
json_node = json.loads(resp.data)
|
||||
@@ -221,14 +220,14 @@ class NodeOwnerTest(AbstractPillarTest):
|
||||
self._test_user(test_node)
|
||||
|
||||
def _test_user(self, test_node):
|
||||
from application.utils import dumps
|
||||
from pillar.api.utils import dumps
|
||||
|
||||
resp = self.client.post('/nodes', data=dumps(test_node),
|
||||
resp = self.client.post('/api/nodes', data=dumps(test_node),
|
||||
headers={'Authorization': self.make_header('token'),
|
||||
'Content-Type': 'application/json'})
|
||||
self.assertEqual(201, resp.status_code, resp.data)
|
||||
created = json.loads(resp.data)
|
||||
resp = self.client.get('/nodes/%s' % created['_id'],
|
||||
resp = self.client.get('/api/nodes/%s' % created['_id'],
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
json_node = json.loads(resp.data)
|
||||
@@ -252,7 +251,7 @@ class NodeSharingTest(AbstractPillarTest):
|
||||
self.create_valid_auth_token(self.user_id, 'token')
|
||||
|
||||
# Create a node to share
|
||||
resp = self.post('/nodes', expected_status=201, auth_token='token', json={
|
||||
resp = self.post('/api/nodes', expected_status=201, auth_token='token', json={
|
||||
'project': self.project_id,
|
||||
'node_type': 'asset',
|
||||
'name': str(self),
|
||||
@@ -268,7 +267,7 @@ class NodeSharingTest(AbstractPillarTest):
|
||||
|
||||
def test_share_node(self):
|
||||
# Share the node
|
||||
resp = self.post('/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
resp = self.post('/api/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
expected_status=201)
|
||||
share_data = resp.json()
|
||||
|
||||
@@ -276,57 +275,57 @@ class NodeSharingTest(AbstractPillarTest):
|
||||
|
||||
def test_anonymous_access_shared_node(self):
|
||||
# Anonymous user should not have access
|
||||
self.get('/nodes/%s' % self.node_id, expected_status=403)
|
||||
self.get('/api/nodes/%s' % self.node_id, expected_status=403)
|
||||
|
||||
# Share the node
|
||||
self.post('/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
self.post('/api/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
expected_status=201)
|
||||
|
||||
# Check that an anonymous user has acces.
|
||||
resp = self.get('/nodes/%s' % self.node_id)
|
||||
resp = self.get('/api/nodes/%s' % self.node_id)
|
||||
self.assertEqual(str(self.node_id), resp.json()['_id'])
|
||||
|
||||
def test_other_user_access_shared_node(self):
|
||||
# Share the node
|
||||
self.post('/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
self.post('/api/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
expected_status=201)
|
||||
|
||||
# Check that another user has access
|
||||
other_user_id = self.create_user(user_id=24 * 'a')
|
||||
self.create_valid_auth_token(other_user_id, 'other-token')
|
||||
resp = self.get('/nodes/%s' % self.node_id, auth_token='other-token')
|
||||
resp = self.get('/api/nodes/%s' % self.node_id, auth_token='other-token')
|
||||
self.assertEqual(str(self.node_id), resp.json()['_id'])
|
||||
|
||||
def test_get_share_data__unshared_node(self):
|
||||
self.get('/nodes/%s/share' % self.node_id,
|
||||
self.get('/api/nodes/%s/share' % self.node_id,
|
||||
expected_status=204,
|
||||
auth_token='token')
|
||||
|
||||
def test_get_share_data__shared_node(self):
|
||||
# Share the node first.
|
||||
self.post('/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
self.post('/api/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
expected_status=201)
|
||||
|
||||
# Then get its share info.
|
||||
resp = self.get('/nodes/%s/share' % self.node_id, auth_token='token')
|
||||
resp = self.get('/api/nodes/%s/share' % self.node_id, auth_token='token')
|
||||
share_data = resp.json()
|
||||
|
||||
self._check_share_data(share_data)
|
||||
|
||||
def test_unauthenticated(self):
|
||||
self.post('/nodes/%s/share' % self.node_id,
|
||||
self.post('/api/nodes/%s/share' % self.node_id,
|
||||
expected_status=403)
|
||||
|
||||
def test_other_user(self):
|
||||
other_user_id = self.create_user(user_id=24 * 'a')
|
||||
self.create_valid_auth_token(other_user_id, 'other-token')
|
||||
|
||||
self.post('/nodes/%s/share' % self.node_id,
|
||||
self.post('/api/nodes/%s/share' % self.node_id,
|
||||
auth_token='other-token',
|
||||
expected_status=403)
|
||||
|
||||
def test_create_short_link(self):
|
||||
from application.modules.nodes import create_short_code
|
||||
from pillar.api.nodes import create_short_code
|
||||
|
||||
with self.app.test_request_context():
|
||||
length = self.app.config['SHORT_CODE_LENGTH']
|
||||
@@ -339,7 +338,7 @@ class NodeSharingTest(AbstractPillarTest):
|
||||
|
||||
def test_short_code_collision(self):
|
||||
# Create a second node that has already been shared.
|
||||
self.post('/nodes', expected_status=201, auth_token='token', json={
|
||||
self.post('/api/nodes', expected_status=201, auth_token='token', json={
|
||||
'project': self.project_id,
|
||||
'node_type': 'asset',
|
||||
'name': 'collider',
|
||||
@@ -349,9 +348,9 @@ class NodeSharingTest(AbstractPillarTest):
|
||||
|
||||
# Mock create_short_code so that it returns predictable short codes.
|
||||
codes = ['takenX', 'takenX', 'freeXX']
|
||||
with mock.patch('application.modules.nodes.create_short_code',
|
||||
with mock.patch('pillar.api.nodes.create_short_code',
|
||||
side_effect=codes) as create_short_link:
|
||||
resp = self.post('/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
resp = self.post('/api/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
expected_status=201)
|
||||
|
||||
share_data = resp.json()
|
||||
@@ -363,19 +362,19 @@ class NodeSharingTest(AbstractPillarTest):
|
||||
"""Projecting short_code should get us short_link as well."""
|
||||
|
||||
# Share the node
|
||||
resp = self.post('/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
resp = self.post('/api/nodes/%s/share' % self.node_id, auth_token='token',
|
||||
expected_status=201)
|
||||
share_data = resp.json()
|
||||
|
||||
# Get the node with short_code
|
||||
resp = self.get('/nodes/%s' % self.node_id,
|
||||
resp = self.get('/api/nodes/%s' % self.node_id,
|
||||
json={'projection': {'short_code': 1}})
|
||||
node = resp.json()
|
||||
self.assertEqual(node['short_code'], share_data['short_code'])
|
||||
self.assertTrue(node['short_link'].endswith(share_data['short_code']))
|
||||
|
||||
# Get the node without short_code
|
||||
resp = self.get('/nodes/%s' % self.node_id,
|
||||
resp = self.get('/api/nodes/%s' % self.node_id,
|
||||
qs={'projection': {'short_code': 0}})
|
||||
node = resp.json()
|
||||
self.assertNotIn('short_code', node)
|
@@ -1,19 +1,35 @@
|
||||
from common_test_class import AbstractPillarTest
|
||||
import common_test_data as ctd
|
||||
from pillar.tests import AbstractPillarTest
|
||||
|
||||
|
||||
class PatchCommentTest(AbstractPillarTest):
|
||||
def setUp(self, **kwargs):
|
||||
AbstractPillarTest.setUp(self, **kwargs)
|
||||
|
||||
self.project_id, proj = self.ensure_project_exists()
|
||||
admin_group_id = proj['permissions']['groups'][0]['group']
|
||||
|
||||
self.user_id = self.create_user(user_id=24 * 'a')
|
||||
self.owner_id = self.create_user(user_id=24 * 'b')
|
||||
self.owner_id = self.create_user(user_id=24 * 'b', groups=[admin_group_id])
|
||||
self.create_valid_auth_token(self.user_id, 'token')
|
||||
self.create_valid_auth_token(self.owner_id, 'owner-token')
|
||||
self.project_id, _ = self.ensure_project_exists()
|
||||
|
||||
# Create a node to attach the comment to
|
||||
asset = {'description': '',
|
||||
'project': self.project_id,
|
||||
'node_type': 'asset',
|
||||
'user': self.owner_id,
|
||||
'properties': {'status': 'published'},
|
||||
'name': 'Test asset'}
|
||||
|
||||
resp = self.post('/api/nodes', json=asset,
|
||||
auth_token='owner-token',
|
||||
expected_status=201)
|
||||
asset_id = resp.json()['_id']
|
||||
|
||||
# Create the comment
|
||||
comment = {'description': '',
|
||||
'project': self.project_id,
|
||||
'parent': asset_id,
|
||||
'node_type': 'comment',
|
||||
'user': self.owner_id,
|
||||
'properties': {'rating_positive': 0,
|
||||
@@ -24,15 +40,11 @@ class PatchCommentTest(AbstractPillarTest):
|
||||
},
|
||||
'name': 'Test comment'}
|
||||
|
||||
# Use MongoDB to insert the node (comments aren't allowed to be parentless,
|
||||
# so Eve would bark).
|
||||
with self.app.test_request_context():
|
||||
nodes_coll = self.app.data.driver.db['nodes']
|
||||
result = nodes_coll.insert_one(comment)
|
||||
self.assertIsNotNone(result.inserted_id)
|
||||
comment_id = result.inserted_id
|
||||
|
||||
self.node_url = '/nodes/%s' % comment_id
|
||||
resp = self.post('/api/nodes', json=comment,
|
||||
auth_token='owner-token',
|
||||
expected_status=201)
|
||||
comment_info = resp.json()
|
||||
self.node_url = '/api/nodes/%s' % comment_info['_id']
|
||||
|
||||
def test_upvote_other_comment(self):
|
||||
# Patch the node
|
@@ -8,8 +8,7 @@ import logging
|
||||
import urllib
|
||||
|
||||
from bson import ObjectId
|
||||
|
||||
from common_test_class import AbstractPillarTest
|
||||
from pillar.tests import AbstractPillarTest
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -21,7 +20,7 @@ class AbstractProjectTest(AbstractPillarTest):
|
||||
return user_id
|
||||
|
||||
def _create_project(self, project_name, token):
|
||||
resp = self.client.post('/p/create',
|
||||
resp = self.client.post('/api/p/create',
|
||||
headers={'Authorization': self.make_header(token)},
|
||||
data={'project_name': project_name})
|
||||
return resp
|
||||
@@ -60,7 +59,7 @@ class ProjectCreationTest(AbstractProjectTest):
|
||||
project_id = project_info['_id']
|
||||
|
||||
# Test that the Location header contains the location of the project document.
|
||||
self.assertEqual('http://localhost/projects/%s' % project_id,
|
||||
self.assertEqual('http://localhost/api/projects/%s' % project_id,
|
||||
resp.headers['Location'])
|
||||
|
||||
# GET the project from the URL in the Location header to see if that works too.
|
||||
@@ -76,7 +75,7 @@ class ProjectCreationTest(AbstractProjectTest):
|
||||
self.assertEqual(1, len(project['permissions']['groups']))
|
||||
|
||||
# Check the etag
|
||||
resp = self.client.get('/projects/%s' % project_id, headers=auth_header)
|
||||
resp = self.client.get('/api/projects/%s' % project_id, headers=auth_header)
|
||||
from_db = json.loads(resp.data)
|
||||
self.assertEqual(from_db['_etag'], project['_etag'])
|
||||
|
||||
@@ -126,21 +125,21 @@ class ProjectCreationTest(AbstractProjectTest):
|
||||
token='token-b')
|
||||
|
||||
# Assertion: each user must have access to their own project.
|
||||
resp = self.client.get('/projects/%s' % proj_a['_id'],
|
||||
resp = self.client.get('/api/projects/%s' % proj_a['_id'],
|
||||
headers={'Authorization': self.make_header('token-a')})
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
resp = self.client.get('/projects/%s' % proj_b['_id'],
|
||||
resp = self.client.get('/api/projects/%s' % proj_b['_id'],
|
||||
headers={'Authorization': self.make_header('token-b')})
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
|
||||
# Getting a project list should return projects you have access to.
|
||||
resp = self.client.get('/projects',
|
||||
resp = self.client.get('/api/projects',
|
||||
headers={'Authorization': self.make_header('token-a')})
|
||||
self.assertEqual(200, resp.status_code)
|
||||
proj_list = json.loads(resp.data)
|
||||
self.assertEqual({u'Prøject A'}, {p['name'] for p in proj_list['_items']})
|
||||
|
||||
resp = self.client.get('/projects',
|
||||
resp = self.client.get('/api/projects',
|
||||
headers={'Authorization': self.make_header('token-b')})
|
||||
self.assertEqual(200, resp.status_code)
|
||||
proj_list = json.loads(resp.data)
|
||||
@@ -148,7 +147,7 @@ class ProjectCreationTest(AbstractProjectTest):
|
||||
|
||||
# No access to anything for user C, should result in empty list.
|
||||
self._create_user_with_token(roles={u'subscriber'}, token='token-c', user_id=12 * 'c')
|
||||
resp = self.client.get('/projects',
|
||||
resp = self.client.get('/api/projects',
|
||||
headers={'Authorization': self.make_header('token-c')})
|
||||
self.assertEqual(200, resp.status_code)
|
||||
proj_list = json.loads(resp.data)
|
||||
@@ -159,11 +158,11 @@ class ProjectEditTest(AbstractProjectTest):
|
||||
def test_editing_as_subscriber(self):
|
||||
"""Test that we can set certain fields, but not all."""
|
||||
|
||||
from application.utils import remove_private_keys, PillarJSONEncoder
|
||||
from pillar.api.utils import remove_private_keys, PillarJSONEncoder
|
||||
dumps = functools.partial(json.dumps, cls=PillarJSONEncoder)
|
||||
|
||||
project_info = self._create_user_and_project([u'subscriber'])
|
||||
project_url = '/projects/%(_id)s' % project_info
|
||||
project_url = '/api/projects/%(_id)s' % project_info
|
||||
|
||||
resp = self.client.get(project_url,
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
@@ -174,7 +173,7 @@ class ProjectEditTest(AbstractProjectTest):
|
||||
self._create_user_with_token(['subscriber'], 'other-token', user_id=other_user_id)
|
||||
|
||||
# Unauthenticated should be forbidden
|
||||
resp = self.client.put('/projects/%s' % project['_id'],
|
||||
resp = self.client.put('/api/projects/%s' % project['_id'],
|
||||
data=dumps(remove_private_keys(project)),
|
||||
headers={'Content-Type': 'application/json'})
|
||||
self.assertEqual(403, resp.status_code)
|
||||
@@ -220,11 +219,11 @@ class ProjectEditTest(AbstractProjectTest):
|
||||
def test_editing_as_admin(self):
|
||||
"""Test that we can set all fields as admin."""
|
||||
|
||||
from application.utils import remove_private_keys, PillarJSONEncoder
|
||||
from pillar.api.utils import remove_private_keys, PillarJSONEncoder
|
||||
dumps = functools.partial(json.dumps, cls=PillarJSONEncoder)
|
||||
|
||||
project_info = self._create_user_and_project([u'subscriber', u'admin'])
|
||||
project_url = '/projects/%(_id)s' % project_info
|
||||
project_url = '/api/projects/%(_id)s' % project_info
|
||||
|
||||
resp = self.client.get(project_url)
|
||||
project = json.loads(resp.data.decode('utf-8'))
|
||||
@@ -255,7 +254,7 @@ class ProjectEditTest(AbstractProjectTest):
|
||||
# Re-fetch from database to see which fields actually made it there.
|
||||
# equal to put_project -> changed in DB
|
||||
# equal to project -> not changed in DB
|
||||
resp = self.client.get('/projects/%s' % project['_id'])
|
||||
resp = self.client.get('/api/projects/%s' % project['_id'])
|
||||
db_proj = json.loads(resp.data)
|
||||
self.assertEqual(put_project['url'], db_proj['url'])
|
||||
self.assertEqual(put_project['description'], db_proj['description'])
|
||||
@@ -269,13 +268,13 @@ class ProjectEditTest(AbstractProjectTest):
|
||||
def test_edits_by_nonowner_admin(self):
|
||||
"""Any admin should be able to edit any project."""
|
||||
|
||||
from application.utils import remove_private_keys, PillarJSONEncoder
|
||||
from pillar.api.utils import remove_private_keys, PillarJSONEncoder
|
||||
dumps = functools.partial(json.dumps, cls=PillarJSONEncoder)
|
||||
|
||||
# Create test project.
|
||||
project = self._create_user_and_project([u'subscriber'])
|
||||
project_id = project['_id']
|
||||
project_url = '/projects/%s' % project_id
|
||||
project_url = '/api/projects/%s' % project_id
|
||||
|
||||
# Create test user.
|
||||
self._create_user_with_token(['admin'], 'admin-token', user_id='cafef00dbeef')
|
||||
@@ -294,13 +293,13 @@ class ProjectEditTest(AbstractProjectTest):
|
||||
def test_edits_by_nonowner_subscriber(self):
|
||||
"""A subscriber should only be able to edit their own projects."""
|
||||
|
||||
from application.utils import remove_private_keys, PillarJSONEncoder
|
||||
from pillar.api.utils import remove_private_keys, PillarJSONEncoder
|
||||
dumps = functools.partial(json.dumps, cls=PillarJSONEncoder)
|
||||
|
||||
# Create test project.
|
||||
project = self._create_user_and_project([u'subscriber'])
|
||||
project_id = project['_id']
|
||||
project_url = '/projects/%s' % project_id
|
||||
project_url = '/api/projects/%s' % project_id
|
||||
|
||||
# Create test user.
|
||||
my_user_id = 'cafef00dbeefcafef00dbeef'
|
||||
@@ -321,7 +320,7 @@ class ProjectEditTest(AbstractProjectTest):
|
||||
# Create public test project.
|
||||
project_info = self._create_user_and_project([u'admin'])
|
||||
project_id = project_info['_id']
|
||||
project_url = '/projects/%s' % project_id
|
||||
project_url = '/api/projects/%s' % project_id
|
||||
|
||||
# Create admin user that doesn't own the project, to check that
|
||||
# non-owner admins can delete projects too.
|
||||
@@ -347,7 +346,7 @@ class ProjectEditTest(AbstractProjectTest):
|
||||
# Also see http://python-eve.org/features.html#soft-delete
|
||||
projection = json.dumps({'name': 1, 'permissions': 1})
|
||||
where = json.dumps({'_deleted': True}) # MUST be True, 1 does not work.
|
||||
resp = self.client.get('/projects?where=%s&projection=%s' %
|
||||
resp = self.client.get('/api/projects?where=%s&projection=%s' %
|
||||
(urllib.quote(where), urllib.quote(projection)))
|
||||
self.assertEqual(200, resp.status_code, resp.data)
|
||||
|
||||
@@ -359,7 +358,7 @@ class ProjectEditTest(AbstractProjectTest):
|
||||
# Create test project.
|
||||
project_info = self._create_user_and_project([u'subscriber'])
|
||||
project_id = project_info['_id']
|
||||
project_url = '/projects/%s' % project_id
|
||||
project_url = '/api/projects/%s' % project_id
|
||||
|
||||
# Create test user.
|
||||
self._create_user_with_token(['subscriber'], 'mortal-token', user_id='cafef00dbeef')
|
||||
@@ -381,7 +380,7 @@ class ProjectNodeAccess(AbstractProjectTest):
|
||||
def setUp(self, **kwargs):
|
||||
super(ProjectNodeAccess, self).setUp(**kwargs)
|
||||
|
||||
from application.utils import PillarJSONEncoder
|
||||
from pillar.api.utils import PillarJSONEncoder
|
||||
|
||||
# Project is created by regular subscriber, so should be private.
|
||||
self.user_id = self._create_user_with_token([u'subscriber'], 'token')
|
||||
@@ -407,7 +406,7 @@ class ProjectNodeAccess(AbstractProjectTest):
|
||||
}
|
||||
|
||||
# Add a node to the project
|
||||
resp = self.client.post('/nodes',
|
||||
resp = self.client.post('/api/nodes',
|
||||
headers={'Authorization': self.make_header('token'),
|
||||
'Content-Type': 'application/json'},
|
||||
data=json.dumps(self.test_node, cls=PillarJSONEncoder),
|
||||
@@ -415,7 +414,7 @@ class ProjectNodeAccess(AbstractProjectTest):
|
||||
self.assertEqual(201, resp.status_code, (resp.status_code, resp.data))
|
||||
self.node_info = json.loads(resp.data)
|
||||
self.node_id = self.node_info['_id']
|
||||
self.node_url = '/nodes/%s' % self.node_id
|
||||
self.node_url = '/api/nodes/%s' % self.node_id
|
||||
|
||||
def test_node_access(self):
|
||||
"""Getting nodes should adhere to project access rules."""
|
||||
@@ -432,23 +431,23 @@ class ProjectNodeAccess(AbstractProjectTest):
|
||||
|
||||
def test_node_resource_access(self):
|
||||
# The owner of the project should get the node.
|
||||
resp = self.client.get('/nodes',
|
||||
resp = self.client.get('/api/nodes',
|
||||
headers={'Authorization': self.make_header('token')})
|
||||
self.assertEqual(200, resp.status_code, (resp.status_code, resp.data))
|
||||
listed_nodes = json.loads(resp.data)['_items']
|
||||
self.assertEquals(self.node_id, listed_nodes[0]['_id'])
|
||||
|
||||
# Listing all nodes should not include nodes from private projects.
|
||||
resp = self.client.get('/nodes',
|
||||
resp = self.client.get('/api/nodes',
|
||||
headers={'Authorization': self.make_header('other-token')})
|
||||
self.assertEqual(403, resp.status_code, (resp.status_code, resp.data))
|
||||
|
||||
def test_is_private_updated_by_world_permissions(self):
|
||||
"""For backward compatibility, is_private should reflect absence of world-GET"""
|
||||
|
||||
from application.utils import remove_private_keys, dumps
|
||||
from pillar.api.utils import remove_private_keys, dumps
|
||||
|
||||
project_url = '/projects/%s' % self.project_id
|
||||
project_url = '/api/projects/%s' % self.project_id
|
||||
put_project = remove_private_keys(self.project)
|
||||
|
||||
# Create admin user.
|
||||
@@ -488,10 +487,10 @@ class ProjectNodeAccess(AbstractProjectTest):
|
||||
self.assertTrue(db_proj['is_private'])
|
||||
|
||||
def test_add_remove_user(self):
|
||||
from application.modules import projects
|
||||
from application.utils import dumps
|
||||
from pillar.api.projects import utils as proj_utils
|
||||
from pillar.api.utils import dumps
|
||||
|
||||
project_mng_user_url = '/p/users'
|
||||
project_mng_user_url = '/api/p/users'
|
||||
|
||||
# Use our API to add user to group
|
||||
payload = {
|
||||
@@ -512,7 +511,7 @@ class ProjectNodeAccess(AbstractProjectTest):
|
||||
users = self.app.data.driver.db['users']
|
||||
|
||||
db_user = users.find_one(self.other_user_id)
|
||||
admin_group = projects.get_admin_group(self.project)
|
||||
admin_group = proj_utils.get_admin_group(self.project)
|
||||
|
||||
self.assertIn(admin_group['_id'], db_user['groups'])
|
||||
|
||||
@@ -539,10 +538,10 @@ class ProjectNodeAccess(AbstractProjectTest):
|
||||
regardless of permissions.
|
||||
"""
|
||||
|
||||
from application.modules import projects
|
||||
from application.utils import dumps
|
||||
from pillar.api.projects import utils as proj_utils
|
||||
from pillar.api.utils import dumps
|
||||
|
||||
project_mng_user_url = '/p/users'
|
||||
project_mng_user_url = '/api/p/users'
|
||||
|
||||
# Use our API to add user to group
|
||||
payload = {
|
||||
@@ -570,5 +569,5 @@ class ProjectNodeAccess(AbstractProjectTest):
|
||||
users = self.app.data.driver.db['users']
|
||||
|
||||
db_user = users.find_one(self.other_user_id)
|
||||
admin_group = projects.get_admin_group(self.project)
|
||||
admin_group = proj_utils.get_admin_group(self.project)
|
||||
self.assertNotIn(admin_group['_id'], db_user['groups'])
|
@@ -1,13 +1,13 @@
|
||||
"""Test badger service."""
|
||||
|
||||
from common_test_class import AbstractPillarTest, TEST_EMAIL_ADDRESS
|
||||
from pillar.tests import AbstractPillarTest, TEST_EMAIL_ADDRESS
|
||||
|
||||
|
||||
class BadgerServiceTest(AbstractPillarTest):
|
||||
def setUp(self, **kwargs):
|
||||
AbstractPillarTest.setUp(self, **kwargs)
|
||||
|
||||
from application.modules import service
|
||||
from pillar.api import service
|
||||
|
||||
with self.app.test_request_context():
|
||||
self.badger, token_doc = service.create_service_account(
|
||||
@@ -20,8 +20,8 @@ class BadgerServiceTest(AbstractPillarTest):
|
||||
self.user_email = TEST_EMAIL_ADDRESS
|
||||
|
||||
def _post(self, data):
|
||||
from application.utils import dumps
|
||||
return self.client.post('/service/badger',
|
||||
from pillar.api.utils import dumps
|
||||
return self.client.post('/api/service/badger',
|
||||
data=dumps(data),
|
||||
headers={'Authorization': self.make_header(self.badger_token),
|
||||
'Content-Type': 'application/json'})
|
@@ -1,14 +1,13 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
from bson import ObjectId
|
||||
from pillar.tests import AbstractPillarTest
|
||||
from werkzeug.exceptions import BadRequest
|
||||
|
||||
from common_test_class import AbstractPillarTest
|
||||
|
||||
|
||||
class Str2idTest(AbstractPillarTest):
|
||||
def test_happy(self):
|
||||
from application.utils import str2id
|
||||
from pillar.api.utils import str2id
|
||||
|
||||
def happy(str_id):
|
||||
self.assertEqual(ObjectId(str_id), str2id(str_id))
|
||||
@@ -18,7 +17,7 @@ class Str2idTest(AbstractPillarTest):
|
||||
happy(u'577e23ad98377323f74c368c')
|
||||
|
||||
def test_unhappy(self):
|
||||
from application.utils import str2id
|
||||
from pillar.api.utils import str2id
|
||||
|
||||
def unhappy(str_id):
|
||||
self.assertRaises(BadRequest, str2id, str_id)
|
108
tests/test_sdk.py
Normal file
108
tests/test_sdk.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""Tests for the FlaskInternal SDK."""
|
||||
|
||||
from flask import url_for
|
||||
import pillarsdk
|
||||
|
||||
from pillar.tests import AbstractPillarTest
|
||||
from pillar.sdk import FlaskInternalApi
|
||||
|
||||
|
||||
class FlaskInternalApiTest(AbstractPillarTest):
|
||||
def setUp(self, **kwargs):
|
||||
AbstractPillarTest.setUp(self, **kwargs)
|
||||
|
||||
self.project_id, self.user_id = self.create_project_with_admin()
|
||||
self.create_valid_auth_token(self.user_id, 'token')
|
||||
|
||||
self.sdk_api = FlaskInternalApi(
|
||||
endpoint='/api/',
|
||||
username=None,
|
||||
password=None,
|
||||
token='token'
|
||||
)
|
||||
|
||||
def test_create_asset(self):
|
||||
with self.app.test_request_context():
|
||||
asset = pillarsdk.Node({'description': '',
|
||||
'project': str(self.project_id),
|
||||
'node_type': 'asset',
|
||||
'user': str(self.user_id),
|
||||
'properties': {'status': 'published',
|
||||
'content_type': 'je moeder'},
|
||||
'name': 'Test asset'})
|
||||
created_ok = asset.create(api=self.sdk_api)
|
||||
self.assertTrue(created_ok)
|
||||
self.assertTrue(asset._id)
|
||||
|
||||
with self.app.test_request_context():
|
||||
# Check the asset in MongoDB
|
||||
resp = self.get(url_for('nodes|item_lookup', _id=asset._id), auth_token='token')
|
||||
db_asset = resp.json()
|
||||
self.assertEqual('Test asset', db_asset['name'])
|
||||
|
||||
return asset
|
||||
|
||||
def test_delete_asset(self):
|
||||
asset = self.test_create_asset()
|
||||
with self.app.test_request_context():
|
||||
asset.delete(api=self.sdk_api)
|
||||
|
||||
def test_upload_file_to_project(self):
|
||||
import test_api
|
||||
from os.path import join, dirname, abspath
|
||||
|
||||
file_path = join(dirname(abspath(test_api.__file__)), 'BlenderDesktopLogo.png')
|
||||
|
||||
with self.app.test_request_context():
|
||||
resp = pillarsdk.File.upload_to_project(
|
||||
self.project_id,
|
||||
'image/png',
|
||||
file_path,
|
||||
api=self.sdk_api
|
||||
)
|
||||
file_id = resp['file_id']
|
||||
self.assertTrue(file_id)
|
||||
|
||||
# Check the file in MongoDB
|
||||
with self.app.test_request_context():
|
||||
resp = self.get(url_for('files|item_lookup', _id=file_id), auth_token='token')
|
||||
file_doc = resp.json()
|
||||
self.assertEqual('BlenderDesktopLogo.png', file_doc['filename'])
|
||||
|
||||
def test_create_asset_from_file(self):
|
||||
import test_api
|
||||
from os.path import join, dirname, abspath
|
||||
|
||||
file_path = join(dirname(abspath(test_api.__file__)), 'BlenderDesktopLogo.png')
|
||||
|
||||
# Create a group node to serve as parent.
|
||||
with self.app.test_request_context():
|
||||
resp = self.post(url_for('nodes|resource'), auth_token='token',
|
||||
json={
|
||||
'name': 'Group node',
|
||||
'node_type': 'group',
|
||||
'project': self.project_id,
|
||||
'properties': {}
|
||||
},
|
||||
expected_status=201)
|
||||
parent_id = resp.json()['_id']
|
||||
|
||||
with self.app.test_request_context(), open(file_path, 'rb') as fileobj:
|
||||
resp = pillarsdk.Node.create_asset_from_file(
|
||||
unicode(self.project_id),
|
||||
unicode(parent_id),
|
||||
'image',
|
||||
file_path,
|
||||
mimetype='image/jpeg',
|
||||
always_create_new_node=False,
|
||||
fileobj=fileobj,
|
||||
api=self.sdk_api)
|
||||
|
||||
node_id = resp._id
|
||||
self.assertTrue(node_id)
|
||||
|
||||
# Check the node in MongoDB
|
||||
with self.app.test_request_context():
|
||||
resp = self.get(url_for('nodes|item_lookup', _id=node_id), auth_token='token')
|
||||
node_doc = resp.json()
|
||||
self.assertEqual('BlenderDesktopLogo.png', node_doc['name'])
|
Reference in New Issue
Block a user