Repository: Unleash/unleash-client-java
Pull request #249 (2024-07-29 12:40:02)

Setup coveralls action instead of ancient coveralls maven plugin
Bumps dependencies to fix some security warnings. Sets up to use coverallsaction instead of outdated coveralls maven plugin

coveralls: 
[![Coverage Status](https://coveralls.io/builds/68908698/badge)](https://coveralls.io/builds/68908698)

coverage: 86.458% (-0.006%) from 86.464%
when pulling **009e51d8d0adfb9bb038f13fec24683ebe77c30d on chore/dependencyUpgrades**
into **efef58804421ebcd1eaeb8d5334222f580130dd2 on main**.


Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 66a52c77..bc82f8d0 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -5,14 +5,12 @@ on:
     branches:
       - main
 
-
-
 jobs:
   build:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        version: [8,11]
+        version: [8, 11, 17]
     steps:
       - name: Checkout
         uses: actions/checkout@v4
@@ -20,10 +18,18 @@ jobs:
         uses: actions/setup-java@v4
         with:
           java-version: ${{ matrix.version }}
-          cache: 'maven'
-          distribution: 'temurin'
+          cache: "maven"
+          distribution: "temurin"
       - name: Build, test, coverage
-        run: ./mvnw clean test jacoco:report coveralls:report
+        run: ./mvnw clean test jacoco:report
+      - name: Coveralls
+        uses: coverallsapp/github-action@v2
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          allow-empty: true
+          base-path: src/main/java
+          parallel: true
+          flag-name: run-jvm-${{ join(matrix.*, '-') }}
       - name: Notify Slack of pipeline completion
         uses: 8398a7/action-slack@v2
         with:
@@ -34,28 +40,18 @@ jobs:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           SLACK_WEBHOOK_URL: ${{ secrets.slack_webhook }}
         if: always()
-  java17:
+  finish:
+    needs: build
+    if: ${{ always() }}
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
         uses: actions/checkout@v4
-      - name: Setup Java
-        uses: actions/setup-java@v4
         with:
-          java-version: 17
-          distribution: 'temurin'
-          cache: 'maven'
-      - name: Build, test, coverage
-        run: ./mvnw clean test jacoco:report coveralls:report
-        env:
-          MAVEN_OPTS: "--add-opens java.base/java.net=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED"
-      - name: Notify Slack of pipeline completion
-        uses: 8398a7/action-slack@v2
+          fetch-depth: 0
+      - name: Coveralls Finished
+        uses: coverallsapp/github-action@v2
         with:
-          status: ${{ job.status }}
-          author_name: Github Action
-          text: Build on Java 17
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          SLACK_WEBHOOK_URL: ${{ secrets.slack_webhook }}
-        if: always()
+          parallel-finished: true
+          carryforward: run-jvm-8,run-jvm-11,run-jvm-17
+
diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml
index 42896f0b..00dedd4e 100644
--- a/.github/workflows/pull_requests.yml
+++ b/.github/workflows/pull_requests.yml
@@ -1,13 +1,12 @@
 on:
   pull_request:
 
-
 jobs:
   build:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        version: [8,11,17]
+        version: [ 8, 11, 17 ]
     steps:
       - name: Checkout
         uses: actions/checkout@v4
@@ -15,7 +14,30 @@ jobs:
         uses: actions/setup-java@v4
         with:
           java-version: ${{ matrix.version }}
-          cache: 'maven'
-          distribution: 'temurin'
+          cache: "maven"
+          distribution: "temurin"
       - name: Build, test, coverage
-        run: ./mvnw clean test jacoco:report coveralls:report
+        run: ./mvnw clean test jacoco:report
+      - name: Coveralls parallel
+        uses: coverallsapp/github-action@v2
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          allow-empty: true
+          flag-name: run-jvm-${{ join(matrix.*, '-') }}
+          parallel: true
+          base-path: src/main/java
+  finish:
+    needs: build
+    if: ${{ always() }}
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+
+      - name: Coveralls Finished
+        uses: coverallsapp/github-action@v2
+        with:
+          parallel-finished: true
+          carryforward: run-jvm-8,run-jvm-11,run-jvm-17
diff --git a/.github/workflows/release_changelog.yml b/.github/workflows/release_changelog.yml
index 1d8acdf0..01345cac 100644
--- a/.github/workflows/release_changelog.yml
+++ b/.github/workflows/release_changelog.yml
@@ -1,8 +1,8 @@
-name: 'Releases'
+name: "Releases"
 on:
   push:
     tags:
-      - 'unleash-client-java-*'
+      - "unleash-client-java-*"
 
 jobs:
   release:
@@ -22,3 +22,13 @@ jobs:
           body: ${{ steps.github_release.outputs.changelog }}
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN}}
+  finish:
+    needs: build
+    if: ${{ always() }}
+    runs-on: ubuntu-latest
+    steps:
+      - name: Coveralls Finished
+        uses: coverallsapp/github-action@v2
+        with:
+          parallel-finished: true
+          carryforward: run-jvm-8,run-jvm-11,run-jvm-17
diff --git a/pom.xml b/pom.xml
index 50c7c4a3..03a89916 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,17 +3,18 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>io.getunleash</groupId>
     <artifactId>unleash-client-java</artifactId>
