/**
* Copyright (c) 2009 - 2012 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package org.candlepin.controller;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.candlepin.audit.Event;
import org.candlepin.audit.EventFactory;
import org.candlepin.audit.EventSink;
import org.candlepin.auth.UserPrincipal;
import org.candlepin.common.exceptions.BadRequestException;
import org.candlepin.common.exceptions.ForbiddenException;
import org.candlepin.common.exceptions.NotFoundException;
import org.candlepin.guice.PrincipalProvider;
import org.candlepin.model.Cdn;
import org.candlepin.model.CdnCurator;
import org.candlepin.model.Consumer;
import org.candlepin.model.ConsumerCurator;
import org.candlepin.model.Entitlement;
import org.candlepin.model.EntitlementCurator;
import org.candlepin.model.Owner;
import org.candlepin.pinsetter.core.model.JobStatus;
import org.candlepin.sync.ConflictOverrides;
import org.candlepin.sync.ExportResult;
import org.candlepin.sync.Exporter;
import org.candlepin.sync.Importer;
import org.candlepin.sync.Importer.Conflict;
import org.candlepin.sync.file.ManifestFile;
import org.candlepin.sync.file.ManifestFileService;
import org.candlepin.sync.file.ManifestFileType;
import org.candlepin.test.TestUtil;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.xnap.commons.i18n.I18n;
import org.xnap.commons.i18n.I18nFactory;
@RunWith(MockitoJUnitRunner.class)
public class ManifestManagerTest {
@Mock private ManifestFileService fileService;
@Mock private Exporter exporter;
@Mock private Importer importer;
@Mock private ConsumerCurator consumerCurator;
@Mock private CdnCurator cdnCurator;
@Mock private EntitlementCurator curator;
@Mock private PoolManager poolManager;
@Mock private EntitlementCurator entitlementCurator;
@Mock private PrincipalProvider principalProvider;
@Mock private I18n i18n;
@Mock private EventSink eventSink;
@Mock private EventFactory eventFactory;
private ManifestManager manager;
@Before
public void setupTest() {
i18n = I18nFactory.getI18n(getClass(), Locale.US, I18nFactory.FALLBACK);
manager = new ManifestManager(fileService, exporter, importer, consumerCurator,
entitlementCurator, cdnCurator, poolManager, principalProvider, i18n, eventSink, eventFactory);
}
@Test
public void ensureGenerateAsyncManifestDoesNotRefreshEntitlementsBeforeStartingJob() throws Exception {
Consumer consumer = TestUtil.createDistributor();
Cdn cdn = new Cdn("test-cdn", "Test CDN", "");
String webAppPrefix = "webapp-prefix";
String apiUrl = "api-url";
when(consumerCurator.verifyAndLookupConsumer(eq(consumer.getUuid()))).thenReturn(consumer);
when(cdnCurator.lookupByLabel(eq(cdn.getLabel()))).thenReturn(cdn);
manager.generateManifestAsync(consumer.getUuid(), cdn.getLabel(), webAppPrefix, apiUrl,
new HashMap<String, String>());
verify(poolManager, never()).regenerateDirtyEntitlements(anyCollection());
}
@Test
public void ensureGenerateManifestRefreshesEnitlements() throws Exception {
Consumer consumer = TestUtil.createDistributor();
Cdn cdn = new Cdn("test-cdn", "Test CDN", "");
String webAppPrefix = "webapp-prefix";
String apiUrl = "api-url";
Map<String, String> extData = new HashMap<String, String>();
extData.put("version", "1.0");
List<Entitlement> ents = new ArrayList<Entitlement>();
when(entitlementCurator.listByConsumer(eq(consumer))).thenReturn(ents);
when(consumerCurator.verifyAndLookupConsumer(eq(consumer.getUuid()))).thenReturn(consumer);
when(cdnCurator.lookupByLabel(eq(cdn.getLabel()))).thenReturn(cdn);
manager.generateManifest(consumer.getUuid(), cdn.getLabel(), webAppPrefix, apiUrl, extData);
verify(poolManager).regenerateDirtyEntitlements(eq(ents));
verify(exporter).getFullExport(eq(consumer), eq(cdn.getLabel()), eq(webAppPrefix), eq(apiUrl),
eq(extData));
}
@Test
public void ensureEventSentOnManifestGeneration() throws Exception {
Consumer consumer = TestUtil.createDistributor();
Cdn cdn = new Cdn("test-cdn", "Test CDN", "");
String webAppPrefix = "webapp-prefix";
String apiUrl = "api-url";
Event event = mock(Event.class);
when(eventFactory.exportCreated(eq(consumer))).thenReturn(event);
when(consumerCurator.verifyAndLookupConsumer(eq(consumer.getUuid()))).thenReturn(consumer);
when(cdnCurator.lookupByLabel(eq(cdn.getLabel()))).thenReturn(cdn);
manager.generateManifest(consumer.getUuid(), cdn.getLabel(), webAppPrefix, apiUrl,
new HashMap<String, String>());
verify(eventFactory).exportCreated(eq(consumer));
verify(eventSink).queueEvent(eq(event));
}
@Test
public void ensureEventSentWhenManifestGeneratedAndStored() throws Exception {
Consumer consumer = TestUtil.createDistributor();
Cdn cdn = new Cdn("test-cdn", "Test CDN", "");
String webAppPrefix = "webapp-prefix";
String apiUrl = "api-url";
Event event = mock(Event.class);
when(eventFactory.exportCreated(eq(consumer))).thenReturn(event);
UserPrincipal principal = TestUtil.createOwnerPrincipal();
when(principalProvider.get()).thenReturn(principal);
ManifestFile manifest = mock(ManifestFile.class);
when(fileService.store(eq(ManifestFileType.EXPORT), any(File.class),
eq(principal.getName()), any(String.class))).thenReturn(manifest);
when(consumerCurator.verifyAndLookupConsumer(eq(consumer.getUuid()))).thenReturn(consumer);
when(cdnCurator.lookupByLabel(eq(cdn.getLabel()))).thenReturn(cdn);
manager.generateAndStoreManifest(consumer.getUuid(), cdn.getLabel(), webAppPrefix, apiUrl,
new HashMap<String, String>());
verify(eventFactory).exportCreated(eq(consumer));
verify(eventSink).queueEvent(eq(event));
}
@Test
public void testGenerateManifest() throws Exception {
Consumer consumer = TestUtil.createDistributor();
Cdn cdn = new Cdn("test-cdn", "Test CDN", "");
String webAppPrefix = "webapp-prefix";
String apiUrl = "api-url";
Map<String, String> extData = new HashMap<String, String>();
Event event = mock(Event.class);
when(eventFactory.exportCreated(eq(consumer))).thenReturn(event);
List<Entitlement> ents = new ArrayList<Entitlement>();
when(entitlementCurator.listByConsumer(eq(consumer))).thenReturn(ents);
when(consumerCurator.verifyAndLookupConsumer(eq(consumer.getUuid()))).thenReturn(consumer);
when(cdnCurator.lookupByLabel(eq(cdn.getLabel()))).thenReturn(cdn);
File manifestFile = mock(File.class);
when(exporter.getFullExport(eq(consumer), eq(cdn.getLabel()), eq(webAppPrefix),
eq(apiUrl), eq(extData))).thenReturn(manifestFile);
File result = manager.generateManifest(consumer.getUuid(), cdn.getLabel(), webAppPrefix, apiUrl,
extData);
assertEquals(manifestFile, result);
verify(entitlementCurator).listByConsumer(eq(consumer));
verify(exporter).getFullExport(eq(consumer), eq(cdn.getLabel()), eq(webAppPrefix), eq(apiUrl),
eq(extData));
verify(eventFactory).exportCreated(eq(consumer));
verify(eventSink).queueEvent(eq(event));
verifyZeroInteractions(fileService);
}
@Test
public void testGenerateAndStoreManifest() throws Exception {
Consumer consumer = TestUtil.createDistributor();
Cdn cdn = new Cdn("test-cdn", "Test CDN", "");
String webAppPrefix = "webapp-prefix";
String apiUrl = "api-url";
Map<String, String> extData = new HashMap<String, String>();
Event event = mock(Event.class);
when(eventFactory.exportCreated(eq(consumer))).thenReturn(event);
UserPrincipal principal = TestUtil.createOwnerPrincipal();
when(principalProvider.get()).thenReturn(principal);
String exportId = "export-id";
ManifestFile manifest = mock(ManifestFile.class);
when(manifest.getId()).thenReturn(exportId);
when(fileService.store(eq(ManifestFileType.EXPORT), any(File.class),
eq(principal.getName()), any(String.class))).thenReturn(manifest);
when(consumerCurator.verifyAndLookupConsumer(eq(consumer.getUuid()))).thenReturn(consumer);
when(cdnCurator.lookupByLabel(eq(cdn.getLabel()))).thenReturn(cdn);
List<Entitlement> ents = new ArrayList<Entitlement>();
when(entitlementCurator.listByConsumer(eq(consumer))).thenReturn(ents);
ExportResult result = manager.generateAndStoreManifest(consumer.getUuid(), cdn.getLabel(),
webAppPrefix, apiUrl, extData);
assertEquals(consumer.getUuid(), result.getExportedConsumer());
assertEquals(exportId, result.getExportId());
verify(entitlementCurator).listByConsumer(eq(consumer));
verify(exporter).getFullExport(eq(consumer), eq(cdn.getLabel()), eq(webAppPrefix), eq(apiUrl),
eq(extData));
verify(eventFactory).exportCreated(eq(consumer));
verify(eventSink).queueEvent(eq(event));
verify(fileService).delete(eq(ManifestFileType.EXPORT), eq(consumer.getUuid()));
}
@Test
public void testManifestImportAsync() throws Exception {
Owner owner = TestUtil.createOwner();
File file = mock(File.class);
String filename = "manifest.zip";
ConflictOverrides overrides = new ConflictOverrides(Conflict.DISTRIBUTOR_CONFLICT);
UserPrincipal principal = TestUtil.createOwnerPrincipal();
when(principalProvider.get()).thenReturn(principal);
ManifestFile manifest = mock(ManifestFile.class);
when(fileService.store(ManifestFileType.IMPORT, file, principal.getName(),
owner.getKey())).thenReturn(manifest);
JobDetail job = manager.importManifestAsync(owner, file, filename, overrides);
JobDataMap jobData = job.getJobDataMap();
assertEquals(owner.getKey(), jobData.get("owner_id"));
assertEquals(JobStatus.TargetType.OWNER, jobData.get("target_type"));
assertEquals(owner.getKey(), jobData.get("target_id"));
assertEquals(manifest.getId(), jobData.get("stored_manifest_file_id"));
assertEquals(filename, jobData.get("uploaded_file_name"));
ConflictOverrides retrievedOverrides =
new ConflictOverrides((String[]) jobData.get("conflict_overrides"));
assertTrue(retrievedOverrides.isForced(Conflict.DISTRIBUTOR_CONFLICT));
verify(fileService).store(eq(ManifestFileType.IMPORT), eq(file), eq(principal.getName()),
eq(owner.getKey()));
}
@Test
public void testManifestImport() throws Exception {
Owner owner = TestUtil.createOwner();
File file = mock(File.class);
String filename = "manifest.zip";
ConflictOverrides overrides = new ConflictOverrides(Conflict.DISTRIBUTOR_CONFLICT);
manager.importManifest(owner, file, filename, overrides);
verify(importer).loadExport(eq(owner), eq(file), eq(overrides), eq(filename));
verifyNoMoreInteractions(fileService);
}
@Test
public void testImportStoredManifest() throws Exception {
Owner owner = TestUtil.createOwner();
String fileId = "1234";
String filename = "manifest.zip";
ConflictOverrides overrides = new ConflictOverrides(Conflict.DISTRIBUTOR_CONFLICT);
ManifestFile manifest = mock(ManifestFile.class);
when(manifest.getId()).thenReturn(fileId);
when(fileService.get(eq(fileId))).thenReturn(manifest);
manager.importStoredManifest(owner, fileId, overrides, filename);
verify(importer).loadStoredExport(eq(manifest), eq(owner), eq(overrides), eq(filename));
verify(fileService).delete(fileId);
}
@Test(expected = BadRequestException.class)
public void testImportStoredManifestThrowsBadRequestWhenManifestNotFound() throws Exception {
Owner owner = TestUtil.createOwner();
String fileId = "1234";
String filename = "manifest.zip";
ConflictOverrides overrides = new ConflictOverrides(Conflict.DISTRIBUTOR_CONFLICT);
when(fileService.get(eq(fileId))).thenReturn(null);
manager.importStoredManifest(owner, fileId, overrides, filename);
}
@Test
public void testManifestCleanup() throws Exception {
when(fileService.deleteExpired(any(Date.class))).thenReturn(4);
int cleaned = manager.cleanup(1);
// Can't hook into the util class, so just verify that
// the call was made. The file service test will cover
// the guts of that method.
verify(fileService).deleteExpired(any(Date.class));
assertEquals(4, cleaned);
}
@Test
public void testManifestCleanupDoesNoCleaningWhenmaxAgeIsLessThanZero() throws Exception {
int cleaned = manager.cleanup(-1);
assertEquals(0, cleaned);
verifyNoMoreInteractions(fileService);
}
@Test
public void testWriteStoredExportToResponse() throws Exception {
HttpServletResponse response = mock(HttpServletResponse.class);
ServletOutputStream responseOutputStream = mock(ServletOutputStream.class);
when(response.getOutputStream()).thenReturn(responseOutputStream);
Consumer exportedConsumer = TestUtil.createDistributor();
when(consumerCurator.verifyAndLookupConsumer(eq(exportedConsumer.getUuid())))
.thenReturn(exportedConsumer);
String manifestId = "124";
String manifestFilename = "manifest.zip";
ManifestFile manifest = mock(ManifestFile.class);
InputStream mockManifestInputStream = mock(InputStream.class);
when(manifest.getId()).thenReturn(manifestId);
when(manifest.getName()).thenReturn(manifestFilename);
when(manifest.getTargetId()).thenReturn(exportedConsumer.getUuid());
when(manifest.getInputStream()).thenReturn(mockManifestInputStream);
when(fileService.get(eq(manifestId))).thenReturn(manifest);
when(mockManifestInputStream.read()).thenReturn(-1); // Simulate no data for test.
manager.writeStoredExportToResponse(manifestId, exportedConsumer.getUuid(), response);
verify(fileService).get(eq(manifestId));
verify(response).setContentType("application/zip");
verify(response).setHeader(eq("Content-Disposition"), eq("attachment; filename=" + manifestFilename));
verify(responseOutputStream).flush();
}
@Test(expected = NotFoundException.class)
public void testWriteStoredExportToResponseFailsWhenManifestFileNotFound() throws Exception {
HttpServletResponse response = mock(HttpServletResponse.class);
Consumer exportedConsumer = TestUtil.createDistributor();
String manifestId = "124";
ManifestFile manifest = mock(ManifestFile.class);
when(manifest.getTargetId()).thenReturn(exportedConsumer.getUuid());
when(fileService.get(eq(manifestId))).thenReturn(null);
manager.writeStoredExportToResponse(manifestId, exportedConsumer.getUuid(), response);
}
@Test(expected = BadRequestException.class)
public void testWriteStoredExportToResponseFailsWhenConsumerIdDoesntMatchManifest() throws Exception {
HttpServletResponse response = mock(HttpServletResponse.class);
Consumer exportedConsumer = TestUtil.createDistributor();
String manifestId = "124";
when(consumerCurator.verifyAndLookupConsumer(eq(exportedConsumer.getUuid())))
.thenReturn(exportedConsumer);
ManifestFile manifest = mock(ManifestFile.class);
when(manifest.getTargetId()).thenReturn("another-consumer-uuid");
when(fileService.get(eq(manifestId))).thenReturn(manifest);
manager.writeStoredExportToResponse(manifestId, exportedConsumer.getUuid(), response);
}
@Test
public void deleteStoredManifest() throws Exception {
String manifestFileId = "1234";
manager.deleteStoredManifest(manifestFileId);
verify(fileService).delete(eq(manifestFileId));
}
@Test
public void verifyConsumerIsDistributorBeforeGeneratingManifest() throws Exception {
Consumer consumer = TestUtil.createConsumer();
Cdn cdn = new Cdn("test-cdn", "Test CDN", "");
String webAppPrefix = "webapp-prefix";
String apiUrl = "api-url";
Map<String, String> extData = new HashMap<String, String>();
when(consumerCurator.verifyAndLookupConsumer(eq(consumer.getUuid()))).thenReturn(consumer);
when(cdnCurator.lookupByLabel(eq(cdn.getLabel()))).thenReturn(cdn);
try {
manager.generateManifest(consumer.getUuid(), cdn.getLabel(), webAppPrefix, apiUrl, extData);
fail("Expected ForbiddenException not thrown");
}
catch (Exception e) {
assertTrue(e instanceof ForbiddenException);
String expectedMsg = String.format("Unit %s cannot be exported. A manifest cannot be made for " +
"units of type '%s'.", consumer.getUuid(), consumer.getType().getLabel());
assertEquals(e.getMessage(), expectedMsg);
}
}
@Test
public void verifyConsumerIsDistributorBeforeSchedulingManifestGeneration() throws Exception {
Consumer consumer = TestUtil.createConsumer();
Cdn cdn = new Cdn("test-cdn", "Test CDN", "");
String webAppPrefix = "webapp-prefix";
String apiUrl = "api-url";
Map<String, String> extData = new HashMap<String, String>();
when(consumerCurator.verifyAndLookupConsumer(eq(consumer.getUuid()))).thenReturn(consumer);
when(cdnCurator.lookupByLabel(eq(cdn.getLabel()))).thenReturn(cdn);
try {
manager.generateManifestAsync(consumer.getUuid(), cdn.getLabel(), webAppPrefix, apiUrl, extData);
fail("Expected ForbiddenException not thrown");
}
catch (Exception e) {
assertTrue(e instanceof ForbiddenException);
String expectedMsg = String.format("Unit %s cannot be exported. A manifest cannot be made for " +
"units of type '%s'.", consumer.getUuid(), consumer.getType().getLabel());
assertEquals(e.getMessage(), expectedMsg);
}
}
@Test
public void verifyCdnExistsBeforeGeneratingManifest() throws Exception {
Consumer consumer = TestUtil.createDistributor();
Cdn cdn = new Cdn("test-cdn", "Test CDN", "");
String webAppPrefix = "webapp-prefix";
String apiUrl = "api-url";
Map<String, String> extData = new HashMap<String, String>();
when(consumerCurator.verifyAndLookupConsumer(eq(consumer.getUuid()))).thenReturn(consumer);
when(cdnCurator.lookupByLabel(eq(cdn.getLabel()))).thenReturn(null);
try {
manager.generateManifestAsync(consumer.getUuid(), cdn.getLabel(), webAppPrefix, apiUrl, extData);
fail("Expected ForbiddenException not thrown");
}
catch (Exception e) {
assertTrue(e instanceof ForbiddenException);
String expectedMsg = String.format("A CDN with label %s does not exist on this system.",
cdn.getLabel());
assertEquals(e.getMessage(), expectedMsg);
}
}
@Test
public void verifyCdnExistsBeforeSchedulingManifestGeneration() throws Exception {
Consumer consumer = TestUtil.createDistributor();
Cdn cdn = new Cdn("test-cdn", "Test CDN", "");
String webAppPrefix = "webapp-prefix";
String apiUrl = "api-url";
Map<String, String> extData = new HashMap<String, String>();
when(consumerCurator.verifyAndLookupConsumer(eq(consumer.getUuid()))).thenReturn(consumer);
when(cdnCurator.lookupByLabel(eq(cdn.getLabel()))).thenReturn(null);
try {
manager.generateManifestAsync(consumer.getUuid(), cdn.getLabel(), webAppPrefix, apiUrl, extData);
fail("Expected ForbiddenException not thrown");
}
catch (Exception e) {
assertTrue(e instanceof ForbiddenException);
String expectedMsg = String.format("A CDN with label %s does not exist on this system.",
cdn.getLabel());
assertEquals(e.getMessage(), expectedMsg);
}
}
}