diff --git a/eoxserver/resources/coverages/management/commands/collection.py b/eoxserver/resources/coverages/management/commands/collection.py index f4cfab4e3..0c15be227 100644 --- a/eoxserver/resources/coverages/management/commands/collection.py +++ b/eoxserver/resources/coverages/management/commands/collection.py @@ -27,6 +27,7 @@ from django.core.management.base import CommandError, BaseCommand from django.db import transaction +from django.db.models import Q from eoxserver.resources.coverages import models from eoxserver.resources.coverages.management.commands import ( @@ -45,9 +46,10 @@ def add_arguments(self, parser): exclude_parser = self.add_subparser(parser, 'exclude') purge_parser = self.add_subparser(parser, 'purge') summary_parser = self.add_subparser(parser, 'summary') + import_parser = self.add_subparser(parser, 'import') parsers = [ create_parser, insert_parser, exclude_parser, - purge_parser, summary_parser + purge_parser, summary_parser, import_parser ] # identifier is a common argument (except for delete it is optional, @@ -91,8 +93,8 @@ def add_arguments(self, parser): ) delete_parser.add_argument( - 'identifier', default=None, nargs='?', - help='The identifier of the collection to delete.' + 'identifier', default=None, nargs='?', + help='The identifier of the collection to delete.' ) # common arguments for insertion/exclusion insert_parser.add_argument( @@ -131,13 +133,13 @@ def add_arguments(self, parser): ) summary_parser.add_argument( '--no-products', action='store_false', default=True, - dest='coverage_summary', + dest='product_summary', help=("Don't collect summary product metadata.") ) summary_parser.add_argument( '--coverages', action='store_true', default=True, - dest='product_summary', + dest='coverage_summary', help=('Collect summary coverage metadata. Default.') ) summary_parser.add_argument( @@ -146,6 +148,48 @@ def add_arguments(self, parser): help=("Don't collect summary coverage metadata.") ) + import_parser.add_argument( + '--from', action='append', default=[], dest="from_collections", + help=("Declare to import from that collection") + ) + import_parser.add_argument( + '--from-producttype', action='append', default=[], + dest="from_producttypes", + help=("Declare to import from that product type") + ) + import_parser.add_argument( + '--from-coveragetype', action='append', default=[], + dest="from_coveragetypes", + help=("Declare to import from that coverage type") + ) + import_parser.add_argument( + '--products', action='store_true', default=True, + dest='product_import', + help=('Import products. Default.') + ) + import_parser.add_argument( + '--no-products', action='store_false', default=True, + dest='product_import', + help=("Don't import products.") + ) + import_parser.add_argument( + '--coverages', action='store_true', default=True, + dest='coverage_import', + help=('Import coverages. Default.') + ) + import_parser.add_argument( + '--no-coverages', action='store_false', default=True, + dest='coverage_import', + help=("Don't import coverages.") + ) + import_parser.add_argument( + '--use-extent', action='store_true', default=False, + help=( + 'Whether to simply collect the bounding box of the ' + 'footprint as the collections footprint' + ) + ) + @transaction.atomic def handle(self, subcommand, identifier, *args, **kwargs): """ Dispatch sub-commands: create, delete, insert, exclude, purge. @@ -162,6 +206,8 @@ def handle(self, subcommand, identifier, *args, **kwargs): self.handle_purge(identifier[0], *args, **kwargs) elif subcommand == "summary": self.handle_summary(identifier[0], *args, **kwargs) + elif subcommand == "import": + self.handle_import(identifier[0], *args, **kwargs) def handle_create(self, identifier, type_name, grid_name, replace, **kwargs): """ Handle the creation of a new collection. @@ -188,8 +234,8 @@ def handle_create(self, identifier, type_name, grid_name, replace, **kwargs): models.Collection.objects.update_or_create( identifier=identifier, defaults={ - 'collection_type':collection_type, - 'grid':grid, + 'collection_type': collection_type, + 'grid': grid, } ) else: @@ -308,6 +354,56 @@ def handle_summary(self, identifier, product_summary, coverage_summary, ) print('Successfully collected metadata for collection %r' % identifier) + def handle_import(self, identifier, from_collections, from_producttypes, + from_coveragetypes, product_import, coverage_import, + use_extent, **kwargs): + collection = self.get_collection(identifier) + + collections = [ + self.get_collection(from_collection) + for from_collection in from_collections + ] + + if product_import: + # get distinct products that are in the collections in + # `from_collections` associated with a product type in + # `from_producttypes` + product_types = [ + models.ProductType.objects.get(name=name) + for name in from_producttypes + ] + qs = models.Product.objects.filter( + Q(collections__in=collections) + | Q(product_type__in=product_types) + ).exclude(collections__in=[collection]) + + num_products = len(qs) + for product in qs: + models.collection_insert_eo_object(collection, product, use_extent) + print("Imported %d products into collection %r." % (num_products, collection)) + + if coverage_import: + # get distinct coverages that are in the collections in + # `from_collections` associated with a coverage type in + # `from_coveragetypes` + coverage_types = [ + models.CoverageType.objects.get(name=name) + for name in from_coveragetypes + ] + qs = models.Coverage.objects.filter( + Q(collections__in=collections) + | Q(coverage_type__in=coverage_types) + ).exclude(collections__in=[collection]) + + num_coverages = len(qs) + for coverage in qs: + models.collection_insert_eo_object(collection, coverage, use_extent) + print( + "Imported %d coverages into collection %r." % ( + num_coverages, collection + ) + ) + def get_collection(self, identifier): """ Helper method to get a collection by identifier or raise a CommandError. diff --git a/eoxserver/resources/coverages/tests.py b/eoxserver/resources/coverages/tests.py index 22f7cb273..6b6a2be54 100644 --- a/eoxserver/resources/coverages/tests.py +++ b/eoxserver/resources/coverages/tests.py @@ -1,11 +1,11 @@ -#----------------------------------------------------------------------- +# ----------------------------------------------------------------------- # # Project: EOxServer # Authors: Fabian Schindler # Stephan Meissl # Stephan Krause # -#------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------- # Copyright (C) 2011 EOX IT Services GmbH # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -25,10 +25,11 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -#------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------- import sys from datetime import datetime + try: from StringIO import StringIO except ImportError: @@ -36,17 +37,18 @@ from textwrap import dedent from unittest import skipIf +from django.core import management from django.test import TestCase -from django.core.exceptions import ValidationError from django.contrib.gis.geos import GEOSGeometry, Polygon, MultiPolygon from django.utils.dateparse import parse_datetime from django.utils.timezone import utc from eoxserver.core import env -from eoxserver.resources.coverages.models import * +from eoxserver.resources.coverages import models from eoxserver.resources.coverages.util import collect_eo_metadata from eoxserver.resources.coverages.metadata.coverage_formats import ( - native, eoom, dimap_general + native, + eoom, ) @@ -88,85 +90,93 @@ def assertGeometryEqual(self, ga, gb, tolerance=0.05, max_area=0.00001): except Exception: pass - self.fail( - ga.equals_exact(gb, tolerance), - "%r != %r" % (ga.wkt, gb.wkt) - ) + self.fail(ga.equals_exact(gb, tolerance), "%r != %r" % (ga.wkt, gb.wkt)) + class ModelTests(GeometryMixIn, TestCase): def setUp(self): - self.coverage_type = create(CoverageType, - name="RGB" - ) - self.rectified_grid = Grid.objects.create( - name="rectified_grid", - coordinate_reference_system="EPSG:4326", - axis_1_name="x", - axis_1_type=0, - axis_1_offset="5", - axis_2_name="y", - axis_2_type=0, - axis_2_offset="5" + self.coverage_type = create(models.CoverageType, name="RGB") + self.rectified_grid = models.Grid.objects.create( + name="rectified_grid", + coordinate_reference_system="EPSG:4326", + axis_1_name="x", + axis_1_type=0, + axis_1_offset="5", + axis_2_name="y", + axis_2_type=0, + axis_2_offset="5", ) - self.referenced_grid= Grid.objects.create( - name="referenced_grid", - coordinate_reference_system="EPSG:4326", - axis_1_name="x", - axis_1_type=0, - axis_2_name="y", - axis_2_type=0 - + self.referenced_grid = models.Grid.objects.create( + name="referenced_grid", + coordinate_reference_system="EPSG:4326", + axis_1_name="x", + axis_1_type=0, + axis_2_name="y", + axis_2_type=0, ) - self.rectified_1 = create(Coverage, + self.rectified_1 = create( + models.Coverage, identifier="rectified-1", - footprint=GEOSGeometry("MULTIPOLYGON (((-111.6210939999999994 26.8588260000000005, -113.0273439999999994 -4.0786740000000004, -80.6835939999999994 -9.7036739999999995, -68.0273439999999994 15.6088260000000005, -111.6210939999999994 26.8588260000000005)))"), + footprint=GEOSGeometry( + "MULTIPOLYGON (((-111.6210939999999994 26.8588260000000005, -113.0273439999999994 -4.0786740000000004, -80.6835939999999994 -9.7036739999999995, -68.0273439999999994 15.6088260000000005, -111.6210939999999994 26.8588260000000005)))" + ), begin_time=parse_datetime("2013-06-11T14:55:23Z"), end_time=parse_datetime("2013-06-11T14:55:23Z"), grid=self.rectified_grid, axis_1_size=100, axis_2_size=100, - coverage_type=self.coverage_type + coverage_type=self.coverage_type, ) - self.rectified_2 = create(Coverage, + self.rectified_2 = create( + models.Coverage, identifier="rectified-2", - footprint=GEOSGeometry("MULTIPOLYGON (((-28.0371090000000009 19.4760129999999982, -32.9589840000000009 -0.9146120000000000, -2.8125000000000000 -3.8150019999999998, 4.2187500000000000 19.1244510000000005, -28.0371090000000009 19.4760129999999982)))"), + footprint=GEOSGeometry( + "MULTIPOLYGON (((-28.0371090000000009 19.4760129999999982, -32.9589840000000009 -0.9146120000000000, -2.8125000000000000 -3.8150019999999998, 4.2187500000000000 19.1244510000000005, -28.0371090000000009 19.4760129999999982)))" + ), begin_time=parse_datetime("2013-06-10T18:52:34Z"), end_time=parse_datetime("2013-06-10T18:52:32Z"), grid=self.rectified_grid, axis_1_size=100, axis_2_size=100, - coverage_type=self.coverage_type + coverage_type=self.coverage_type, ) - self.rectified_3 = create(Coverage, + self.rectified_3 = create( + models.Coverage, identifier="rectified-3", - footprint=GEOSGeometry("MULTIPOLYGON (((-85.5175780000000003 14.2904660000000003, -116.2792969999999997 -8.3853150000000003, -63.7207030000000003 -19.4595340000000014, -58.7988280000000003 7.2592160000000003, -85.5175780000000003 14.2904660000000003)))"), + footprint=GEOSGeometry( + "MULTIPOLYGON (((-85.5175780000000003 14.2904660000000003, -116.2792969999999997 -8.3853150000000003, -63.7207030000000003 -19.4595340000000014, -58.7988280000000003 7.2592160000000003, -85.5175780000000003 14.2904660000000003)))" + ), begin_time=parse_datetime("2013-06-10T18:55:54Z"), end_time=parse_datetime("2013-06-10T18:55:54Z"), grid=self.rectified_grid, axis_1_size=100, axis_2_size=100, - coverage_type=self.coverage_type + coverage_type=self.coverage_type, ) - self.referenceable = create(Coverage, + self.referenceable = create( + models.Coverage, identifier="referenceable-1", - footprint=GEOSGeometry("MULTIPOLYGON (((-85.5175780000000003 14.2904660000000003, -116.2792969999999997 -8.3853150000000003, -63.7207030000000003 -19.4595340000000014, -58.7988280000000003 7.2592160000000003, -85.5175780000000003 14.2904660000000003)))"), + footprint=GEOSGeometry( + "MULTIPOLYGON (((-85.5175780000000003 14.2904660000000003, -116.2792969999999997 -8.3853150000000003, -63.7207030000000003 -19.4595340000000014, -58.7988280000000003 7.2592160000000003, -85.5175780000000003 14.2904660000000003)))" + ), begin_time=parse_datetime("2013-06-10T18:55:54Z"), end_time=parse_datetime("2013-06-10T18:55:54Z"), grid=self.referenced_grid, axis_1_size=100, axis_2_size=100, - coverage_type=self.coverage_type + coverage_type=self.coverage_type, ) - self.mosaic = create(Mosaic, + self.mosaic = create( + models.Mosaic, identifier="mosaic-1", grid=self.rectified_grid, axis_1_size=100, axis_2_size=100, - coverage_type=self.coverage_type + coverage_type=self.coverage_type, ) # TODO: bug, requires identifier to be set manually again @@ -174,50 +184,47 @@ def setUp(self): self.mosaic.full_clean() self.mosaic.save() - #======================================================================= + # ======================================================================= # Collections - #======================================================================= + # ======================================================================= - self.series_1 = create(Collection, - identifier="series-1" - ) + self.series_1 = create(models.Collection, identifier="series-1") - self.series_2 = create(Collection, - identifier="series-2" - ) + self.series_2 = create(models.Collection, identifier="series-2") def tearDown(self): pass def test_insertion(self): rectified_1, rectified_2, rectified_3 = ( - self.rectified_1, self.rectified_2, self.rectified_3 + self.rectified_1, + self.rectified_2, + self.rectified_3, ) mosaic, series_1, series_2 = self.mosaic, self.series_1, self.series_2 - mosaic_insert_coverage(mosaic, rectified_1) - mosaic_insert_coverage(mosaic, rectified_2) - mosaic_insert_coverage(mosaic, rectified_3) + models.mosaic_insert_coverage(mosaic, rectified_1) + models.mosaic_insert_coverage(mosaic, rectified_2) + models.mosaic_insert_coverage(mosaic, rectified_3) mosaic_list = mosaic.coverages.all() self.assertIn(rectified_1, mosaic_list) self.assertIn(rectified_2, mosaic_list) self.assertIn(rectified_3, mosaic_list) + models.collection_insert_eo_object(series_1, rectified_1) + models.collection_insert_eo_object(series_1, rectified_2) + models.collection_insert_eo_object(series_1, rectified_3) - collection_insert_eo_object(series_1, rectified_1) - collection_insert_eo_object(series_1, rectified_2) - collection_insert_eo_object(series_1, rectified_3) - - series_1_list= series_1.coverages.all() + series_1_list = series_1.coverages.all() self.assertIn(rectified_1, series_1_list) self.assertIn(rectified_2, series_1_list) self.assertIn(rectified_3, series_1_list) - collection_insert_eo_object(series_2, rectified_1) - collection_insert_eo_object(series_2, rectified_2) - collection_insert_eo_object(series_2, rectified_3) + models.collection_insert_eo_object(series_2, rectified_1) + models.collection_insert_eo_object(series_2, rectified_2) + models.collection_insert_eo_object(series_2, rectified_3) series_2_list = series_2.coverages.all() @@ -229,14 +236,14 @@ def test_insertion(self): self.assertEqual(len(series_1_list), 3) self.assertEqual(len(series_2_list), 3) - mosaic = Mosaic.objects.get(identifier="mosaic-1") + mosaic = models.Mosaic.objects.get(identifier="mosaic-1") mosaic, series_1, series_2 = refresh(mosaic, series_1, series_2) # TODO: further check metadata self.assertTrue(series_1.begin_time is not None) begin_time, end_time, all_rectified_footprints = collect_eo_metadata( - Coverage.objects.all() + models.Coverage.objects.all() ) time_extent = begin_time, end_time @@ -261,17 +268,20 @@ def test_insertion(self): def test_insertion_cascaded(self): rectified_1, mosaic, series_1, series_2 = ( - self.rectified_1, self.mosaic, self.series_1, self.series_2 + self.rectified_1, + self.mosaic, + self.series_1, + self.series_2, ) - mosaic_insert_coverage(mosaic, rectified_1) - collection_insert_eo_object(series_1, rectified_1) - collection_insert_eo_object(series_2, rectified_1) + models.mosaic_insert_coverage(mosaic, rectified_1) + models.collection_insert_eo_object(series_1, rectified_1) + models.collection_insert_eo_object(series_2, rectified_1) series_1 = refresh(series_1) - series_1_list= series_1.coverages.all() - series_2_list= series_2.coverages.all() - mosaic_list= mosaic.coverages.all() + series_1_list = series_1.coverages.all() + series_2_list = series_2.coverages.all() + mosaic_list = mosaic.coverages.all() self.assertIn(rectified_1, series_2_list) self.assertIn(rectified_1, series_1_list) @@ -284,36 +294,36 @@ def test_insertion_cascaded(self): def test_insertion_failed(self): referenceable, mosaic = self.referenceable, self.mosaic - with self.assertRaises(ManagementError): - mosaic_insert_coverage(mosaic, referenceable) + with self.assertRaises(models.ManagementError): + models.mosaic_insert_coverage(mosaic, referenceable) mosaic = refresh(mosaic) - mosaic_list= mosaic.coverages.all() + mosaic_list = mosaic.coverages.all() self.assertNotIn(referenceable, mosaic_list) def test_insertion_and_removal(self): rectified_1, rectified_2, series_1 = ( - self.rectified_1, self.rectified_2, self.series_1 + self.rectified_1, + self.rectified_2, + self.series_1, ) - collection_insert_eo_object(series_1, rectified_1) - collection_insert_eo_object(series_1, rectified_2) + models.collection_insert_eo_object(series_1, rectified_1) + models.collection_insert_eo_object(series_1, rectified_2) series_1 = refresh(series_1) - - collection_exclude_eo_object(series_1, rectified_2) + models.collection_exclude_eo_object(series_1, rectified_2) series_1 = refresh(series_1) rectified_1_time_extent = rectified_1.begin_time, rectified_1.end_time series_1_time_extent = series_1.begin_time, series_1.end_time self.assertEqual(rectified_1_time_extent, series_1_time_extent) - self.assertGeometryEqual(rectified_1.footprint,series_1.footprint) + self.assertGeometryEqual(rectified_1.footprint, series_1.footprint) def test_propagate_eo_metadata_change(self): rectified_1, series_1 = self.rectified_1, self.series_1 - new_begin_time = parse_datetime("2010-06-11T14:55:23Z") new_end_time = parse_datetime("2010-06-11T14:55:23Z") @@ -321,7 +331,7 @@ def test_propagate_eo_metadata_change(self): rectified_1.end_time = new_end_time rectified_1.full_clean() rectified_1.save() - collection_insert_eo_object(series_1, rectified_1) + models.collection_insert_eo_object(series_1, rectified_1) series_1 = refresh(series_1) @@ -329,7 +339,6 @@ def test_propagate_eo_metadata_change(self): self.assertEqual(series_1.end_time, new_end_time) - class MetadataFormatTests(GeometryMixIn, TestCase): def test_native_reader(self): xml = """ @@ -354,33 +363,37 @@ def test_native_reader(self): self.assertTrue(reader.test(xml)) values = reader.read(xml) - self.assertEqual({ - "identifier": "some_unique_id", - "begin_time": datetime(2013, 8, 27, 10, 0, 0, tzinfo=utc), - "end_time": datetime(2013, 8, 27, 10, 0, 10, tzinfo=utc), - "footprint": MultiPolygon( - Polygon.from_bbox((0, 0, 10, 20)), - Polygon.from_bbox((10, 10, 30, 40)) - ), - "format": "native" - }, values) + self.assertEqual( + { + "identifier": "some_unique_id", + "begin_time": datetime(2013, 8, 27, 10, 0, 0, tzinfo=utc), + "end_time": datetime(2013, 8, 27, 10, 0, 10, tzinfo=utc), + "footprint": MultiPolygon( + Polygon.from_bbox((0, 0, 10, 20)), + Polygon.from_bbox((10, 10, 30, 40)), + ), + "format": "native", + }, + values, + ) - @skipIf(sys.version_info.major == 3, 'segfault in Django') + @skipIf(sys.version_info.major == 3, "segfault in Django") def test_native_writer(self): values = { "identifier": "some_unique_id", "begin_time": datetime(2013, 8, 27, 10, 0, 0, tzinfo=utc), "end_time": datetime(2013, 8, 27, 10, 0, 10, tzinfo=utc), "footprint": MultiPolygon( - Polygon.from_bbox((0, 0, 10, 20)), - Polygon.from_bbox((10, 10, 30, 40)) - ) + Polygon.from_bbox((0, 0, 10, 20)), Polygon.from_bbox((10, 10, 30, 40)) + ), } writer = native.NativeFormat(env) f = StringIO() writer.write(values, f, pretty=True) - self.assertEqual(dedent("""\ + self.assertEqual( + dedent( + """\ some_unique_id 2013-08-27T10:00:00Z @@ -394,7 +407,10 @@ def test_native_writer(self): - """), dedent(f.getvalue())) + """ + ), + dedent(f.getvalue()), + ) def test_eoom_reader(self): xml = """ @@ -486,33 +502,33 @@ def test_eoom_reader(self): "begin_time": datetime(2006, 8, 16, 9, 9, 29, tzinfo=utc), "end_time": datetime(2006, 8, 16, 9, 12, 46, tzinfo=utc), "footprint": MultiPolygon( - Polygon.from_bbox((10, 20, 30, 40)), - Polygon.from_bbox((50, 60, 70, 80)) + Polygon.from_bbox((10, 20, 30, 40)), Polygon.from_bbox((50, 60, 70, 80)) ), - 'format': 'eogml', - 'metadata': { - 'acquisition_station': 'PDHS-E', - 'acquisition_sub_type': None, - 'antenna_look_direction': None, - 'availability_time': datetime(2006, 8, 16, 11, 3, 8, tzinfo=utc), - 'cloud_cover': None, - 'completion_time_from_ascending_node': None, - 'doppler_frequency': None, - 'highest_location': None, - 'illumination_azimuth_angle': None, - 'illumination_elevation_angle': None, - 'illumination_zenith_angle': None, - 'incidence_angle_variation': None, - 'lowest_location': None, - 'maximum_incidence_angle': None, - 'minimum_incidence_angle': None, - 'across_track_incidence_angle': None, - 'along_track_incidence_angle': None, - 'modification_date': None, - 'polarisation_mode': None, - 'polarization_channels': None, - 'snow_cover': None, - 'start_time_from_ascending_node': None} + "format": "eogml", + "metadata": { + "acquisition_station": "PDHS-E", + "acquisition_sub_type": None, + "antenna_look_direction": None, + "availability_time": datetime(2006, 8, 16, 11, 3, 8, tzinfo=utc), + "cloud_cover": None, + "completion_time_from_ascending_node": None, + "doppler_frequency": None, + "highest_location": None, + "illumination_azimuth_angle": None, + "illumination_elevation_angle": None, + "illumination_zenith_angle": None, + "incidence_angle_variation": None, + "lowest_location": None, + "maximum_incidence_angle": None, + "minimum_incidence_angle": None, + "across_track_incidence_angle": None, + "along_track_incidence_angle": None, + "modification_date": None, + "polarisation_mode": None, + "polarization_channels": None, + "snow_cover": None, + "start_time_from_ascending_node": None, + }, } self.maxDiff = None # self.assertEqual(expected, values) @@ -532,31 +548,159 @@ def test_dimap_reader(self): class CastingTest(TestCase): def test_cast(self): - coverage_type = create(CoverageType, - name="RGB" - ) - rectified_grid = Grid.objects.create( - name="rectified_grid", - coordinate_reference_system="EPSG:4326", - axis_1_name="x", - axis_1_type=0, - axis_1_offset="5", - axis_2_name="y", - axis_2_type=0, - axis_2_offset="5" + coverage_type = create(models.CoverageType, name="RGB") + rectified_grid = models.Grid.objects.create( + name="rectified_grid", + coordinate_reference_system="EPSG:4326", + axis_1_name="x", + axis_1_type=0, + axis_1_offset="5", + axis_2_name="y", + axis_2_type=0, + axis_2_offset="5", ) - create(Coverage, + create( + models.Coverage, identifier="rectified-1", - footprint=GEOSGeometry("MULTIPOLYGON (((-111.6210939999999994 26.8588260000000005, -113.0273439999999994 -4.0786740000000004, -80.6835939999999994 -9.7036739999999995, -68.0273439999999994 15.6088260000000005, -111.6210939999999994 26.8588260000000005)))"), + footprint=GEOSGeometry( + "MULTIPOLYGON (((-111.6210939999999994 26.8588260000000005, -113.0273439999999994 -4.0786740000000004, -80.6835939999999994 -9.7036739999999995, -68.0273439999999994 15.6088260000000005, -111.6210939999999994 26.8588260000000005)))" + ), begin_time=parse_datetime("2013-06-11T14:55:23Z"), end_time=parse_datetime("2013-06-11T14:55:23Z"), grid=rectified_grid, axis_1_size=100, axis_2_size=100, - coverage_type=coverage_type + coverage_type=coverage_type, ) - eo_object = EOObject.objects.get(identifier="rectified-1") - cast_object = cast_eo_object(eo_object) + eo_object = models.EOObject.objects.get(identifier="rectified-1") + cast_object = models.cast_eo_object(eo_object) + + self.assertEqual(type(cast_object), models.Coverage) + + +class CommandTestCaseMixIn(object): + def call_command(self, command_name, *args, **kwargs): + stdout = StringIO() + management.call_command( + command_name, + *args, + **kwargs, + stdout=stdout, + ) + return stdout + + +class CollectionImportCommandTestCase(CommandTestCaseMixIn, TestCase): + def setUp(self): + super().setUp() + self.coverage_type = create(models.CoverageType, name="RGB") + self.rectified_grid = models.Grid.objects.create( + name="rectified_grid", + coordinate_reference_system="EPSG:4326", + axis_1_name="x", + axis_1_type=0, + axis_1_offset="5", + axis_2_name="y", + axis_2_type=0, + axis_2_offset="5", + ) + self.coverage = create( + models.Coverage, + identifier="rectified-1", + grid=self.rectified_grid, + axis_1_size=100, + axis_2_size=100, + coverage_type=self.coverage_type, + ) + + self.product_type = create(models.ProductType, name="ProductTypeA") + self.product = models.Product.objects.create( + identifier="product-1", + product_type=self.product_type, + ) + + self.collection_type = models.CollectionType.objects.create( + name="CollectionTypeA" + ) + self.collection_type.allowed_coverage_types.add(self.coverage_type) + self.collection_type.allowed_product_types.add(self.product_type) + + self.collection = models.Collection.objects.create( + identifier="collection-1", + collection_type=self.collection_type, + ) + + def test_import_coverages_from_other_collection(self): + other_collection = models.Collection.objects.create( + identifier="collection-2", + collection_type=self.collection_type, + ) + + models.collection_insert_eo_object(other_collection, self.coverage) + + self.call_command( + "collection", + "import", + self.collection.identifier, + from_collections=[other_collection.identifier], + from_producttypes=None, + from_coveragetypes=[], + coverage_import=True, + product_import=False, + use_extent=False, + ) + + self.assertIn(self.coverage, self.collection.coverages.all()) + + def test_import_products_from_other_collection(self): + other_collection = models.Collection.objects.create( + identifier="collection-2", + collection_type=self.collection_type, + ) + + models.collection_insert_eo_object(other_collection, self.product) + + self.call_command( + "collection", + "import", + self.collection.identifier, + from_collections=[other_collection.identifier], + from_producttypes=[], + from_coveragetypes=[], + coverage_import=False, + product_import=True, + use_extent=False, + ) + + self.assertIn(self.product, self.collection.products.all()) + + def test_import_coverages_from_coverage_type(self): + self.call_command( + "collection", + "import", + self.collection.identifier, + from_collections=[], + from_producttypes=[], + from_coveragetypes=[self.coverage_type.name], + coverage_import=True, + product_import=False, + use_extent=False, + ) + + self.assertIn(self.coverage, self.collection.coverages.all()) + + def test_import_products_from_product_type(self): + self.call_command( + "collection", + "import", + self.collection.identifier, + from_collections=[], + from_producttypes=[self.product_type.name], + from_coveragetypes=[], + coverage_import=False, + product_import=True, + use_extent=False, + ) - self.assertEqual(type(cast_object), Coverage) + self.assertIn(self.product, self.collection.products.all())