-    <version>9.2.4-SNAPSHOT</version>
+    <version>9.2.5-SNAPSHOT</version>
 
     <properties>
-        <version.slf4j>2.0.9</version.slf4j>
-        <version.log4j2>2.19.0</version.log4j2>
-        <version.junit5>5.10.0</version.junit5>
-        <version.okhttp>4.10.0</version.okhttp>
+        <version.slf4j>2.0.13</version.slf4j>
+        <version.junit5>5.10.3</version.junit5>
+        <version.okhttp>4.12.0</version.okhttp>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <version.unleash.specification>5.1.5</version.unleash.specification>
         <arguments />
-        <version.jackson>2.14.3</version.jackson>
+        <version.jackson>2.17.2</version.jackson>
+        <version.logback>1.3.14</version.logback>
+        <version.gson>2.11.0</version.gson>
     </properties>
 
     <name>io.getunleash:unleash-client-java</name>
@@ -58,7 +59,7 @@
         <dependency>
             <groupId>com.google.code.gson</groupId>
             <artifactId>gson</artifactId>
-            <version>2.10.1</version>
+            <version>${version.gson}</version>
         </dependency>
         <dependency>
             <groupId>com.squareup.okhttp3</groupId>
@@ -104,20 +105,20 @@
         <dependency>
             <groupId>org.assertj</groupId>
             <artifactId>assertj-core</artifactId>
-            <version>3.24.2</version>
+            <version>3.26.3</version>
             <scope>test</scope>
         </dependency>
 
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
-            <version>4.8.0</version>
+            <version>4.8.1</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>com.github.tomakehurst</groupId>
             <artifactId>wiremock-jre8</artifactId>
-            <version>2.35.1</version>
+            <version>2.35.2</version>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -142,13 +143,13 @@
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-core</artifactId>
-            <version>1.3.5</version>
+            <version>${version.logback}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
-            <version>1.3.5</version>
+            <version>${version.logback}</version>
             <scope>test</scope>
         </dependency>
 
@@ -218,7 +219,7 @@
             <plugin>
                 <groupId>org.jacoco</groupId>
                 <artifactId>jacoco-maven-plugin</artifactId>
-                <version>0.8.8</version>
+                <version>0.8.12</version>
                 <executions>
                     <execution>
                         <id>prepare-agent</id>
@@ -228,21 +229,6 @@
                     </execution>
                 </executions>
             </plugin>
-            <plugin>
-                <groupId>org.eluder.coveralls</groupId>
-                <artifactId>coveralls-maven-plugin</artifactId>
-                <version>4.3.0</version>
-                <configuration>
-                    <repoToken>Z9wVezAubEVqnGPYkOUW031cqHPve2jBz</repoToken>
-                </configuration>
-                <dependencies>
-                    <dependency>
-                        <groupId>javax.xml.bind</groupId>
-                        <artifactId>jaxb-api</artifactId>
-                        <version>2.3.1</version>
-                    </dependency>
-                </dependencies>
-            </plugin>
 
             <!--Download client-specifications-->
             <plugin>
