Merge branch 'feature/backup-testing' into 'master'

add backup testing

See merge request search_discovery/SearchAnalyticsE2ETest!15
This commit is contained in:
Paul Brodner
2019-03-04 13:46:48 +00:00
18 changed files with 458 additions and 43 deletions
+3 -1
View File
@@ -29,4 +29,6 @@ target
# Package Files #
*.jar
*.war
*.ear
*.ear
qa/search/backup/host-bkp
qa/search/backup/host-bkp_T0
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -e # exit if commands fails
set -x # trace what gets exe
WAIT_INTERVAL=1
COUNTER=0
TIMEOUT=2000
t0=`date +%s`
# this is the default value, but you can override this passing the new endpoint as argument: $ wait-service-to-start.sh http://localhost:8083/solr
ENDPOINT="${1:-http://localhost:8081/alfresco}"
echo "Waiting for Service to start using endpoint: ${ENDPOINT}"
until $(curl --output /dev/null --silent --head --fail ${ENDPOINT}) || [ "$COUNTER" -eq "$TIMEOUT" ]; do
printf '.'
sleep $WAIT_INTERVAL
COUNTER=$(($COUNTER+$WAIT_INTERVAL))
done
if (("$COUNTER" < "$TIMEOUT")) ; then
t1=`date +%s`
delta=$((($t1 - $t0)/60))
echo "Service ${ENDPOINT} Started in $delta minutes"
else
echo "Service ${ENDPOINT} could not start in time."
echo "Waited $COUNTER seconds"
exit 1
fi
+17
View File
@@ -0,0 +1,17 @@
# About
This folder contains code for provisioning ACS with SearchServices or InsightEngine - for testing purposes.
# Content
```ruby
.
README.md # this readme file
search # code related to search product
Makefile # main Makefile (with common tasks)
backup # related to backup testing of Search Service
Makefile # start here if you want to test backup
README.md # how you can use it
docker-compose.backup.yml # overrides standard docker-compose.yml with backup data
docker-compose.yml # standard docker-compose.yml for Search Service
```
+56
View File
@@ -0,0 +1,56 @@
# master Makefile that contains common tasks for other Makefiles in this QA folder
# execute any on the task that are found here from your terminal
UNAME := $(shell uname)
SHELL := /bin/bash
# CURRENT_DIR is the current location of this script: qa/search
CURRENT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
# ROOT_DIR is the location of 'qa' folder
ROOT_DIR:=$(shell dirname $(CURRENT_DIR))
# TEST_DIR is the location of POM
POM_DIR:=$(shell dirname $(ROOT_DIR))
help: ## main: output this help
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
.DEFAULT_GOAL := help
# $(helpers)/wait-service-to-start.sh
ifeq ($(dc),)
helpers:=$(ROOT_DIR)/.helpers
endif
# $(dc) ls
ifeq ($(dc),)
dc:=docker-compose
endif
# on linux use sudo
ifeq ($(UNAME), Linux)
sudo := sudo
endif
# define the maven version
ifeq ($(mvn),)
ifeq ($(bamboo_working_directory),)#if on local environment
mvn:=mvn
else
export M2_HOME=
export JAVA_HOME=/opt/jdk-11
mvn:=/opt/maven-3.3/bin/mvn
endif
endif
# open a shell to search containers
shell: ## main: open a shell to search service: $ make shell
@$(dc) exec search sh
# kill all containers on default docker-compose.yml file
clean: ## kill containers
$(dc) kill && $(dc) rm -fv
# just waits for a alfresco and solr to start
wait: ## main: wait for alfresco service && solr to startup
$(helpers)/wait-service-to-start.sh && \
$(helpers)/wait-service-to-start.sh http://localhost:8083/solr
+11
View File
@@ -0,0 +1,11 @@
# docker-compose related environments
ALFRESCO_IMAGE=alfresco/alfresco-content-repository
ALFRESCO_TAG=6.1.0-EA3
SHARE_IMAGE=alfresco/alfresco-share
SHARE_TAG=6.0
POSTGRES_IMAGE=postgres
POSTGRES_TAG=10.1
SEARCH_IMAGE=quay.io/alfresco/search-services
SEARCH_TAG=latest
ACTIVEMQ_IMAGE=alfresco/alfresco-activemq
ACTIVEMQ_TAG=5.15.6
+72
View File
@@ -0,0 +1,72 @@
include ../Makefile
include .env
# the suffix of the backup taken in time. It can be overriden on runtime: make SUFIX=T1 backup-perform
SUFIX ?=T0
suiteXmlFile ?=./src/test/resources/search-pre-backup-suite.xml
export COMPOSE_INTERACTIVE_NO_CLI=1
# this is used also in compose yml files
export HOST_BACKUP_LOCATION:=$(CURRENT_DIR)/backup/host-bkp
ifeq ($(dc-backup),)
dc-backup:=$(dc) -f ../docker-compose.yml -f docker-compose.backup.yml
endif
backup-prepare: ## 1 - prepare backup for testing
@echo "Starting Backup Prepare" && \
$(sudo) rm -rf $(HOST_BACKUP_LOCATION) && \
mkdir -p $(HOST_BACKUP_LOCATION)/alf_data && \
mkdir -p $(HOST_BACKUP_LOCATION)/solr/archive && \
mkdir -p $(HOST_BACKUP_LOCATION)/solr/alfresco && \
mkdir -p $(HOST_BACKUP_LOCATION)/db && \
$(sudo) chmod -R 777 $(HOST_BACKUP_LOCATION) && \
$(dc-backup) up -d
backup-perform: ## 2 - perform the backup of alf_data and db data
@echo "Starting Backup Perform" && \
$(sudo) rm -rf $(HOST_BACKUP_LOCATION)_$(SUFIX) && \
$(sudo) chmod -R 777 $(HOST_BACKUP_LOCATION) && \
docker-compose stop alfresco && \
$(dc-backup) exec postgres bash -c 'pg_dump --dbname=postgresql://alfresco:alfresco@127.0.0.1:5432/alfresco' > $(HOST_BACKUP_LOCATION)/db/alfresco.pg && \
cp -R $(HOST_BACKUP_LOCATION) $(HOST_BACKUP_LOCATION)_$(SUFIX) && \
docker-compose start alfresco
backup-restore: ## 3 - start restoring from backup location
@echo "Starting Backup Restore" && \
$(sudo) rm -rf $(HOST_BACKUP_LOCATION) && \
mkdir -p $(HOST_BACKUP_LOCATION) && \
cp -rf $(HOST_BACKUP_LOCATION)_$(SUFIX)/alf_data $(HOST_BACKUP_LOCATION)/alf_data && \
cp -rf $(HOST_BACKUP_LOCATION)_$(SUFIX)/db/ $(HOST_BACKUP_LOCATION)/db/ && \
cp -rf $(HOST_BACKUP_LOCATION)_$(SUFIX)/solr $(HOST_BACKUP_LOCATION)/solr && \
$(sudo) chmod -R 777 $(HOST_BACKUP_LOCATION) && \
$(dc-backup) up -d postgres && sleep 30 && \
docker-compose exec postgres bash -c 'psql --dbname=postgresql://alfresco:alfresco@127.0.0.1:5432/alfresco < /backup/db/alfresco.pg' && \
$(dc-backup) up -d
run-mvn-tests: ## run e2e suiteXmlFile: $make run-e2e-tests suiteXmlFile=./src/test/resources/search-post-backup-suite.xml
cd $(POM_DIR) && $(mvn) test -DsuiteXmlFile=$(suiteXmlFile)
all: show-config ## 0 - executes the entire backup process
# perform the backup and waits until the server is starting
# do some change on backed up data
# then restore from backup and check the content is restored as expected
make clean backup-prepare wait && \
make run-mvn-tests suiteXmlFile=./src/test/resources/search-pre-backup-suite.xml
make backup-perform wait && \
make run-mvn-tests suiteXmlFile=./src/test/resources/search-on-backup-suite.xml
make clean backup-restore wait && \
make run-mvn-tests suiteXmlFile=./src/test/resources/search-post-backup-suite.xml
show-config: ## show compose configuration
$(dc-backup) config
clean: ## kill containers, remove volumes and data
$(dc-backup) kill && $(dc-backup) rm -fv
$(sudo) rm -rf $(HOST_BACKUP_LOCATION)
tail-logs: ## tails all container logs
$(dc-backup) logs -f
+42
View File
@@ -0,0 +1,42 @@
# About
Testing the Backup of SearchService product
# Steps
* **a)** prepare the backup
```shel
make backup-prepare wait
```
>more details on Makefile [task](Makefile#L27).
* **b)** create some data manually or using automated tests found on this project
```shel
make run-mvn-tests suiteXmlFile=./src/test/resources/search-pre-backup-suite.xml
```
* **c)** perform the backup of data
```shel
make backup-perform wait
```
* **d)** now you can also update the data/remove it from TS, or even remove the entire volumes
```shel
make run-mvn-tests suiteXmlFile=./src/test/resources/search-on-backup-suite.xml
# or
make clean
```
* **e)** at any time you can restore the backup
```shel
make backup-restore wait
```
* **f)** now you can check the data from point **b)** is corectly recovered
```shel
make run-mvn-tests suiteXmlFile=./src/test/resources/search-post-backup-suite.xml
```
# All in one
At any time you can run the `make all` taks that will execute all the above commands for you
```shel
make all
```
@@ -0,0 +1,39 @@
version: '3'
services:
alfresco:
environment:
JAVA_OPTS : "
-Ddb.driver=org.postgresql.Driver
-Ddb.username=alfresco
-Ddb.password=alfresco
-Ddb.url=jdbc:postgresql://postgres:5432/alfresco
-Dsolr.host=search
-Dsolr.port=8983
-Dsolr.secureComms=none
-Dsolr.base.url=/solr
-Dindex.subsystem.name=solr6
-Dalfresco.restApi.basicAuthScheme=true
-Ddeployment.method=DOCKER_COMPOSE
-Dcsrf.filter.enabled=false
-Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\"
-Dsolr.backup.alfresco.remoteBackupLocation=/backup/solr/alfresco/
-Dsolr.backup.alfresco.numberToKeep=1
-Dsolr.backup.archive.remoteBackupLocation=/backup/solr/archive/
-Dsolr.backup.archive.numberToKeep=1"
volumes:
- ${HOST_BACKUP_LOCATION}/alf_data:/usr/local/tomcat/alf_data
search:
environment:
- VERSION=${SEARCH_TAG}
image: ${SEARCH_IMAGE}:${SEARCH_TAG}
volumes:
- ${HOST_BACKUP_LOCATION}/solr:/backup/solr
postgres:
environment:
- POSTGRES_PASSWORD=alfresco
- POSTGRES_USER=alfresco
- POSTGRES_DB=alfresco
volumes:
- ${HOST_BACKUP_LOCATION}/db:/backup/db
+63
View File
@@ -0,0 +1,63 @@
version: '3'
services:
alfresco:
image: ${ALFRESCO_IMAGE}:${ALFRESCO_TAG}
environment:
JAVA_OPTS : "
-Ddb.driver=org.postgresql.Driver
-Ddb.username=alfresco
-Ddb.password=alfresco
-Ddb.url=jdbc:postgresql://postgres:5432/alfresco
-Dsolr.host=search
-Dsolr.port=8983
-Dsolr.secureComms=none
-Dsolr.base.url=/solr
-Dindex.subsystem.name=solr6
-Dalfresco.restApi.basicAuthScheme=true
-Ddeployment.method=DOCKER_COMPOSE
-Dcsrf.filter.enabled=false
-Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\"
"
ports:
- "7203:7203" #JMX connect via service:jmx:rmi:///jndi/rmi://localhost:7203/jmxrmi
- "5005:5005" #Java debugging
- "8081:8080" #Browser port for Alfresco
share:
image: ${SHARE_IMAGE}:${SHARE_TAG}
environment:
- REPO_HOST=alfresco
- REPO_PORT=8080
ports:
- 8082:8080 #Browser port for Share
postgres:
image: ${POSTGRES_IMAGE}:${POSTGRES_TAG}
environment:
- POSTGRES_PASSWORD=alfresco
- POSTGRES_USER=alfresco
- POSTGRES_DB=alfresco
ports:
- 5432:5432
search:
image: ${SEARCH_IMAGE}:${SEARCH_TAG}
environment:
#Solr needs to know how to register itself with Alfresco
- SOLR_ALFRESCO_HOST=alfresco
- SOLR_ALFRESCO_PORT=8080
#Alfresco needs to know how to call solr
- SOLR_SOLR_HOST=search
- SOLR_SOLR_PORT=8983
#Create the default alfresco and archive cores
- SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive
ports:
- 8083:8983 #Browser port
activemq:
image: ${ACTIVEMQ_IMAGE}:${ACTIVEMQ_TAG}
ports:
- 8161:8161 # Web Console
- 5672:5672 # AMQP
- 61616:61616 # OpenWire
- 61613:61613 # STOMP
@@ -3,11 +3,16 @@ package org.alfresco.service.search.backup;
import java.io.File;
import java.nio.file.Paths;
import org.alfresco.cmis.CmisWrapper;
import org.alfresco.rest.core.RestRequest;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestHtmlResponse;
import org.alfresco.utility.Utility;
import org.alfresco.utility.data.DataSite;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FileType;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.network.ServerHealth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -25,20 +30,25 @@ import com.jayway.restassured.RestAssured;
@ContextConfiguration("classpath:alfresco-search-e2e-context.xml")
public abstract class AbstractBackupTest extends AbstractTestNGSpringContextTests {
protected SiteModel testSite = new SiteModel("siteForBackupTesting");
protected FolderModel folder = new FolderModel("folderBackedUp");
protected FileModel file = new FileModel("fileBackedUp.txt", FileType.TEXT_PLAIN, "uber important file");
@Autowired
protected ServerHealth serverHealth;
@Autowired
protected DataSite dataSite;
@Autowired
protected CmisWrapper cmisWrapper;
@Autowired
RestWrapper restWrapper;
protected RestWrapper restWrapper;
@Value("${solr.port}")
int solrPort;
@Value("${solr.docker.hostPath}")
String solrDockerHostPath;
@BeforeClass(alwaysRun = true)
protected void setupSolrRequest() throws Exception {
@@ -55,7 +65,7 @@ public abstract class AbstractBackupTest extends AbstractTestNGSpringContextTest
* Prepare a GET "backup" command request to localhost:{solrPort}/solr
*
* @param core : alfresco or archive
* @param location : location inside docker container, should be mounted as volume
* @param dockerVolume : location inside docker container, should be mounted as volume
* @param numberToKeep : how many backup you want to keep
*
* @return {@link RestHtmlResponse}
@@ -66,18 +76,16 @@ public abstract class AbstractBackupTest extends AbstractTestNGSpringContextTest
* file:///nop/snapshot.20190212152339023","status":"OK"}
* @throws InterruptedException
*/
protected RestHtmlResponse executeSolrBackupRequest(String core, String location, int numberToKeep)
protected RestHtmlResponse executeSolrBackupRequest(String core, String dockerVolume, int numberToKeep)
throws InterruptedException {
String keep = String.valueOf(numberToKeep);
RestRequest request = RestRequest.simpleRequest(HttpMethod.GET,
"{core}/replication?command=backup&location={location}&numberToKeep={keep}&wt=json", core,
location, keep);
RestRequest request = RestRequest.simpleRequest(HttpMethod.GET, "{core}/replication?command=backup&location={dockerVolume}&numberToKeep={keep}&wt=json", core,dockerVolume, keep);
RestHtmlResponse htmlResponse = restWrapper.processHtmlResponse(request);
// need to wait for backup data to be created or deleted based on numberToKeep
Utility.waitToLoopTime(2, "Wait until the backup data is created/deleted");
return htmlResponse;
// need to wait for backup data to be created or deleted based on numberToKeep
Utility.waitToLoopTime(2, "Wait until the backup data is created/deleted on docker volume");
return htmlResponse;
}
/**
@@ -86,8 +94,9 @@ public abstract class AbstractBackupTest extends AbstractTestNGSpringContextTest
*/
protected File[] assertFileExistInLocalBackupFolder(String folder, String filePrefix, int count) {
File backupLocation = Paths.get(solrDockerHostPath, folder).toFile();
File backupLocation = Paths.get("./qa/search/backup/host-bkp", folder).toFile();
Assert.assertTrue(backupLocation.exists(), "Backup location exists: " + backupLocation.getAbsolutePath());
if (count >= 1) {
Assert.assertEquals(backupLocation.listFiles().length, count,
"Expected Files in folder:" + backupLocation.getPath());
@@ -1,15 +1,7 @@
# About
This suite(s) will test the backup process of SearchService/InsightEngine
# Prerequisites
# How to run the backup
a) `docker-compose.backup.yml`
You need to execute the "start-backup" tasks from the `BuildScripts/qa` folder
That command will provision some docker containers with:
* `alfresco` service having 'remoteBackupLocation' set for `archive` and `alfresco` cores
* `search` service that will automatically or/on demand save the index to location specified
b) I assume that
# Tests
Run the MAVEN tests after you start the test environment (prerequisites)
These tests works in correlation with provisioning code found on `qa/backup` folder (from root of this project).
Checkout the README.md file to prepare the environment and run the maven backup tests automatically according to your test strategy.
@@ -0,0 +1,28 @@
package org.alfresco.service.search.backup;
import org.testng.annotations.Test;
/**
*
* Documentation: http://docs.alfresco.com/6.0/tasks/solr6-backup.html
*
* @author Paul Brodner
*
*/
public class SearchServiceOnBackupTests extends AbstractBackupTest {
@Test
public void deleteBackupFolder() throws Exception {
/**
* Site: siteForBackupTesting
* > documentLibrary
* | siteForBackupTesting
* |- fileBackedUp.txt
*/
cmisWrapper.authenticateUser(dataSite.getAdminUser())
.usingSite(testSite).setLastContentModel(folder);
cmisWrapper.deleteFolderTree().and().assertThat().doesNotExistInRepo();
}
}
@@ -0,0 +1,23 @@
package org.alfresco.service.search.backup;
import org.testng.annotations.Test;
/**
*
* Documentation: http://docs.alfresco.com/6.0/tasks/solr6-backup.html
*
* @author Paul Brodner
*
*/
public class SearchServicePostBackupTests extends AbstractBackupTest {
@Test
public void testIFBackupDataExist() throws Exception {
cmisWrapper.authenticateUser(dataSite.getAdminUser())
.usingSite(testSite)
.setLastContentModel(folder);
cmisWrapper.assertThat().existsInRepo();
}
}
@@ -4,7 +4,6 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;
import org.alfresco.rest.model.RestHtmlResponse;
import org.alfresco.utility.model.SiteModel;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -15,38 +14,51 @@ import org.testng.annotations.Test;
* @author Paul Brodner
*
*/
public class SearchServiceBackupTests extends AbstractBackupTest {
private SiteModel testSite = new SiteModel("siteForBackupTesting");
public class SearchServicePreBackupTests extends AbstractBackupTest {
/**
* {"responseHeader":{"status":0,"QTime":1},"exception":"org.apache.solr.common.SolrException:org.apache.solr.common.SolrException:
* Directory does not exist:
* file:///thisDoesntExist1/snapshot.20190212161435995","status":"OK"}
*/
@Test(priority = 0)
public void throwSorlExceptioIfDestinationFolderDoesntExist() throws Exception {
@Test
public void testIFSolrThrowsExceptioIfDestinationFolderDoesntExist() throws Exception {
RestHtmlResponse htmlResponse = executeSolrBackupRequest("alfresco", "/thisDoesntExist", 1);
String exception = htmlResponse.getBody().jsonPath().get("exception").toString();
assertThat(exception, containsString(
"org.apache.solr.common.SolrException:org.apache.solr.common.SolrException: Directory does not exist: file:///thisDoesntExist"));
}
@Test(priority=1)
public void createTestSiteForBackup() {
if(dataSite.isSiteCreated(testSite))
@Test
public void createTestSiteForBackup() throws Exception {
if (!dataSite.isSiteCreated(testSite))
testSite = dataSite.usingAdmin().createSite(testSite);
/**
* Site: siteForBackupTesting
* > documentLibrary
* | siteForBackupTesting
* |- fileBackedUp.txt
*/
cmisWrapper.authenticateUser(dataSite.getAdminUser())
.usingSite(testSite).createFolder(folder)
.usingResource(folder)
.createFile(file).and().assertThat()
.existsInRepo();
}
/**
* In case of success: {"responseHeader":{"status":0,"QTime":3},"status":"OK"}
*/
@Test(priority=2)
@Test(enabled=false)
public void save1AlfrescoSnaphotToExistingBackupFolder() throws Exception {
RestHtmlResponse htmlResponse = executeSolrBackupRequest("alfresco", "/backup/alfresco", 1);
RestHtmlResponse htmlResponse = executeSolrBackupRequest("alfresco", "/backup/solr/alfresco", 1);
String status = htmlResponse.getBody().jsonPath().get("status").toString();
@@ -61,8 +73,9 @@ public class SearchServiceBackupTests extends AbstractBackupTest {
Assert.assertEquals(status, "OK");
assertFileExistInLocalBackupFolder("solr/alfresco", "snapshot.", 1);
//execute another request and see that files inside solr/alfresco backup folder are 1
// execute another request and see that files inside solr/alfresco backup folder
// are 1
htmlResponse = executeSolrBackupRequest("alfresco", "/backup/alfresco", 1);
assertFileExistInLocalBackupFolder("solr/alfresco", "snapshot.", 1);
@@ -11,9 +11,6 @@ sync.port=9090
# solr service related
solr.port=8083
# backup section
# solr.docker.hostPath=. # is the volume mounted inside the search service image
solr.docker.hostPath=.
#CMIS Related: Set CMIS binding to 'browser' or 'atom'
cmis.binding=browser
@@ -1,8 +1,10 @@
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="SearchSuite" verbose="6" preserve-order="true">
<test name="BackupTests">
<test name="Pre-Backup">
<classes>
<class name="org.alfresco.service.search.backup.SearchServiceBackupTests" />
<!-- execute this before backup -->
<class
name="org.alfresco.service.search.backup.SearchServiceOnBackupTests" />
</classes>
</test>
</suite>
@@ -0,0 +1,10 @@
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="SearchSuite" verbose="6" preserve-order="true">
<test name="Post-Backup">
<classes>
<!-- execute this after backup -->
<class
name="org.alfresco.service.search.backup.SearchServicePostBackupTests" />
</classes>
</test>
</suite>
@@ -0,0 +1,10 @@
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="SearchSuite" verbose="6" preserve-order="true">
<test name="Pre-Backup">
<classes>
<!-- execute this before backup -->
<class
name="org.alfresco.service.search.backup.SearchServicePreBackupTests" />
</classes>
</test>
</suite>