This is an automated email from the ASF dual-hosted git repository.

richardstartin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new aadd0cddcf make ConfigUtils testable without illegal reflective access 
(#8530)
aadd0cddcf is described below

commit aadd0cddcf5fb59286d4205fa55a9e1ff2879bc8
Author: Richard Startin <rich...@startree.ai>
AuthorDate: Thu Apr 14 08:48:03 2022 +0100

    make ConfigUtils testable without illegal reflective access (#8530)
---
 .../org/apache/pinot/spi/config/ConfigUtils.java   | 24 ++++++++-----
 .../org/apache/pinot/spi/config/Environment.java   | 30 ++++++++++++++++
 .../apache/pinot/spi/config/ConfigUtilsTest.java   | 41 +++-------------------
 3 files changed, 51 insertions(+), 44 deletions(-)

diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/config/ConfigUtils.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/config/ConfigUtils.java
index dcee78aff6..a4f34a49fe 100644
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/config/ConfigUtils.java
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/config/ConfigUtils.java
@@ -32,17 +32,24 @@ public class ConfigUtils {
   private ConfigUtils() {
   }
 
-  private static final Map<String, String> ENVIRONMENT_VARIABLES = 
System.getenv();
-
   /**
    * Apply environment variables to any given BaseJsonConfig.
    *
    * @return Config with environment variable applied.
    */
   public static <T extends BaseJsonConfig> T applyConfigWithEnvVariables(T 
config) {
+    return applyConfigWithEnvVariables(System::getenv, config);
+  }
+
+  /**
+   * Apply environment variables to any given BaseJsonConfig.
+   *
+   * @return Config with environment variable applied.
+   */
+  public static <T extends BaseJsonConfig> T 
applyConfigWithEnvVariables(Environment environment, T config) {
     JsonNode jsonNode;
     try {
-      jsonNode = applyConfigWithEnvVariables(config.toJsonNode());
+      jsonNode = applyConfigWithEnvVariables(environment, config.toJsonNode());
     } catch (RuntimeException e) {
       throw new RuntimeException(String
           .format("Unable to apply environment variables on json config class 
[%s].", config.getClass().getName()), e);
@@ -56,7 +63,7 @@ public class ConfigUtils {
     }
   }
 
-  private static JsonNode applyConfigWithEnvVariables(JsonNode jsonNode) {
+  private static JsonNode applyConfigWithEnvVariables(Environment environment, 
JsonNode jsonNode) {
     final JsonNodeType nodeType = jsonNode.getNodeType();
     switch (nodeType) {
       case OBJECT:
@@ -64,7 +71,7 @@ public class ConfigUtils {
           Iterator<Map.Entry<String, JsonNode>> iterator = jsonNode.fields();
           while (iterator.hasNext()) {
             final Map.Entry<String, JsonNode> next = iterator.next();
-            next.setValue(applyConfigWithEnvVariables(next.getValue()));
+            next.setValue(applyConfigWithEnvVariables(environment, 
next.getValue()));
           }
         }
         break;
@@ -73,7 +80,7 @@ public class ConfigUtils {
           ArrayNode arrayNode = (ArrayNode) jsonNode;
           for (int i = 0; i < arrayNode.size(); i++) {
             JsonNode arrayElement = arrayNode.get(i);
-            arrayNode.set(i, applyConfigWithEnvVariables(arrayElement));
+            arrayNode.set(i, applyConfigWithEnvVariables(environment, 
arrayElement));
           }
         }
         break;
@@ -82,8 +89,9 @@ public class ConfigUtils {
         if (field.startsWith("${") && field.endsWith("}")) {
           String[] envVarSplits = field.substring(2, field.length() - 
1).split(":", 2);
           String envVarKey = envVarSplits[0];
-          if (ENVIRONMENT_VARIABLES.containsKey(envVarKey)) {
-            return 
JsonNodeFactory.instance.textNode(ENVIRONMENT_VARIABLES.get(envVarKey));
+          String value = environment.getVariable(envVarKey);
+          if (value != null) {
+            return JsonNodeFactory.instance.textNode(value);
           } else if (envVarSplits.length > 1) {
             return JsonNodeFactory.instance.textNode(envVarSplits[1]);
           }
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/config/Environment.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/config/Environment.java
new file mode 100644
index 0000000000..efd9eb1908
--- /dev/null
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/config/Environment.java
@@ -0,0 +1,30 @@
+/**
+ * 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.pinot.spi.config;
+
+/**
+ * Encapsulates environment variables so they can be overridden for testing 
purposes.
+ */
+public interface Environment {
+  /**
+   * @param name the name of the environment variable
+   * @return an environment variable or null if not set
+   */
+  String getVariable(String name);
+}
diff --git 
a/pinot-spi/src/test/java/org/apache/pinot/spi/config/ConfigUtilsTest.java 
b/pinot-spi/src/test/java/org/apache/pinot/spi/config/ConfigUtilsTest.java
index 61d9021f39..9220cfd425 100644
--- a/pinot-spi/src/test/java/org/apache/pinot/spi/config/ConfigUtilsTest.java
+++ b/pinot-spi/src/test/java/org/apache/pinot/spi/config/ConfigUtilsTest.java
@@ -19,9 +19,7 @@
 package org.apache.pinot.spi.config;
 
 import com.google.common.collect.ImmutableMap;
-import java.lang.reflect.Field;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -40,8 +38,7 @@ import static org.testng.Assert.assertTrue;
 public class ConfigUtilsTest {
 
   @Test
-  public void testIndexing()
-      throws Exception {
+  public void testIndexing() {
     IndexingConfig indexingConfig = new IndexingConfig();
     indexingConfig.setLoadMode("${LOAD_MODE}");
     indexingConfig.setAggregateMetrics(true);
@@ -90,10 +87,11 @@ public class ConfigUtilsTest {
         .put(StreamConfigProperties.constructStreamProperty(streamType, 
"aws.secretKey"), "${AWS_SECRET_KEY}");
     indexingConfig.setStreamConfigs(streamConfigMap);
 
-    setEnv(ImmutableMap.of("LOAD_MODE", "MMAP", "AWS_ACCESS_KEY", 
"default_aws_access_key", "AWS_SECRET_KEY",
-        "default_aws_secret_key"));
+    Map<String, String> environment =
+        ImmutableMap.of("LOAD_MODE", "MMAP", "AWS_ACCESS_KEY", 
"default_aws_access_key", "AWS_SECRET_KEY",
+            "default_aws_secret_key");
 
-    indexingConfig = ConfigUtils.applyConfigWithEnvVariables(indexingConfig);
+    indexingConfig = ConfigUtils.applyConfigWithEnvVariables(environment::get, 
indexingConfig);
     assertEquals(indexingConfig.getLoadMode(), "MMAP");
     assertTrue(indexingConfig.isAggregateMetrics());
     assertEquals(indexingConfig.getInvertedIndexColumns(), 
invertedIndexColumns);
@@ -126,35 +124,6 @@ public class ConfigUtilsTest {
         StreamConfig.DEFAULT_FLUSH_THRESHOLD_SEGMENT_SIZE_BYTES);
   }
 
-  private static void setEnv(Map<String, String> newEnvVariablsMap)
-      throws Exception {
-    try {
-      Class<?> processEnvironmentClass = 
Class.forName("java.lang.ProcessEnvironment");
-      Field theEnvironmentField = 
processEnvironmentClass.getDeclaredField("theEnvironment");
-      theEnvironmentField.setAccessible(true);
-      Map<String, String> env = (Map<String, String>) 
theEnvironmentField.get(null);
-      env.putAll(newEnvVariablsMap);
-      Field theCaseInsensitiveEnvironmentField =
-          
processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
-      theCaseInsensitiveEnvironmentField.setAccessible(true);
-      Map<String, String> cienv = (Map<String, String>) 
theCaseInsensitiveEnvironmentField.get(null);
-      cienv.putAll(newEnvVariablsMap);
-    } catch (NoSuchFieldException e) {
-      Class[] classes = Collections.class.getDeclaredClasses();
-      Map<String, String> env = System.getenv();
-      for (Class cl : classes) {
-        if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
-          Field field = cl.getDeclaredField("m");
-          field.setAccessible(true);
-          Object obj = field.get(env);
-          Map<String, String> map = (Map<String, String>) obj;
-          map.clear();
-          map.putAll(newEnvVariablsMap);
-        }
-      }
-    }
-  }
-
   @Test
   public void testDefaultObfuscation() {
     Map<String, Object> map = new HashMap<>();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to