@@ -334,7 +320,7 @@
             <plugin>
                 <groupId>com.diffplug.spotless</groupId>
                 <artifactId>spotless-maven-plugin</artifactId>
-                <version>2.28.0</version>
+                <version>2.30.0</version>
                 <configuration>
                     <formats>
                         <format>
diff --git a/src/main/java/io/getunleash/DefaultUnleash.java b/src/main/java/io/getunleash/DefaultUnleash.java
index 7480ec1e..9abcdb9b 100644
--- a/src/main/java/io/getunleash/DefaultUnleash.java
+++ b/src/main/java/io/getunleash/DefaultUnleash.java
@@ -179,56 +179,53 @@ public class DefaultUnleash implements Unleash {
                     fallbackAction.test(toggleName, enhancedContext), defaultVariant);
         } else if (!featureToggle.isEnabled()) {
             return new FeatureEvaluationResult(false, defaultVariant);
-        } else if (featureToggle.getStrategies().isEmpty()) {
-            return new FeatureEvaluationResult(
-                    true, VariantUtil.selectVariant(featureToggle, context, defaultVariant));
-        } else {
+        } else if (isParentDependencySatisfied(featureToggle, context, fallbackAction)) {
             // Dependent toggles, no point in evaluating child strategies if our dependencies are
             // not satisfied
-            if (isParentDependencySatisfied(featureToggle, context, fallbackAction)) {
-                for (ActivationStrategy strategy : featureToggle.getStrategies()) {
-                    Strategy configuredStrategy = getStrategy(strategy.getName());
-                    if (configuredStrategy == UNKNOWN_STRATEGY) {
-                        LOGGER.warn(
-                                "Unable to find matching strategy for toggle:{} strategy:{}",
-                                toggleName,
-                                strategy.getName());
-                    }
+            if (featureToggle.getStrategies().isEmpty()) {
+                return new FeatureEvaluationResult(
+                        true, VariantUtil.selectVariant(featureToggle, context, defaultVariant));
+            }
+            for (ActivationStrategy strategy : featureToggle.getStrategies()) {
+                Strategy configuredStrategy = getStrategy(strategy.getName());
+                if (configuredStrategy == UNKNOWN_STRATEGY) {
+                    LOGGER.warn(
+                            "Unable to find matching strategy for toggle:{} strategy:{}",
+                            toggleName,
+                            strategy.getName());
+                }
 
-                    FeatureEvaluationResult result =
-                            configuredStrategy.getResult(
-                                    strategy.getParameters(),
-                                    enhancedContext,
-                                    ConstraintMerger.mergeConstraints(featureRepository, strategy),
-                                    strategy.getVariants());
-
-                    if (result.isEnabled()) {
-                        Variant variant = result.getVariant();
-                        // If strategy variant is null, look for a variant in the featureToggle
-                        if (variant == null) {
-                            variant =
-                                    VariantUtil.selectVariant(
-                                            featureToggle, context, defaultVariant);
-                        }
-                        result.setVariant(variant);
-                        return result;
+                FeatureEvaluationResult result =
+                        configuredStrategy.getResult(
+                                strategy.getParameters(),
+                                enhancedContext,
+                                ConstraintMerger.mergeConstraints(featureRepository, strategy),
+                                strategy.getVariants());
+
+                if (result.isEnabled()) {
+                    Variant variant = result.getVariant();
+                    // If strategy variant is null, look for a variant in the featureToggle
+                    if (variant == null) {
+                        variant = VariantUtil.selectVariant(featureToggle, context, defaultVariant);
                     }
+                    result.setVariant(variant);
+                    return result;
                 }
             }
-            return new FeatureEvaluationResult(false, defaultVariant);
         }
+        return new FeatureEvaluationResult(false, defaultVariant);
     }
 
     /**
      * Uses the old, statistically broken Variant seed for finding the correct variant
      *
-     * @deprecated
      * @param toggleName Name of the toggle
      * @param context The UnleashContext
      * @param fallbackAction What to do if we fail to find the toggle
      * @param defaultVariant If we can't resolve a variant, what are we returning
      * @return A wrapper containing whether the feature was enabled as well which Variant was
      *     selected
+     * @deprecated
      */
     private FeatureEvaluationResult deprecatedGetFeatureEvaluationResult(
             String toggleName,
@@ -244,46 +241,43 @@ public class DefaultUnleash implements Unleash {
                     fallbackAction.test(toggleName, enhancedContext), defaultVariant);
         } else if (!featureToggle.isEnabled()) {
             return new FeatureEvaluationResult(false, defaultVariant);
-        } else if (featureToggle.getStrategies().isEmpty()) {
-            return new FeatureEvaluationResult(
-                    true,
-                    VariantUtil.selectDeprecatedVariantHashingAlgo(
-                            featureToggle, context, defaultVariant));
-        } else {
-            // Dependent toggles, no point in evaluating child strategies if our dependencies are
-            // not satisfied
-            if (isParentDependencySatisfied(featureToggle, context, fallbackAction)) {
-                for (ActivationStrategy strategy : featureToggle.getStrategies()) {
-                    Strategy configuredStrategy = getStrategy(strategy.getName());
-                    if (configuredStrategy == UNKNOWN_STRATEGY) {
-                        LOGGER.warn(
-                                "Unable to find matching strategy for toggle:{} strategy:{}",
-                                toggleName,
-                                strategy.getName());
-                    }
+        } else if (isParentDependencySatisfied(featureToggle, context, fallbackAction)) {
+            if (featureToggle.getStrategies().isEmpty()) {
+                return new FeatureEvaluationResult(
+                        true,
+                        VariantUtil.selectDeprecatedVariantHashingAlgo(
+                                featureToggle, context, defaultVariant));
+            }
+            for (ActivationStrategy strategy : featureToggle.getStrategies()) {
+                Strategy configuredStrategy = getStrategy(strategy.getName());
+                if (configuredStrategy == UNKNOWN_STRATEGY) {
+                    LOGGER.warn(
+                            "Unable to find matching strategy for toggle:{} strategy:{}",
+                            toggleName,
+                            strategy.getName());
+                }
 
-                    FeatureEvaluationResult result =
-                            configuredStrategy.getDeprecatedHashingAlgoResult(
-                                    strategy.getParameters(),
-                                    enhancedContext,
-                                    ConstraintMerger.mergeConstraints(featureRepository, strategy),
-                                    strategy.getVariants());
-
-                    if (result.isEnabled()) {
-                        Variant variant = result.getVariant();
-                        // If strategy variant is null, look for a variant in the featureToggle
-                        if (variant == null) {
-                            variant =
-                                    VariantUtil.selectDeprecatedVariantHashingAlgo(
-                                            featureToggle, context, defaultVariant);
-                        }
-                        result.setVariant(variant);
-                        return result;
+                FeatureEvaluationResult result =
+                        configuredStrategy.getDeprecatedHashingAlgoResult(
+                                strategy.getParameters(),
+                                enhancedContext,
+                                ConstraintMerger.mergeConstraints(featureRepository, strategy),
+                                strategy.getVariants());
+
+                if (result.isEnabled()) {
+                    Variant variant = result.getVariant();
+                    // If strategy variant is null, look for a variant in the featureToggle
+                    if (variant == null) {
+                        variant =
+                                VariantUtil.selectDeprecatedVariantHashingAlgo(
+                                        featureToggle, context, defaultVariant);
                     }
+                    result.setVariant(variant);
+                    return result;
                 }
             }
-            return new FeatureEvaluationResult(false, defaultVariant);
         }
+        return new FeatureEvaluationResult(false, defaultVariant);
     }
 
     private boolean isParentDependencySatisfied(
@@ -393,10 +387,10 @@ public class DefaultUnleash implements Unleash {
     /**
      * Uses the old, statistically broken Variant seed for finding the correct variant
      *
-     * @deprecated
      * @param toggleName
      * @param context
      * @return
+     * @deprecated
      */
     @Override
     public Variant deprecatedGetVariant(String toggleName, UnleashContext context) {
@@ -406,11 +400,11 @@ public class DefaultUnleash implements Unleash {
     /**
      * Uses the old, statistically broken Variant seed for finding the correct variant
      *
-     * @deprecated
      * @param toggleName
      * @param context
      * @param defaultValue
      * @return
+     * @deprecated
      */
     @Override
     public Variant deprecatedGetVariant(
@@ -437,9 +431,9 @@ public class DefaultUnleash implements Unleash {
     /**
      * Uses the old, statistically broken Variant seed for finding the correct variant
      *
-     * @deprecated
      * @param toggleName
      * @return
+     * @deprecated
      */
     @Override
     public Variant deprecatedGetVariant(String toggleName) {
@@ -449,10 +443,10 @@ public class DefaultUnleash implements Unleash {
     /**
      * Uses the old, statistically broken Variant seed for finding the correct variant
      *
-     * @deprecated
      * @param toggleName
      * @param defaultValue
      * @return
+     * @deprecated
      */
     @Override
     public Variant deprecatedGetVariant(String toggleName, Variant defaultValue) {
diff --git a/src/main/java/io/getunleash/util/ConstraintMerger.java b/src/main/java/io/getunleash/util/ConstraintMerger.java
index 7440decb..28db759e 100644
--- a/src/main/java/io/getunleash/util/ConstraintMerger.java
+++ b/src/main/java/io/getunleash/util/ConstraintMerger.java
@@ -17,8 +17,7 @@ public class ConstraintMerger {
                         Optional.ofNullable(strategy.getConstraints())
                                 .orElseGet(Collections::emptyList),
                         Optional.ofNullable(strategy.getSegments())
-                                .orElseGet(Collections::emptyList)
-                                .stream()
+                                .orElseGet(Collections::emptyList).stream()
                                 .map(repository::getSegment)
                                 .map(s -> s == null ? DENY_SEGMENT : s)
                                 .map(Segment::getConstraints)


Test patch:
diff --git a/src/test/java/io/getunleash/DependentFeatureToggleTest.java b/src/test/java/io/getunleash/DependentFeatureToggleTest.java
index 84761aa9..194bf671 100644
--- a/src/test/java/io/getunleash/DependentFeatureToggleTest.java
+++ b/src/test/java/io/getunleash/DependentFeatureToggleTest.java
@@ -176,4 +176,30 @@ public class DependentFeatureToggleTest {
         when(featureRepository.getToggle(parentName)).thenReturn(parent);
         assertThat(sut.isEnabled(childName, UnleashContext.builder().build())).isFalse();
     }
+
+    @Test
+    public void childIsDisabledWhenChildDoesNotHaveStrategiesAndParentIsDisabled() {
+        FeatureToggle parent =
+                new FeatureToggle(
+                        "parent", false, singletonList(new ActivationStrategy("default", null)));
+        FeatureDependency childDependsOnParent = new FeatureDependency("parant", true, emptyList());
+        FeatureToggle child =
+                new FeatureToggle(
+                        "child",
+                        true,
+                        emptyList(),
+                        emptyList(),
+                        true,
+                        singletonList(childDependsOnParent));
+        when(featureRepository.getToggle("child")).thenReturn(child);
+        when(featureRepository.getToggle("parent")).thenReturn(parent);
+        assertThat(sut.isEnabled("child", UnleashContext.builder().build())).isFalse();
+    }
+
+    @Test
+    public void shouldBeEnabledWhenMissingStrategies() {
+        FeatureToggle c = new FeatureToggle("c", true, emptyList());
+        when(featureRepository.getToggle("c")).thenReturn(c);
+        assertThat(sut.isEnabled("c", UnleashContext.builder().build())).isTrue();
+    }
 }
diff --git a/src/test/java/io/getunleash/util/IpAddressMatcherTest.java b/src/test/java/io/getunleash/util/IpAddressMatcherTest.java
index 8b2bf5cb..f9d48f37 100644
--- a/src/test/java/io/getunleash/util/IpAddressMatcherTest.java
+++ b/src/test/java/io/getunleash/util/IpAddressMatcherTest.java
@@ -19,9 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 import org.junit.jupiter.api.Test;
 
-/**
- * @author Luke Taylor
- */
+/** @author Luke Taylor */
 class IpAddressMatcherTest {
     private final IpAddressMatcher v6matcher = new IpAddressMatcher("fe80::21f:5bff:fe33:bd68");
     private final IpAddressMatcher v4matcher = new IpAddressMatcher("192.168.1.104");