diff --git a/beat/web/attestations/tests.py b/beat/web/attestations/tests.py old mode 100644 new mode 100755 index d2ea57a1ca3b421ae1d37d1a2534c0c580ab06fe..baea5e956e203a6196272fe4fbe00d06db9c90b5 --- a/beat/web/attestations/tests.py +++ b/beat/web/attestations/tests.py @@ -220,6 +220,7 @@ class AttestationsAPIBase(BaseTestCase): # Create an environment and queue environment = Environment(name='env1', version='1.0') environment.save() + environment.share() queue = Queue(name='queue1', memory_limit=1024, time_limit=60, cores_per_slot=1, max_slots_per_user=10) queue.save() diff --git a/beat/web/experiments/api.py b/beat/web/experiments/api.py old mode 100644 new mode 100755 diff --git a/beat/web/experiments/models.py b/beat/web/experiments/models.py old mode 100644 new mode 100755 index 2b7e9c398ffa3113a2fbc2ea1c5653aa47e3c1d2..392382b9f6c2efb0acbe52e1c9dc26223fbe013d --- a/beat/web/experiments/models.py +++ b/beat/web/experiments/models.py @@ -74,37 +74,52 @@ logger = logging.getLogger(__name__) #---------------------------------------------------------- -def validate_environments(experiment): +def validate_environments(experiment, user=None): """Validates the environments throughout the experiment""" - def _valid(queue, environment): + def _valid(environment): + q = Environment.objects.for_user(user, True) if user is not None else Environment.objects + + return bool(q.filter( + name=environment['name'], + version=environment['version'], + )) + + def _valid_combination(queue, environment): return bool(Queue.objects.filter(name=queue, environments__name=environment['name'], - environments__version=environment['version'])) + environments__version=environment['version'] + )) errors = [] default_q = experiment.data['globals']['queue'] default_env = experiment.data['globals']['environment'] - if not _valid(default_q, default_env): + if not _valid(default_env): + errors.append("The environment '%s (%s)' in the global experiment declaration does not exist" % (default_env['name'], default_env['version'])) + elif not _valid_combination(default_q, default_env): errors.append("The combination of queue '%s' with environment '%s (%s)' in the global experiment declaration does not exist" % (default_q, default_env['name'], default_env['version'])) for name, config in experiment.blocks.items(): q = config.get('queue', default_q) env = config.get('environment', default_env) - if not _valid(q, env): + if not _valid(env): + errors.append("The environment '%s (%s)' for block '%s' does not exist" % (env['name'], env['version'], name)) + elif not _valid_combination(q, env): errors.append("The combination of queue '%s' with environment '%s (%s)' for block '%s' does not exist" % (q, env['name'], env['version'], name)) for name, config in experiment.analyzers.items(): q = config.get('queue', default_q) env = config.get('environment', default_env) - if not _valid(q, env): + if not _valid(env): + errors.append("The environment '%s (%s)' for analyzer '%s' does not exist" % (env['name'], env['version'], name)) + elif not _valid_combination(q, env): errors.append("The combination of queue '%s' with environment '%s (%s)' for analyzer '%s' does not exist" % (q, env['name'], env['version'], name)) return errors -def validate_experiment(experiment_info, toolchain_info): +def validate_experiment(experiment_info, toolchain_info, user=None): """Makes sure the experiment can be run""" xp = beat.core.experiment.Experiment(settings.PREFIX, @@ -112,7 +127,7 @@ def validate_experiment(experiment_info, toolchain_info): if not xp.valid: return xp, xp.errors - return xp, xp.errors + validate_environments(xp) + return xp, xp.errors + validate_environments(xp, user) #---------------------------------------------------------- @@ -180,6 +195,8 @@ class ExperimentManager(ContributionManager): # Save the experiment (will run the validation) try: experiment.save() + except SyntaxError, e: + return (None, None, e.message) except Exception: import traceback return (None, None, traceback.format_exc()) @@ -387,7 +404,7 @@ class Experiment(Shareable): if content_modified: # validates the experiment - xp, errors = validate_experiment(declaration, self.toolchain.declaration) + xp, errors = validate_experiment(declaration, self.toolchain.declaration, self.author) if errors: message = "The experiment isn't valid, due to the " \ "following errors:\n * %s" @@ -607,7 +624,7 @@ class Experiment(Shareable): return (self.reports.count() == 0) and not self.has_attestation() and super(Experiment, self).deletable() def core(self): - return validate_experiment(self.declaration, self.toolchain.declaration)[0] + return validate_experiment(self.declaration, self.toolchain.declaration, self.author)[0] def job_splits(self, status=None): from ..backend.models import JobSplit diff --git a/beat/web/experiments/tests.py b/beat/web/experiments/tests.py old mode 100644 new mode 100755 index 23107adf2e7a445df9bdc3b162445cf90324822a..10408a6ab6577c5d39e761e32291f1e197429103 --- a/beat/web/experiments/tests.py +++ b/beat/web/experiments/tests.py @@ -28,6 +28,7 @@ import os import simplejson as json import shutil +import copy from datetime import datetime from django.conf import settings @@ -193,11 +194,16 @@ class ExperimentTestBase(BaseTestCase): # Create an environment and queue environment = Environment(name='env1', version='1.0') environment.save() + environment.share() + + environment2 = Environment(name='private_env', version='1.0') + environment2.save() queue = Queue(name='queue1', memory_limit=1024, time_limit=60, cores_per_slot=1, max_slots_per_user=10) queue.save() queue.environments.add(environment) + queue.environments.add(environment2) DataFormat.objects.create_dataformat( @@ -509,6 +515,171 @@ class ExperimentCreationAPI(ExperimentTestBase): self.checkResponse(response, 400, content_type='application/json') + def test_bad_request_with_unknown_global_environment_name(self): + self.client.login(username='johndoe', password='1234') + + declaration = copy.deepcopy(ExperimentTestBase.DECLARATION1) + + declaration['globals']['environment']['name'] = 'unknown' + + response = self.client.post(self.url, + json.dumps({ + 'toolchain': 'johndoe/toolchain1/1', + 'declaration': declaration, + }), content_type='application/json') + + self.checkResponse(response, 400, content_type='application/json') + + + def test_bad_request_with_unknown_global_environment_version(self): + self.client.login(username='johndoe', password='1234') + + declaration = copy.deepcopy(ExperimentTestBase.DECLARATION1) + + declaration['globals']['environment']['version'] = 'unknown' + + response = self.client.post(self.url, + json.dumps({ + 'toolchain': 'johndoe/toolchain1/1', + 'declaration': declaration, + }), content_type='application/json') + + self.checkResponse(response, 400, content_type='application/json') + + + def test_bad_request_with_unknown_algorithm_environment_name(self): + self.client.login(username='johndoe', password='1234') + + declaration = copy.deepcopy(ExperimentTestBase.DECLARATION1) + + declaration['blocks']['addition1']['environment'] = dict( + name='unknown', + version='1', + ) + + response = self.client.post(self.url, + json.dumps({ + 'toolchain': 'johndoe/toolchain1/1', + 'declaration': declaration, + }), content_type='application/json') + + self.checkResponse(response, 400, content_type='application/json') + + + def test_bad_request_with_unknown_algorithm_environment_version(self): + self.client.login(username='johndoe', password='1234') + + declaration = copy.deepcopy(ExperimentTestBase.DECLARATION1) + + declaration['blocks']['addition1']['environment'] = dict( + name='env1', + version='unknown', + ) + + response = self.client.post(self.url, + json.dumps({ + 'toolchain': 'johndoe/toolchain1/1', + 'declaration': declaration, + }), content_type='application/json') + + self.checkResponse(response, 400, content_type='application/json') + + + def test_bad_request_with_unknown_analyzer_environment_name(self): + self.client.login(username='johndoe', password='1234') + + declaration = copy.deepcopy(ExperimentTestBase.DECLARATION1) + + declaration['analyzers']['analysis']['environment'] = dict( + name='unknown', + version='1', + ) + + response = self.client.post(self.url, + json.dumps({ + 'toolchain': 'johndoe/toolchain1/1', + 'declaration': declaration, + }), content_type='application/json') + + self.checkResponse(response, 400, content_type='application/json') + + + def test_bad_request_with_unknown_analyzer_environment_version(self): + self.client.login(username='johndoe', password='1234') + + declaration = copy.deepcopy(ExperimentTestBase.DECLARATION1) + + declaration['analyzers']['analysis']['environment'] = dict( + name='env1', + version='unknown', + ) + + response = self.client.post(self.url, + json.dumps({ + 'toolchain': 'johndoe/toolchain1/1', + 'declaration': declaration, + }), content_type='application/json') + + self.checkResponse(response, 400, content_type='application/json') + + + def test_bad_request_with_unusable_global_environment(self): + self.client.login(username='johndoe', password='1234') + + declaration = copy.deepcopy(ExperimentTestBase.DECLARATION1) + + declaration['globals']['environment'] = dict( + name='private_env', + version='1.0' + ) + + response = self.client.post(self.url, + json.dumps({ + 'toolchain': 'johndoe/toolchain1/1', + 'declaration': declaration, + }), content_type='application/json') + + self.checkResponse(response, 400, content_type='application/json') + + + def test_bad_request_with_unusable_algorithm_environment(self): + self.client.login(username='johndoe', password='1234') + + declaration = copy.deepcopy(ExperimentTestBase.DECLARATION1) + + declaration['blocks']['addition1']['environment'] = dict( + name='private_env', + version='1.0', + ) + + response = self.client.post(self.url, + json.dumps({ + 'toolchain': 'johndoe/toolchain1/1', + 'declaration': declaration, + }), content_type='application/json') + + self.checkResponse(response, 400, content_type='application/json') + + + def test_bad_request_with_unusable_analyzer_environment(self): + self.client.login(username='johndoe', password='1234') + + declaration = copy.deepcopy(ExperimentTestBase.DECLARATION1) + + declaration['analyzers']['analysis']['environment'] = dict( + name='private_env', + version='1.0', + ) + + response = self.client.post(self.url, + json.dumps({ + 'toolchain': 'johndoe/toolchain1/1', + 'declaration': declaration, + }), content_type='application/json') + + self.checkResponse(response, 400, content_type='application/json') + + def test_valid_experiment(self): self.client.login(username='johndoe', password='1234') diff --git a/beat/web/reports/tests.py b/beat/web/reports/tests.py old mode 100644 new mode 100755 index e9edac72e6db5d5b86d213886616f537be9769c2..bd1fc642bb8081abd8da59ba92207bbcf6d48593 --- a/beat/web/reports/tests.py +++ b/beat/web/reports/tests.py @@ -498,6 +498,7 @@ class ReportTestCase(APITestCase): # Create an environment and queue environment = Environment(name='env1', version='1.0') environment.save() + environment.share() queue = Queue(name='queue1', memory_limit=1024, time_limit=60, cores_per_slot=1, max_slots_per_user=10) queue.save()