Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions integration-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ createDockerFile {
dependsOn(configurations.backupJar)

if (flavor == "solr6") {
// Remove the old imported solr-backup from docker-solr:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But where do both sets of dependencies come from? I assume from gradle. Can't we avoid pulling in the incorrect deps there? Removing it afterwards here feels like a hack.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed with @codingBenVdS and @RVanhuysseXenit, we will merge docker-solr and solr-backup instead.

// Resolves DOUBLE library issues!
runCommand 'rm /opt/alfresco-search-services/solrhome/lib/solr-backup-0.0.11.jar'
runCommand 'rm /opt/alfresco-search-services/solrhome/lib/aws-java-sdk*'
runCommand 'rm /opt/alfresco-search-services/solrhome/lib/jackson-*'

smartCopy "${project.projectDir}/src/test/resources/solr.xml", "/opt/alfresco-search-services/solrhome/solr.xml"
smartCopy configurations.backupJar, "/opt/alfresco-search-services/solrhome/lib/"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,14 @@
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ObjectListing;
import groovy.util.logging.Slf4j;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.parsing.Parser;
import io.restassured.specification.RequestSpecification;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.*;

import java.util.concurrent.TimeUnit;

Expand All @@ -33,13 +28,13 @@
class SolrBackupTest {
private static final Log log = LogFactory.getLog(SolrBackupTest.class);
static RequestSpecification spec;
static RequestSpecification specBackup;
static RequestSpecification specBackupDetails;
static RequestSpecification specRestore;
static RequestSpecification specRestoreStatus;
static RequestSpecification backupRequestSpec;
static RequestSpecification backupDetailsRequestSpec;
static RequestSpecification restoreRequestSpec;
static RequestSpecification restoreStatusRequestSpec;
static RequestSpecification restoreFixedSnapshotRequestSpec;
static AmazonS3 s3Client;
static final String BUCKET = "bucket";

@BeforeEach
public void setup() {
String basePathSolr = "solr/alfresco";
Expand All @@ -66,7 +61,7 @@ public void setup() {
.setPort(solrPort)
.setBasePath(basePathSolr)
.build();
specBackup = new RequestSpecBuilder()
backupRequestSpec = new RequestSpecBuilder()
.setBaseUri(baseURISolr)
.setPort(solrPort)
.setBasePath(basePathSolrBackup)
Expand All @@ -75,29 +70,36 @@ public void setup() {
.addParam("numberToKeep", "2")
.addParam("wt", "json")
.build();
specBackupDetails = new RequestSpecBuilder()
backupDetailsRequestSpec = new RequestSpecBuilder()
.setBaseUri(baseURISolr)
.setPort(solrPort)
.setBasePath(basePathSolrBackup)
.addParam("command", "details")
.addParam("wt", "json")
.build();
specRestore = new RequestSpecBuilder()
restoreRequestSpec = new RequestSpecBuilder()
.setBaseUri(baseURISolr)
.setPort(solrPort)
.setBasePath(basePathSolrBackup)
.addParam("command", "restore")
.addParam("repository", "s3")
.build();
specRestoreStatus = new RequestSpecBuilder()
restoreStatusRequestSpec = new RequestSpecBuilder()
.setBaseUri(baseURISolr)
.setPort(solrPort)
.setBasePath(basePathSolrBackup)
.addParam("command", "restorestatus")
.addParam("wt", "json")
.build();


restoreFixedSnapshotRequestSpec = new RequestSpecBuilder()
.setBaseUri(baseURISolr)
.setPort(solrPort)
.setBasePath(basePathSolrBackup)
.addParam("command", "restore")
.addParam("repository", "s3")
.addParam("location", "bucket")
.addParam("name", "my-alfresco-backup-20251006")
.build();
// wait for solr to track
try {
sleep(30000);
Expand All @@ -106,12 +108,43 @@ public void setup() {
}
}

@Test
@Order(3)
void testRestorePointInTimeScriptEndpoint() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great you added integration test 👍

System.out.println("Restore triggered at solr-startup after health-check succeeded, will wait maximum 3 minutes");
// Check logs for restore at startup... (Solr doesnt remember by the time we reach our test).
// Retrigger a restore from the backup
String responseBody = given()
.spec(restoreFixedSnapshotRequestSpec)
.when()
.get()
.then()
.statusCode(200)
.extract()
.body() // Extract the whole body
.asString(); // as a simple string
System.out.println("RAW RESPONSE: " + responseBody); // Print it!
long startTime = System.currentTimeMillis();
await().atMost(180, TimeUnit.SECONDS)
.pollInterval(1, TimeUnit.SECONDS).until(() -> {
String status = given()
.spec(restoreStatusRequestSpec)
.when()
.get()
.then()
.statusCode(200)
.extract()
.path("restorestatus.status");
System.out.println("elapsed = " + (System.currentTimeMillis() - startTime) + "with status= " + status);
return "success".equals(status);
});
}

@Test
@Order(2)
void testRestoreEndpoint() {
given()
.spec(specRestore)
.spec(restoreRequestSpec)
.when()
.get()
.then()
Expand All @@ -121,7 +154,7 @@ void testRestoreEndpoint() {
await().atMost(180, TimeUnit.SECONDS)
.pollInterval(1, TimeUnit.SECONDS).until(() -> {
String status = given()
.spec(specRestoreStatus)
.spec(restoreStatusRequestSpec)
.when()
.get()
.then()
Expand All @@ -137,11 +170,13 @@ void testRestoreEndpoint() {
@Order(1)
void testBackupWithNumberToLiveEndpoint() {
validateSnapshotCount(0);
callBackupEndpoint(1);
triggerBackupAndWaitForCompletion(1, backupRequestSpec);

validateSnapshotCount(1);
callBackupEndpoint(2);
triggerBackupAndWaitForCompletion(2, backupRequestSpec);

validateSnapshotCount(2);
callBackupEndpoint(3);
triggerBackupAndWaitForCompletion(3, backupRequestSpec);
validateSnapshotCount(2);
}

Expand All @@ -156,26 +191,23 @@ void validateSnapshotCount(long count) {
.count() == count);

}
private void callBackupEndpoint() {
callBackupEndpoint(0);
}
private void callBackupEndpoint(int count) {
private void triggerBackupAndWaitForCompletion(int count, RequestSpecification solrBackupRequestSpec) {
String status = given()
.spec(specBackup)
.spec(solrBackupRequestSpec)
.when()
.get()
.then()
.statusCode(200)
.extract()
.path("status");
assertEquals("OK", status);
System.out.println("Backup triggered" + (count == 0 ? "" : count + " time ") + ", will wait maximum 9 minutes");
System.out.println("Solr backup triggered" + (count == 0 ? "" : count + " time ") + ", will wait maximum 9 minutes");
long startTime = System.currentTimeMillis();
await().atMost(540, TimeUnit.SECONDS)
.pollInterval(1, TimeUnit.SECONDS)
.until(() -> {
Object backup = given()
.spec(specBackupDetails)
.spec(backupDetailsRequestSpec)
.when()
.get()
.then()
Expand Down
6 changes: 5 additions & 1 deletion integration-tests/src/test/resources/compose/aws/script.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
#!/bin/bash
awslocal s3 mb s3://bucket
echo "--- Creating S3 bucket for Solr backups ---"
awslocal s3 mb s3://bucket

echo "--- Uploading Solr snapshot 'my-test-name-x' to S3 ---"
awslocal s3 sync /backups/snapshot s3://bucket/opt/alfresco-search-services/data/solr6Backup/alfresco/snapshot.my-alfresco-backup-20251006
48 changes: 40 additions & 8 deletions integration-tests/src/test/resources/compose/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
version: '3.8'

services:
alfresco:
image: ${ALFRESCO_IMAGE}
image: "${ALFRESCO_IMAGE:-local}"
networks:
- solr-backup-local-network
restart: unless-stopped
ports:
- "8080"
Expand All @@ -12,9 +12,10 @@ services:
- GLOBAL_local.transform.service.enabled=false
- GLOBAL_solr.sharedSecret=mysolrsecret
- JAVA_XMX=2048M

postgresql:
image: docker.io/xenit/postgres
networks:
- solr-backup-local-network
environment:
- POSTGRES_USER=alfresco
- POSTGRES_PASSWORD=admin
Expand All @@ -23,13 +24,17 @@ services:

share:
image: docker.io/xenit/alfresco-share-community:7.3
networks:
- solr-backup-local-network
ports:
- "8080"

solr:
image: ${DOCKER_IMAGE}
image: "${DOCKER_IMAGE:-local}"
restart: unless-stopped
hostname: solr
networks:
- solr-backup-local-network
ports:
- "8080:8080"
- "8000:8000"
Expand All @@ -45,10 +50,35 @@ services:
- S3_ACCESS_KEY=access_key
- S3_SECRET_KEY=secret_key
- S3_PATH_STYLE_ACCESS_ENABLED=true

# solr-fixed-snapshot-restore:
# image: "${DOCKER_IMAGE:-local}"
# restart: unless-stopped
# hostname: solr-fixed-snapshot-restore
# networks:
# - solr-backup-local-network
# ports:
# - "8081:8080"
# - "8001:8000"
# environment:
# - ALFRESCO_SSL=secret
# - DEBUG=true
# - JMX_ENABLED=true
# - JAVA_XMX=1024M
# - ALFRESCO_SECRET=mysolrsecret
# - S3_ENDPOINT=http://localstack:4566
# - S3_REGION=us-east-1
# - S3_BUCKET_NAME=bucket
# - S3_ACCESS_KEY=access_key
# - S3_SECRET_KEY=secret_key
# - S3_PATH_STYLE_ACCESS_ENABLED=true
# - RESTORE_FROM_BACKUP=true
# - RESTORE_BACKUP_NAME=my-alfresco-backup-20251006
# - RESTORE_BACKUP_PATH=bucket
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd leave this in as an example for anyone on how to actually setup a working FIXED_SNAPSHOT restore...

  • Breaks when doing e.g. RESTORE_BACKUP_NAME="my-alfresco-backup-20251006" or if you try to pass the path of the snapshot instead of the bucket name...

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then please add the reason as a comment.

localstack:
container_name: localstack
image: localstack/localstack:2.3.2
networks:
- solr-backup-local-network
ports:
- "4566:4566"
environment:
Expand All @@ -58,5 +88,7 @@ services:
- AWS_DEFAULT_REGION=us-east-1
volumes:
- ./aws:/etc/localstack/init/ready.d


- ./solr-snapshot:/backups
networks:
solr-backup-local-network:
driver: bridge
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading