Merge branch 'master' into nomenclature

Conflicts:
	test/data/test.db
This commit is contained in:
Jake Moshenko 2014-11-17 17:59:59 -05:00
commit f4681f2c18
60 changed files with 1716 additions and 496 deletions

Binary file not shown.

60
test/fulldbtest.sh Executable file
View file

@ -0,0 +1,60 @@
set -e
up_mysql() {
# Run a SQL database on port 3306 inside of Docker.
docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=password -d mysql
# Sleep for 5s to get MySQL get started.
echo 'Sleeping for 10...'
sleep 10
# Add the database to mysql.
docker run --rm --link mysql:mysql mysql sh -c 'echo "create database genschema" | mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -ppassword'
}
down_mysql() {
docker kill mysql
docker rm mysql
}
up_postgres() {
# Run a SQL database on port 5432 inside of Docker.
docker run --name postgres -p 5432:5432 -d postgres
# Sleep for 5s to get SQL get started.
echo 'Sleeping for 5...'
sleep 5
# Add the database to postgres.
docker run --rm --link postgres:postgres postgres sh -c 'echo "create database genschema" | psql -h "$POSTGRES_PORT_5432_TCP_ADDR" -p "$POSTGRES_PORT_5432_TCP_PORT" -U postgres'
}
down_postgres() {
docker kill postgres
docker rm postgres
}
run_tests() {
TEST_DATABASE_URI=$1 TEST=true python -m unittest discover
}
# Test (and generate, if requested) via MySQL.
echo '> Starting MySQL'
up_mysql
echo '> Running Full Test Suite (mysql)'
set +e
run_tests "mysql+pymysql://root:password@192.168.59.103/genschema"
set -e
down_mysql
# Test via Postgres.
echo '> Starting Postgres'
up_postgres
echo '> Running Full Test Suite (postgres)'
set +e
run_tests "postgresql://postgres@192.168.59.103/genschema"
set -e
down_postgres

View file

