/* (c) 2016 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.backuprestore;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.logging.Level;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.config.GeoServerDataDirectory;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.resource.Files;
import org.geoserver.platform.resource.Resource;
import org.geotools.factory.Hints;
import org.geotools.filter.text.ecql.ECQL;
import org.junit.Before;
import org.junit.Test;
import org.opengis.filter.Filter;
import org.springframework.batch.core.BatchStatus;
/**
*
* @author Alessio Fabiani, GeoSolutions
*
*/
public class BackupTest extends BackupRestoreTestSupport {
@Before
public void beforeTest() {
// reset invocations counter of continuable handler
ContinuableHandler.resetInvocationsCount();
// reset invocation of generic listener
GenericListener.reset();
}
@Test
public void testRunSpringBatchBackupJob() throws Exception {
Hints hints = new Hints(new HashMap(2));
hints.add(new Hints(new Hints.OptionKey(Backup.PARAM_BEST_EFFORT_MODE), Backup.PARAM_BEST_EFFORT_MODE));
BackupExecutionAdapter backupExecution = backupFacade.runBackupAsync(
Files.asResource(File.createTempFile("testRunSpringBatchBackupJob", ".zip")), true, null, hints);
// Wait a bit
Thread.sleep(100);
assertNotNull(backupFacade.getBackupExecutions());
assertTrue(!backupFacade.getBackupExecutions().isEmpty());
assertNotNull(backupExecution);
while (backupExecution.getStatus() != BatchStatus.COMPLETED) {
Thread.sleep(100);
if (backupExecution.getStatus() == BatchStatus.ABANDONED
|| backupExecution.getStatus() == BatchStatus.FAILED
|| backupExecution.getStatus() == BatchStatus.UNKNOWN) {
for (Throwable exception : backupExecution.getAllFailureExceptions()) {
LOGGER.log(Level.INFO, "ERROR: " + exception.getLocalizedMessage(), exception);
exception.printStackTrace();
}
break;
}
}
assertTrue(backupExecution.getStatus() == BatchStatus.COMPLETED);
assertThat(ContinuableHandler.getInvocationsCount() > 2, is(true));
// check that generic listener was invoked for the backup job
assertThat(GenericListener.getBackupAfterInvocations(), is(1));
assertThat(GenericListener.getBackupBeforeInvocations(), is(1));
assertThat(GenericListener.getRestoreAfterInvocations(), is(0));
assertThat(GenericListener.getRestoreBeforeInvocations(), is(0));
}
@Test
public void testTryToRunMultipleSpringBatchBackupJobs() throws Exception {
Hints hints = new Hints(new HashMap(2));
hints.add(new Hints(new Hints.OptionKey(Backup.PARAM_BEST_EFFORT_MODE), Backup.PARAM_BEST_EFFORT_MODE));
backupFacade.runBackupAsync(
Files.asResource(File.createTempFile("testRunSpringBatchBackupJob", ".zip")), true, null, hints);
try {
backupFacade.runBackupAsync(
Files.asResource(File.createTempFile("testRunSpringBatchBackupJob", ".zip")),
true, null, hints);
} catch (IOException e) {
assertEquals(e.getMessage(),
"Could not start a new Backup Job Execution since there are currently Running jobs.");
}
// Wait a bit
Thread.sleep(100);
assertNotNull(backupFacade.getBackupExecutions());
assertTrue(!backupFacade.getBackupExecutions().isEmpty());
assertTrue(backupFacade.getBackupRunningExecutions().size() == 1);
BackupExecutionAdapter backupExecution = null;
final Iterator<BackupExecutionAdapter> iterator = backupFacade.getBackupExecutions()
.values().iterator();
while (iterator.hasNext()) {
backupExecution = iterator.next();
}
assertNotNull(backupExecution);
while (backupExecution.getStatus() != BatchStatus.COMPLETED) {
Thread.sleep(100);
if (backupExecution.getStatus() == BatchStatus.ABANDONED
|| backupExecution.getStatus() == BatchStatus.FAILED
|| backupExecution.getStatus() == BatchStatus.UNKNOWN) {
LOGGER.severe("backupExecution.getStatus() == " + (backupExecution.getStatus()));
for (Throwable exception : backupExecution.getAllFailureExceptions()) {
LOGGER.log(Level.INFO, "ERROR: " + exception.getLocalizedMessage(), exception);
exception.printStackTrace();
}
break;
}
}
assertTrue(backupExecution.getStatus() == BatchStatus.COMPLETED);
assertThat(ContinuableHandler.getInvocationsCount() > 2, is(true));
}
@Test
public void testRunSpringBatchRestoreJob() throws Exception {
Hints hints = new Hints(new HashMap(2));
hints.add(new Hints(new Hints.OptionKey(Backup.PARAM_BEST_EFFORT_MODE), Backup.PARAM_BEST_EFFORT_MODE));
RestoreExecutionAdapter restoreExecution = backupFacade
.runRestoreAsync(file("geoserver-full-backup.zip"), null, hints);
// Wait a bit
Thread.sleep(100);
assertNotNull(backupFacade.getRestoreExecutions());
assertTrue(!backupFacade.getRestoreExecutions().isEmpty());
assertNotNull(restoreExecution);
Thread.sleep(100);
final Catalog restoreCatalog = restoreExecution.getRestoreCatalog();
assertNotNull(restoreCatalog);
while (restoreExecution.getStatus() != BatchStatus.COMPLETED) {
Thread.sleep(100);
if (restoreExecution.getStatus() == BatchStatus.ABANDONED
|| restoreExecution.getStatus() == BatchStatus.FAILED
|| restoreExecution.getStatus() == BatchStatus.UNKNOWN) {
for (Throwable exception : restoreExecution.getAllFailureExceptions()) {
LOGGER.log(Level.INFO, "ERROR: " + exception.getLocalizedMessage(), exception);
exception.printStackTrace();
}
break;
}
}
assertTrue(restoreExecution.getStatus() == BatchStatus.COMPLETED);
if (restoreCatalog.getWorkspaces().size() > 0) {
assertTrue(restoreCatalog.getWorkspaces().size() == restoreCatalog.getNamespaces().size());
assertTrue(restoreCatalog.getDataStores().size() == 4);
assertTrue(restoreCatalog.getResources(FeatureTypeInfo.class).size() == 14);
assertTrue(restoreCatalog.getResources(CoverageInfo.class).size() == 4);
assertTrue(restoreCatalog.getStyles().size() == 21);
assertTrue(restoreCatalog.getLayers().size() == 4);
assertTrue(restoreCatalog.getLayerGroups().size() == 1);
}
checkExtraPropertiesExists();
assertThat(ContinuableHandler.getInvocationsCount() > 2, is(true));
// check that generic listener was invoked for the backup job
assertThat(GenericListener.getBackupAfterInvocations(), is(0));
assertThat(GenericListener.getBackupBeforeInvocations(), is(0));
assertThat(GenericListener.getRestoreAfterInvocations(), is(1));
assertThat(GenericListener.getRestoreBeforeInvocations(), is(1));
}
@Test
public void testRunSpringBatchFilteredRestoreJob() throws Exception {
Hints hints = new Hints(new HashMap(2));
hints.add(new Hints(new Hints.OptionKey(Backup.PARAM_BEST_EFFORT_MODE), Backup.PARAM_BEST_EFFORT_MODE));
Filter filter = ECQL.toFilter("name = 'topp'");
RestoreExecutionAdapter restoreExecution = backupFacade
.runRestoreAsync(file("geoserver-full-backup.zip"), filter, hints);
// Wait a bit
Thread.sleep(100);
assertNotNull(backupFacade.getRestoreExecutions());
assertTrue(!backupFacade.getRestoreExecutions().isEmpty());
assertNotNull(restoreExecution);
Thread.sleep(100);
final Catalog restoreCatalog = restoreExecution.getRestoreCatalog();
assertNotNull(restoreCatalog);
while (restoreExecution.getStatus() != BatchStatus.COMPLETED) {
Thread.sleep(100);
if (restoreExecution.getStatus() == BatchStatus.ABANDONED
|| restoreExecution.getStatus() == BatchStatus.FAILED
|| restoreExecution.getStatus() == BatchStatus.UNKNOWN) {
for (Throwable exception : restoreExecution.getAllFailureExceptions()) {
LOGGER.log(Level.INFO, "ERROR: " + exception.getLocalizedMessage(), exception);
exception.printStackTrace();
}
break;
}
}
assertTrue(restoreExecution.getStatus() == BatchStatus.COMPLETED);
if (restoreCatalog.getWorkspaces().size() > 0) {
// assertTrue(restoreCatalog.getWorkspaces().size() == 2);
assertTrue(restoreCatalog.getDataStores().size() == 2);
assertTrue(restoreCatalog.getStyles().size() == 21);
}
checkExtraPropertiesExists();
assertThat(ContinuableHandler.getInvocationsCount() > 2, is(true));
}
@Test
public void testStopSpringBatchBackupJob() throws Exception {
Hints hints = new Hints(new HashMap(2));
hints.add(new Hints(new Hints.OptionKey(Backup.PARAM_BEST_EFFORT_MODE), Backup.PARAM_BEST_EFFORT_MODE));
BackupExecutionAdapter backupExecution = backupFacade.runBackupAsync(
Files.asResource(File.createTempFile("testRunSpringBatchBackupJob", ".zip")), true, null, hints);
while(backupExecution.getStatus() != BatchStatus.STARTED) {
// Wait a bit
Thread.sleep(10);
if (backupExecution.getStatus() == BatchStatus.ABANDONED
|| backupExecution.getStatus() == BatchStatus.FAILED
|| backupExecution.getStatus() == BatchStatus.UNKNOWN) {
for (Throwable exception : backupExecution.getAllFailureExceptions()) {
LOGGER.log(Level.INFO, "ERROR: " + exception.getLocalizedMessage(), exception);
exception.printStackTrace();
}
break;
}
}
if (backupExecution.getStatus() != BatchStatus.COMPLETED) {
backupFacade.stopExecution(backupExecution.getId());
// Wait a bit
Thread.sleep(100);
assertNotNull(backupExecution);
while (backupExecution.getStatus() != BatchStatus.STOPPED) {
Thread.sleep(100);
if (backupExecution.getStatus() == BatchStatus.ABANDONED
|| backupExecution.getStatus() == BatchStatus.FAILED
|| backupExecution.getStatus() == BatchStatus.UNKNOWN) {
for (Throwable exception : backupExecution.getAllFailureExceptions()) {
LOGGER.log(Level.INFO, "ERROR: " + exception.getLocalizedMessage(), exception);
exception.printStackTrace();
}
break;
}
}
assertTrue(backupExecution.getStatus() == BatchStatus.STOPPED);
}
}
/**
* Helper method that just check if the extra properties file was correctly backup / restore.
*/
private void checkExtraPropertiesExists() {
// find the properties file on the current data dir
GeoServerDataDirectory dataDirectory = GeoServerExtensions.bean(GeoServerDataDirectory.class);
Resource extraResource = dataDirectory.get(ExtraFileHandler.EXTRA_FILE_NAME);
assertThat(extraResource.file().exists(), is(true));
// load the properties
Properties extraProperties = new Properties();
try(InputStream input = extraResource.in()) {
extraProperties.load(input);
} catch (Exception exception) {
throw new RuntimeException("Error reading extra properties file.", exception);
}
// check that the expected properties are present
assertThat(extraProperties.size(), is(2));
assertThat(extraProperties.getProperty("property.a"), is("1"));
assertThat(extraProperties.getProperty("property.b"), is("2"));
}
}