From 7587af8de972785610fa4491f4cfbe033a6fcf50 Mon Sep 17 00:00:00 2001 From: Oleg Anastassov Date: Sat, 27 Jul 2024 09:26:58 +0200 Subject: [PATCH] feature control --- .../vms/api/internal/FeatureController.java | 35 +++++++++++ .../api/internal/FeatureControllerTest.java | 63 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/main/java/vms/api/internal/FeatureController.java create mode 100644 src/test/java/vms/api/internal/FeatureControllerTest.java diff --git a/src/main/java/vms/api/internal/FeatureController.java b/src/main/java/vms/api/internal/FeatureController.java new file mode 100644 index 0000000..f3d7de1 --- /dev/null +++ b/src/main/java/vms/api/internal/FeatureController.java @@ -0,0 +1,35 @@ +package vms.api.internal; + +import static java.util.function.Predicate.not; +import static java.util.stream.Collectors.toSet; + +import java.util.Collection; +import java.util.Map; +import java.util.stream.Stream; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/internal/feature-control") +public class FeatureController { + + private final Collection features; + + FeatureController(Environment environment) { + var values = environment.getProperty("FEATURE_CONTROL", "").split(","); + features = Stream.of(values).map(String::trim).filter(not(String::isBlank)).collect(toSet()); + } + + @GetMapping + Collection getAll() { + return features; + } + + @GetMapping("/{name}") + Map getFeature(@PathVariable String name) { + return Map.of(name, features.contains(name)); + } +} diff --git a/src/test/java/vms/api/internal/FeatureControllerTest.java b/src/test/java/vms/api/internal/FeatureControllerTest.java new file mode 100644 index 0000000..f063464 --- /dev/null +++ b/src/test/java/vms/api/internal/FeatureControllerTest.java @@ -0,0 +1,63 @@ +package vms.api.internal; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import java.util.Collection; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.core.env.Environment; + +@ExtendWith(MockitoExtension.class) +class FeatureControllerTest { + + @Mock Environment environment; + + @BeforeEach + void setUp() { + when(environment.getProperty("FEATURE_CONTROL", "")).thenReturn("FooEarlyPreview,HideAppBar"); + } + + @Test + void shouldReturnNoFeaturesIfNoEnvironmentPropertySet() { + // given + when(environment.getProperty("FEATURE_CONTROL", "")).thenReturn(""); + + // when + Collection features = new FeatureController(environment).getAll(); + + // then + assertThat(features).isEmpty(); + } + + @Test + void shouldReturnFeaturesIfEnvironmentPropertySet() { + // when + Collection features = new FeatureController(environment).getAll(); + + // then + assertThat(features).containsOnly("FooEarlyPreview", "HideAppBar"); + } + + @Test + void shouldReturnFeatureDisabledIfNoFeaturePresent() { + // when + Map feature = new FeatureController(environment).getFeature("NewUI"); + + // then + assertThat(feature).containsExactly(Map.entry("NewUI", false)); + } + + @Test + void shouldReturnFeatureEnabledIfFeaturePresent() { + // when + Map feature = new FeatureController(environment).getFeature("HideAppBar"); + + // then + assertThat(feature).containsExactly(Map.entry("HideAppBar", true)); + } +}