diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml index 5a5c9f3c..e8866bc6 100644 --- a/.github/workflows/build-check.yml +++ b/.github/workflows/build-check.yml @@ -15,11 +15,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Set up JDK 8 - uses: actions/setup-java@v1 - with: - java-version: '1.8' - cache: maven - - name: Build with Maven - run: mvn -B clean package --file pom.xml + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: 17 + cache: maven + distribution: 'temurin' + - name: Build with Maven + run: mvn -B clean package --file pom.xml \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f76813fc..a758d08b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ # Changelog All notable changes to this project will be documented in this file. +## [1.0-RC15] +- Moved discovery bundle from https://github.com/appform-io/dropwizard-service-discovery. +- Updated to dropwizard version 2.1.10 : BOM update. +- Upgraded to java version 17 with release in 11 +- Removed com.fasterxml and introduced dropwizard-jackson for the jackson bindings. +- Upgraded to junit 5 and fixed the necessary tests including wiremock versions and tests. +- Upgraded the curator framework version +- Done sonar fixes after the java version upgrade + ## [1.0-RC14] - When the Collection of Services is empty the monitor should gracefully return [PR](https://github.com/appform-io/ranger/pull/27) diff --git a/pom.xml b/pom.xml index 018c326b..b14a9849 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ io.appform.ranger ranger pom - 1.0-RC14 + 1.0-RC15 Ranger https://github.com/appform-io/ranger Service Discovery for Java @@ -27,6 +27,7 @@ ranger-http-model ranger-http-server-bundle ranger-zk-server-bundle + ranger-discovery-bundle @@ -82,26 +83,45 @@ UTF-8 31.0.1-jre - 5.1.0 - 2.13.1 + 5.5.0 1.7.32 3.8.0 - 1.8 + 17 + 11 1.18.22 3.0.1u2 - 4.13.2 + 5.8.2 4.1.1 2.0.0 4.9.3 - 2.27.2 + 3.3.1 4.2.0 - 1.2.10 + 2.1.10 + + + + org.junit + junit-bom + ${junit.jupiter.version} + pom + import + + + io.dropwizard + dropwizard-bom + pom + import + ${dropwizard.version} + + + + org.projectlombok @@ -124,32 +144,25 @@ slf4j-api ${slf4j.version} - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - test + io.dropwizard + dropwizard-jackson - ch.qos.logback - logback-classic - ${logback.version} + org.junit.jupiter + junit-jupiter-api test - - junit - junit - ${junit.version} + org.junit.jupiter + junit-jupiter-engine + test - com.github.rholder guava-retrying ${guava-retrying.version} - org.awaitility awaitility @@ -167,12 +180,18 @@ ${java.version} ${java.version} + ${java.release.version} + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + org.jacoco jacoco-maven-plugin - 0.8.6 + 0.8.8 @@ -206,7 +225,10 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.3.0 + 3.6.3 + + all,-missing + attach-javadocs @@ -265,6 +287,20 @@ + + + add-java-open-options-for-jdk16+ + + [16,) + + + + --add-opens java.base/java.net=ALL-UNNAMED + --add-opens java.base/sun.net=ALL-UNNAMED + + + diff --git a/ranger-client/pom.xml b/ranger-client/pom.xml index caf0f078..727e9c1b 100644 --- a/ranger-client/pom.xml +++ b/ranger-client/pom.xml @@ -5,7 +5,7 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 @@ -23,11 +23,6 @@ ${project.version} test-jar - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - diff --git a/ranger-client/src/test/java/io/appform/ranger/client/AbstractRangerHubClientTest.java b/ranger-client/src/test/java/io/appform/ranger/client/AbstractRangerHubClientTest.java index d027f463..b741b627 100644 --- a/ranger-client/src/test/java/io/appform/ranger/client/AbstractRangerHubClientTest.java +++ b/ranger-client/src/test/java/io/appform/ranger/client/AbstractRangerHubClientTest.java @@ -20,42 +20,41 @@ import io.appform.ranger.core.utils.RangerTestUtils; import lombok.extern.slf4j.Slf4j; import lombok.val; -import lombok.var; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; @Slf4j -public class AbstractRangerHubClientTest { +class AbstractRangerHubClientTest { private static final Service service = RangerTestUtils.getService("test-ns", "test-s"); @Test - public void testAbstractHubClient() { + void testAbstractHubClient() { val testAbstractHub = RangerHubTestUtils.getTestHub(); testAbstractHub.start(); var node = testAbstractHub.getNode(service).orElse(null); - Assert.assertNotNull(node); - Assert.assertTrue(node.getHost().equalsIgnoreCase("localhost")); - Assert.assertEquals(9200, node.getPort()); - Assert.assertEquals(1, node.getNodeData().getShardId()); - Assert.assertFalse(testAbstractHub.getNode(RangerTestUtils.getService("test", "test")).isPresent()); - Assert.assertFalse(testAbstractHub.getNode(service, nodeData -> nodeData.getShardId() == 2).isPresent()); - Assert.assertFalse(testAbstractHub.getNode(RangerTestUtils.getService("test", "test"), nodeData -> nodeData.getShardId() == 1).isPresent()); + Assertions.assertNotNull(node); + Assertions.assertTrue(node.getHost().equalsIgnoreCase("localhost")); + Assertions.assertEquals(9200, node.getPort()); + Assertions.assertEquals(1, node.getNodeData().getShardId()); + Assertions.assertFalse(testAbstractHub.getNode(RangerTestUtils.getService("test", "test")).isPresent()); + Assertions.assertFalse(testAbstractHub.getNode(service, nodeData -> nodeData.getShardId() == 2).isPresent()); + Assertions.assertFalse(testAbstractHub.getNode(RangerTestUtils.getService("test", "test"), nodeData -> nodeData.getShardId() == 1).isPresent()); testAbstractHub.stop(); } @Test - public void testAbstractHubClientWithDataSource() { + void testAbstractHubClientWithDataSource() { val testAbstractHub = RangerHubTestUtils.getTestHubWithDataSource(); testAbstractHub.start(); - var node = testAbstractHub.getNode(service).orElse(null); - Assert.assertNotNull(node); - Assert.assertTrue(node.getHost().equalsIgnoreCase("localhost")); - Assert.assertEquals(9200, node.getPort()); - Assert.assertEquals(1, node.getNodeData().getShardId()); - Assert.assertFalse(testAbstractHub.getNode(RangerTestUtils.getService("test", "test")).isPresent()); - Assert.assertFalse(testAbstractHub.getNode(service, nodeData -> nodeData.getShardId() == 2).isPresent()); - Assert.assertFalse(testAbstractHub.getNode(RangerTestUtils.getService("test", "test"), nodeData -> nodeData.getShardId() == 1).isPresent()); + val node = testAbstractHub.getNode(service).orElse(null); + Assertions.assertNotNull(node); + Assertions.assertTrue(node.getHost().equalsIgnoreCase("localhost")); + Assertions.assertEquals(9200, node.getPort()); + Assertions.assertEquals(1, node.getNodeData().getShardId()); + Assertions.assertFalse(testAbstractHub.getNode(RangerTestUtils.getService("test", "test")).isPresent()); + Assertions.assertFalse(testAbstractHub.getNode(service, nodeData -> nodeData.getShardId() == 2).isPresent()); + Assertions.assertFalse(testAbstractHub.getNode(RangerTestUtils.getService("test", "test"), nodeData -> nodeData.getShardId() == 1).isPresent()); testAbstractHub.stop(); } } diff --git a/ranger-client/src/test/java/io/appform/ranger/client/CriteriaUtilsTest.java b/ranger-client/src/test/java/io/appform/ranger/client/CriteriaUtilsTest.java index 457b20dd..31a6b425 100644 --- a/ranger-client/src/test/java/io/appform/ranger/client/CriteriaUtilsTest.java +++ b/ranger-client/src/test/java/io/appform/ranger/client/CriteriaUtilsTest.java @@ -18,27 +18,26 @@ import io.appform.ranger.client.utils.CriteriaUtils; import io.appform.ranger.core.units.TestNodeData; import lombok.val; -import lombok.var; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.util.function.Predicate; -public class CriteriaUtilsTest { +class CriteriaUtilsTest { private Predicate getCriteria(int shardId){ return testNodeData -> testNodeData.getShardId() == shardId; } @Test - public void testGetCriteria(){ + void testGetCriteria(){ val initialCriteria = getCriteria(1); val argCriteria = getCriteria(2); var mergedCriteria = CriteriaUtils.getCriteria(true, initialCriteria, argCriteria); - Assert.assertFalse(mergedCriteria.test(TestNodeData.builder().shardId(1).build())); - Assert.assertFalse(mergedCriteria.test(TestNodeData.builder().shardId(2).build())); + Assertions.assertFalse(mergedCriteria.test(TestNodeData.builder().shardId(1).build())); + Assertions.assertFalse(mergedCriteria.test(TestNodeData.builder().shardId(2).build())); mergedCriteria = CriteriaUtils.getCriteria(false, initialCriteria, argCriteria); - Assert.assertFalse(mergedCriteria.test(TestNodeData.builder().shardId(1).build())); - Assert.assertTrue(mergedCriteria.test(TestNodeData.builder().shardId(2).build())); + Assertions.assertFalse(mergedCriteria.test(TestNodeData.builder().shardId(1).build())); + Assertions.assertTrue(mergedCriteria.test(TestNodeData.builder().shardId(2).build())); } } diff --git a/ranger-client/src/test/java/io/appform/ranger/client/stubs/TestServiceFinderFactory.java b/ranger-client/src/test/java/io/appform/ranger/client/stubs/TestServiceFinderFactory.java index 11068e9b..c682e992 100644 --- a/ranger-client/src/test/java/io/appform/ranger/client/stubs/TestServiceFinderFactory.java +++ b/ranger-client/src/test/java/io/appform/ranger/client/stubs/TestServiceFinderFactory.java @@ -30,7 +30,8 @@ public ServiceFinder> build val finder = new TestSimpleUnshardedServiceFinder() .withNamespace(service.getNamespace()) .withServiceName(service.getServiceName()) - .withDeserializer(new Deserializer() {}) + .withDeserializer(new Deserializer<>() { + }) .build(); finder.start(); return finder; diff --git a/ranger-core/pom.xml b/ranger-core/pom.xml index 1a1931f5..634ab4a9 100644 --- a/ranger-core/pom.xml +++ b/ranger-core/pom.xml @@ -5,7 +5,7 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 diff --git a/ranger-core/src/main/java/io/appform/ranger/core/finder/serviceregistry/MapBasedServiceRegistry.java b/ranger-core/src/main/java/io/appform/ranger/core/finder/serviceregistry/MapBasedServiceRegistry.java index 95f177f1..5204ba93 100644 --- a/ranger-core/src/main/java/io/appform/ranger/core/finder/serviceregistry/MapBasedServiceRegistry.java +++ b/ranger-core/src/main/java/io/appform/ranger/core/finder/serviceregistry/MapBasedServiceRegistry.java @@ -16,7 +16,6 @@ package io.appform.ranger.core.finder.serviceregistry; import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ListMultimap; import io.appform.ranger.core.model.Service; @@ -46,7 +45,7 @@ public ListMultimap> nodes() { @Override public List> nodeList() { val nodeList = nodes.get(); - return null == nodeList ? ImmutableList.of() : new ArrayList<>(nodeList.values()); + return null == nodeList ? List.of() : new ArrayList<>(nodeList.values()); } @Override diff --git a/ranger-core/src/main/java/io/appform/ranger/core/finder/serviceregistry/ServiceRegistryUpdater.java b/ranger-core/src/main/java/io/appform/ranger/core/finder/serviceregistry/ServiceRegistryUpdater.java index 38790182..63756741 100644 --- a/ranger-core/src/main/java/io/appform/ranger/core/finder/serviceregistry/ServiceRegistryUpdater.java +++ b/ranger-core/src/main/java/io/appform/ranger/core/finder/serviceregistry/ServiceRegistryUpdater.java @@ -25,7 +25,6 @@ import io.appform.ranger.core.util.Exceptions; import lombok.extern.slf4j.Slf4j; import lombok.val; -import lombok.var; import java.util.List; import java.util.concurrent.ExecutorService; @@ -67,7 +66,7 @@ public void start() { log.info("Started updater for [{}]. Triggering initial update.", serviceName); checkForUpdate(null); log.info("Waiting for initial update to complete for: {}", serviceName); - var stopwatch = Stopwatch.createStarted(); + val stopwatch = Stopwatch.createStarted(); try { RetryerBuilder.newBuilder() .retryIfResult(r -> null == r || !r) diff --git a/ranger-core/src/main/java/io/appform/ranger/core/healthservice/monitor/IsolatedHealthMonitor.java b/ranger-core/src/main/java/io/appform/ranger/core/healthservice/monitor/IsolatedHealthMonitor.java index 0a84a0fb..8ac7a2df 100644 --- a/ranger-core/src/main/java/io/appform/ranger/core/healthservice/monitor/IsolatedHealthMonitor.java +++ b/ranger-core/src/main/java/io/appform/ranger/core/healthservice/monitor/IsolatedHealthMonitor.java @@ -20,6 +20,7 @@ import io.appform.ranger.core.healthservice.monitor.sample.CountMonitor; import io.appform.ranger.core.healthservice.monitor.sample.PingCheckMonitor; import io.appform.ranger.core.healthservice.monitor.sample.RotationStatusMonitor; +import lombok.Getter; import java.util.Date; import java.util.concurrent.atomic.AtomicBoolean; @@ -36,6 +37,7 @@ public abstract class IsolatedHealthMonitor implements Runnable, Monitor { /* name of the monitor */ + @Getter protected String name; /* reference of the health that this monitor tracks */ @@ -45,6 +47,7 @@ public abstract class IsolatedHealthMonitor implements Runnable, Monitor { private Date lastStatusUpdateTime; /* how often should this monitor run */ + @Getter private final TimeEntity runInterval; /* reference to if this monitor is disabled or not (default: false) */ @@ -102,18 +105,10 @@ public void enable() { disabled.set(false); } - public TimeEntity getRunInterval() { - return runInterval; - } - public T getHealthStatus() { return healthStatus.get(); } - public String getName() { - return name; - } - @Override public boolean isDisabled() { return disabled.get(); diff --git a/ranger-core/src/test/java/io/appform/ranger/core/finder/SimpleShardFinderTest.java b/ranger-core/src/test/java/io/appform/ranger/core/finder/SimpleShardFinderTest.java index c547fe7c..85563cba 100644 --- a/ranger-core/src/test/java/io/appform/ranger/core/finder/SimpleShardFinderTest.java +++ b/ranger-core/src/test/java/io/appform/ranger/core/finder/SimpleShardFinderTest.java @@ -23,14 +23,14 @@ import io.appform.ranger.core.utils.RangerTestUtils; import io.appform.ranger.core.utils.RegistryTestUtils; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.util.Collections; import java.util.List; import java.util.function.Predicate; -public class SimpleShardFinderTest { +class SimpleShardFinderTest { static class TestSimpleShardSelector implements ShardSelector> { @@ -41,7 +41,7 @@ public List> nodes(Predicate criteria, MapBasedServiceRegistry } @Test - public void testSimpleShardedFinder() { + void testSimpleShardedFinder() { val serviceRegistry = RegistryTestUtils.getServiceRegistry(); val shardSelector = new TestSimpleShardSelector(); val roundRobinServiceNodeSelector = new RoundRobinServiceNodeSelector(); @@ -49,6 +49,6 @@ public void testSimpleShardedFinder() { serviceRegistry, shardSelector, roundRobinServiceNodeSelector); val testNodeDataServiceNode = simpleShardedFinder.get( RangerTestUtils.getCriteria(2)); - Assert.assertFalse(testNodeDataServiceNode.isPresent()); + Assertions.assertFalse(testNodeDataServiceNode.isPresent()); } } diff --git a/ranger-core/src/test/java/io/appform/ranger/core/finder/UnshardedClusterFinderTest.java b/ranger-core/src/test/java/io/appform/ranger/core/finder/UnshardedClusterFinderTest.java index f9a185eb..4b5f214b 100644 --- a/ranger-core/src/test/java/io/appform/ranger/core/finder/UnshardedClusterFinderTest.java +++ b/ranger-core/src/test/java/io/appform/ranger/core/finder/UnshardedClusterFinderTest.java @@ -22,12 +22,12 @@ import io.appform.ranger.core.utils.RangerTestUtils; import io.appform.ranger.core.utils.RegistryTestUtils; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.util.List; -public class UnshardedClusterFinderTest { +class UnshardedClusterFinderTest { static class TestUnshardedNodeSelector implements ServiceNodeSelector { @@ -37,7 +37,7 @@ public ServiceNode select(List> serviceN } } @Test - public void unshardedClusterFinder(){ + void unshardedClusterFinder(){ val unshardedRegistry = RegistryTestUtils.getUnshardedRegistry(); val shardSelector = new ListShardSelector(); val simpleUnshardedServiceFinder = new SimpleUnshardedServiceFinder<>( @@ -46,7 +46,7 @@ public void unshardedClusterFinder(){ new TestUnshardedNodeSelector() ); val serviceNode = simpleUnshardedServiceFinder.get(RangerTestUtils.getCriteria(1)); - Assert.assertTrue(serviceNode.isPresent()); - Assert.assertEquals("localhost-1", serviceNode.get().getHost()); + Assertions.assertTrue(serviceNode.isPresent()); + Assertions.assertEquals("localhost-1", serviceNode.get().getHost()); } } diff --git a/ranger-core/src/test/java/io/appform/ranger/core/finder/nodeselector/RoundRobinServiceNodeSelectorTest.java b/ranger-core/src/test/java/io/appform/ranger/core/finder/nodeselector/RoundRobinServiceNodeSelectorTest.java index 57e005f6..f563f00d 100644 --- a/ranger-core/src/test/java/io/appform/ranger/core/finder/nodeselector/RoundRobinServiceNodeSelectorTest.java +++ b/ranger-core/src/test/java/io/appform/ranger/core/finder/nodeselector/RoundRobinServiceNodeSelectorTest.java @@ -18,21 +18,21 @@ import io.appform.ranger.core.model.ServiceNode; import io.appform.ranger.core.units.TestNodeData; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.util.ArrayList; -public class RoundRobinServiceNodeSelectorTest { +class RoundRobinServiceNodeSelectorTest { @Test - public void testRandomNodeSelector(){ + void testRandomNodeSelector(){ val roundRobinSelector = new RoundRobinServiceNodeSelector(); val serviceNodes = new ArrayList>(); serviceNodes.add(ServiceNode.builder().host("localhost-1").port(9000).nodeData(TestNodeData.builder().shardId(1).build()).build()); serviceNodes.add(ServiceNode.builder().host("localhost-2").port(9001).nodeData(TestNodeData.builder().shardId(2).build()).build()); serviceNodes.add(ServiceNode.builder().host("localhost-3").port(9002).nodeData(TestNodeData.builder().shardId(3).build()).build()); - Assert.assertEquals("localhost-2", roundRobinSelector.select(serviceNodes).getHost()); - Assert.assertEquals("localhost-3", roundRobinSelector.select(serviceNodes).getHost()); - Assert.assertEquals("localhost-1", roundRobinSelector.select(serviceNodes).getHost()); + Assertions.assertEquals("localhost-2", roundRobinSelector.select(serviceNodes).getHost()); + Assertions.assertEquals("localhost-3", roundRobinSelector.select(serviceNodes).getHost()); + Assertions.assertEquals("localhost-1", roundRobinSelector.select(serviceNodes).getHost()); } } diff --git a/ranger-core/src/test/java/io/appform/ranger/core/finder/serviceregistry/MapBasedServiceRegistryTest.java b/ranger-core/src/test/java/io/appform/ranger/core/finder/serviceregistry/MapBasedServiceRegistryTest.java index 667d7731..6aee37db 100644 --- a/ranger-core/src/test/java/io/appform/ranger/core/finder/serviceregistry/MapBasedServiceRegistryTest.java +++ b/ranger-core/src/test/java/io/appform/ranger/core/finder/serviceregistry/MapBasedServiceRegistryTest.java @@ -20,20 +20,20 @@ import io.appform.ranger.core.utils.RangerTestUtils; import io.appform.ranger.core.utils.RegistryTestUtils; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class MapBasedServiceRegistryTest { +class MapBasedServiceRegistryTest { @Test - public void testMapBasedServiceRegistryWithMatchingShardSelector(){ + void testMapBasedServiceRegistryWithMatchingShardSelector(){ val serviceRegistry = RegistryTestUtils.getServiceRegistry(); - Assert.assertTrue(null != serviceRegistry.nodes() && !serviceRegistry.nodes().isEmpty()); + Assertions.assertTrue(null != serviceRegistry.nodes() && !serviceRegistry.nodes().isEmpty()); val matchingShardSelector = new MatchingShardSelector(); val nodes = matchingShardSelector.nodes( RangerTestUtils.getCriteria(1), serviceRegistry); - Assert.assertFalse(nodes.isEmpty()); - Assert.assertEquals("localhost-1", nodes.get(0).getHost()); + Assertions.assertFalse(nodes.isEmpty()); + Assertions.assertEquals("localhost-1", nodes.get(0).getHost()); } } diff --git a/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/ListShardSelectorTest.java b/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/ListShardSelectorTest.java index 8355f9b1..6c867d37 100644 --- a/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/ListShardSelectorTest.java +++ b/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/ListShardSelectorTest.java @@ -19,17 +19,17 @@ import io.appform.ranger.core.utils.RangerTestUtils; import io.appform.ranger.core.utils.RegistryTestUtils; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class ListShardSelectorTest { +class ListShardSelectorTest { @Test - public void testListShardSelector(){ + void testListShardSelector(){ val serviceRegistry = RegistryTestUtils.getUnshardedRegistry(); val shardSelector = new ListShardSelector(); val nodes = shardSelector.nodes(RangerTestUtils.getCriteria(1), serviceRegistry); - Assert.assertFalse(nodes.isEmpty()); - Assert.assertEquals("localhost-1", nodes.get(0).getHost()); + Assertions.assertFalse(nodes.isEmpty()); + Assertions.assertEquals("localhost-1", nodes.get(0).getHost()); } } diff --git a/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/MatchingShardSelectorTest.java b/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/MatchingShardSelectorTest.java index 6fee777f..9c8c7d12 100644 --- a/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/MatchingShardSelectorTest.java +++ b/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/MatchingShardSelectorTest.java @@ -19,18 +19,18 @@ import io.appform.ranger.core.utils.RangerTestUtils; import io.appform.ranger.core.utils.RegistryTestUtils; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class MatchingShardSelectorTest { +class MatchingShardSelectorTest { @Test - public void testMatchingShardSelector(){ + void testMatchingShardSelector(){ val serviceRegistry = RegistryTestUtils.getServiceRegistry(); val shardSelector = new MatchingShardSelector(); val nodes = shardSelector.nodes( RangerTestUtils.getCriteria(1), serviceRegistry); - Assert.assertFalse(nodes.isEmpty()); - Assert.assertEquals("localhost-1", nodes.get(0).getHost()); + Assertions.assertFalse(nodes.isEmpty()); + Assertions.assertEquals("localhost-1", nodes.get(0).getHost()); } } diff --git a/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/NoopShardSelectorTest.java b/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/NoopShardSelectorTest.java index 858b5461..c4b89f11 100644 --- a/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/NoopShardSelectorTest.java +++ b/ranger-core/src/test/java/io/appform/ranger/core/finder/shardselector/NoopShardSelectorTest.java @@ -4,17 +4,17 @@ import io.appform.ranger.core.utils.RangerTestUtils; import io.appform.ranger.core.utils.RegistryTestUtils; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class NoopShardSelectorTest { +class NoopShardSelectorTest { @Test - public void testNoOpShardSelector(){ + void testNoOpShardSelector(){ val serviceRegistry = RegistryTestUtils.getUnshardedRegistry(); val shardSelector = new NoopShardSelector(); val nodes = shardSelector.nodes(RangerTestUtils.getCriteria(1), serviceRegistry); - Assert.assertFalse(nodes.isEmpty()); - Assert.assertEquals("localhost-1", nodes.get(0).getHost()); + Assertions.assertFalse(nodes.isEmpty()); + Assertions.assertEquals("localhost-1", nodes.get(0).getHost()); } } diff --git a/ranger-core/src/test/java/io/appform/ranger/core/finderhub/ServiceFinderHubTest.java b/ranger-core/src/test/java/io/appform/ranger/core/finderhub/ServiceFinderHubTest.java index 1ca9fcb2..cc76b11c 100644 --- a/ranger-core/src/test/java/io/appform/ranger/core/finderhub/ServiceFinderHubTest.java +++ b/ranger-core/src/test/java/io/appform/ranger/core/finderhub/ServiceFinderHubTest.java @@ -12,14 +12,14 @@ import io.appform.ranger.core.units.TestNodeData; import java.util.Optional; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.HashSet; import java.util.List; -public class ServiceFinderHubTest { +class ServiceFinderHubTest { private final ServiceFinderHub> serviceFinderHub = new ServiceFinderHub<>( new DynamicDataSource(Lists.newArrayList(new Service("NS", "PRE_REGISTERED_SERVICE"))), @@ -32,38 +32,38 @@ public class ServiceFinderHubTest { .build()); @Test - public void testDynamicServiceAddition() { + void testDynamicServiceAddition() { serviceFinderHub.start(); val preRegisteredServiceFinder = serviceFinderHub.finder(new Service("NS", "PRE_REGISTERED_SERVICE")) .orElseThrow(() -> new IllegalStateException("Finder should be present")); val node = preRegisteredServiceFinder.get(null, (criteria, serviceRegistry) -> serviceRegistry.nodeList()); - Assert.assertTrue(node.isPresent()); - Assert.assertEquals("HOST", node.get().getHost()); - Assert.assertEquals(0, node.get().getPort()); + Assertions.assertTrue(node.isPresent()); + Assertions.assertEquals("HOST", node.get().getHost()); + Assertions.assertEquals(0, node.get().getPort()); serviceFinderHub.buildFinder(new Service("NS", "SERVICE")).join(); val dynamicServiceFinder = serviceFinderHub.finder(new Service("NS", "SERVICE")) .orElseThrow(() -> new IllegalStateException("Finder should be present")); val dynamicServiceNode = dynamicServiceFinder.get(null, (criteria, serviceRegistry) -> serviceRegistry.nodeList()); - Assert.assertTrue(dynamicServiceNode.isPresent()); - Assert.assertEquals("HOST", dynamicServiceNode.get().getHost()); - Assert.assertEquals(0, dynamicServiceNode.get().getPort()); + Assertions.assertTrue(dynamicServiceNode.isPresent()); + Assertions.assertEquals("HOST", dynamicServiceNode.get().getHost()); + Assertions.assertEquals(0, dynamicServiceNode.get().getPort()); } @Test - public void testDynamicServiceAdditionAsync() throws InterruptedException { + void testDynamicServiceAdditionAsync() throws InterruptedException { serviceFinderHub.start(); serviceFinderHub.buildFinder(new Service("NS", "SERVICE_NAME")); val finderOpt = serviceFinderHub.finder(new Service("NS", "SERVICE_NAME")); - Assert.assertFalse("Finders will not be availbale immediately", finderOpt.isPresent()); + Assertions.assertFalse(finderOpt.isPresent(), "Finders will not be availbale immediately"); Thread.sleep(1000); val finderAfterWaitOpt = serviceFinderHub.finder(new Service("NS", "SERVICE_NAME")); - Assert.assertTrue("Finders should be availble after some time", finderAfterWaitOpt.isPresent()); + Assertions.assertTrue(finderAfterWaitOpt.isPresent(), "Finders should be availble after some time"); } @Test - public void testDynamicServiceAdditionWithNonDynamicDataSource() { + void testDynamicServiceAdditionWithNonDynamicDataSource() { val serviceFinderHub = new ServiceFinderHub<>(new StaticDataSource(new HashSet<>()), service -> new TestServiceFinderBuilder() .withNamespace(service.getNamespace()) @@ -75,11 +75,10 @@ public void testDynamicServiceAdditionWithNonDynamicDataSource() { try { val future = serviceFinderHub.buildFinder(new Service("NS", "SERVICE_NAME")); future.join(); - Assert.fail("Exception should have been thrown"); + Assertions.fail("Exception should have been thrown"); } catch (Exception exception) { - Assert.assertTrue("Unsupported exception should be thrown", exception instanceof UnsupportedOperationException); + Assertions.assertTrue(exception instanceof UnsupportedOperationException, "Unsupported exception should be thrown"); } - } private static class TestServiceFinderBuilder extends BaseServiceFinderBuilder, ServiceFinder>, TestServiceFinderBuilder, Deserializer> { diff --git a/ranger-core/src/test/java/io/appform/ranger/core/serviceprovider/ServiceProviderTest.java b/ranger-core/src/test/java/io/appform/ranger/core/serviceprovider/ServiceProviderTest.java index afb1c2bf..cff88392 100644 --- a/ranger-core/src/test/java/io/appform/ranger/core/serviceprovider/ServiceProviderTest.java +++ b/ranger-core/src/test/java/io/appform/ranger/core/serviceprovider/ServiceProviderTest.java @@ -24,10 +24,10 @@ import io.appform.ranger.core.model.ServiceNode; import io.appform.ranger.core.units.TestNodeData; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class ServiceProviderTest { +class ServiceProviderTest { static TestNodeData testNodeData = null; @@ -98,29 +98,29 @@ protected NodeDataSink> dataSink(Service service) { } } - @Test(expected = NullPointerException.class) - public void testInvalidServiceProvider(){ - new TestServiceProviderBuilder<>() + @Test + void testInvalidServiceProvider() { + Assertions.assertThrowsExactly(NullPointerException.class, () -> new TestServiceProviderBuilder<>() .withServiceName("test-service") .withNamespace("test") .withHostname("localhost-1") .withPort(9000) - .build(); + .build()); } - @Test(expected = IllegalArgumentException.class) - public void testInvalidServiceProviderNoHealthCheck(){ - new TestServiceProviderBuilder<>() + @Test + void testInvalidServiceProviderNoHealthCheck() { + Assertions.assertThrowsExactly(IllegalArgumentException.class, () -> new TestServiceProviderBuilder<>() .withServiceName("test-service") .withNamespace("test") .withHostname("localhost-1") .withPort(9000) .withSerializer(new TestSerializerImpl()) - .build(); + .build()); } @Test - public void testBuildServiceProvider(){ + void testBuildServiceProvider() { val testProvider = new TestServiceProviderBuilder<>() .withServiceName("test-service") .withNamespace("test") @@ -132,8 +132,8 @@ public void testBuildServiceProvider(){ .withHealthUpdateIntervalMs(1000) .build(); testProvider.start(); - Assert.assertNotNull(testNodeData); - Assert.assertEquals(1, testNodeData.getShardId()); + Assertions.assertNotNull(testNodeData); + Assertions.assertEquals(1, testNodeData.getShardId()); } } diff --git a/ranger-discovery-bundle/README.md b/ranger-discovery-bundle/README.md new file mode 100644 index 00000000..e69de29b diff --git a/ranger-discovery-bundle/perf/results/io.appform.ranger.discovery.bundle.id.IdGeneratorPerfTest.testGenerate.json b/ranger-discovery-bundle/perf/results/io.appform.ranger.discovery.bundle.id.IdGeneratorPerfTest.testGenerate.json new file mode 100644 index 00000000..f19b937b --- /dev/null +++ b/ranger-discovery-bundle/perf/results/io.appform.ranger.discovery.bundle.id.IdGeneratorPerfTest.testGenerate.json @@ -0,0 +1,8 @@ +{ + "name" : "io.appform.ranger.discovery.bundle.id.IdGeneratorPerfTest.testGenerate", + "mode" : "Throughput", + "iterations" : 4, + "threads" : 1, + "forks" : 3, + "mean_ops" : 644166.1778513143 +} \ No newline at end of file diff --git a/ranger-discovery-bundle/perf/results/io.appform.ranger.discovery.bundle.id.IdGeneratorPerfTest.testGenerateBase36.json b/ranger-discovery-bundle/perf/results/io.appform.ranger.discovery.bundle.id.IdGeneratorPerfTest.testGenerateBase36.json new file mode 100644 index 00000000..272db000 --- /dev/null +++ b/ranger-discovery-bundle/perf/results/io.appform.ranger.discovery.bundle.id.IdGeneratorPerfTest.testGenerateBase36.json @@ -0,0 +1,8 @@ +{ + "name" : "io.appform.ranger.discovery.bundle.id.IdGeneratorPerfTest.testGenerateBase36", + "mode" : "Throughput", + "iterations" : 4, + "threads" : 1, + "forks" : 3, + "mean_ops" : 502644.4941310657 +} \ No newline at end of file diff --git a/ranger-discovery-bundle/pom.xml b/ranger-discovery-bundle/pom.xml new file mode 100644 index 00000000..11233eb1 --- /dev/null +++ b/ranger-discovery-bundle/pom.xml @@ -0,0 +1,82 @@ + + + + ranger + io.appform.ranger + 1.0-RC15 + + 4.0.0 + + ranger-discovery-bundle + + + 1.7.2 + 3.2.4 + + + + + org.openjdk.jmh + jmh-core + 1.35 + test + + + org.openjdk.jmh + jmh-generator-annprocess + 1.35 + test + + + io.dropwizard + dropwizard-core + provided + + + dev.failsafe + failsafe + ${failsafe.version} + + + org.apache.curator + curator-test + ${curator.version} + test + + + log4j + log4j + + + io.netty + * + + + + + org.mockito + mockito-core + ${mockito.version} + test + + + io.appform.ranger + ranger-zk-client + ${project.version} + + + io.appform.ranger + ranger-server-common + ${project.version} + + + com.alibaba + dns-cache-manipulator + ${dns.cache.manipulator.version} + test + + + + \ No newline at end of file diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/Constants.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/Constants.java new file mode 100644 index 00000000..bd32cfa8 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/Constants.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import com.google.common.collect.ImmutableSet; +import lombok.experimental.UtilityClass; + +import java.util.Set; + +/** + * Constants + */ +@UtilityClass +public class Constants { + public static final String DEFAULT_NAMESPACE = "default"; + public static final String DEFAULT_HOST = "__DEFAULT_SERVICE_HOST"; + public static final int DEFAULT_PORT = -1; + public static final int DEFAULT_DW_CHECK_INTERVAL = 15; + public static final int DEFAULT_RETRY_CONN_INTERVAL = 5000; + + public static final String ZOOKEEPER_HOST_DELIMITER = ","; + public static final String HOST_PORT_DELIMITER = ":"; + public static final String PATH_DELIMITER = "/"; + + public static final Set LOCAL_ADDRESSES = ImmutableSet.of("127.0.0.1", "127.0.1.1", "localhost"); +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/InfoResource.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/InfoResource.java new file mode 100644 index 00000000..ca255fd8 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/InfoResource.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import io.appform.ranger.client.RangerClient; +import io.appform.ranger.common.server.ShardInfo; +import io.appform.ranger.core.finder.serviceregistry.MapBasedServiceRegistry; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Given information about the cluster. + */ +@Produces(MediaType.APPLICATION_JSON) +@Path("/instances") +public class InfoResource { + private final RangerClient> serviceDiscoveryClient; + + public InfoResource(RangerClient> serviceDiscoveryClient) { + this.serviceDiscoveryClient = serviceDiscoveryClient; + } + + @GET + public Response get() { + return Response.ok(serviceDiscoveryClient.getAllNodes()).build(); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundle.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundle.java new file mode 100644 index 00000000..c9397312 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundle.java @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import io.appform.ranger.client.RangerClient; +import io.appform.ranger.client.zk.SimpleRangerZKClient; +import io.appform.ranger.common.server.ShardInfo; +import io.appform.ranger.core.finder.serviceregistry.MapBasedServiceRegistry; +import io.appform.ranger.core.healthcheck.Healthcheck; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; +import io.appform.ranger.core.healthservice.TimeEntity; +import io.appform.ranger.core.healthservice.monitor.IsolatedHealthMonitor; +import io.appform.ranger.core.model.ServiceNode; +import io.appform.ranger.core.model.ShardSelector; +import io.appform.ranger.core.serviceprovider.ServiceProvider; +import io.appform.ranger.discovery.bundle.healthchecks.InitialDelayChecker; +import io.appform.ranger.discovery.bundle.healthchecks.InternalHealthChecker; +import io.appform.ranger.discovery.bundle.healthchecks.RotationCheck; +import io.appform.ranger.discovery.bundle.id.IdGenerator; +import io.appform.ranger.discovery.bundle.id.NodeIdManager; +import io.appform.ranger.discovery.bundle.id.constraints.IdValidationConstraint; +import io.appform.ranger.discovery.bundle.monitors.DropwizardHealthMonitor; +import io.appform.ranger.discovery.bundle.monitors.DropwizardServerStartupCheck; +import io.appform.ranger.discovery.bundle.resolvers.DefaultNodeInfoResolver; +import io.appform.ranger.discovery.bundle.resolvers.DefaultPortSchemeResolver; +import io.appform.ranger.discovery.bundle.resolvers.NodeInfoResolver; +import io.appform.ranger.discovery.bundle.resolvers.PortSchemeResolver; +import io.appform.ranger.discovery.bundle.rotationstatus.BIRTask; +import io.appform.ranger.discovery.bundle.rotationstatus.DropwizardServerStatus; +import io.appform.ranger.discovery.bundle.rotationstatus.OORTask; +import io.appform.ranger.discovery.bundle.rotationstatus.RotationStatus; +import io.appform.ranger.discovery.bundle.selectors.HierarchicalEnvironmentAwareShardSelector; +import io.appform.ranger.discovery.bundle.util.ConfigurationUtils; +import io.appform.ranger.zookeeper.ServiceProviderBuilders; +import io.appform.ranger.zookeeper.serde.ZkNodeDataSerializer; +import io.dropwizard.Configuration; +import io.dropwizard.ConfiguredBundle; +import io.dropwizard.lifecycle.Managed; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.retry.RetryForever; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static io.appform.ranger.discovery.bundle.Constants.LOCAL_ADDRESSES; + + +/** + * A dropwizard bundle for service discovery. + */ +@SuppressWarnings("unused") +@Slf4j +public abstract class ServiceDiscoveryBundle implements ConfiguredBundle { + + private final List healthchecks = Lists.newArrayList(); + private final List globalIdConstraints; + private ServiceDiscoveryConfiguration serviceDiscoveryConfiguration; + private ServiceProvider> serviceProvider; + + @Getter + private CuratorFramework curator; + @Getter + private RangerClient> serviceDiscoveryClient; + @Getter + @VisibleForTesting + private RotationStatus rotationStatus; + @Getter + @VisibleForTesting + private DropwizardServerStatus serverStatus; + + protected ServiceDiscoveryBundle() { + globalIdConstraints = Collections.emptyList(); + } + + protected ServiceDiscoveryBundle(List globalIdConstraints) { + this.globalIdConstraints = globalIdConstraints != null + ? globalIdConstraints + : Collections.emptyList(); + } + + @Override + public void initialize(Bootstrap bootstrap) { + + } + + @Override + public void run(T configuration, + Environment environment) throws Exception { + val portSchemeResolver = createPortSchemeResolver(); + Preconditions.checkNotNull(portSchemeResolver, "Port scheme resolver can't be null"); + val portScheme = portSchemeResolver.resolve(configuration); + serviceDiscoveryConfiguration = getRangerConfiguration(configuration); + val objectMapper = environment.getObjectMapper(); + val namespace = serviceDiscoveryConfiguration.getNamespace(); + val serviceName = getServiceName(configuration); + val hostname = getHost(); + val port = getPort(configuration); + val initialCriteria = getInitialCriteria(configuration); + val useInitialCriteria = alwaysMergeWithInitialCriteria(configuration); + val shardSelector = getShardSelector(configuration); + rotationStatus = new RotationStatus(serviceDiscoveryConfiguration.isInitialRotationStatus()); + serverStatus = new DropwizardServerStatus(false); + curator = CuratorFrameworkFactory.builder() + .connectString(serviceDiscoveryConfiguration.getZookeeper()) + .namespace(namespace) + .retryPolicy(new RetryForever(serviceDiscoveryConfiguration.getConnectionRetryIntervalMillis())) + .build(); + serviceProvider = buildServiceProvider(environment, objectMapper, namespace, serviceName, hostname, port, + portScheme); + serviceDiscoveryClient = buildDiscoveryClient(environment, namespace, serviceName, initialCriteria, + useInitialCriteria, shardSelector); + environment.lifecycle() + .manage(new ServiceDiscoveryManager(serviceName)); + environment.jersey() + .register(new InfoResource(serviceDiscoveryClient)); + environment.admin() + .addTask(new OORTask(rotationStatus)); + environment.admin() + .addTask(new BIRTask(rotationStatus)); + } + + protected ShardSelector> getShardSelector(T configuration) { + return new HierarchicalEnvironmentAwareShardSelector(getRangerConfiguration(configuration).getEnvironment()); + } + + protected abstract ServiceDiscoveryConfiguration getRangerConfiguration(T configuration); + + protected abstract String getServiceName(T configuration); + + protected NodeInfoResolver createNodeInfoResolver() { + return new DefaultNodeInfoResolver(); + } + + protected PortSchemeResolver createPortSchemeResolver() { + return new DefaultPortSchemeResolver<>(); + } + + /** + * Override the following if you require. + **/ + protected Predicate getInitialCriteria(T configuration) { + return shardInfo -> true; + } + + protected boolean alwaysMergeWithInitialCriteria(T configuration) { + return false; + } + + protected List> getHealthMonitors() { + return Collections.emptyList(); + } + + @SuppressWarnings("unused") + protected int getPort(T configuration) { + Preconditions.checkArgument(Constants.DEFAULT_PORT != serviceDiscoveryConfiguration.getPublishedPort() + && 0 != serviceDiscoveryConfiguration.getPublishedPort(), + "Looks like publishedPost has not been set and getPort() has not been overridden. This is wrong. \n" + + "Either set publishedPort in config or override getPort() to return the port on which the service is running"); + return serviceDiscoveryConfiguration.getPublishedPort(); + } + + protected String getHost() throws UnknownHostException { + val host = ConfigurationUtils.resolveNonEmptyPublishedHost(serviceDiscoveryConfiguration.getPublishedHost()); + + val publishedHostAddress = InetAddress.getByName(host) + .getHostAddress(); + + val zkHostAddresses = ConfigurationUtils.resolveZookeeperHosts(serviceDiscoveryConfiguration.getZookeeper()) + .stream() + .map(zkHost -> { + try { + return InetAddress.getByName(zkHost) + .getHostAddress(); + } catch (UnknownHostException e) { + throw new IllegalArgumentException( + String.format("Couldn't resolve host address for zkHost : %s", zkHost), e); + } + }) + .collect(Collectors.toSet()); + + Preconditions.checkArgument( + !LOCAL_ADDRESSES.contains(publishedHostAddress) || LOCAL_ADDRESSES.containsAll(zkHostAddresses), + "Not allowed to publish localhost address to remote zookeeper"); + + return host; + } + + public void registerHealthcheck(Healthcheck healthcheck) { + this.healthchecks.add(healthcheck); + } + + public void registerHealthchecks(List healthchecks) { + this.healthchecks.addAll(healthchecks); + } + + + private RangerClient> buildDiscoveryClient(Environment environment, + String namespace, + String serviceName, + Predicate initialCriteria, + boolean mergeWithInitialCriteria, + ShardSelector> shardSelector) { + return SimpleRangerZKClient.builder() + .curatorFramework(curator) + .namespace(namespace) + .serviceName(serviceName) + .mapper(environment.getObjectMapper()) + .nodeRefreshIntervalMs(serviceDiscoveryConfiguration.getRefreshTimeMs()) + .disableWatchers(serviceDiscoveryConfiguration.isDisableWatchers()) + .deserializer(data -> { + try { + return environment.getObjectMapper() + .readValue(data, new TypeReference>() { + }); + } catch (IOException e) { + log.warn("Error parsing node data with value {}", new String(data)); + } + return null; + }) + .initialCriteria(initialCriteria) + .alwaysUseInitialCriteria(mergeWithInitialCriteria) + .shardSelector(shardSelector) + .build(); + } + + private ServiceProvider> buildServiceProvider(Environment environment, + ObjectMapper objectMapper, + String namespace, + String serviceName, + String hostname, + int port, + String portScheme) { + val nodeInfoResolver = createNodeInfoResolver(); + val nodeInfo = nodeInfoResolver.resolve(serviceDiscoveryConfiguration); + val initialDelayForMonitor = serviceDiscoveryConfiguration.getInitialDelaySeconds() > 1 + ? serviceDiscoveryConfiguration.getInitialDelaySeconds() - 1 + : 0; + val dwMonitoringInterval = serviceDiscoveryConfiguration.getDropwizardCheckInterval() == 0 + ? Constants.DEFAULT_DW_CHECK_INTERVAL + : serviceDiscoveryConfiguration.getDropwizardCheckInterval(); + val dwMonitoringStaleness = Math.max(serviceDiscoveryConfiguration.getDropwizardCheckStaleness(), + dwMonitoringInterval + 1); + val serviceProviderBuilder = ServiceProviderBuilders.shardedServiceProviderBuilder() + .withCuratorFramework(curator) + .withNamespace(namespace) + .withServiceName(serviceName) + .withSerializer(data -> { + try { + return objectMapper.writeValueAsBytes(data); + } catch (Exception e) { + log.warn("Could not parse node data", e); + } + return null; + }) + .withPortScheme(portScheme) + .withNodeData(nodeInfo) + .withHostname(hostname) + .withPort(port) + .withHealthcheck(new InternalHealthChecker(healthchecks)) + .withHealthcheck(new RotationCheck(rotationStatus)) + .withHealthcheck(new InitialDelayChecker(serviceDiscoveryConfiguration.getInitialDelaySeconds())) + .withHealthcheck(new DropwizardServerStartupCheck(environment, serverStatus)) + .withIsolatedHealthMonitor(new DropwizardHealthMonitor( + new TimeEntity(initialDelayForMonitor, dwMonitoringInterval, TimeUnit.SECONDS), + dwMonitoringStaleness * 1_000L, environment)) + .withHealthUpdateIntervalMs(serviceDiscoveryConfiguration.getRefreshTimeMs()) + .withStaleUpdateThresholdMs(10000); + + val healthMonitors = getHealthMonitors(); + if (healthMonitors != null && !healthMonitors.isEmpty()) { + healthMonitors.forEach(serviceProviderBuilder::withIsolatedHealthMonitor); + } + return serviceProviderBuilder.build(); + } + + @AllArgsConstructor + private class ServiceDiscoveryManager implements Managed { + + private final String serviceName; + + @Override + public void start() { + log.debug("Starting the discovery manager"); + curator.start(); + serviceProvider.start(); + serviceDiscoveryClient.start(); + val nodeIdManager = new NodeIdManager(curator, serviceName); + IdGenerator.initialize(nodeIdManager.fixNodeId(), globalIdConstraints, Collections.emptyMap()); + log.debug("Discovery manager has been successfully started."); + } + + @Override + public void stop() { + serviceDiscoveryClient.stop(); + serviceProvider.stop(); + curator.close(); + IdGenerator.cleanUp(); + } + } + +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryConfiguration.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryConfiguration.java new file mode 100644 index 00000000..516f6c75 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryConfiguration.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import com.google.common.base.Strings; +import lombok.*; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Set; + +/** + * Ranger configuration. + */ +@Data +@EqualsAndHashCode +@ToString +@NoArgsConstructor +public class ServiceDiscoveryConfiguration { + + + @NotNull + @NotEmpty + private String namespace = Constants.DEFAULT_NAMESPACE; + + @NotNull + @NotEmpty + private String environment; + + @NotNull + @NotEmpty + private String zookeeper; + + @Min(1000) + @Max(60000) + private int connectionRetryIntervalMillis = Constants.DEFAULT_RETRY_CONN_INTERVAL; + + @NotNull + @NotEmpty + private String publishedHost = Constants.DEFAULT_HOST; + + @NotNull + @Min(-1) + @Max(65535) + private int publishedPort = Constants.DEFAULT_PORT; + + private int refreshTimeMs; + + private boolean disableWatchers; + + @Min(0) + @Max(600) + private long initialDelaySeconds; + + private boolean initialRotationStatus = true; + + private int dropwizardCheckInterval = Constants.DEFAULT_DW_CHECK_INTERVAL; + + private int dropwizardCheckStaleness; + + private Set tags; + + @Builder + public ServiceDiscoveryConfiguration(String namespace, + String environment, + String zookeeper, + int connectionRetryIntervalMillis, + String publishedHost, + int publishedPort, + int refreshTimeMs, + boolean disableWatchers, + long initialDelaySeconds, + boolean initialRotationStatus, + int dropwizardCheckInterval, + int dropwizardCheckStaleness, + Set tags) { + this.namespace = Strings.isNullOrEmpty(namespace) + ? Constants.DEFAULT_NAMESPACE + : namespace; + this.environment = environment; + this.zookeeper = zookeeper; + this.connectionRetryIntervalMillis = connectionRetryIntervalMillis == 0 + ? Constants.DEFAULT_RETRY_CONN_INTERVAL + : connectionRetryIntervalMillis; + this.publishedHost = Strings.isNullOrEmpty(publishedHost) + ? Constants.DEFAULT_HOST + : publishedHost; + this.publishedPort = publishedPort == 0 + ? Constants.DEFAULT_PORT + : publishedPort; + this.refreshTimeMs = refreshTimeMs; + this.disableWatchers = disableWatchers; + this.initialDelaySeconds = initialDelaySeconds; + this.initialRotationStatus = initialRotationStatus; + this.dropwizardCheckInterval = dropwizardCheckInterval == 0 + ? Constants.DEFAULT_DW_CHECK_INTERVAL + : dropwizardCheckInterval; + this.dropwizardCheckStaleness = dropwizardCheckStaleness; + this.tags = tags; + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/healthchecks/InitialDelayChecker.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/healthchecks/InitialDelayChecker.java new file mode 100644 index 00000000..c7e4a9e4 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/healthchecks/InitialDelayChecker.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.healthchecks; + +import io.appform.ranger.core.healthcheck.Healthcheck; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; + +/** + * The following will return healthy only after stipulated time + * This will give other bundles etc to startup properly + * By the time the node joins the cluster + */ +public class InitialDelayChecker implements Healthcheck { + private final long validRegistrationTime; + + + public InitialDelayChecker(long initialDelaySeconds) { + validRegistrationTime = System.currentTimeMillis() + initialDelaySeconds * 1000; + } + + @Override + public HealthcheckStatus check() { + return System.currentTimeMillis() > validRegistrationTime + ? HealthcheckStatus.healthy + : HealthcheckStatus.unhealthy; + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/healthchecks/InternalHealthChecker.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/healthchecks/InternalHealthChecker.java new file mode 100644 index 00000000..df6655f1 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/healthchecks/InternalHealthChecker.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.healthchecks; + +import io.appform.ranger.core.healthcheck.Healthcheck; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; + +import java.util.List; + +/** + * Evaluates all registered healthchecks + */ +public class InternalHealthChecker implements Healthcheck { + private final List healthchecks; + + public InternalHealthChecker(List healthchecks) { + this.healthchecks = healthchecks; + } + + @Override + public HealthcheckStatus check() { + return healthchecks.stream() + .map(Healthcheck::check) + .filter(healthcheckStatus -> healthcheckStatus == HealthcheckStatus.unhealthy) + .findFirst() + .orElse(HealthcheckStatus.healthy); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/healthchecks/RotationCheck.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/healthchecks/RotationCheck.java new file mode 100644 index 00000000..3741b035 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/healthchecks/RotationCheck.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.healthchecks; + +import io.appform.ranger.core.healthcheck.Healthcheck; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; +import io.appform.ranger.discovery.bundle.rotationstatus.RotationStatus; + +/** + * This allows the node to be taken offline in the cluster but still keep running + */ +public class RotationCheck implements Healthcheck { + + private final RotationStatus rotationStatus; + + public RotationCheck(RotationStatus rotationStatus) { + this.rotationStatus = rotationStatus; + } + + @Override + public HealthcheckStatus check() { + return (rotationStatus.status()) + ? HealthcheckStatus.healthy + : HealthcheckStatus.unhealthy; + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/CollisionChecker.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/CollisionChecker.java new file mode 100644 index 00000000..b3e947a7 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/CollisionChecker.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id; + +import lombok.extern.slf4j.Slf4j; + +import java.util.BitSet; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Checks collisions between ids in given period + */ +@Slf4j +public class CollisionChecker { + private final BitSet bitSet = new BitSet(1000); + private long currentInstant = 0; + + private final Lock dataLock = new ReentrantLock(); + + public CollisionChecker() { + //Nothing to do here + } + + public boolean check(long time, int location) { + dataLock.lock(); + try { + if (currentInstant != time) { + currentInstant = time; + bitSet.clear(); + } + + if (bitSet.get(location)) { + return false; + } + bitSet.set(location); + return true; + } + finally { + dataLock.unlock(); + } + } + + public void free(long time, int location) { + dataLock.lock(); + try { + if (currentInstant != time) { + return; + } + bitSet.clear(location); + } + finally { + dataLock.unlock(); + } + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/Constants.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/Constants.java new file mode 100644 index 00000000..f191b90e --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/Constants.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id; + +import lombok.experimental.UtilityClass; + +/** + * All constants for this project + */ +@UtilityClass +public class Constants { + public static final int MAX_ID_PER_MS = 1000; + public static final int MAX_NUM_NODES = 10000; +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/CuratorPathUtils.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/CuratorPathUtils.java new file mode 100644 index 00000000..806b5f41 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/CuratorPathUtils.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id; + +/** + * Utilities for curator + */ +public class CuratorPathUtils { + private final String processName; + + public CuratorPathUtils(String processName) { + this.processName = processName; + } + + public String path(int nodeId) { + return String.format("/%s/%s/%03d", "id-generator", processName, nodeId); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/Id.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/Id.java new file mode 100644 index 00000000..0ef6edc4 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/Id.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id; + +import lombok.*; + +import java.util.Date; + +/** + * A representation of an ID + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +public class Id { + private String id; + private Date generatedDate; + private int node; + private int exponent; +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/IdGenerator.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/IdGenerator.java new file mode 100644 index 00000000..3a0f9dbd --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/IdGenerator.java @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import dev.failsafe.Failsafe; +import dev.failsafe.FailsafeExecutor; +import dev.failsafe.RetryPolicy; +import io.appform.ranger.discovery.bundle.id.constraints.IdValidationConstraint; +import io.appform.ranger.discovery.bundle.id.formatter.IdFormatter; +import io.appform.ranger.discovery.bundle.id.formatter.IdFormatters; +import io.appform.ranger.discovery.bundle.id.request.IdGenerationRequest; +import lombok.Value; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; + +import java.security.SecureRandom; +import java.util.*; +import java.util.regex.Pattern; + +/** + * Id generation + */ +@SuppressWarnings("unused") +@Slf4j +public class IdGenerator { + + private static final int MINIMUM_ID_LENGTH = 22; + private static final SecureRandom SECURE_RANDOM = new SecureRandom(Long.toBinaryString(System.currentTimeMillis()).getBytes()); + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyMMddHHmmssSSS"); + private static final CollisionChecker COLLISION_CHECKER = new CollisionChecker(); + private static final RetryPolicy RETRY_POLICY = RetryPolicy.builder() + .withMaxAttempts(readRetryCount()) + .handleIf(throwable -> true) + .handleResultIf(Objects::isNull) + .handleResultIf(generationResult -> generationResult.getState() == IdValidationState.INVALID_RETRYABLE) + .onRetry(event -> { + val res = event.getLastResult(); + if(null != res && !res.getState().equals(IdValidationState.VALID)) { + val id = res.getId(); + COLLISION_CHECKER.free(id.getGeneratedDate().getTime(), id.getExponent()); + } + }) + .build(); + private static final FailsafeExecutor RETRIER + = Failsafe.with(Collections.singletonList(RETRY_POLICY)); + private static final Pattern PATTERN = Pattern.compile("(.*)([0-9]{15})([0-9]{4})([0-9]{3})"); + + private static final List GLOBAL_CONSTRAINTS = new ArrayList<>(); + private static final Map> DOMAIN_SPECIFIC_CONSTRAINTS = new HashMap<>(); + private static int nodeId; + + public static void initialize(int node) { + nodeId = node; + } + + public static synchronized void cleanUp() { + GLOBAL_CONSTRAINTS.clear(); + DOMAIN_SPECIFIC_CONSTRAINTS.clear(); + } + + + public static synchronized void initialize( + int node, List globalConstraints, Map> domainSpecificConstraints) { + nodeId = node; + if(null != globalConstraints) { + IdGenerator.GLOBAL_CONSTRAINTS.addAll(globalConstraints); + } + if(null != domainSpecificConstraints) { + IdGenerator.DOMAIN_SPECIFIC_CONSTRAINTS.putAll(domainSpecificConstraints); + } + } + + public static synchronized void registerGlobalConstraints(IdValidationConstraint... constraints) { + registerGlobalConstraints(ImmutableList.copyOf(constraints)); + } + + public static synchronized void registerGlobalConstraints(List constraints) { + Preconditions.checkArgument(null != constraints && !constraints.isEmpty()); + GLOBAL_CONSTRAINTS.addAll(constraints); + } + + public static synchronized void registerDomainSpecificConstraints( + String domain, + IdValidationConstraint... validationConstraints) { + registerDomainSpecificConstraints(domain, ImmutableList.copyOf(validationConstraints)); + } + + public static synchronized void registerDomainSpecificConstraints( + String domain, + List validationConstraints) { + Preconditions.checkArgument(null != validationConstraints && !validationConstraints.isEmpty()); + DOMAIN_SPECIFIC_CONSTRAINTS.computeIfAbsent(domain, key -> new ArrayList<>()) + .addAll(validationConstraints); + } + + /** + * Generate id with given prefix + * + * @param prefix String prefix with will be used to blindly merge + * @return Generated Id + */ + public static Id generate(String prefix) { + return generate(prefix, IdFormatters.original()); + } + + public static Id generate(final String prefix, + final IdFormatter idFormatter) { + val idInfo = random(); + val dateTime = new DateTime(idInfo.time); + val id = String.format("%s%s", prefix, idFormatter.format(dateTime, nodeId, idInfo.exponent)); + return Id.builder() + .id(id) + .exponent(idInfo.exponent) + .generatedDate(dateTime.toDate()) + .node(nodeId) + .build(); + } + + /** + * Generate id that mathces all passed constraints. + * NOTE: There are performance implications for this. + * The evaluation of constraints will take it's toll on id generation rates. Tun rests to check speed. + * + * @param prefix String prefix + * @param domain Domain for constraint selection + * @return Return generated id or empty if it was impossible to satisfy constraints and generate + */ + public static Optional generateWithConstraints(String prefix, String domain) { + return generateWithConstraints(prefix, DOMAIN_SPECIFIC_CONSTRAINTS.getOrDefault(domain, Collections.emptyList()), true); + } + + /** + * Generate id that mathces all passed constraints. + * NOTE: There are performance implications for this. + * The evaluation of constraints will take it's toll on id generation rates. Tun rests to check speed. + * + * @param prefix String prefix + * @param domain Domain for constraint selection + * @param skipGlobal Skip global constrains and use only passed ones + * @return Id if it could be generated + */ + public static Optional generateWithConstraints(String prefix, String domain, boolean skipGlobal) { + return generateWithConstraints(prefix, DOMAIN_SPECIFIC_CONSTRAINTS.getOrDefault(domain, Collections.emptyList()), skipGlobal); + } + + /** + * Generate id that mathces all passed constraints. + * NOTE: There are performance implications for this. + * The evaluation of constraints will take it's toll on id generation rates. Tun rests to check speed. + * + * @param prefix String prefix + * @param inConstraints Constraints that need to be validated. + * @return Id if it could be generated + */ + public static Optional generateWithConstraints(String prefix, final List inConstraints) { + return generateWithConstraints(prefix, inConstraints, false); + } + + /** + * Generate id by parsing given string + * + * @param idString String idString + * @return Id if it could be generated + */ + public static Optional parse(final String idString) { + if (idString == null + || idString.length() < MINIMUM_ID_LENGTH) { + return Optional.empty(); + } + try { + val matcher = PATTERN.matcher(idString); + if (matcher.find()) { + return Optional.of(Id.builder() + .id(idString) + .node(Integer.parseInt(matcher.group(3))) + .exponent(Integer.parseInt(matcher.group(4))) + .generatedDate(DATE_TIME_FORMATTER.parseDateTime(matcher.group(2)).toDate()) + .build()); + } + return Optional.empty(); + } + catch (Exception e) { + log.warn("Could not parse idString {}", e.getMessage()); + return Optional.empty(); + } + } + + /** + * Generate id that mathces all passed constraints. + * NOTE: There are performance implications for this. + * The evaluation of constraints will take it's toll on id generation rates. Tun rests to check speed. + * + * @param prefix String prefix + * @param inConstraints Constraints that need to be validate. + * @param skipGlobal Skip global constrains and use only passed ones + * @return Id if it could be generated + */ + public static Optional generateWithConstraints(String prefix, final List inConstraints, boolean skipGlobal) { + return generate(IdGenerationRequest.builder() + .prefix(prefix) + .constraints(inConstraints) + .skipGlobal(skipGlobal) + .idFormatter(IdFormatters.original()) + .build()); + } + + public static Optional generate(final IdGenerationRequest request) { + return Optional.ofNullable(RETRIER.get( + () -> { + Id id = generate(request.getPrefix(), request.getIdFormatter()); + return new GenerationResult(id, validateId(request.getConstraints(), id, request.isSkipGlobal())); + })) + .filter(generationResult -> generationResult.getState() == IdValidationState.VALID) + .map(GenerationResult::getId); + } + + private static IdInfo random() { + int randomGen; + long time; + do { + time = System.currentTimeMillis(); + randomGen = SECURE_RANDOM.nextInt(Constants.MAX_ID_PER_MS); + } while (!COLLISION_CHECKER.check(time, randomGen)); + return new IdInfo(randomGen, time); + } + + private static IdValidationState validateId(List inConstraints, Id id, boolean skipGlobal) { + //First evaluate global constraints + val failedGlobalConstraint + = skipGlobal + ? null + : GLOBAL_CONSTRAINTS.stream() + .filter(constraint -> !constraint.isValid(id)) + .findFirst() + .orElse(null); + if (null != failedGlobalConstraint) { + return failedGlobalConstraint.failFast() + ? IdValidationState.INVALID_NON_RETRYABLE + : IdValidationState.INVALID_RETRYABLE; + } + //Evaluate local + domain constraints + val failedLocalConstraint + = null == inConstraints + ? null + : inConstraints.stream() + .filter(constraint -> !constraint.isValid(id)) + .findFirst() + .orElse(null); + if (null != failedLocalConstraint) { + return failedLocalConstraint.failFast() + ? IdValidationState.INVALID_NON_RETRYABLE + : IdValidationState.INVALID_RETRYABLE; + } + return IdValidationState.VALID; + } + + private static int readRetryCount() { + try { + val count = Integer.parseInt(System.getenv().getOrDefault("NUM_ID_GENERATION_RETRIES", "512")); + if (count <= 0) { + throw new IllegalArgumentException( + "Negative number of retries does not make sense. Please set a proper value for " + + "NUM_ID_GENERATION_RETRIES"); + } + return count; + } + catch (NumberFormatException e) { + throw new IllegalArgumentException("Please provide a valid positive integer for NUM_ID_GENERATION_RETRIES"); + } + } + + private enum IdValidationState { + VALID, + INVALID_RETRYABLE, + INVALID_NON_RETRYABLE + } + + @Value + private static class IdInfo { + int exponent; + long time; + + public IdInfo(int exponent, long time) { + this.exponent = exponent; + this.time = time; + } + } + + @Value + private static class GenerationResult { + Id id; + IdValidationState state; + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/NodeIdManager.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/NodeIdManager.java new file mode 100644 index 00000000..bc865cf9 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/NodeIdManager.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id; + +import com.github.rholder.retry.RetryException; +import com.github.rholder.retry.RetryerBuilder; +import com.github.rholder.retry.StopStrategies; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.curator.framework.CuratorFramework; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; + +import java.security.SecureRandom; +import java.util.Objects; +import java.util.concurrent.ExecutionException; + +/** + * Created by santanu on 2/5/16. + */ +@Slf4j +public class NodeIdManager { + + private final CuratorFramework curatorFramework; + private final SecureRandom secureRandom; + private final CuratorPathUtils pathUtils; + + @Getter + private int node; + + public NodeIdManager(CuratorFramework curatorFramework, String processName) { + this.curatorFramework = curatorFramework; + this.secureRandom = new SecureRandom(Long.toBinaryString(System.currentTimeMillis()).getBytes()); + this.pathUtils = new CuratorPathUtils(processName); + } + + public int fixNodeId() { + try { + log.info("Waiting for curator to start"); + curatorFramework.blockUntilConnected(); + log.info("Curator started"); + } catch (InterruptedException e) { + log.error("Wait for curator start interrupted", e); + Thread.currentThread().interrupt(); + } + val retryer = RetryerBuilder.newBuilder() + .retryIfResult(aBoolean -> Objects.equals(aBoolean, false)) + .retryIfException() + .withStopStrategy(StopStrategies.neverStop()) + .build(); + try { + retryer.call(() -> { + node = secureRandom.nextInt(Constants.MAX_NUM_NODES); + val path = pathUtils.path(node); + try { + curatorFramework.create() + .creatingParentContainersIfNeeded() + .withMode(CreateMode.EPHEMERAL) + .forPath(path); + } catch (KeeperException.NodeExistsException e) { + log.warn("Collision on node {}, will retry with new node.", node); + return false; + } + log.info("Node will be set to node id {}", node); + return true; + }); + } catch (RetryException e) { + log.error("Error creating node", e); + } catch (ExecutionException e) { + log.error("Execution exception while creating node", e); + } + return node; + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/IdValidationConstraint.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/IdValidationConstraint.java new file mode 100644 index 00000000..eb43a6ed --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/IdValidationConstraint.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id.constraints; + + +import io.appform.ranger.discovery.bundle.id.Id; + +/** + * + */ +public interface IdValidationConstraint { + + boolean isValid(Id id); + + default boolean failFast() { + return false; + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/JavaHashCodeBasedKeyPartitioner.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/JavaHashCodeBasedKeyPartitioner.java new file mode 100644 index 00000000..65bcee36 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/JavaHashCodeBasedKeyPartitioner.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id.constraints.impl; + + +import io.appform.ranger.discovery.bundle.id.Id; + +/** + * + */ +public class JavaHashCodeBasedKeyPartitioner implements KeyPartitioner { + + private final int maxPartitions; + + public JavaHashCodeBasedKeyPartitioner(int maxPartitions) { + this.maxPartitions = maxPartitions; + } + + @Override + public int partition(Id id) { + var hashCode = id.getId().hashCode(); + hashCode *= hashCode < 0 ? -1 : 1; + return hashCode % maxPartitions; + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/KeyPartitioner.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/KeyPartitioner.java new file mode 100644 index 00000000..87eee3b7 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/KeyPartitioner.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id.constraints.impl; + + +import io.appform.ranger.discovery.bundle.id.Id; + +/** + * Takes an id and generates a partition + */ +@FunctionalInterface +public interface KeyPartitioner { + int partition(Id id); +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/MurmurBasedKeyPartitioner.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/MurmurBasedKeyPartitioner.java new file mode 100644 index 00000000..f4b3d488 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/MurmurBasedKeyPartitioner.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id.constraints.impl; + +import com.google.common.hash.Hashing; +import io.appform.ranger.discovery.bundle.id.Id; + +import java.nio.charset.StandardCharsets; + +/** + * + */ +@SuppressWarnings("unused") +public class MurmurBasedKeyPartitioner implements KeyPartitioner { + + private final int maxPartitions; + + public MurmurBasedKeyPartitioner(int maxPartitions) { + this.maxPartitions = maxPartitions; + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public int partition(Id id) { + int hashCode = Hashing.murmur3_128().hashString(id.toString(), StandardCharsets.UTF_8).asInt(); + hashCode *= hashCode < 0 ? -1 : 1; + return hashCode % maxPartitions; + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/PartitionValidator.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/PartitionValidator.java new file mode 100644 index 00000000..474c2404 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/constraints/impl/PartitionValidator.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id.constraints.impl; + +import com.google.common.base.Preconditions; +import io.appform.ranger.discovery.bundle.id.Id; +import io.appform.ranger.discovery.bundle.id.constraints.IdValidationConstraint; +import lombok.extern.slf4j.Slf4j; + +/** + * Checks if key is same partition as provided. + */ +@Slf4j +public class PartitionValidator implements IdValidationConstraint { + + private final int partition; + private final KeyPartitioner partitioner; + + public PartitionValidator(int partition, KeyPartitioner partitioner) { + Preconditions.checkArgument(partition > 0, + "Provide a non-negative and non-zero partition count"); + Preconditions.checkArgument(partitioner != null, + "Provide a non null key partitioner"); + this.partition = partition; + this.partitioner = partitioner; + } + + @Override + public boolean isValid(Id id) { + return partition == partitioner.partition(id); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/Base36IdFormatter.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/Base36IdFormatter.java new file mode 100644 index 00000000..1af19d86 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/Base36IdFormatter.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id.formatter; + +import org.joda.time.DateTime; + +import java.math.BigInteger; + +public class Base36IdFormatter implements IdFormatter { + + private final IdFormatter idFormatter; + + public Base36IdFormatter(IdFormatter idFormatter) { + this.idFormatter = idFormatter; + } + + @Override + public String format(final DateTime dateTime, + final int nodeId, + final int randomNonce) { + return toBase36(idFormatter.format(dateTime, nodeId, randomNonce)); + } + + private static String toBase36(final String payload) { + return new BigInteger(payload).toString(36).toUpperCase(); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/DefaultIdFormatter.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/DefaultIdFormatter.java new file mode 100644 index 00000000..7bd27c6a --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/DefaultIdFormatter.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id.formatter; + +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; + +public class DefaultIdFormatter implements IdFormatter { + + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyMMddHHmmssSSS"); + + @Override + public String format(final DateTime dateTime, + final int nodeId, + final int randomNonce) { + return String.format("%s%04d%03d", DATE_TIME_FORMATTER.print(dateTime), nodeId, randomNonce); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/IdFormatter.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/IdFormatter.java new file mode 100644 index 00000000..6a38f073 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/IdFormatter.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id.formatter; + +import org.joda.time.DateTime; + +public interface IdFormatter { + + String format(final DateTime dateTime, + final int nodeId, + final int randomNonce); + + +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/IdFormatters.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/IdFormatters.java new file mode 100644 index 00000000..30bca972 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/formatter/IdFormatters.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id.formatter; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class IdFormatters { + + private static final IdFormatter originalIdFormatter = new DefaultIdFormatter(); + private static final IdFormatter base36IdFormatter = new Base36IdFormatter(originalIdFormatter); + + public static IdFormatter original() { + return originalIdFormatter; + } + + public static IdFormatter base36() { + return base36IdFormatter; + } + +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/request/IdGenerationRequest.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/request/IdGenerationRequest.java new file mode 100644 index 00000000..444ccfa2 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/id/request/IdGenerationRequest.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id.request; + +import io.appform.ranger.discovery.bundle.id.constraints.IdValidationConstraint; +import io.appform.ranger.discovery.bundle.id.formatter.IdFormatter; +import lombok.Builder; +import lombok.Value; + +import java.util.List; + +@Value +@Builder +public class IdGenerationRequest { + + String prefix; + String domain; + boolean skipGlobal; + List constraints; + IdFormatter idFormatter; + +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/monitors/DropwizardHealthMonitor.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/monitors/DropwizardHealthMonitor.java new file mode 100644 index 00000000..af6a4c45 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/monitors/DropwizardHealthMonitor.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.monitors; + +import com.codahale.metrics.health.HealthCheck; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; +import io.appform.ranger.core.healthservice.TimeEntity; +import io.appform.ranger.core.healthservice.monitor.IsolatedHealthMonitor; +import io.dropwizard.setup.Environment; + +/** + * This monitor calls dropwizard healthchecks every few secs. + */ +public class DropwizardHealthMonitor extends IsolatedHealthMonitor { + + private final Environment environment; + + public DropwizardHealthMonitor( + TimeEntity runInterval, + long stalenessAllowedInMillis, + Environment environment) { + super("dropwizard-health-monitor", runInterval, stalenessAllowedInMillis); + this.environment = environment; + } + + @Override + public HealthcheckStatus monitor() { + return (null != environment.healthChecks() + && environment.healthChecks() + .runHealthChecks() + .values() + .stream() + .allMatch(HealthCheck.Result::isHealthy)) + ? HealthcheckStatus.healthy + : HealthcheckStatus.unhealthy; + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/monitors/DropwizardServerStartupCheck.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/monitors/DropwizardServerStartupCheck.java new file mode 100644 index 00000000..94e4156d --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/monitors/DropwizardServerStartupCheck.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.monitors; + +import io.appform.ranger.core.healthcheck.Healthcheck; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; +import io.appform.ranger.discovery.bundle.rotationstatus.DropwizardServerStatus; +import io.dropwizard.setup.Environment; +import lombok.extern.slf4j.Slf4j; + +/** + * This healthcheck listens to server started event to mark service healthy on ranger. + */ +@Slf4j +public class DropwizardServerStartupCheck implements Healthcheck { + + private final DropwizardServerStatus serverStatus; + + public DropwizardServerStartupCheck(Environment environment, + DropwizardServerStatus serverStatus) { + this.serverStatus = serverStatus; + environment.lifecycle().addServerLifecycleListener(server -> { + log.info("Dropwizard server started. Marking healthcheck as healthy"); + serverStatus.markStarted(); + }); + } + + @Override + public HealthcheckStatus check() { + return serverStatus.started() ? HealthcheckStatus.healthy : HealthcheckStatus.unhealthy; + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/CriteriaResolver.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/CriteriaResolver.java new file mode 100644 index 00000000..32637445 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/CriteriaResolver.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.resolvers; + +/** + * CriteriaResolver.java + * Interface to help resolve from an argument A to the typed object T. + * Keeping this as the qualified class instead of using Function so that in the future if all criteria resolvers were to + * be fetched to register using reflections et. al, there is a qualified naming. + */ +@FunctionalInterface +public interface CriteriaResolver { + + T resolve(A args); + +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/DefaultNodeInfoResolver.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/DefaultNodeInfoResolver.java new file mode 100644 index 00000000..c75bbdff --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/DefaultNodeInfoResolver.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.resolvers; + +import io.appform.ranger.common.server.ShardInfo; +import io.appform.ranger.discovery.bundle.ServiceDiscoveryConfiguration; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import lombok.val; + + +@NoArgsConstructor +@Slf4j +public class DefaultNodeInfoResolver implements NodeInfoResolver { + + private static final String FARM_ID = "FARM_ID"; + + @Override + public ShardInfo resolve(ServiceDiscoveryConfiguration configuration) { + val region = System.getenv(FARM_ID); + log.debug("The region received from the env variable FARM_ID is {}. Setting the same in nodeInfo", region); + return ShardInfo.builder() + .environment(configuration.getEnvironment()) + .region(region) + .tags(configuration.getTags()) + .build(); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/DefaultPortSchemeResolver.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/DefaultPortSchemeResolver.java new file mode 100644 index 00000000..74185e28 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/DefaultPortSchemeResolver.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.resolvers; + +import io.appform.ranger.core.model.PortSchemes; +import io.dropwizard.Configuration; +import io.dropwizard.jetty.ConnectorFactory; +import io.dropwizard.jetty.HttpsConnectorFactory; +import io.dropwizard.server.DefaultServerFactory; +import io.dropwizard.server.ServerFactory; +import io.dropwizard.server.SimpleServerFactory; +import lombok.val; + +import java.util.Optional; + +/** + * DefaultPortSchemeResolver.java + * To derive PortScheme from the ServerFactory from Dropwizard startup config + */ +public class DefaultPortSchemeResolver implements PortSchemeResolver { + + /** + * Returns a PortScheme basis the configuration. The default in case of a new + * Connector found (Possibly on version upgrades, if we have forgotten mutate it, + * is HTTP) + * + * @param configuration {@link Configuration} the dropwizard startup config + * @return {@link String} The relevant portScheme with HTTP as default + */ + @Override + public String resolve(T configuration) { + val connectionFactory = getConnectorFactory(configuration.getServerFactory()); + return connectionFactory.filter(HttpsConnectorFactory.class::isInstance) + .map(factory -> PortSchemes.HTTPS) + .orElse(PortSchemes.HTTP); + } + + private Optional getConnectorFactory(ServerFactory serverFactory) { + if (serverFactory instanceof DefaultServerFactory) { + val defaultFactory = (DefaultServerFactory) serverFactory; + return defaultFactory.getApplicationConnectors() + .stream() + .findFirst(); + } else if (serverFactory instanceof SimpleServerFactory) { + val defaultFactory = (SimpleServerFactory) serverFactory; + return Optional.ofNullable(defaultFactory.getConnector()); + } else { + return Optional.empty(); + } + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/NodeInfoResolver.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/NodeInfoResolver.java new file mode 100644 index 00000000..04504735 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/NodeInfoResolver.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.resolvers; + +import io.appform.ranger.common.server.ShardInfo; +import io.appform.ranger.discovery.bundle.ServiceDiscoveryBundle; +import io.appform.ranger.discovery.bundle.ServiceDiscoveryConfiguration; + +/** + * NodeInfoResolver.java + * Interface to help build a node to be saved in the discovery backend while building the serviceProvider. + * To define your custom nodeData {@link ShardInfo}, please define your own implementation, during the bundle {@link + * ServiceDiscoveryBundle} init. + */ +@FunctionalInterface +public interface NodeInfoResolver extends CriteriaResolver { + +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/PortSchemeResolver.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/PortSchemeResolver.java new file mode 100644 index 00000000..4c772e38 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/resolvers/PortSchemeResolver.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.resolvers; + +import io.dropwizard.Configuration; + +/** + * NodeInfoResolver.java + * Interface to help build a portScheme basis the server {@link Configuration} + */ +@FunctionalInterface +public interface PortSchemeResolver extends CriteriaResolver { + +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/BIRTask.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/BIRTask.java new file mode 100644 index 00000000..086d8be1 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/BIRTask.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.rotationstatus; + + +import io.dropwizard.servlets.tasks.Task; +import lombok.extern.slf4j.Slf4j; + +import java.io.PrintWriter; +import java.util.List; +import java.util.Map; + +/** + * Admin task to take node bir in ranger + */ +@Slf4j +public class BIRTask extends Task { + private final RotationStatus rotationStatus; + public BIRTask(RotationStatus rotationStatus) { + super("ranger-bir"); + this.rotationStatus = rotationStatus; + } + + @Override + public void execute(Map> map, PrintWriter printWriter) { + rotationStatus.bir(); + log.info("Taking node back into rotation on ranger"); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/DropwizardServerStatus.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/DropwizardServerStatus.java new file mode 100644 index 00000000..77de15ea --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/DropwizardServerStatus.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.rotationstatus; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Current server startup started + */ +@SuppressWarnings("unused") +public class DropwizardServerStatus { + + private final AtomicBoolean serverStarted; + + public DropwizardServerStatus(boolean initialStatus) { + serverStarted = new AtomicBoolean(initialStatus); + } + + public void markStarted() { + serverStarted.set(true); + } + + public void markStopped() { + serverStarted.set(false); + } + + public boolean started() { + return serverStarted.get(); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/OORTask.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/OORTask.java new file mode 100644 index 00000000..b4d1984b --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/OORTask.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.rotationstatus; + +import io.dropwizard.servlets.tasks.Task; +import lombok.extern.slf4j.Slf4j; + +import java.io.PrintWriter; +import java.util.List; +import java.util.Map; + +/** + * Admin task to take node oor in ranger + */ +@Slf4j +public class OORTask extends Task { + private final RotationStatus rotationStatus; + public OORTask(RotationStatus rotationStatus) { + super("ranger-oor"); + this.rotationStatus = rotationStatus; + } + + @Override + public void execute(Map> map, PrintWriter printWriter) { + rotationStatus.oor(); + log.info("Taking node out of rotation on ranger"); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/RotationStatus.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/RotationStatus.java new file mode 100644 index 00000000..369c1bcb --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/rotationstatus/RotationStatus.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.rotationstatus; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Current rotation status + */ +public class RotationStatus { + private final AtomicBoolean inRotation; + + public RotationStatus(boolean initialStatus) { + inRotation = new AtomicBoolean(initialStatus); + } + + public void oor() { + inRotation.set(false); + } + + public void bir() { + inRotation.set(true); + } + + public boolean status() { + return inRotation.get(); + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/selectors/HierarchicalEnvironmentAwareShardSelector.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/selectors/HierarchicalEnvironmentAwareShardSelector.java new file mode 100644 index 00000000..c3f442d3 --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/selectors/HierarchicalEnvironmentAwareShardSelector.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2022 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.selectors; + +import com.google.common.base.Strings; +import io.appform.ranger.common.server.ShardInfo; +import io.appform.ranger.core.finder.serviceregistry.MapBasedServiceRegistry; +import io.appform.ranger.core.model.ServiceNode; +import io.appform.ranger.core.model.ShardSelector; +import lombok.extern.slf4j.Slf4j; +import lombok.val; + +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * + */ +@Slf4j +public class HierarchicalEnvironmentAwareShardSelector implements ShardSelector> { + private static final String DEFAULT_SEPARATOR = "."; + private static final Predicate DEFAULT_PREDICATE = shardInfo -> true; + + private final String environment; + private final String separator; + + public HierarchicalEnvironmentAwareShardSelector(String environment) { + this(environment, DEFAULT_SEPARATOR); + } + + public HierarchicalEnvironmentAwareShardSelector(String environment, String separator) { + this.environment = environment; + this.separator = separator; + } + + @Override + public List> nodes( + Predicate criteria, MapBasedServiceRegistry serviceRegistry) { + val serviceNodes = serviceRegistry.nodes(); + val serviceName = serviceRegistry.getService().getServiceName(); + val evalPredicate = null != criteria + ? criteria + : DEFAULT_PREDICATE; + for (val env : new IterableEnvironment(environment, separator)) { + val eligibleNodes = serviceNodes.entries() + .stream() + .filter(e -> e.getKey().getEnvironment().equals(env.environment) && evalPredicate.test(e.getKey())) + .map(Map.Entry::getValue) + .collect(Collectors.toList()); + if (!eligibleNodes.isEmpty()) { + log.debug("Effective environment for discovery of {} is {}", serviceName, env.environment); + return eligibleNodes; + } + log.trace("No nodes found for environment: {}", env.environment); + } + log.warn("No valid nodes could be found for environment: {}", environment); + return Collections.emptyList(); + } + + private static final class IterableEnvironment implements Iterable { + private final String environment; + private final String separator; + + private IterableEnvironment(String environment, String separator) { + this.environment = environment; + this.separator = separator; + } + + @Override + public Iterator iterator() { + return new EnvironmentIterator(environment, separator); + } + + public static final class EnvironmentIterator implements Iterator { + + private String remainingEnvironment; + private final String separator; + + public EnvironmentIterator(String remainingEnvironment, String separator) { + this.remainingEnvironment = remainingEnvironment; + this.separator = separator; + } + + @Override + public boolean hasNext() { + return !Strings.isNullOrEmpty(remainingEnvironment); + } + + @Override + public IterableEnvironment next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + log.debug("Effective environment for discovery is {}", remainingEnvironment); + val shardInfo = new IterableEnvironment(remainingEnvironment, separator); + val sepIndex = remainingEnvironment.indexOf(this.separator); + remainingEnvironment = sepIndex < 0 + ? "" + : remainingEnvironment.substring(0, sepIndex); + return shardInfo; + } + } + } +} diff --git a/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/util/ConfigurationUtils.java b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/util/ConfigurationUtils.java new file mode 100644 index 00000000..ad1ca77b --- /dev/null +++ b/ranger-discovery-bundle/src/main/java/io/appform/ranger/discovery/bundle/util/ConfigurationUtils.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.util; + +import com.google.common.base.Strings; +import io.appform.ranger.discovery.bundle.Constants; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +import static io.appform.ranger.discovery.bundle.Constants.*; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ConfigurationUtils { + + public static String resolveNonEmptyPublishedHost(String publishedHost) throws UnknownHostException { + if (Strings.isNullOrEmpty(publishedHost) || publishedHost.equals(Constants.DEFAULT_HOST)) { + return InetAddress.getLocalHost() + .getCanonicalHostName(); + } + return publishedHost; + } + + public static Set resolveZookeeperHosts(String zkHostString) { + return Arrays.stream(zkHostString.split(ZOOKEEPER_HOST_DELIMITER)) + .map(zkHostPort -> zkHostPort.split(HOST_PORT_DELIMITER)[0]) + .map(zkHostPath -> zkHostPath.split(PATH_DELIMITER)[0]) + .collect(Collectors.toSet()); + } + +} diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleCustomHostPortTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleCustomHostPortTest.java new file mode 100644 index 00000000..12c2b9d3 --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleCustomHostPortTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.health.HealthCheckRegistry; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; +import io.dropwizard.Configuration; +import io.dropwizard.jersey.DropwizardResourceConfig; +import io.dropwizard.jersey.setup.JerseyEnvironment; +import io.dropwizard.jetty.ConnectorFactory; +import io.dropwizard.jetty.HttpConnectorFactory; +import io.dropwizard.lifecycle.setup.LifecycleEnvironment; +import io.dropwizard.server.DefaultServerFactory; +import io.dropwizard.setup.AdminEnvironment; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.curator.test.TestingCluster; +import org.eclipse.jetty.util.component.LifeCycle; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; + +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodeAbsence; +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodePresence; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + + +@Slf4j +class ServiceDiscoveryBundleCustomHostPortTest { + + static { + val root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + root.setLevel(Level.INFO); + } + + private final HealthCheckRegistry healthChecks = mock(HealthCheckRegistry.class); + private final JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class); + private final MetricRegistry metricRegistry = mock(MetricRegistry.class); + private final LifecycleEnvironment lifecycleEnvironment = new LifecycleEnvironment(metricRegistry); + private final Environment environment = mock(Environment.class); + private final Bootstrap bootstrap = mock(Bootstrap.class); + private final Configuration configuration = mock(Configuration.class); + private final DefaultServerFactory serverFactory = mock(DefaultServerFactory.class); + private final ConnectorFactory connectorFactory = mock(HttpConnectorFactory.class); + private final TestingCluster testingCluster = new TestingCluster(1); + private ServiceDiscoveryConfiguration serviceDiscoveryConfiguration; + private final ServiceDiscoveryBundle bundle = new ServiceDiscoveryBundle() { + @Override + protected ServiceDiscoveryConfiguration getRangerConfiguration(Configuration configuration) { + return serviceDiscoveryConfiguration; + } + + @Override + protected String getServiceName(Configuration configuration) { + return "TestService"; + } + + @Override + protected int getPort(Configuration configuration) { + return 21000; + } + + @Override + protected String getHost() { + return "CustomHost"; + } + + }; + private HealthcheckStatus status = HealthcheckStatus.healthy; + + @BeforeEach + void setup() throws Exception { + when(serverFactory.getApplicationConnectors()).thenReturn(Lists.newArrayList(connectorFactory)); + when(configuration.getServerFactory()).thenReturn(serverFactory); + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + testingCluster.start(); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper(testingCluster.getConnectString()) + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("TestHost") + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + bundle.initialize(bootstrap); + bundle.run(configuration, environment); + bundle.getServerStatus() + .markStarted(); + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.start(); + } + bundle.registerHealthcheck(() -> status); + + } + + @AfterEach + void tearDown() throws Exception { + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.stop(); + } + testingCluster.stop(); + } + + @Test + void testDiscovery() { + assertNodePresence(bundle); + val info = bundle.getServiceDiscoveryClient() + .getNode() + .orElse(null); + + Assertions.assertNotNull(info); + Assertions.assertNotNull(info.getNodeData()); + Assertions.assertEquals("testing", info.getNodeData() + .getEnvironment()); + Assertions.assertEquals("CustomHost", info.getHost()); + Assertions.assertEquals(21000, info.getPort()); + status = HealthcheckStatus.unhealthy; + + assertNodeAbsence(bundle); + } +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleDwMonitorTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleDwMonitorTest.java new file mode 100644 index 00000000..80bf6ab8 --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleDwMonitorTest.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.health.HealthCheck; +import com.codahale.metrics.health.HealthCheckRegistry; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; +import io.dropwizard.Configuration; +import io.dropwizard.jersey.DropwizardResourceConfig; +import io.dropwizard.jersey.setup.JerseyEnvironment; +import io.dropwizard.jetty.ConnectorFactory; +import io.dropwizard.jetty.HttpConnectorFactory; +import io.dropwizard.lifecycle.setup.LifecycleEnvironment; +import io.dropwizard.server.DefaultServerFactory; +import io.dropwizard.setup.AdminEnvironment; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.curator.test.TestingCluster; +import org.eclipse.jetty.util.component.LifeCycle; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.atomic.AtomicInteger; + +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodeAbsence; +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodePresence; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + + +@Slf4j +class ServiceDiscoveryBundleDwMonitorTest { + + static { + val root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + root.setLevel(Level.INFO); + } + + private final HealthCheckRegistry healthChecks = new HealthCheckRegistry(); + private final JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class); + private final MetricRegistry metricRegistry = mock(MetricRegistry.class); + private final LifecycleEnvironment lifecycleEnvironment = new LifecycleEnvironment(metricRegistry); + private final Environment environment = mock(Environment.class); + private final Bootstrap bootstrap = mock(Bootstrap.class); + private final Configuration configuration = mock(Configuration.class); + private final DefaultServerFactory serverFactory = mock(DefaultServerFactory.class); + private final ConnectorFactory connectorFactory = mock(HttpConnectorFactory.class); + private final TestingCluster testingCluster = new TestingCluster(1); + private final HealthcheckStatus status = HealthcheckStatus.healthy; + private ServiceDiscoveryConfiguration serviceDiscoveryConfiguration; + private final ServiceDiscoveryBundle bundle = new ServiceDiscoveryBundle() { + @Override + protected ServiceDiscoveryConfiguration getRangerConfiguration(Configuration configuration) { + return serviceDiscoveryConfiguration; + } + + @Override + protected String getServiceName(Configuration configuration) { + return "TestService"; + } + + @Override + protected int getPort(Configuration configuration) { + return 21000; + } + + @Override + protected String getHost() { + return "CustomHost"; + } + + }; + + @BeforeEach + void setup() throws Exception { + healthChecks.register("twice-healthy-only", new HealthCheck() { + private final AtomicInteger counter = new AtomicInteger(5); + + @Override + protected Result check() { + val result = (counter.decrementAndGet() < 0) + ? Result.unhealthy("unhealthy") + : Result.healthy(); + log.info("Marking node as {}", result.isHealthy()); + return result; + } + }); + + when(serverFactory.getApplicationConnectors()).thenReturn(Lists.newArrayList(connectorFactory)); + when(configuration.getServerFactory()).thenReturn(serverFactory); + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + testingCluster.start(); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper(testingCluster.getConnectString()) + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("TestHost") + .publishedPort(8021) + .initialRotationStatus(true) + .dropwizardCheckInterval(2) + .dropwizardCheckStaleness(2) + .build(); + bundle.initialize(bootstrap); + bundle.run(configuration, environment); + bundle.getServerStatus() + .markStarted(); + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.start(); + } + bundle.registerHealthcheck(() -> status); + } + + @AfterEach + void tearDown() throws Exception { + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.stop(); + } + testingCluster.stop(); + } + + @Test + void testDiscovery() { + assertNodePresence(bundle); + val info = bundle.getServiceDiscoveryClient() + .getNode() + .orElse(null); + Assertions.assertNotNull(info); + Assertions.assertNotNull(info.getNodeData()); + Assertions.assertEquals("testing", info.getNodeData() + .getEnvironment()); + Assertions.assertEquals("CustomHost", info.getHost()); + Assertions.assertEquals(21000, info.getPort()); + + /* after 5 turns, the healthcheck will return unhealthy, and since dropwizardCheckInterval + is 5 seconds, within 2*5=10 seconds, nodes should be absent */ + assertNodeAbsence(bundle); + } +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleDwStalenessMonitorTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleDwStalenessMonitorTest.java new file mode 100644 index 00000000..64d4d1ad --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleDwStalenessMonitorTest.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.health.HealthCheck; +import com.codahale.metrics.health.HealthCheckRegistry; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; +import io.dropwizard.Configuration; +import io.dropwizard.jersey.DropwizardResourceConfig; +import io.dropwizard.jersey.setup.JerseyEnvironment; +import io.dropwizard.jetty.ConnectorFactory; +import io.dropwizard.jetty.HttpConnectorFactory; +import io.dropwizard.lifecycle.setup.LifecycleEnvironment; +import io.dropwizard.server.DefaultServerFactory; +import io.dropwizard.setup.AdminEnvironment; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.curator.test.TestingCluster; +import org.eclipse.jetty.util.component.LifeCycle; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.atomic.AtomicBoolean; + +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodeAbsence; +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodePresence; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + + +@Slf4j +class ServiceDiscoveryBundleDwStalenessMonitorTest { + + static { + val root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + root.setLevel(Level.INFO); + } + + private final HealthCheckRegistry healthChecks = new HealthCheckRegistry(); + private final JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class); + private final MetricRegistry metricRegistry = mock(MetricRegistry.class); + private final LifecycleEnvironment lifecycleEnvironment = new LifecycleEnvironment(metricRegistry); + private final Environment environment = mock(Environment.class); + private final Bootstrap bootstrap = mock(Bootstrap.class); + private final Configuration configuration = mock(Configuration.class); + private final DefaultServerFactory serverFactory = mock(DefaultServerFactory.class); + private final ConnectorFactory connectorFactory = mock(HttpConnectorFactory.class); + private final TestingCluster testingCluster = new TestingCluster(1); + private final AtomicBoolean healthySucceeded = new AtomicBoolean(false); + private ServiceDiscoveryConfiguration serviceDiscoveryConfiguration; + private final ServiceDiscoveryBundle bundle = new ServiceDiscoveryBundle() { + @Override + protected ServiceDiscoveryConfiguration getRangerConfiguration(Configuration configuration) { + return serviceDiscoveryConfiguration; + } + + @Override + protected String getServiceName(Configuration configuration) { + return "TestService"; + } + + @Override + protected int getPort(Configuration configuration) { + return 21000; + } + + @Override + protected String getHost() { + return "CustomHost"; + } + + }; + + @BeforeEach + void setup() throws Exception { + healthChecks.register("healthy-once-but-then-sleep5", new HealthCheck() { + + @Override + protected Result check() { + if (healthySucceeded.get()) { + return Result.unhealthy("Forced unhealthy as healthy check has succeded"); + } + return Result.healthy(); + } + }); + + when(serverFactory.getApplicationConnectors()).thenReturn(Lists.newArrayList(connectorFactory)); + when(configuration.getServerFactory()).thenReturn(serverFactory); + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + testingCluster.start(); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper(testingCluster.getConnectString()) + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("TestHost") + .publishedPort(8021) + .initialRotationStatus(true) + .dropwizardCheckInterval(6) + .dropwizardCheckStaleness(6) + .build(); + bundle.initialize(bootstrap); + bundle.run(configuration, environment); + bundle.getServerStatus() + .markStarted(); + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.start(); + } + bundle.registerHealthcheck(() -> HealthcheckStatus.healthy); + } + + @AfterEach + void tearDown() throws Exception { + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.stop(); + } + testingCluster.stop(); + } + + @Test + void testDiscovery() { + assertNodePresence(bundle); + val info = bundle.getServiceDiscoveryClient() + .getNode() + .orElse(null); + Assertions.assertNotNull(info); + Assertions.assertNotNull(info.getNodeData()); + Assertions.assertEquals("testing", info.getNodeData() + .getEnvironment()); + Assertions.assertEquals("CustomHost", info.getHost()); + Assertions.assertEquals(21000, info.getPort()); + healthySucceeded.set(true); + + /* once the first check has succeeded it should get unhealthy and hence no node */ + assertNodeAbsence(bundle); + healthySucceeded.set(false); + + /* again mark healthy and check */ + + assertNodePresence(bundle); + } +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleHierarchicalSelectorTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleHierarchicalSelectorTest.java new file mode 100644 index 00000000..decb76fc --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleHierarchicalSelectorTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import com.alibaba.dcm.DnsCacheManipulator; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.health.HealthCheckRegistry; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; +import io.appform.ranger.discovery.bundle.util.ConfigurationUtils; +import io.dropwizard.Configuration; +import io.dropwizard.jersey.DropwizardResourceConfig; +import io.dropwizard.jersey.setup.JerseyEnvironment; +import io.dropwizard.jetty.ConnectorFactory; +import io.dropwizard.jetty.HttpConnectorFactory; +import io.dropwizard.lifecycle.setup.LifecycleEnvironment; +import io.dropwizard.server.DefaultServerFactory; +import io.dropwizard.setup.AdminEnvironment; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.curator.test.TestingCluster; +import org.eclipse.jetty.util.component.LifeCycle; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; + +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodeAbsence; +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodePresence; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + + +@Slf4j +class ServiceDiscoveryBundleHierarchicalSelectorTest { + + static { + val root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + root.setLevel(Level.INFO); + } + + private final HealthCheckRegistry healthChecks = mock(HealthCheckRegistry.class); + private final JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class); + private final MetricRegistry metricRegistry = mock(MetricRegistry.class); + private final LifecycleEnvironment lifecycleEnvironment = new LifecycleEnvironment(metricRegistry); + private final Environment environment = mock(Environment.class); + private final Bootstrap bootstrap = mock(Bootstrap.class); + private final Configuration configuration = mock(Configuration.class); + private final DefaultServerFactory serverFactory = mock(DefaultServerFactory.class); + private final ConnectorFactory connectorFactory = mock(HttpConnectorFactory.class); + private final TestingCluster testingCluster = new TestingCluster(1); + private ServiceDiscoveryConfiguration serviceDiscoveryConfiguration; + private final ServiceDiscoveryBundle bundle = new ServiceDiscoveryBundle() { + @Override + protected ServiceDiscoveryConfiguration getRangerConfiguration(TestConfig configuration) { + return serviceDiscoveryConfiguration; + } + + @Override + protected String getServiceName(TestConfig configuration) { + return "TestService"; + } + }; + private HealthcheckStatus status = HealthcheckStatus.healthy; + + @BeforeEach + void setup() throws Exception { + when(serverFactory.getApplicationConnectors()).thenReturn(Lists.newArrayList(connectorFactory)); + when(configuration.getServerFactory()).thenReturn(serverFactory); + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + testingCluster.start(); + + DnsCacheManipulator.setDnsCache("TestHost", "127.0.0.1"); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper(testingCluster.getConnectString()) + .namespace("test") + .environment("x.y") + .connectionRetryIntervalMillis(5000) + .publishedHost("TestHost") + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + ConfigurationUtils.resolveZookeeperHosts(serviceDiscoveryConfiguration.getZookeeper()) + .forEach(zkHost -> { + DnsCacheManipulator.setDnsCache(zkHost, "127.0.0.1"); + }); + val testConfig = new TestConfig(serviceDiscoveryConfiguration); + testConfig.setServerFactory(serverFactory); + bundle.initialize(bootstrap); + bundle.run(testConfig, environment); + bundle.getServerStatus() + .markStarted(); + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.start(); + } + bundle.registerHealthcheck(() -> status); + } + + @AfterEach + void tearDown() throws Exception { + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.stop(); + } + testingCluster.stop(); + } + + @Test + void testDiscovery() { + assertNodePresence(bundle); + val info = bundle.getServiceDiscoveryClient() + .getNode() + .orElse(null); + Assertions.assertNotNull(info); + Assertions.assertNotNull(info.getNodeData()); + Assertions.assertEquals("x.y", info.getNodeData() + .getEnvironment()); + Assertions.assertEquals("TestHost", info.getHost()); + Assertions.assertEquals(8021, info.getPort()); + + status = HealthcheckStatus.unhealthy; + + assertNodeAbsence(bundle); + } + + private static final class TestConfig extends Configuration { + + @Getter + private final ServiceDiscoveryConfiguration configuration; + + private TestConfig(ServiceDiscoveryConfiguration configuration) { + this.configuration = configuration; + } + + } +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleLocalHostPortTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleLocalHostPortTest.java new file mode 100644 index 00000000..d0db400a --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleLocalHostPortTest.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import com.alibaba.dcm.DnsCacheManipulator; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.health.HealthCheckRegistry; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.appform.ranger.discovery.bundle.util.ConfigurationUtils; +import io.dropwizard.Configuration; +import io.dropwizard.jersey.DropwizardResourceConfig; +import io.dropwizard.jersey.setup.JerseyEnvironment; +import io.dropwizard.lifecycle.setup.LifecycleEnvironment; +import io.dropwizard.setup.AdminEnvironment; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.net.UnknownHostException; +import java.util.UUID; + +import static io.appform.ranger.discovery.bundle.Constants.LOCAL_ADDRESSES; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + + +@Slf4j +class ServiceDiscoveryBundleLocalHostPortTest { + + private final HealthCheckRegistry healthChecks = mock(HealthCheckRegistry.class); + private final JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class); + private final MetricRegistry metricRegistry = mock(MetricRegistry.class); + private final LifecycleEnvironment lifecycleEnvironment = new LifecycleEnvironment(metricRegistry); + private final Environment environment = mock(Environment.class); + private final Bootstrap bootstrap = mock(Bootstrap.class); + private final Configuration configuration = mock(Configuration.class); + + private final ServiceDiscoveryBundle bundle = new ServiceDiscoveryBundle() { + @Override + protected ServiceDiscoveryConfiguration getRangerConfiguration(Configuration configuration) { + return serviceDiscoveryConfiguration; + } + + @Override + protected String getServiceName(Configuration configuration) { + return "TestService"; + } + + + }; + + @AfterEach + public void afterMethod() { + DnsCacheManipulator.clearDnsCache(); + } + + private ServiceDiscoveryConfiguration serviceDiscoveryConfiguration; + + + @Test + void shouldFailLocalhostPublish() { + DnsCacheManipulator.setDnsCache("myzookeeper", "19.10.1.1"); + DnsCacheManipulator.setDnsCache("myfavzookeeper", "127.0.0.1"); + DnsCacheManipulator.setDnsCache("custom-host", "127.0.0.1"); + + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper("myzookeeper:2181,myfavzookeeper:2181") + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("custom-host") + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + bundle.initialize(bootstrap); + assertLocalHostNotAllowed(); + + } + + @Test + void shouldThrowExceptionForInvalidZkHost() { + DnsCacheManipulator.setDnsCache("custom-host", "127.0.0.1"); + + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper(String.format("%s:2181", UUID.randomUUID())) + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("custom-host") + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + bundle.initialize(bootstrap); + + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> { + bundle.run(configuration, environment); + + }); + + assertTrue(thrown.getMessage() + .contains("Couldn't resolve host address for zkHost")); + + } + + @Test + void testPublishWithEmptyZkHost() throws UnknownHostException { + DnsCacheManipulator.setDnsCache("myzookeeper", "19.10.1.1"); + DnsCacheManipulator.setDnsCache("myfavzookeeper", "127.0.0.1"); + DnsCacheManipulator.setDnsCache("custom-host", "127.0.0.1"); + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper("myzookeeper:2181,myfavzookeeper:2181") + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("") + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + bundle.initialize(bootstrap); + + String publishedHost = ConfigurationUtils.resolveNonEmptyPublishedHost( + serviceDiscoveryConfiguration.getPublishedHost()); + if (LOCAL_ADDRESSES.contains(publishedHost)) { + assertLocalHostNotAllowed(); + } else { + assertDoesNotThrow(); + } + } + + @Test + void testPublishWithNullZkHost() throws UnknownHostException { + DnsCacheManipulator.setDnsCache("myzookeeper", "19.10.1.1"); + DnsCacheManipulator.setDnsCache("myfavzookeeper", "127.0.0.1"); + DnsCacheManipulator.setDnsCache("custom-host", "127.0.0.1"); + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper("myzookeeper:2181,myfavzookeeper:2181") + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + bundle.initialize(bootstrap); + + String publishedHost = ConfigurationUtils.resolveNonEmptyPublishedHost( + serviceDiscoveryConfiguration.getPublishedHost()); + if (LOCAL_ADDRESSES.contains(publishedHost)) { + assertLocalHostNotAllowed(); + } else { + assertDoesNotThrow(); + } + } + + @Test + void shouldPublishingToLocalZk() { + DnsCacheManipulator.setDnsCache("myfavzookeeper", "127.0.0.1"); + DnsCacheManipulator.setDnsCache("custom-host", "127.0.0.1"); + + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper("localhost:2181,myfavzookeeper:2181") + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("localhost") + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + bundle.initialize(bootstrap); + + assertDoesNotThrow(); + + } + + @Test + void shouldPublishToRemoteZk() { + DnsCacheManipulator.setDnsCache("myfavzookeeper", "17.4.0.1"); + DnsCacheManipulator.setDnsCache("custom-host", "17.1.2.1"); + + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper("myfavzookeeper:2181") + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("custom-host") + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + bundle.initialize(bootstrap); + + assertDoesNotThrow(); + } + + private void assertLocalHostNotAllowed() { + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> { + bundle.run(configuration, environment); + + }); + assertTrue(thrown.getMessage() + .contains("Not allowed to publish localhost address to remote zookeeper")); + } + + + private void assertDoesNotThrow() { + Assertions.assertDoesNotThrow(() -> { + bundle.run(configuration, environment); + }); + } + +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleRotationTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleRotationTest.java new file mode 100644 index 00000000..98b457d9 --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleRotationTest.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import com.alibaba.dcm.DnsCacheManipulator; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.health.HealthCheckRegistry; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import io.appform.ranger.discovery.bundle.rotationstatus.BIRTask; +import io.appform.ranger.discovery.bundle.rotationstatus.OORTask; +import io.appform.ranger.discovery.bundle.rotationstatus.RotationStatus; +import io.appform.ranger.discovery.bundle.util.ConfigurationUtils; +import io.dropwizard.Configuration; +import io.dropwizard.jersey.DropwizardResourceConfig; +import io.dropwizard.jersey.setup.JerseyEnvironment; +import io.dropwizard.jetty.ConnectorFactory; +import io.dropwizard.jetty.HttpConnectorFactory; +import io.dropwizard.lifecycle.setup.LifecycleEnvironment; +import io.dropwizard.server.DefaultServerFactory; +import io.dropwizard.setup.AdminEnvironment; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.curator.test.TestingCluster; +import org.eclipse.jetty.util.component.LifeCycle; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; + +import java.util.Collections; + +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodeAbsence; +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodePresence; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + + +@Slf4j +class ServiceDiscoveryBundleRotationTest { + + static { + val root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + root.setLevel(Level.INFO); + } + + private final HealthCheckRegistry healthChecks = mock(HealthCheckRegistry.class); + private final JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class); + private final MetricRegistry metricRegistry = mock(MetricRegistry.class); + private final LifecycleEnvironment lifecycleEnvironment = new LifecycleEnvironment(metricRegistry); + private final Environment environment = mock(Environment.class); + private final Bootstrap bootstrap = mock(Bootstrap.class); + private final Configuration configuration = mock(Configuration.class); + private final DefaultServerFactory serverFactory = mock(DefaultServerFactory.class); + private final ConnectorFactory connectorFactory = mock(HttpConnectorFactory.class); + private final TestingCluster testingCluster = new TestingCluster(1); + private ServiceDiscoveryConfiguration serviceDiscoveryConfiguration; + private final ServiceDiscoveryBundle bundle = new ServiceDiscoveryBundle() { + @Override + protected ServiceDiscoveryConfiguration getRangerConfiguration(Configuration configuration) { + return serviceDiscoveryConfiguration; + } + + @Override + protected String getServiceName(Configuration configuration) { + return "TestService"; + } + + }; + private RotationStatus rotationStatus; + + @BeforeEach + void setup() throws Exception { + when(serverFactory.getApplicationConnectors()).thenReturn(Lists.newArrayList(connectorFactory)); + when(configuration.getServerFactory()).thenReturn(serverFactory); + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + testingCluster.start(); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper(testingCluster.getConnectString()) + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("TestHost") + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + + DnsCacheManipulator.setDnsCache("TestHost", "127.0.0.1"); + ConfigurationUtils.resolveZookeeperHosts(serviceDiscoveryConfiguration.getZookeeper()) + .forEach(zkHost -> { + DnsCacheManipulator.setDnsCache(zkHost, "127.0.0.1"); + }); + bundle.initialize(bootstrap); + bundle.run(configuration, environment); + rotationStatus = bundle.getRotationStatus(); + bundle.getServerStatus() + .markStarted(); + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.start(); + } + } + + @AfterEach + void tearDown() throws Exception { + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.stop(); + } + testingCluster.stop(); + } + + @Test + void testDiscovery() { + assertNodePresence(bundle); + val info = bundle.getServiceDiscoveryClient() + .getNode() + .orElse(null); + Assertions.assertNotNull(info); + Assertions.assertNotNull(info.getNodeData()); + Assertions.assertEquals("testing", info.getNodeData() + .getEnvironment()); + Assertions.assertEquals("TestHost", info.getHost()); + Assertions.assertEquals(8021, info.getPort()); + + val oorTask = new OORTask(rotationStatus); + oorTask.execute(Collections.emptyMap(), null); + + assertNodeAbsence(bundle); + + val birTask = new BIRTask(rotationStatus); + birTask.execute(Collections.emptyMap(), null); + + assertNodePresence(bundle); + } +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleTest.java new file mode 100644 index 00000000..844a1073 --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/ServiceDiscoveryBundleTest.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2019 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import com.alibaba.dcm.DnsCacheManipulator; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.health.HealthCheckRegistry; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; +import io.appform.ranger.discovery.bundle.resolvers.DefaultNodeInfoResolver; +import io.appform.ranger.discovery.bundle.resolvers.NodeInfoResolver; +import io.appform.ranger.discovery.bundle.util.ConfigurationUtils; +import io.dropwizard.Configuration; +import io.dropwizard.jersey.DropwizardResourceConfig; +import io.dropwizard.jersey.setup.JerseyEnvironment; +import io.dropwizard.jetty.ConnectorFactory; +import io.dropwizard.jetty.HttpConnectorFactory; +import io.dropwizard.lifecycle.setup.LifecycleEnvironment; +import io.dropwizard.server.DefaultServerFactory; +import io.dropwizard.setup.AdminEnvironment; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.curator.test.TestingCluster; +import org.eclipse.jetty.util.component.LifeCycle; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; + +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodeAbsence; +import static io.appform.ranger.discovery.bundle.TestUtils.assertNodePresence; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + + +@Slf4j +class ServiceDiscoveryBundleTest { + + static { + val root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + root.setLevel(Level.INFO); + } + + private final HealthCheckRegistry healthChecks = mock(HealthCheckRegistry.class); + private final JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class); + private final MetricRegistry metricRegistry = mock(MetricRegistry.class); + private final LifecycleEnvironment lifecycleEnvironment = new LifecycleEnvironment(metricRegistry); + private final Environment environment = mock(Environment.class); + private final Bootstrap bootstrap = mock(Bootstrap.class); + private final Configuration configuration = mock(Configuration.class); + private final DefaultServerFactory serverFactory = mock(DefaultServerFactory.class); + private final ConnectorFactory connectorFactory = mock(HttpConnectorFactory.class); + private final TestingCluster testingCluster = new TestingCluster(1); + private ServiceDiscoveryConfiguration serviceDiscoveryConfiguration; + private final ServiceDiscoveryBundle bundle = new ServiceDiscoveryBundle() { + @Override + protected ServiceDiscoveryConfiguration getRangerConfiguration(Configuration configuration) { + return serviceDiscoveryConfiguration; + } + + @Override + protected String getServiceName(Configuration configuration) { + return "TestService"; + } + + @Override + protected NodeInfoResolver createNodeInfoResolver() { + return new DefaultNodeInfoResolver(); + } + }; + private HealthcheckStatus status = HealthcheckStatus.healthy; + + @BeforeEach + void setup() throws Exception { + when(serverFactory.getApplicationConnectors()).thenReturn(Lists.newArrayList(connectorFactory)); + when(configuration.getServerFactory()).thenReturn(serverFactory); + when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(environment.jersey()).thenReturn(jerseyEnvironment); + when(environment.lifecycle()).thenReturn(lifecycleEnvironment); + when(environment.healthChecks()).thenReturn(healthChecks); + when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); + doNothing().when(adminEnvironment) + .addTask(any()); + when(environment.admin()).thenReturn(adminEnvironment); + + testingCluster.start(); + + serviceDiscoveryConfiguration = ServiceDiscoveryConfiguration.builder() + .zookeeper(testingCluster.getConnectString()) + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("TestHost") + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + + DnsCacheManipulator.setDnsCache("TestHost", "127.0.0.1"); + ConfigurationUtils.resolveZookeeperHosts(serviceDiscoveryConfiguration.getZookeeper()) + .forEach(zkHost -> { + DnsCacheManipulator.setDnsCache(zkHost, "127.0.0.1"); + }); + + bundle.initialize(bootstrap); + bundle.run(configuration, environment); + bundle.getServerStatus() + .markStarted(); + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.start(); + } + bundle.registerHealthcheck(() -> status); + } + + @AfterEach + void tearDown() throws Exception { + for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + lifeCycle.stop(); + } + testingCluster.stop(); + } + + @Test + void testDiscovery() { + assertNodePresence(bundle); + val info = bundle.getServiceDiscoveryClient() + .getNode() + .orElse(null); + Assertions.assertNotNull(info); + Assertions.assertNotNull(info.getNodeData()); + Assertions.assertEquals("testing", info.getNodeData() + .getEnvironment()); + Assertions.assertEquals("TestHost", info.getHost()); + Assertions.assertEquals(8021, info.getPort()); + Assertions.assertNull(info.getNodeData() + .getRegion()); + + status = HealthcheckStatus.unhealthy; + + assertNodeAbsence(bundle); + } +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/TestUtils.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/TestUtils.java new file mode 100644 index 00000000..1c9663d7 --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/TestUtils.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle; + +import io.dropwizard.Configuration; +import lombok.experimental.UtilityClass; +import org.awaitility.Awaitility; + +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + + +/** + * + */ +@UtilityClass +public class TestUtils { + public static void assertNodePresence(ServiceDiscoveryBundle bundle) { + Awaitility.await() + .pollInterval(Duration.ofSeconds(1)) + .atMost(Duration.ofSeconds(30)) + .untilAsserted(() -> assertNotNull(bundle.getServiceDiscoveryClient() + .getNode() + .orElse(null))); + } + public static void assertNodeAbsence(ServiceDiscoveryBundle bundle) { + Awaitility.await() + .pollInterval(Duration.ofSeconds(1)) + .atMost(Duration.ofSeconds(30)) + .untilAsserted(() -> assertNull(bundle.getServiceDiscoveryClient() + .getNode() + .orElse(null))); + } +} diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/BenchmarkTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/BenchmarkTest.java new file mode 100644 index 00000000..fd8fdd11 --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/BenchmarkTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import lombok.val; +import org.junit.jupiter.api.Test; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.OptionsBuilder; +import org.openjdk.jmh.runner.options.TimeValue; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +public abstract class BenchmarkTest { + + public static final ObjectMapper mapper = new ObjectMapper(); + + @Test + void testBenchmark() throws RunnerException { + val opt = new OptionsBuilder() + .include(String.format("%s.*", this.getClass().getName())) + .mode(Mode.Throughput) + .timeUnit(TimeUnit.SECONDS) + .warmupTime(TimeValue.seconds(5)) + .warmupIterations(1) + .measurementTime(TimeValue.seconds(5)) + .measurementIterations(4) + .threads(1) + .forks(3) + .shouldFailOnError(true) + .shouldDoGC(true) + .build(); + val results = new Runner(opt).run(); + results.iterator() + .forEachRemaining(new Consumer() { + @SneakyThrows + @Override + public void accept(RunResult runResult) { + val benchmarkName = runResult.getParams().getBenchmark(); + val outputFilePath = Paths.get(String.format("perf/results/%s.json", benchmarkName)); + val outputNode = mapper.createObjectNode(); + outputNode.put("name", benchmarkName); + outputNode.put("mode", runResult.getParams().getMode().name()); + outputNode.put("iterations", runResult.getParams().getMeasurement().getCount()); + outputNode.put("threads", runResult.getParams().getThreads()); + outputNode.put("forks", runResult.getParams().getForks()); + outputNode.put("mean_ops", runResult.getPrimaryResult().getStatistics().getMean()); + Files.write(outputFilePath, mapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(outputNode)); + } + }); + } + + +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/CollisionCheckerTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/CollisionCheckerTest.java new file mode 100644 index 00000000..8342a787 --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/CollisionCheckerTest.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id; + + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.stream.IntStream; + +/** + * Test on {@link CollisionChecker} + */ +class CollisionCheckerTest { + + @Test + void testCheck() { + CollisionChecker collisionChecker = new CollisionChecker(); + Assertions.assertTrue(collisionChecker.check(100, 1)); + Assertions.assertFalse(collisionChecker.check(100, 1)); + IntStream.range(0, 1000).forEach(i -> { + Assertions.assertTrue(collisionChecker.check(101, i)); + Assertions.assertFalse(collisionChecker.check(101, i)); + }); + } +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/IdGeneratorPerfTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/IdGeneratorPerfTest.java new file mode 100644 index 00000000..55f6cd92 --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/IdGeneratorPerfTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2022. Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id; + +import io.appform.ranger.discovery.bundle.id.formatter.IdFormatters; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.io.IOException; + +/** + * Test performance between different constructs + */ +@Slf4j +public class IdGeneratorPerfTest extends BenchmarkTest { + + @State(Scope.Benchmark) + public static class BenchmarkState { + + @Setup(Level.Trial) + public void setUp() throws IOException { + IdGenerator.initialize(23); + } + } + + @SneakyThrows + @Benchmark + public void testGenerateBase36(Blackhole blackhole, BenchmarkState state) { + IdGenerator.generate("X", IdFormatters.base36()); + } + + @SneakyThrows + @Benchmark + public void testGenerate(Blackhole blackhole, BenchmarkState state) { + IdGenerator.generate("X", IdFormatters.original()); + } +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/IdGeneratorTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/IdGeneratorTest.java new file mode 100644 index 00000000..0089eaac --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/id/IdGeneratorTest.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2016 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.id; + +import com.google.common.collect.ImmutableList; +import io.appform.ranger.discovery.bundle.id.constraints.IdValidationConstraint; +import io.appform.ranger.discovery.bundle.id.constraints.impl.JavaHashCodeBasedKeyPartitioner; +import io.appform.ranger.discovery.bundle.id.constraints.impl.PartitionValidator; +import io.appform.ranger.discovery.bundle.id.formatter.IdFormatters; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.time.*; +import java.util.Collections; +import java.util.Date; +import java.util.Optional; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * Test for {@link IdGenerator} + */ +@Slf4j +@SuppressWarnings({"unused", "FieldMayBeFinal"}) +class IdGeneratorTest { + + @Getter + private static final class Runner implements Callable { + private boolean stop = false; + private long count = 0L; + + @Override + public Long call() { + while (!stop) { + val id = IdGenerator.generate("X"); + count++; + } + return count; + } + } + + @Getter + private static final class ConstraintRunner implements Callable { + private final IdValidationConstraint constraint; + private boolean stop = false; + private long count = 0L; + + private ConstraintRunner(IdValidationConstraint constraint) { + this.constraint = constraint; + } + + @Override + public Long call() { + while (!stop) { + Optional id = IdGenerator.generateWithConstraints("X", Collections.singletonList(constraint)); + Assertions.assertTrue(id.isPresent()); + count++; + } + return count; + } + } + + @Test + void testGenerate() { + IdGenerator.initialize(23); + val numRunners = 20; + val runners = IntStream.range(0, numRunners).mapToObj(i -> new Runner()).collect(Collectors.toList()); + val executorService = Executors.newFixedThreadPool(numRunners); + runners.forEach(executorService::submit); + Awaitility.await() + .pollInterval(Duration.ofSeconds(10)) + .timeout(Duration.ofSeconds(11)) + .until(() -> true); + executorService.shutdownNow(); + val totalCount = runners.stream().mapToLong(Runner::getCount).sum(); + log.debug("Generated ID count: {}", totalCount); + log.debug("Generated ID rate: {}/sec", totalCount / 10); + Assertions.assertTrue(totalCount > 0); + } + + @Test + void testGenerateOriginal() { + IdGenerator.initialize(23); + String id = IdGenerator.generate("TEST", IdFormatters.original()).getId(); + Assertions.assertEquals(26, id.length()); + } + + @Test + void testGenerateBase36() { + IdGenerator.initialize(23); + String id = IdGenerator.generate("TEST", IdFormatters.base36()).getId(); + Assertions.assertEquals(18, id.length()); + } + + + @Test + void testGenerateWithConstraintsNoConstraint() { + IdGenerator.initialize(23); + int numRunners = 20; + + val runners = IntStream.range(0, numRunners).mapToObj(i -> new ConstraintRunner(new PartitionValidator(4, new JavaHashCodeBasedKeyPartitioner(16)))).collect(Collectors.toList()); + val executorService = Executors.newFixedThreadPool(numRunners); + runners.forEach(executorService::submit); + Awaitility.await() + .pollInterval(Duration.ofSeconds(10)) + .timeout(Duration.ofSeconds(11)) + .until(() -> true); + executorService.shutdownNow(); + val totalCount = runners.stream().mapToLong(ConstraintRunner::getCount).sum(); + log.debug("Generated ID count: {}", totalCount); + log.debug("Generated ID rate: {}/sec", totalCount / 10); + Assertions.assertTrue(totalCount > 0); + + } + + @Test + void testConstraintFailure() { + IdGenerator.initialize(23); + Assertions.assertFalse(IdGenerator.generateWithConstraints( + "TST", + ImmutableList.of(id -> false), + false).isPresent()); + } + + @Test + void testParseFailure() { + //Null or Empty String + Assertions.assertFalse(IdGenerator.parse(null).isPresent()); + Assertions.assertFalse(IdGenerator.parse("").isPresent()); + + //Invalid length + Assertions.assertFalse(IdGenerator.parse("TEST").isPresent()); + + //Invalid chars + Assertions.assertFalse(IdGenerator.parse("XCL983dfb1ee0a847cd9e7321fcabc2f223").isPresent()); + Assertions.assertFalse(IdGenerator.parse("XCL98-3df-b1e:e0a847cd9e7321fcabc2f223").isPresent()); + + //Invalid month + Assertions.assertFalse(IdGenerator.parse("ABC2032250959030643972247").isPresent()); + //Invalid date + Assertions.assertFalse(IdGenerator.parse("ABC2011450959030643972247").isPresent()); + //Invalid hour + Assertions.assertFalse(IdGenerator.parse("ABC2011259659030643972247").isPresent()); + //Invalid minute + Assertions.assertFalse(IdGenerator.parse("ABC2011250972030643972247").isPresent()); + //Invalid sec + Assertions.assertFalse(IdGenerator.parse("ABC2011250959720643972247").isPresent()); + } + + @Test + void testParseSuccess() { + val idString = "ABC2011250959030643972247"; + val id = IdGenerator.parse(idString).orElse(null); + Assertions.assertNotNull(id); + Assertions.assertEquals(idString, id.getId()); + Assertions.assertEquals(247, id.getExponent()); + Assertions.assertEquals(3972, id.getNode()); + Assertions.assertEquals(generateDate(2020, 11, 25, 9, 59, 3, 64, ZoneId.systemDefault()), + id.getGeneratedDate()); + } + + @Test + void testParseSuccessAfterGeneration() { + val generatedId = IdGenerator.generate("TEST123"); + val parsedId = IdGenerator.parse(generatedId.getId()).orElse(null); + Assertions.assertNotNull(parsedId); + Assertions.assertEquals(parsedId.getId(), generatedId.getId()); + Assertions.assertEquals(parsedId.getExponent(), generatedId.getExponent()); + Assertions.assertEquals(parsedId.getNode(), generatedId.getNode()); + Assertions.assertEquals(parsedId.getGeneratedDate(), generatedId.getGeneratedDate()); + } + + + @SuppressWarnings("SameParameterValue") + private Date generateDate(int year, int month, int day, int hour, int min, int sec, int ms, ZoneId zoneId) { + return Date.from( + Instant.from( + ZonedDateTime.of( + LocalDateTime.of( + year, month, day, hour, min, sec, Math.multiplyExact(ms, 1000000) + ), + zoneId + ) + ) + ); + } + + +} \ No newline at end of file diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/resolvers/DefaultNodeInfoResolverTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/resolvers/DefaultNodeInfoResolverTest.java new file mode 100644 index 00000000..5e3527e6 --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/resolvers/DefaultNodeInfoResolverTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.resolvers; + +import io.appform.ranger.discovery.bundle.ServiceDiscoveryConfiguration; +import lombok.val; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class DefaultNodeInfoResolverTest { + + @Test + void testNodeInfoResolver() { + val configuration = ServiceDiscoveryConfiguration.builder() + .zookeeper("connectionString") + .namespace("test") + .environment("testing") + .connectionRetryIntervalMillis(5000) + .publishedHost("TestHost") + .publishedPort(8021) + .initialRotationStatus(true) + .build(); + val resolver = new DefaultNodeInfoResolver(); + val nodeInfo = resolver.resolve(configuration); + Assertions.assertNotNull(nodeInfo); + Assertions.assertEquals("testing", configuration.getEnvironment()); + Assertions.assertNull(nodeInfo.getRegion()); + Assertions.assertNull(nodeInfo.getTags()); + } +} diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/resolvers/DefaultPortSchemeResolverTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/resolvers/DefaultPortSchemeResolverTest.java new file mode 100644 index 00000000..236c714a --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/resolvers/DefaultPortSchemeResolverTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.resolvers; + +import com.google.common.collect.Lists; +import io.dropwizard.Configuration; +import io.dropwizard.jetty.HttpConnectorFactory; +import io.dropwizard.jetty.HttpsConnectorFactory; +import io.dropwizard.server.DefaultServerFactory; +import io.dropwizard.server.SimpleServerFactory; +import lombok.val; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class DefaultPortSchemeResolverTest { + + @Test + void testPortSchemeDefaultServerFactory() { + val server = mock(DefaultServerFactory.class); + val connectorFactory = mock(HttpConnectorFactory.class); + when(server.getApplicationConnectors()).thenReturn(Lists.newArrayList(connectorFactory)); + val resolver = new DefaultPortSchemeResolver<>(); + val configuration = mock(Configuration.class); + when(configuration.getServerFactory()).thenReturn(server); + Assertions.assertEquals("http", resolver.resolve(configuration)); + } + + @Test + void testPortSchemeSimpleServerFactory() { + val server = mock(SimpleServerFactory.class); + val connectorFactory = mock(HttpsConnectorFactory.class); + when(server.getConnector()).thenReturn(connectorFactory); + val resolver = new DefaultPortSchemeResolver<>(); + val configuration = mock(Configuration.class); + when(configuration.getServerFactory()).thenReturn(server); + Assertions.assertEquals("https", resolver.resolve(configuration)); + } + + @Test + void testPortSchemeDefault() { + val server = mock(SimpleServerFactory.class); + when(server.getConnector()).thenReturn(null); + val resolver = new DefaultPortSchemeResolver<>(); + val configuration = mock(Configuration.class); + when(configuration.getServerFactory()).thenReturn(server); + Assertions.assertEquals("http", resolver.resolve(configuration)); + } +} diff --git a/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/selectors/HierarchicalEnvironmentAwareShardSelectorTest.java b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/selectors/HierarchicalEnvironmentAwareShardSelectorTest.java new file mode 100644 index 00000000..472919c1 --- /dev/null +++ b/ranger-discovery-bundle/src/test/java/io/appform/ranger/discovery/bundle/selectors/HierarchicalEnvironmentAwareShardSelectorTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2022 Santanu Sinha + * + * Licensed 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 io.appform.ranger.discovery.bundle.selectors; + +import com.google.common.collect.ArrayListMultimap; +import io.appform.ranger.common.server.ShardInfo; +import io.appform.ranger.core.finder.serviceregistry.MapBasedServiceRegistry; +import io.appform.ranger.core.healthcheck.HealthcheckStatus; +import io.appform.ranger.core.model.Service; +import io.appform.ranger.core.model.ServiceNode; +import lombok.val; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.doReturn; + +/** + * + */ +class HierarchicalEnvironmentAwareShardSelectorTest { + + @Mock + private MapBasedServiceRegistry serviceRegistry; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void testNoNodeAvailableForTheEnvironment() { + val serviceName = UUID.randomUUID().toString(); + val service = Mockito.mock(Service.class); + doReturn(serviceName).when(service).getServiceName(); + doReturn(service).when(serviceRegistry).getService(); + + val serviceNodes = ArrayListMultimap.create(); + serviceNodes.put( + ShardInfo.builder().environment("x.y").build(), + new ServiceNode<>("host1", + 8888, + ShardInfo.builder().environment("x.y").build(), + HealthcheckStatus.healthy, + System.currentTimeMillis(), + "http")); + + serviceNodes.put( + ShardInfo.builder().environment("x").build(), + new ServiceNode<>("host2", + 8888, + ShardInfo.builder().environment("x.y").build(), + HealthcheckStatus.healthy, + System.currentTimeMillis(), + "http")); + + doReturn(serviceNodes).when(serviceRegistry).nodes(); + + val nodes = selector("z").nodes(null, serviceRegistry); + assertEquals(0, nodes.size()); + } + + @Test + void testNodeAvailableForChildEnv() { + val serviceName = UUID.randomUUID().toString(); + val service = Mockito.mock(Service.class); + doReturn(serviceName).when(service).getServiceName(); + doReturn(service).when(serviceRegistry).getService(); + + val serviceNodes = ArrayListMultimap.create(); + serviceNodes.put( + ShardInfo.builder().environment("x.y").build(), + new ServiceNode<>("host1", + 8888, + ShardInfo.builder().environment("x.y").build(), + HealthcheckStatus.healthy, + System.currentTimeMillis(), + "http")); + serviceNodes.put( + ShardInfo.builder().environment("x").build(), + new ServiceNode<>("host2", + 8888, + ShardInfo.builder().environment("x").build(), + HealthcheckStatus.healthy, + System.currentTimeMillis(), + "http")); + doReturn(serviceNodes).when(serviceRegistry).nodes(); + + val nodes = selector("x.y") + .nodes(null, serviceRegistry); + assertEquals(1, nodes.size()); + assertEquals("host1", nodes.get(0).getHost()); + assertEquals(8888, nodes.get(0).getPort()); + } + + private HierarchicalEnvironmentAwareShardSelector selector(String environment) { + return new HierarchicalEnvironmentAwareShardSelector(environment); + } + + @Test + void testNoNodeAvailableForChildEnvButAvailableForParentEnv() { + val serviceName = UUID.randomUUID().toString(); + val service = Mockito.mock(Service.class); + doReturn(serviceName).when(service).getServiceName(); + doReturn(service).when(serviceRegistry).getService(); + + val serviceNodes = ArrayListMultimap.create(); + serviceNodes.put( + ShardInfo.builder().environment("x.y.z").build(), + new ServiceNode<>("host1", + 8888, + ShardInfo.builder().environment("x.y").build(), + HealthcheckStatus.healthy, + System.currentTimeMillis(), + "http")); + serviceNodes.put( + ShardInfo.builder().environment("x").build(), + new ServiceNode<>("host2", + 9999, + ShardInfo.builder().environment("x").build(), + HealthcheckStatus.healthy, + System.currentTimeMillis(), + "http")); + doReturn(serviceNodes).when(serviceRegistry).nodes(); + + val nodes = selector("x.y").nodes(null, serviceRegistry); + assertEquals(1, nodes.size()); + assertEquals("host2", nodes.get(0).getHost()); + assertEquals(9999, nodes.get(0).getPort()); + } +} \ No newline at end of file diff --git a/ranger-http-client/pom.xml b/ranger-http-client/pom.xml index 42d7c92b..ff13feea 100644 --- a/ranger-http-client/pom.xml +++ b/ranger-http-client/pom.xml @@ -5,7 +5,7 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 @@ -23,17 +23,17 @@ ${project.version} - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - com.github.tomakehurst + org.wiremock wiremock ${wiremock.version} test + + + commons-fileupload + commons-fileupload + + - \ No newline at end of file diff --git a/ranger-http-client/src/test/java/io/appform/ranger/client/http/BaseRangerHttpClientTest.java b/ranger-http-client/src/test/java/io/appform/ranger/client/http/BaseRangerHttpClientTest.java index 6841320f..bdab6924 100644 --- a/ranger-http-client/src/test/java/io/appform/ranger/client/http/BaseRangerHttpClientTest.java +++ b/ranger-http-client/src/test/java/io/appform/ranger/client/http/BaseRangerHttpClientTest.java @@ -17,7 +17,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import io.appform.ranger.core.healthcheck.HealthcheckStatus; @@ -31,9 +31,8 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; import java.io.IOException; @@ -45,12 +44,15 @@ public abstract class BaseRangerHttpClientTest { private final ObjectMapper objectMapper = new ObjectMapper(); - @Rule - public WireMockRule server = new WireMockRule(wireMockConfig().dynamicPort()); private HttpClientConfig httpClientConfig; - @Before - public void startTestCluster() throws Exception { + @RegisterExtension + static WireMockExtension wireMockExtension = WireMockExtension.newInstance() + .options(wireMockConfig().dynamicPort().dynamicHttpsPort()) + .build(); + + @BeforeEach + public void prepareHttpMocks() throws Exception { val testNode = TestNodeData.builder().shardId(1).build(); val node = ServiceNode.builder().host("127.0.0.1").port(80).nodeData(testNode).build(); node.setHealthcheckStatus(HealthcheckStatus.healthy); @@ -59,7 +61,7 @@ public void startTestCluster() throws Exception { ServiceNodesResponse.builder() .data(Lists.newArrayList(node)) .build()); - server.stubFor(get(urlEqualTo("/ranger/nodes/v1/test-n/test-s")) + wireMockExtension.stubFor(get(urlEqualTo("/ranger/nodes/v1/test-n/test-s")) .willReturn(aResponse() .withBody(payload) .withStatus(200))); @@ -70,25 +72,20 @@ public void startTestCluster() throws Exception { )) .build(); val response = objectMapper.writeValueAsBytes(responseObj); - server.stubFor(get(urlEqualTo("/ranger/services/v1")) + wireMockExtension.stubFor(get(urlEqualTo("/ranger/services/v1")) .willReturn(aResponse() .withBody(response) .withStatus(200))); httpClientConfig = HttpClientConfig.builder() .host("127.0.0.1") - .port(server.port()) + .port(wireMockExtension.getPort()) .connectionTimeoutMs(30_000) .operationTimeoutMs(30_000) .build(); log.debug("Started http subsystem"); } - @After - public void stopTestCluster() { - log.debug("Stopping http subsystem"); - } - protected ServiceNodesResponse read(final byte[] data) { try { return getObjectMapper().readValue(data, new TypeReference>() {}); diff --git a/ranger-http-client/src/test/java/io/appform/ranger/client/http/ShardedRangerHttpClientTest.java b/ranger-http-client/src/test/java/io/appform/ranger/client/http/ShardedRangerHttpClientTest.java index 6f5fae4c..1e09e1e6 100644 --- a/ranger-http-client/src/test/java/io/appform/ranger/client/http/ShardedRangerHttpClientTest.java +++ b/ranger-http-client/src/test/java/io/appform/ranger/client/http/ShardedRangerHttpClientTest.java @@ -18,13 +18,13 @@ import io.appform.ranger.core.units.TestNodeData; import io.appform.ranger.core.utils.RangerTestUtils; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class ShardedRangerHttpClientTest extends BaseRangerHttpClientTest { +class ShardedRangerHttpClientTest extends BaseRangerHttpClientTest { @Test - public void testShardedHttpHubClient(){ + void testShardedHttpHubClient(){ val client = ShardedRangerHttpHubClient.builder() .clientConfig(getHttpClientConfig()) .namespace("test-n") @@ -34,9 +34,9 @@ public void testShardedHttpHubClient(){ .build(); client.start(); val service = RangerTestUtils.getService("test-n", "test-s"); - Assert.assertNotNull(client.getNode(service).orElse(null)); - Assert.assertNotNull(client.getNode(service, nodeData -> nodeData.getShardId() == 1).orElse(null)); - Assert.assertNull(client.getNode(service, nodeData -> nodeData.getShardId() == 2).orElse(null)); + Assertions.assertNotNull(client.getNode(service).orElse(null)); + Assertions.assertNotNull(client.getNode(service, nodeData -> nodeData.getShardId() == 1).orElse(null)); + Assertions.assertNull(client.getNode(service, nodeData -> nodeData.getShardId() == 2).orElse(null)); client.stop(); } } diff --git a/ranger-http-client/src/test/java/io/appform/ranger/client/http/SimpleRangerHttpClientTest.java b/ranger-http-client/src/test/java/io/appform/ranger/client/http/SimpleRangerHttpClientTest.java index c37a07e9..e379f272 100644 --- a/ranger-http-client/src/test/java/io/appform/ranger/client/http/SimpleRangerHttpClientTest.java +++ b/ranger-http-client/src/test/java/io/appform/ranger/client/http/SimpleRangerHttpClientTest.java @@ -18,13 +18,13 @@ import io.appform.ranger.core.units.TestNodeData; import io.appform.ranger.core.utils.RangerTestUtils; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class SimpleRangerHttpClientTest extends BaseRangerHttpClientTest{ +class SimpleRangerHttpClientTest extends BaseRangerHttpClientTest{ @Test - public void testSimpleHttpRangerClient(){ + void testSimpleHttpRangerClient(){ val client = SimpleRangerHttpClient.builder() .clientConfig(getHttpClientConfig()) .mapper(getObjectMapper()) @@ -35,10 +35,10 @@ public void testSimpleHttpRangerClient(){ .build(); client.start(); RangerTestUtils.sleepUntilFinderStarts(client.getServiceFinder()); - Assert.assertNotNull(client.getNode().orElse(null)); - Assert.assertFalse(client.getAllNodes().isEmpty()); - Assert.assertNotNull(client.getNode(nodeData -> nodeData.getShardId() == 1).orElse(null)); - Assert.assertFalse(client.getAllNodes(nodeData -> nodeData.getShardId() == 1).isEmpty()); + Assertions.assertNotNull(client.getNode().orElse(null)); + Assertions.assertFalse(client.getAllNodes().isEmpty()); + Assertions.assertNotNull(client.getNode(nodeData -> nodeData.getShardId() == 1).orElse(null)); + Assertions.assertFalse(client.getAllNodes(nodeData -> nodeData.getShardId() == 1).isEmpty()); client.stop(); } } diff --git a/ranger-http-client/src/test/java/io/appform/ranger/client/http/UnshardedRangerHttpClientTest.java b/ranger-http-client/src/test/java/io/appform/ranger/client/http/UnshardedRangerHttpClientTest.java index 9470a32f..a3ced34c 100644 --- a/ranger-http-client/src/test/java/io/appform/ranger/client/http/UnshardedRangerHttpClientTest.java +++ b/ranger-http-client/src/test/java/io/appform/ranger/client/http/UnshardedRangerHttpClientTest.java @@ -18,13 +18,13 @@ import io.appform.ranger.core.units.TestNodeData; import io.appform.ranger.core.utils.RangerTestUtils; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class UnshardedRangerHttpClientTest extends BaseRangerHttpClientTest { +class UnshardedRangerHttpClientTest extends BaseRangerHttpClientTest { @Test - public void testUnshardedRangerHubClient(){ + void testUnshardedRangerHubClient(){ val client = UnshardedRangerHttpHubClient.builder() .clientConfig(getHttpClientConfig()) .namespace("test-n") @@ -34,9 +34,9 @@ public void testUnshardedRangerHubClient(){ .build(); client.start(); val service = RangerTestUtils.getService("test-n", "test-s"); - Assert.assertNotNull(client.getNode(service).orElse(null)); - Assert.assertNotNull(client.getNode(service, nodeData -> nodeData.getShardId() == 1).orElse(null)); - Assert.assertNull(client.getNode(service, nodeData -> nodeData.getShardId() == 2).orElse(null)); + Assertions.assertNotNull(client.getNode(service).orElse(null)); + Assertions.assertNotNull(client.getNode(service, nodeData -> nodeData.getShardId() == 1).orElse(null)); + Assertions.assertNull(client.getNode(service, nodeData -> nodeData.getShardId() == 2).orElse(null)); client.stop(); } } diff --git a/ranger-http-model/pom.xml b/ranger-http-model/pom.xml index 30d69a33..d3937423 100644 --- a/ranger-http-model/pom.xml +++ b/ranger-http-model/pom.xml @@ -5,18 +5,9 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 ranger-http-model - - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - \ No newline at end of file diff --git a/ranger-http-server-bundle/pom.xml b/ranger-http-server-bundle/pom.xml index aec77d72..740183ff 100644 --- a/ranger-http-server-bundle/pom.xml +++ b/ranger-http-server-bundle/pom.xml @@ -5,14 +5,14 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 ranger-http-server-bundle - 2.0.23 + 2.1.10 @@ -31,15 +31,9 @@ ranger-server-common ${project.version} - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - io.dropwizard dropwizard-core - ${dropwizard.version} provided diff --git a/ranger-http-server-bundle/src/main/java/io/appform/ranger/http/server/bundle/HttpServerBundle.java b/ranger-http-server-bundle/src/main/java/io/appform/ranger/http/server/bundle/HttpServerBundle.java index 159ad237..a40e02b3 100644 --- a/ranger-http-server-bundle/src/main/java/io/appform/ranger/http/server/bundle/HttpServerBundle.java +++ b/ranger-http-server-bundle/src/main/java/io/appform/ranger/http/server/bundle/HttpServerBundle.java @@ -17,14 +17,10 @@ import com.codahale.metrics.health.HealthCheck; import com.fasterxml.jackson.core.type.TypeReference; -import com.google.common.collect.ImmutableList; import io.appform.ranger.client.RangerHubClient; -import io.appform.ranger.client.http.ShardedRangerHttpHubClient; import io.appform.ranger.client.http.UnshardedRangerHttpHubClient; import io.appform.ranger.common.server.ShardInfo; import io.appform.ranger.core.finder.serviceregistry.ListBasedServiceRegistry; -import io.appform.ranger.core.finder.serviceregistry.MapBasedServiceRegistry; -import io.appform.ranger.http.model.ServiceNodesResponse; import io.appform.ranger.http.server.bundle.config.RangerHttpConfiguration; import io.appform.ranger.http.server.bundle.healthcheck.RangerHttpHealthCheck; import io.appform.ranger.server.bundle.RangerServerBundle; @@ -56,7 +52,7 @@ protected List>> .nodeRefreshTimeMs(rangerConfiguration.getNodeRefreshTimeMs()) .deserializer(data -> { try { - return getMapper().readValue(data, new TypeReference>() { + return getMapper().readValue(data, new TypeReference<>() { }); } catch (IOException e) { log.warn("Error parsing node data with value {}", new String(data)); @@ -67,6 +63,6 @@ protected List>> } protected List withHealthChecks(U configuration) { - return ImmutableList.of(new RangerHttpHealthCheck()); + return List.of(new RangerHttpHealthCheck()); } } diff --git a/ranger-http-server/config/local.yml b/ranger-http-server/config/local.yml index 67d450c5..bffca045 100644 --- a/ranger-http-server/config/local.yml +++ b/ranger-http-server/config/local.yml @@ -1,6 +1,5 @@ name: ranger-http-server -initialRotationStatus: false rangerConfiguration: namespace: test diff --git a/ranger-http-server/pom.xml b/ranger-http-server/pom.xml index 5972c301..4989fdb9 100644 --- a/ranger-http-server/pom.xml +++ b/ranger-http-server/pom.xml @@ -5,16 +5,12 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 ranger-http-server - - 2.0.23 - - io.appform.ranger @@ -24,22 +20,6 @@ io.dropwizard dropwizard-core - ${dropwizard.version} - - - ch.qos.logback - logback-classic - ${logback.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} diff --git a/ranger-http-server/src/main/java/io/appform/ranger/http/server/App.java b/ranger-http-server/src/main/java/io/appform/ranger/http/server/App.java index 75698075..e482827a 100644 --- a/ranger-http-server/src/main/java/io/appform/ranger/http/server/App.java +++ b/ranger-http-server/src/main/java/io/appform/ranger/http/server/App.java @@ -29,7 +29,7 @@ public static void main(String[] args) throws Exception { @Override public void initialize(Bootstrap bootstrap) { - bootstrap.addBundle(new HttpServerBundle() { + bootstrap.addBundle(new HttpServerBundle<>() { @Override protected RangerHttpConfiguration getRangerConfiguration(HttpAppConfiguration configuration) { return configuration.getRangerConfiguration(); diff --git a/ranger-http-server/src/main/java/io/appform/ranger/http/server/HttpAppConfiguration.java b/ranger-http-server/src/main/java/io/appform/ranger/http/server/HttpAppConfiguration.java index 259a915c..d2a5c4e3 100644 --- a/ranger-http-server/src/main/java/io/appform/ranger/http/server/HttpAppConfiguration.java +++ b/ranger-http-server/src/main/java/io/appform/ranger/http/server/HttpAppConfiguration.java @@ -15,6 +15,7 @@ */ package io.appform.ranger.http.server; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import io.appform.ranger.http.server.bundle.config.RangerHttpConfiguration; import io.dropwizard.Configuration; import lombok.AllArgsConstructor; @@ -30,6 +31,7 @@ @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties(ignoreUnknown = true) public class HttpAppConfiguration extends Configuration { @NotEmpty @NotNull diff --git a/ranger-http/pom.xml b/ranger-http/pom.xml index f8770bfd..ab190b79 100644 --- a/ranger-http/pom.xml +++ b/ranger-http/pom.xml @@ -5,7 +5,7 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 @@ -28,20 +28,16 @@ ${http.client.version} - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - com.github.tomakehurst + org.wiremock wiremock ${wiremock.version} test + + + commons-fileupload + commons-fileupload + + io.appform.ranger diff --git a/ranger-http/src/test/java/io/appform/ranger/http/common/HttpNodeDataStoreConnectorTest.java b/ranger-http/src/test/java/io/appform/ranger/http/common/HttpNodeDataStoreConnectorTest.java index 0f4c98b0..07e76767 100644 --- a/ranger-http/src/test/java/io/appform/ranger/http/common/HttpNodeDataStoreConnectorTest.java +++ b/ranger-http/src/test/java/io/appform/ranger/http/common/HttpNodeDataStoreConnectorTest.java @@ -18,20 +18,20 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.appform.ranger.http.config.HttpClientConfig; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class HttpNodeDataStoreConnectorTest { +class HttpNodeDataStoreConnectorTest { @Test - public void testHttpNodeDataStoreConnector(){ + void testHttpNodeDataStoreConnector(){ val objectMapper = new ObjectMapper(); val httpClientConfig = HttpClientConfig.builder() .host("localhost-1") .port(80) .build(); val httpNodeDataStoreConnector = new HttpNodeDataStoreConnector<>(httpClientConfig, objectMapper); - Assert.assertNotNull(httpNodeDataStoreConnector); - Assert.assertTrue(httpNodeDataStoreConnector.isActive()); + Assertions.assertNotNull(httpNodeDataStoreConnector); + Assertions.assertTrue(httpNodeDataStoreConnector.isActive()); } } diff --git a/ranger-http/src/test/java/io/appform/ranger/http/config/HttpClientConfigTest.java b/ranger-http/src/test/java/io/appform/ranger/http/config/HttpClientConfigTest.java index a272610e..aef7a34c 100644 --- a/ranger-http/src/test/java/io/appform/ranger/http/config/HttpClientConfigTest.java +++ b/ranger-http/src/test/java/io/appform/ranger/http/config/HttpClientConfigTest.java @@ -17,18 +17,18 @@ import io.appform.ranger.http.ResourceHelper; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class HttpClientConfigTest { +class HttpClientConfigTest { @Test - public void testHttpClientConfig(){ + void testHttpClientConfig(){ val resource = ResourceHelper.getResource("fixtures/httpClientConfig.json", HttpClientConfig.class); - Assert.assertNotNull(resource); - Assert.assertEquals("localhost-1", resource.getHost()); - Assert.assertEquals(80, resource.getPort()); - Assert.assertEquals(10, resource.getConnectionTimeoutMs()); - Assert.assertEquals(10, resource.getOperationTimeoutMs()); + Assertions.assertNotNull(resource); + Assertions.assertEquals("localhost-1", resource.getHost()); + Assertions.assertEquals(80, resource.getPort()); + Assertions.assertEquals(10, resource.getConnectionTimeoutMs()); + Assertions.assertEquals(10, resource.getOperationTimeoutMs()); } } diff --git a/ranger-http/src/test/java/io/appform/ranger/http/model/ServiceNodeResponseTest.java b/ranger-http/src/test/java/io/appform/ranger/http/model/ServiceNodeResponseTest.java index ae706110..f5d77eb8 100644 --- a/ranger-http/src/test/java/io/appform/ranger/http/model/ServiceNodeResponseTest.java +++ b/ranger-http/src/test/java/io/appform/ranger/http/model/ServiceNodeResponseTest.java @@ -21,8 +21,8 @@ import lombok.Value; import lombok.extern.jackson.Jacksonized; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class ServiceNodeResponseTest { @@ -37,11 +37,11 @@ static class TestNodeInfo{ @Test public void testServiceNodesResponse(){ val serviceNodesResponse = ResourceHelper.getResource("fixtures/serviceNodesResponse.json", ServiceNodesResponse.class); - Assert.assertNotNull(serviceNodesResponse); - Assert.assertFalse(serviceNodesResponse.getData().isEmpty()); - Assert.assertNotNull(((ServiceNode) serviceNodesResponse.getData().get(0)).getNodeData()); - Assert.assertNotNull(((ServiceNode) serviceNodesResponse.getData().get(1)).getNodeData()); - Assert.assertEquals("localhost-1", ((ServiceNode) serviceNodesResponse.getData().get(0)).getHost()); - Assert.assertEquals("localhost-2", ((ServiceNode) serviceNodesResponse.getData().get(1)).getHost()); + Assertions.assertNotNull(serviceNodesResponse); + Assertions.assertFalse(serviceNodesResponse.getData().isEmpty()); + Assertions.assertNotNull(((ServiceNode) serviceNodesResponse.getData().get(0)).getNodeData()); + Assertions.assertNotNull(((ServiceNode) serviceNodesResponse.getData().get(1)).getNodeData()); + Assertions.assertEquals("localhost-1", ((ServiceNode) serviceNodesResponse.getData().get(0)).getHost()); + Assertions.assertEquals("localhost-2", ((ServiceNode) serviceNodesResponse.getData().get(1)).getHost()); } } diff --git a/ranger-http/src/test/java/io/appform/ranger/http/model/ServiceRegistrationResponseTest.java b/ranger-http/src/test/java/io/appform/ranger/http/model/ServiceRegistrationResponseTest.java index 69375dda..95a18148 100644 --- a/ranger-http/src/test/java/io/appform/ranger/http/model/ServiceRegistrationResponseTest.java +++ b/ranger-http/src/test/java/io/appform/ranger/http/model/ServiceRegistrationResponseTest.java @@ -17,15 +17,15 @@ import io.appform.ranger.http.ResourceHelper; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class ServiceRegistrationResponseTest { @Test public void testServiceRegistrationResponse(){ val resource = ResourceHelper.getResource("fixtures/serviceResponse.json", ServiceRegistrationResponse.class); - Assert.assertNotNull(resource); - Assert.assertTrue(resource.valid()); + Assertions.assertNotNull(resource); + Assertions.assertTrue(resource.valid()); } } diff --git a/ranger-http/src/test/java/io/appform/ranger/http/servicefinder/HttpShardedServiceFinderBuilderTest.java b/ranger-http/src/test/java/io/appform/ranger/http/servicefinder/HttpShardedServiceFinderBuilderTest.java index 26ef7efd..df51b998 100644 --- a/ranger-http/src/test/java/io/appform/ranger/http/servicefinder/HttpShardedServiceFinderBuilderTest.java +++ b/ranger-http/src/test/java/io/appform/ranger/http/servicefinder/HttpShardedServiceFinderBuilderTest.java @@ -18,7 +18,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; import io.appform.ranger.core.healthcheck.HealthcheckStatus; import io.appform.ranger.core.model.ServiceNode; import io.appform.ranger.core.utils.RangerTestUtils; @@ -26,20 +27,19 @@ import io.appform.ranger.http.model.ServiceNodesResponse; import lombok.Data; import lombok.val; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Collections; import static com.github.tomakehurst.wiremock.client.WireMock.*; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; /** * */ -public class HttpShardedServiceFinderBuilderTest { +@WireMockTest +class HttpShardedServiceFinderBuilderTest { @Data private static final class NodeData { @@ -52,11 +52,8 @@ public NodeData(@JsonProperty("name") String name) { private static final ObjectMapper MAPPER = new ObjectMapper(); - @Rule - public WireMockRule server = new WireMockRule(wireMockConfig().dynamicPort()); - @Test - public void testFinder() throws Exception { + void testFinder(WireMockRuntimeInfo wireMockRuntimeInfo) throws Exception { val testNode = new NodeData("testNode"); val node = ServiceNode.builder().host("127.0.0.1").port(80).nodeData(testNode).build(); node.setHealthcheckStatus(HealthcheckStatus.healthy); @@ -65,13 +62,13 @@ public void testFinder() throws Exception { ServiceNodesResponse.builder() .data(Collections.singletonList(node)) .build()); - server.stubFor(get(urlEqualTo("/ranger/nodes/v1/testns/test")) + stubFor(get(urlEqualTo("/ranger/nodes/v1/testns/test")) .willReturn(aResponse() .withBody(payload) .withStatus(200))); val clientConfig = HttpClientConfig.builder() .host("127.0.0.1") - .port(server.port()) + .port(wireMockRuntimeInfo.getHttpPort()) .connectionTimeoutMs(30_000) .operationTimeoutMs(30_000) .build(); @@ -94,7 +91,7 @@ public void testFinder() throws Exception { .build(); finder.start(); RangerTestUtils.sleepUntilFinderStarts(finder); - Assert.assertNotNull(finder.get(nodeData -> true).orElse(null)); + Assertions.assertNotNull(finder.get(nodeData -> true).orElse(null)); } } \ No newline at end of file diff --git a/ranger-http/src/test/java/io/appform/ranger/http/servicefinderhub/HttpServiceDataSourceTest.java b/ranger-http/src/test/java/io/appform/ranger/http/servicefinderhub/HttpServiceDataSourceTest.java index 97175fc1..1996364f 100644 --- a/ranger-http/src/test/java/io/appform/ranger/http/servicefinderhub/HttpServiceDataSourceTest.java +++ b/ranger-http/src/test/java/io/appform/ranger/http/servicefinderhub/HttpServiceDataSourceTest.java @@ -16,30 +16,26 @@ package io.appform.ranger.http.servicefinderhub; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; import com.google.common.collect.Sets; import io.appform.ranger.core.utils.RangerTestUtils; import io.appform.ranger.http.config.HttpClientConfig; import io.appform.ranger.http.model.ServiceDataSourceResponse; import lombok.val; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.io.IOException; import static com.github.tomakehurst.wiremock.client.WireMock.*; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -public class HttpServiceDataSourceTest { +@WireMockTest +class HttpServiceDataSourceTest { private static final ObjectMapper MAPPER = new ObjectMapper(); - - @Rule - public WireMockRule server = new WireMockRule(wireMockConfig().dynamicPort()); - @Test - public void testServiceDataSource() throws IOException { + void testServiceDataSource(WireMockRuntimeInfo wireMockRuntimeInfo) throws IOException { val responseObj = ServiceDataSourceResponse.builder() .data(Sets.newHashSet( RangerTestUtils.getService("test-n", "test-s"), @@ -48,24 +44,24 @@ public void testServiceDataSource() throws IOException { )) .build(); val response = MAPPER.writeValueAsBytes(responseObj); - server.stubFor(get(urlEqualTo("/ranger/services/v1")) + stubFor(get(urlEqualTo("/ranger/services/v1")) .willReturn(aResponse() .withBody(response) .withStatus(200))); val clientConfig = HttpClientConfig.builder() .host("127.0.0.1") - .port(server.port()) + .port(wireMockRuntimeInfo.getHttpPort()) .connectionTimeoutMs(30_000) .operationTimeoutMs(30_000) .build(); val httpServiceDataSource = new HttpServiceDataSource<>(clientConfig, MAPPER); val services = httpServiceDataSource.services(); - Assert.assertNotNull(services); - Assert.assertFalse(services.isEmpty()); - Assert.assertEquals(3, services.size()); - Assert.assertFalse(services.stream().noneMatch(each -> each.getServiceName().equalsIgnoreCase("test-s"))); - Assert.assertFalse(services.stream().noneMatch(each -> each.getServiceName().equalsIgnoreCase("test-s1"))); - Assert.assertFalse(services.stream().noneMatch(each -> each.getServiceName().equalsIgnoreCase("test-s2"))); + Assertions.assertNotNull(services); + Assertions.assertFalse(services.isEmpty()); + Assertions.assertEquals(3, services.size()); + Assertions.assertFalse(services.stream().noneMatch(each -> each.getServiceName().equalsIgnoreCase("test-s"))); + Assertions.assertFalse(services.stream().noneMatch(each -> each.getServiceName().equalsIgnoreCase("test-s1"))); + Assertions.assertFalse(services.stream().noneMatch(each -> each.getServiceName().equalsIgnoreCase("test-s2"))); } } diff --git a/ranger-http/src/test/java/io/appform/ranger/http/serviceprovider/HttpShardedServiceProviderBuilderTest.java b/ranger-http/src/test/java/io/appform/ranger/http/serviceprovider/HttpShardedServiceProviderBuilderTest.java index 6c1936d3..39cd8cb2 100644 --- a/ranger-http/src/test/java/io/appform/ranger/http/serviceprovider/HttpShardedServiceProviderBuilderTest.java +++ b/ranger-http/src/test/java/io/appform/ranger/http/serviceprovider/HttpShardedServiceProviderBuilderTest.java @@ -17,7 +17,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; import io.appform.ranger.core.healthcheck.Healthchecks; import io.appform.ranger.core.model.PortSchemes; import io.appform.ranger.core.model.ServiceNode; @@ -26,14 +27,13 @@ import lombok.Builder; import lombok.Data; import lombok.val; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import static com.github.tomakehurst.wiremock.client.WireMock.*; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -public class HttpShardedServiceProviderBuilderTest { +@WireMockTest +class HttpShardedServiceProviderBuilderTest { @Data private static final class TestNodeData { @@ -47,14 +47,11 @@ public TestNodeData(@JsonProperty("farmId") String farmId) { private static final ObjectMapper MAPPER = new ObjectMapper(); - @Rule - public WireMockRule server = new WireMockRule(wireMockConfig().dynamicPort()); - @Test - public void testProvider() throws Exception { + void testProvider(WireMockRuntimeInfo wireMockRuntimeInfo) throws Exception { val farmNodeData = TestNodeData.builder().farmId("farm1").build(); val testNode = ServiceNode.builder().host("127.0.0.1").port(80).nodeData(farmNodeData).build(); - Assert.assertEquals(PortSchemes.HTTP, testNode.getPortScheme()); + Assertions.assertEquals(PortSchemes.HTTP, testNode.getPortScheme()); val response = MAPPER.writeValueAsBytes( GenericResponse.builder() .data(ServiceNode.builder() @@ -64,14 +61,14 @@ public void testProvider() throws Exception { ) .build()); byte[] requestBytes = MAPPER.writeValueAsBytes(testNode); - server.stubFor(post(urlEqualTo("/ranger/nodes/v1/add/testns/test")) + stubFor(post(urlEqualTo("/ranger/nodes/v1/add/testns/test")) .withRequestBody(binaryEqualTo(requestBytes)) .willReturn(aResponse() .withBody(response) .withStatus(200))); val clientConfig = HttpClientConfig.builder() .host("127.0.0.1") - .port(server.port()) + .port(wireMockRuntimeInfo.getHttpPort()) .connectionTimeoutMs(30_000) .operationTimeoutMs(30_000) .build(); @@ -88,7 +85,7 @@ public void testProvider() throws Exception { .withSerializer(node -> requestBytes) .build(); serviceProvider.start(); - Assert.assertNotNull(serviceProvider); + Assertions.assertNotNull(serviceProvider); } } diff --git a/ranger-server-bundle/pom.xml b/ranger-server-bundle/pom.xml index ad3b6f69..ba3c9510 100644 --- a/ranger-server-bundle/pom.xml +++ b/ranger-server-bundle/pom.xml @@ -5,37 +5,26 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 ranger-server-bundle - - 2.0.23 - - io.appform.ranger ranger-client ${project.version} - io.appform.ranger ranger-http-model ${project.version} - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - io.dropwizard dropwizard-core - ${dropwizard.version} provided diff --git a/ranger-server-bundle/src/test/java/io/appform/ranger/server/bundle/RangerServerBundleTest.java b/ranger-server-bundle/src/test/java/io/appform/ranger/server/bundle/RangerServerBundleTest.java index e5fc1576..b5059bcd 100644 --- a/ranger-server-bundle/src/test/java/io/appform/ranger/server/bundle/RangerServerBundleTest.java +++ b/ranger-server-bundle/src/test/java/io/appform/ranger/server/bundle/RangerServerBundleTest.java @@ -33,12 +33,8 @@ import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; import lombok.val; -import lombok.var; import org.eclipse.jetty.util.component.LifeCycle; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.*; import java.util.Collections; import java.util.List; @@ -49,15 +45,15 @@ public class RangerServerBundleTest { - private final JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class); - private final MetricRegistry metricRegistry = mock(MetricRegistry.class); - private final LifecycleEnvironment lifecycleEnvironment = new LifecycleEnvironment(metricRegistry); - private final Environment environment = mock(Environment.class); - private final Bootstrap bootstrap = mock(Bootstrap.class); - private final Configuration configuration = mock(Configuration.class); + private static final JerseyEnvironment JERSEY_ENVIRONMENT = mock(JerseyEnvironment.class); + private static final MetricRegistry METRIC_REGISTRY = mock(MetricRegistry.class); + private static final LifecycleEnvironment LIFECYCLE_ENVIRONMENT = new LifecycleEnvironment(METRIC_REGISTRY); + private static final Environment ENVIRONMENT = mock(Environment.class); + private static final Bootstrap BOOTSTRAP = mock(Bootstrap.class); + private static final Configuration CONFIGURATION = mock(Configuration.class); - private final RangerServerBundle, Configuration> - rangerServerBundle = new RangerServerBundle, Configuration>() { + private static final RangerServerBundle, Configuration> + RANGER_SERVER_BUNDLE = new RangerServerBundle<>() { @Override protected List>> withHubs(Configuration configuration) { @@ -70,46 +66,46 @@ protected List withHealthChecks(Configuration configuration) { } }; - @Before - public void setup() throws Exception { - when(jerseyEnvironment.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); - when(environment.jersey()).thenReturn(jerseyEnvironment); - when(environment.lifecycle()).thenReturn(lifecycleEnvironment); - when(environment.getObjectMapper()).thenReturn(new ObjectMapper()); + @BeforeAll + public static void setup() throws Exception { + when(JERSEY_ENVIRONMENT.getResourceConfig()).thenReturn(new DropwizardResourceConfig()); + when(ENVIRONMENT.jersey()).thenReturn(JERSEY_ENVIRONMENT); + when(ENVIRONMENT.lifecycle()).thenReturn(LIFECYCLE_ENVIRONMENT); + when(ENVIRONMENT.getObjectMapper()).thenReturn(new ObjectMapper()); val adminEnvironment = mock(AdminEnvironment.class); doNothing().when(adminEnvironment).addTask(any()); - when(environment.admin()).thenReturn(adminEnvironment); + when(ENVIRONMENT.admin()).thenReturn(adminEnvironment); val healthCheckRegistry = mock(HealthCheckRegistry.class); doNothing().when(healthCheckRegistry).register(anyString(), any()); - when(environment.healthChecks()).thenReturn(healthCheckRegistry); + when(ENVIRONMENT.healthChecks()).thenReturn(healthCheckRegistry); - rangerServerBundle.initialize(bootstrap); - rangerServerBundle.run(configuration, environment); - for (val lifeCycle : lifecycleEnvironment.getManagedObjects()) { + RANGER_SERVER_BUNDLE.initialize(BOOTSTRAP); + RANGER_SERVER_BUNDLE.run(CONFIGURATION, ENVIRONMENT); + for (val lifeCycle : LIFECYCLE_ENVIRONMENT.getManagedObjects()) { lifeCycle.start(); } } @Test - public void testRangerBundle() { - var hub = rangerServerBundle.getHubs().get(0); - Assert.assertTrue(hub instanceof RangerTestHub); + void testRangerBundle() { + var hub = RANGER_SERVER_BUNDLE.getHubs().get(0); + Assertions.assertTrue(hub instanceof RangerTestHub); var node = hub.getNode(service).orElse(null); - Assert.assertNotNull(node); - Assert.assertTrue(node.getHost().equalsIgnoreCase("localhost")); - Assert.assertEquals(9200, node.getPort()); - Assert.assertEquals(1, node.getNodeData().getShardId()); - Assert.assertNull(hub.getNode(RangerTestUtils.getService("test", "test")).orElse(null)); - Assert.assertNull(hub.getNode(service, nodeData -> nodeData.getShardId() == 2).orElse(null)); - Assert.assertNull(hub.getNode(RangerTestUtils.getService("test", "test"), + Assertions.assertNotNull(node); + Assertions.assertTrue(node.getHost().equalsIgnoreCase("localhost")); + Assertions.assertEquals(9200, node.getPort()); + Assertions.assertEquals(1, node.getNodeData().getShardId()); + Assertions.assertNull(hub.getNode(RangerTestUtils.getService("test", "test")).orElse(null)); + Assertions.assertNull(hub.getNode(service, nodeData -> nodeData.getShardId() == 2).orElse(null)); + Assertions.assertNull(hub.getNode(RangerTestUtils.getService("test", "test"), nodeData -> nodeData.getShardId() == 1).orElse(null)); } - @After - public void tearDown() throws Exception { - for (LifeCycle lifeCycle : lifecycleEnvironment.getManagedObjects()) { + @AfterAll + public static void tearDown() throws Exception { + for (LifeCycle lifeCycle : LIFECYCLE_ENVIRONMENT.getManagedObjects()) { lifeCycle.stop(); } } diff --git a/ranger-server-common/pom.xml b/ranger-server-common/pom.xml index fe745dbf..ab777715 100644 --- a/ranger-server-common/pom.xml +++ b/ranger-server-common/pom.xml @@ -5,17 +5,10 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 ranger-server-common - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - \ No newline at end of file diff --git a/ranger-server-common/src/test/java/io/appform/ranger/common/server/ShardInfoTest.java b/ranger-server-common/src/test/java/io/appform/ranger/common/server/ShardInfoTest.java index 284621fd..9c86b9df 100644 --- a/ranger-server-common/src/test/java/io/appform/ranger/common/server/ShardInfoTest.java +++ b/ranger-server-common/src/test/java/io/appform/ranger/common/server/ShardInfoTest.java @@ -3,8 +3,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.SneakyThrows; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.io.BufferedReader; import java.io.InputStreamReader; @@ -36,14 +36,14 @@ private T getResource(String path, Class klass) { public void testShardInfo(){ val shardInfo1 = getResource("fixtures/env1.json", ShardInfo.class); val shardInfo2 = getResource("fixtures/env2.json", ShardInfo.class); - Assert.assertNotNull(shardInfo1); - Assert.assertNotNull(shardInfo2); - Assert.assertNotEquals(shardInfo1, shardInfo2); - Arrays.asList(shardInfo1, shardInfo2).forEach(shardInfo -> Assert.assertEquals("e", shardInfo.getEnvironment())); - Assert.assertEquals("r", shardInfo1.getRegion()); - Assert.assertNull(shardInfo2.getRegion()); - Assert.assertNotNull(shardInfo1.getTags()); - Assert.assertNotNull(shardInfo2.getTags()); - Assert.assertTrue(shardInfo2.getTags().contains("tag1")); + Assertions.assertNotNull(shardInfo1); + Assertions.assertNotNull(shardInfo2); + Assertions.assertNotEquals(shardInfo1, shardInfo2); + Arrays.asList(shardInfo1, shardInfo2).forEach(shardInfo -> Assertions.assertEquals("e", shardInfo.getEnvironment())); + Assertions.assertEquals("r", shardInfo1.getRegion()); + Assertions.assertNull(shardInfo2.getRegion()); + Assertions.assertNotNull(shardInfo1.getTags()); + Assertions.assertNotNull(shardInfo2.getTags()); + Assertions.assertTrue(shardInfo2.getTags().contains("tag1")); } } diff --git a/ranger-zk-client/pom.xml b/ranger-zk-client/pom.xml index 9c42804b..8b6443d3 100644 --- a/ranger-zk-client/pom.xml +++ b/ranger-zk-client/pom.xml @@ -5,7 +5,7 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 @@ -22,11 +22,6 @@ ranger-client ${project.version} - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - org.apache.curator curator-test diff --git a/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/BaseRangerZKClientTest.java b/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/BaseRangerZKClientTest.java index 4b804b02..7f7c69e4 100644 --- a/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/BaseRangerZKClientTest.java +++ b/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/BaseRangerZKClientTest.java @@ -33,8 +33,9 @@ import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.curator.test.TestingCluster; -import org.junit.After; -import org.junit.Before; +import org.junit.jupiter.api.AfterEach; + +import org.junit.jupiter.api.BeforeEach; import java.io.IOException; import java.util.Collections; @@ -49,7 +50,7 @@ public abstract class BaseRangerZKClientTest { private CuratorFramework curatorFramework; private ServiceProvider> provider; - @Before + @BeforeEach public void startTestCluster() throws Exception { objectMapper = new ObjectMapper(); testingCluster = new TestingCluster(3); @@ -65,7 +66,7 @@ public void startTestCluster() throws Exception { log.debug("Started zk subsystem"); } - @After + @AfterEach public void stopTestCluster() throws Exception { log.debug("Stopping zk subsystem"); curatorFramework.close(); @@ -112,7 +113,7 @@ protected void initilizeProvider(){ .withNodeData(TestNodeData.builder().shardId(1).build()) .withHealthcheck(() -> HealthcheckStatus.healthy) .withAdditionalRefreshSignal(refreshProviderSignal) - .withCuratorFramework(getCuratorFramework()) + .withCuratorFramework(curatorFramework) .build(); provider.start(); refreshProviderSignal.trigger(); diff --git a/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/ShardedZKRangerClientTest.java b/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/ShardedZKRangerClientTest.java index efb3685a..cfbfac71 100644 --- a/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/ShardedZKRangerClientTest.java +++ b/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/ShardedZKRangerClientTest.java @@ -19,14 +19,14 @@ import io.appform.ranger.core.utils.RangerTestUtils; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; @Slf4j -public class ShardedZKRangerClientTest extends BaseRangerZKClientTest { +class ShardedZKRangerClientTest extends BaseRangerZKClientTest { @Test - public void testShardedHub(){ + void testShardedHub(){ val zkHubClient = ShardedRangerZKHubClient.builder() .namespace("test-n") .connectionString(getTestingCluster().getConnectString()) @@ -37,8 +37,8 @@ public void testShardedHub(){ .nodeRefreshTimeMs(1000) .build(); zkHubClient.start(); - Assert.assertNotNull(zkHubClient.getNode(RangerTestUtils.getService("test-n", "s1")).orElse(null)); - Assert.assertNotNull(zkHubClient.getNode(RangerTestUtils.getService("test-n", "s1"), nodeData -> nodeData.getShardId() == 1).orElse(null)); + Assertions.assertNotNull(zkHubClient.getNode(RangerTestUtils.getService("test-n", "s1")).orElse(null)); + Assertions.assertNotNull(zkHubClient.getNode(RangerTestUtils.getService("test-n", "s1"), nodeData -> nodeData.getShardId() == 1).orElse(null)); zkHubClient.stop(); } } diff --git a/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/SimpleRangerZKClientTest.java b/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/SimpleRangerZKClientTest.java index c2c6ec09..233cbc33 100644 --- a/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/SimpleRangerZKClientTest.java +++ b/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/SimpleRangerZKClientTest.java @@ -17,13 +17,13 @@ import io.appform.ranger.core.units.TestNodeData; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class SimpleRangerZKClientTest extends BaseRangerZKClientTest { +class SimpleRangerZKClientTest extends BaseRangerZKClientTest { @Test - public void testBaseClient(){ + void testBaseClient(){ val client = SimpleRangerZKClient.builder() .curatorFramework(getCuratorFramework()) .deserializer(this::read) @@ -33,8 +33,8 @@ public void testBaseClient(){ .mapper(getObjectMapper()) .build(); client.start(); - Assert.assertNotNull( client.getNode().orElse(null)); - Assert.assertNotNull(client.getNode(c -> c.getShardId() == 1).orElse(null)); - Assert.assertNull(client.getNode(c -> c.getShardId() == 2).orElse(null)); + Assertions.assertNotNull( client.getNode().orElse(null)); + Assertions.assertNotNull(client.getNode(c -> c.getShardId() == 1).orElse(null)); + Assertions.assertNull(client.getNode(c -> c.getShardId() == 2).orElse(null)); } } diff --git a/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/UnshardedZKRangerClientTest.java b/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/UnshardedZKRangerClientTest.java index de3ffaaf..c42eb2ad 100644 --- a/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/UnshardedZKRangerClientTest.java +++ b/ranger-zk-client/src/test/java/io/appform/ranger/client/zk/UnshardedZKRangerClientTest.java @@ -19,14 +19,14 @@ import io.appform.ranger.core.utils.RangerTestUtils; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; @Slf4j -public class UnshardedZKRangerClientTest extends BaseRangerZKClientTest { +class UnshardedZKRangerClientTest extends BaseRangerZKClientTest { @Test - public void testShardedHub(){ + void testShardedHub(){ val zkHubClient =UnshardedRangerZKHubClient.builder() .namespace("test-n") .connectionString(getTestingCluster().getConnectString()) @@ -38,8 +38,8 @@ public void testShardedHub(){ .build(); zkHubClient.start(); val service = RangerTestUtils.getService("test-n", "s1"); - Assert.assertNotNull(zkHubClient.getNode(service).orElse(null)); - Assert.assertNotNull(zkHubClient.getNode(service, nodeData -> nodeData.getShardId() == 1).orElse(null)); + Assertions.assertNotNull(zkHubClient.getNode(service).orElse(null)); + Assertions.assertNotNull(zkHubClient.getNode(service, nodeData -> nodeData.getShardId() == 1).orElse(null)); zkHubClient.stop(); } } diff --git a/ranger-zk-server-bundle/pom.xml b/ranger-zk-server-bundle/pom.xml index 6dfd7b63..cf76d7d5 100644 --- a/ranger-zk-server-bundle/pom.xml +++ b/ranger-zk-server-bundle/pom.xml @@ -5,16 +5,12 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 ranger-zk-server-bundle - - 2.0.23 - - io.appform.ranger @@ -31,15 +27,9 @@ ranger-server-common ${project.version} - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - io.dropwizard dropwizard-core - ${dropwizard.version} provided diff --git a/ranger-zk-server-bundle/src/main/java/io/appform/ranger/server/bundle/ZKServerBundle.java b/ranger-zk-server-bundle/src/main/java/io/appform/ranger/server/bundle/ZKServerBundle.java index d3d02eb2..19e4b243 100644 --- a/ranger-zk-server-bundle/src/main/java/io/appform/ranger/server/bundle/ZKServerBundle.java +++ b/ranger-zk-server-bundle/src/main/java/io/appform/ranger/server/bundle/ZKServerBundle.java @@ -17,7 +17,6 @@ import com.codahale.metrics.health.HealthCheck; import com.fasterxml.jackson.core.type.TypeReference; -import com.google.common.collect.ImmutableList; import io.appform.ranger.client.RangerClientConstants; import io.appform.ranger.client.RangerHubClient; import io.appform.ranger.client.zk.UnshardedRangerZKHubClient; @@ -62,7 +61,7 @@ protected void preBundle(U configuration) { @Override protected List>> withHubs(U configuration) { val rangerConfiguration = getRangerConfiguration(configuration); - return ImmutableList.of(UnshardedRangerZKHubClient.builder() + return List.of(UnshardedRangerZKHubClient.builder() .namespace(rangerConfiguration.getNamespace()) .connectionString(rangerConfiguration.getZookeeper()) .curatorFramework(curatorFramework) @@ -82,12 +81,12 @@ protected List>> } protected List> withLifecycleSignals(U configuration) { - return ImmutableList.of( + return List.of( new CuratorLifecycle(curatorFramework) ); } protected List withHealthChecks(U configuration) { - return ImmutableList.of(new RangerHealthCheck(curatorFramework)); + return List.of(new RangerHealthCheck(curatorFramework)); } } diff --git a/ranger-zk-server/config/local.yml b/ranger-zk-server/config/local.yml index ee2f0adc..793a1b29 100644 --- a/ranger-zk-server/config/local.yml +++ b/ranger-zk-server/config/local.yml @@ -1,10 +1,8 @@ name: ranger-server -initialRotationStatus: false rangerConfiguration: namespace: test zookeeper: localhost:2181 - disablePushUpdaters: true server: maxThreads: 128 diff --git a/ranger-zk-server/pom.xml b/ranger-zk-server/pom.xml index cd01721d..b4a7f298 100644 --- a/ranger-zk-server/pom.xml +++ b/ranger-zk-server/pom.xml @@ -5,16 +5,12 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 ranger-zk-server - - 2.0.23 - - io.appform.ranger @@ -24,22 +20,6 @@ io.dropwizard dropwizard-core - ${dropwizard.version} - - - ch.qos.logback - logback-classic - ${logback.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} diff --git a/ranger-zk-server/src/main/java/io/appform/ranger/zk/server/App.java b/ranger-zk-server/src/main/java/io/appform/ranger/zk/server/App.java index 4c8b0b6e..2d68b0e8 100644 --- a/ranger-zk-server/src/main/java/io/appform/ranger/zk/server/App.java +++ b/ranger-zk-server/src/main/java/io/appform/ranger/zk/server/App.java @@ -29,7 +29,7 @@ public static void main(String[] args) throws Exception { @Override public void initialize(Bootstrap bootstrap) { - bootstrap.addBundle(new ZKServerBundle() { + bootstrap.addBundle(new ZKServerBundle<>() { @Override protected RangerConfiguration getRangerConfiguration(AppConfiguration configuration) { return configuration.getRangerConfiguration(); diff --git a/ranger-zk-server/src/main/java/io/appform/ranger/zk/server/AppConfiguration.java b/ranger-zk-server/src/main/java/io/appform/ranger/zk/server/AppConfiguration.java index e9583ad5..d04e2482 100644 --- a/ranger-zk-server/src/main/java/io/appform/ranger/zk/server/AppConfiguration.java +++ b/ranger-zk-server/src/main/java/io/appform/ranger/zk/server/AppConfiguration.java @@ -15,6 +15,7 @@ */ package io.appform.ranger.zk.server; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import io.appform.ranger.server.bundle.config.RangerConfiguration; import io.dropwizard.Configuration; import lombok.AllArgsConstructor; @@ -30,6 +31,7 @@ @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties(ignoreUnknown = true) public class AppConfiguration extends Configuration { @NotEmpty @NotNull diff --git a/ranger-zookeeper/pom.xml b/ranger-zookeeper/pom.xml index d026d139..e9356012 100644 --- a/ranger-zookeeper/pom.xml +++ b/ranger-zookeeper/pom.xml @@ -5,7 +5,7 @@ ranger io.appform.ranger - 1.0-RC14 + 1.0-RC15 4.0.0 @@ -17,7 +17,6 @@ ranger-core ${project.version} - org.apache.curator @@ -30,7 +29,6 @@ - org.apache.curator curator-recipes diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/ServiceHealthAggregatorTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/ServiceHealthAggregatorTest.java index 71b60903..eb9199e5 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/ServiceHealthAggregatorTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/ServiceHealthAggregatorTest.java @@ -21,20 +21,20 @@ import io.appform.ranger.core.healthservice.monitor.IsolatedHealthMonitor; import io.appform.ranger.core.healthservice.monitor.Monitor; import io.appform.ranger.core.utils.RangerTestUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.Date; -public class ServiceHealthAggregatorTest { +class ServiceHealthAggregatorTest { ServiceHealthAggregator serviceHealthAggregator = new ServiceHealthAggregator(); TestMonitor testMonitor; @SuppressWarnings("unchecked") - @Before + @BeforeEach public void setUp() { testMonitor = new TestMonitor("TestHealthMonitor", TimeEntity.everySecond(), 1000); serviceHealthAggregator.addIsolatedMonitor(testMonitor); @@ -54,13 +54,13 @@ public boolean isDisabled() { RangerTestUtils.sleepUntil(3, () -> serviceHealthAggregator.getRunning().get()); } - @After + @AfterEach public void tearDown() { serviceHealthAggregator.stop(); } @Test - public void testStaleRun() { + void testStaleRun() { testMonitor.run(); testMonitor.setThreadSleep(2000); @@ -69,14 +69,14 @@ public void testStaleRun() { /* in the TestMonitor, thread was sleeping for 2 seconds, */ /* so its state is supposed to be stale (>1 second) and service has to be unhealthy */ - Assert.assertEquals(HealthcheckStatus.unhealthy, serviceHealthAggregator.getServiceHealth()); + Assertions.assertEquals(HealthcheckStatus.unhealthy, serviceHealthAggregator.getServiceHealth()); testMonitor.setThreadSleep(5); RangerTestUtils.sleepUntil(3, () -> testMonitor.hasValidUpdatedTime(new Date())); /* in the TestMonitor, thread is sleeping only for 10 milliseconds, */ /* so its state is supposed to be NOT stale (>1 second) and service has to be healthy */ - Assert.assertEquals(HealthcheckStatus.healthy, serviceHealthAggregator.getServiceHealth()); + Assertions.assertEquals(HealthcheckStatus.healthy, serviceHealthAggregator.getServiceHealth()); } diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/ServiceProviderIntegrationTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/ServiceProviderIntegrationTest.java index 057fd911..b3e6819b 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/ServiceProviderIntegrationTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/ServiceProviderIntegrationTest.java @@ -31,16 +31,16 @@ import io.appform.ranger.zookeeper.ServiceProviderBuilders; import lombok.val; import org.apache.curator.test.TestingCluster; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; import java.util.List; -public class ServiceProviderIntegrationTest { +class ServiceProviderIntegrationTest { final String filePath = "/tmp/rangerRotationFile.html"; File file = new File(filePath); @@ -52,7 +52,7 @@ public class ServiceProviderIntegrationTest { SimpleShardedServiceFinder serviceFinder; - @Before + @BeforeEach public void startTestCluster() throws Exception { objectMapper = new ObjectMapper(); testingCluster = new TestingCluster(3); @@ -82,7 +82,7 @@ public void startTestCluster() throws Exception { serviceFinder.start(); } - @After + @AfterEach public void stopTestCluster() throws Exception { if (null != testingCluster) { testingCluster.close(); @@ -92,7 +92,7 @@ public void stopTestCluster() throws Exception { @SuppressWarnings("ResultOfMethodCallIgnored") @Test - public void testBasicDiscovery() throws Exception { + void testBasicDiscovery() throws Exception { /* clean slate */ file.delete(); @@ -104,7 +104,7 @@ public void testBasicDiscovery() throws Exception { RangerTestUtils.sleepUntil(5); List> all = serviceFinder.getAll(null); System.out.println("all = " + all); - Assert.assertEquals(3, all.size()); + Assertions.assertEquals(3, all.size()); /* with file deleted, all 3 nodes should be unhealthy */ file.delete(); @@ -112,7 +112,7 @@ public void testBasicDiscovery() throws Exception { RangerTestUtils.sleepUntil(5); all = serviceFinder.getAll(null); System.out.println("all = " + all); - Assert.assertEquals(0, all.size()); + Assertions.assertEquals(0, all.size()); /* with anotherFile created, the 4th node should become healthy and discoverable */ anotherFile.createNewFile(); @@ -120,7 +120,7 @@ public void testBasicDiscovery() throws Exception { RangerTestUtils.sleepUntil(5); all = serviceFinder.getAll(null); System.out.println("all = " + all); - Assert.assertEquals(1, all.size()); + Assertions.assertEquals(1, all.size()); /* clean slate */ file.delete(); diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/RollingWindowHealthQueueTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/RollingWindowHealthQueueTest.java index 36388018..a3845472 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/RollingWindowHealthQueueTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/RollingWindowHealthQueueTest.java @@ -18,97 +18,97 @@ import io.appform.ranger.core.healthcheck.HealthcheckStatus; import io.appform.ranger.core.healthservice.monitor.RollingWindowHealthQueue; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class RollingWindowHealthQueueTest { +class RollingWindowHealthQueueTest { @Test - public void testCheckInRollingWindow1() { + void testCheckInRollingWindow1() { val rollingWindowHealthQueue = new RollingWindowHealthQueue(5, 3); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); } @Test - public void testCheckInRollingWindowEdge() { + void testCheckInRollingWindowEdge() { try { val rollingWindowHealthQueue = new RollingWindowHealthQueue(1, 3); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); } catch (Exception u) { - Assert.assertTrue(u instanceof UnsupportedOperationException); + Assertions.assertTrue(u instanceof UnsupportedOperationException); } } @Test - public void testCheckInRollingWindowEdge2() { + void testCheckInRollingWindowEdge2() { val rollingWindowHealthQueue = new RollingWindowHealthQueue(3, 3); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); } @Test - public void testCheckInRollingWindowEdge3() { + void testCheckInRollingWindowEdge3() { val rollingWindowHealthQueue = new RollingWindowHealthQueue(5, 1); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); } @Test - public void testCheckInRollingWindow2() { + void testCheckInRollingWindow2() { val rollingWindowHealthQueue = new RollingWindowHealthQueue(5, 3); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); } @Test - public void testCheckInRollingWindow3() { + void testCheckInRollingWindow3() { val rollingWindowHealthQueue = new RollingWindowHealthQueue(5, 3); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); } @Test - public void testCheckInRollingWindow4() { + void testCheckInRollingWindow4() { val rollingWindowHealthQueue = new RollingWindowHealthQueue(5, 3); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); - Assert.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); - Assert.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); + Assertions.assertFalse(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.healthy)); + Assertions.assertTrue(rollingWindowHealthQueue.checkInRollingWindow(HealthcheckStatus.unhealthy)); } } \ No newline at end of file diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/DiskSpaceMonitorTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/DiskSpaceMonitorTest.java index 5e29dd48..609281ed 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/DiskSpaceMonitorTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/DiskSpaceMonitorTest.java @@ -18,24 +18,23 @@ import io.appform.ranger.core.healthcheck.HealthcheckStatus; import io.appform.ranger.core.healthservice.TimeEntity; -import io.appform.ranger.core.healthservice.monitor.IsolatedHealthMonitor; import io.appform.ranger.core.healthservice.monitor.sample.DiskSpaceMonitor; import lombok.val; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.util.concurrent.TimeUnit; -public class DiskSpaceMonitorTest { +class DiskSpaceMonitorTest { @Test - public void testGetCount() { + void testGetCount() { val diskSpaceMonitor = new DiskSpaceMonitor("/", 1000, new TimeEntity(2, TimeUnit.SECONDS)); - Assert.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, diskSpaceMonitor.monitor()); } } \ No newline at end of file diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/PingCheckMonitorTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/PingCheckMonitorTest.java index 70e467b4..573418a5 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/PingCheckMonitorTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/PingCheckMonitorTest.java @@ -20,32 +20,32 @@ import io.appform.ranger.core.healthservice.monitor.sample.PingCheckMonitor; import lombok.val; import org.apache.http.client.methods.HttpGet; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.util.concurrent.TimeUnit; -public class PingCheckMonitorTest { +class PingCheckMonitorTest { @Test - public void testMonitor() { + void testMonitor() { val httpRequest = new HttpGet("/"); val pingCheckMonitor = new PingCheckMonitor(new TimeEntity(2, TimeUnit.SECONDS), httpRequest, 5000, 5, 3, "google.com", 80); - Assert.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); } @Test - public void testMonitor2() { + void testMonitor2() { val httpRequest = new HttpGet("/help"); val pingCheckMonitor = new PingCheckMonitor(new TimeEntity(2, TimeUnit.SECONDS), httpRequest, 5000, 5, 3, "google.com", 80); - Assert.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.unhealthy, pingCheckMonitor.monitor()); - Assert.assertEquals(HealthcheckStatus.unhealthy, pingCheckMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, pingCheckMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.unhealthy, pingCheckMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.unhealthy, pingCheckMonitor.monitor()); } } \ No newline at end of file diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/RotationStatusMonitorTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/RotationStatusMonitorTest.java index f92be35c..7a0b3f5b 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/RotationStatusMonitorTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/healthservice/monitor/sample/RotationStatusMonitorTest.java @@ -18,41 +18,41 @@ import io.appform.ranger.core.healthcheck.HealthcheckStatus; import io.appform.ranger.core.healthservice.monitor.sample.RotationStatusMonitor; import lombok.val; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.File; -public class RotationStatusMonitorTest { +class RotationStatusMonitorTest { final String filePath = "/tmp/rangerRotationFile.html"; File file = new File(filePath); - @Before + @BeforeEach public void setUp() throws Exception { deleteRotationFile(); } - @After + @AfterEach public void tearDown() throws Exception { deleteRotationFile(); } @Test - public void testMonitor() throws Exception { + void testMonitor() throws Exception { deleteRotationFile(); val rotationStatusMonitor = new RotationStatusMonitor("/tmp/rotationFile.html"); - Assert.assertEquals(HealthcheckStatus.unhealthy, rotationStatusMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.unhealthy, rotationStatusMonitor.monitor()); } @Test - public void testMonitor2() throws Exception { + void testMonitor2() throws Exception { deleteRotationFile(); if (file.createNewFile()) { val rotationStatusMonitor = new RotationStatusMonitor(filePath); - Assert.assertEquals(HealthcheckStatus.healthy, rotationStatusMonitor.monitor()); + Assertions.assertEquals(HealthcheckStatus.healthy, rotationStatusMonitor.monitor()); } else { System.out.println("Unable to create file = " + filePath); throw new Exception("Unable to create file = " + filePath); diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/CustomShardSelectorTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/CustomShardSelectorTest.java index 1197d3e7..aeec80f1 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/CustomShardSelectorTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/CustomShardSelectorTest.java @@ -31,10 +31,10 @@ import lombok.extern.jackson.Jacksonized; import lombok.extern.slf4j.Slf4j; import org.apache.curator.test.TestingCluster; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.ArrayList; @@ -43,12 +43,12 @@ @Slf4j -public class CustomShardSelectorTest { +class CustomShardSelectorTest { private TestingCluster testingCluster; private ObjectMapper objectMapper; private final List>> serviceProviders = Lists.newArrayList(); - @Before + @BeforeEach public void startTestCluster() throws Exception { objectMapper = new ObjectMapper(); testingCluster = new TestingCluster(3); @@ -58,7 +58,7 @@ public void startTestCluster() throws Exception { registerService("localhost-3", 9002, 2, 3); } - @After + @AfterEach public void stopTestCluster() throws Exception { serviceProviders.forEach(ServiceProvider::stop); if (null != testingCluster) { @@ -94,7 +94,7 @@ public List> nodes(Predicate criteria, } @Test - public void testBasicDiscovery() { + void testBasicDiscovery() { val serviceFinder = ServiceFinderBuilders.shardedFinderBuilder() .withConnectionString(testingCluster.getConnectString()) .withNamespace("test") @@ -113,16 +113,16 @@ public void testBasicDiscovery() { serviceFinder.start(); { val node = serviceFinder.get(TestShardInfo.getCriteria(1, 10)).orElse(null); - Assert.assertNull(node); + Assertions.assertNull(node); } { val node = serviceFinder.get(TestShardInfo.getCriteria(1, 2)).orElse(null); - Assert.assertNotNull(node); - Assert.assertEquals(new TestShardInfo(1, 2), node.getNodeData()); + Assertions.assertNotNull(node); + Assertions.assertEquals(new TestShardInfo(1, 2), node.getNodeData()); } { val node = serviceFinder.get(TestShardInfo.getCriteria(2, 3)).orElse(null); - Assert.assertNotNull(node); + Assertions.assertNotNull(node); } serviceFinder.stop(); } diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceNoProviderTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceNoProviderTest.java index cd2732fe..a5bd64eb 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceNoProviderTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceNoProviderTest.java @@ -24,26 +24,27 @@ import io.appform.ranger.zookeeper.ServiceFinderBuilders; import lombok.val; import org.apache.curator.test.TestingCluster; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import java.io.IOException; -public class ServiceNoProviderTest { +class ServiceNoProviderTest { private TestingCluster testingCluster; private ObjectMapper objectMapper; - @Before + @BeforeEach public void startTestCluster() throws Exception { objectMapper = new ObjectMapper(); testingCluster = new TestingCluster(3); testingCluster.start(); } - @After + @AfterEach public void stopTestCluster() throws Exception { if (null != testingCluster) { testingCluster.close(); @@ -51,7 +52,7 @@ public void stopTestCluster() throws Exception { } @Test - public void testBasicDiscovery() { + void testBasicDiscovery() { val serviceFinder = ServiceFinderBuilders.shardedFinderBuilder() .withConnectionString(testingCluster.getConnectString()) .withNamespace("test") @@ -70,13 +71,13 @@ public void testBasicDiscovery() { .build(); serviceFinder.start(); val node = serviceFinder.get(RangerTestUtils.getCriteria(1)).orElse(null); - Assert.assertNull(node); + Assertions.assertNull(node); serviceFinder.stop(); } @Test - public void testBasicDiscoveryRR() { + void testBasicDiscoveryRR() { val serviceFinder = ServiceFinderBuilders.shardedFinderBuilder() .withConnectionString(testingCluster.getConnectString()) .withNamespace("test") @@ -96,7 +97,7 @@ public void testBasicDiscoveryRR() { .build(); serviceFinder.start(); val node = serviceFinder.get(RangerTestUtils.getCriteria(1)).orElse(null); - Assert.assertNull(node); + Assertions.assertNull(node); serviceFinder.stop(); } diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderExtCuratorTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderExtCuratorTest.java index db175338..5705fa78 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderExtCuratorTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderExtCuratorTest.java @@ -33,24 +33,24 @@ import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.curator.test.TestingCluster; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.List; import java.util.stream.LongStream; @Slf4j -public class ServiceProviderExtCuratorTest { +class ServiceProviderExtCuratorTest { private TestingCluster testingCluster; private ObjectMapper objectMapper; private final List>> serviceProviders = Lists.newArrayList(); private CuratorFramework curatorFramework; - @Before + @BeforeEach public void startTestCluster() throws Exception { objectMapper = new ObjectMapper(); testingCluster = new TestingCluster(3); @@ -65,7 +65,7 @@ public void startTestCluster() throws Exception { registerService("localhost-3", 9002, 2); } - @After + @AfterEach public void stopTestCluster() throws Exception { serviceProviders.forEach(ServiceProvider::stop); curatorFramework.close(); @@ -75,7 +75,7 @@ public void stopTestCluster() throws Exception { } @Test - public void testBasicDiscovery() { + void testBasicDiscovery() { val serviceFinder = ServiceFinderBuilders.shardedFinderBuilder() .withCuratorFramework(curatorFramework) .withNamespace("test") @@ -94,23 +94,23 @@ public void testBasicDiscovery() { serviceFinder.start(); { val node = serviceFinder.get(RangerTestUtils.getCriteria(1)).orElse(null); - Assert.assertNotNull(node); - Assert.assertEquals(1, node.getNodeData().getShardId()); + Assertions.assertNotNull(node); + Assertions.assertEquals(1, node.getNodeData().getShardId()); } { val node = serviceFinder.get(RangerTestUtils.getCriteria(1)).orElse(null); - Assert.assertNotNull(node); - Assert.assertEquals(1, node.getNodeData().getShardId()); + Assertions.assertNotNull(node); + Assertions.assertEquals(1, node.getNodeData().getShardId()); } val startTime = System.currentTimeMillis(); LongStream.range(0, 1000000).mapToObj(i -> serviceFinder.get(RangerTestUtils.getCriteria(2)).orElse(null)).forEach(node -> { - Assert.assertNotNull(node); - Assert.assertEquals(2, node.getNodeData().getShardId()); + Assertions.assertNotNull(node); + Assertions.assertEquals(2, node.getNodeData().getShardId()); }); log.info("PERF::RandomSelector::Took (ms):" + (System.currentTimeMillis() - startTime)); { val node = serviceFinder.get(RangerTestUtils.getCriteria(99)).orElse(null); - Assert.assertNull(node); + Assertions.assertNull(node); } serviceFinder.stop(); } diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderHealthcheckTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderHealthcheckTest.java index 88dfc36a..0ec4377d 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderHealthcheckTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderHealthcheckTest.java @@ -30,21 +30,21 @@ import lombok.Getter; import lombok.val; import org.apache.curator.test.TestingCluster; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Map; -public class ServiceProviderHealthcheckTest { +class ServiceProviderHealthcheckTest { private TestingCluster testingCluster; private ObjectMapper objectMapper; private final Map serviceProviders = Maps.newHashMap(); - @Before + @BeforeEach public void startTestCluster() throws Exception { objectMapper = new ObjectMapper(); testingCluster = new TestingCluster(3); @@ -53,7 +53,7 @@ public void startTestCluster() throws Exception { registerService("localhost-3", 9001, 2); } - @After + @AfterEach public void stopTestCluster() throws Exception { if (null != testingCluster) { testingCluster.close(); @@ -61,7 +61,7 @@ public void stopTestCluster() throws Exception { } @Test - public void testBasicDiscovery() { + void testBasicDiscovery() { val serviceFinder = ServiceFinderBuilders.shardedFinderBuilder() .withConnectionString(testingCluster.getConnectString()) .withNamespace("test") @@ -80,12 +80,12 @@ public void testBasicDiscovery() { .build(); serviceFinder.start(); val node = serviceFinder.get(RangerTestUtils.getCriteria(1)).orElse(null); - Assert.assertNotNull(node); - Assert.assertEquals("localhost-1", node.getHost()); + Assertions.assertNotNull(node); + Assertions.assertEquals("localhost-1", node.getHost()); TestServiceProvider testServiceProvider = serviceProviders.get(node.getHost()); testServiceProvider.oor(); RangerTestUtils.sleepUntil(2); //Sleep till the increment refresh healthCheck interval (> 1sec), no upper bound condition. - Assert.assertFalse(serviceFinder.get(RangerTestUtils.getCriteria(1)).isPresent()); + Assertions.assertFalse(serviceFinder.get(RangerTestUtils.getCriteria(1)).isPresent()); serviceFinder.stop(); } @@ -134,7 +134,7 @@ public void oor() { healthcheck.setStatus(HealthcheckStatus.unhealthy); } - public void start() throws Exception { + public void start() { val serviceProvider = ServiceProviderBuilders.shardedServiceProviderBuilder() .withConnectionString(connectionString) .withNamespace("test") diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderTest.java index 899e4407..73d8e1a3 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/ServiceProviderTest.java @@ -32,23 +32,23 @@ import lombok.extern.slf4j.Slf4j; import lombok.val; import org.apache.curator.test.TestingCluster; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.List; import java.util.stream.LongStream; @Slf4j -public class ServiceProviderTest { +class ServiceProviderTest { private TestingCluster testingCluster; private ObjectMapper objectMapper; private final List>> serviceProviders = Lists.newArrayList(); - @Before + @BeforeEach public void startTestCluster() throws Exception { objectMapper = new ObjectMapper(); testingCluster = new TestingCluster(3); @@ -59,7 +59,7 @@ public void startTestCluster() throws Exception { registerService("localhost-4", 9003, 2); } - @After + @AfterEach public void stopTestCluster() throws Exception { serviceProviders.forEach(ServiceProvider::stop); if (null != testingCluster) { @@ -68,7 +68,7 @@ public void stopTestCluster() throws Exception { } @Test - public void testBasicDiscovery() { + void testBasicDiscovery() { val serviceFinder = ServiceFinderBuilders.shardedFinderBuilder() .withConnectionString(testingCluster.getConnectString()) .withNamespace("test") @@ -86,29 +86,29 @@ public void testBasicDiscovery() { serviceFinder.start(); { val node = serviceFinder.get(RangerTestUtils.getCriteria(1)).orElse(null); - Assert.assertNotNull(node); - Assert.assertEquals(1, node.getNodeData().getShardId()); + Assertions.assertNotNull(node); + Assertions.assertEquals(1, node.getNodeData().getShardId()); } { val node = serviceFinder.get(RangerTestUtils.getCriteria(1)).orElse(null); - Assert.assertNotNull(node); - Assert.assertEquals(1, node.getNodeData().getShardId()); + Assertions.assertNotNull(node); + Assertions.assertEquals(1, node.getNodeData().getShardId()); } val startTime = System.currentTimeMillis(); LongStream.range(0, 1000000).mapToObj(i -> serviceFinder.get(RangerTestUtils.getCriteria(2)).orElse(null)).forEach(node -> { - Assert.assertNotNull(node); - Assert.assertEquals(2, node.getNodeData().getShardId()); + Assertions.assertNotNull(node); + Assertions.assertEquals(2, node.getNodeData().getShardId()); }); log.info("PERF::RandomSelector::Took (ms):" + (System.currentTimeMillis() - startTime)); { val node = serviceFinder.get(RangerTestUtils.getCriteria(99)).orElse(null); - Assert.assertNull(node); + Assertions.assertNull(node); } serviceFinder.stop(); } @Test - public void testBasicDiscoveryRR() { + void testBasicDiscoveryRR() { val serviceFinder = ServiceFinderBuilders.shardedFinderBuilder() .withConnectionString(testingCluster.getConnectString()) @@ -129,30 +129,30 @@ public void testBasicDiscoveryRR() { serviceFinder.start(); { val node = serviceFinder.get(RangerTestUtils.getCriteria(1)); - Assert.assertTrue(node.isPresent()); - Assert.assertEquals(1, node.get().getNodeData().getShardId()); + Assertions.assertTrue(node.isPresent()); + Assertions.assertEquals(1, node.get().getNodeData().getShardId()); } { val node = serviceFinder.get(RangerTestUtils.getCriteria(1)); - Assert.assertTrue(node.isPresent()); - Assert.assertEquals(1, node.get().getNodeData().getShardId()); + Assertions.assertTrue(node.isPresent()); + Assertions.assertEquals(1, node.get().getNodeData().getShardId()); } long startTime = System.currentTimeMillis(); LongStream.range(0, 1000000).mapToObj(i -> serviceFinder.get(RangerTestUtils.getCriteria(2))).forEach(node -> { - Assert.assertTrue(node.isPresent()); - Assert.assertEquals(2, node.get().getNodeData().getShardId()); + Assertions.assertTrue(node.isPresent()); + Assertions.assertEquals(2, node.get().getNodeData().getShardId()); }); log.info("PERF::RoundRobinSelector::Took (ms):" + (System.currentTimeMillis() - startTime)); { val node = serviceFinder.get(RangerTestUtils.getCriteria(99)); - Assert.assertFalse(node.isPresent()); + Assertions.assertFalse(node.isPresent()); } serviceFinder.stop(); //while (true); } @Test - public void testVisibility() { + void testVisibility() { val serviceFinder = ServiceFinderBuilders. shardedFinderBuilder() .withConnectionString(testingCluster.getConnectString()) @@ -175,7 +175,7 @@ public void testVisibility() { log.info("Testing ServiceFinder.getAll()"); all.stream().map(serviceNode -> "node = " + serviceNode.getHost() + ":" + serviceNode.getPort() + " " + serviceNode.getHealthcheckStatus() + " " + serviceNode .getLastUpdatedTimeStamp()).forEach(log::info); - Assert.assertEquals(3, all.size()); + Assertions.assertEquals(3, all.size()); serviceFinder.stop(); } diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/SimpleServiceProviderTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/SimpleServiceProviderTest.java index 255900a6..f92ec88c 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/SimpleServiceProviderTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/model/SimpleServiceProviderTest.java @@ -26,20 +26,20 @@ import io.appform.ranger.zookeeper.ServiceProviderBuilders; import lombok.val; import org.apache.curator.test.TestingCluster; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.stream.LongStream; -public class SimpleServiceProviderTest { +class SimpleServiceProviderTest { private TestingCluster testingCluster; private ObjectMapper objectMapper; - @Before + @BeforeEach public void startTestCluster() throws Exception { objectMapper = new ObjectMapper(); testingCluster = new TestingCluster(3); @@ -49,7 +49,7 @@ public void startTestCluster() throws Exception { registerService("localhost-3", 9002); } - @After + @AfterEach public void stopTestCluster() throws Exception { if(null != testingCluster) { testingCluster.close(); @@ -70,7 +70,7 @@ public boolean equals(Object obj) { } @Test - public void testBasicDiscovery() { + void testBasicDiscovery() { val serviceFinder = ServiceFinderBuilders.unshardedFinderBuilder() .withConnectionString(testingCluster.getConnectString()) .withNamespace("test") @@ -90,13 +90,13 @@ public void testBasicDiscovery() { serviceFinder.start(); { val node = serviceFinder.get(null).orElse(null); - Assert.assertNotNull(node); + Assertions.assertNotNull(node); System.out.println(node.getHost()); } val frequency = HashMultiset.create(); val startTime = System.currentTimeMillis(); LongStream.range(0, 1000000).mapToObj(i -> serviceFinder.get(null).orElse(null)).forEach(node -> { - Assert.assertNotNull(node); + Assertions.assertNotNull(node); frequency.add(node.getHost()); }); System.out.println("1 Million lookups and freq counting took (ms):" + (System.currentTimeMillis() -startTime)); diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/servicehub/ServiceHubTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/servicehub/ServiceHubTest.java index 6a818cee..f082548a 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/servicehub/ServiceHubTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/servicehub/ServiceHubTest.java @@ -35,10 +35,10 @@ import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.curator.test.TestingCluster; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Collections; @@ -48,7 +48,7 @@ * */ @Slf4j -public class ServiceHubTest { +class ServiceHubTest { private static final String NAMESPACE = "test"; @@ -56,7 +56,7 @@ public class ServiceHubTest { private ObjectMapper objectMapper = new ObjectMapper(); private CuratorFramework curatorFramework; - @Before + @BeforeEach public void startTestCluster() throws Exception { objectMapper = new ObjectMapper(); testingCluster = new TestingCluster(3); @@ -71,7 +71,7 @@ public void startTestCluster() throws Exception { log.debug("Started zk subsystem"); } - @After + @AfterEach public void stopTestCluster() throws Exception { log.debug("Stopping zk subsystem"); curatorFramework.close(); @@ -81,7 +81,7 @@ public void stopTestCluster() throws Exception { } @Test - public void testHub() { + void testHub() { val refreshProviderSignal = new ExternalTriggeredSignal<>( () -> HealthcheckResult.builder() .status(HealthcheckStatus.healthy) @@ -118,7 +118,7 @@ public void testHub() { val node = hub.finder(RangerTestUtils.getService(NAMESPACE, "s1")) .flatMap(finder -> finder.get(nodeData -> nodeData.getShardId() == 1)).orElse(null); - Assert.assertNotNull(node); + Assertions.assertNotNull(node); hub.stop(); provider1.stop(); } diff --git a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/serviceprovider/BaseServiceProviderBuilderTest.java b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/serviceprovider/BaseServiceProviderBuilderTest.java index 7cadf7c5..33aabf64 100644 --- a/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/serviceprovider/BaseServiceProviderBuilderTest.java +++ b/ranger-zookeeper/src/test/java/io/appform/ranger/zookeeper/serviceprovider/BaseServiceProviderBuilderTest.java @@ -22,29 +22,29 @@ import io.appform.ranger.zookeeper.ServiceProviderBuilders; import lombok.val; import org.apache.curator.test.TestingCluster; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author tushar.naik * @version 1.0 * @date 12/03/16 - 7:40 PM */ -public class BaseServiceProviderBuilderTest { +class BaseServiceProviderBuilderTest { private TestingCluster testingCluster; private ObjectMapper objectMapper; - @Before + @BeforeEach public void startTestCluster() throws Exception { objectMapper = new ObjectMapper(); testingCluster = new TestingCluster(3); testingCluster.start(); } - @After + @AfterEach public void stopTestCluster() throws Exception { if(null != testingCluster) { testingCluster.close(); @@ -52,7 +52,7 @@ public void stopTestCluster() throws Exception { } @Test - public void testServiceProviderBuilder() { + void testServiceProviderBuilder() { val host = "localhost"; val port = 9000; Exception exception = null; @@ -77,7 +77,7 @@ public void testServiceProviderBuilder() { } catch (Exception e) { exception = e; } - Assert.assertTrue(exception instanceof IllegalArgumentException); + Assertions.assertTrue(exception instanceof IllegalArgumentException); val serviceProvider = ServiceProviderBuilders.unshardedServiceProviderBuilder() .withConnectionString(testingCluster.getConnectString())