diff --git a/modules/compatibility-tests/build.gradle b/modules/compatibility-tests/build.gradle index af015ce44ca1..e5416945771b 100644 --- a/modules/compatibility-tests/build.gradle +++ b/modules/compatibility-tests/build.gradle @@ -52,6 +52,7 @@ dependencies { integrationTestImplementation project(':ignite-storage-page-memory') integrationTestImplementation project(':ignite-metastorage-api') integrationTestImplementation project(':ignite-metastorage') + integrationTestImplementation project(':ignite-vault') integrationTestImplementation project(':ignite-cluster-management') integrationTestImplementation project(':ignite-raft') integrationTestImplementation project(':ignite-jdbc') diff --git a/modules/compatibility-tests/jobs.gradle b/modules/compatibility-tests/jobs.gradle index 193bd6faf014..f1e9553d280a 100644 --- a/modules/compatibility-tests/jobs.gradle +++ b/modules/compatibility-tests/jobs.gradle @@ -45,6 +45,7 @@ dependencies { jobsImplementation project(':ignite-metastorage-api') jobsImplementation project(':ignite-metastorage') jobsImplementation project(':ignite-page-memory') + jobsImplementation project(':ignite-vault') jobsImplementation project(':ignite-storage-api') jobsImplementation project(':ignite-storage-page-memory') jobsImplementation project(':ignite-raft') diff --git a/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/ItVaultStorageCompatibilityTest.java b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/ItVaultStorageCompatibilityTest.java new file mode 100644 index 000000000000..a9de49603e6c --- /dev/null +++ b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/ItVaultStorageCompatibilityTest.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal; + +import static org.apache.ignite.internal.TestWrappers.unwrapIgniteImpl; +import static org.apache.ignite.internal.compute.PutVaultEntriesJob.NEW_VALUE; +import static org.apache.ignite.internal.compute.PutVaultEntriesJob.OVERWRITTEN_KEY; +import static org.apache.ignite.internal.compute.PutVaultEntriesJob.REMOVED_KEY; +import static org.apache.ignite.internal.compute.PutVaultEntriesJob.TEST_KEY; +import static org.apache.ignite.internal.compute.PutVaultEntriesJob.TEST_VALUE; +import static org.apache.ignite.internal.jobs.DeploymentUtils.runJob; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import org.apache.ignite.Ignite; +import org.apache.ignite.internal.app.IgniteImpl; +import org.apache.ignite.internal.compute.PutVaultEntriesJob; +import org.apache.ignite.internal.jobs.DeploymentUtils; +import org.apache.ignite.internal.vault.VaultEntry; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; + +/** Compatibility tests for vault storage. */ +@ParameterizedClass +@MethodSource("baseVersions") +@MicronautTest(rebuildContext = true) +public class ItVaultStorageCompatibilityTest extends CompatibilityTestBase { + @Override + protected int nodesCount() { + return 1; + } + + @Override + protected void setupBaseVersion(Ignite baseIgnite) { + DeploymentUtils.deployJobs(); + + runPutVaultEntriesJob(); + } + + @Test + void testVaultStorageCompatibility() { + IgniteImpl ignite = unwrapIgniteImpl(cluster.node(0)); + + assertThat(ignite.vault().get(TEST_KEY).value(), is(TEST_VALUE)); + assertThat(ignite.vault().get(OVERWRITTEN_KEY).value(), is(NEW_VALUE)); + assertThat(ignite.vault().get(REMOVED_KEY), is(nullValue())); + + for (var entry : PutVaultEntriesJob.PUT_ALL_ENTRIES.entrySet()) { + VaultEntry actual = ignite.vault().get(entry.getKey()); + + assertThat(actual, is(notNullValue())); + assertThat(actual.value(), is(entry.getValue())); + } + } + + private void runPutVaultEntriesJob() { + runJob(cluster, PutVaultEntriesJob.class, null); + } +} diff --git a/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/CheckpointJob.java b/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/CheckpointJob.java index d0a6c65acdb5..d20576f72c08 100644 --- a/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/CheckpointJob.java +++ b/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/CheckpointJob.java @@ -18,6 +18,8 @@ package org.apache.ignite.internal.compute; import static java.lang.Thread.sleep; +import static java.util.concurrent.CompletableFuture.failedFuture; +import static org.apache.ignite.internal.compute.JobsCommon.unwrapIgniteImpl; import static org.apache.ignite.internal.wrapper.Wrappers.unwrapNullable; import java.lang.reflect.Field; @@ -32,7 +34,6 @@ import org.apache.ignite.internal.pagememory.persistence.store.FilePageStoreManager; import org.apache.ignite.internal.storage.DataStorageManager; import org.apache.ignite.internal.storage.pagememory.PersistentPageMemoryStorageEngine; -import org.apache.ignite.internal.wrapper.Wrappers; /** A job that forces a checkpoint and optionally cancels the compaction process on the node. */ public class CheckpointJob implements ComputeJob { @@ -40,7 +41,7 @@ public class CheckpointJob implements ComputeJob { public CompletableFuture executeAsync(JobExecutionContext context, Boolean shouldCancelCompaction) { try { - IgniteImpl igniteImpl = Wrappers.unwrap(context.ignite(), IgniteImpl.class); + IgniteImpl igniteImpl = unwrapIgniteImpl(context.ignite()); CheckpointManager checkpointManager = checkpointManager(igniteImpl); @@ -63,7 +64,7 @@ public CompletableFuture executeAsync(JobExecutionContext context, Boolean } }); } catch (Exception e) { - throw new RuntimeException(e); + return failedFuture(e); } } diff --git a/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/PutVaultEntriesJob.java b/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/PutVaultEntriesJob.java new file mode 100644 index 000000000000..dbac87662297 --- /dev/null +++ b/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/PutVaultEntriesJob.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.compute; + +import static org.apache.ignite.internal.compute.JobsCommon.unwrapIgniteImpl; +import static org.apache.ignite.internal.util.CompletableFutures.nullCompletedFuture; + +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.apache.ignite.compute.ComputeJob; +import org.apache.ignite.compute.JobExecutionContext; +import org.apache.ignite.internal.app.IgniteImpl; +import org.apache.ignite.internal.lang.ByteArray; +import org.apache.ignite.internal.vault.VaultManager; + +/** A job that writes values specified in constants to node's vault. */ +public class PutVaultEntriesJob implements ComputeJob { + public static final ByteArray TEST_KEY = new ByteArray("test_key".getBytes(StandardCharsets.UTF_8)); + + public static final byte[] TEST_VALUE = "test_value".getBytes(StandardCharsets.UTF_8); + + public static final ByteArray OVERWRITTEN_KEY = new ByteArray("overwritten_key".getBytes(StandardCharsets.UTF_8)); + + public static final byte[] INITIAL_VALUE = "initial_value".getBytes(StandardCharsets.UTF_8); + + public static final byte[] NEW_VALUE = "NEW_VALUE".getBytes(StandardCharsets.UTF_8); + + public static final ByteArray REMOVED_KEY = new ByteArray("removed_key".getBytes(StandardCharsets.UTF_8)); + + public static final Map PUT_ALL_ENTRIES = Map.of( + new ByteArray("put_all_key1".getBytes(StandardCharsets.UTF_8)), "put_all_value1".getBytes(StandardCharsets.UTF_8), + new ByteArray("put_all_key2".getBytes(StandardCharsets.UTF_8)), "put_all_value2".getBytes(StandardCharsets.UTF_8) + ); + + @Override + public CompletableFuture executeAsync(JobExecutionContext context, String arg) { + IgniteImpl igniteImpl = unwrapIgniteImpl(context.ignite()); + + VaultManager vault = igniteImpl.vault(); + + vault.put(TEST_KEY, TEST_VALUE); + vault.put(OVERWRITTEN_KEY, INITIAL_VALUE); + vault.put(REMOVED_KEY, INITIAL_VALUE); + vault.put(OVERWRITTEN_KEY, NEW_VALUE); + vault.remove(REMOVED_KEY); + vault.putAll(PUT_ALL_ENTRIES); + + return nullCompletedFuture(); + } +} diff --git a/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/SendAllMetastorageCommandTypesJob.java b/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/SendAllMetastorageCommandTypesJob.java index 19b1f2bf9528..fd89163f39cd 100644 --- a/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/SendAllMetastorageCommandTypesJob.java +++ b/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/SendAllMetastorageCommandTypesJob.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.compute; import static java.util.concurrent.CompletableFuture.allOf; +import static java.util.concurrent.CompletableFuture.failedFuture; import static org.apache.ignite.internal.metastorage.dsl.Conditions.exists; import static org.apache.ignite.internal.metastorage.dsl.Operations.noop; import static org.apache.ignite.internal.metastorage.dsl.Operations.ops; @@ -34,42 +35,40 @@ import org.apache.ignite.internal.hlc.HybridTimestamp; import org.apache.ignite.internal.lang.ByteArray; import org.apache.ignite.internal.metastorage.impl.MetaStorageManagerImpl; -import org.apache.ignite.internal.wrapper.Wrappers; /** A job that runs different MetastorageWriteCommands. */ // TODO IGNITE-26874 Add a check that all write commands are covered. public class SendAllMetastorageCommandTypesJob implements ComputeJob { @Override public CompletableFuture executeAsync(JobExecutionContext context, String arg) { + IgniteImpl igniteImpl = JobsCommon.unwrapIgniteImpl(context.ignite()); - try { - IgniteImpl igniteImpl = Wrappers.unwrap(context.ignite(), IgniteImpl.class); + byte[] value = "value".getBytes(StandardCharsets.UTF_8); + + MetaStorageManagerImpl metastorage = (MetaStorageManagerImpl) igniteImpl.metaStorageManager(); - byte[] value = "value".getBytes(StandardCharsets.UTF_8); + return allOf( + metastorage.put(ByteArray.fromString("put"), value), + metastorage.putAll(Map.of(ByteArray.fromString("putAll"), value)), + metastorage.remove(ByteArray.fromString("remove")), + metastorage.removeAll(Set.of(ByteArray.fromString("removeAll"))), + metastorage.removeByPrefix(ByteArray.fromString("removeByPrefix")), + metastorage.invoke(exists(ByteArray.fromString("key")), noop(), noop()), + metastorage.invoke( + iif(exists(ByteArray.fromString("key")), ops().yield(), ops().yield())), + metastorage.evictIdempotentCommandsCache(HybridTimestamp.MAX_VALUE), + sendCompactionCommand(metastorage) + ).thenCompose((v) -> metastorage.storage().flush()); + } - MetaStorageManagerImpl metastorage = (MetaStorageManagerImpl) igniteImpl.metaStorageManager(); + private static CompletableFuture sendCompactionCommand(MetaStorageManagerImpl metastorage) { + try { + Method sendCompactionCommand = metastorage.getClass().getDeclaredMethod("sendCompactionCommand", long.class); + sendCompactionCommand.setAccessible(true); - return allOf( - metastorage.put(ByteArray.fromString("put"), value), - metastorage.putAll(Map.of(ByteArray.fromString("putAll"), value)), - metastorage.remove(ByteArray.fromString("remove")), - metastorage.removeAll(Set.of(ByteArray.fromString("removeAll"))), - metastorage.removeByPrefix(ByteArray.fromString("removeByPrefix")), - metastorage.invoke(exists(ByteArray.fromString("key")), noop(), noop()), - metastorage.invoke( - iif(exists(ByteArray.fromString("key")), ops().yield(), ops().yield())), - metastorage.evictIdempotentCommandsCache(HybridTimestamp.MAX_VALUE), - sendCompactionCommand(metastorage) - ).thenCompose((v) -> metastorage.storage().flush()); + return (CompletableFuture) sendCompactionCommand.invoke(metastorage, metastorage.appliedRevision()); } catch (Exception e) { - throw new RuntimeException(e); + return failedFuture(e); } } - - private static CompletableFuture sendCompactionCommand(MetaStorageManagerImpl metastorage) - throws Exception { - Method sendCompactionCommand = metastorage.getClass().getDeclaredMethod("sendCompactionCommand", long.class); - sendCompactionCommand.setAccessible(true); - return (CompletableFuture) sendCompactionCommand.invoke(metastorage, metastorage.appliedRevision()); - } } diff --git a/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/TruncateRaftLogCommand.java b/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/TruncateRaftLogCommand.java index 6ac35c19890c..f6f1f4fda8d3 100644 --- a/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/TruncateRaftLogCommand.java +++ b/modules/compatibility-tests/src/jobs/java/org/apache/ignite/internal/compute/TruncateRaftLogCommand.java @@ -20,7 +20,6 @@ import static org.apache.ignite.internal.compute.JobsCommon.unwrapIgniteImpl; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; import org.apache.ignite.compute.ComputeJob; import org.apache.ignite.compute.JobExecutionContext; import org.apache.ignite.internal.app.IgniteImpl; @@ -33,22 +32,18 @@ public class TruncateRaftLogCommand implements ComputeJob { @Override public CompletableFuture executeAsync(JobExecutionContext context, String groupId) { - try { - IgniteImpl igniteImpl = unwrapIgniteImpl(context.ignite()); + IgniteImpl igniteImpl = unwrapIgniteImpl(context.ignite()); - SnapshotRequest request = new RaftMessagesFactory().snapshotRequest() - .groupId(groupId) - .peerId(igniteImpl.name()) - .build(); + SnapshotRequest request = new RaftMessagesFactory().snapshotRequest() + .groupId(groupId) + .peerId(igniteImpl.name()) + .build(); - MessagingService messagingService = igniteImpl.raftManager().messagingService(); + MessagingService messagingService = igniteImpl.raftManager().messagingService(); - // Version 3.0.0 doesn't have "forced" snapshot, so we have to request it twice. - return messagingService.invoke(igniteImpl.name(), request, 10_000L) - .thenCompose(ignored -> messagingService.invoke(igniteImpl.name(), request, 10_000L)) - .thenApply(ignored -> null); - } catch (Exception e) { - throw new CompletionException(e); - } + // Version 3.0.0 doesn't have "forced" snapshot, so we have to request it twice. + return messagingService.invoke(igniteImpl.name(), request, 10_000L) + .thenCompose(ignored -> messagingService.invoke(igniteImpl.name(), request, 10_000L)) + .thenApply(ignored -> null); } }