/** * 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.workflow.handler.composer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.opencastproject.composer.api.ComposerService; import org.opencastproject.composer.api.EncoderException; import org.opencastproject.composer.api.EncodingProfileImpl; import org.opencastproject.composer.layout.Dimension; import org.opencastproject.job.api.Job; import org.opencastproject.job.api.JobBarrier; import org.opencastproject.mediapackage.MediaPackage; import org.opencastproject.mediapackage.MediaPackageElement; import org.opencastproject.mediapackage.MediaPackageElementFlavor; import org.opencastproject.mediapackage.MediaPackageException; import org.opencastproject.mediapackage.Track; import org.opencastproject.mediapackage.VideoStream; import org.opencastproject.mediapackage.track.TrackImpl; import org.opencastproject.mediapackage.track.VideoStreamImpl; import org.opencastproject.serviceregistry.api.ServiceRegistry; import org.opencastproject.serviceregistry.api.ServiceRegistryException; import org.opencastproject.util.NotFoundException; import org.opencastproject.util.data.Collections; import org.opencastproject.workflow.api.WorkflowOperationException; import org.opencastproject.workflow.api.WorkflowOperationInstance; import org.easymock.EasyMock; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; /** * Test class for {@link PartialImportWorkflowOperationHandler} */ public class PartialImportWorkflowOperationHandlerTest { // Target flavors private static final String PRESENTER_TARGET_FLAVOR_STRING = "presenter/target"; private static final MediaPackageElementFlavor PRESENTER_TARGET_FLAVOR = MediaPackageElementFlavor .parseFlavor(PRESENTER_TARGET_FLAVOR_STRING); private static final String PRESENTATION_TARGET_FLAVOR_STRING = "presentation/target"; private static final MediaPackageElementFlavor PRESENTATION_TARGET_FLAVOR = MediaPackageElementFlavor .parseFlavor(PRESENTATION_TARGET_FLAVOR_STRING); private static List<String> defaultExtensions = new ArrayList<String>(); private static List<String> moreExtensions = new ArrayList<String>(); @BeforeClass public static void setUpClass() { defaultExtensions.add("mp4"); moreExtensions.add("mp4"); moreExtensions.add("mov"); } @Test public void trackNeedsTobeEncodedToStandardInputMp4ReturnsFalse() throws URISyntaxException { Track track = EasyMock.createMock(Track.class); EasyMock.expect(track.getURI()) .andReturn( new URI( "http://mh-allinone.localdomain/files/mediapackage/4631bade-04ae-4369-a38f-63a9a0f2e5bf/9404c35b-9463-4932-ad88-0f7030c2448e/audio.mp4")) .anyTimes(); EasyMock.replay(track); boolean result = PartialImportWorkflowOperationHandler.trackNeedsTobeEncodedToStandard(track, defaultExtensions); assertFalse(result); } @Test public void trackNeedsTobeEncodedToStandardInputNoExtensionReturnsTrue() throws URISyntaxException { Track track = EasyMock.createMock(Track.class); EasyMock.expect(track.getURI()) .andReturn( new URI( "http://mh-allinone.localdomain/files/mediapackage/4631bade-04ae-4369-a38f-63a9a0f2e5bf/9404c35b-9463-4932-ad88-0f7030c2448e/audio")) .anyTimes(); EasyMock.replay(track); boolean result = PartialImportWorkflowOperationHandler.trackNeedsTobeEncodedToStandard(track, defaultExtensions); assertTrue(result); } @Test public void trackNeedsTobeEncodedToStandardInputOnlyPeriodExtensionReturnsTrue() throws URISyntaxException { Track track = EasyMock.createMock(Track.class); EasyMock.expect(track.getURI()) .andReturn( new URI( "http://mh-allinone.localdomain/files/mediapackage/4631bade-04ae-4369-a38f-63a9a0f2e5bf/9404c35b-9463-4932-ad88-0f7030c2448e/audio.")) .anyTimes(); EasyMock.replay(track); boolean result = PartialImportWorkflowOperationHandler.trackNeedsTobeEncodedToStandard(track, defaultExtensions); assertTrue(result); } @Test public void trackNeedsTobeEncodedToStandardInputMovExtensionOnlyMp4AllowedReturnsTrue() throws URISyntaxException { Track track = EasyMock.createMock(Track.class); EasyMock.expect(track.getURI()) .andReturn( new URI( "http://mh-allinone.localdomain/files/mediapackage/4631bade-04ae-4369-a38f-63a9a0f2e5bf/9404c35b-9463-4932-ad88-0f7030c2448e/audio.mov")) .anyTimes(); EasyMock.replay(track); boolean result = PartialImportWorkflowOperationHandler.trackNeedsTobeEncodedToStandard(track, defaultExtensions); assertTrue(result); } @Test public void trackNeedsTobeEncodedToStandardInputMovMp4AndMovAllowedReturnsFalse() throws URISyntaxException { Track track = EasyMock.createMock(Track.class); EasyMock.expect(track.getURI()) .andReturn( new URI( "http://mh-allinone.localdomain/files/mediapackage/4631bade-04ae-4369-a38f-63a9a0f2e5bf/9404c35b-9463-4932-ad88-0f7030c2448e/audio.mov")) .anyTimes(); EasyMock.replay(track); boolean result = PartialImportWorkflowOperationHandler.trackNeedsTobeEncodedToStandard(track, moreExtensions); assertFalse(result); } private Track createTrack(MediaPackageElementFlavor flavor, String filename, boolean video, boolean audio) throws URISyntaxException { Track track = EasyMock.createMock(Track.class); EasyMock.expect(track.getFlavor()).andReturn(flavor).anyTimes(); EasyMock.expect(track.hasAudio()).andReturn(audio).anyTimes(); EasyMock.expect(track.hasVideo()).andReturn(video).anyTimes(); EasyMock.expect(track.getURI()).andReturn(new URI(filename)).anyTimes(); EasyMock.replay(track); return track; } @Test public void getRequiredExtensionsInput3ExtensionsExpect3InList() { WorkflowOperationInstance operation = EasyMock.createMock(WorkflowOperationInstance.class); EasyMock.expect(operation.getConfiguration("required-extensions")).andReturn("mp4,mov,m4a"); EasyMock.replay(operation); PartialImportWorkflowOperationHandler handler = new PartialImportWorkflowOperationHandler(); List<String> result = handler.getRequiredExtensions(operation); assertEquals("There should be 3 required extensions", 3, result.size()); } @Test public void checkForMuxingInputPresenterVideoPresenterAudioNoAudioSuffixExpectsNoMux() throws EncoderException, MediaPackageException, WorkflowOperationException, NotFoundException, ServiceRegistryException, IOException, URISyntaxException { // Setup tracks Track audioTrack = createTrack(PRESENTER_TARGET_FLAVOR, "audio.mp4", false, true); Track videoTrack = createTrack(PRESENTER_TARGET_FLAVOR, "video.mp4", true, false); Track[] tracks = { audioTrack, videoTrack }; // Setup media package MediaPackage mediaPackage = EasyMock.createMock(MediaPackage.class); EasyMock.expect(mediaPackage.getTracks()).andReturn(tracks).anyTimes(); ComposerService composerService = EasyMock.createMock(ComposerService.class); // Replay all mocks EasyMock.replay(composerService, mediaPackage); // Make sure that the composer service was not called. EasyMock.verify(composerService); PartialImportWorkflowOperationHandler handler = new PartialImportWorkflowOperationHandler(); handler.setComposerService(composerService); handler.checkForMuxing(mediaPackage, PRESENTATION_TARGET_FLAVOR, PRESENTER_TARGET_FLAVOR, false, new ArrayList<MediaPackageElement>()); } @Test public void checkForMuxingInputPresentationVideoPresentationAudioExpectsNoMux() throws EncoderException, MediaPackageException, WorkflowOperationException, NotFoundException, ServiceRegistryException, IOException, URISyntaxException { // Setup tracks Track audioTrack = createTrack(PRESENTATION_TARGET_FLAVOR, "audio.mp4", false, true); Track videoTrack = createTrack(PRESENTATION_TARGET_FLAVOR, "video.mp4", true, false); Track[] tracks = { audioTrack, videoTrack }; // Setup media package MediaPackage mediaPackage = EasyMock.createMock(MediaPackage.class); EasyMock.expect(mediaPackage.getTracks()).andReturn(tracks).anyTimes(); ComposerService composerService = EasyMock.createMock(ComposerService.class); // Replay all mocks EasyMock.replay(composerService, mediaPackage); // Make sure that the composer service was not called. EasyMock.verify(composerService); PartialImportWorkflowOperationHandler handler = new PartialImportWorkflowOperationHandler(); handler.setComposerService(composerService); handler.checkForMuxing(mediaPackage, PRESENTATION_TARGET_FLAVOR, PRESENTER_TARGET_FLAVOR, false, new ArrayList<MediaPackageElement>()); } @Test public void checkForMuxingInputPresenterVideoPresentationAudioExpectsMux() throws EncoderException, MediaPackageException, WorkflowOperationException, NotFoundException, ServiceRegistryException, IOException, URISyntaxException { // Setup tracks Track audioTrack = createTrack(PRESENTER_TARGET_FLAVOR, "audio.mp4", false, true); Track videoTrack = createTrack(PRESENTATION_TARGET_FLAVOR, "video.mp4", true, false); Track[] tracks = { audioTrack, videoTrack }; // Setup media package MediaPackage mediaPackage = EasyMock.createMock(MediaPackage.class); EasyMock.expect(mediaPackage.getTracks()).andReturn(tracks).anyTimes(); // Create a Job for the mux Job to return. Job muxJob = EasyMock.createMock(Job.class); EasyMock.expect(muxJob.getId()).andReturn(1L); // Create the composer service to track muxing of tracks. ComposerService composerService = EasyMock.createMock(ComposerService.class); EasyMock.expect(composerService.mux(videoTrack, audioTrack, PrepareAVWorkflowOperationHandler.MUX_AV_PROFILE)) .andReturn(muxJob); // Service Registry ServiceRegistry serviceRegistry = EasyMock.createMock(ServiceRegistry.class); EasyMock.expect(serviceRegistry.getJob(1L)).andReturn(muxJob); // Replay all mocks EasyMock.replay(composerService, mediaPackage, serviceRegistry); TestPartialImportWorkflowOperationHandler handler = new TestPartialImportWorkflowOperationHandler(videoTrack, audioTrack); handler.setComposerService(composerService); handler.setServiceRegistry(serviceRegistry); handler.checkForMuxing(mediaPackage, PRESENTATION_TARGET_FLAVOR, PRESENTER_TARGET_FLAVOR, false, new ArrayList<MediaPackageElement>()); } @Test public void checkForMuxingInputPresentationVideoPresenterAudioExpectsMux() throws EncoderException, MediaPackageException, WorkflowOperationException, NotFoundException, ServiceRegistryException, IOException, URISyntaxException { // Setup tracks Track audioTrack = createTrack(PRESENTATION_TARGET_FLAVOR, "audio.mp4", false, true); Track videoTrack = createTrack(PRESENTER_TARGET_FLAVOR, "video.mp4", true, false); Track[] tracks = { audioTrack, videoTrack }; // Setup media package MediaPackage mediaPackage = EasyMock.createMock(MediaPackage.class); EasyMock.expect(mediaPackage.getTracks()).andReturn(tracks).anyTimes(); // Create a Job for the mux Job to return. Job muxJob = EasyMock.createMock(Job.class); EasyMock.expect(muxJob.getId()).andReturn(1L); // Create the composer service to track muxing of tracks. ComposerService composerService = EasyMock.createMock(ComposerService.class); EasyMock.expect(composerService.mux(videoTrack, audioTrack, PrepareAVWorkflowOperationHandler.MUX_AV_PROFILE)) .andReturn(muxJob); // Service Registry ServiceRegistry serviceRegistry = EasyMock.createMock(ServiceRegistry.class); EasyMock.expect(serviceRegistry.getJob(1L)).andReturn(muxJob); // Replay all mocks EasyMock.replay(composerService, mediaPackage, serviceRegistry); TestPartialImportWorkflowOperationHandler handler = new TestPartialImportWorkflowOperationHandler(videoTrack, audioTrack); handler.setComposerService(composerService); handler.setServiceRegistry(serviceRegistry); handler.checkForMuxing(mediaPackage, PRESENTATION_TARGET_FLAVOR, PRESENTER_TARGET_FLAVOR, false, new ArrayList<MediaPackageElement>()); } @Test public void testDetermineDimension() throws Exception { // Setup tracks VideoStreamImpl videoStream = new VideoStreamImpl("test1"); videoStream.setFrameWidth(80); videoStream.setFrameHeight(30); VideoStreamImpl videoStream2 = new VideoStreamImpl("test2"); videoStream2.setFrameWidth(101); videoStream2.setFrameHeight(50); TrackImpl videoTrack = new TrackImpl(); videoTrack.setURI(URI.create("/test")); videoTrack.setVideo(Collections.list((VideoStream) videoStream)); TrackImpl videoTrack2 = new TrackImpl(); videoTrack2.setURI(URI.create("/test")); videoTrack2.setVideo(Collections.list((VideoStream) videoStream2)); List<Track> tracks = Collections.list((Track) videoTrack, (Track) videoTrack2); EncodingProfileImpl encodingProfile = new EncodingProfileImpl(); encodingProfile.setIdentifier("test"); ComposerService composerService = EasyMock.createMock(ComposerService.class); EasyMock.expect( composerService.concat(encodingProfile.getIdentifier(), Dimension.dimension(101, 50), tracks.toArray(new Track[tracks.size()]))).andReturn(null).once(); EasyMock.expect( composerService.concat(encodingProfile.getIdentifier(), Dimension.dimension(100, 50), tracks.toArray(new Track[tracks.size()]))).andReturn(null).once(); EasyMock.replay(composerService); PartialImportWorkflowOperationHandler handler = new PartialImportWorkflowOperationHandler(); handler.setComposerService(composerService); handler.startConcatJob(encodingProfile, tracks, -1.0F, false); handler.startConcatJob(encodingProfile, tracks, -1.0F, true); } /** * Test class to verify that muxing is done as expected without circumventing the service registry. */ private class TestPartialImportWorkflowOperationHandler extends PartialImportWorkflowOperationHandler { private Track expectedVideo = null; private Track expectedAudio = null; TestPartialImportWorkflowOperationHandler() { super(); } TestPartialImportWorkflowOperationHandler(Track expectedVideo, Track expectedAudio) { this.expectedVideo = expectedVideo; this.expectedAudio = expectedAudio; } @Override protected long mux(MediaPackage mediaPackage, Track video, Track audio, List<MediaPackageElement> elementsToClean) throws EncoderException, MediaPackageException, WorkflowOperationException, NotFoundException, ServiceRegistryException, IOException { if (expectedVideo == null || expectedAudio == null) { Assert.fail("This test was not expected to mux a video and audio track together."); } else if (expectedVideo != video || expectedAudio != audio) { Assert.fail("The expected tracks are not being muxed together."); } return 100L; } @Override protected JobBarrier.Result waitForStatus(Job... jobs) throws IllegalStateException, IllegalArgumentException { JobBarrier.Result result = EasyMock.createMock(JobBarrier.Result.class); EasyMock.expect(result.isSuccess()).andReturn(true); EasyMock.replay(result); return result; } } }