class TarDownloadTestCase(TestCase): def setUp(self): # create user self.testuser = User(username="******") self.testuser.save() # create test experiment self.exp = Experiment( title="tar download test" * 15, created_by=self.testuser, public_access=Experiment.PUBLIC_ACCESS_FULL ) self.exp.save() # create test dataset self.ds = self.exp.datasets.create(description="testing tar download dataset") datafile_content = "\n".join(["some data %d" % i for i in range(1000)]) filesize = len(datafile_content) md5sum = hashlib.md5(datafile_content).hexdigest() # create test datafiles and datafile objects self.dfs = [] for i in range(20): df = self.ds.datafile_set.create( filename="testfile%d.txt" % i, mimetype="text/plain", size=filesize, md5sum=md5sum, directory="/".join(["testdir%d" % i for i in range(i, i + 4)]), ) df.file_object = StringIO(datafile_content) df.refresh_from_db() self.dfs.append(df) # mock client self.client = Client() def tearDown(self): # delete created objects and files [ds.delete() for ds in self.exp.datasets.all()] self.exp.delete() def test_tar_experiment_download(self): self.assertTrue(all(df.verified for df in self.dfs)) response = self.client.get( reverse("tardis.tardis_portal.download.streaming_download_experiment", args=(self.exp.id, "tar")) ) with NamedTemporaryFile("w") as tarfile: for c in response.streaming_content: tarfile.write(c) tarfile.flush() self.assertEqual(int(response["Content-Length"]), os.stat(tarfile.name).st_size) tf = TarFile(tarfile.name) for df in self.dfs: full_path = os.path.join( self.exp.title.replace(" ", "_"), self.ds.description, df.directory, df.filename ) tf.extract(full_path, "/tmp") self.assertEqual(os.stat(os.path.join("/tmp", full_path)).st_size, int(df.size))
class ViewTemplateContextsTest(TestCase): def setUp(self): """ setting up essential objects, copied from tests above """ user = '******' pwd = 'secret' email = '' self.user = User.objects.create_user(user, email, pwd) self.userProfile = self.user.userprofile self.exp = Experiment(title='test exp1', institution_name='monash', created_by=self.user) self.exp.save() self.acl = ObjectACL( pluginId=django_user, entityId=str(self.user.id), content_object=self.exp, canRead=True, isOwner=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) self.acl.save() self.dataset = Dataset(description='dataset description...') self.dataset.save() self.dataset.experiments.add(self.exp) self.dataset.save() self.datafile = DataFile(dataset=self.dataset, size=42, filename="foo", md5sum="junk") self.datafile.save() def tearDown(self): self.user.delete() self.exp.delete() self.dataset.delete() self.datafile.delete() self.acl.delete() def testExperimentView(self): """ test some template context parameters for an experiment view """ from tardis.tardis_portal.views import ExperimentView from django.http import HttpRequest import sys # Default behavior views_module = flexmock(sys.modules['tardis.tardis_portal.views']) request = HttpRequest() request.method = 'GET' request.user = self.user request.groups = [] context = { 'organization': ['test', 'test2'], 'default_organization': 'test', 'default_format': 'tar', 'protocol': [['tgz', '/download/experiment/1/tgz/'], ['tar', '/download/experiment/1/tar/']] } views_module.should_call('render_response_index'). \ with_args(_AnyMatcher(), "tardis_portal/view_experiment.html", _ContextMatcher(context)) view_fn = ExperimentView.as_view() response = view_fn(request, experiment_id=self.exp.id) self.assertEqual(response.status_code, 200) # Behavior with USER_AGENT_SENSING enabled and a request.user_agent saved_setting = getattr(settings, "USER_AGENT_SENSING", None) try: setattr(settings, "USER_AGENT_SENSING", True) request = HttpRequest() request.method = 'GET' request.user = self.user request.groups = [] mock_agent = _MiniMock(os=_MiniMock(family="Macintosh")) setattr(request, 'user_agent', mock_agent) context = { 'organization': ['classic', 'test', 'test2'], 'default_organization': 'classic', 'default_format': 'tar', 'protocol': [['tar', '/download/experiment/1/tar/']] } views_module.should_call('render_response_index'). \ with_args(_AnyMatcher(), "tardis_portal/view_experiment.html", _ContextMatcher(context)) view_fn = ExperimentView.as_view() response = view_fn(request, experiment_id=self.exp.id) self.assertEqual(response.status_code, 200) finally: if saved_setting is not None: setattr(settings, "USER_AGENT_SENSING", saved_setting) else: delattr(settings, "USER_AGENT_SENSING") def testDatasetView(self): """ test some context parameters for a dataset view """ from tardis.tardis_portal.views import DatasetView from django.http import HttpRequest import sys views_module = flexmock(sys.modules['tardis.tardis_portal.views']) request = HttpRequest() request.method = 'GET' request.user = self.user request.groups = [] context = {'default_organization': 'test', 'default_format': 'tar'} views_module.should_call('render_response_index'). \ with_args(_AnyMatcher(), "tardis_portal/view_dataset.html", _ContextMatcher(context)) view_fn = DatasetView.as_view() response = view_fn(request, dataset_id=self.dataset.id) self.assertEqual(response.status_code, 200) # Behavior with USER_AGENT_SENSING enabled and a request.user_agent saved_setting = getattr(settings, "USER_AGENT_SENSING", None) try: setattr(settings, "USER_AGENT_SENSING", True) request = HttpRequest() request.method = 'GET' request.user = self.user request.groups = [] mock_agent = _MiniMock(os=_MiniMock(family="Macintosh")) setattr(request, 'user_agent', mock_agent) context = { 'default_organization': 'classic', 'default_format': 'tar' } views_module.should_call('render_response_index'). \ with_args(_AnyMatcher(), "tardis_portal/view_dataset.html", _ContextMatcher(context)) view_fn = DatasetView.as_view() response = view_fn(request, dataset_id=self.dataset.id) self.assertEqual(response.status_code, 200) finally: if saved_setting is not None: setattr(settings, "USER_AGENT_SENSING", saved_setting) else: delattr(settings, "USER_AGENT_SENSING")
class ContextualViewTest(TestCase): def setUp(self): """ setting up essential objects, copied from tests above """ user = '******' pwd = 'secret' email = '' self.user = User.objects.create_user(user, email, pwd) self.userProfile = self.user.userprofile self.exp = Experiment(title='test exp1', institution_name='monash', created_by=self.user) self.exp.save() self.acl = ObjectACL( pluginId=django_user, entityId=str(self.user.id), content_object=self.exp, canRead=True, isOwner=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) self.acl.save() self.dataset = Dataset(description='dataset description...') self.dataset.save() self.dataset.experiments.add(self.exp) self.dataset.save() self.datafile = DataFile(dataset=self.dataset, size=42, filename="foo", md5sum="junk") self.datafile.save() self.testschema = Schema(namespace="http://test.com/test/schema", name="Test View", type=Schema.DATAFILE, hidden=True) self.testschema.save() self.dfps = DatafileParameterSet(datafile=self.datafile, schema=self.testschema) self.dfps.save() def tearDown(self): self.user.delete() self.exp.delete() self.dataset.delete() self.datafile.delete() self.testschema.delete() self.dfps.delete() self.acl.delete() def testDetailsDisplay(self): """ test display of view for an existing schema and no display for an undefined one. """ from tardis.tardis_portal.views import display_datafile_details request = flexmock(user=self.user, groups=[("testgroup", flexmock())]) with self.settings(DATAFILE_VIEWS=[( "http://test.com/test/schema", "/test/url"), ("http://does.not.exist", "/false/url")]): response = display_datafile_details(request, datafile_id=self.datafile.id) self.assertEqual(response.status_code, 200) self.assertTrue("/ajax/parameters/" in response.content) self.assertTrue("/test/url" in response.content) self.assertFalse("/false/url" in response.content)
class DownloadTestCase(TestCase): def setUp(self): # create a test user self.user = User.objects.create_user(username='******', email='', password='******') # create a public experiment self.experiment1 = Experiment( title='Experiment 1', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_FULL) self.experiment1.save() # create a non-public experiment self.experiment2 = Experiment( title='Experiment 2', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_NONE) self.experiment2.save() # dataset1 belongs to experiment1 self.dataset1 = Dataset(description='dangerous;name') self.dataset1.save() self.dataset1.experiments.add(self.experiment1) self.dataset1.save() # dataset2 belongs to experiment2 self.dataset2 = Dataset(description='terrible\nname') self.dataset2.save() self.dataset2.experiments.add(self.experiment2) self.dataset2.save() # absolute path first filename1 = 'testfile.txt' filename2 = 'testfile.tiff' self.dest1 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment1.id, self.dataset1.id))) self.dest2 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment2.id, self.dataset2.id))) if not exists(self.dest1): makedirs(self.dest1) if not exists(self.dest2): makedirs(self.dest2) testfile1 = abspath(join(self.dest1, filename1)) f = open(testfile1, 'w') f.write("Hello World!\n") f.close() testfile2 = abspath(join(self.dest2, filename2)) _generate_test_image(testfile2) self.datafile1 = self._build_datafile(testfile1, filename1, self.dataset1) self.datafile2 = self._build_datafile(testfile2, filename2, self.dataset2) def _build_datafile(self, testfile, filename, dataset, checksum=None, size=None, mimetype=''): filesize, sha512sum = get_size_and_sha512sum(testfile) datafile = DataFile(dataset=dataset, filename=filename, mimetype=mimetype, size=size if size is not None else filesize, sha512sum=(checksum if checksum else sha512sum)) datafile.save() dfo = DataFileObject( datafile=datafile, storage_box=datafile.get_default_storage_box()) dfo.save() with open(testfile, 'r') as sourcefile: dfo.file_object = sourcefile return DataFile.objects.get(pk=datafile.pk) def tearDown(self): self.user.delete() self.experiment1.delete() self.experiment2.delete() rmtree(self.dest1) rmtree(self.dest2) def testView(self): client = Client() # check view of file1 response = client.get('/datafile/view/%i/' % self.datafile1.id) self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % self.datafile1.filename) self.assertEqual(response.status_code, 200) response_content = "" for c in response.streaming_content: response_content += c self.assertEqual(response_content, 'Hello World!\n') # check view of file2 response = client.get('/datafile/view/%i/' % self.datafile2.id) # Should be forbidden self.assertEqual(response.status_code, 403) self.experiment2.public_access = Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() # check view of file2 again response = client.get('/datafile/view/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 200) # The following behaviour relies on ImageMagick if IMAGEMAGICK_AVAILABLE: # file2 should have a ".png" filename self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % (self.datafile2.filename+'.png')) # file2 should be a PNG self.assertEqual(response['Content-Type'], 'image/png') png_signature = "\x89PNG\r\n\x1a\n" self.assertEqual(response.content[0:8], png_signature) else: # file2 should have a ".tiff" filename self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % (self.datafile2.filename)) # file2 should be a TIFF self.assertEqual(response['Content-Type'], 'image/tiff') tiff_signature = "II\x2a\x00" self.assertEqual(response.content[0:4], tiff_signature) def _check_tar_file(self, content, rootdir, datafiles, simpleNames=False, noTxt=False): with NamedTemporaryFile('w') as tempfile: for c in content: tempfile.write(c) tempfile.flush() if getsize(tempfile.name) > 0: expect(is_tarfile(tempfile.name)).to_be_truthy() try: tf = TarFile(tempfile.name, 'r') self._check_names(datafiles, tf.getnames(), rootdir, simpleNames, noTxt) finally: tf.close() else: self._check_names(datafiles, [], rootdir, simpleNames, noTxt) def _check_zip_file(self, content, rootdir, datafiles, simpleNames=False, noTxt=False): with NamedTemporaryFile('w') as tempfile: for c in content: tempfile.write(c) tempfile.flush() # It should be a zip file expect(is_zipfile(tempfile.name)).to_be_truthy() try: zf = ZipFile(tempfile.name, 'r') self._check_names(datafiles, zf.namelist(), rootdir, simpleNames, noTxt) finally: zf.close() def _check_names(self, datafiles, names, rootdir, simpleNames, noTxt): # SimpleNames says if we expect basenames or pathnames # NoTxt says if we expect '.txt' files to be filtered out for name in names: self.assertNotRegexpMatches(name, '\n|;') expect(len(names)).to_equal(len(datafiles)) def testDownload(self): client = Client() # check download for experiment1 as tar response = client.get('/download/experiment/%i/tar/' % self.experiment1.id) if settings.EXP_SPACES_TO_UNDERSCORES: exp1_title = self.experiment1.title.replace(' ', '_') else: exp1_title = self.experiment1.title exp1_title = quote(exp1_title, safe=settings.SAFE_FILESYSTEM_CHARACTERS) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s-complete.tar"' % exp1_title) self.assertEqual(response.status_code, 200) self._check_tar_file( response.streaming_content, exp1_title, reduce(lambda x, y: x + y, [ds.datafile_set.all() for ds in self.experiment1.datasets.all()])) # check download of file1 response = client.get('/download/datafile/%i/' % self.datafile1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s"' % self.datafile1.filename) self.assertEqual(response.status_code, 200) response_content = "" for c in response.streaming_content: response_content += c self.assertEqual(response_content, 'Hello World!\n') # requesting file2 should be forbidden... response = client.get('/download/datafile/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 403) # check dataset1 download as tar response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': [], 'comptype': 'tar'}) self.assertEqual(response.status_code, 200) self._check_tar_file(response.streaming_content, 'Experiment 1-selection', self.dataset1.datafile_set.all()) # check dataset2 download response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [self.dataset2.id], 'datafile': []}) self.assertEqual(response.status_code, 403) # check datafile1 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [], 'datafile': [self.datafile1.id]}) self.assertEqual(response.status_code, 200) self._check_tar_file(response.streaming_content, 'Experiment 1-selection', [self.datafile1]) # check datafile2 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [], 'datafile': [self.datafile2.id]}) self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to "metadata only" self.experiment2.public_access = Experiment.PUBLIC_ACCESS_METADATA self.experiment2.save() response = client.get('/download/datafile/%i/' % self.datafile2.id) # Metadata-only means "no file access"! self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to public self.experiment2.public_access = Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() response = client.get('/download/datafile/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 200) # This should be a TIFF (which often starts with "II\x2a\x00") self.assertEqual(response['Content-Type'], 'image/tiff') response_content = "" for c in response.streaming_content: response_content += c self.assertEqual(response_content[0:4], "II\x2a\x00") # check experiment tar download with alternative organization response = client.get('/download/experiment/%i/tar/' % self.experiment1.id) self.assertEqual(response.status_code, 200) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s-complete.tar"' % exp1_title) self._check_tar_file( response.streaming_content, str(self.experiment1.id), reduce(lambda x, y: x + y, [ds.datafile_set.all() for ds in self.experiment1.datasets.all()]), simpleNames=True) # check experiment1 download with '.txt' filtered out (none left) response = client.get('/download/experiment/%i/tar/' % self.experiment1.id) self.assertEqual(response.status_code, 200) # check experiment2 download with '.txt' filtered out if settings.EXP_SPACES_TO_UNDERSCORES: exp2_title = self.experiment2.title.replace(' ', '_') else: exp2_title = self.experiment2.title exp2_title = quote(exp2_title, safe=settings.SAFE_FILESYSTEM_CHARACTERS) response = client.get('/download/experiment/%i/tar/' % self.experiment2.id) self.assertEqual(response.status_code, 200) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s-complete.tar"' % exp2_title) self._check_tar_file( response.streaming_content, str(self.experiment2.id), reduce(lambda x, y: x + y, [ds.datafile_set.all() for ds in self.experiment2.datasets.all()]), simpleNames=True, noTxt=True) def testDatasetFile(self): # check registered text file for physical file meta information df = DataFile.objects.get(pk=self.datafile1.id) # skipping test # noqa # pylint: disable=W0101 try: from magic import Magic self.assertEqual(df.mimetype, 'text/plain; charset=us-ascii') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(df.size, 13) self.assertEqual(df.md5sum, '8ddd8be4b179a529afa5f2ffae4b9858') # Now check we can calculate checksums and infer the mime type # for a JPG file. filename = 'tardis/tardis_portal/tests/test_data/ands-logo-hi-res.jpg' dataset = Dataset.objects.get(pk=self.dataset1.id) pdf1 = self._build_datafile(filename, basename(filename), dataset) self.assertEqual(pdf1.file_objects.get().verify(), True) pdf1 = DataFile.objects.get(pk=pdf1.pk) try: from magic import Magic # noqa self.assertEqual(pdf1.mimetype, 'image/jpeg') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(pdf1.size, 14232) self.assertEqual(pdf1.md5sum, 'c450d5126ffe3d14643815204daf1bfb') # Now check that we can override the physical file meta information # We are setting size/checksums that don't match the actual file, so # the pdf2 = self._build_datafile(filename, filename, dataset, checksum=('cf83e1357eefb8bdf1542850d66d800' '7d620e4050b5715dc83f4a921d36ce9' 'ce47d0d13c5d85f2b0ff8318d2877ee' 'c2f63b931bd47417a81a538327af927' 'da3e'), size=0, mimetype=('application/vnd.openxmlformats-' 'officedocument.presentationml.' 'presentation')) self.assertEqual(pdf2.size, 0) self.assertEqual(pdf2.md5sum, '') self.assertEqual(pdf2.file_objects.get().verified, False) pdf2 = DataFile.objects.get(pk=pdf2.pk) try: from magic import Magic # noqa self.assertEqual(pdf2.mimetype, ('application/vnd.openxmlformats-' 'officedocument.presentationml.' 'presentation')) except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(pdf2.size, 0) self.assertEqual(pdf2.md5sum, '') pdf2.mimetype = '' pdf2.save() pdf2.file_objects.get().save() pdf2 = DataFile.objects.get(pk=pdf2.pk) try: from magic import Magic # noqa self.assertEqual(pdf2.mimetype, 'application/pdf') except: # XXX Test disabled because lib magic can't be loaded pass
class ParameterSetManagerTestCase(TestCase): def setUp(self): from django.contrib.auth.models import User from tempfile import mkdtemp user = '******' pwd = 'secret' email = '' self.user = User.objects.create_user(user, email, pwd) self.test_dir = mkdtemp() self.exp = Experiment(title='test exp1', institution_name='monash', created_by=self.user) self.exp.save() self.dataset = Dataset(description="dataset description...") self.dataset.save() self.dataset.experiments.add(self.exp) self.dataset.save() self.datafile = DataFile(dataset=self.dataset, filename="testfile.txt", size="42", md5sum='bogus') self.datafile.save() self.dfo = DataFileObject( datafile=self.datafile, storage_box=self.datafile.get_default_storage_box(), uri="1/testfile.txt") self.dfo.save() self.schema = Schema( namespace="http://localhost/psmtest/df/", name="Parameter Set Manager", type=3) self.schema.save() self.parametername1 = ParameterName( schema=self.schema, name="parameter1", full_name="Parameter 1") self.parametername1.save() self.parametername2 = ParameterName( schema=self.schema, name="parameter2", full_name="Parameter 2", data_type=ParameterName.NUMERIC) self.parametername2.save() self.parametername3 = ParameterName( schema=self.schema, name="parameter3", full_name="Parameter 3", data_type=ParameterName.DATETIME) self.parametername3.save() self.datafileparameterset = DatafileParameterSet( schema=self.schema, datafile=self.datafile) self.datafileparameterset.save() self.datafileparameter1 = DatafileParameter( parameterset=self.datafileparameterset, name=self.parametername1, string_value="test1") self.datafileparameter1.save() self.datafileparameter2 = DatafileParameter( parameterset=self.datafileparameterset, name=self.parametername2, numerical_value=2) self.datafileparameter2.save() # Create a ParameterName and Parameter of type LINK to an experiment self.parametername_exp_link = ParameterName( schema=self.schema, name="exp_link", full_name="This parameter is a experiment LINK", data_type=ParameterName.LINK) self.parametername_exp_link.save() self.exp_link_param = DatafileParameter( parameterset=self.datafileparameterset, name=self.parametername_exp_link) exp_url = self.exp.get_absolute_url() # /experiment/view/1/ self.exp_link_param.set_value(exp_url) self.exp_link_param.save() # Create a ParameterName and Parameter of type LINK to a dataset self.parametername_dataset_link = ParameterName( schema=self.schema, name="dataset_link", full_name="This parameter is a dataset LINK", data_type=ParameterName.LINK) self.parametername_dataset_link.save() self.dataset_link_param = DatafileParameter( parameterset=self.datafileparameterset, name=self.parametername_dataset_link) dataset_url = self.dataset.get_absolute_url() # /dataset/1/ self.dataset_link_param.set_value(dataset_url) self.dataset_link_param.save() # Create a ParameterName type LINK to an unresolvable (non-URL) # free-text value self.parametername_unresolvable_link = ParameterName( schema=self.schema, name="freetext_link", full_name="This parameter is a non-URL LINK", data_type=ParameterName.LINK) self.parametername_unresolvable_link.save() def tearDown(self): self.exp.delete() self.user.delete() self.parametername1.delete() self.parametername2.delete() self.parametername3.delete() self.parametername_exp_link.delete() self.parametername_dataset_link.delete() self.parametername_unresolvable_link.delete() self.schema.delete() def test_existing_parameterset(self): psm = ParameterSetManager(parameterset=self.datafileparameterset) self.assertTrue(psm.get_schema().namespace == "http://localhost/psmtest/df/") self.assertTrue(psm.get_param("parameter1").string_value == "test1") self.assertTrue(psm.get_param("parameter2", True) == 2) def test_new_parameterset(self): psm = ParameterSetManager(parentObject=self.datafile, schema="http://localhost/psmtest/df2/") self.assertTrue(psm.get_schema().namespace == "http://localhost/psmtest/df2/") psm.set_param("newparam1", "test3", "New Parameter 1") self.assertTrue(psm.get_param("newparam1").string_value == "test3") self.assertTrue(psm.get_param("newparam1").name.full_name == "New Parameter 1") psm.new_param("newparam1", "test4") self.assertTrue(len(psm.get_params("newparam1", True)) == 2) psm.set_param_list("newparam2", ("a", "b", "c", "d")) self.assertTrue(len(psm.get_params("newparam2")) == 4) psm.set_params_from_dict( {"newparam2": "test5", "newparam3": 3}) self.assertTrue(psm.get_param("newparam2", True) == "test5") # the newparam3 gets created and '3' is set to a string_value # since once cannot assume that an initial numeric value # will imply continuing numeric type for this new param self.assertTrue(psm.get_param("newparam3").string_value == '3') psm.delete_params("newparam1") self.assertTrue(len(psm.get_params("newparam1", True)) == 0) def test_link_parameter_type(self): """ Test that Parameter.link_gfk (GenericForeignKey) is correctly assigned after using Parameter.set_value(some_url) for a LINK Parameter. """ psm = ParameterSetManager(parameterset=self.datafileparameterset) # Check link to experiment exp_url = self.exp.get_absolute_url() # /experiment/view/1/ self.assertTrue(psm.get_param("exp_link").string_value == exp_url) self.assertTrue(psm.get_param("exp_link").link_id == self.exp.id) exp_ct = ContentType.objects.get(model__iexact="experiment") self.assertTrue(psm.get_param("exp_link").link_ct == exp_ct) self.assertTrue(psm.get_param("exp_link").link_gfk == self.exp) # Check link to dataset dataset_url = self.dataset.get_absolute_url() # /dataset/1/ self.assertTrue(psm.get_param("dataset_link").string_value == dataset_url) self.assertTrue(psm.get_param("dataset_link").link_id == self.dataset.id) dataset_ct = ContentType.objects.get(model__iexact="dataset") self.assertTrue(psm.get_param("dataset_link").link_ct == dataset_ct) self.assertTrue(psm.get_param("dataset_link").link_gfk == self.dataset) def test_link_parameter_type_extra(self): # make a second ParameterSet for testing some variations # in URL values self.datafileparameterset2 = DatafileParameterSet( schema=self.schema, datafile=self.datafile) self.datafileparameterset2.save() psm = ParameterSetManager(parameterset=self.datafileparameterset2) self.dataset_link_param2 = DatafileParameter( parameterset=self.datafileparameterset2, name=self.parametername_dataset_link) # /dataset/1 - no trailing slash dataset_url = self.dataset.get_absolute_url() self.dataset_link_param2.set_value(dataset_url) self.dataset_link_param2.save() # Check link_id/link_ct/link_gfk to dataset self.assertTrue(psm.get_param("dataset_link").link_id == self.dataset.id) dataset_ct = ContentType.objects.get(model__iexact="dataset") self.assertTrue(psm.get_param("dataset_link").link_ct == dataset_ct) self.assertTrue(psm.get_param("dataset_link").link_gfk == self.dataset) # Test links of the form /api/v1/experiment/<experiment_id>/ self.exp_link_param2 = DatafileParameter( parameterset=self.datafileparameterset2, name=self.parametername_exp_link) exp_url = '/api/v1/experiment/%s/' % self.exp.id self.exp_link_param2.set_value(exp_url) self.exp_link_param2.save() # Check link_id/link_ct/link_gfk to experiment self.assertTrue(psm.get_param("exp_link").link_id == self.exp.id) exp_ct = ContentType.objects.get(model__iexact="experiment") self.assertTrue(psm.get_param("exp_link").link_ct == exp_ct) self.assertTrue(psm.get_param("exp_link").link_gfk == self.exp) def test_unresolvable_link_parameter(self): """ Test that LINK Parameters that can't be resolved to a model (including non-URL values) still work. """ self.datafileparameterset3 = DatafileParameterSet( schema=self.schema, datafile=self.datafile) self.datafileparameterset3.save() psm = ParameterSetManager(parameterset=self.datafileparameterset3) # Create a Parameter of type LINK to an unresolvable (non-URL) # free-text value self.freetext_link_param = DatafileParameter( parameterset=self.datafileparameterset3, name=self.parametername_unresolvable_link) self.assertRaises(SuspiciousOperation, lambda: self.freetext_link_param.set_value( "FREETEXT_ID_123")) def test_tz_naive_date_handling(self): """ Ensure that dates are handling in a timezone-aware way. """ psm = ParameterSetManager(parameterset=self.datafileparameterset) psm.new_param("parameter3", str(datetime(1970, 01, 01, 10, 0, 0))) expect(psm.get_param("parameter3", True))\ .to_equal(datetime(1970, 01, 01, 0, 0, 0, tzinfo=pytz.utc)) def test_tz_aware_date_handling(self): """ Ensure that dates are handling in a timezone-aware way. """ psm = ParameterSetManager(parameterset=self.datafileparameterset) psm.new_param("parameter3", '1970-01-01T08:00:00+08:00') expect(psm.get_param("parameter3", True))\ .to_equal(datetime(1970, 01, 01, 0, 0, 0, tzinfo=pytz.utc))
class DownloadTestCase(TestCase): def setUp(self): # create a test user self.user = User.objects.create_user(username='******', email='', password='******') Location.force_initialize() # create a public experiment self.experiment1 = Experiment(title='Experiment 1', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_FULL) self.experiment1.save() # create a non-public experiment self.experiment2 = Experiment(title='Experiment 2', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_NONE) self.experiment2.save() # dataset1 belongs to experiment1 self.dataset1 = Dataset() self.dataset1.save() self.dataset1.experiments.add(self.experiment1) self.dataset1.save() # dataset2 belongs to experiment2 self.dataset2 = Dataset() self.dataset2.save() self.dataset2.experiments.add(self.experiment2) self.dataset2.save() # absolute path first filename1 = 'testfile.txt' filename2 = 'testfile.tiff' self.dest1 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment1.id, self.dataset1.id))) self.dest2 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment2.id, self.dataset2.id))) if not exists(self.dest1): makedirs(self.dest1) if not exists(self.dest2): makedirs(self.dest2) testfile1 = abspath(join(self.dest1, filename1)) f = open(testfile1, 'w') f.write("Hello World!\n") f.close() testfile2 = abspath(join(self.dest2, filename2)) _generate_test_image(testfile2) self.datafile1 = self._build_datafile( \ testfile1, filename1, self.dataset1, '%d/%d/%s' % (self.experiment1.id, self.dataset1.id, filename1)) self.datafile2 = self._build_datafile( \ testfile2, filename2, self.dataset2, '%d/%d/%s' % (self.experiment2.id, self.dataset2.id, filename2)) def _build_datafile(self, testfile, filename, dataset, url, protocol='', checksum=None, size=None, mimetype=''): filesize, sha512sum = get_size_and_sha512sum(testfile) datafile = Dataset_File(dataset=dataset, filename=filename, mimetype=mimetype, size=str(size if size != None else filesize), sha512sum=(checksum if checksum else sha512sum)) datafile.save() if urlparse.urlparse(url).scheme == '': location = Location.get_location('local') else: location = Location.get_location_for_url(url) if not location: location = Location.load_location({ 'name': filename, 'url': urlparse.urljoin(url, '.'), 'type': 'external', 'priority': 10, 'transfer_provider': 'local'}) replica = Replica(datafile=datafile, protocol=protocol, url=url, location=location) replica.verify() replica.save() return Dataset_File.objects.get(pk=datafile.pk) def tearDown(self): self.user.delete() self.experiment1.delete() self.experiment2.delete() rmtree(self.dest1) rmtree(self.dest2) def testView(self): client = Client() # check view of file1 response = client.get('/datafile/view/%i/' % self.datafile1.id) self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % self.datafile1.filename) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'Hello World!\n') # check view of file2 response = client.get('/datafile/view/%i/' % self.datafile2.id) # Should be forbidden self.assertEqual(response.status_code, 403) self.experiment2.public_access=Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() # check view of file2 again response = client.get('/datafile/view/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 200) # The following behaviour relies on ImageMagick if IMAGEMAGICK_AVAILABLE: # file2 should have a ".png" filename self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % (self.datafile2.filename+'.png')) # file2 should be a PNG self.assertEqual(response['Content-Type'], 'image/png') png_signature = "\x89PNG\r\n\x1a\n" self.assertEqual(response.content[0:8], png_signature) else: # file2 should have a ".tiff" filename self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % (self.datafile2.filename)) # file2 should be a TIFF self.assertEqual(response['Content-Type'], 'image/tiff') tiff_signature = "II\x2a\x00" self.assertEqual(response.content[0:4], tiff_signature) def _check_tar_file(self, content, rootdir, datafiles, simpleNames=False, noTxt=False): with NamedTemporaryFile('w') as tempfile: tempfile.write(content) tempfile.flush() if getsize(tempfile.name) > 0: expect(is_tarfile(tempfile.name)).to_be_truthy() try: tf = TarFile(tempfile.name, 'r') self._check_names(datafiles, tf.getnames(), rootdir, simpleNames, noTxt) finally: tf.close() else: self._check_names(datafiles, [], rootdir, simpleNames, noTxt) def _check_zip_file(self, content, rootdir, datafiles, simpleNames=False, noTxt=False): with NamedTemporaryFile('w') as tempfile: tempfile.write(content) tempfile.flush() # It should be a zip file expect(is_zipfile(tempfile.name)).to_be_truthy() try: zf = ZipFile(tempfile.name, 'r') self._check_names(datafiles, zf.namelist(), rootdir, simpleNames, noTxt) finally: zf.close() def _check_names(self, datafiles, names, rootdir, simpleNames, noTxt): # SimpleNames says if we expect basenames or pathnames # NoTxt says if we expect '.txt' files to be filtered out if not noTxt: expect(len(names)).to_equal(len(datafiles)) for df in datafiles: if simpleNames: filename = df.filename else: filename = join(rootdir, str(df.dataset.id), df.filename) expect(filename in names).to_be( not (noTxt and filename.endswith('.txt'))) def testDownload(self): client = Client() # check download for experiment1 response = client.get('/download/experiment/%i/zip/' % \ self.experiment1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="experiment%s-complete.zip"' % self.experiment1.id) self.assertEqual(response.status_code, 200) self._check_zip_file( response.content, str(self.experiment1.id), reduce(lambda x, y: x + y, [ds.dataset_file_set.all() \ for ds in self.experiment1.datasets.all()])) # check download for experiment1 as tar response = client.get('/download/experiment/%i/tar/' % \ self.experiment1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="experiment%s-complete.tar"' % self.experiment1.id) self.assertEqual(response.status_code, 200) self._check_tar_file( response.content, str(self.experiment1.id), reduce(lambda x, y: x + y, [ds.dataset_file_set.all() \ for ds in self.experiment1.datasets.all()])) # check download of file1 response = client.get('/download/datafile/%i/' % self.datafile1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s"' % self.datafile1.filename) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'Hello World!\n') # requesting file2 should be forbidden... response = client.get('/download/datafile/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 403) # check dataset1 download response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': []}) self.assertEqual(response.status_code, 200) self._check_zip_file(response.content, 'datasets', self.dataset1.dataset_file_set.all()) # check dataset1 download as tar response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': [], 'comptype': 'tar'}) self.assertEqual(response.status_code, 200) self._check_tar_file(response.content, 'datasets', self.dataset1.dataset_file_set.all()) # check dataset2 download response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [self.dataset2.id], 'datafile': []}) self.assertEqual(response.status_code, 403) # check datafile1 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [], 'datafile': [self.datafile1.id]}) self.assertEqual(response.status_code, 200) self._check_zip_file(response.content, 'datasets', [self.datafile1]) # check datafile2 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [], 'datafile': [self.datafile2.id]}) self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to "metadata only" self.experiment2.public_access=Experiment.PUBLIC_ACCESS_METADATA self.experiment2.save() response = client.get('/download/datafile/%i/' % self.datafile2.id) # Metadata-only means "no file access"! self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to public self.experiment2.public_access=Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() response = client.get('/download/datafile/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 200) # This should be a TIFF (which often starts with "II\x2a\x00") self.assertEqual(response['Content-Type'], 'image/tiff') self.assertEqual(response.content[0:4], "II\x2a\x00") # check experiment zip download with alternative organization response = client.get('/download/experiment/%i/zip/test/' % \ self.experiment1.id) self.assertEqual(response.status_code, 200) self.assertEqual(response['Content-Disposition'], 'attachment; filename="experiment%s-complete.zip"' % self.experiment1.id) self._check_zip_file( response.content, str(self.experiment1.id), reduce(lambda x, y: x + y, [ds.dataset_file_set.all() \ for ds in self.experiment1.datasets.all()]), simpleNames=True) # check experiment tar download with alternative organization response = client.get('/download/experiment/%i/tar/test/' % \ self.experiment1.id) self.assertEqual(response.status_code, 200) self.assertEqual(response['Content-Disposition'], 'attachment; filename="experiment%s-complete.tar"' % self.experiment1.id) self._check_tar_file( response.content, str(self.experiment1.id), reduce(lambda x, y: x + y, [ds.dataset_file_set.all() \ for ds in self.experiment1.datasets.all()]), simpleNames=True) # check experiment1 download with '.txt' filtered out (none left) response = client.get('/download/experiment/%i/tar/test2/' % \ self.experiment1.id) self.assertEqual(response.status_code, 400) # check experiment2 download with '.txt' filtered out response = client.get('/download/experiment/%i/tar/test2/' % \ self.experiment2.id) self.assertEqual(response.status_code, 200) self.assertEqual(response['Content-Disposition'], 'attachment; filename="experiment%s-complete.tar"' % self.experiment2.id) self._check_tar_file( response.content, str(self.experiment2.id), reduce(lambda x, y: x + y, [ds.dataset_file_set.all() \ for ds in self.experiment2.datasets.all()]), simpleNames=True, noTxt=True) # check dataset1 download response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': [], 'comptype': 'zip', 'organization': 'test'}) self.assertEqual(response.status_code, 200) self._check_zip_file(response.content, 'datasets', self.dataset1.dataset_file_set.all(), simpleNames=True) def testDatasetFile(self): # check registered text file for physical file meta information df = Dataset_File.objects.get(pk=self.datafile1.id) try: from magic import Magic self.assertEqual(df.mimetype, 'text/plain; charset=us-ascii') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(df.size, str(13)) self.assertEqual(df.md5sum, '8ddd8be4b179a529afa5f2ffae4b9858') # Now check we can calculate checksums and infer the mime type # for a JPG file. filename = abspath(join(dirname(__file__), '../static/images/ands-logo-hi-res.jpg')) dataset = Dataset.objects.get(pk=self.dataset1.id) pdf1 = self._build_datafile(filename, basename(filename), dataset, 'file://%s' % filename, protocol='file') self.assertEqual(pdf1.get_preferred_replica().verify(), True) pdf1 = Dataset_File.objects.get(pk=pdf1.pk) try: from magic import Magic self.assertEqual(pdf1.mimetype, 'image/jpeg') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(pdf1.size, str(14232)) self.assertEqual(pdf1.md5sum, 'c450d5126ffe3d14643815204daf1bfb') # Now check that we can override the physical file meta information # We are setting size/checksums that don't match the actual file, so # the pdf2 = self._build_datafile( filename, filename, dataset, 'file://%s' % filename, protocol='file', mimetype='application/vnd.openxmlformats-officedocument.presentationml.presentation', size=0, # Empty string always has the same hash checksum='cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e') self.assertEqual(pdf2.size, str(0)) self.assertEqual(pdf2.md5sum, '') self.assertEqual(pdf2.get_preferred_replica().verify(), False) pdf2 = Dataset_File.objects.get(pk=pdf2.pk) try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/vnd.openxmlformats-officedocument.presentationml.presentation') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(pdf2.size, str(0)) self.assertEqual(pdf2.md5sum, '') pdf2.mimetype = '' pdf2.save() pdf2.get_preferred_replica().save() pdf2 = Dataset_File.objects.get(pk=pdf2.pk) try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/pdf') except: # XXX Test disabled because lib magic can't be loaded pass
class DownloadTestCase(TestCase): def setUp(self): # create a test user self.user = User.objects.create_user(username='******', email='', password='******') # create a public experiment self.experiment1 = Experiment(title='Experiment 1', created_by=self.user, public=True) self.experiment1.save() # create a non-public experiment self.experiment2 = Experiment(title='Experiment 2', created_by=self.user, public=False) self.experiment2.save() # dataset1 belongs to experiment1 self.dataset1 = Dataset(experiment=self.experiment1) self.dataset1.save() # dataset2 belongs to experiment2 self.dataset2 = Dataset(experiment=self.experiment2) self.dataset2.save() # absolute path first filename = 'testfile.txt' self.dest1 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment1.id, self.dataset1.id))) self.dest2 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment2.id, self.dataset2.id))) if not exists(self.dest1): makedirs(self.dest1) if not exists(self.dest2): makedirs(self.dest2) testfile1 = abspath(join(self.dest1, filename)) f = open(testfile1, 'w') f.write("Hello World!\n") f.close() testfile2 = abspath(join(self.dest2, filename)) f = open(testfile2, 'w') f.write("Hello World!\n") f.close() self.dataset_file1 = Dataset_File(dataset=self.dataset1, filename=filename, protocol='tardis', url='tardis://%s' % filename) self.dataset_file1.save() self.dataset_file2 = Dataset_File(dataset=self.dataset2, filename=basename(filename), protocol='tardis', url='tardis://%s' % filename) self.dataset_file2.save() def tearDown(self): self.user.delete() self.experiment1.delete() self.experiment2.delete() rmtree(self.dest1) rmtree(self.dest2) def testDownload(self): client = Client() # check download for experiment1 response = client.get('/download/experiment/%i/zip/' % self.experiment1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="experiment%s-complete.zip"' % self.experiment1.id) self.assertEqual(response.status_code, 200) # check download of file1 response = client.get('/download/datafile/%i/' % self.dataset_file1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s"' % self.dataset_file2.filename) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'Hello World!\n') # requesting file2 should be forbidden... response = client.get('/download/datafile/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 403) # check dataset1 download response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': []}) self.assertEqual(response.status_code, 200) # check dataset2 download response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [self.dataset2.id], 'datafile': []}) self.assertEqual(response.status_code, 403) # check datafile1 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [], 'datafile': [self.dataset_file1.id]}) self.assertEqual(response.status_code, 200) # check datafile2 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [], 'datafile': [self.dataset_file2.id]}) self.assertEqual(response.status_code, 403) def testDatasetFile(self): # check registered text file for physical file meta information df = Dataset_File.objects.get(pk=self.dataset_file1.id) try: from magic import Magic self.assertEqual(df.mimetype, 'text/plain; charset=us-ascii') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(df.size, str(13)) self.assertEqual(df.md5sum, '8ddd8be4b179a529afa5f2ffae4b9858') # now check a pdf file filename = join(abspath(dirname(__file__)), '../static/downloads/DatasetDepositionGuide.pdf') dataset = Dataset.objects.get(pk=self.dataset1.id) pdf1 = Dataset_File(dataset=dataset, filename=basename(filename), url='file://%s' % filename, protocol='file') pdf1.save() try: from magic import Magic self.assertEqual(pdf1.mimetype, 'application/pdf') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(pdf1.size, str(1008475)) self.assertEqual(pdf1.md5sum, '9192b3d3e0056412b1d21d3e33562eba') # now check that we can override the physical file meta information pdf2 = Dataset_File(dataset=dataset, filename=basename(filename), url='file://%s' % filename, protocol='file', mimetype='application/vnd.openxmlformats-officedocument.presentationml.presentation', size=str(0), md5sum='md5sum') pdf2.save() try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/vnd.openxmlformats-officedocument.presentationml.presentation') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(pdf2.size, str(0)) self.assertEqual(pdf2.md5sum, 'md5sum') pdf2.mimetype = '' pdf2.save() try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/pdf') except: # XXX Test disabled becuse lib magic can't be loaded pass
class ViewTemplateContextsTest(TestCase): def setUp(self): """ setting up essential objects, copied from tests above """ Location.force_initialize() self.location = Location.get_location('local') user = '******' pwd = 'secret' email = '' self.user = User.objects.create_user(user, email, pwd) self.userProfile = UserProfile(user=self.user).save() self.exp = Experiment(title='test exp1', institution_name='monash', created_by=self.user) self.exp.save() self.acl = ObjectACL( pluginId=django_user, entityId=str(self.user.id), content_object=self.exp, canRead=True, isOwner=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) self.acl.save() self.dataset = Dataset(description='dataset description...') self.dataset.save() self.dataset.experiments.add(self.exp) self.dataset.save() self.dataset_file = Dataset_File(dataset=self.dataset, size=42, filename="foo", md5sum="junk") self.dataset_file.save() self.replica = Replica(datafile=self.dataset_file, url="http://foo", location=self.location, verified=False) self.replica.save() def tearDown(self): self.user.delete() self.exp.delete() self.dataset.delete() self.dataset_file.delete() self.acl.delete() def testExperimentView(self): """ test some template context parameters for an experiment view """ from tardis.tardis_portal.views import view_experiment from tardis.tardis_portal.shortcuts import render_response_index from django.http import HttpRequest from django.template import Context import sys # Default behavior views_module = flexmock(sys.modules['tardis.tardis_portal.views']) request = HttpRequest() request.user=self.user request.groups=[] context = {'organization': ['classic', 'test', 'test2'], 'default_organization': 'classic', 'default_format': 'zip', 'protocol': [['zip', '/download/experiment/1/zip/'], ['tar', '/download/experiment/1/tar/']]} views_module.should_call('render_response_index'). \ with_args(_AnyMatcher(), "tardis_portal/view_experiment.html", _ContextMatcher(context)) response = view_experiment(request, experiment_id=self.exp.id) self.assertEqual(response.status_code, 200) # Behavior with USER_AGENT_SENSING enabled and a request.user_agent saved_setting = getattr(settings, "USER_AGENT_SENSING", None) try: setattr(settings, "USER_AGENT_SENSING", True) request = HttpRequest() request.user=self.user request.groups=[] mock_agent = _MiniMock(os=_MiniMock(family="Macintosh")) setattr(request, 'user_agent', mock_agent); context = {'organization': ['classic', 'test', 'test2'], 'default_organization': 'classic', 'default_format': 'tar', 'protocol': [['tar', '/download/experiment/1/tar/']]} views_module.should_call('render_response_index'). \ with_args(_AnyMatcher(), "tardis_portal/view_experiment.html", _ContextMatcher(context)) response = view_experiment(request, experiment_id=self.exp.id) self.assertEqual(response.status_code, 200) finally: if saved_setting != None: setattr(settings, "USER_AGENT_SENSING", saved_setting) else: delattr(settings, "USER_AGENT_SENSING") def testDatasetView(self): """ test some context parameters for a dataset view """ from tardis.tardis_portal.views import view_dataset from tardis.tardis_portal.shortcuts import render_response_index from django.http import HttpRequest from django.template import Context import sys views_module = flexmock(sys.modules['tardis.tardis_portal.views']) request = HttpRequest() request.user=self.user request.groups=[] context = {'default_organization': 'classic', 'default_format': 'zip'} views_module.should_call('render_response_index'). \ with_args(_AnyMatcher(), "tardis_portal/view_dataset.html", _ContextMatcher(context)) response = view_dataset(request, dataset_id=self.dataset.id) self.assertEqual(response.status_code, 200) # Behavior with USER_AGENT_SENSING enabled and a request.user_agent saved_setting = getattr(settings, "USER_AGENT_SENSING", None) try: setattr(settings, "USER_AGENT_SENSING", True) request = HttpRequest() request.user=self.user request.groups=[] mock_agent = _MiniMock(os=_MiniMock(family="Macintosh")) setattr(request, 'user_agent', mock_agent); context = {'default_organization': 'classic', 'default_format': 'tar'} views_module.should_call('render_response_index'). \ with_args(_AnyMatcher(), "tardis_portal/view_dataset.html", _ContextMatcher(context)) response = view_dataset(request, dataset_id=self.dataset.id) self.assertEqual(response.status_code, 200) finally: if saved_setting != None: setattr(settings, "USER_AGENT_SENSING", saved_setting) else: delattr(settings, "USER_AGENT_SENSING")
class ObjectACLTestCase(TestCase): urls = 'tardis.urls' def setUp(self): # create a couple of test users self.user1 = User.objects.create_user('testuser1', '', 'secret') self.user2 = User.objects.create_user('testuser2', '', 'secret') self.user3 = User.objects.create_user('testuser3', '', 'secret') self.user4 = User.objects.create_user('testuser4', '', 'secret') # with standard permissions for user in [self.user1, self.user2, self.user3, self.user4]: user.user_permissions.add(Permission.objects.get(codename='add_experiment')) user.user_permissions.add(Permission.objects.get(codename='change_experiment')) user.user_permissions.add(Permission.objects.get(codename='change_group')) user.user_permissions.add(Permission.objects.get(codename='change_userauthentication')) user.user_permissions.add(Permission.objects.get(codename='change_objectacl')) self.userProfile1 = self.user1.userprofile self.userProfile2 = self.user2.userprofile self.userProfile3 = self.user3.userprofile self.userProfile4 = self.user4.userprofile # each user will have their own client self.client1 = Client() self.client2 = Client() self.client3 = Client() self.client4 = Client() # user1 will own experiment1 self.experiment1 = Experiment( title='Experiment1', institution_name='Australian Synchrotron', approved=True, public_access=Experiment.PUBLIC_ACCESS_NONE, created_by=self.user1, ) self.experiment1.save() # user2 will own experiment2 self.experiment2 = Experiment( title='Experiment2', institution_name='Australian Synchrotron', approved=True, public_access=Experiment.PUBLIC_ACCESS_NONE, created_by=self.user2, ) self.experiment2.save() # experiment3 is public & locked self.experiment3 = Experiment( title='Experiment3', institution_name='Australian Synchrotron', approved=True, locked=True, public_access=Experiment.PUBLIC_ACCESS_FULL, created_by=self.user3, ) self.experiment3.save() # experiment4 will be accessible based on location information self.experiment4 = Experiment( title='Experiment4', institution_name='Australian Synchrotron', approved=True, public_access=Experiment.PUBLIC_ACCESS_NONE, created_by=self.user1, ) self.experiment4.save() # user1 owns experiment1 acl = ObjectACL( pluginId=django_user, entityId=str(self.user1.id), content_object=self.experiment1, canRead=True, isOwner=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) acl.save() # user2 owns experiment2 acl = ObjectACL( pluginId=django_user, entityId=str(self.user2.id), content_object=self.experiment2, canRead=True, isOwner=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) acl.save() # experiment4 is accessible via location acl = ObjectACL( pluginId='ip_address', entityId='127.0.0.1', content_object=self.experiment4, canRead=True, aclOwnershipType=ObjectACL.SYSTEM_OWNED, ) acl.save() def tearDown(self): self.experiment1.delete() self.experiment2.delete() self.experiment3.delete() self.experiment4.delete() self.user1.delete() self.user2.delete() self.user3.delete() self.user4.delete() self.client1.logout() self.client2.logout() self.client3.logout() self.client4.logout() def testChangeUserPermissions(self): login1 = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login1) login3 = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login3) # user1 should be see experiment1 response = self.client1.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user3 should not be able to see experiment1 response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # make the group1 a full read/write/owner of the experiment1 response = self.client1.get('/experiment/control_panel/%i' '/access_list/add/group/%s/?canRead=true' '&canWrite=true&canDelete=false&isOwner=true' % (self.experiment1.id, 'group1')) self.assertEqual(response.status_code, 200) # ok, now do some tricky stuff today = datetime.datetime.today() yesterday = today - datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1) # add user3 to experiment1 response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) self.assertContains(response, '<div class="access_list_user') # check permissions for user3 - fail as canRead not set to True response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # give user3 read permissions for experiment1 effective TOMORROW url = ("/experiment/control_panel/%i/access_list" "/change/user/%s/?authMethod=%s") response = self.client1.post(url % (self.experiment1.id, self.user3.username, localdb_auth_key), {'canRead': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) self.assertEqual(response.status_code, 302) # check permissions for user3 response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # user1 should be see experiment1 response = self.client1.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # give user3 read permissions for experiment1 effective YESTERDAY url = ("/experiment/control_panel/%i/access_list" "/change/user/%s/?authMethod=%s") response = self.client1.post(url % (self.experiment1.id, self.user3.username, localdb_auth_key), {'canRead': True, 'effectiveDate_year': yesterday.year, 'effectiveDate_month': yesterday.month, 'effectiveDate_day': yesterday.day, }) self.assertEqual(response.status_code, 302) # check permissions for user3 response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) def testReadAccess(self): login = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login) # user1 should be see experiment1 response = self.client1.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user1 should not be allowed to see experiment2 response = self.client1.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # user1 should be allowed to see experiment3 as it's public response = self.client1.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user1 should be allowed to see experiment4 based on his IP address # response = self.client1.get('/experiment/view/%i/' # % (self.experiment4.id)) # self.assertEqual(response.status_code, 200) # create a group and add it to experiment1 response = self.client1.get('/experiment/control_panel' '/create/group/?group=%s&authMethod=localdb' % ('group1')) self.assertEqual(response.status_code, 200) # make the group1 a full read/write/owner of the experiment1 response = self.client1.get('/experiment/control_panel/%i' '/access_list/add/group/%s/?canRead=true' '&canWrite=true&canDelete=false&isOwner=true' % (self.experiment1.id, 'group1')) self.assertEqual(response.status_code, 200) # add user2 as admin to the newly created group1 group = Group.objects.get(name='group1') response = self.client1.get('/group/%i/add/%s/?isAdmin=true&authMethod=%s' % (group.id, self.user2.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # try it again response = self.client1.get('/group/%i/add/%s/?isAdmin=true&authMethod=%s' % (group.id, self.user2.username, localdb_auth_key)) self.assertEqual(response.content, 'User %s is already member of that' ' group.' % self.user2.username) # user1 is not allowed to modify acls for experiment2 response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment2.id, self.user1.username, localdb_auth_key)) self.assertEqual(response.status_code, 403) # user2 *IS* allowed to modify acls for experiment1, since they are part # of an owning group (we add then remove access for user3) response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'OK') # test add non-existent user non_existant = 'test_boozer' response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment1.id, non_existant, localdb_auth_key)) self.assertContains(response, 'User %s does not exist' % non_existant) # test add to non existant experiment # Note: Ideally we'd like to check for error message, but we # can't hit it with the decorator in place. However, # currently we check for a 403 (forbidden) error, as the # 'experiment_ownership_required' decorator simply checks if # the experiment_id appears in the specified user's ACL, and # assumes that the absence of the experiment_id means that the # experiment exists but the user doesn't have access to # it. This could possibly be changed to a 404 error. response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (9999, self.user1.username, localdb_auth_key)) self.assertEqual(response.status_code, 403) self.client1.logout() # now check user2's permissions login = self.client2.login(username=self.user2.username, password='******') self.assertTrue(login) # user2 should be able to see experiment1 now response = self.client2.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user2 should be also able to see experiment2 response = self.client2.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 200) # user2 should be allowed to see experiment3 as it's public response = self.client2.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user2 should be able to add user3 to group1 (experiment1) response = self.client2.get( '/group/%i/add/%s/?isAdmin=false&authMethod=%s' % (group.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) self.client2.logout() # now check user3's permissions login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) # user3 should be able to see experiment1 via his group permissions response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user3 should not be able to see experiment2 response = self.client3.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # user3 should be able to see experiment3 response = self.client3.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user3 should not be able to add another user4 to group1 response = self.client3.get( '/group/%i/add/%s/?isAdmin=false&authMethod=%s' % (group.id, 'testuser4', localdb_auth_key)) self.assertEqual(response.status_code, 403) self.client3.logout() # ok, now do some tricky stuff today = datetime.datetime.today() yesterday = today - datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1) url = ("/experiment/control_panel/%i/access_list" "/change/user/%s/?authMethod=%s") login = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login) # remove user3 from group1 response = self.client1.get('/group/%i/remove/%s/' % (group.id, self.user3.username)) self.assertEqual(response.status_code, 200) # add user3 to experiment1 response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) self.assertContains(response, '<div class="access_list_user') # give user3 read permissions for experiment1 effective TOMORROW response = self.client1.post(url % (self.experiment1.id, self.user3.username, localdb_auth_key), {'canRead': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) # logger.debug('[1] response =' + str(response)) self.assertEqual(response.status_code, 302) # check permissions for user3 login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # change effective date to TODAY response = self.client1.post(url % (self.experiment1.id, self.user3.username, localdb_auth_key), {'canRead': True, 'effectiveDate_year': today.year, 'effectiveDate_month': today.month, 'effectiveDate_day': today.day, }) self.assertEqual(response.status_code, 302) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # change effictive date to YESTERDAY self.client1.post(url % (self.experiment1.id, self.user3.username, localdb_auth_key), {'canRead': True, 'effectiveDate_year': yesterday.year, 'effectiveDate_month': yesterday.month, 'effectiveDate_day': yesterday.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to TOMORROW self.client1.post(url % (self.experiment1.id, self.user3.username, localdb_auth_key), {'canRead': True, 'expiryDate_year': tomorrow.year, 'expiryDate_month': tomorrow.month, 'expiryDate_day': tomorrow.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to TODAY self.client1.post(url % (self.experiment1.id, self.user3.username, localdb_auth_key), {'canRead': True, 'expiryDate_year': today.year, 'expiryDate_month': today.month, 'expiryDate_day': today.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to YESTERDAY self.client1.post(url % (self.experiment1.id, self.user3.username, localdb_auth_key), {'canRead': True, 'expiryDate_year': yesterday.year, 'expiryDate_month': yesterday.month, 'expiryDate_day': yesterday.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # remove user3 from experiment1 again response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (self.experiment1.id, self.user3.username)) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'OK') # try again, see if it falls over response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (self.experiment1.id, self.user3.username)) self.assertEqual(response.content, 'The user %s does not have access to this experiment.' % self.user3.username) # try to remove from a non-existant experiment response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (9999, self.user3.username)) self.assertEqual(response.status_code, 403) # try to remove the only owner response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (self.experiment1.id, self.user1.username)) self.assertEqual(response.content, 'All experiments must have at least ' 'one user as owner. Add an ' 'additional owner first before ' 'removing this one.') # create a group2 and add it to experiment1 response = self.client1.get('/experiment/control_panel' '/create/group/?group=%s&authMethod=localdb' % ('group2')) self.assertEqual(response.status_code, 200) # give group2 read-only access to experiment1 response = self.client1.get('/experiment/control_panel/%i' '/access_list/add/group/%s/?canRead=true' '&canWrite=false&canDelete=false&isOwner=false' % (self.experiment1.id, 'group2')) self.assertEqual(response.status_code, 200) # add user3 as admin to group2 self.group2 = Group.objects.get(name='group2') response = self.client1.get( '/group/%i/add/%s/?isAdmin=true&authMethod=%s' % (self.group2.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # as user3, try to add myself as an owner of the experiment1 response = self.client3.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s&canRead=true' '&canWrite=true&canDelete=false&' 'isOwner=true' % (self.experiment1.id, self.user3.username, localdb_auth_key)) # this should fail since the group2, of which user3 is a member, is # not an 'owner' group, just a read-only group self.assertEqual(response.status_code, 403) # as user3, attempt to remove user1 as the owner of experiment1 response = self.client3.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/?authMethod=%s' % (self.experiment1.id, self.user1.username, localdb_auth_key)) # this should fail since the group2, of which user3 is a member, is # not an 'owner' group, just a read-only group self.assertEqual(response.status_code, 403) # as user1, add user3 as an owner of experiment1 response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s&canRead=true' '&canWrite=true&canDelete=false&' 'isOwner=true' % (self.experiment1.id, self.user3.username, localdb_auth_key)) # since user1 is an owner user of experiment1, we can add additional # owner users to the experiment self.assertEqual(response.status_code, 200) # as user3 (now an owner), attempt to remove user1 as the owner of # experiment1, leaving user3 as the sole owner response = self.client3.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/?authMethod=%s' % (self.experiment1.id, self.user1.username, localdb_auth_key)) # this should now succeed since both user3 and user1 are owners of # experiment1, and user3 is allowed to remove other owners (unless they # are the only owner user) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'OK') # as user3 (now the only owner), attempts to remove myself as the owner # of experiment1 response = self.client3.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) # this should fail with an error since every experiment must have at # least one user owner self.assertEqual(response.content, 'All experiments must have at least one user as ' 'owner. Add an additional owner first before ' 'removing this one.') self.client1.logout() self.client3.logout() def testWriteAccess(self): # without logging in the request should be redirected response = self.client1.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 302) # now check access for user1 login = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login) response = self.client1.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # write access has not been granted for experiment2 response = self.client1.get('/experiment/edit/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # neither experiment3 which is public response = self.client1.get('/experiment/edit/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 403) # create a group 'group1w' with write permissions response = self.client1.get('/experiment/control_panel' '/create/group/?group=%s&authMethod=localdb' % ('group1w')) self.assertEqual(response.status_code, 200) response = self.client1.get('/experiment/control_panel/%i' '/access_list/add/group/%s/?canRead=true' '&canWrite=true&canDelete=false&isOwner=undefined' % (self.experiment1.id, 'group1w')) self.assertEqual(response.status_code, 200) # add user2 to 'group1w' which gives him write permissions group = Group.objects.get(name='group1w') response = self.client1.get('/group/%i/add/%s/?isAdmin=false&authMethod=%s' % (group.id, self.user2.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # add user3 explicitly to experiment1 response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s&canRead=true' '&canWrite=true' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # check newly created permissions for user2 and user3 response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 302) response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 302) login = self.client2.login(username=self.user2.username, password='******') self.assertTrue(login) login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) # response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) # self.assertEqual(response.status_code, 200) response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # now the fancy stuff with timestamps today = datetime.datetime.today() yesterday = today - datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1) url = '/experiment/control_panel/%i/access_list/change/group/%i/' # give group 'group1w' write permissions for experiment1 effictive TOMORROW response = self.client1.post(url % (self.experiment1.id, group.id), {'canRead': True, 'canWrite': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) self.assertEqual(response.status_code, 302) response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # change effictive date to TODAY response = self.client1.post(url % (self.experiment1.id, group.id), {'canRead': True, 'canWrite': True, 'effectiveDate_year': today.year, 'effectiveDate_month': today.month, 'effectiveDate_day': today.day, }) self.assertEqual(response.status_code, 302) # now user2 should have write access again response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # repeat all the tests with timestamps for user3 url = '/experiment/control_panel/%i/access_list/change/user/%s/' # give user3 write permissions for experiment1 effictive TOMORROW response = self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'canWrite': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) self.assertEqual(response.status_code, 302) response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # change effictive date to TODAY response = self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'canWrite': True, 'effectiveDate_year': today.year, 'effectiveDate_month': today.month, 'effectiveDate_day': today.day, }) self.assertEqual(response.status_code, 302) # now user3 should have write access again response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) self.client1.logout() self.client2.logout() self.client3.logout() def testCantEditLockedExperiment(self): login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) # user3 has acl to write to experiment3 acl = ObjectACL( pluginId=django_user, entityId=str(self.user3.id), content_object=self.experiment3, canRead=True, canWrite=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) acl.save() response = self.client3.get('/experiment/edit/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 403) response = self.client3.post('/experiment/edit/%i/' % (self.experiment3.id), {'anything': True, }) self.assertEqual(response.status_code, 403) acl.delete() self.client3.logout() def testOwnedExperiments(self): user = AnonymousUser() # not logged in class MockRequest: pass request = MockRequest() request.user = user num_exps = Experiment.safe.owned(request.user).count() self.assertEqual(num_exps, 0) def testCantAddTokenuserToGroups(self): from django.conf import settings login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) g = Group() g.save() self.client3.get('/group/%s/%s/' % (g.id, settings.TOKEN_USERNAME)) self.assertEqual(0, g.user_set.count()) # user should not be added
class ExperimentACLTestCase(TestCase): urls = 'tardis.urls' def setUp(self): # create a couple of test users self.user1 = User.objects.create_user('testuser1', '', 'secret') self.user2 = User.objects.create_user('testuser2', '', 'secret') self.user3 = User.objects.create_user('testuser3', '', 'secret') self.user4 = User.objects.create_user('testuser4', '', 'secret') # each user will have their own client self.client1 = Client() self.client2 = Client() self.client3 = Client() self.client4 = Client() # user1 will own experiment1 self.experiment1 = Experiment( title='Experiment1', institution_name='Australian Synchrotron', approved=True, public=False, created_by=self.user1, ) self.experiment1.save() # user2 will own experiment2 self.experiment2 = Experiment( title='Experiment2', institution_name='Australian Synchrotron', approved=True, public=False, created_by=self.user2, ) self.experiment2.save() # experiment3 is public self.experiment3 = Experiment( title='Experiment3', institution_name='Australian Synchrotron', approved=True, public=True, created_by=self.user3, ) self.experiment3.save() # experiment4 will be accessible based on location information self.experiment4 = Experiment( title='Experiment4', institution_name='Australian Synchrotron', approved=True, public=False, created_by=self.user1, ) self.experiment4.save() # user1 owns experiment1 acl = ExperimentACL( pluginId=django_user, entityId=str(self.user1.id), experiment=self.experiment1, canRead=True, isOwner=True, aclOwnershipType=ExperimentACL.OWNER_OWNED, ) acl.save() # user2 owns experiment2 acl = ExperimentACL( pluginId=django_user, entityId=str(self.user2.id), experiment=self.experiment2, canRead=True, isOwner=True, aclOwnershipType=ExperimentACL.OWNER_OWNED, ) acl.save() # experiment4 is accessible via location acl = ExperimentACL( pluginId='ip_address', entityId='127.0.0.1', experiment=self.experiment4, canRead=True, aclOwnershipType=ExperimentACL.SYSTEM_OWNED, ) acl.save() def tearDown(self): self.client1.logout() self.client2.logout() self.client3.logout() self.client4.logout() self.experiment1.delete() self.experiment2.delete() self.experiment3.delete() self.experiment4.delete() self.user1.delete() self.user2.delete() self.user3.delete() self.user4.delete() def testAccessControl(self): login = self.client1.login(username='******', password='******') self.assertTrue(login) # user1 should be see experiment1 response = self.client1.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user1 should not be allowed to see experiment2 response = self.client1.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # user1 should be allowed to see experiment3 as it's public response = self.client1.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user1 should be allowed to see experiment4 based on his IP address response = self.client1.get('/experiment/view/%i/' % (self.experiment4.id)) self.assertEqual(response.status_code, 200) # create a group and add it to experiment1 response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/group/%s?canRead=true&create=true' % (self.experiment1.id, 'group1')) self.assertEqual(response.status_code, 200) # add user2 as admin to the newly created group group = Group.objects.get(name='group1') response = self.client1.get('/group/%i/add/%s?isAdmin=true' % (group.id, self.user2.username)) self.assertEqual(response.status_code, 200) self.client1.logout() # now check user2's permissions login = self.client2.login(username='******', password='******') self.assertTrue(login) # user2 should be able to see experiment1 now response = self.client2.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user2 should be also able to see experiment2 response = self.client2.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 200) # user2 should be allowed to see experiment3 as it's public response = self.client2.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user2 should be able to add user3 to group1 (experiment1) response = self.client2.get('/group/%i/add/%s?isAdmin=false' % (group.id, self.user3.username)) self.client1.logout() # now check user3's permissions login = self.client3.login(username='******', password='******') self.assertTrue(login) # user3 should be able to see experiment1 via his group permissions response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user3 should not be able to see experiment2 response = self.client3.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # user3 should be able to see experiment3 response = self.client3.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user3 should not be able to add another user4 to group1 response = self.client3.get('/group/%i/add/%s?isAdmin=false' % (group.id, self.user4.username)) self.assertEqual(response.status_code, 403) self.client3.logout() # ok, now do some tricky stuff import datetime today = datetime.datetime.today() yesterday = today - datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1) url = '/experiment/control_panel/%i/access_list/change/user/%s/' login = self.client1.login(username='******', password='******') self.assertTrue(login) # remove user3 from group1 response = self.client1.get('/group/%i/remove/%s/' % (group.id, self.user3.username)) self.assertEqual(response.status_code, 200) # add user3 to experiment1 self.client1.get('/experiment/control_panel/%i/access_list/add/user/%s' % (self.experiment1.id, self.user3.username)) self.assertEqual(response.status_code, 200) # give user3 read permissions for experiment1 effictive TOMORROW self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) self.assertEqual(response.status_code, 200) # check permissions for user3 login = self.client3.login(username='******', password='******') self.assertTrue(login) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # change effictive date to TODAY self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'effectiveDate_year': today.year, 'effectiveDate_year': today.month, 'effectiveDate_year': today.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # change effictive date to YESTERDAY self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'effectiveDate_year': yesterday.year, 'effectiveDate_year': yesterday.month, 'effectiveDate_year': yesterday.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to TOMORROW self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'expiryDate_year': tomorrow.year, 'expiryDate_month': tomorrow.month, 'expiryDate_day': tomorrow.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to TODAY self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'expiryDate_year': today.year, 'expiryDate_month': today.month, 'expiryDate_day': today.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to YESTERDAY self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'expiryDate_year': yesterday.year, 'expiryDate_month': yesterday.month, 'expiryDate_day': yesterday.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # can't think of any more stuff atm... self.client1.logout() self.client3.logout()
class DownloadTestCase(TestCase): def setUp(self): # create a test user self.user = User.objects.create_user(username='******', email='', password='******') # create a public experiment self.experiment1 = Experiment(title='Experiment 1', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_FULL) self.experiment1.save() # create a non-public experiment self.experiment2 = Experiment(title='Experiment 2', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_NONE) self.experiment2.save() # dataset1 belongs to experiment1 self.dataset1 = Dataset(experiment=self.experiment1) self.dataset1.save() # dataset2 belongs to experiment2 self.dataset2 = Dataset(experiment=self.experiment2) self.dataset2.save() # absolute path first filename1 = 'testfile.txt' filename2 = 'testfile.tiff' self.dest1 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment1.id, self.dataset1.id))) self.dest2 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment2.id, self.dataset2.id))) if not exists(self.dest1): makedirs(self.dest1) if not exists(self.dest2): makedirs(self.dest2) testfile1 = abspath(join(self.dest1, filename1)) f = open(testfile1, 'w') f.write("Hello World!\n") f.close() testfile2 = abspath(join(self.dest2, filename2)) if IMAGEMAGICK_AVAILABLE: with Image(filename='logo:') as img: img.format = 'tiff' img.save(filename=testfile2) else: # Apparently ImageMagick isn't installed... # Write a "fake" TIFF file f = open(testfile2, 'w') f.write("II\x2a\x00") f.close() self.dataset_file1 = Dataset_File(dataset=self.dataset1, filename=filename1, protocol='tardis', url='tardis://%s' % filename1) self.dataset_file1.save() self.dataset_file2 = Dataset_File(dataset=self.dataset2, filename=basename(filename2), protocol='tardis', url='tardis://%s' % filename2) self.dataset_file2.save() def tearDown(self): self.user.delete() self.experiment1.delete() self.experiment2.delete() rmtree(self.dest1) rmtree(self.dest2) def testView(self): client = Client() # check view of file1 response = client.get('/datafile/view/%i/' % self.dataset_file1.id) self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % self.dataset_file1.filename) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'Hello World!\n') # check view of file2 response = client.get('/datafile/view/%i/' % self.dataset_file2.id) # Should be forbidden self.assertEqual(response.status_code, 403) self.experiment2.public_access=Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() # check view of file2 again response = client.get('/datafile/view/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 200) # The following behaviour relies on ImageMagick if IMAGEMAGICK_AVAILABLE: # file2 should have a ".png" filename self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % (self.dataset_file2.filename+'.png')) # file2 should be a PNG self.assertEqual(response['Content-Type'], 'image/png') png_signature = "\x89PNG\r\n\x1a\n" self.assertEqual(response.content[0:8], png_signature) else: # file2 should have a ".tiff" filename self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % (self.dataset_file2.filename)) # file2 should be a TIFF self.assertEqual(response['Content-Type'], 'image/tiff') tiff_signature = "II\x2a\x00" self.assertEqual(response.content[0:4], tiff_signature) def testDownload(self): client = Client() # check download for experiment1 response = client.get('/download/experiment/%i/zip/' % self.experiment1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="experiment%s-complete.zip"' % self.experiment1.id) self.assertEqual(response.status_code, 200) # check download of file1 response = client.get('/download/datafile/%i/' % self.dataset_file1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s"' % self.dataset_file1.filename) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'Hello World!\n') # requesting file2 should be forbidden... response = client.get('/download/datafile/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 403) # check dataset1 download response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': []}) self.assertEqual(response.status_code, 200) # check dataset2 download response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [self.dataset2.id], 'datafile': []}) self.assertEqual(response.status_code, 403) # check datafile1 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [], 'datafile': [self.dataset_file1.id]}) self.assertEqual(response.status_code, 200) # It should be a zip file (all of which start with "PK") self.assertEqual(response.content[0:2], "PK") # check datafile2 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [], 'datafile': [self.dataset_file2.id]}) self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to "metadata only" self.experiment2.public_access=Experiment.PUBLIC_ACCESS_METADATA self.experiment2.save() response = client.get('/download/datafile/%i/' % self.dataset_file2.id) # Metadata-only means "no file access"! self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to public self.experiment2.public_access=Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() response = client.get('/download/datafile/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 200) # This should be a TIFF (which often starts with "II\x2a\x00") self.assertEqual(response['Content-Type'], 'image/tiff') self.assertEqual(response.content[0:4], "II\x2a\x00") def testDatasetFile(self): # check registered text file for physical file meta information df = Dataset_File.objects.get(pk=self.dataset_file1.id) try: from magic import Magic self.assertEqual(df.mimetype, 'text/plain; charset=us-ascii') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(df.size, str(13)) self.assertEqual(df.md5sum, '8ddd8be4b179a529afa5f2ffae4b9858') # now check a JPG file filename = join(abspath(dirname(__file__)), '../static/images/ands-logo-hi-res.jpg') dataset = Dataset.objects.get(pk=self.dataset1.id) pdf1 = Dataset_File(dataset=dataset, filename=basename(filename), url='file://%s' % filename, protocol='file') pdf1.save() try: from magic import Magic self.assertEqual(pdf1.mimetype, 'image/jpeg') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(pdf1.size, str(14232)) self.assertEqual(pdf1.md5sum, 'c450d5126ffe3d14643815204daf1bfb') # now check that we can override the physical file meta information pdf2 = Dataset_File(dataset=dataset, filename=basename(filename), url='file://%s' % filename, protocol='file', mimetype='application/vnd.openxmlformats-officedocument.presentationml.presentation', size=str(0), md5sum='md5sum') pdf2.save() try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/vnd.openxmlformats-officedocument.presentationml.presentation') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(pdf2.size, str(0)) self.assertEqual(pdf2.md5sum, 'md5sum') pdf2.mimetype = '' pdf2.save() try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/pdf') except: # XXX Test disabled becuse lib magic can't be loaded pass
class ViewTemplateContextsTest(TestCase): def setUp(self): """ setting up essential objects, copied from tests above """ user = "******" pwd = "secret" email = "" self.user = User.objects.create_user(user, email, pwd) self.userProfile = self.user.userprofile self.exp = Experiment(title="test exp1", institution_name="monash", created_by=self.user) self.exp.save() self.acl = ObjectACL( pluginId=django_user, entityId=str(self.user.id), content_object=self.exp, canRead=True, isOwner=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) self.acl.save() self.dataset = Dataset(description="dataset description...") self.dataset.save() self.dataset.experiments.add(self.exp) self.dataset.save() self.datafile = DataFile(dataset=self.dataset, size=42, filename="foo", md5sum="junk") self.datafile.save() def tearDown(self): self.user.delete() self.exp.delete() self.dataset.delete() self.datafile.delete() self.acl.delete() def testExperimentView(self): """ test some template context parameters for an experiment view """ from tardis.tardis_portal.views import ExperimentView from django.http import HttpRequest import sys # Default behavior views_module = flexmock(sys.modules["tardis.tardis_portal.views"]) request = HttpRequest() request.method = "GET" request.user = self.user request.groups = [] context = { "organization": ["test", "test2"], "default_organization": "test", "default_format": "tar", "protocol": [["tgz", "/download/experiment/1/tgz/"], ["tar", "/download/experiment/1/tar/"]], } views_module.should_call("render_response_index").with_args( _AnyMatcher(), "tardis_portal/view_experiment.html", _ContextMatcher(context) ) view_fn = ExperimentView.as_view() response = view_fn(request, experiment_id=self.exp.id) self.assertEqual(response.status_code, 200) # Behavior with USER_AGENT_SENSING enabled and a request.user_agent saved_setting = getattr(settings, "USER_AGENT_SENSING", None) try: setattr(settings, "USER_AGENT_SENSING", True) request = HttpRequest() request.method = "GET" request.user = self.user request.groups = [] mock_agent = _MiniMock(os=_MiniMock(family="Macintosh")) setattr(request, "user_agent", mock_agent) context = { "organization": ["classic", "test", "test2"], "default_organization": "classic", "default_format": "tar", "protocol": [["tar", "/download/experiment/1/tar/"]], } views_module.should_call("render_response_index").with_args( _AnyMatcher(), "tardis_portal/view_experiment.html", _ContextMatcher(context) ) view_fn = ExperimentView.as_view() response = view_fn(request, experiment_id=self.exp.id) self.assertEqual(response.status_code, 200) finally: if saved_setting is not None: setattr(settings, "USER_AGENT_SENSING", saved_setting) else: delattr(settings, "USER_AGENT_SENSING") def testDatasetView(self): """ test some context parameters for a dataset view """ from tardis.tardis_portal.views import DatasetView from django.http import HttpRequest import sys views_module = flexmock(sys.modules["tardis.tardis_portal.views"]) request = HttpRequest() request.method = "GET" request.user = self.user request.groups = [] context = {"default_organization": "test", "default_format": "tar"} views_module.should_call("render_response_index").with_args( _AnyMatcher(), "tardis_portal/view_dataset.html", _ContextMatcher(context) ) view_fn = DatasetView.as_view() response = view_fn(request, dataset_id=self.dataset.id) self.assertEqual(response.status_code, 200) # Behavior with USER_AGENT_SENSING enabled and a request.user_agent saved_setting = getattr(settings, "USER_AGENT_SENSING", None) try: setattr(settings, "USER_AGENT_SENSING", True) request = HttpRequest() request.method = "GET" request.user = self.user request.groups = [] mock_agent = _MiniMock(os=_MiniMock(family="Macintosh")) setattr(request, "user_agent", mock_agent) context = {"default_organization": "classic", "default_format": "tar"} views_module.should_call("render_response_index").with_args( _AnyMatcher(), "tardis_portal/view_dataset.html", _ContextMatcher(context) ) view_fn = DatasetView.as_view() response = view_fn(request, dataset_id=self.dataset.id) self.assertEqual(response.status_code, 200) finally: if saved_setting is not None: setattr(settings, "USER_AGENT_SENSING", saved_setting) else: delattr(settings, "USER_AGENT_SENSING")
class UploadTestCase(TestCase): def setUp(self): from os import path, mkdir from tempfile import mkdtemp user = "******" pwd = "secret" email = "" self.user = User.objects.create_user(user, email, pwd) self.userProfile = self.user.userprofile self.test_dir = mkdtemp() self.exp = Experiment(title="test exp1", institution_name="monash", created_by=self.user) self.exp.save() acl = ObjectACL( pluginId=django_user, entityId=str(self.user.id), content_object=self.exp, canRead=True, isOwner=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) acl.save() self.dataset = Dataset(description="dataset description...") self.dataset.save() self.dataset.experiments.add(self.exp) self.dataset.save() path_parts = [ settings.FILE_STORE_PATH, "%s-%s" % (quote(self.dataset.description, safe="") or "untitled", self.dataset.id), ] self.dataset_path = path.join(*path_parts) if not path.exists(self.dataset_path): mkdir(self.dataset_path) # write test file self.filename = "testfile.txt" self.f1 = open(path.join(self.test_dir, self.filename), "w") self.f1.write("Test file 1") self.f1.close() self.f1_size = path.getsize(path.join(self.test_dir, self.filename)) self.f1 = open(path.join(self.test_dir, self.filename), "r") def tearDown(self): from shutil import rmtree self.f1.close() rmtree(self.test_dir) rmtree(self.dataset_path) self.exp.delete() def testFileUpload(self): from os import path c = Client() c.login(username="******", password="******") session_id = c.session.session_key c.post("/upload/" + str(self.dataset.id) + "/", {"Filedata": self.f1, "session_id": session_id}) test_files_db = DataFile.objects.filter(dataset__id=self.dataset.id) self.assertTrue(path.exists(path.join(self.dataset_path, self.filename))) target_id = Dataset.objects.first().id self.assertEqual(self.dataset.id, target_id) url = test_files_db[0].file_objects.all()[0].uri self.assertEqual(url, path.relpath("%s/testfile.txt" % self.dataset_path, settings.FILE_STORE_PATH)) self.assertTrue(test_files_db[0].file_objects.all()[0].verified) def testUploadComplete(self): from django.http import QueryDict, HttpRequest from tardis.tardis_portal.views import upload_complete data = [("filesUploaded", "1"), ("speed", "really fast!"), ("allBytesLoaded", "2"), ("errorCount", "0")] post = QueryDict("&".join(["%s=%s" % (k, v) for (k, v) in data])) request = HttpRequest() request.POST = post response = upload_complete(request) self.assertTrue("<p>Number: 1</p>" in response.content) self.assertTrue("<p>Errors: 0</p>" in response.content) self.assertTrue("<p>Bytes: 2</p>" in response.content) self.assertTrue("<p>Speed: really fast!</p>" in response.content)
class UploadTestCase(TestCase): def setUp(self): from os import path, mkdir from tempfile import mkdtemp user = '******' pwd = 'secret' email = '' self.user = User.objects.create_user(user, email, pwd) self.userProfile = UserProfile(user=self.user) self.test_dir = mkdtemp() self.exp = Experiment(title='test exp1', institution_name='monash', created_by=self.user) self.exp.save() acl = ExperimentACL( pluginId=django_user, entityId=str(self.user.id), experiment=self.exp, canRead=True, isOwner=True, aclOwnershipType=ExperimentACL.OWNER_OWNED, ) acl.save() self.dataset = \ Dataset(description='dataset description...') self.dataset.save() self.dataset.experiments.add(self.exp) self.dataset.save() self.experiment_path = path.join( settings.FILE_STORE_PATH, str(self.dataset.get_first_experiment().id)) self.dataset_path = path.join(self.experiment_path, str(self.dataset.id)) if not path.exists(self.experiment_path): mkdir(self.experiment_path) if not path.exists(self.dataset_path): mkdir(self.dataset_path) # write test file self.filename = 'testfile.txt' self.f1 = open(path.join(self.test_dir, self.filename), 'w') self.f1.write('Test file 1') self.f1.close() self.f1_size = path.getsize(path.join(self.test_dir, self.filename)) self.f1 = open(path.join(self.test_dir, self.filename), 'r') def tearDown(self): from shutil import rmtree self.f1.close() rmtree(self.test_dir) rmtree(self.dataset_path) rmtree(self.experiment_path) self.exp.delete() def testFileUpload(self): from os import path c = Client() c.login(username='******', password='******') session_id = c.session.session_key response = c.post('/upload/' + str(self.dataset.id) + '/', { 'Filedata': self.f1, 'session_id': session_id }) test_files_db = \ Dataset_File.objects.filter(dataset__id=self.dataset.id) self.assertTrue( path.exists(path.join(self.dataset_path, self.filename))) self.assertTrue(self.dataset.id == 1) self.assertTrue( test_files_db[0].url == '%d/%d/testfile.txt' % (self.dataset.get_first_experiment().id, self.dataset.id)) self.assertTrue(test_files_db[0].verified) def testUploadComplete(self): from django.http import QueryDict, HttpRequest from tardis.tardis_portal.views import upload_complete data = [('filesUploaded', '1'), ('speed', 'really fast!'), ('allBytesLoaded', '2'), ('errorCount', '0')] post = QueryDict('&'.join(['%s=%s' % (k, v) for (k, v) in data])) request = HttpRequest() request.POST = post response = upload_complete(request) self.assertTrue('<p>Number: 1</p>' in response.content) self.assertTrue('<p>Errors: 0</p>' in response.content) self.assertTrue('<p>Bytes: 2</p>' in response.content) self.assertTrue('<p>Speed: really fast!</p>' in response.content)
class DownloadTestCase(TestCase): def setUp(self): # create a test user self.user = User.objects.create_user(username='******', email='', password='******') Location.force_initialize() # create a public experiment self.experiment1 = Experiment( title='Experiment 1', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_FULL) self.experiment1.save() # create a non-public experiment self.experiment2 = Experiment( title='Experiment 2', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_NONE) self.experiment2.save() # dataset1 belongs to experiment1 self.dataset1 = Dataset() self.dataset1.save() self.dataset1.experiments.add(self.experiment1) self.dataset1.save() # dataset2 belongs to experiment2 self.dataset2 = Dataset() self.dataset2.save() self.dataset2.experiments.add(self.experiment2) self.dataset2.save() # absolute path first filename1 = 'testfile.txt' filename2 = 'testfile.tiff' self.dest1 = abspath( join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment1.id, self.dataset1.id))) self.dest2 = abspath( join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment2.id, self.dataset2.id))) if not exists(self.dest1): makedirs(self.dest1) if not exists(self.dest2): makedirs(self.dest2) testfile1 = abspath(join(self.dest1, filename1)) f = open(testfile1, 'w') f.write("Hello World!\n") f.close() testfile2 = abspath(join(self.dest2, filename2)) _generate_test_image(testfile2) self.datafile1 = self._build_datafile( \ testfile1, filename1, self.dataset1, '%d/%d/%s' % (self.experiment1.id, self.dataset1.id, filename1)) self.datafile2 = self._build_datafile( \ testfile2, filename2, self.dataset2, '%d/%d/%s' % (self.experiment2.id, self.dataset2.id, filename2)) def _build_datafile(self, testfile, filename, dataset, url, protocol='', checksum=None, size=None, mimetype=''): filesize, sha512sum = get_size_and_sha512sum(testfile) datafile = Dataset_File( dataset=dataset, filename=filename, mimetype=mimetype, size=str(size if size != None else filesize), sha512sum=(checksum if checksum else sha512sum)) datafile.save() if urlparse.urlparse(url).scheme == '': location = Location.get_location('local') else: location = Location.get_location_for_url(url) if not location: location = Location.load_location({ 'name': filename, 'url': urlparse.urljoin(url, '.'), 'type': 'external', 'priority': 10, 'transfer_provider': 'local' }) replica = Replica(datafile=datafile, protocol=protocol, url=url, location=location) replica.verify() replica.save() return Dataset_File.objects.get(pk=datafile.pk) def tearDown(self): self.user.delete() self.experiment1.delete() self.experiment2.delete() rmtree(self.dest1) rmtree(self.dest2) def testView(self): client = Client() # check view of file1 response = client.get('/datafile/view/%i/' % self.datafile1.id) self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % self.datafile1.filename) self.assertEqual(response.status_code, 200) response_content = "" for c in response.streaming_content: response_content += c self.assertEqual(response_content, 'Hello World!\n') # check view of file2 response = client.get('/datafile/view/%i/' % self.datafile2.id) # Should be forbidden self.assertEqual(response.status_code, 403) self.experiment2.public_access = Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() # check view of file2 again response = client.get('/datafile/view/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 200) # The following behaviour relies on ImageMagick if IMAGEMAGICK_AVAILABLE: # file2 should have a ".png" filename self.assertEqual( response['Content-Disposition'], 'inline; filename="%s"' % (self.datafile2.filename + '.png')) # file2 should be a PNG self.assertEqual(response['Content-Type'], 'image/png') png_signature = "\x89PNG\r\n\x1a\n" self.assertEqual(response.content[0:8], png_signature) else: # file2 should have a ".tiff" filename self.assertEqual( response['Content-Disposition'], 'inline; filename="%s"' % (self.datafile2.filename)) # file2 should be a TIFF self.assertEqual(response['Content-Type'], 'image/tiff') tiff_signature = "II\x2a\x00" self.assertEqual(response.content[0:4], tiff_signature) def _check_tar_file(self, content, rootdir, datafiles, simpleNames=False, noTxt=False): with NamedTemporaryFile('w') as tempfile: for c in content: tempfile.write(c) tempfile.flush() if getsize(tempfile.name) > 0: expect(is_tarfile(tempfile.name)).to_be_truthy() try: tf = TarFile(tempfile.name, 'r') self._check_names(datafiles, tf.getnames(), rootdir, simpleNames, noTxt) finally: tf.close() else: self._check_names(datafiles, [], rootdir, simpleNames, noTxt) def _check_zip_file(self, content, rootdir, datafiles, simpleNames=False, noTxt=False): with NamedTemporaryFile('w') as tempfile: #import rpdb2; rpdb2.start_embedded_debugger("a") #import ipdb; ipdb.set_trace() for c in content: tempfile.write(c) tempfile.flush() # It should be a zip file expect(is_zipfile(tempfile.name)).to_be_truthy() try: zf = ZipFile(tempfile.name, 'r') self._check_names(datafiles, zf.namelist(), rootdir, simpleNames, noTxt) finally: zf.close() def _check_names(self, datafiles, names, rootdir, simpleNames, noTxt): # SimpleNames says if we expect basenames or pathnames # NoTxt says if we expect '.txt' files to be filtered out if not noTxt: expect(len(names)).to_equal(len(datafiles)) for df in datafiles: if simpleNames: filename = df.filename else: filename = join(df.filename) # TODO: update 'classic' to a # useful method and adapt test expect(filename in names).to_be(not ( noTxt and filename.endswith('.txt'))) def testDownload(self): client = Client() # check download for experiment1 # disable zip test while zip is disabled # response = client.get('/download/experiment/%i/zip/' % \ # self.experiment1.id) # self.assertEqual(response['Content-Disposition'], # 'attachment; filename="experiment%s-complete.zip"' # % self.experiment1.id) # self.assertEqual(response.status_code, 200) # self._check_zip_file( # response.streaming_content, str(self.experiment1.id), # reduce(lambda x, y: x + y, # [ds.dataset_file_set.all() \ # for ds in self.experiment1.datasets.all()])) # check download for experiment1 as tar response = client.get('/download/experiment/%i/tar/test/' % self.experiment1.id) self.assertEqual( response['Content-Disposition'], 'attachment; filename="%s-complete.tar"' % self.experiment1.title.replace(' ', '_')) self.assertEqual(response.status_code, 200) self._check_tar_file( response.streaming_content, str(self.experiment1.title.replace(' ', '_')), reduce(lambda x, y: x + y, [ ds.dataset_file_set.all() for ds in self.experiment1.datasets.all() ])) # check download of file1 response = client.get('/download/datafile/%i/' % self.datafile1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s"' % self.datafile1.filename) self.assertEqual(response.status_code, 200) response_content = "" for c in response.streaming_content: response_content += c self.assertEqual(response_content, 'Hello World!\n') # requesting file2 should be forbidden... response = client.get('/download/datafile/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 403) # check dataset1 download # zips disabled for now # response = client.post('/download/datafiles/', # {'expid': self.experiment1.id, # 'dataset': [self.dataset1.id], # 'datafile': []}) # self.assertEqual(response.status_code, 200) # self._check_zip_file(response.streaming_content, 'datasets', # self.dataset1.dataset_file_set.all()) # check dataset1 download as tar response = client.post( '/download/datafiles/', { 'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': [], 'comptype': 'tar' }) self.assertEqual(response.status_code, 200) self._check_tar_file(response.streaming_content, 'Experiment 1-selection', self.dataset1.dataset_file_set.all()) # check dataset2 download response = client.post( '/download/datafiles/', { 'expid': self.experiment2.id, 'dataset': [self.dataset2.id], 'datafile': [] }) self.assertEqual(response.status_code, 403) # check datafile1 download via POST response = client.post( '/download/datafiles/', { 'expid': self.experiment1.id, 'dataset': [], 'datafile': [self.datafile1.id] }) self.assertEqual(response.status_code, 200) self._check_tar_file(response.streaming_content, 'Experiment 1-selection', [self.datafile1]) # check datafile2 download via POST response = client.post( '/download/datafiles/', { 'expid': self.experiment2.id, 'dataset': [], 'datafile': [self.datafile2.id] }) self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to "metadata only" self.experiment2.public_access = Experiment.PUBLIC_ACCESS_METADATA self.experiment2.save() response = client.get('/download/datafile/%i/' % self.datafile2.id) # Metadata-only means "no file access"! self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to public self.experiment2.public_access = Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() response = client.get('/download/datafile/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 200) # This should be a TIFF (which often starts with "II\x2a\x00") self.assertEqual(response['Content-Type'], 'image/tiff') response_content = "" for c in response.streaming_content: response_content += c self.assertEqual(response_content[0:4], "II\x2a\x00") # check experiment zip download with alternative organization # disable zip for now # response = client.get('/download/experiment/%i/zip/test/' % \ # self.experiment1.id) # self.assertEqual(response.status_code, 200) # self.assertEqual(response['Content-Disposition'], # 'attachment; filename="%s-complete.zip"' # % self.experiment1.title) # self._check_zip_file( # response.streaming_content, str(self.experiment1.id), # reduce(lambda x, y: x + y, # [ds.dataset_file_set.all() \ # for ds in self.experiment1.datasets.all()]), # simpleNames=True) # check experiment tar download with alternative organization response = client.get('/download/experiment/%i/tar/test/' % \ self.experiment1.id) self.assertEqual(response.status_code, 200) self.assertEqual( response['Content-Disposition'], 'attachment; filename="%s-complete.tar"' % self.experiment1.title.replace(' ', '_')) self._check_tar_file( response.streaming_content, str(self.experiment1.id), reduce(lambda x, y: x + y, [ds.dataset_file_set.all() \ for ds in self.experiment1.datasets.all()]), simpleNames=True) # check experiment1 download with '.txt' filtered out (none left) response = client.get('/download/experiment/%i/tar/test2/' % \ self.experiment1.id) self.assertEqual(response.status_code, 200) # check experiment2 download with '.txt' filtered out response = client.get('/download/experiment/%i/tar/test2/' % \ self.experiment2.id) self.assertEqual(response.status_code, 200) self.assertEqual( response['Content-Disposition'], 'attachment; filename="%s-complete.tar"' % self.experiment2.title.replace(' ', '_')) self._check_tar_file( response.streaming_content, str(self.experiment2.id), reduce(lambda x, y: x + y, [ds.dataset_file_set.all() \ for ds in self.experiment2.datasets.all()]), simpleNames=True, noTxt=True) # check dataset1 download # zips disabled for now # response = client.post('/download/datafiles/', # {'expid': self.experiment1.id, # 'dataset': [self.dataset1.id], # 'datafile': [], # 'comptype': 'zip', # 'organization': 'test'}) # self.assertEqual(response.status_code, 200) # self._check_zip_file(response.streaming_content, 'datasets', # self.dataset1.dataset_file_set.all(), # simpleNames=True) def testDatasetFile(self): # check registered text file for physical file meta information df = Dataset_File.objects.get(pk=self.datafile1.id) try: from magic import Magic self.assertEqual(df.mimetype, 'text/plain; charset=us-ascii') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(df.size, str(13)) self.assertEqual(df.md5sum, '8ddd8be4b179a529afa5f2ffae4b9858') # Now check we can calculate checksums and infer the mime type # for a JPG file. filename = abspath( join(dirname(__file__), '../static/images/ands-logo-hi-res.jpg')) dataset = Dataset.objects.get(pk=self.dataset1.id) pdf1 = self._build_datafile(filename, basename(filename), dataset, 'file://%s' % filename, protocol='file') self.assertEqual(pdf1.get_preferred_replica().verify(), True) pdf1 = Dataset_File.objects.get(pk=pdf1.pk) try: from magic import Magic self.assertEqual(pdf1.mimetype, 'image/jpeg') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(pdf1.size, str(14232)) self.assertEqual(pdf1.md5sum, 'c450d5126ffe3d14643815204daf1bfb') # Now check that we can override the physical file meta information # We are setting size/checksums that don't match the actual file, so # the pdf2 = self._build_datafile( filename, filename, dataset, 'file://%s' % filename, protocol='file', mimetype= 'application/vnd.openxmlformats-officedocument.presentationml.presentation', size=0, # Empty string always has the same hash checksum= 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e' ) self.assertEqual(pdf2.size, str(0)) self.assertEqual(pdf2.md5sum, '') self.assertEqual(pdf2.get_preferred_replica().verify(), False) pdf2 = Dataset_File.objects.get(pk=pdf2.pk) try: from magic import Magic self.assertEqual( pdf2.mimetype, 'application/vnd.openxmlformats-officedocument.presentationml.presentation' ) except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(pdf2.size, str(0)) self.assertEqual(pdf2.md5sum, '') pdf2.mimetype = '' pdf2.save() pdf2.get_preferred_replica().save() pdf2 = Dataset_File.objects.get(pk=pdf2.pk) try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/pdf') except: # XXX Test disabled because lib magic can't be loaded pass
class ContextualViewTest(TestCase): def setUp(self): """ setting up essential objects, copied from tests above """ user = '******' pwd = 'secret' email = '' self.user = User.objects.create_user(user, email, pwd) self.userProfile = UserProfile(user=self.user).save() self.exp = Experiment(title='test exp1', institution_name='monash', created_by=self.user) self.exp.save() self.acl = ObjectACL( pluginId=django_user, entityId=str(self.user.id), content_object=self.exp, canRead=True, isOwner=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) self.acl.save() self.dataset = Dataset(description='dataset description...') self.dataset.save() self.dataset.experiments.add(self.exp) self.dataset.save() self.dataset_file = Dataset_File(dataset=self.dataset, size=42, filename="foo", md5sum="junk") self.dataset_file.save() self.testschema = Schema(namespace="http://test.com/test/schema", name="Test View", type=Schema.DATAFILE, hidden=True) self.testschema.save() self.dfps = DatafileParameterSet(dataset_file=self.dataset_file, schema=self.testschema) self.dfps.save() def tearDown(self): self.user.delete() self.exp.delete() self.dataset.delete() self.dataset_file.delete() self.testschema.delete() self.dfps.delete() self.acl.delete() def testDetailsDisplay(self): """ test display of view for an existing schema and no display for an undefined one. """ from tardis.tardis_portal.views import display_datafile_details request = flexmock(user=self.user, groups=[("testgroup",flexmock())]) with self.settings(DATAFILE_VIEWS=[("http://test.com/test/schema", "/test/url"), ("http://does.not.exist", "/false/url")]): response = display_datafile_details(request, dataset_file_id=self.dataset_file.id) self.assertEqual(response.status_code, 200) self.assertTrue("/ajax/parameters/" in response.content) self.assertTrue("/test/url" in response.content) self.assertFalse("/false/url" in response.content)
class ObjectACLTestCase(TestCase): urls = 'tardis.urls' def setUp(self): # create a couple of test users self.user1 = User.objects.create_user('testuser1', '', 'secret') self.user2 = User.objects.create_user('testuser2', '', 'secret') self.user3 = User.objects.create_user('testuser3', '', 'secret') self.user4 = User.objects.create_user('testuser4', '', 'secret') # with standard permissions for user in [self.user1, self.user2, self.user3, self.user4]: user.user_permissions.add( Permission.objects.get(codename='add_experiment')) user.user_permissions.add( Permission.objects.get(codename='change_experiment')) user.user_permissions.add( Permission.objects.get(codename='change_group')) user.user_permissions.add( Permission.objects.get(codename='change_userauthentication')) user.user_permissions.add( Permission.objects.get(codename='change_objectacl')) self.userProfile1 = self.user1.userprofile self.userProfile2 = self.user2.userprofile self.userProfile3 = self.user3.userprofile self.userProfile4 = self.user4.userprofile # each user will have their own client self.client1 = Client() self.client2 = Client() self.client3 = Client() self.client4 = Client() # user1 will own experiment1 self.experiment1 = Experiment( title='Experiment1', institution_name='Australian Synchrotron', approved=True, public_access=Experiment.PUBLIC_ACCESS_NONE, created_by=self.user1, ) self.experiment1.save() # user2 will own experiment2 self.experiment2 = Experiment( title='Experiment2', institution_name='Australian Synchrotron', approved=True, public_access=Experiment.PUBLIC_ACCESS_NONE, created_by=self.user2, ) self.experiment2.save() # experiment3 is public & locked self.experiment3 = Experiment( title='Experiment3', institution_name='Australian Synchrotron', approved=True, locked=True, public_access=Experiment.PUBLIC_ACCESS_FULL, created_by=self.user3, ) self.experiment3.save() # experiment4 will be accessible based on location information self.experiment4 = Experiment( title='Experiment4', institution_name='Australian Synchrotron', approved=True, public_access=Experiment.PUBLIC_ACCESS_NONE, created_by=self.user1, ) self.experiment4.save() # user1 owns experiment1 acl = ObjectACL( pluginId=django_user, entityId=str(self.user1.id), content_object=self.experiment1, canRead=True, isOwner=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) acl.save() # user2 owns experiment2 acl = ObjectACL( pluginId=django_user, entityId=str(self.user2.id), content_object=self.experiment2, canRead=True, isOwner=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) acl.save() # experiment4 is accessible via location acl = ObjectACL( pluginId='ip_address', entityId='127.0.0.1', content_object=self.experiment4, canRead=True, aclOwnershipType=ObjectACL.SYSTEM_OWNED, ) acl.save() def tearDown(self): self.experiment1.delete() self.experiment2.delete() self.experiment3.delete() self.experiment4.delete() self.user1.delete() self.user2.delete() self.user3.delete() self.user4.delete() self.client1.logout() self.client2.logout() self.client3.logout() self.client4.logout() def testChangeUserPermissions(self): login1 = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login1) login3 = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login3) # user1 should be see experiment1 response = self.client1.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user3 should not be able to see experiment1 response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # make the group1 a full read/write/owner of the experiment1 response = self.client1.get( '/experiment/control_panel/%i' '/access_list/add/group/%s/?canRead=true' '&canWrite=true&canDelete=false&isOwner=true' % (self.experiment1.id, 'group1')) self.assertEqual(response.status_code, 200) # ok, now do some tricky stuff today = datetime.datetime.today() yesterday = today - datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1) # add user3 to experiment1 response = self.client1.get( '/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) self.assertContains(response, '<div class="access_list_user') # check permissions for user3 - fail as canRead not set to True response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # give user3 read permissions for experiment1 effective TOMORROW url = ("/experiment/control_panel/%i/access_list" "/change/user/%s/?authMethod=%s") response = self.client1.post( url % (self.experiment1.id, self.user3.username, localdb_auth_key), { 'canRead': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) self.assertEqual(response.status_code, 302) # check permissions for user3 response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # user1 should be see experiment1 response = self.client1.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # give user3 read permissions for experiment1 effective YESTERDAY url = ("/experiment/control_panel/%i/access_list" "/change/user/%s/?authMethod=%s") response = self.client1.post( url % (self.experiment1.id, self.user3.username, localdb_auth_key), { 'canRead': True, 'effectiveDate_year': yesterday.year, 'effectiveDate_month': yesterday.month, 'effectiveDate_day': yesterday.day, }) self.assertEqual(response.status_code, 302) # check permissions for user3 response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) def testReadAccess(self): login = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login) # user1 should be see experiment1 response = self.client1.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user1 should not be allowed to see experiment2 response = self.client1.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # user1 should be allowed to see experiment3 as it's public response = self.client1.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user1 should be allowed to see experiment4 based on his IP address # response = self.client1.get('/experiment/view/%i/' # % (self.experiment4.id)) # self.assertEqual(response.status_code, 200) # create a group and add it to experiment1 response = self.client1.get( '/experiment/control_panel' '/create/group/?group=%s&authMethod=localdb' % ('group1')) self.assertEqual(response.status_code, 200) # make the group1 a full read/write/owner of the experiment1 response = self.client1.get( '/experiment/control_panel/%i' '/access_list/add/group/%s/?canRead=true' '&canWrite=true&canDelete=false&isOwner=true' % (self.experiment1.id, 'group1')) self.assertEqual(response.status_code, 200) # add user2 as admin to the newly created group1 group = Group.objects.get(name='group1') response = self.client1.get( '/group/%i/add/%s/?isAdmin=true&authMethod=%s' % (group.id, self.user2.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # try it again response = self.client1.get( '/group/%i/add/%s/?isAdmin=true&authMethod=%s' % (group.id, self.user2.username, localdb_auth_key)) self.assertEqual( response.content, 'User %s is already member of that' ' group.' % self.user2.username) # user1 is not allowed to modify acls for experiment2 response = self.client1.get( '/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment2.id, self.user1.username, localdb_auth_key)) self.assertEqual(response.status_code, 403) # user2 *IS* allowed to modify acls for experiment1, since they are part # of an owning group (we add then remove access for user3) response = self.client1.get( '/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) response = self.client1.get( '/experiment/control_panel/%i/access_list' '/remove/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'OK') # test add non-existent user non_existant = 'test_boozer' response = self.client1.get( '/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment1.id, non_existant, localdb_auth_key)) self.assertContains(response, 'User %s does not exist' % non_existant) # test add to non existant experiment # Note: Ideally we'd like to check for error message, but we # can't hit it with the decorator in place. However, # currently we check for a 403 (forbidden) error, as the # 'experiment_ownership_required' decorator simply checks if # the experiment_id appears in the specified user's ACL, and # assumes that the absence of the experiment_id means that the # experiment exists but the user doesn't have access to # it. This could possibly be changed to a 404 error. response = self.client1.get( '/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (9999, self.user1.username, localdb_auth_key)) self.assertEqual(response.status_code, 403) self.client1.logout() # now check user2's permissions login = self.client2.login(username=self.user2.username, password='******') self.assertTrue(login) # user2 should be able to see experiment1 now response = self.client2.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user2 should be also able to see experiment2 response = self.client2.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 200) # user2 should be allowed to see experiment3 as it's public response = self.client2.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user2 should be able to add user3 to group1 (experiment1) response = self.client2.get( '/group/%i/add/%s/?isAdmin=false&authMethod=%s' % (group.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) self.client2.logout() # now check user3's permissions login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) # user3 should be able to see experiment1 via his group permissions response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user3 should not be able to see experiment2 response = self.client3.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # user3 should be able to see experiment3 response = self.client3.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user3 should not be able to add another user4 to group1 response = self.client3.get( '/group/%i/add/%s/?isAdmin=false&authMethod=%s' % (group.id, 'testuser4', localdb_auth_key)) self.assertEqual(response.status_code, 403) self.client3.logout() # ok, now do some tricky stuff today = datetime.datetime.today() yesterday = today - datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1) url = ("/experiment/control_panel/%i/access_list" "/change/user/%s/?authMethod=%s") login = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login) # remove user3 from group1 response = self.client1.get('/group/%i/remove/%s/' % (group.id, self.user3.username)) self.assertEqual(response.status_code, 200) # add user3 to experiment1 response = self.client1.get( '/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) self.assertContains(response, '<div class="access_list_user') # give user3 read permissions for experiment1 effective TOMORROW response = self.client1.post( url % (self.experiment1.id, self.user3.username, localdb_auth_key), { 'canRead': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) # logger.debug('[1] response =' + str(response)) self.assertEqual(response.status_code, 302) # check permissions for user3 login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # change effective date to TODAY response = self.client1.post( url % (self.experiment1.id, self.user3.username, localdb_auth_key), { 'canRead': True, 'effectiveDate_year': today.year, 'effectiveDate_month': today.month, 'effectiveDate_day': today.day, }) self.assertEqual(response.status_code, 302) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # change effictive date to YESTERDAY self.client1.post( url % (self.experiment1.id, self.user3.username, localdb_auth_key), { 'canRead': True, 'effectiveDate_year': yesterday.year, 'effectiveDate_month': yesterday.month, 'effectiveDate_day': yesterday.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to TOMORROW self.client1.post( url % (self.experiment1.id, self.user3.username, localdb_auth_key), { 'canRead': True, 'expiryDate_year': tomorrow.year, 'expiryDate_month': tomorrow.month, 'expiryDate_day': tomorrow.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to TODAY self.client1.post( url % (self.experiment1.id, self.user3.username, localdb_auth_key), { 'canRead': True, 'expiryDate_year': today.year, 'expiryDate_month': today.month, 'expiryDate_day': today.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to YESTERDAY self.client1.post( url % (self.experiment1.id, self.user3.username, localdb_auth_key), { 'canRead': True, 'expiryDate_year': yesterday.year, 'expiryDate_month': yesterday.month, 'expiryDate_day': yesterday.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # remove user3 from experiment1 again response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (self.experiment1.id, self.user3.username)) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'OK') # try again, see if it falls over response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (self.experiment1.id, self.user3.username)) self.assertEqual( response.content, 'The user %s does not have access to this experiment.' % self.user3.username) # try to remove from a non-existant experiment response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (9999, self.user3.username)) self.assertEqual(response.status_code, 403) # try to remove the only owner response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (self.experiment1.id, self.user1.username)) self.assertEqual( response.content, 'All experiments must have at least ' 'one user as owner. Add an ' 'additional owner first before ' 'removing this one.') # create a group2 and add it to experiment1 response = self.client1.get( '/experiment/control_panel' '/create/group/?group=%s&authMethod=localdb' % ('group2')) self.assertEqual(response.status_code, 200) # give group2 read-only access to experiment1 response = self.client1.get( '/experiment/control_panel/%i' '/access_list/add/group/%s/?canRead=true' '&canWrite=false&canDelete=false&isOwner=false' % (self.experiment1.id, 'group2')) self.assertEqual(response.status_code, 200) # add user3 as admin to group2 self.group2 = Group.objects.get(name='group2') response = self.client1.get( '/group/%i/add/%s/?isAdmin=true&authMethod=%s' % (self.group2.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # as user3, try to add myself as an owner of the experiment1 response = self.client3.get( '/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s&canRead=true' '&canWrite=true&canDelete=false&' 'isOwner=true' % (self.experiment1.id, self.user3.username, localdb_auth_key)) # this should fail since the group2, of which user3 is a member, is # not an 'owner' group, just a read-only group self.assertEqual(response.status_code, 403) # as user3, attempt to remove user1 as the owner of experiment1 response = self.client3.get( '/experiment/control_panel/%i/access_list' '/remove/user/%s/?authMethod=%s' % (self.experiment1.id, self.user1.username, localdb_auth_key)) # this should fail since the group2, of which user3 is a member, is # not an 'owner' group, just a read-only group self.assertEqual(response.status_code, 403) # as user1, add user3 as an owner of experiment1 response = self.client1.get( '/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s&canRead=true' '&canWrite=true&canDelete=false&' 'isOwner=true' % (self.experiment1.id, self.user3.username, localdb_auth_key)) # since user1 is an owner user of experiment1, we can add additional # owner users to the experiment self.assertEqual(response.status_code, 200) # as user3 (now an owner), attempt to remove user1 as the owner of # experiment1, leaving user3 as the sole owner response = self.client3.get( '/experiment/control_panel/%i/access_list' '/remove/user/%s/?authMethod=%s' % (self.experiment1.id, self.user1.username, localdb_auth_key)) # this should now succeed since both user3 and user1 are owners of # experiment1, and user3 is allowed to remove other owners (unless they # are the only owner user) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'OK') # as user3 (now the only owner), attempts to remove myself as the owner # of experiment1 response = self.client3.get( '/experiment/control_panel/%i/access_list' '/remove/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) # this should fail with an error since every experiment must have at # least one user owner self.assertEqual( response.content, 'All experiments must have at least one user as ' 'owner. Add an additional owner first before ' 'removing this one.') self.client1.logout() self.client3.logout() def testWriteAccess(self): # without logging in the request should be redirected response = self.client1.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 302) # now check access for user1 login = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login) response = self.client1.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # write access has not been granted for experiment2 response = self.client1.get('/experiment/edit/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # neither experiment3 which is public response = self.client1.get('/experiment/edit/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 403) # create a group 'group1w' with write permissions response = self.client1.get( '/experiment/control_panel' '/create/group/?group=%s&authMethod=localdb' % ('group1w')) self.assertEqual(response.status_code, 200) response = self.client1.get( '/experiment/control_panel/%i' '/access_list/add/group/%s/?canRead=true' '&canWrite=true&canDelete=false&isOwner=undefined' % (self.experiment1.id, 'group1w')) self.assertEqual(response.status_code, 200) # add user2 to 'group1w' which gives him write permissions group = Group.objects.get(name='group1w') response = self.client1.get( '/group/%i/add/%s/?isAdmin=false&authMethod=%s' % (group.id, self.user2.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # add user3 explicitly to experiment1 response = self.client1.get( '/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s&canRead=true' '&canWrite=true' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # check newly created permissions for user2 and user3 response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 302) response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 302) login = self.client2.login(username=self.user2.username, password='******') self.assertTrue(login) login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) # response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) # self.assertEqual(response.status_code, 200) response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # now the fancy stuff with timestamps today = datetime.datetime.today() yesterday = today - datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1) url = '/experiment/control_panel/%i/access_list/change/group/%i/' # give group 'group1w' write permissions for experiment1 effictive TOMORROW response = self.client1.post( url % (self.experiment1.id, group.id), { 'canRead': True, 'canWrite': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) self.assertEqual(response.status_code, 302) response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # change effictive date to TODAY response = self.client1.post( url % (self.experiment1.id, group.id), { 'canRead': True, 'canWrite': True, 'effectiveDate_year': today.year, 'effectiveDate_month': today.month, 'effectiveDate_day': today.day, }) self.assertEqual(response.status_code, 302) # now user2 should have write access again response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # repeat all the tests with timestamps for user3 url = '/experiment/control_panel/%i/access_list/change/user/%s/' # give user3 write permissions for experiment1 effictive TOMORROW response = self.client1.post( url % (self.experiment1.id, self.user3.username), { 'canRead': True, 'canWrite': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) self.assertEqual(response.status_code, 302) response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # change effictive date to TODAY response = self.client1.post( url % (self.experiment1.id, self.user3.username), { 'canRead': True, 'canWrite': True, 'effectiveDate_year': today.year, 'effectiveDate_month': today.month, 'effectiveDate_day': today.day, }) self.assertEqual(response.status_code, 302) # now user3 should have write access again response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) self.client1.logout() self.client2.logout() self.client3.logout() def testCantEditLockedExperiment(self): login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) # user3 has acl to write to experiment3 acl = ObjectACL( pluginId=django_user, entityId=str(self.user3.id), content_object=self.experiment3, canRead=True, canWrite=True, aclOwnershipType=ObjectACL.OWNER_OWNED, ) acl.save() response = self.client3.get('/experiment/edit/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 403) response = self.client3.post( '/experiment/edit/%i/' % (self.experiment3.id), { 'anything': True, }) self.assertEqual(response.status_code, 403) acl.delete() self.client3.logout() def testOwnedExperiments(self): user = AnonymousUser() # not logged in class MockRequest: pass request = MockRequest() request.user = user num_exps = Experiment.safe.owned(request.user).count() self.assertEqual(num_exps, 0) def testCantAddTokenuserToGroups(self): from django.conf import settings login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) g = Group() g.save() self.client3.get('/group/%s/%s/' % (g.id, settings.TOKEN_USERNAME)) self.assertEqual(0, g.user_set.count()) # user should not be added
class UploadTestCase(TestCase): def setUp(self): from os import path, mkdir from tempfile import mkdtemp user = '******' pwd = 'secret' email = '' self.user = User.objects.create_user(user, email, pwd) self.userProfile = UserProfile(user=self.user) self.test_dir = mkdtemp() self.exp = Experiment(title='test exp1', institution_name='monash', created_by=self.user) self.exp.save() acl = ExperimentACL( pluginId=django_user, entityId=str(self.user.id), experiment=self.exp, canRead=True, isOwner=True, aclOwnershipType=ExperimentACL.OWNER_OWNED, ) acl.save() self.dataset = \ Dataset(description='dataset description...', experiment=self.exp) self.dataset.save() self.experiment_path = path.join(settings.FILE_STORE_PATH, str(self.dataset.experiment.id)) self.dataset_path = path.join(self.experiment_path, str(self.dataset.id)) if not path.exists(self.experiment_path): mkdir(self.experiment_path) if not path.exists(self.dataset_path): mkdir(self.dataset_path) # write test file self.filename = 'testfile.txt' self.f1 = open(path.join(self.test_dir, self.filename), 'w') self.f1.write('Test file 1') self.f1.close() self.f1_size = path.getsize(path.join(self.test_dir, self.filename)) self.f1 = open(path.join(self.test_dir, self.filename), 'r') def tearDown(self): from shutil import rmtree self.f1.close() rmtree(self.test_dir) rmtree(self.dataset_path) rmtree(self.experiment_path) self.exp.delete() def testFileUpload(self): from os import path c = Client() c.login(username='******', password='******') session_id = c.session.session_key response = c.post('/upload/' + str(self.dataset.id) + '/', {'Filedata': self.f1, 'session_id': session_id}) test_files_db = \ Dataset_File.objects.filter(dataset__id=self.dataset.id) self.assertTrue(path.exists(path.join(self.dataset_path, self.filename))) self.assertTrue(self.dataset.id == 1) self.assertTrue(test_files_db[0].url == 'tardis://testfile.txt') def testUploadComplete(self): from django.http import QueryDict, HttpRequest from tardis.tardis_portal.views import upload_complete data = [('filesUploaded', '1'), ('speed', 'really fast!'), ('allBytesLoaded', '2'), ('errorCount', '0')] post = QueryDict('&'.join(['%s=%s' % (k, v) for (k, v) in data])) request = HttpRequest() request.POST = post response = upload_complete(request) self.assertTrue('<p>Number: 1</p>' in response.content) self.assertTrue('<p>Errors: 0</p>' in response.content) self.assertTrue('<p>Bytes: 2</p>' in response.content) self.assertTrue('<p>Speed: really fast!</p>' in response.content)
class TarDownloadTestCase(TestCase): def setUp(self): # create user self.testuser = User(username='******') self.testuser.save() # create test experiment self.exp = Experiment(title='tar download test' * 15, created_by=self.testuser, public_access=Experiment.PUBLIC_ACCESS_FULL) self.exp.save() # create test dataset self.ds = self.exp.datasets.create( description="testing tar download dataset") datafile_content = "\n".join(['some data %d' % i for i in range(1000)]) filesize = len(datafile_content) md5sum = hashlib.md5(datafile_content).hexdigest() # create test datafiles and datafile objects self.dfs = [] for i in range(20): df = self.ds.datafile_set.create( filename='testfile%d.txt' % i, mimetype='text/plain', size=filesize, md5sum=md5sum, directory='/'.join([ 'testdir%d' % i for i in range(i, i + 4) ])) df.file_object = StringIO(datafile_content) df.refresh_from_db() self.dfs.append(df) # mock client self.client = Client() def tearDown(self): # delete created objects and files [ds.delete() for ds in self.exp.datasets.all()] self.exp.delete() def test_tar_experiment_download(self): self.assertTrue(all(df.verified for df in self.dfs)) response = self.client.get(reverse( 'tardis.tardis_portal.download.streaming_download_experiment', args=(self.exp.id, 'tar'))) with NamedTemporaryFile('w') as tarfile: for c in response.streaming_content: tarfile.write(c) tarfile.flush() self.assertEqual(int(response['Content-Length']), os.stat(tarfile.name).st_size) tf = TarFile(tarfile.name) if settings.EXP_SPACES_TO_UNDERSCORES: exp_title = self.exp.title.replace(' ', '_') else: exp_title = self.exp.title exp_title = quote(exp_title, safe=settings.SAFE_FILESYSTEM_CHARACTERS) for df in self.dfs: full_path = os.path.join( exp_title, quote(self.ds.description, safe=settings.SAFE_FILESYSTEM_CHARACTERS), df.directory, df.filename) # docker has a file path limit of ~240 characters if os.environ.get('DOCKER_BUILD', 'false') != 'true': tf.extract(full_path, '/tmp') self.assertEqual( os.stat(os.path.join('/tmp', full_path)).st_size, int(df.size))
class DownloadTestCase(TestCase): def setUp(self): # create a test user self.user = User.objects.create_user(username='******', email='', password='******') # create a public experiment self.experiment1 = Experiment(title='Experiment 1', created_by=self.user, public=True) self.experiment1.save() # create a non-public experiment self.experiment2 = Experiment(title='Experiment 2', created_by=self.user, public=False) self.experiment2.save() # dataset1 belongs to experiment1 self.dataset1 = Dataset(experiment=self.experiment1) self.dataset1.save() # dataset2 belongs to experiment2 self.dataset2 = Dataset(experiment=self.experiment2) self.dataset2.save() # absolute path first filename = 'testfile.txt' self.dest1 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment1.id, self.dataset1.id))) self.dest2 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment2.id, self.dataset2.id))) if not exists(self.dest1): makedirs(self.dest1) if not exists(self.dest2): makedirs(self.dest2) testfile1 = abspath(join(self.dest1, filename)) f = open(testfile1, 'w') f.write("Hello World!\n") f.close() testfile2 = abspath(join(self.dest2, filename)) f = open(testfile2, 'w') f.write("Hello World!\n") f.close() self.dataset_file1 = Dataset_File(dataset=self.dataset1, filename=filename, protocol='tardis', url='tardis://%s' % filename) self.dataset_file1.save() self.dataset_file2 = Dataset_File(dataset=self.dataset2, filename=basename(filename), protocol='tardis', url='tardis://%s' % filename) self.dataset_file2.save() def tearDown(self): self.user.delete() self.experiment1.delete() self.experiment2.delete() rmtree(self.dest1) rmtree(self.dest2) def testDownload(self): client = Client() # check download for experiment1 response = client.get('/download/experiment/%i/zip/' % self.experiment1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="experiment%s-complete.zip"' % self.experiment1.id) self.assertEqual(response.status_code, 200) # check download of file1 response = client.get('/download/datafile/%i/' % self.dataset_file1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s"' % self.dataset_file2.filename) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'Hello World!\n') # requesting file2 should be forbidden... response = client.get('/download/datafile/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 403) # check dataset1 download response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': []}) self.assertEqual(response.status_code, 200) # check dataset2 download response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [self.dataset2.id], 'datafile': []}) self.assertEqual(response.status_code, 403) # check datafile1 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [], 'datafile': [self.dataset_file1.id]}) self.assertEqual(response.status_code, 200) # check datafile2 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [], 'datafile': [self.dataset_file2.id]}) self.assertEqual(response.status_code, 403) def testDatasetFile(self): # check registered text file for physical file meta information df = Dataset_File.objects.get(pk=self.dataset_file1.id) try: from magic import Magic self.assertEqual(df.mimetype, 'text/plain; charset=us-ascii') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(df.size, str(13)) self.assertEqual(df.md5sum, '8ddd8be4b179a529afa5f2ffae4b9858') # now check a JPG file filename = join(abspath(dirname(__file__)), '../static/images/ands-logo-hi-res.jpg') dataset = Dataset.objects.get(pk=self.dataset1.id) pdf1 = Dataset_File(dataset=dataset, filename=basename(filename), url='file://%s' % filename, protocol='file') pdf1.save() try: from magic import Magic self.assertEqual(pdf1.mimetype, 'image/jpeg') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(pdf1.size, str(14232)) self.assertEqual(pdf1.md5sum, 'c450d5126ffe3d14643815204daf1bfb') # now check that we can override the physical file meta information pdf2 = Dataset_File(dataset=dataset, filename=basename(filename), url='file://%s' % filename, protocol='file', mimetype='application/vnd.openxmlformats-officedocument.presentationml.presentation', size=str(0), md5sum='md5sum') pdf2.save() try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/vnd.openxmlformats-officedocument.presentationml.presentation') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(pdf2.size, str(0)) self.assertEqual(pdf2.md5sum, 'md5sum') pdf2.mimetype = '' pdf2.save() try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/pdf') except: # XXX Test disabled becuse lib magic can't be loaded pass
class DownloadTestCase(TestCase): def setUp(self): # create a test user self.user = User.objects.create_user(username='******', email='', password='******') # create a public experiment self.experiment1 = Experiment(title='Experiment 1', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_FULL) self.experiment1.save() # create a non-public experiment self.experiment2 = Experiment(title='Experiment 2', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_NONE) self.experiment2.save() # dataset1 belongs to experiment1 self.dataset1 = Dataset() self.dataset1.save() self.dataset1.experiments.add(self.experiment1) self.dataset1.save() # dataset2 belongs to experiment2 self.dataset2 = Dataset() self.dataset2.save() self.dataset2.experiments.add(self.experiment2) self.dataset2.save() # absolute path first filename1 = 'testfile.txt' filename2 = 'testfile.tiff' self.dest1 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment1.id, self.dataset1.id))) self.dest2 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment2.id, self.dataset2.id))) if not exists(self.dest1): makedirs(self.dest1) if not exists(self.dest2): makedirs(self.dest2) testfile1 = abspath(join(self.dest1, filename1)) f = open(testfile1, 'w') f.write("Hello World!\n") f.close() testfile2 = abspath(join(self.dest2, filename2)) if IMAGEMAGICK_AVAILABLE: with Image(filename='logo:') as img: img.format = 'tiff' img.save(filename=testfile2) else: # Apparently ImageMagick isn't installed... # Write a "fake" TIFF file f = open(testfile2, 'w') f.write("II\x2a\x00") f.close() size, sha512sum = get_size_and_sha512sum(testfile1) self.dataset_file1 = Dataset_File(dataset=self.dataset1, filename=filename1, protocol='', size=size, sha512sum=sha512sum, url='%d/%d/%s' % (self.experiment1.id, self.dataset1.id, filename1)) self.dataset_file1.verify() self.dataset_file1.save() size, sha512sum = get_size_and_sha512sum(testfile2) self.dataset_file2 = Dataset_File(dataset=self.dataset2, filename=basename(filename2), protocol='', size=size, sha512sum=sha512sum, url='%d/%d/%s' % (self.experiment2.id, self.dataset2.id, filename2)) self.dataset_file2.verify() self.dataset_file2.save() def tearDown(self): self.user.delete() self.experiment1.delete() self.experiment2.delete() rmtree(self.dest1) rmtree(self.dest2) def testView(self): client = Client() # check view of file1 response = client.get('/datafile/view/%i/' % self.dataset_file1.id) self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % self.dataset_file1.filename) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'Hello World!\n') # check view of file2 response = client.get('/datafile/view/%i/' % self.dataset_file2.id) # Should be forbidden self.assertEqual(response.status_code, 403) self.experiment2.public_access=Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() # check view of file2 again response = client.get('/datafile/view/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 200) # The following behaviour relies on ImageMagick if IMAGEMAGICK_AVAILABLE: # file2 should have a ".png" filename self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % (self.dataset_file2.filename+'.png')) # file2 should be a PNG self.assertEqual(response['Content-Type'], 'image/png') png_signature = "\x89PNG\r\n\x1a\n" self.assertEqual(response.content[0:8], png_signature) else: # file2 should have a ".tiff" filename self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % (self.dataset_file2.filename)) # file2 should be a TIFF self.assertEqual(response['Content-Type'], 'image/tiff') tiff_signature = "II\x2a\x00" self.assertEqual(response.content[0:4], tiff_signature) def _check_tar_file(self, content, rootdir, datafiles): # It should be a zip file with NamedTemporaryFile('w') as tempfile: tempfile.write(content) tempfile.flush() with open(tempfile.name, 'r') as zipread: # It should be a zip file (all of which start with "PK") expect(zipread.read(2)).to_equal('PK') expect(is_zipfile(tempfile.name)).to_be_truthy() with ZipFile(tempfile.name, 'r') as zf: expect(len(zf.namelist())).to_equal(len(datafiles)) for df in datafiles: filename = join(rootdir, str(df.dataset.id), df.filename) expect(filename in zf.namelist()).to_be_truthy() def _check_zip_file(self, content, rootdir, datafiles): # It should be a zip file with NamedTemporaryFile('w') as tempfile: tempfile.write(content) tempfile.flush() with open(tempfile.name, 'r') as zipread: # It should be a zip file (all of which start with "PK") expect(zipread.read(2)).to_equal('PK') expect(is_zipfile(tempfile.name)).to_be_truthy() zf = ZipFile(tempfile.name, 'r') expect(len(zf.namelist())).to_equal(len(datafiles)) for df in datafiles: filename = join(rootdir, str(df.dataset.id), df.filename) expect(filename in zf.namelist()).to_be_truthy() zf.close() def testDownload(self): client = Client() # check download for experiment1 response = client.get('/download/experiment/%i/zip/' % self.experiment1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="experiment%s-complete.zip"' % self.experiment1.id) self.assertEqual(response.status_code, 200) self._check_zip_file(response.content, str(self.experiment1.id), reduce(lambda x, y: x + y, [ds.dataset_file_set.all() \ for ds in self.experiment1.datasets.all()])) # check download of file1 response = client.get('/download/datafile/%i/' % self.dataset_file1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s"' % self.dataset_file1.filename) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'Hello World!\n') # requesting file2 should be forbidden... response = client.get('/download/datafile/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 403) # check dataset1 download response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': []}) self.assertEqual(response.status_code, 200) self._check_zip_file(response.content, 'datasets', self.dataset1.dataset_file_set.all()) # check dataset2 download response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [self.dataset2.id], 'datafile': []}) self.assertEqual(response.status_code, 403) # check datafile1 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [], 'datafile': [self.dataset_file1.id]}) self.assertEqual(response.status_code, 200) self._check_zip_file(response.content, 'datasets', [self.dataset_file1]) # check datafile2 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [], 'datafile': [self.dataset_file2.id]}) self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to "metadata only" self.experiment2.public_access=Experiment.PUBLIC_ACCESS_METADATA self.experiment2.save() response = client.get('/download/datafile/%i/' % self.dataset_file2.id) # Metadata-only means "no file access"! self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to public self.experiment2.public_access=Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() response = client.get('/download/datafile/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 200) # This should be a TIFF (which often starts with "II\x2a\x00") self.assertEqual(response['Content-Type'], 'image/tiff') self.assertEqual(response.content[0:4], "II\x2a\x00") def testDatasetFile(self): # check registered text file for physical file meta information df = Dataset_File.objects.get(pk=self.dataset_file1.id) try: from magic import Magic self.assertEqual(df.mimetype, 'text/plain; charset=us-ascii') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(df.size, str(13)) self.assertEqual(df.md5sum, '8ddd8be4b179a529afa5f2ffae4b9858') # now check a JPG file filename = abspath(join(dirname(__file__), '../static/images/ands-logo-hi-res.jpg')) dataset = Dataset.objects.get(pk=self.dataset1.id) size, sha512sum = get_size_and_sha512sum(filename) pdf1 = Dataset_File(dataset=dataset, filename=basename(filename), size=str(size), sha512sum=sha512sum, url='file://%s' % filename, protocol='file') pdf1.verify() pdf1.save() try: from magic import Magic self.assertEqual(pdf1.mimetype, 'image/jpeg') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(pdf1.size, str(14232)) self.assertEqual(pdf1.md5sum, 'c450d5126ffe3d14643815204daf1bfb') # now check that we can override the physical file meta information pdf2 = Dataset_File(dataset=dataset, filename=basename(filename), url='file://%s' % filename, protocol='file', mimetype='application/vnd.openxmlformats-officedocument.presentationml.presentation', size=str(0), # Empty string always has the same hash sha512sum='cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e') pdf2.save() try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/vnd.openxmlformats-officedocument.presentationml.presentation') except: # XXX Test disabled becuse lib magic can't be loaded pass self.assertEqual(pdf2.size, str(0)) self.assertEqual(pdf2.md5sum, '') pdf2.mimetype = '' pdf2.save() try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/pdf') except: # XXX Test disabled becuse lib magic can't be loaded pass
class DownloadTestCase(TestCase): def setUp(self): # create a test user self.user = User.objects.create_user(username='******', email='', password='******') # create a public experiment self.experiment1 = Experiment( title='Experiment 1', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_FULL) self.experiment1.save() # create a non-public experiment self.experiment2 = Experiment( title='Experiment 2', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_NONE) self.experiment2.save() # dataset1 belongs to experiment1 self.dataset1 = Dataset(description='dangerous;name') self.dataset1.save() self.dataset1.experiments.add(self.experiment1) self.dataset1.save() # dataset2 belongs to experiment2 self.dataset2 = Dataset(description='terrible\nname') self.dataset2.save() self.dataset2.experiments.add(self.experiment2) self.dataset2.save() # absolute path first filename1 = 'testfile.txt' filename2 = 'testfile.tiff' self.dest1 = abspath( join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment1.id, self.dataset1.id))) self.dest2 = abspath( join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment2.id, self.dataset2.id))) if not exists(self.dest1): makedirs(self.dest1) if not exists(self.dest2): makedirs(self.dest2) testfile1 = abspath(join(self.dest1, filename1)) f = open(testfile1, 'w') f.write("Hello World!\n") f.close() testfile2 = abspath(join(self.dest2, filename2)) _generate_test_image(testfile2) self.datafile1 = self._build_datafile(testfile1, filename1, self.dataset1) self.datafile2 = self._build_datafile(testfile2, filename2, self.dataset2) def _build_datafile(self, testfile, filename, dataset, checksum=None, size=None, mimetype=''): filesize, sha512sum = get_size_and_sha512sum(testfile) datafile = DataFile(dataset=dataset, filename=filename, mimetype=mimetype, size=size if size is not None else filesize, sha512sum=(checksum if checksum else sha512sum)) datafile.save() dfo = DataFileObject(datafile=datafile, storage_box=datafile.get_default_storage_box()) dfo.save() with open(testfile, 'r') as sourcefile: dfo.file_object = sourcefile return DataFile.objects.get(pk=datafile.pk) def tearDown(self): self.user.delete() self.experiment1.delete() self.experiment2.delete() rmtree(self.dest1) rmtree(self.dest2) def testView(self): client = Client() # check view of file1 response = client.get('/datafile/view/%i/' % self.datafile1.id) self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % self.datafile1.filename) self.assertEqual(response.status_code, 200) response_content = "" for c in response.streaming_content: response_content += c self.assertEqual(response_content, 'Hello World!\n') # check view of file2 response = client.get('/datafile/view/%i/' % self.datafile2.id) # Should be forbidden self.assertEqual(response.status_code, 403) self.experiment2.public_access = Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() # check view of file2 again response = client.get('/datafile/view/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 200) # The following behaviour relies on ImageMagick if IMAGEMAGICK_AVAILABLE: # file2 should have a ".png" filename self.assertEqual( response['Content-Disposition'], 'inline; filename="%s"' % (self.datafile2.filename + '.png')) # file2 should be a PNG self.assertEqual(response['Content-Type'], 'image/png') png_signature = "\x89PNG\r\n\x1a\n" self.assertEqual(response.content[0:8], png_signature) else: # file2 should have a ".tiff" filename self.assertEqual( response['Content-Disposition'], 'inline; filename="%s"' % (self.datafile2.filename)) # file2 should be a TIFF self.assertEqual(response['Content-Type'], 'image/tiff') tiff_signature = "II\x2a\x00" self.assertEqual(response.content[0:4], tiff_signature) def _check_tar_file(self, content, rootdir, datafiles, simpleNames=False, noTxt=False): with NamedTemporaryFile('w') as tempfile: for c in content: tempfile.write(c) tempfile.flush() if getsize(tempfile.name) > 0: expect(is_tarfile(tempfile.name)).to_be_truthy() try: tf = TarFile(tempfile.name, 'r') self._check_names(datafiles, tf.getnames(), rootdir, simpleNames, noTxt) finally: tf.close() else: self._check_names(datafiles, [], rootdir, simpleNames, noTxt) def _check_zip_file(self, content, rootdir, datafiles, simpleNames=False, noTxt=False): with NamedTemporaryFile('w') as tempfile: for c in content: tempfile.write(c) tempfile.flush() # It should be a zip file expect(is_zipfile(tempfile.name)).to_be_truthy() try: zf = ZipFile(tempfile.name, 'r') self._check_names(datafiles, zf.namelist(), rootdir, simpleNames, noTxt) finally: zf.close() def _check_names(self, datafiles, names, rootdir, simpleNames, noTxt): # SimpleNames says if we expect basenames or pathnames # NoTxt says if we expect '.txt' files to be filtered out for name in names: self.assertNotRegexpMatches(name, '\n|;') expect(len(names)).to_equal(len(datafiles)) def testDownload(self): client = Client() # check download for experiment1 as tar response = client.get('/download/experiment/%i/tar/' % self.experiment1.id) self.assertEqual( response['Content-Disposition'], 'attachment; filename="%s-complete.tar"' % self.experiment1.title.replace(' ', '_')) self.assertEqual(response.status_code, 200) self._check_tar_file( response.streaming_content, str(self.experiment1.title.replace(' ', '_')), reduce(lambda x, y: x + y, [ ds.datafile_set.all() for ds in self.experiment1.datasets.all() ])) # check download of file1 response = client.get('/download/datafile/%i/' % self.datafile1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s"' % self.datafile1.filename) self.assertEqual(response.status_code, 200) response_content = "" for c in response.streaming_content: response_content += c self.assertEqual(response_content, 'Hello World!\n') # requesting file2 should be forbidden... response = client.get('/download/datafile/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 403) # check dataset1 download as tar response = client.post( '/download/datafiles/', { 'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': [], 'comptype': 'tar' }) self.assertEqual(response.status_code, 200) self._check_tar_file(response.streaming_content, 'Experiment 1-selection', self.dataset1.datafile_set.all()) # check dataset2 download response = client.post( '/download/datafiles/', { 'expid': self.experiment2.id, 'dataset': [self.dataset2.id], 'datafile': [] }) self.assertEqual(response.status_code, 403) # check datafile1 download via POST response = client.post( '/download/datafiles/', { 'expid': self.experiment1.id, 'dataset': [], 'datafile': [self.datafile1.id] }) self.assertEqual(response.status_code, 200) self._check_tar_file(response.streaming_content, 'Experiment 1-selection', [self.datafile1]) # check datafile2 download via POST response = client.post( '/download/datafiles/', { 'expid': self.experiment2.id, 'dataset': [], 'datafile': [self.datafile2.id] }) self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to "metadata only" self.experiment2.public_access = Experiment.PUBLIC_ACCESS_METADATA self.experiment2.save() response = client.get('/download/datafile/%i/' % self.datafile2.id) # Metadata-only means "no file access"! self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to public self.experiment2.public_access = Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() response = client.get('/download/datafile/%i/' % self.datafile2.id) self.assertEqual(response.status_code, 200) # This should be a TIFF (which often starts with "II\x2a\x00") self.assertEqual(response['Content-Type'], 'image/tiff') response_content = "" for c in response.streaming_content: response_content += c self.assertEqual(response_content[0:4], "II\x2a\x00") # check experiment tar download with alternative organization response = client.get('/download/experiment/%i/tar/' % self.experiment1.id) self.assertEqual(response.status_code, 200) self.assertEqual( response['Content-Disposition'], 'attachment; filename="%s-complete.tar"' % self.experiment1.title.replace(' ', '_')) self._check_tar_file(response.streaming_content, str(self.experiment1.id), reduce(lambda x, y: x + y, [ ds.datafile_set.all() for ds in self.experiment1.datasets.all() ]), simpleNames=True) # check experiment1 download with '.txt' filtered out (none left) response = client.get('/download/experiment/%i/tar/' % self.experiment1.id) self.assertEqual(response.status_code, 200) # check experiment2 download with '.txt' filtered out response = client.get('/download/experiment/%i/tar/' % self.experiment2.id) self.assertEqual(response.status_code, 200) self.assertEqual( response['Content-Disposition'], 'attachment; filename="%s-complete.tar"' % self.experiment2.title.replace(' ', '_')) self._check_tar_file(response.streaming_content, str(self.experiment2.id), reduce(lambda x, y: x + y, [ ds.datafile_set.all() for ds in self.experiment2.datasets.all() ]), simpleNames=True, noTxt=True) def testDatasetFile(self): # check registered text file for physical file meta information df = DataFile.objects.get(pk=self.datafile1.id) # skipping test # noqa # pylint: disable=W0101 try: from magic import Magic self.assertEqual(df.mimetype, 'text/plain; charset=us-ascii') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(df.size, 13) self.assertEqual(df.md5sum, '8ddd8be4b179a529afa5f2ffae4b9858') # Now check we can calculate checksums and infer the mime type # for a JPG file. filename = 'tardis/tardis_portal/tests/test_data/ands-logo-hi-res.jpg' dataset = Dataset.objects.get(pk=self.dataset1.id) pdf1 = self._build_datafile(filename, basename(filename), dataset) self.assertEqual(pdf1.file_objects.get().verify(), True) pdf1 = DataFile.objects.get(pk=pdf1.pk) try: from magic import Magic # noqa self.assertEqual(pdf1.mimetype, 'image/jpeg') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(pdf1.size, 14232) self.assertEqual(pdf1.md5sum, 'c450d5126ffe3d14643815204daf1bfb') # Now check that we can override the physical file meta information # We are setting size/checksums that don't match the actual file, so # the pdf2 = self._build_datafile( filename, filename, dataset, checksum= 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', size=0, mimetype= 'application/vnd.openxmlformats-officedocument.presentationml.presentation' ) # noqa self.assertEqual(pdf2.size, 0) self.assertEqual(pdf2.md5sum, '') self.assertEqual(pdf2.file_objects.get().verified, False) pdf2 = DataFile.objects.get(pk=pdf2.pk) try: from magic import Magic # noqa self.assertEqual( pdf2.mimetype, 'application/vnd.openxmlformats-officedocument.presentationml.presentation' ) # noqa except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(pdf2.size, 0) self.assertEqual(pdf2.md5sum, '') pdf2.mimetype = '' pdf2.save() pdf2.file_objects.get().save() pdf2 = DataFile.objects.get(pk=pdf2.pk) try: from magic import Magic # noqa self.assertEqual(pdf2.mimetype, 'application/pdf') except: # XXX Test disabled because lib magic can't be loaded pass
class DownloadTestCase(TestCase): def setUp(self): # create a test user self.user = User.objects.create_user(username='******', email='', password='******') # create a public experiment self.experiment1 = Experiment(title='Experiment 1', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_FULL) self.experiment1.save() # create a non-public experiment self.experiment2 = Experiment(title='Experiment 2', created_by=self.user, public_access=Experiment.PUBLIC_ACCESS_NONE) self.experiment2.save() # dataset1 belongs to experiment1 self.dataset1 = Dataset() self.dataset1.save() self.dataset1.experiments.add(self.experiment1) self.dataset1.save() # dataset2 belongs to experiment2 self.dataset2 = Dataset() self.dataset2.save() self.dataset2.experiments.add(self.experiment2) self.dataset2.save() # absolute path first filename1 = 'testfile.txt' filename2 = 'testfile.tiff' self.dest1 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment1.id, self.dataset1.id))) self.dest2 = abspath(join(settings.FILE_STORE_PATH, '%s/%s/' % (self.experiment2.id, self.dataset2.id))) if not exists(self.dest1): makedirs(self.dest1) if not exists(self.dest2): makedirs(self.dest2) testfile1 = abspath(join(self.dest1, filename1)) f = open(testfile1, 'w') f.write("Hello World!\n") f.close() testfile2 = abspath(join(self.dest2, filename2)) _generate_test_image(testfile2) size, sha512sum = get_size_and_sha512sum(testfile1) self.dataset_file1 = Dataset_File(dataset=self.dataset1, filename=filename1, protocol='', size=size, sha512sum=sha512sum, url='%d/%d/%s' % (self.experiment1.id, self.dataset1.id, filename1)) self.dataset_file1.verify() self.dataset_file1.save() size, sha512sum = get_size_and_sha512sum(testfile2) self.dataset_file2 = Dataset_File(dataset=self.dataset2, filename=basename(filename2), protocol='', size=size, sha512sum=sha512sum, url='%d/%d/%s' % (self.experiment2.id, self.dataset2.id, filename2)) self.dataset_file2.verify() self.dataset_file2.save() def tearDown(self): self.user.delete() self.experiment1.delete() self.experiment2.delete() rmtree(self.dest1) rmtree(self.dest2) def testView(self): client = Client() # check view of file1 response = client.get('/datafile/view/%i/' % self.dataset_file1.id) self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % self.dataset_file1.filename) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'Hello World!\n') # check view of file2 response = client.get('/datafile/view/%i/' % self.dataset_file2.id) # Should be forbidden self.assertEqual(response.status_code, 403) self.experiment2.public_access=Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() # check view of file2 again response = client.get('/datafile/view/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 200) # The following behaviour relies on ImageMagick if IMAGEMAGICK_AVAILABLE: # file2 should have a ".png" filename self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % (self.dataset_file2.filename+'.png')) # file2 should be a PNG self.assertEqual(response['Content-Type'], 'image/png') png_signature = "\x89PNG\r\n\x1a\n" self.assertEqual(response.content[0:8], png_signature) else: # file2 should have a ".tiff" filename self.assertEqual(response['Content-Disposition'], 'inline; filename="%s"' % (self.dataset_file2.filename)) # file2 should be a TIFF self.assertEqual(response['Content-Type'], 'image/tiff') tiff_signature = "II\x2a\x00" self.assertEqual(response.content[0:4], tiff_signature) def _check_tar_file(self, content, rootdir, datafiles): # It should be a zip file with NamedTemporaryFile('w') as tempfile: tempfile.write(content) tempfile.flush() with open(tempfile.name, 'r') as zipread: # It should be a zip file (all of which start with "PK") expect(zipread.read(2)).to_equal('PK') expect(is_zipfile(tempfile.name)).to_be_truthy() with ZipFile(tempfile.name, 'r') as zf: expect(len(zf.namelist())).to_equal(len(datafiles)) for df in datafiles: filename = join(rootdir, str(df.dataset.id), df.filename) expect(filename in zf.namelist()).to_be_truthy() def _check_zip_file(self, content, rootdir, datafiles): # It should be a zip file with NamedTemporaryFile('w') as tempfile: tempfile.write(content) tempfile.flush() with open(tempfile.name, 'r') as zipread: # It should be a zip file (all of which start with "PK") expect(zipread.read(2)).to_equal('PK') expect(is_zipfile(tempfile.name)).to_be_truthy() zf = ZipFile(tempfile.name, 'r') expect(len(zf.namelist())).to_equal(len(datafiles)) for df in datafiles: filename = join(rootdir, str(df.dataset.id), df.filename) expect(filename in zf.namelist()).to_be_truthy() zf.close() def testDownload(self): client = Client() # check download for experiment1 response = client.get('/download/experiment/%i/zip/' % self.experiment1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="experiment%s-complete.zip"' % self.experiment1.id) self.assertEqual(response.status_code, 200) self._check_zip_file(response.content, str(self.experiment1.id), reduce(lambda x, y: x + y, [ds.dataset_file_set.all() \ for ds in self.experiment1.datasets.all()])) # check download of file1 response = client.get('/download/datafile/%i/' % self.dataset_file1.id) self.assertEqual(response['Content-Disposition'], 'attachment; filename="%s"' % self.dataset_file1.filename) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'Hello World!\n') # requesting file2 should be forbidden... response = client.get('/download/datafile/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 403) # check dataset1 download response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [self.dataset1.id], 'datafile': []}) self.assertEqual(response.status_code, 200) self._check_zip_file(response.content, 'datasets', self.dataset1.dataset_file_set.all()) # check dataset2 download response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [self.dataset2.id], 'datafile': []}) self.assertEqual(response.status_code, 403) # check datafile1 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment1.id, 'dataset': [], 'datafile': [self.dataset_file1.id]}) self.assertEqual(response.status_code, 200) self._check_zip_file(response.content, 'datasets', [self.dataset_file1]) # check datafile2 download via POST response = client.post('/download/datafiles/', {'expid': self.experiment2.id, 'dataset': [], 'datafile': [self.dataset_file2.id]}) self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to "metadata only" self.experiment2.public_access=Experiment.PUBLIC_ACCESS_METADATA self.experiment2.save() response = client.get('/download/datafile/%i/' % self.dataset_file2.id) # Metadata-only means "no file access"! self.assertEqual(response.status_code, 403) # Check datafile2 download with second experiment to public self.experiment2.public_access=Experiment.PUBLIC_ACCESS_FULL self.experiment2.save() response = client.get('/download/datafile/%i/' % self.dataset_file2.id) self.assertEqual(response.status_code, 200) # This should be a TIFF (which often starts with "II\x2a\x00") self.assertEqual(response['Content-Type'], 'image/tiff') self.assertEqual(response.content[0:4], "II\x2a\x00") def testDatasetFile(self): # check registered text file for physical file meta information df = Dataset_File.objects.get(pk=self.dataset_file1.id) try: from magic import Magic self.assertEqual(df.mimetype, 'text/plain; charset=us-ascii') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(df.size, str(13)) self.assertEqual(df.md5sum, '8ddd8be4b179a529afa5f2ffae4b9858') # now check a JPG file filename = abspath(join(dirname(__file__), '../static/images/ands-logo-hi-res.jpg')) dataset = Dataset.objects.get(pk=self.dataset1.id) size, sha512sum = get_size_and_sha512sum(filename) pdf1 = Dataset_File(dataset=dataset, filename=basename(filename), size=str(size), sha512sum=sha512sum, url='file://%s' % filename, protocol='file') pdf1.verify() pdf1.save() try: from magic import Magic self.assertEqual(pdf1.mimetype, 'image/jpeg') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(pdf1.size, str(14232)) self.assertEqual(pdf1.md5sum, 'c450d5126ffe3d14643815204daf1bfb') # now check that we can override the physical file meta information pdf2 = Dataset_File(dataset=dataset, filename=basename(filename), url='file://%s' % filename, protocol='file', mimetype='application/vnd.openxmlformats-officedocument.presentationml.presentation', size=str(0), # Empty string always has the same hash sha512sum='cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e') pdf2.save() try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/vnd.openxmlformats-officedocument.presentationml.presentation') except: # XXX Test disabled because lib magic can't be loaded pass self.assertEqual(pdf2.size, str(0)) self.assertEqual(pdf2.md5sum, '') pdf2.mimetype = '' pdf2.save() try: from magic import Magic self.assertEqual(pdf2.mimetype, 'application/pdf') except: # XXX Test disabled because lib magic can't be loaded pass
class ExperimentACLTestCase(TestCase): urls = 'tardis.urls' def setUp(self): # create a couple of test users self.user1 = User.objects.create_user('testuser1', '', 'secret') self.user2 = User.objects.create_user('testuser2', '', 'secret') self.user3 = User.objects.create_user('testuser3', '', 'secret') self.user4 = User.objects.create_user('testuser4', '', 'secret') # with standard permissions for user in [self.user1, self.user2, self.user3, self.user4]: user.user_permissions.add(Permission.objects.get(codename='add_experiment')) user.user_permissions.add(Permission.objects.get(codename='change_experiment')) user.user_permissions.add(Permission.objects.get(codename='change_group')) user.user_permissions.add(Permission.objects.get(codename='change_userauthentication')) user.user_permissions.add(Permission.objects.get(codename='change_experimentacl')) self.userProfile1 = UserProfile(user=self.user1) self.userProfile2 = UserProfile(user=self.user2) self.userProfile3 = UserProfile(user=self.user3) self.userProfile4 = UserProfile(user=self.user4) # each user will have their own client self.client1 = Client() self.client2 = Client() self.client3 = Client() self.client4 = Client() # user1 will own experiment1 self.experiment1 = Experiment( title='Experiment1', institution_name='Australian Synchrotron', approved=True, public=False, created_by=self.user1, ) self.experiment1.save() # user2 will own experiment2 self.experiment2 = Experiment( title='Experiment2', institution_name='Australian Synchrotron', approved=True, public=False, created_by=self.user2, ) self.experiment2.save() # experiment3 is public self.experiment3 = Experiment( title='Experiment3', institution_name='Australian Synchrotron', approved=True, public=True, created_by=self.user3, ) self.experiment3.save() # experiment4 will be accessible based on location information self.experiment4 = Experiment( title='Experiment4', institution_name='Australian Synchrotron', approved=True, public=False, created_by=self.user1, ) self.experiment4.save() # user1 owns experiment1 acl = ExperimentACL( pluginId=django_user, entityId=str(self.user1.id), experiment=self.experiment1, canRead=True, isOwner=True, aclOwnershipType=ExperimentACL.OWNER_OWNED, ) acl.save() # user2 owns experiment2 acl = ExperimentACL( pluginId=django_user, entityId=str(self.user2.id), experiment=self.experiment2, canRead=True, isOwner=True, aclOwnershipType=ExperimentACL.OWNER_OWNED, ) acl.save() # experiment4 is accessible via location acl = ExperimentACL( pluginId='ip_address', entityId='127.0.0.1', experiment=self.experiment4, canRead=True, aclOwnershipType=ExperimentACL.SYSTEM_OWNED, ) acl.save() def tearDown(self): self.client1.logout() self.client2.logout() self.client3.logout() self.client4.logout() self.experiment1.delete() self.experiment2.delete() self.experiment3.delete() self.experiment4.delete() self.user1.delete() self.user2.delete() self.user3.delete() self.user4.delete() def testReadAccess(self): login = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login) # user1 should be see experiment1 response = self.client1.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user1 should not be allowed to see experiment2 response = self.client1.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # user1 should be allowed to see experiment3 as it's public response = self.client1.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user1 should be allowed to see experiment4 based on his IP address response = self.client1.get('/experiment/view/%i/' % (self.experiment4.id)) self.assertEqual(response.status_code, 200) # create a group and add it to experiment1 response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/group/%s/?canRead=true&create=true' % (self.experiment1.id, 'group1')) self.assertEqual(response.status_code, 200) # add user2 as admin to the newly created group group = Group.objects.get(name='group1') response = self.client1.get('/group/%i/add/%s/?isAdmin=true&authMethod=%s' % (group.id, self.user2.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # try it again response = self.client1.get('/group/%i/add/%s/?isAdmin=true&authMethod=%s' % (group.id, self.user2.username, localdb_auth_key)) self.assertEqual(response.content, 'User %s is already member of that' ' group.' % self.user2.username) self.assertEqual(response.status_code, 200) # user1 is not allowed to modify acls for experiment2 response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment2.id, self.user1.username, localdb_auth_key)) self.assertEqual(response.status_code, 403) # test add non-existent user non_existant = 'test_boozer' response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment1.id, non_existant, localdb_auth_key)) self.assertContains(response, 'User %s does not exist' % non_existant) # test add to non existant experiment # Note: Ideally we'd like to check for error message, but we # can't hit it with the decorator in place. However, # currently we check for a 403 (forbidden) error, as the # 'experiment_ownership_required' decorator simply checks if # the experiment_id appears in the specified user's ACL, and # assumes that the absence of the experiment_id means that the # experiment exists but the user doesn't have access to # it. This could possibly be changed to a 404 error. response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (9999, self.user1.username, localdb_auth_key)) self.assertEqual(response.status_code, 403) self.client1.logout() # now check user2's permissions login = self.client2.login(username=self.user2.username, password='******') self.assertTrue(login) # user2 should be able to see experiment1 now response = self.client2.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user2 should be also able to see experiment2 response = self.client2.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 200) # user2 should be allowed to see experiment3 as it's public response = self.client2.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user2 should be able to add user3 to group1 (experiment1) response = self.client2.get('/group/%i/add/%s/?isAdmin=false&authMethod=%s' % (group.id, self.user3.username, localdb_auth_key)) self.client2.logout() # now check user3's permissions login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) # user3 should be able to see experiment1 via his group permissions response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # user3 should not be able to see experiment2 response = self.client3.get('/experiment/view/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # user3 should be able to see experiment3 response = self.client3.get('/experiment/view/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 200) # user3 should not be able to add another user4 to group1 response = self.client3.get('/group/%i/add/%s/?isAdmin=false&authMethod=%s' % (group.id, 'testuser4', localdb_auth_key)) self.assertEqual(response.status_code, 403) self.client3.logout() # ok, now do some tricky stuff today = datetime.datetime.today() yesterday = today - datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1) url = '/experiment/control_panel/%i/access_list/change/user/%s/' login = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login) # remove user3 from group1 response = self.client1.get('/group/%i/remove/%s/' % (group.id, self.user3.username)) self.assertEqual(response.status_code, 200) # add user3 to experiment1 response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) self.assertContains(response, '<div class="access_list_user">') # give user3 read permissions for experiment1 effictive TOMORROW response = self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) self.assertEqual(response.status_code, 302) # check permissions for user3 login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # change effictive date to TODAY response = self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'effectiveDate_year': today.year, 'effectiveDate_month': today.month, 'effectiveDate_day': today.day, }) self.assertEqual(response.status_code, 302) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # change effictive date to YESTERDAY self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'effectiveDate_year': yesterday.year, 'effectiveDate_month': yesterday.month, 'effectiveDate_day': yesterday.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to TOMORROW self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'expiryDate_year': tomorrow.year, 'expiryDate_month': tomorrow.month, 'expiryDate_day': tomorrow.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to TODAY self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'expiryDate_year': today.year, 'expiryDate_month': today.month, 'expiryDate_day': today.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # set expiry date to YESTERDAY self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'expiryDate_year': yesterday.year, 'expiryDate_month': yesterday.month, 'expiryDate_day': yesterday.day, }) response = self.client3.get('/experiment/view/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # remove user3 from experiment1 again response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (self.experiment1.id, self.user3.username)) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'OK') # try again, see if it falls over response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (self.experiment1.id, self.user3.username)) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, 'The user %s does not have access to this experiment.' % self.user3.username) # try to remove from a non-existant experiment response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (9999, self.user3.username)) self.assertEqual(response.status_code, 403) # try to remove the owner response = self.client1.get('/experiment/control_panel/%i/access_list' '/remove/user/%s/' % (self.experiment1.id, self.user1.username)) self.assertEqual(response.content, 'Cannot remove your own user access.') self.client1.logout() self.client3.logout() def testWriteAccess(self): # without logging in the request should be redirected response = self.client1.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 302) # now check access for user1 login = self.client1.login(username=self.user1.username, password='******') self.assertTrue(login) response = self.client1.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # write access has not been granted for experiment2 response = self.client1.get('/experiment/edit/%i/' % (self.experiment2.id)) self.assertEqual(response.status_code, 403) # neither experiment3 which is public response = self.client1.get('/experiment/edit/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 403) # create a group 'group1w' with write permissions response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/group/%s/?canRead=true&canWrite=true&create=true' % (self.experiment1.id, 'group1w')) self.assertEqual(response.status_code, 200) # add user2 to 'group1w' which gives him write permissions group = Group.objects.get(name='group1w') response = self.client1.get('/group/%i/add/%s/?isAdmin=false&authMethod=%s' % (group.id, self.user2.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # add user3 explicitly to experiment1 response = self.client1.get('/experiment/control_panel/%i/access_list' '/add/user/%s/?authMethod=%s&canRead=true' '&canWrite=true' % (self.experiment1.id, self.user3.username, localdb_auth_key)) self.assertEqual(response.status_code, 200) # check newly created permissions for user2 and user3 response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 302) response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 302) login = self.client2.login(username=self.user2.username, password='******') self.assertTrue(login) login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # now the fancy stuff with timestamps today = datetime.datetime.today() yesterday = today - datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1) url = '/experiment/control_panel/%i/access_list/change/group/%i/' # give group 'group1w' write permissions for experiment1 effictive TOMORROW response = self.client1.post(url % (self.experiment1.id, group.id), {'canRead': True, 'canWrite': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) self.assertEqual(response.status_code, 302) response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # change effictive date to TODAY response = self.client1.post(url % (self.experiment1.id, group.id), {'canRead': True, 'canWrite': True, 'effectiveDate_year': today.year, 'effectiveDate_month': today.month, 'effectiveDate_day': today.day, }) self.assertEqual(response.status_code, 302) # now user2 should have write access again response = self.client2.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) # repeat all the tests with timestamps for user3 url = '/experiment/control_panel/%i/access_list/change/user/%s/' # give user3 write permissions for experiment1 effictive TOMORROW response = self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'canWrite': True, 'effectiveDate_year': tomorrow.year, 'effectiveDate_month': tomorrow.month, 'effectiveDate_day': tomorrow.day, }) self.assertEqual(response.status_code, 302) response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 403) # change effictive date to TODAY response = self.client1.post(url % (self.experiment1.id, self.user3.username), {'canRead': True, 'canWrite': True, 'effectiveDate_year': today.year, 'effectiveDate_month': today.month, 'effectiveDate_day': today.day, }) self.assertEqual(response.status_code, 302) # now user3 should have write access again response = self.client3.get('/experiment/edit/%i/' % (self.experiment1.id)) self.assertEqual(response.status_code, 200) self.client1.logout() self.client2.logout() self.client3.logout() def testCantEditPublicExperiment(self): login = self.client3.login(username=self.user3.username, password='******') self.assertTrue(login) # user3 has acl to write to experiment3 acl = ExperimentACL( pluginId=django_user, entityId=str(self.user3.id), experiment=self.experiment3, canRead=True, canWrite=True, aclOwnershipType=ExperimentACL.OWNER_OWNED, ) acl.save() response = self.client3.get('/experiment/edit/%i/' % (self.experiment3.id)) self.assertEqual(response.status_code, 403) response = self.client3.post('/experiment/edit/%i/' % (self.experiment3.id), {'anything': True, }) self.assertEqual(response.status_code, 403) acl.delete() self.client3.logout() def testOwnedExperiments(self): user = AnonymousUser() # not logged in class MockRequest: pass request = MockRequest() request.user = user num_exps = Experiment.safe.owned(request).count() self.assertEqual(num_exps, 0)
class ParameterSetManagerTestCase(TestCase): def setUp(self): from django.contrib.auth.models import User from tempfile import mkdtemp user = '******' pwd = 'secret' email = '' self.user = User.objects.create_user(user, email, pwd) self.test_dir = mkdtemp() self.exp = Experiment(title='test exp1', institution_name='monash', created_by=self.user) self.exp.save() self.dataset = Dataset(description="dataset description...") self.dataset.save() self.dataset.experiments.add(self.exp) self.dataset.save() self.datafile = DataFile(dataset=self.dataset, filename="testfile.txt", size="42", md5sum='bogus') self.datafile.save() self.dfo = DataFileObject( datafile=self.datafile, storage_box=self.datafile.get_default_storage_box(), uri="1/testfile.txt") self.dfo.save() self.schema = Schema(namespace="http://localhost/psmtest/df/", name="Parameter Set Manager", type=3) self.schema.save() self.parametername1 = ParameterName(schema=self.schema, name="parameter1", full_name="Parameter 1") self.parametername1.save() self.parametername2 = ParameterName(schema=self.schema, name="parameter2", full_name="Parameter 2", data_type=ParameterName.NUMERIC) self.parametername2.save() self.parametername3 = ParameterName(schema=self.schema, name="parameter3", full_name="Parameter 3", data_type=ParameterName.DATETIME) self.parametername3.save() self.datafileparameterset = DatafileParameterSet( schema=self.schema, datafile=self.datafile) self.datafileparameterset.save() self.datafileparameter1 = DatafileParameter( parameterset=self.datafileparameterset, name=self.parametername1, string_value="test1") self.datafileparameter1.save() self.datafileparameter2 = DatafileParameter( parameterset=self.datafileparameterset, name=self.parametername2, numerical_value=2) self.datafileparameter2.save() # Create a ParameterName and Parameter of type LINK to an experiment self.parametername_exp_link = ParameterName( schema=self.schema, name="exp_link", full_name="This parameter is a experiment LINK", data_type=ParameterName.LINK) self.parametername_exp_link.save() self.exp_link_param = DatafileParameter( parameterset=self.datafileparameterset, name=self.parametername_exp_link) exp_url = self.exp.get_absolute_url() # /experiment/view/1/ self.exp_link_param.set_value(exp_url) self.exp_link_param.save() # Create a ParameterName and Parameter of type LINK to a dataset self.parametername_dataset_link = ParameterName( schema=self.schema, name="dataset_link", full_name="This parameter is a dataset LINK", data_type=ParameterName.LINK) self.parametername_dataset_link.save() self.dataset_link_param = DatafileParameter( parameterset=self.datafileparameterset, name=self.parametername_dataset_link) dataset_url = self.dataset.get_absolute_url() # /dataset/1/ self.dataset_link_param.set_value(dataset_url) self.dataset_link_param.save() # Create a ParameterName type LINK to an unresolvable (non-URL) # free-text value self.parametername_unresolvable_link = ParameterName( schema=self.schema, name="freetext_link", full_name="This parameter is a non-URL LINK", data_type=ParameterName.LINK) self.parametername_unresolvable_link.save() def tearDown(self): self.exp.delete() self.user.delete() self.parametername1.delete() self.parametername2.delete() self.parametername3.delete() self.parametername_exp_link.delete() self.parametername_dataset_link.delete() self.parametername_unresolvable_link.delete() self.schema.delete() def test_existing_parameterset(self): psm = ParameterSetManager(parameterset=self.datafileparameterset) self.assertTrue( psm.get_schema().namespace == "http://localhost/psmtest/df/") self.assertTrue(psm.get_param("parameter1").string_value == "test1") self.assertTrue(psm.get_param("parameter2", True) == 2) def test_new_parameterset(self): psm = ParameterSetManager(parentObject=self.datafile, schema="http://localhost/psmtest/df2/") self.assertTrue( psm.get_schema().namespace == "http://localhost/psmtest/df2/") psm.set_param("newparam1", "test3", "New Parameter 1") self.assertTrue(psm.get_param("newparam1").string_value == "test3") self.assertTrue( psm.get_param("newparam1").name.full_name == "New Parameter 1") psm.new_param("newparam1", "test4") self.assertTrue(len(psm.get_params("newparam1", True)) == 2) psm.set_param_list("newparam2", ("a", "b", "c", "d")) self.assertTrue(len(psm.get_params("newparam2")) == 4) psm.set_params_from_dict({"newparam2": "test5", "newparam3": 3}) self.assertTrue(psm.get_param("newparam2", True) == "test5") # the newparam3 gets created and '3' is set to a string_value # since once cannot assume that an initial numeric value # will imply continuing numeric type for this new param self.assertTrue(psm.get_param("newparam3").string_value == '3') psm.delete_params("newparam1") self.assertTrue(len(psm.get_params("newparam1", True)) == 0) def test_link_parameter_type(self): """ Test that Parameter.link_gfk (GenericForeignKey) is correctly assigned after using Parameter.set_value(some_url) for a LINK Parameter. """ psm = ParameterSetManager(parameterset=self.datafileparameterset) # Check link to experiment exp_url = self.exp.get_absolute_url() # /experiment/view/1/ self.assertTrue(psm.get_param("exp_link").string_value == exp_url) self.assertTrue(psm.get_param("exp_link").link_id == self.exp.id) exp_ct = ContentType.objects.get(model__iexact="experiment") self.assertTrue(psm.get_param("exp_link").link_ct == exp_ct) self.assertTrue(psm.get_param("exp_link").link_gfk == self.exp) # Check link to dataset dataset_url = self.dataset.get_absolute_url() # /dataset/1/ self.assertTrue( psm.get_param("dataset_link").string_value == dataset_url) self.assertTrue( psm.get_param("dataset_link").link_id == self.dataset.id) dataset_ct = ContentType.objects.get(model__iexact="dataset") self.assertTrue(psm.get_param("dataset_link").link_ct == dataset_ct) self.assertTrue(psm.get_param("dataset_link").link_gfk == self.dataset) def test_link_parameter_type_extra(self): # make a second ParameterSet for testing some variations # in URL values self.datafileparameterset2 = DatafileParameterSet( schema=self.schema, datafile=self.datafile) self.datafileparameterset2.save() psm = ParameterSetManager(parameterset=self.datafileparameterset2) self.dataset_link_param2 = DatafileParameter( parameterset=self.datafileparameterset2, name=self.parametername_dataset_link) # /dataset/1 - no trailing slash dataset_url = self.dataset.get_absolute_url() self.dataset_link_param2.set_value(dataset_url) self.dataset_link_param2.save() # Check link_id/link_ct/link_gfk to dataset self.assertTrue( psm.get_param("dataset_link").link_id == self.dataset.id) dataset_ct = ContentType.objects.get(model__iexact="dataset") self.assertTrue(psm.get_param("dataset_link").link_ct == dataset_ct) self.assertTrue(psm.get_param("dataset_link").link_gfk == self.dataset) # Test links of the form /api/v1/experiment/<experiment_id>/ self.exp_link_param2 = DatafileParameter( parameterset=self.datafileparameterset2, name=self.parametername_exp_link) exp_url = '/api/v1/experiment/%s/' % self.exp.id self.exp_link_param2.set_value(exp_url) self.exp_link_param2.save() # Check link_id/link_ct/link_gfk to experiment self.assertTrue(psm.get_param("exp_link").link_id == self.exp.id) exp_ct = ContentType.objects.get(model__iexact="experiment") self.assertTrue(psm.get_param("exp_link").link_ct == exp_ct) self.assertTrue(psm.get_param("exp_link").link_gfk == self.exp) def test_unresolvable_link_parameter(self): """ Test that LINK Parameters that can't be resolved to a model (including non-URL values) still work. """ self.datafileparameterset3 = DatafileParameterSet( schema=self.schema, datafile=self.datafile) self.datafileparameterset3.save() psm = ParameterSetManager(parameterset=self.datafileparameterset3) # Create a Parameter of type LINK to an unresolvable (non-URL) # free-text value self.freetext_link_param = DatafileParameter( parameterset=self.datafileparameterset3, name=self.parametername_unresolvable_link) self.assertRaises( SuspiciousOperation, lambda: self.freetext_link_param.set_value("FREETEXT_ID_123")) def test_tz_naive_date_handling(self): """ Ensure that dates are handling in a timezone-aware way. """ psm = ParameterSetManager(parameterset=self.datafileparameterset) psm.new_param("parameter3", str(datetime(1970, 01, 01, 10, 0, 0))) expect(psm.get_param("parameter3", True))\ .to_equal(datetime(1970, 01, 01, 0, 0, 0, tzinfo=pytz.utc)) def test_tz_aware_date_handling(self): """ Ensure that dates are handling in a timezone-aware way. """ psm = ParameterSetManager(parameterset=self.datafileparameterset) psm.new_param("parameter3", '1970-01-01T08:00:00+08:00') expect(psm.get_param("parameter3", True))\ .to_equal(datetime(1970, 01, 01, 0, 0, 0, tzinfo=pytz.utc))