@ -43,7 +43,7 @@ from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPe
RepositoryTeamPermissionList, RepositoryUserPermissionList)
from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserManagement,
SuperUserSendRecoveryEmail)
SuperUserSendRecoveryEmail, UsageInformation)
try:
@ -3636,6 +3636,24 @@ class TestTeamMemberInvite(ApiTestCase):
self._run_test('DELETE', 400, 'devtable', None)
class TestUsageInformation(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(UsageInformation)
def test_get_anonymous(self):
self._run_test('GET', 401, None, None)
def test_get_freshuser(self):
self._run_test('GET', 403, 'freshuser', None)
def test_get_reader(self):
self._run_test('GET', 403, 'reader', None)
def test_get_devtable(self):
self._run_test('GET', 200, 'devtable', None)
class TestSuperUserList(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)

View file

@ -43,7 +43,8 @@ from endpoints.api.organization import (OrganizationList, OrganizationMember,
from endpoints.api.repository import RepositoryList, RepositoryVisibility, Repository
from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPermission,
RepositoryTeamPermissionList, RepositoryUserPermissionList)
from endpoints.api.superuser import SuperUserLogs, SuperUserList, SuperUserManagement
from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserManagement,
UsageInformation)
try:
app.register_blueprint(api_bp, url_prefix='/api')
@ -1139,6 +1140,8 @@ class TestChangeRepoVisibility(ApiTestCase):
class TestDeleteRepository(ApiTestCase):
SIMPLE_REPO = ADMIN_ACCESS_USER + '/simple'
COMPLEX_REPO = ADMIN_ACCESS_USER + '/complex'
def test_deleterepo(self):
self.login(ADMIN_ACCESS_USER)
@ -1150,6 +1153,64 @@ class TestDeleteRepository(ApiTestCase):
params=dict(repository=self.SIMPLE_REPO),
expected_code=404)
def test_deleterepo2(self):
self.login(ADMIN_ACCESS_USER)
self.deleteResponse(Repository,
params=dict(repository=self.COMPLEX_REPO))
# Verify the repo was deleted.
self.getResponse(Repository,
params=dict(repository=self.COMPLEX_REPO),
expected_code=404)
def test_populate_and_delete_repo(self):
self.login(ADMIN_ACCESS_USER)
# Make sure the repository has come images and tags.
self.assertTrue(len(list(model.get_repository_images(ADMIN_ACCESS_USER, 'complex'))) > 0)
self.assertTrue(len(list(model.list_repository_tags(ADMIN_ACCESS_USER, 'complex'))) > 0)
# Add some data for the repository, in addition to is already existing images and tags.
repository = model.get_repository(ADMIN_ACCESS_USER, 'complex')
# Create some access tokens.
access_token = model.create_access_token(repository, 'read')
model.create_access_token(repository, 'write')
delegate_token = model.create_delegate_token(ADMIN_ACCESS_USER, 'complex', 'sometoken', 'read')
model.create_delegate_token(ADMIN_ACCESS_USER, 'complex', 'sometoken', 'write')
# Create some repository builds.
model.create_repository_build(repository, access_token, {}, 'someid', 'foobar')
model.create_repository_build(repository, delegate_token, {}, 'someid2', 'foobar2')
# Create some notifications.
model.create_repo_notification(repository, 'repo_push', 'hipchat', {})
model.create_repo_notification(repository, 'build_queued', 'slack', {})
# Create some logs.
model.log_action('push_repo', ADMIN_ACCESS_USER, repository=repository)
model.log_action('push_repo', ADMIN_ACCESS_USER, repository=repository)
# Create some build triggers.
user = model.get_user(ADMIN_ACCESS_USER)
model.create_build_trigger(repository, 'github', 'sometoken', user)
model.create_build_trigger(repository, 'github', 'anothertoken', user)
# Create some email authorizations.
model.create_email_authorization_for_repo(ADMIN_ACCESS_USER, 'complex', 'a@b.com')
model.create_email_authorization_for_repo(ADMIN_ACCESS_USER, 'complex', 'b@c.com')
# Delete the repository.
self.deleteResponse(Repository,
params=dict(repository=self.COMPLEX_REPO))
# Verify the repo was deleted.
self.getResponse(Repository,
params=dict(repository=self.COMPLEX_REPO),
expected_code=404)
class TestGetRepository(ApiTestCase):
PUBLIC_REPO = PUBLIC_USER + '/publicrepo'
@ -1267,7 +1328,9 @@ class TestRepoBuilds(ApiTestCase):
status_json = self.getJsonResponse(RepositoryBuildStatus,
params=dict(repository=ADMIN_ACCESS_USER + '/building', build_uuid=build['id']))
self.assertEquals(status_json, build)
self.assertEquals(status_json['id'], build['id'])
self.assertEquals(status_json['resource_key'], build['resource_key'])
self.assertEquals(status_json['trigger'], build['trigger'])
class TestRequestRepoBuild(ApiTestCase):
def test_requestrepobuild(self):
@ -1779,7 +1842,7 @@ class TestOrgSubscription(ApiTestCase):
class TestUserRobots(ApiTestCase):
def getRobotNames(self):
return [r['name'] for r in self.getJsonResponse(UserRobotList)['robots']]
return [r['name'] for r in self.getJsonResponse(UserRobotList)['robots']]
def test_robots(self):
self.login(NO_ACCESS_USER)
@ -1833,6 +1896,65 @@ class TestOrgRobots(ApiTestCase):
return [r['name'] for r in self.getJsonResponse(OrgRobotList,
params=dict(orgname=ORGANIZATION))['robots']]
def test_delete_robot_after_use(self):
self.login(ADMIN_ACCESS_USER)
# Create the robot.
self.putJsonResponse(OrgRobot,
params=dict(orgname=ORGANIZATION, robot_shortname='bender'),
expected_code=201)
# Add the robot to a team.
membername = ORGANIZATION + '+bender'
self.putJsonResponse(TeamMember,
params=dict(orgname=ORGANIZATION, teamname='readers',
membername=membername))
# Add a repository permission.
self.putJsonResponse(RepositoryUserPermission,
params=dict(repository=ORGANIZATION + '/' + ORG_REPO, username=membername),
data=dict(role='read'))
# Add a permission prototype with the robot as the activating user.
self.postJsonResponse(PermissionPrototypeList,
params=dict(orgname=ORGANIZATION),
data=dict(role='read',
activating_user={'name': membername},
delegate={'kind': 'user',
'name': membername}))
# Add a permission prototype with the robot as the delegating user.
self.postJsonResponse(PermissionPrototypeList,
params=dict(orgname=ORGANIZATION),
data=dict(role='read',
delegate={'kind': 'user',
'name': membername}))
# Add a build trigger with the robot as the pull robot.
database.BuildTriggerService.create(name='fakeservice')
# Add a new fake trigger.
repo = model.get_repository(ORGANIZATION, ORG_REPO)
user = model.get_user(ADMIN_ACCESS_USER)
pull_robot = model.get_user(membername)
model.create_build_trigger(repo, 'fakeservice', 'sometoken', user, pull_robot=pull_robot)
# Delete the robot and verify it works.
self.deleteResponse(OrgRobot,
params=dict(orgname=ORGANIZATION, robot_shortname='bender'))
# All the above records should now be deleted, along with the robot. We verify a few of the
# critical ones below.
# Check the team.
team = model.get_organization_team(ORGANIZATION, 'readers')
members = [member.username for member in model.get_organization_team_members(team.id)]
self.assertFalse(membername in members)
# Check the robot itself.
self.assertIsNone(model.get_user(membername))
def test_robots(self):
self.login(ADMIN_ACCESS_USER)
@ -1931,7 +2053,14 @@ class TestOrganizationApplications(ApiTestCase):
json = self.getJsonResponse(OrganizationApplications, params=dict(orgname=ORGANIZATION))
self.assertEquals(2, len(json['applications']))
self.assertEquals(FAKE_APPLICATION_CLIENT_ID, json['applications'][0]['client_id'])
found = False
for application in json['applications']:
if application['client_id'] == FAKE_APPLICATION_CLIENT_ID:
found = True
break
self.assertTrue(found)
# Add a new application.
json = self.postJsonResponse(OrganizationApplications, params=dict(orgname=ORGANIZATION),
@ -1943,7 +2072,6 @@ class TestOrganizationApplications(ApiTestCase):
# Retrieve the apps list again
list_json = self.getJsonResponse(OrganizationApplications, params=dict(orgname=ORGANIZATION))
self.assertEquals(3, len(list_json['applications']))
self.assertEquals(json, list_json['applications'][2])
class TestOrganizationApplicationResource(ApiTestCase):
@ -2358,6 +2486,15 @@ class TestSuperUserList(ApiTestCase):
assert len(json['users']) > 0
class TestUsageInformation(ApiTestCase):
def test_get_usage(self):
self.login(ADMIN_ACCESS_USER)
json = self.getJsonResponse(UsageInformation)
assert 'usage' in json
assert 'allowed' in json
class TestSuperUserManagement(ApiTestCase):
def test_get_user(self):
self.login(ADMIN_ACCESS_USER)

View file

@ -34,6 +34,17 @@ class TestGarbageColection(unittest.TestCase):
for i in range(0, 2):
model.find_or_create_derived_storage(image.storage, 'squash', preferred)
# Add some additional placements to the image.
for location_name in ['local_eu']:
location = database.ImageStorageLocation.get(name=location_name)
try:
database.ImageStoragePlacement.get(location=location, storage=image.storage)
except:
continue
database.ImageStoragePlacement.create(location=location, storage=image.storage)
return image.storage
def createRepository(self, namespace=ADMIN_ACCESS_USER, name=REPO, **kwargs):

View file

@ -3,6 +3,7 @@ import tarfile
from StringIO import StringIO
from util.streamlayerformat import StreamLayerMerger, AUFS_WHITEOUT
from util.tarlayerformat import TarLayerReadException
class TestStreamLayerMerger(unittest.TestCase):
def create_layer(self, **kwargs):
@ -30,6 +31,9 @@ class TestStreamLayerMerger(unittest.TestCase):
return output.getvalue()
def create_empty_layer(self):
return ''
def squash_layers(self, layers):
def get_layers():
return [StringIO(layer) for layer in layers]
@ -337,5 +341,59 @@ class TestStreamLayerMerger(unittest.TestCase):
self.assertHasFile(squashed, 'foobar/baz/some_file', 'foo')
self.assertDoesNotHaveFile(squashed, 'foo/another_file')
def test_delete_root_directory(self):
third_layer = self.create_layer(
foo = 'build/first_file',
bar = 'build/second_file')
second_layer = self.create_layer(
_ = 'build')
squashed = self.squash_layers([second_layer, third_layer])
self.assertDoesNotHaveFile(squashed, 'build/first_file')
self.assertDoesNotHaveFile(squashed, 'build/second_file')
def test_tar_empty_layer(self):
third_layer = self.create_layer(
foo = 'build/first_file',
bar = 'build/second_file')
empty_layer = self.create_layer()
squashed = self.squash_layers([empty_layer, third_layer])
self.assertHasFile(squashed, 'build/first_file', 'foo')
self.assertHasFile(squashed, 'build/second_file', 'bar')
def test_data_empty_layer(self):
third_layer = self.create_layer(
foo = 'build/first_file',
bar = 'build/second_file')
empty_layer = self.create_empty_layer()
squashed = self.squash_layers([empty_layer, third_layer])
self.assertHasFile(squashed, 'build/first_file', 'foo')
self.assertHasFile(squashed, 'build/second_file', 'bar')
def test_broken_layer(self):
third_layer = self.create_layer(
foo = 'build/first_file',
bar = 'build/second_file')
broken_layer = 'not valid data'
try:
self.squash_layers([broken_layer, third_layer])
self.fail('Expected exception')
except TarLayerReadException as ex:
self.assertEquals('Could not read layer', ex.message)
if __name__ == '__main__':
unittest.main()

View file

@ -1,3 +1,5 @@
import os
from datetime import datetime, timedelta
from config import DefaultConfig
@ -14,8 +16,11 @@ class FakeTransaction(object):
class TestConfig(DefaultConfig):
TESTING = True
DB_URI = 'sqlite:///:memory:'
DB_CONNECTION_ARGS = {}
DB_URI = os.environ.get('TEST_DATABASE_URI', 'sqlite:///:memory:')
DB_CONNECTION_ARGS = {
'threadlocals': True,
'autorollback': True
}
@staticmethod
def create_transaction(db):
@ -23,7 +28,7 @@ class TestConfig(DefaultConfig):
DB_TRANSACTION_FACTORY = create_transaction
DISTRIBUTED_STORAGE_CONFIG = {'local_us': ['FakeStorage', {}]}
DISTRIBUTED_STORAGE_CONFIG = {'local_us': ['FakeStorage', {}], 'local_eu': ['FakeStorage', {}]}
DISTRIBUTED_STORAGE_PREFERENCE = ['local_us']
BUILDLOGS_MODULE_AND_CLASS = ('test.testlogs', 'testlogs.TestBuildLogs')