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.doAnswer;
import static org.mockito.Mockito.mock;
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 org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
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.YggdrasilConfig;
import dk.kb.yggdrasil.config.RabbitMqSettings;
import dk.kb.yggdrasil.db.PreservationImportRequestState;
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.preservationimport.PreservationImportRequest;
import dk.kb.yggdrasil.json.preservationimport.Warc;
import dk.kb.yggdrasil.messaging.MQ;
import dk.kb.yggdrasil.messaging.MqResponse;
import dk.kb.yggdrasil.messaging.RemotePreservationStateUpdater;
import dk.kb.yggdrasil.preservationimport.PreservationImportState;
@RunWith(JUnit4.class)
public class PreservationImportRequestWorkflowTest 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;
protected static final File WARC_FILE = new File("src/test/resources/warc/warcexample.warc");
protected static final String SECURITY_CHECKSUM = "sha-1:5875f4d3fe7058ef89bcd28b6e11258e8ed2762b";
protected static final String NON_RANDOM_UUID = "random-uuid";
protected static final String NON_RANDOM_WARC_ID = "random-warc-id";
protected static final String NON_RANDOM_RECORD_UUID = "random-file-uuid";
@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);
Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater);
String profile = "simple";
String uuid = NON_RANDOM_RECORD_UUID;
String warcId = WARC_FILE.getName();
String recordId = uuid;
String type = "FILE";
String url = "http://localhost:3000/view_file/import_from_preservation";
PreservationImportRequest request = makeRequest(profile, type, url, uuid, warcId, recordId);
byte[] requestBytes = JSONMessagingTestUtils.getPreservationImportRequest(request);
MqResponse handledResponse = new MqResponse(MQ.IMPORTREQUEST_MESSAGE_TYPE, requestBytes);
MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes());
when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse);
when(mq.getSettings()).thenReturn(settings);
when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList(profile));
when(bitrepository.getFile(anyString(), anyString(), any())).thenReturn(WARC_FILE);
when(httpCommunication.post(anyString(), any())).thenReturn(true);
workflow.run();
verifyNoMoreInteractions(stateDatabase);
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_REQUEST_RECEIVED_AND_VALIDATED), any());
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_RETRIEVAL_FROM_BITREPOSITORY_INITIATED), any());
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_DELIVERY_INITIATED), any());
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_FINISHED), any());
verifyNoMoreInteractions(updater);
verify(bitrepository).getKnownCollections();
verify(bitrepository).getFile(anyString(), anyString(), any());
verifyNoMoreInteractions(bitrepository);
verify(mq, times(2)).getSettings();
verify(mq, times(2)).receiveMessageFromQueue(anyString());
verifyNoMoreInteractions(mq);
}
@Test
public void preservationRequestHandlingProfileError() 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);
Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater);
String profile = "NotAValidProfile";
String uuid = NON_RANDOM_RECORD_UUID;
String warcId = WARC_FILE.getName();
String recordId = uuid;
String type = "FILE";
String url = "http://localhost:3000/view_file/import_from_preservation";
PreservationImportRequest request = makeRequest(profile, type, url, uuid, warcId, recordId);
byte[] requestBytes = JSONMessagingTestUtils.getPreservationImportRequest(request);
MqResponse handledResponse = new MqResponse(MQ.IMPORTREQUEST_MESSAGE_TYPE, requestBytes);
MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes());
when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse);
when(mq.getSettings()).thenReturn(settings);
when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList());
workflow.run();
verifyNoMoreInteractions(stateDatabase);
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_REQUEST_VALIDATION_FAILURE), any());
verifyNoMoreInteractions(updater);
verify(bitrepository).getKnownCollections();
verifyNoMoreInteractions(bitrepository);
verify(mq, times(2)).getSettings();
verify(mq, times(2)).receiveMessageFromQueue(anyString());
verifyNoMoreInteractions(mq);
}
@Test
public void preservationRequestHandlingTypeError() 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);
Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater);
String profile = "simple";
String uuid = NON_RANDOM_RECORD_UUID;
String warcId = WARC_FILE.getName();
String recordId = uuid;
String type = "ThisIsNotAValidType";
String url = "http://localhost:3000/view_file/import_from_preservation";
PreservationImportRequest request = makeRequest(profile, type, url, uuid, warcId, recordId);
byte[] requestBytes = JSONMessagingTestUtils.getPreservationImportRequest(request);
MqResponse handledResponse = new MqResponse(MQ.IMPORTREQUEST_MESSAGE_TYPE, requestBytes);
MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes());
when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse);
when(mq.getSettings()).thenReturn(settings);
when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList(profile));
workflow.run();
verifyNoMoreInteractions(stateDatabase);
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_REQUEST_VALIDATION_FAILURE), any());
verifyNoMoreInteractions(updater);
verify(bitrepository).getKnownCollections();
verifyNoMoreInteractions(bitrepository);
verify(mq, times(2)).getSettings();
verify(mq, times(2)).receiveMessageFromQueue(anyString());
verifyNoMoreInteractions(mq);
}
@Test
public void preservationRequestHandlingNoFile() 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);
Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater);
String profile = "simple";
String uuid = NON_RANDOM_RECORD_UUID;
String warcId = WARC_FILE.getName();
String recordId = uuid;
String type = "FILE";
String url = "http://localhost:3000/view_file/import_from_preservation";
PreservationImportRequest request = makeRequest(profile, type, url, uuid, warcId, recordId);
byte[] requestBytes = JSONMessagingTestUtils.getPreservationImportRequest(request);
MqResponse handledResponse = new MqResponse(MQ.IMPORTREQUEST_MESSAGE_TYPE, requestBytes);
MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes());
when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse);
when(mq.getSettings()).thenReturn(settings);
when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList(profile));
when(bitrepository.getFile(anyString(), anyString(), any())).thenThrow(new YggdrasilException("Not file"));
// Needed for setting of the preservation import state by the updater, when failing.
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
PreservationImportRequestState prs = (PreservationImportRequestState) invocation.getArguments()[0];
PreservationImportState newState = (PreservationImportState) invocation.getArguments()[1];
prs.setState(newState);
return null;
}
}).when(updater).sendPreservationImportResponse(any(), any(), any());
workflow.run();
verifyNoMoreInteractions(stateDatabase);
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_REQUEST_RECEIVED_AND_VALIDATED), any());
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_RETRIEVAL_FROM_BITREPOSITORY_INITIATED), any());
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_RETRIEVAL_FROM_BITREPOSITORY_FAILURE), any());
verifyNoMoreInteractions(updater);
verify(bitrepository).getKnownCollections();
verify(bitrepository).getFile(anyString(), anyString(), any());
verifyNoMoreInteractions(bitrepository);
verify(mq, times(2)).getSettings();
verify(mq, times(2)).receiveMessageFromQueue(anyString());
verifyNoMoreInteractions(mq);
}
@Test
public void preservationRequestHandlingMissingRecord() 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);
Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater);
String profile = "simple";
String uuid = UUID.randomUUID().toString();
String warcId = WARC_FILE.getName();
String recordId = uuid;
String type = "FILE";
String url = "http://localhost:3000/view_file/import_from_preservation";
PreservationImportRequest request = makeRequest(profile, type, url, uuid, warcId, recordId);
byte[] requestBytes = JSONMessagingTestUtils.getPreservationImportRequest(request);
MqResponse handledResponse = new MqResponse(MQ.IMPORTREQUEST_MESSAGE_TYPE, requestBytes);
MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes());
when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse);
when(mq.getSettings()).thenReturn(settings);
when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList(profile));
when(bitrepository.getFile(anyString(), anyString(), any())).thenReturn(WARC_FILE);;
// Needed for setting of the preservation import state by the updater, when failing.
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
PreservationImportRequestState prs = (PreservationImportRequestState) invocation.getArguments()[0];
PreservationImportState newState = (PreservationImportState) invocation.getArguments()[1];
prs.setState(newState);
return null;
}
}).when(updater).sendPreservationImportResponse(any(), any(), any());
workflow.run();
verifyNoMoreInteractions(stateDatabase);
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_REQUEST_RECEIVED_AND_VALIDATED), any());
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_RETRIEVAL_FROM_BITREPOSITORY_INITIATED), any());
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_RETRIEVAL_FROM_BITREPOSITORY_FAILURE), any());
verifyNoMoreInteractions(updater);
verify(bitrepository).getKnownCollections();
verify(bitrepository).getFile(anyString(), anyString(), any());
verifyNoMoreInteractions(bitrepository);
verify(mq, times(2)).getSettings();
verify(mq, times(2)).receiveMessageFromQueue(anyString());
verifyNoMoreInteractions(mq);
}
@Test
public void preservationRequestHandlingCannotUpload() 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);
Workflow workflow = new Workflow(mq, stateDatabase, bitrepository, config, models, httpCommunication, updater);
String profile = "simple";
String uuid = NON_RANDOM_RECORD_UUID;
String warcId = WARC_FILE.getName();
String recordId = uuid;
String type = "FILE";
String url = "http://localhost:3000/view_file/import_from_preservation";
PreservationImportRequest request = makeRequest(profile, type, url, uuid, warcId, recordId);
byte[] requestBytes = JSONMessagingTestUtils.getPreservationImportRequest(request);
MqResponse handledResponse = new MqResponse(MQ.IMPORTREQUEST_MESSAGE_TYPE, requestBytes);
MqResponse finalReponse = new MqResponse(MQ.SHUTDOWN_MESSAGE_TYPE, "Please terminate Yggdrasil".getBytes());
when(mq.receiveMessageFromQueue(anyString())).thenReturn(handledResponse, finalReponse);
when(mq.getSettings()).thenReturn(settings);
when(bitrepository.getKnownCollections()).thenReturn(Arrays.asList(profile));
when(bitrepository.getFile(anyString(), anyString(), any())).thenReturn(WARC_FILE);
when(httpCommunication.post(anyString(), any())).thenReturn(false);
// Needed for setting of the preservation import state by the updater, when failing.
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
PreservationImportRequestState prs = (PreservationImportRequestState) invocation.getArguments()[0];
PreservationImportState newState = (PreservationImportState) invocation.getArguments()[1];
prs.setState(newState);
return null;
}
}).when(updater).sendPreservationImportResponse(any(), any(), any());
workflow.run();
verifyNoMoreInteractions(stateDatabase);
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_REQUEST_RECEIVED_AND_VALIDATED), any());
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_RETRIEVAL_FROM_BITREPOSITORY_INITIATED), any());
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_DELIVERY_INITIATED), any());
verify(updater).sendPreservationImportResponse(any(PreservationImportRequestState.class),
eq(PreservationImportState.PRESERVATION_IMPORT_DELIVERY_FAILURE), any());
verifyNoMoreInteractions(updater);
verify(bitrepository).getKnownCollections();
verify(bitrepository).getFile(anyString(), anyString(), any());
verifyNoMoreInteractions(bitrepository);
verify(mq, times(2)).getSettings();
verify(mq, times(2)).receiveMessageFromQueue(anyString());
verifyNoMoreInteractions(mq);
}
public static PreservationImportRequest makeRequest(String preservationProfile, String type, String url,
String uuid, String warcId, String recordUuid) {
PreservationImportRequest request = new PreservationImportRequest();
request.preservation_profile = preservationProfile;
request.security = null;
request.type = type;
request.url = url;
request.uuid = uuid;
request.warc = new Warc();
request.warc.warc_file_id = warcId;
request.warc.warc_record_id = recordUuid;
return request;
}
}