From 9bf024dd0a35de52a3cfff57b2ebfd3246a9063a Mon Sep 17 00:00:00 2001 From: Tsz-Wo Nicholas Sze Date: Thu, 21 May 2026 15:44:07 -0700 Subject: [PATCH] HDDS-15322. Add tests for ScmInvoker subclasses. --- .../ha/invoker/CertificateStoreInvoker.java | 3 +- .../invoker/ContainerStateManagerInvoker.java | 12 +-- .../ha/invoker/ScmInvokerCodeGenerator.java | 38 ++++++-- .../invoker/ScmInvokerCodeGeneratorMains.java | 32 +++++-- .../invoker/TestScmInvokerCodeGenerator.java | 89 +++++++++++++++++++ 5 files changed, 148 insertions(+), 26 deletions(-) create mode 100644 hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/TestScmInvokerCodeGenerator.java diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/CertificateStoreInvoker.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/CertificateStoreInvoker.java index 2305dc542e26..f4f71043e090 100644 --- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/CertificateStoreInvoker.java +++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/CertificateStoreInvoker.java @@ -88,8 +88,7 @@ public void reinitialize(SCMMetadataStore arg0) { @Override public List removeAllExpiredCertificates() throws IOException { final Object[] args = {}; - return (List) invoker.invokeReplicateDirect(ReplicateMethod.removeAllExpiredCertificates, - args); + return (List)invoker.invokeReplicateDirect(ReplicateMethod.removeAllExpiredCertificates, args); } @Override diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java index 12cc3785d28d..394dfd3376b1 100644 --- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java +++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java @@ -116,12 +116,12 @@ public List getContainerIDs(LifeCycleState arg0, ContainerID arg1, } @Override - public List getContainerInfos(ReplicationType arg0) { + public List getContainerInfos(LifeCycleState arg0) { return invoker.getImpl().getContainerInfos(arg0); } @Override - public List getContainerInfos(LifeCycleState arg0) { + public List getContainerInfos(ReplicationType arg0) { return invoker.getImpl().getContainerInfos(arg0); } @@ -231,14 +231,14 @@ public Message invokeLocal(String methodName, Object[] p) throws Exception { break; case "getContainerInfos": - if (p.length == 1 && (p[0] == null || ReplicationType.class.isInstance(p[0]))) { - final ReplicationType arg7 = (ReplicationType) p[0]; + if (p.length == 1 && (p[0] == null || LifeCycleState.class.isInstance(p[0]))) { + final LifeCycleState arg7 = (LifeCycleState) p[0]; returnType = List.class; returnValue = getImpl().getContainerInfos(arg7); break; } - if (p.length == 1 && (p[0] == null || LifeCycleState.class.isInstance(p[0]))) { - final LifeCycleState arg8 = (LifeCycleState) p[0]; + if (p.length == 1 && (p[0] == null || ReplicationType.class.isInstance(p[0]))) { + final ReplicationType arg8 = (ReplicationType) p[0]; returnType = List.class; returnValue = getImpl().getContainerInfos(arg8); break; diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGenerator.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGenerator.java index 813e17619d50..dd188916b587 100644 --- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGenerator.java +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGenerator.java @@ -49,7 +49,9 @@ import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.hdds.scm.metadata.Replicate; +import org.apache.ratis.io.MD5Hash; import org.apache.ratis.protocol.Message; +import org.apache.ratis.util.MD5FileUtil; import org.apache.ratis.util.Preconditions; import org.apache.ratis.util.UncheckedAutoCloseable; @@ -82,7 +84,7 @@ public final class ScmInvokerCodeGenerator { private final StringWriter out = new StringWriter(); private String indentation = ""; - private ScmInvokerCodeGenerator(Class api) { + ScmInvokerCodeGenerator(Class api) { this.api = api; this.apiName = api.getSimpleName(); this.invokerClassName = getInvokerClassName(api); @@ -296,7 +298,9 @@ List getMethods(Boolean isDefault, Boolean isDeprecated) { List getMethods(Predicate filter) { return Arrays.stream(api.getMethods()) .filter(filter) - .sorted(Comparator.comparing(Method::getName).thenComparing(Method::getParameterCount)) + .sorted(Comparator.comparing(Method::getName) + .thenComparing(Method::getParameterCount) + .thenComparing(m -> Arrays.toString(m.getParameterTypes()))) .collect(Collectors.toList()); } @@ -607,15 +611,17 @@ public String generateClass() { return out.toString(); } - File updateFile(String classString) throws IOException { - final File java = new File(DIR, invokerClassName + ".java"); + File updateFile(String classString, String dir, boolean overwrite) throws IOException { + final File java = new File(dir, invokerClassName + ".java"); if (!java.isFile()) { throw new FileNotFoundException("Not found: " + java.getAbsolutePath()); } - final File tmp = new File(DIR, invokerClassName + "_tmp.java"); + final File tmp = new File(dir, invokerClassName + "_tmp.java"); if (tmp.exists()) { throw new IOException("Already exist: " + java.getAbsolutePath()); } + tmp.deleteOnExit(); + try (InputStream inStream = Files.newInputStream(java.toPath()); BufferedReader in = new BufferedReader(new InputStreamReader(new BufferedInputStream(inStream), UTF_8)); OutputStream outStream = Files.newOutputStream(tmp.toPath(), StandardOpenOption.CREATE_NEW); @@ -634,8 +640,18 @@ File updateFile(String classString) throws IOException { out.print(classString); } - Files.move(tmp.toPath(), java.toPath(), StandardCopyOption.REPLACE_EXISTING); - return java; + final MD5Hash javaMd5 = MD5FileUtil.computeMd5ForFile(java); + final MD5Hash tmpMd5 = MD5FileUtil.computeMd5ForFile(tmp); + if (Arrays.equals(javaMd5.getDigest(), tmpMd5.getDigest())) { + Files.delete(tmp.toPath()); + return null; + } + if (overwrite) { + Files.move(tmp.toPath(), java.toPath(), StandardCopyOption.REPLACE_EXISTING); + return java; + } else { + return tmp; + } } public static void generate(Class api, boolean updateFile) { @@ -648,11 +664,15 @@ public static void generate(Class api, boolean updateFile) { final File file; try { - file = generator.updateFile(classString); + file = generator.updateFile(classString, DIR, true); } catch (IOException e) { throw new IllegalStateException("Failed to updateFile", e); } - System.out.printf("Successfully update file: %s%n", file); + if (file == null) { + System.out.printf("No change for %s%n", getInvokerClassName(api)); + } else { + System.out.printf("Successfully update file: %s%n", file); + } } static class DeclaredMethod { diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGeneratorMains.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGeneratorMains.java index 846b5096d2f0..601246c12dcd 100644 --- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGeneratorMains.java +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGeneratorMains.java @@ -31,56 +31,70 @@ class ScmInvokerCodeGeneratorMains { static class GenerateDeletedBlockLogStateManager { - public static void main(String[] args) { + public static void main(String... args) { ScmInvokerCodeGenerator.generate(DeletedBlockLogStateManager.class, true); } } static class GenerateContainerStateManager { - public static void main(String[] args) { + public static void main(String... args) { ScmInvokerCodeGenerator.generate(ContainerStateManager.class, true); } } static class GeneratePipelineStateManager { - public static void main(String[] args) { + public static void main(String... args) { ScmInvokerCodeGenerator.generate(PipelineStateManager.class, true); } } static class GenerateRootCARotationHandler { - public static void main(String[] args) { + public static void main(String... args) { ScmInvokerCodeGenerator.generate(RootCARotationHandler.class, true); } } static class GenerateFinalizationStateManager { - public static void main(String[] args) { + public static void main(String... args) { ScmInvokerCodeGenerator.generate(FinalizationStateManager.class, true); } } static class GenerateSecretKeyState { - public static void main(String[] args) { + public static void main(String... args) { ScmInvokerCodeGenerator.generate(SecretKeyState.class, true); } } static class GenerateSequenceIdGeneratorStateManager { - public static void main(String[] args) { + public static void main(String... args) { ScmInvokerCodeGenerator.generate(SequenceIdGenerator.StateManager.class, true); } } static class GenerateStatefulServiceStateManager { - public static void main(String[] args) { + public static void main(String... args) { ScmInvokerCodeGenerator.generate(StatefulServiceStateManager.class, true); } } static class GenerateCertificateStore { - public static void main(String[] args) { + public static void main(String... args) { ScmInvokerCodeGenerator.generate(CertificateStore.class, true); } } + + static class All { + public static void main(String... args) { + GenerateCertificateStore.main(); + GenerateContainerStateManager.main(); + GenerateDeletedBlockLogStateManager.main(); + GenerateFinalizationStateManager.main(); + GeneratePipelineStateManager.main(); + GenerateRootCARotationHandler.main(); + GenerateSecretKeyState.main(); + GenerateSequenceIdGeneratorStateManager.main(); + GenerateStatefulServiceStateManager.main(); + } + } } diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/TestScmInvokerCodeGenerator.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/TestScmInvokerCodeGenerator.java new file mode 100644 index 000000000000..c4d8a009e0bd --- /dev/null +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/invoker/TestScmInvokerCodeGenerator.java @@ -0,0 +1,89 @@ +/* + * 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.hadoop.hdds.scm.ha.invoker; + +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.File; +import org.apache.hadoop.hdds.scm.block.DeletedBlockLogStateManager; +import org.apache.hadoop.hdds.scm.container.ContainerStateManager; +import org.apache.hadoop.hdds.scm.ha.SequenceIdGenerator; +import org.apache.hadoop.hdds.scm.ha.StatefulServiceStateManager; +import org.apache.hadoop.hdds.scm.pipeline.PipelineStateManager; +import org.apache.hadoop.hdds.scm.security.RootCARotationHandler; +import org.apache.hadoop.hdds.scm.server.upgrade.FinalizationStateManager; +import org.apache.hadoop.hdds.security.symmetric.SecretKeyState; +import org.apache.hadoop.hdds.security.x509.certificate.authority.CertificateStore; +import org.junit.jupiter.api.Test; + +/** Test the code generated by {@link ScmInvokerCodeGenerator}. */ +public final class TestScmInvokerCodeGenerator { + static final String DIR = "src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/"; + + static void runTest(Class api) throws Exception { + final ScmInvokerCodeGenerator generator = new ScmInvokerCodeGenerator(api); + final String classString = generator.generateClass(); + final File file = generator.updateFile(classString, DIR, false); + assertNull(file, () -> ScmInvokerCodeGenerator.getInvokerClassName(api) + " is changed."); + } + + @Test + public void testDeletedBlockLogStateManager() throws Exception { + runTest(DeletedBlockLogStateManager.class); + } + + @Test + public void testContainerStateManager() throws Exception { + runTest(ContainerStateManager.class); + } + + @Test + public void testPipelineStateManager() throws Exception { + runTest(PipelineStateManager.class); + } + + @Test + public void testRootCARotationHandler() throws Exception { + runTest(RootCARotationHandler.class); + } + + @Test + public void testFinalizationStateManager() throws Exception { + runTest(FinalizationStateManager.class); + } + + @Test + public void testSecretKeyState() throws Exception { + runTest(SecretKeyState.class); + } + + @Test + public void testSequenceIdGeneratorStateManager() throws Exception { + runTest(SequenceIdGenerator.StateManager.class); + } + + @Test + public void testStatefulServiceStateManager() throws Exception { + runTest(StatefulServiceStateManager.class); + } + + @Test + public void testCertificateStore() throws Exception { + runTest(CertificateStore.class); + } +}