Skip to content

Commit

Permalink
Simplify E2E tests in metadata
Browse files Browse the repository at this point in the history
Signed-off-by: Andre Kurait <[email protected]>
  • Loading branch information
AndreKurait committed Dec 10, 2024
1 parent 4d1b8a7 commit 1e81a14
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 433 deletions.
1 change: 1 addition & 0 deletions MetadataMigration/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
testImplementation group: 'org.mockito', name: 'mockito-junit-jupiter'
testImplementation group: 'org.hamcrest', name: 'hamcrest'
testImplementation group: 'org.testcontainers', name: 'testcontainers'
testImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind'

testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ public class MigrateOrEvaluateArgs {
public Version sourceVersion = null;

@ParametersDelegate
public MetadataTransformerParams metadataTransformationParams = new MetadataTransformationParams();
public MetadataTransformationParams metadataTransformationParams = new MetadataTransformationParams();

@ParametersDelegate
public TransformerParams metadataCustomTransformationParams = new MetadataCustomTransformationParams();

@Getter
public static class MetadataTransformationParams implements MetadataTransformerParams {
@Parameter(names = {"--multi-type-behavior"}, description = "How to resolve multi type mappings e.g SPLIT or UNION.", converter = MultiTypeResolutionBehaviorConverter.class)
public IndexMappingTypeRemoval.MultiTypeResolutionBehavior multiTypeResolutionBehavior = IndexMappingTypeRemoval.MultiTypeResolutionBehavior.SPLIT;
@Parameter(names = {"--multi-type-behavior"}, description = "Define behavior for resolving multi type mappings.")
public IndexMappingTypeRemoval.MultiTypeResolutionBehavior multiTypeResolutionBehavior = IndexMappingTypeRemoval.MultiTypeResolutionBehavior.NONE;
}

@Getter
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package org.opensearch.migrations;

import java.io.File;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import org.opensearch.migrations.bulkload.common.FileSystemSnapshotCreator;
import org.opensearch.migrations.bulkload.common.OpenSearchClient;
import org.opensearch.migrations.bulkload.common.http.ConnectionContextTestParams;
import org.opensearch.migrations.bulkload.framework.SearchClusterContainer;
import org.opensearch.migrations.bulkload.http.ClusterOperations;
import org.opensearch.migrations.bulkload.worker.SnapshotRunner;
import org.opensearch.migrations.commands.MigrationItemResult;
import org.opensearch.migrations.metadata.tracing.MetadataMigrationTestContext;
import org.opensearch.migrations.snapshot.creation.tracing.SnapshotTestContext;

import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.io.TempDir;

/**
* Base test class providing shared setup and utility methods for migration tests.
*/
@Slf4j
abstract class BaseMigrationTest {

@TempDir
protected File localDirectory;

@Getter
protected SearchClusterContainer sourceCluster;
@Getter
protected SearchClusterContainer targetCluster;

protected ClusterOperations sourceOperations;
protected ClusterOperations targetOperations;

/**
* Starts the source and target clusters.
*/
protected void startClusters() {
CompletableFuture.allOf(
CompletableFuture.runAsync(sourceCluster::start),
CompletableFuture.runAsync(targetCluster::start)
).join();

sourceOperations = new ClusterOperations(sourceCluster.getUrl());
targetOperations = new ClusterOperations(targetCluster.getUrl());
}

/**
* Sets up a snapshot repository and takes a snapshot of the source cluster.
*
* @param snapshotName Name of the snapshot.
* @return The name of the created snapshot.
*/
@SneakyThrows
protected String createSnapshot(String snapshotName) {
var snapshotContext = SnapshotTestContext.factory().noOtelTracking();
var sourceClient = new OpenSearchClient(ConnectionContextTestParams.builder()
.host(sourceCluster.getUrl())
.insecure(true)
.build()
.toConnectionContext());
var snapshotCreator = new org.opensearch.migrations.bulkload.common.FileSystemSnapshotCreator(
snapshotName,
sourceClient,
SearchClusterContainer.CLUSTER_SNAPSHOT_DIR,
List.of(),
snapshotContext.createSnapshotCreateContext()
);
org.opensearch.migrations.bulkload.worker.SnapshotRunner.runAndWaitForCompletion(snapshotCreator);
sourceCluster.copySnapshotData(localDirectory.toString());
return snapshotName;
}

/**
* Prepares migration arguments for snapshot-based migrations.
*
* @param snapshotName Name of the snapshot.
* @return Prepared migration arguments.
*/
protected MigrateOrEvaluateArgs prepareSnapshotMigrationArgs(String snapshotName) {
var arguments = new MigrateOrEvaluateArgs();
arguments.fileSystemRepoPath = localDirectory.getAbsolutePath();
arguments.snapshotName = snapshotName;
arguments.sourceVersion = sourceCluster.getContainerVersion().getVersion();
arguments.targetArgs.host = targetCluster.getUrl();
return arguments;
}

/**
* Executes the migration command (either migrate or evaluate).
*
* @param arguments Migration arguments.
* @param command The migration command to execute.
* @return The result of the migration.
*/
protected MigrationItemResult executeMigration(MigrateOrEvaluateArgs arguments, MetadataCommands command) {
var metadataContext = MetadataMigrationTestContext.factory().noOtelTracking();
var metadata = new MetadataMigration();

if (MetadataCommands.MIGRATE.equals(command)) {
return metadata.migrate(arguments).execute(metadataContext);
} else {
return metadata.evaluate(arguments).execute(metadataContext);
}
}

/**
* Creates an OpenSearch client for the given cluster.
*
* @param cluster The cluster container.
* @return An OpenSearch client.
*/
protected OpenSearchClient createClient(SearchClusterContainer cluster) {
return new OpenSearchClient(ConnectionContextTestParams.builder()
.host(cluster.getUrl())
.insecure(true)
.build()
.toConnectionContext());
}

protected SnapshotTestContext createSnapshotContext() {
return SnapshotTestContext.factory().noOtelTracking();
}

protected FileSystemSnapshotCreator createSnapshotCreator(String snapshotName, OpenSearchClient client, SnapshotTestContext context) {
return new FileSystemSnapshotCreator(
snapshotName,
client,
SearchClusterContainer.CLUSTER_SNAPSHOT_DIR,
List.of(),
context.createSnapshotCreateContext()
);
}

@SneakyThrows
protected void runSnapshotAndCopyData(FileSystemSnapshotCreator snapshotCreator, SearchClusterContainer cluster) {
SnapshotRunner.runAndWaitForCompletion(snapshotCreator);
cluster.copySnapshotData(localDirectory.toString());
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
package org.opensearch.migrations;

import java.io.File;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;

import org.opensearch.migrations.bulkload.SupportedClusters;
import org.opensearch.migrations.bulkload.common.FileSystemSnapshotCreator;
import org.opensearch.migrations.bulkload.common.OpenSearchClient;
import org.opensearch.migrations.bulkload.common.http.ConnectionContextTestParams;
import org.opensearch.migrations.bulkload.framework.SearchClusterContainer;
import org.opensearch.migrations.bulkload.http.ClusterOperations;
import org.opensearch.migrations.bulkload.models.DataFilterArgs;
import org.opensearch.migrations.bulkload.transformers.MetadataTransformerParams;
import org.opensearch.migrations.bulkload.worker.SnapshotRunner;
import org.opensearch.migrations.commands.MigrationItemResult;
import org.opensearch.migrations.metadata.tracing.MetadataMigrationTestContext;
import org.opensearch.migrations.snapshot.creation.tracing.SnapshotTestContext;
import org.opensearch.migrations.transform.TransformerParams;
import org.opensearch.migrations.transformation.rules.IndexMappingTypeRemoval;

Expand All @@ -25,7 +15,6 @@
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
Expand All @@ -39,10 +28,7 @@
*/
@Tag("isolatedTest")
@Slf4j
class CustomTransformationTest {

@TempDir
private File localDirectory;
class CustomTransformationTest extends BaseMigrationTest {

private static Stream<Arguments> scenarios() {
// Define scenarios with different source and target cluster versions
Expand All @@ -62,23 +48,17 @@ void customTransformationMetadataMigration(
final var sourceCluster = new SearchClusterContainer(sourceVersion);
final var targetCluster = new SearchClusterContainer(targetVersion)
) {
performCustomTransformationTest(sourceCluster, targetCluster);
this.sourceCluster = sourceCluster;
this.targetCluster = targetCluster;
performCustomTransformationTest();
}
}

@SneakyThrows
private void performCustomTransformationTest(
final SearchClusterContainer sourceCluster,
final SearchClusterContainer targetCluster
) {
// Start both source and target clusters asynchronously
CompletableFuture.allOf(
CompletableFuture.runAsync(sourceCluster::start),
CompletableFuture.runAsync(targetCluster::start)
).join();
private void performCustomTransformationTest() {
startClusters();

var sourceOperations = new ClusterOperations(sourceCluster.getUrl());
var targetOperations = new ClusterOperations(targetCluster.getUrl());
var newComponentCompatible = sourceCluster.getContainerVersion().getVersion().getMajor() >= 7;

// Test data
var originalIndexName = "test_index";
Expand All @@ -95,28 +75,22 @@ private void performCustomTransformationTest(
var legacyTemplatePattern = "legacy_*";
sourceOperations.createLegacyTemplate(legacyTemplateName, legacyTemplatePattern);

// Create index template
// Create index template and component template if compatible
var indexTemplateName = "index_template";
var indexTemplatePattern = "index*";

// Create component template
var componentTemplateName = "component_template";
var componentTemplateMode = "mode_value"; // Replace with actual mode if applicable
boolean newComponentCompatible = sourceCluster.getContainerVersion().getVersion().getMajor() >= 7;
if (newComponentCompatible) {
sourceOperations.createIndexTemplate(indexTemplateName, "dummy", indexTemplatePattern);

var componentTemplateAdditionalParam = "additional_param"; // Replace with actual param if applicable
sourceOperations.createComponentTemplate(componentTemplateName, indexTemplateName, componentTemplateAdditionalParam, "index*");
sourceOperations.createComponentTemplate(componentTemplateName, indexTemplateName, "additional_param", "index*");
}

// Create index that matches the templates
// Create indices that match the templates
var legacyIndexName = "legacy_index";
var indexIndexName = "index_index";
sourceOperations.createIndex(legacyIndexName);
sourceOperations.createIndex(indexIndexName);

// Define custom transformations for index, legacy, and component templates
// Define custom transformations
String customTransformationJson = "[\n" +
" {\n" +
" \"JsonConditionalTransformerProvider\": [\n" +
Expand Down Expand Up @@ -185,52 +159,23 @@ private void performCustomTransformationTest(
" }\n" +
"]";

var arguments = new MigrateOrEvaluateArgs();

// Use SnapshotImage as the transfer medium
var snapshotName = "custom_transformation_snap";
var snapshotContext = SnapshotTestContext.factory().noOtelTracking();
var sourceClient = new OpenSearchClient(ConnectionContextTestParams.builder()
.host(sourceCluster.getUrl())
.insecure(true)
.build()
.toConnectionContext());
var snapshotCreator = new FileSystemSnapshotCreator(
snapshotName,
sourceClient,
SearchClusterContainer.CLUSTER_SNAPSHOT_DIR,
List.of(),
snapshotContext.createSnapshotCreateContext()
);
SnapshotRunner.runAndWaitForCompletion(snapshotCreator);
sourceCluster.copySnapshotData(localDirectory.toString());
arguments.fileSystemRepoPath = localDirectory.getAbsolutePath();
arguments.snapshotName = snapshotName;
arguments.sourceVersion = sourceCluster.getContainerVersion().getVersion();
var snapshotName = createSnapshot("custom_transformation_snap");
var arguments = prepareSnapshotMigrationArgs(snapshotName);

arguments.targetArgs.host = targetCluster.getUrl();

// Set up data filters to include only the test index and templates
// Set up data filters
var dataFilterArgs = new DataFilterArgs();
dataFilterArgs.indexAllowlist = List.of(originalIndexName, legacyIndexName, indexIndexName, transformedIndexName);
dataFilterArgs.indexTemplateAllowlist = List.of(indexTemplateName, legacyTemplateName, "transformed_legacy_template", "transformed_index_template");
dataFilterArgs.componentTemplateAllowlist = List.of(componentTemplateName, "transformed_component_template");
arguments.dataFilterArgs = dataFilterArgs;

// Use split for multi type mappings resolution
arguments.metadataTransformationParams = TestMetadataTransformationParams.builder()
.multiTypeResolutionBehavior(IndexMappingTypeRemoval.MultiTypeResolutionBehavior.SPLIT)
.build();
// Specify the custom transformer configuration
// Set up transformation parameters
arguments.metadataCustomTransformationParams = TestCustomTransformationParams.builder()
.transformerConfig(customTransformationJson)
.build();

// Execute the migration with the custom transformation
var metadataContext = MetadataMigrationTestContext.factory().noOtelTracking();
var metadata = new MetadataMigration();

MigrationItemResult result = metadata.migrate(arguments).execute(metadataContext);
// Execute migration
MigrationItemResult result = executeMigration(arguments, MetadataCommands.MIGRATE);

// Verify the migration result
log.info(result.asCliOutput());
Expand All @@ -245,31 +190,26 @@ private void performCustomTransformationTest(
res = targetOperations.get("/" + originalIndexName);
assertThat(res.getKey(), equalTo(404));

// Verify that the transformed legacy template exists on the target cluster
// Verify templates
res = targetOperations.get("/_template/transformed_legacy_template");
assertThat(res.getKey(), equalTo(200));
assertThat(res.getValue(), containsString("transformed_legacy_template"));

// Verify that the original legacy template does not exist on the target cluster
res = targetOperations.get("/_template/" + legacyTemplateName);
res = targetOperations.get("/_template/" + "legacy_template");
assertThat(res.getKey(), equalTo(404));

if (newComponentCompatible) {
// Verify that the transformed index template exists on the target cluster
res = targetOperations.get("/_index_template/transformed_index_template");
assertThat(res.getKey(), equalTo(200));
assertThat(res.getValue(), containsString("transformed_index_template"));

// Verify that the original index template does not exist on the target cluster
res = targetOperations.get("/_index_template/" + indexTemplateName);
assertThat(res.getKey(), equalTo(404));

// Verify that the transformed component template exists on the target cluster
res = targetOperations.get("/_component_template/transformed_component_template");
assertThat(res.getKey(), equalTo(200));
assertThat(res.getValue(), containsString("transformed_component_template"));

// Verify that the original component template does not exist on the target cluster
res = targetOperations.get("/_component_template/" + componentTemplateName);
assertThat(res.getKey(), equalTo(404));
}
Expand All @@ -287,8 +227,7 @@ private static class TestCustomTransformationParams implements TransformerParams

@Data
@Builder
private static class TestMetadataTransformationParams implements MetadataTransformerParams {
private static class TestMetadataTransformationParams implements org.opensearch.migrations.bulkload.transformers.MetadataTransformerParams {
private IndexMappingTypeRemoval.MultiTypeResolutionBehavior multiTypeResolutionBehavior;
}

}
Loading

0 comments on commit 1e81a14

Please sign in to comment.