package dk.kb.yggdrasil.workflow; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.UUID; import org.apache.commons.io.FileUtils; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import dk.kb.yggdrasil.HttpCommunication; import dk.kb.yggdrasil.MqFixtureTestAPI; import dk.kb.yggdrasil.Workflow; import dk.kb.yggdrasil.bitmag.Bitrepository; import dk.kb.yggdrasil.config.Models; import dk.kb.yggdrasil.config.RabbitMqSettings; import dk.kb.yggdrasil.config.YggdrasilConfig; import dk.kb.yggdrasil.db.PreservationRequestState; import dk.kb.yggdrasil.db.StateDatabase; import dk.kb.yggdrasil.exceptions.RabbitException; import dk.kb.yggdrasil.exceptions.YggdrasilException; import dk.kb.yggdrasil.json.JSONMessagingTestUtils; import dk.kb.yggdrasil.json.preservation.PreservationRequest; import dk.kb.yggdrasil.messaging.MQ; import dk.kb.yggdrasil.messaging.MqResponse; import dk.kb.yggdrasil.messaging.RemotePreservationStateUpdater; import dk.kb.yggdrasil.preservation.PreservationState; import dk.kb.yggdrasil.testutils.MetadataContentUtils; @RunWith(JUnit4.class) public class PreservationRequestWorkflowTest extends MqFixtureTestAPI { private static String RABBITMQ_CONF_FILE = "src/test/resources/config/rabbitmq.yml"; private static File generalConfigFile = new File("src/test/resources/config/yggdrasil.yml"); private static RabbitMqSettings settings; private static Models models; private static YggdrasilConfig config; @BeforeClass public static void beforeClass() throws YggdrasilException, IOException, RabbitException { System.setProperty("dk.kb.yggdrasil.runningmode", "test"); config = new YggdrasilConfig(generalConfigFile); FileUtils.deleteDirectory(config.getDatabaseDir()); File rabbitMQConfig = new File(RABBITMQ_CONF_FILE); settings = new RabbitMqSettings(rabbitMQConfig); models = new Models(new File("config/models.yml")); } @Test public void preservationRequestHandlingSuccess() throws Exception { StateDatabase stateDatabase = mock(StateDatabase.class); Bitrepository bitrepository = mock(Bitrepository.class); HttpCommunication httpCommunication = mock(HttpCommunication.class); MQ mq = mock(MQ.class); RemotePreservationStateUpdater updater = mock(RemotePreservationStateUpdater.class); when(mq.getSettings()).thenReturn(settings); Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater); String uuid = UUID.randomUUID().toString(); String profile = "simple"; String valhalId = "valhal:1"; String model = "Instance"; String metadata = MetadataContentUtils.getExampleInstanceMetadata(); PreservationRequest request = makeRequest(model, profile, uuid, valhalId, metadata); byte[] requestBytes = JSONMessagingTestUtils.getPreservationRequest(request); MqResponse handledResponse = new MqResponse(MQ.PRESERVATIONREQUEST_MESSAGE_TYPE, requestBytes); MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes()); when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse); when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList(profile)); when(bitrepository.uploadFile(any(), anyString())).thenReturn(true); workflow.run(); verify(stateDatabase, times(3)).putPreservationRecord(eq(uuid), any(PreservationRequestState.class)); verify(stateDatabase, timeout(1500)).delete(eq(uuid)); verifyNoMoreInteractions(stateDatabase); verify(updater).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_REQUEST_RECEIVED)); verify(updater).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_METADATA_PACKAGED_SUCCESSFULLY)); verify(updater).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_PACKAGE_COMPLETE)); verify(updater).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_PACKAGE_WAITING_FOR_MORE_DATA)); verify(updater, timeout(1500)).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_PACKAGE_UPLOAD_SUCCESS)); verifyNoMoreInteractions(updater); verify(bitrepository).getKnownCollections(); verify(bitrepository).uploadFile(any(File.class), eq(profile)); verifyNoMoreInteractions(bitrepository); verify(mq, times(2)).getSettings(); verify(mq, times(2)).receiveMessageFromQueue(anyString()); verifyNoMoreInteractions(mq); } @Test public void preservationRequestHandlingFailWrongProfile() throws Exception { StateDatabase stateDatabase = mock(StateDatabase.class); Bitrepository bitrepository = mock(Bitrepository.class); HttpCommunication httpCommunication = mock(HttpCommunication.class); MQ mq = mock(MQ.class); RemotePreservationStateUpdater updater = mock(RemotePreservationStateUpdater.class); when(mq.getSettings()).thenReturn(settings); Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater); String uuid = UUID.randomUUID().toString(); String profile = "simple"; String valhalId = "valhal:1"; String model = "Instance"; String metadata = MetadataContentUtils.getExampleInstanceMetadata(); PreservationRequest request = makeRequest(model, profile, uuid, valhalId, metadata); byte[] requestBytes = JSONMessagingTestUtils.getPreservationRequest(request); MqResponse handledResponse = new MqResponse(MQ.PRESERVATIONREQUEST_MESSAGE_TYPE, requestBytes); MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes()); when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse); when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList()); when(bitrepository.uploadFile(any(), anyString())).thenReturn(true); workflow.run(); verifyNoMoreInteractions(stateDatabase); verify(updater).sendPreservationResponseWithSpecificDetails(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_REQUEST_FAILED), anyString()); verifyNoMoreInteractions(updater); verify(bitrepository).getKnownCollections(); verifyNoMoreInteractions(bitrepository); verify(mq, times(2)).getSettings(); verify(mq, times(2)).receiveMessageFromQueue(anyString()); verifyNoMoreInteractions(mq); } @Test public void preservationRequestHandlingFailWrongModel() throws Exception { StateDatabase stateDatabase = mock(StateDatabase.class); Bitrepository bitrepository = mock(Bitrepository.class); HttpCommunication httpCommunication = mock(HttpCommunication.class); MQ mq = mock(MQ.class); RemotePreservationStateUpdater updater = mock(RemotePreservationStateUpdater.class); when(mq.getSettings()).thenReturn(settings); Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater); String uuid = UUID.randomUUID().toString(); String profile = "simple"; String valhalId = "valhal:1"; String model = "NotAnValhalModel"; String metadata = MetadataContentUtils.getExampleInstanceMetadata(); PreservationRequest request = makeRequest(model, profile, uuid, valhalId, metadata); byte[] requestBytes = JSONMessagingTestUtils.getPreservationRequest(request); MqResponse handledResponse = new MqResponse(MQ.PRESERVATIONREQUEST_MESSAGE_TYPE, requestBytes); MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes()); when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse); when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList(profile)); when(bitrepository.uploadFile(any(), anyString())).thenReturn(true); workflow.run(); verify(stateDatabase).putPreservationRecord(eq(uuid), any(PreservationRequestState.class)); verify(stateDatabase, timeout(1500)).delete(eq(uuid)); verifyNoMoreInteractions(stateDatabase); verify(updater).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_REQUEST_RECEIVED)); verify(updater).sendPreservationResponseWithSpecificDetails(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_REQUEST_FAILED), anyString()); verifyNoMoreInteractions(updater); verify(bitrepository).getKnownCollections(); verifyNoMoreInteractions(bitrepository); verify(mq, times(2)).getSettings(); verify(mq, times(2)).receiveMessageFromQueue(anyString()); verifyNoMoreInteractions(mq); } @Test public void preservationRequestHandlingFailMetadataError() throws Exception { StateDatabase stateDatabase = mock(StateDatabase.class); Bitrepository bitrepository = mock(Bitrepository.class); HttpCommunication httpCommunication = mock(HttpCommunication.class); MQ mq = mock(MQ.class); RemotePreservationStateUpdater updater = mock(RemotePreservationStateUpdater.class); when(mq.getSettings()).thenReturn(settings); Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater); String uuid = UUID.randomUUID().toString(); String profile = "simple"; String valhalId = "valhal:1"; String model = "Instance"; String metadata = "<metadata></metadata>"; PreservationRequest request = makeRequest(model, profile, uuid, valhalId, metadata); byte[] requestBytes = JSONMessagingTestUtils.getPreservationRequest(request); MqResponse handledResponse = new MqResponse(MQ.PRESERVATIONREQUEST_MESSAGE_TYPE, requestBytes); MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes()); when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse); when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList(profile)); when(bitrepository.uploadFile(any(), anyString())).thenReturn(true); workflow.run(); verify(stateDatabase).putPreservationRecord(eq(uuid), any(PreservationRequestState.class)); verify(stateDatabase, timeout(1500)).delete(eq(uuid)); verifyNoMoreInteractions(stateDatabase); verify(updater).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_REQUEST_RECEIVED)); verify(updater).sendPreservationResponseWithSpecificDetails(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_METADATA_PACKAGED_FAILURE), anyString()); verifyNoMoreInteractions(updater); verify(bitrepository).getKnownCollections(); verifyNoMoreInteractions(bitrepository); verify(mq, times(2)).getSettings(); verify(mq, times(2)).receiveMessageFromQueue(anyString()); verifyNoMoreInteractions(mq); } @Test public void preservationRequestHandlingFailedUpload() throws Exception { StateDatabase stateDatabase = mock(StateDatabase.class); Bitrepository bitrepository = mock(Bitrepository.class); HttpCommunication httpCommunication = mock(HttpCommunication.class); MQ mq = mock(MQ.class); RemotePreservationStateUpdater updater = mock(RemotePreservationStateUpdater.class); when(mq.getSettings()).thenReturn(settings); Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater); String uuid = UUID.randomUUID().toString(); String profile = "simple"; String valhalId = "valhal:1"; String model = "Instance"; String metadata = MetadataContentUtils.getExampleInstanceMetadata(); PreservationRequest request = makeRequest(model, profile, uuid, valhalId, metadata); byte[] requestBytes = JSONMessagingTestUtils.getPreservationRequest(request); MqResponse handledResponse = new MqResponse(MQ.PRESERVATIONREQUEST_MESSAGE_TYPE, requestBytes); MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes()); when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse); when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList(profile)); when(bitrepository.uploadFile(any(), anyString())).thenReturn(false); workflow.run(); verify(stateDatabase, times(3)).putPreservationRecord(eq(uuid), any(PreservationRequestState.class)); verify(stateDatabase, timeout(1500)).delete(eq(uuid)); verifyNoMoreInteractions(stateDatabase); verify(updater).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_REQUEST_RECEIVED)); verify(updater).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_METADATA_PACKAGED_SUCCESSFULLY)); verify(updater).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_PACKAGE_COMPLETE)); verify(updater).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_PACKAGE_WAITING_FOR_MORE_DATA)); verify(updater, timeout(1500)).sendPreservationResponse(any(PreservationRequestState.class), eq(PreservationState.PRESERVATION_PACKAGE_UPLOAD_FAILURE)); verifyNoMoreInteractions(updater); verify(bitrepository).getKnownCollections(); verify(bitrepository).uploadFile(any(File.class), eq(profile)); verifyNoMoreInteractions(bitrepository); verify(mq, times(2)).getSettings(); verify(mq, times(2)).receiveMessageFromQueue(anyString()); verifyNoMoreInteractions(mq); } public static PreservationRequest makeRequest(String model, String preservationProfile, String uuid, String valhalId, String metadata) { PreservationRequest request = new PreservationRequest(); request.Content_URI = null; request.File_UUID = null; request.Model = model; request.Preservation_profile = preservationProfile; request.UUID = uuid; request.Valhal_ID = valhalId; request.metadata = metadata; return request; } }