Java tutorial
/** * Copyright (c) Codice Foundation * * <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU * Lesser General Public License as published by the Free Software Foundation, either version 3 of * the License, or any later version. * * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public * License is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package org.codice.ddf.configuration.migration; import com.github.npathai.hamcrestopt.OptionalMatchers; import com.google.common.base.Charsets; import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; import java.util.stream.Stream; import java.util.zip.ZipFile; import org.apache.commons.io.input.NullInputStream; import org.codice.ddf.migration.Migratable; import org.codice.ddf.migration.MigrationException; import org.codice.ddf.migration.MigrationOperation; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.AdditionalAnswers; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; public class ImportMigrationManagerImplTest extends AbstractMigrationReportTest { private static final String MIGRATABLE_ID2 = "test-migratable-2"; private static final String MIGRATABLE_ID3 = "test-migratable-3"; private static final Path DIR_PATH = Paths.get("some", "dir"); private final Migratable migratable2 = Mockito.mock(Migratable.class); private final Migratable migratable3 = Mockito.mock(Migratable.class); private final Migratable[] migratables = new Migratable[] { migratable, migratable2, migratable3 }; private final ZipFile zip = Mockito.mock(ZipFile.class); private Path exportFile; private ZipEntry zipEntry; private ImportMigrationManagerImpl mgr; public ImportMigrationManagerImplTest() { super(MigrationOperation.IMPORT); } @Before public void setup() throws Exception { exportFile = ddfHome.resolve(createDirectory("exported")).resolve("exported.zip"); initMigratableMock(); initMigratableMock(migratable2, MIGRATABLE_ID2); initMigratableMock(migratable3, MIGRATABLE_ID3); zipEntry = getMetadataZipEntry(zip, Optional.of(MigrationContextImpl.CURRENT_VERSION), Optional.of(PRODUCT_VERSION)); // use answer to ensure we create a new stream each time if called multiple times Mockito.doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return Stream.of(zipEntry); } }).when(zip).stream(); mgr = new ImportMigrationManagerImpl(report, exportFile, Stream.of(migratables), zip); } private ZipEntry getMetadataZipEntry(ZipFile zip, Optional<String> version, Optional<String> productVersion) throws IOException { final StringBuilder sb = new StringBuilder(); sb.append("{\"dummy\":\"dummy"); version.ifPresent( v -> sb.append("\",\"").append(MigrationContextImpl.METADATA_VERSION).append("\":\"").append(v)); productVersion.ifPresent(v -> sb.append("\",\"").append(MigrationContextImpl.METADATA_PRODUCT_VERSION) .append("\":\"").append(v)); sb.append("\",\"").append(MigrationContextImpl.METADATA_MIGRATABLES).append("\":{"); boolean first = true; for (final Migratable m : migratables) { if (first) { first = false; } else { sb.append(","); } sb.append("\"").append(m.getId()).append("\":{\"").append(MigrationContextImpl.METADATA_VERSION) .append("\":\"").append(m.getVersion()).append("\",\"") .append(MigrationContextImpl.METADATA_TITLE).append("\":\"").append(m.getTitle()) .append("\",\"").append(MigrationContextImpl.METADATA_DESCRIPTION).append("\":\"") .append(m.getDescription()).append("\",\"").append(MigrationContextImpl.METADATA_ORGANIZATION) .append("\":\"").append(m.getOrganization()).append("\"}"); } sb.append("\"}"); final ZipEntry ze = Mockito.mock(ZipEntry.class); Mockito.when(ze.getName()).thenReturn(MigrationContextImpl.METADATA_FILENAME.toString()); Mockito.when(ze.isDirectory()).thenReturn(false); // use answer to ensure we create a new stream each time if called multiple times Mockito.doAnswer( AdditionalAnswers.answer(zea -> new ByteArrayInputStream(sb.toString().getBytes(Charsets.UTF_8)))) .when(zip).getInputStream(ze); return ze; } private ZipEntry getDirZipEntry(ZipFile zip, String migratableId, Path path) throws IOException { final ZipEntry ze = Mockito.mock(ZipEntry.class); Mockito.when(ze.getName()).thenReturn(Paths.get(migratableId).resolve(path).toString() + '/'); Mockito.when(ze.isDirectory()).thenReturn(true); // use answer to ensure we create a new stream each time if called multiple times Mockito.doAnswer(AdditionalAnswers.answer(zea -> new NullInputStream(0L))).when(zip).getInputStream(ze); return ze; } @Test public void testConstructor() throws Exception { Assert.assertThat(mgr.getReport(), Matchers.sameInstance(report)); Assert.assertThat(mgr.getExportFile(), Matchers.sameInstance(exportFile)); Assert.assertThat( mgr.getContexts().stream().map(ImportMigrationContextImpl::getMigratable) .toArray(Migratable[]::new), Matchers.arrayContaining(Matchers.sameInstance(migratable), Matchers.sameInstance(migratable2), Matchers.sameInstance(migratable3), Matchers.nullValue())); // null correspond to the system context } @Test public void testConstructorWithAdditionalMigratable() throws Exception { final Migratable migratable4 = Mockito.mock(Migratable.class); initMigratableMock(migratable4, "test-migratable-4"); mgr = new ImportMigrationManagerImpl(report, exportFile, Stream.concat(Stream.of(migratables), Stream.of(migratable4)), zip); Assert.assertThat(mgr.getReport(), Matchers.sameInstance(report)); Assert.assertThat(mgr.getExportFile(), Matchers.sameInstance(exportFile)); Assert.assertThat( mgr.getContexts().stream().map(ImportMigrationContextImpl::getMigratable) .toArray(Migratable[]::new), Matchers.arrayContaining(Matchers.sameInstance(migratable), Matchers.sameInstance(migratable2), Matchers.sameInstance(migratable3), Matchers.sameInstance(migratable4), Matchers.nullValue())); // null correspond to the system context } @Test public void testConstructorWithLessMigratables() throws Exception { mgr = new ImportMigrationManagerImpl(report, exportFile, Stream.of(migratable, migratable3), zip); Assert.assertThat(mgr.getReport(), Matchers.sameInstance(report)); Assert.assertThat(mgr.getExportFile(), Matchers.sameInstance(exportFile)); Assert.assertThat( mgr.getContexts().stream().map(ImportMigrationContextImpl::getMigratable) .toArray(Migratable[]::new), Matchers.arrayContaining(Matchers.sameInstance(migratable), Matchers.sameInstance(migratable3), Matchers.nullValue(), // null correspond to the system context Matchers.nullValue())); // null for migratable2 Assert.assertThat(mgr.getContexts().stream().map(ImportMigrationContextImpl::getId).toArray(String[]::new), Matchers.arrayContaining(Matchers.equalTo(MIGRATABLE_ID), Matchers.equalTo(MIGRATABLE_ID3), Matchers.nullValue(), // null correspond to the system context Matchers.equalTo(MIGRATABLE_ID2))); } @Test public void testConstructorWithDuplicateMigratableIds() throws Exception { final Migratable migratable2_2 = Mockito.mock(Migratable.class); initMigratableMock(migratable2_2, MIGRATABLE_ID2); Assert.assertThat(mgr.getReport(), Matchers.sameInstance(report)); Assert.assertThat(mgr.getExportFile(), Matchers.sameInstance(exportFile)); Assert.assertThat( mgr.getContexts().stream().map(ImportMigrationContextImpl::getMigratable) .toArray(Migratable[]::new), Matchers.arrayContaining(Matchers.sameInstance(migratable), Matchers.sameInstance(migratable2), Matchers.sameInstance(migratable3), Matchers.nullValue())); // null correspond to the system context } @Test public void testConstructorWithNullReport() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage(Matchers.containsString("null report")); new ImportMigrationManagerImpl(null, exportFile, Stream.empty(), zip); } @Test public void testConstructorWithInvalidReport() throws Exception { final MigrationReportImpl report = new MigrationReportImpl(MigrationOperation.EXPORT, Optional.empty()); thrown.expect(IllegalArgumentException.class); thrown.expectMessage(Matchers.containsString("invalid migration operation")); new ImportMigrationManagerImpl(report, exportFile, Stream.empty(), zip); } @Test public void testConstructorWithNullExportFile() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage(Matchers.containsString("null export file")); new ImportMigrationManagerImpl(report, null, Stream.empty()); } @Test public void testConstructorWithNullMigratables() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage(Matchers.containsString("null migratables")); new ImportMigrationManagerImpl(report, exportFile, null, zip); } @Test public void testConstructorWhenZipFileNotFound() throws Exception { thrown.expect(MigrationException.class); thrown.expectCause(Matchers.instanceOf(FileNotFoundException.class)); new ImportMigrationManagerImpl(report, exportFile, Stream.empty()); } @Test public void testConstructorWhenUnableToProcessMetadata() throws Exception { final IOException ioe = new IOException("testing"); Mockito.doThrow(ioe).when(zip).getInputStream(zipEntry); thrown.expect(MigrationException.class); thrown.expectCause(Matchers.sameInstance(ioe)); new ImportMigrationManagerImpl(report, exportFile, Stream.empty(), zip); } @Test public void testConstructorWhenZipIsOfInvalidVersion() throws Exception { zipEntry = getMetadataZipEntry(zip, Optional.of(VERSION), Optional.of(PRODUCT_VERSION)); thrown.expect(MigrationException.class); thrown.expectMessage("unsupported exported version"); new ImportMigrationManagerImpl(report, exportFile, Stream.empty(), zip); } @Test public void testDoImport() throws Exception { mgr.doImport(PRODUCT_VERSION); Mockito.verify(migratable).doImport(Mockito.notNull()); Mockito.verify(migratable2).doImport(Mockito.notNull()); Mockito.verify(migratable3).doImport(Mockito.notNull()); } @Test public void testConstructorWithDirectoryEntriesInZip() throws Exception { final ZipEntry zipDirEntry = getDirZipEntry(zip, MIGRATABLE_ID, DIR_PATH); Mockito.doReturn(Stream.of(zipEntry, zipDirEntry)).when(zip).stream(); Assert.assertThat(mgr.getReport(), Matchers.sameInstance(report)); Assert.assertThat(mgr.getExportFile(), Matchers.sameInstance(exportFile)); Assert.assertThat( mgr.getContexts().stream().map(ImportMigrationContextImpl::getMigratable) .toArray(Migratable[]::new), Matchers.arrayContaining(Matchers.sameInstance(migratable), Matchers.sameInstance(migratable2), Matchers.sameInstance(migratable3), Matchers.nullValue())); // null correspond to the system context Assert.assertThat( mgr.getContexts().stream().filter(c -> c.getMigratable() == migratable) .map(ImportMigrationContextImpl::getEntries).findFirst(), OptionalMatchers.hasValue(Matchers.anEmptyMap())); } @Test public void testDoImportWhenOneMigratableAborts() throws Exception { final MigrationException me = new MigrationException("testing"); Mockito.doThrow(me).when(migratable2).doImport(Mockito.any()); thrown.expect(Matchers.sameInstance(me)); mgr.doImport(PRODUCT_VERSION); Mockito.verify(migratable).doImport(Mockito.notNull()); Mockito.verify(migratable2).doImport(Mockito.notNull()); Mockito.verify(migratable3, Mockito.never()).doImport(Mockito.notNull()); } @Test public void testDoImportWithNullProductVersion() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage(Matchers.containsString("null product version")); mgr.doImport(null); } @Test public void testDoImportWithInvalidProductVersion() throws Exception { thrown.expect(MigrationException.class); thrown.expectMessage(Matchers.containsString("mismatched product version")); mgr.doImport(PRODUCT_VERSION + "2"); } @Test public void testClose() throws Exception { mgr.close(); Mockito.verify(zip).close(); } }