/** * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * * The Apereo Foundation licenses this file to you under the Educational * Community License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License * at: * * http://opensource.org/licenses/ecl2.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * */ package org.opencastproject.index.service.catalog.adapter; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.opencastproject.index.service.catalog.adapter.CatalogUIAdapterFactory.CONF_FLAVOR_KEY; import static org.opencastproject.index.service.catalog.adapter.CatalogUIAdapterFactory.CONF_ORGANIZATION_KEY; import static org.opencastproject.index.service.catalog.adapter.CatalogUIAdapterFactory.CONF_TITLE_KEY; import org.opencastproject.index.service.catalog.adapter.events.ConfigurableEventDCCatalogUIAdapter; import org.opencastproject.index.service.exception.ListProviderException; import org.opencastproject.index.service.resources.list.api.ListProvidersService; import org.opencastproject.index.service.resources.list.query.ResourceListQueryImpl; import org.opencastproject.mediapackage.Catalog; import org.opencastproject.mediapackage.EName; import org.opencastproject.mediapackage.MediaPackage; import org.opencastproject.mediapackage.MediaPackageElementFlavor; import org.opencastproject.mediapackage.identifier.Id; import org.opencastproject.metadata.dublincore.DCMIPeriod; import org.opencastproject.metadata.dublincore.DublinCore; import org.opencastproject.metadata.dublincore.DublinCoreCatalog; import org.opencastproject.metadata.dublincore.DublinCoreValue; import org.opencastproject.metadata.dublincore.DublinCores; import org.opencastproject.metadata.dublincore.MetadataField; import org.opencastproject.security.api.Organization; import org.opencastproject.util.NotFoundException; import org.opencastproject.util.PropertiesUtil; import org.opencastproject.workspace.api.Workspace; import com.entwinemedia.fn.data.Opt; import org.easymock.Capture; import org.easymock.EasyMock; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Dictionary; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.TreeMap; public class DublinCoreCatalogUIAdapterTest { private static final Logger logger = LoggerFactory.getLogger(DublinCoreCatalogUIAdapterTest.class); private static final String TEMPORAL_DUBLIN_CORE_KEY = "temporal"; private static final String INPUT_PERIOD = "start=2014-11-04T19:35:19Z; end=2014-11-04T20:48:23Z; scheme=W3C-DTF;"; private static final String CHANGED_DURATION_PERIOD = "start=2014-11-04T19:35:19Z; end=2014-11-04T20:18:23Z; scheme=W3C-DTF;"; private static final String CHANGED_START_DATE_PERIOD = "start=2013-10-29T19:35:19Z; end=2013-10-29T20:48:23Z; scheme=W3C-DTF;"; private static final String CHANGED_START_TIME_PERIOD = "start=2014-11-04T18:35:19Z; end=2014-11-04T19:48:23Z; scheme=W3C-DTF;"; private static final String label = "The Label"; private static final String title = "title"; private static final String type = "text"; private static final String readOnly = "true"; private static final String required = "true"; private static final String listProvider = "list-provider"; private static final String collectionID = "collection id"; private static final String ORGANIZATION_STRING = "theOrganization"; private static final String FLAVOR_STRING = "type/subtype"; private static final String TITLE_STRING = "Event Metadata"; private Dictionary<String, String> dictionary; private Dictionary<String, String> eventProperties; private ListProvidersService listProvidersService; private MediaPackage mediapackage; private MediaPackageElementFlavor mediaPackageElementFlavor; private Workspace workspace; private Capture<InputStream> writtenCatalog; private File outputCatalog; private URI eventDublincoreURI; private EName temporalEname = new EName(DublinCore.TERMS_NS_URI, TEMPORAL_DUBLIN_CORE_KEY); private FileInputStream startDateTimeDurationCatalog; private DublinCoreCatalog dc; private MetadataField<String> startDateMetadataField; private MetadataField<String> startTimeMetadataField; private MetadataField<String> durationMetadataField; private DublinCoreMetadataCollection metadata; @Rule public TemporaryFolder testFolder = new TemporaryFolder(); @Before public void setUp() throws URISyntaxException, NotFoundException, IOException, ListProviderException { startDateTimeDurationCatalog = new FileInputStream(new File(getClass().getResource( "/catalog-adapter/start-date-time-duration.xml").toURI())); dc = DublinCores.read(startDateTimeDurationCatalog); metadata = new DublinCoreMetadataCollection(); startDateMetadataField = MetadataField.createTemporalStartDateMetadata(TEMPORAL_DUBLIN_CORE_KEY, Opt.some("startDate"), "START_DATE_LABEL", false, false, "yyyy-MM-dd", Opt.<Integer> none(), Opt.<String> none()); startTimeMetadataField = MetadataField.createTemporalStartTimeMetadata(TEMPORAL_DUBLIN_CORE_KEY, Opt.some("startTime"), "START_DATE_LABEL", false, false, "HH:mm:ss", Opt.<Integer> none(), Opt.<String> none()); durationMetadataField = MetadataField.createDurationMetadataField(TEMPORAL_DUBLIN_CORE_KEY, Opt.some("duration"), "DURATION_LABEL", false, false, Opt.<Integer> none(), Opt.<String> none()); TreeMap<String, String> collection = new TreeMap<String, String>(); collection.put("Entry 1", "Value 1"); collection.put("Entry 2", "Value 2"); collection.put("Entry 3", "Value 3"); BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class); EasyMock.replay(bundleContext); listProvidersService = EasyMock.createMock(ListProvidersService.class); EasyMock.expect( listProvidersService.getList(EasyMock.anyString(), EasyMock.anyObject(ResourceListQueryImpl.class), EasyMock.anyObject(Organization.class), EasyMock.anyBoolean())).andReturn(collection).anyTimes(); EasyMock.replay(listProvidersService); Properties props = new Properties(); InputStream in = getClass().getResourceAsStream("/catalog-adapter/event.properties"); props.load(in); in.close(); eventProperties = PropertiesUtil.toDictionary(props); mediaPackageElementFlavor = new MediaPackageElementFlavor(FLAVOR_STRING.split("/")[0], FLAVOR_STRING.split("/")[1]); eventDublincoreURI = getClass().getResource("/catalog-adapter/dublincore.xml").toURI(); outputCatalog = testFolder.newFile("out.xml"); Capture<String> mediapackageIDCapture = new Capture<String>(); Capture<String> catalogIDCapture = new Capture<String>(); Capture<String> filenameCapture = new Capture<String>(); writtenCatalog = new Capture<InputStream>(); workspace = EasyMock.createMock(Workspace.class); EasyMock.expect(workspace.get(eventDublincoreURI)).andReturn(new File(eventDublincoreURI)); EasyMock.expect( workspace.put(EasyMock.capture(mediapackageIDCapture), EasyMock.capture(catalogIDCapture), EasyMock.capture(filenameCapture), EasyMock.capture(writtenCatalog))).andReturn( outputCatalog.toURI()); EasyMock.replay(workspace); Catalog eventCatalog = EasyMock.createMock(Catalog.class); EasyMock.expect(eventCatalog.getIdentifier()).andReturn("CatalogID").anyTimes(); EasyMock.expect(eventCatalog.getURI()).andReturn(eventDublincoreURI).anyTimes(); eventCatalog.setURI(outputCatalog.toURI()); EasyMock.expectLastCall(); eventCatalog.setChecksum(null); EasyMock.expectLastCall(); EasyMock.replay(eventCatalog); Catalog[] catalogs = { eventCatalog }; Id id = EasyMock.createMock(Id.class); EasyMock.replay(id); mediapackage = EasyMock.createMock(MediaPackage.class); EasyMock.expect(mediapackage.getCatalogs(mediaPackageElementFlavor)).andReturn(catalogs).anyTimes(); EasyMock.expect(mediapackage.getIdentifier()).andReturn(id).anyTimes(); EasyMock.replay(mediapackage); dictionary = new Hashtable<String, String>(); dictionary.put(CONF_ORGANIZATION_KEY, ORGANIZATION_STRING); dictionary.put(CONF_FLAVOR_KEY, FLAVOR_STRING); dictionary.put(CONF_TITLE_KEY, TITLE_STRING); dictionary.put(MetadataField.CONFIG_PROPERTY_PREFIX + ".title." + MetadataField.CONFIG_INPUT_ID_KEY, title); dictionary.put(MetadataField.CONFIG_PROPERTY_PREFIX + ".title." + MetadataField.CONFIG_LABEL_KEY, label); dictionary.put(MetadataField.CONFIG_PROPERTY_PREFIX + ".title." + MetadataField.CONFIG_TYPE_KEY, type); dictionary.put(MetadataField.CONFIG_PROPERTY_PREFIX + ".title." + MetadataField.CONFIG_READ_ONLY_KEY, readOnly); dictionary.put(MetadataField.CONFIG_PROPERTY_PREFIX + ".title." + MetadataField.CONFIG_REQUIRED_KEY, required); dictionary.put(MetadataField.CONFIG_PROPERTY_PREFIX + ".title." + MetadataField.CONFIG_LIST_PROVIDER_KEY, listProvider); dictionary.put(MetadataField.CONFIG_PROPERTY_PREFIX + ".title." + MetadataField.CONFIG_COLLECTION_ID_KEY, collectionID); } @Test public void testGetDublinCorePropertyName() { String name = "title"; assertEquals( name, DublinCoreMetadataUtil.getDublinCorePropertyName( MetadataField.CONFIG_PROPERTY_PREFIX + "." + name + "." + MetadataField.CONFIG_INPUT_ID_KEY).get()); assertEquals(Opt.none(), DublinCoreMetadataUtil.getDublinCorePropertyName(MetadataField.CONFIG_PROPERTY_PREFIX + "." + name + ".")); assertEquals(Opt.none(), DublinCoreMetadataUtil.getDublinCorePropertyName(name + "." + MetadataField.CONFIG_INPUT_ID_KEY)); assertEquals( Opt.none(), DublinCoreMetadataUtil.getDublinCorePropertyName("Irrelevant." + name + "." + MetadataField.CONFIG_INPUT_ID_KEY)); } @Test public void testGetDublinCorePropertyKey() { String name = "title"; assertEquals( MetadataField.CONFIG_INPUT_ID_KEY, DublinCoreMetadataUtil.getDublinCorePropertyKey( MetadataField.CONFIG_PROPERTY_PREFIX + "." + name + "." + MetadataField.CONFIG_INPUT_ID_KEY).get()); } @Test public void testGetDublinCoreProperties() { Map<String, MetadataField<?>> dublinCoreProperties = DublinCoreMetadataUtil.getDublinCoreProperties(dictionary); assertEquals(1, dublinCoreProperties.size()); List<MetadataField<?>> metadataFields = new ArrayList<MetadataField<?>>(dublinCoreProperties.values()); assertEquals(title, metadataFields.get(0).getInputID()); assertEquals(label, metadataFields.get(0).getLabel()); assertEquals(MetadataField.Type.TEXT, metadataFields.get(0).getType()); assertEquals(true, metadataFields.get(0).isReadOnly()); assertEquals(true, metadataFields.get(0).isRequired()); assertEquals(listProvider, metadataFields.get(0).getListprovider().get()); assertEquals(collectionID, metadataFields.get(0).getCollectionID().get()); } @Test public void testStoreFields() throws Exception { String temporal = "temporal"; String expectedTemporal = "start=2016-03-01T09:27:35Z; end=2016-03-01T11:43:12Z; scheme=W3C-DTF;"; String expectedTitle = "New Value for Title"; String expectedMissing = "New Value for Missing"; ConfigurableEventDCCatalogUIAdapter configurationDublinCoreCatalogUIAdapter = new ConfigurableEventDCCatalogUIAdapter(); configurationDublinCoreCatalogUIAdapter.setListProvidersService(listProvidersService); configurationDublinCoreCatalogUIAdapter.setWorkspace(workspace); configurationDublinCoreCatalogUIAdapter.updated(eventProperties); DublinCoreMetadataCollection dublinCoreMetadata = new DublinCoreMetadataCollection(); MetadataField<String> titleField = MetadataField.createTextMetadataField(title, Opt.some(title), "New Label for Title", true, false, Opt.<Map<String, String>> none(), Opt.<String> none(), Opt.<Integer> none(), Opt.<String> none()); dublinCoreMetadata.addField(titleField, expectedTitle, listProvidersService); MetadataField<String> missingField = MetadataField.createTextMetadataField("missing", Opt.<String> none(), "The Missing's Label", false, false, Opt.<Map<String, String>> none(), Opt.<String> none(), Opt.<Integer> none(), Opt.<String> none()); dublinCoreMetadata.addField(missingField, expectedMissing, listProvidersService); MetadataField<String> durationField = MetadataField.createDurationMetadataField(temporal, Opt.some("duration"), label, true, true, Opt.<Integer> none(), Opt.<String> none()); dublinCoreMetadata.addField(durationField, "02:15:37", listProvidersService); MetadataField<String> startDate = MetadataField.createTemporalStartDateMetadata(temporal, Opt.some("startDate"), label, true, true, "yyyy-MM-dd", Opt.<Integer> none(), Opt.<String> none()); dublinCoreMetadata.addField(startDate, "2016-03-01", listProvidersService); MetadataField<String> startTime = MetadataField.createTemporalStartTimeMetadata(temporal, Opt.some("startTime"), label, true, true, "HH:mm:ss", Opt.<Integer> none(), Opt.<String> none()); dublinCoreMetadata.addField(startTime, "09:27:35", listProvidersService); configurationDublinCoreCatalogUIAdapter.storeFields(mediapackage, dublinCoreMetadata); assertTrue(writtenCatalog.hasCaptured()); DublinCoreCatalog updatedCatalog = DublinCores.read(writtenCatalog.getValue()); assertEquals(expectedTitle, updatedCatalog.get(new EName(DublinCore.TERMS_NS_URI, "title")).get(0).getValue()); assertEquals(expectedMissing, updatedCatalog.get(new EName(DublinCore.TERMS_NS_URI, "missing")).get(0).getValue()); assertEquals(expectedTemporal, updatedCatalog.get(new EName(DublinCore.TERMS_NS_URI, temporal)).get(0).getValue()); } @Test public void testGetCurrentStartTime() { int startHour = 19; int startMinute = 35; int startSecond = 19; int endHour = 20; int endMinute = 48; int endSecond = 23; // Test a none() period Opt<DCMIPeriod> emptyPeriod = Opt.<DCMIPeriod> none(); DateTime result = DublinCoreMetadataUtil.getCurrentStartTime(emptyPeriod); assertEquals(0, result.getHourOfDay()); assertEquals(0, result.getMinuteOfHour()); assertEquals(0, result.getSecondOfMinute()); DateTime periodStart = new DateTime(2014, 11, 04, startHour, startMinute, startSecond, DateTimeZone.UTC); DateTime periodEnd = new DateTime(2014, 11, 04, endHour, endMinute, endSecond, DateTimeZone.UTC); // Test a period that is missing the start date DCMIPeriod withoutStartPeriod = new DCMIPeriod(null, periodEnd.toDate()); result = DublinCoreMetadataUtil.getCurrentStartTime(Opt.some(withoutStartPeriod)); assertEquals(0, result.getHourOfDay()); assertEquals(0, result.getMinuteOfHour()); assertEquals(0, result.getSecondOfMinute()); // Test a period with a start but no end. DCMIPeriod withoutEndPeriod = new DCMIPeriod(periodStart.toDate(), null); result = DublinCoreMetadataUtil.getCurrentStartTime(Opt.some(withoutEndPeriod)); assertEquals(startHour, result.getHourOfDay()); assertEquals(startMinute, result.getMinuteOfHour()); assertEquals(startSecond, result.getSecondOfMinute()); // Test a period with both a start and an end. DCMIPeriod standardPeriod = new DCMIPeriod(periodStart.toDate(), periodEnd.toDate()); result = DublinCoreMetadataUtil.getCurrentStartTime(Opt.some(standardPeriod)); assertEquals(startHour, result.getHourOfDay()); assertEquals(startMinute, result.getMinuteOfHour()); assertEquals(startSecond, result.getSecondOfMinute()); } @Test public void testGetDuration() { int startHour = 19; int startMinute = 35; int startSecond = 19; int endHour = 20; int endMinute = 48; int endSecond = 23; // Test a none() period Opt<DCMIPeriod> emptyPeriod = Opt.<DCMIPeriod> none(); Long result = DublinCoreMetadataUtil.getDuration(emptyPeriod); assertEquals(new Long(0L), result); DateTime periodStart = new DateTime(2014, 11, 04, startHour, startMinute, startSecond, DateTimeZone.UTC); DateTime periodEnd = new DateTime(2014, 11, 04, endHour, endMinute, endSecond, DateTimeZone.UTC); // Test a period that is missing the start date DCMIPeriod withoutStartPeriod = new DCMIPeriod(null, periodEnd.toDate()); result = DublinCoreMetadataUtil.getDuration(Opt.some(withoutStartPeriod)); assertEquals(new Long(0L), result); // Test a period with a start but no end. DCMIPeriod withoutEndPeriod = new DCMIPeriod(periodStart.toDate(), null); result = DublinCoreMetadataUtil.getDuration(Opt.some(withoutEndPeriod)); assertEquals(new Long(0L), result); // Test a period with both a start and an end. DCMIPeriod standardPeriod = new DCMIPeriod(periodStart.toDate(), periodEnd.toDate()); result = DublinCoreMetadataUtil.getDuration(Opt.some(standardPeriod)); assertEquals(new Long(4384000L), result); } @Test public void testSetTemporalStartDateInputEmptyValueExpectsNoChange() throws IOException, URISyntaxException { metadata.addField(startDateMetadataField, "2013-10-29", listProvidersService); DublinCoreMetadataUtil.setTemporalStartDate(dc, startDateMetadataField, temporalEname); List<DublinCoreValue> result = dc.get(temporalEname); assertEquals(1, result.size()); assertEquals(INPUT_PERIOD, result.get(0).getValue()); } @Test public void testSetTemporalStartDateInputNewValueExpectsChange() throws IOException, URISyntaxException { startDateMetadataField.setValue("2013-10-29"); metadata.addField(startDateMetadataField, "2013-10-29", listProvidersService); DublinCoreMetadataUtil.setTemporalStartDate(dc, startDateMetadataField, temporalEname); List<DublinCoreValue> result = dc.get(temporalEname); assertEquals(1, result.size()); assertEquals(CHANGED_START_DATE_PERIOD, result.get(0).getValue()); } @Test public void testSetTemporalStartTimeInputEmptyValueExpectsNoChange() throws IOException, URISyntaxException { metadata.addField(startTimeMetadataField, "", listProvidersService); DublinCoreMetadataUtil.setTemporalStartDate(dc, startTimeMetadataField, temporalEname); List<DublinCoreValue> result = dc.get(temporalEname); assertEquals(1, result.size()); assertEquals(INPUT_PERIOD, result.get(0).getValue()); } @Test public void testSetTemporalStartTimeInputNewValueExpectsChange() throws IOException, URISyntaxException { startTimeMetadataField.setValue("18:35:19"); metadata.addField(startTimeMetadataField, "18:35:19", listProvidersService); DublinCoreMetadataUtil.setTemporalStartTime(dc, startTimeMetadataField, temporalEname); List<DublinCoreValue> result = dc.get(temporalEname); assertEquals(1, result.size()); assertEquals(CHANGED_START_TIME_PERIOD, result.get(0).getValue()); } @Test public void testSetDurationInputEmptyValueExpectsNoChange() throws IOException, URISyntaxException { metadata.addField(durationMetadataField, "", listProvidersService); DublinCoreMetadataUtil.setTemporalStartDate(dc, startTimeMetadataField, temporalEname); DublinCoreMetadataUtil.setDuration(dc, durationMetadataField, temporalEname); List<DublinCoreValue> result = dc.get(temporalEname); assertEquals(1, result.size()); assertEquals(INPUT_PERIOD, result.get(0).getValue()); } @Test public void testSetDurationInputNewValueExpectsChange() throws IOException, URISyntaxException { metadata.addField(durationMetadataField, "2584000", listProvidersService); DublinCoreMetadataUtil.setDuration(dc, metadata.getOutputFields().get("duration"), temporalEname); List<DublinCoreValue> result = dc.get(temporalEname); assertEquals(1, result.size()); assertEquals(CHANGED_DURATION_PERIOD, result.get(0).getValue()); } @Test public void testUpdateDublincoreCatalog() throws IOException, URISyntaxException { FileInputStream fis = new FileInputStream(new File(getClass().getResource( "/catalog-adapter/start-date-time-duration.xml").toURI())); DublinCoreCatalog catalog = DublinCores.read(fis); MetadataField<String> startDate = MetadataField.createTemporalStartDateMetadata(TEMPORAL_DUBLIN_CORE_KEY, Opt.some("startDate"), "START_DATE_LABEL", false, false, "yyyy-MM-dd", Opt.<Integer> none(), Opt.<String> none()); DublinCoreMetadataCollection metadata = new DublinCoreMetadataCollection(); metadata.addField(startDate, "2014-11-01", listProvidersService); DublinCoreMetadataUtil.updateDublincoreCatalog(catalog, metadata); logger.info("Catalog:" + catalog.toXmlString()); } }