diff --git a/litmus-client/pom.xml b/litmus-client/pom.xml index a8b779e..8b79263 100644 --- a/litmus-client/pom.xml +++ b/litmus-client/pom.xml @@ -40,12 +40,6 @@ - - - - - - com.navi.medici litmus-model @@ -76,6 +70,13 @@ 2.13.0 + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.13.0 + + + diff --git a/litmus-client/src/main/java/com/navi/medici/client/ExperimentBackupHandlerFile.java b/litmus-client/src/main/java/com/navi/medici/client/ExperimentBackupHandlerFile.java index 0b0fbcc..7266408 100644 --- a/litmus-client/src/main/java/com/navi/medici/client/ExperimentBackupHandlerFile.java +++ b/litmus-client/src/main/java/com/navi/medici/client/ExperimentBackupHandlerFile.java @@ -13,6 +13,7 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import lombok.extern.log4j.Log4j2; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.core.util.IOUtils; @Log4j2 @@ -28,7 +29,14 @@ public class ExperimentBackupHandlerFile implements ExperimentBackupHandler { public LitmusExperimentCollection read() { log.info("Litmus will try to load experiments states from temporary backup"); try (FileReader reader = new FileReader(backupFile)) { - return JacksonUtils.stringToObject(IOUtils.toString(reader), LitmusExperimentCollection.class); + var data = IOUtils.toString(reader); + if (StringUtils.isBlank(data)) { + List emptyList = Collections.emptyList(); + return LitmusExperimentCollection.builder() + .litmusExperiments(emptyList) + .build(); + } + return JacksonUtils.stringToObject(data, LitmusExperimentCollection.class); } catch (FileNotFoundException e) { log.info( " Litmus could not find the backup-file '" diff --git a/litmus-client/src/main/java/com/navi/medici/util/JacksonUtils.java b/litmus-client/src/main/java/com/navi/medici/util/JacksonUtils.java index 1f4c75d..f8f4cfb 100644 --- a/litmus-client/src/main/java/com/navi/medici/util/JacksonUtils.java +++ b/litmus-client/src/main/java/com/navi/medici/util/JacksonUtils.java @@ -11,7 +11,9 @@ import lombok.extern.log4j.Log4j2; public class JacksonUtils { public static String objectToString(Object o) { try { - return new ObjectMapper().writeValueAsString(o); + var objectMapper = new ObjectMapper(); + objectMapper.findAndRegisterModules(); + return objectMapper.writeValueAsString(o); } catch (JsonProcessingException e) { throw new RuntimeException("object to string conversion failed", e); } @@ -19,7 +21,9 @@ public class JacksonUtils { public static T stringToObject(String s, Class klazz) { try { - return new ObjectMapper().readValue(s, klazz); + var objectMapper = new ObjectMapper(); + objectMapper.findAndRegisterModules(); + return objectMapper.readValue(s, klazz); } catch (JsonProcessingException e) { throw new RuntimeException("string to object conversion failed", e); } @@ -27,9 +31,12 @@ public class JacksonUtils { public static List stringToListObject(String s, Class klazz) { try { - CollectionType listType = new ObjectMapper().getTypeFactory().constructCollectionType(ArrayList.class, klazz); + var objectMapper = new ObjectMapper(); + objectMapper.findAndRegisterModules(); - return new ObjectMapper().readValue(s, listType); + CollectionType listType = objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, klazz); + + return objectMapper.readValue(s, listType); } catch (JsonProcessingException e) { throw new RuntimeException("string to list object conversion failed", e); } diff --git a/litmus-client/src/main/java/com/navi/medici/util/VariantUtil.java b/litmus-client/src/main/java/com/navi/medici/util/VariantUtil.java index d2068db..7c0b099 100644 --- a/litmus-client/src/main/java/com/navi/medici/util/VariantUtil.java +++ b/litmus-client/src/main/java/com/navi/medici/util/VariantUtil.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Optional; import java.util.Random; import java.util.function.Predicate; +import org.apache.commons.lang3.StringUtils; public final class VariantUtil { private VariantUtil() {} @@ -80,7 +81,7 @@ public final class VariantUtil { } public static Variant selectVariant(LitmusExperiment litmusExperiment, LitmusContext context, Variant defaultVariant) { - if (litmusExperiment == null) { + if (litmusExperiment == null || StringUtils.isBlank(litmusExperiment.getVariants())) { return defaultVariant; } List variants = JacksonUtils.stringToListObject(litmusExperiment.getVariants(), VariantDefinition.class); diff --git a/litmus-core/pom.xml b/litmus-core/pom.xml index 136d430..f8ace9c 100644 --- a/litmus-core/pom.xml +++ b/litmus-core/pom.xml @@ -85,6 +85,12 @@ opencsv 5.5.2 + + + io.springfox + springfox-boot-starter + 3.0.0 + diff --git a/litmus-core/src/main/java/com/navi/medici/config/SwaggerConfig.java b/litmus-core/src/main/java/com/navi/medici/config/SwaggerConfig.java new file mode 100644 index 0000000..490a705 --- /dev/null +++ b/litmus-core/src/main/java/com/navi/medici/config/SwaggerConfig.java @@ -0,0 +1,24 @@ +package com.navi.medici.config; + +import static springfox.documentation.builders.PathSelectors.regex; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@EnableSwagger2 +@Configuration +public class SwaggerConfig { + + @Bean + public Docket configureSwagger() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.any()) + .paths(regex("/litmus-core/v1/.*")) + .build(); + } +} diff --git a/litmus-core/src/main/java/com/navi/medici/controller/v1/ExperimentController.java b/litmus-core/src/main/java/com/navi/medici/controller/v1/ExperimentController.java index b32433b..118d43c 100644 --- a/litmus-core/src/main/java/com/navi/medici/controller/v1/ExperimentController.java +++ b/litmus-core/src/main/java/com/navi/medici/controller/v1/ExperimentController.java @@ -42,7 +42,7 @@ public class ExperimentController { @PutMapping(value = "/attach/variants/{experiment_id}", consumes = MediaType.APPLICATION_JSON_VALUE) public void attachVariants(@PathVariable("experiment_id") String experimentId, @RequestBody List variantDefinitions) { - + experimentService.attachVariants(experimentId, variantDefinitions); } } diff --git a/litmus-core/src/main/java/com/navi/medici/service/experiment/ExperimentServiceImpl.java b/litmus-core/src/main/java/com/navi/medici/service/experiment/ExperimentServiceImpl.java index 5c2e649..237ac0e 100644 --- a/litmus-core/src/main/java/com/navi/medici/service/experiment/ExperimentServiceImpl.java +++ b/litmus-core/src/main/java/com/navi/medici/service/experiment/ExperimentServiceImpl.java @@ -74,6 +74,7 @@ public class ExperimentServiceImpl implements ExperimentService { .enabled(experimentEntity.getEnabled()) .archived(experimentEntity.getArchived()) .strategies(jacksonUtils.stringToListObject(experimentEntity.getStrategies(), ActivationStrategy.class)) + .variants(experimentEntity.getVariants()) .type(experimentEntity.getType()) .startTime(experimentEntity.getStartTime()) .endTime(experimentEntity.getEndTime()) diff --git a/litmus-mock/src/main/java/com/navi/medici/container/CustomLitmusContextProvider.java b/litmus-mock/src/main/java/com/navi/medici/container/CustomLitmusContextProvider.java index d17b56c..c82b9da 100644 --- a/litmus-mock/src/main/java/com/navi/medici/container/CustomLitmusContextProvider.java +++ b/litmus-mock/src/main/java/com/navi/medici/container/CustomLitmusContextProvider.java @@ -2,6 +2,7 @@ package com.navi.medici.container; import com.navi.medici.context.LitmusContext; import com.navi.medici.provider.LitmusContextProvider; +import java.util.Random; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Component; import org.springframework.web.context.annotation.RequestScope; @@ -15,8 +16,7 @@ public class CustomLitmusContextProvider implements LitmusContextProvider { public LitmusContext getContext() { return LitmusContext.builder() .clickStreamPayload(null) - .userId("test123") - + .userId(new Random().nextInt() + "") .build(); } } \ No newline at end of file diff --git a/litmus-mock/src/main/java/com/navi/medici/container/MockContainer.java b/litmus-mock/src/main/java/com/navi/medici/container/MockContainer.java index f5e5512..286c420 100644 --- a/litmus-mock/src/main/java/com/navi/medici/container/MockContainer.java +++ b/litmus-mock/src/main/java/com/navi/medici/container/MockContainer.java @@ -12,7 +12,7 @@ public class MockContainer { @Bean public Litmus litmus() { var litmusConfig = LitmusConfig.builder() - .litmusAPI("http://localhost:12000/v1") + .litmusAPI("http://localhost:12000/litmus-core/v1") .appName("litmus-mock") .instanceId("test-instance") .litmusContextProvider(new CustomLitmusContextProvider()) diff --git a/litmus-mock/src/main/java/com/navi/medici/controller/MockController.java b/litmus-mock/src/main/java/com/navi/medici/controller/MockController.java index ca5d639..da57290 100644 --- a/litmus-mock/src/main/java/com/navi/medici/controller/MockController.java +++ b/litmus-mock/src/main/java/com/navi/medici/controller/MockController.java @@ -2,6 +2,7 @@ package com.navi.medici.controller; import com.navi.medici.context.LitmusContext; import com.navi.medici.litmus.Litmus; +import com.navi.medici.variants.Variant; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.web.bind.annotation.GetMapping; @@ -23,4 +24,12 @@ public class MockController { return "result ==> " + result; } + + @GetMapping("/variants/mock") + public Variant variants(@RequestParam("experiment") String experiment) { + var result = litmus.getVariant(experiment); + + log.info("response ===> {}", result.toString()); + return result; + } } diff --git a/litmus-model/src/main/java/com/navi/medici/variants/Payload.java b/litmus-model/src/main/java/com/navi/medici/variants/Payload.java index 135f75f..9afbb4a 100644 --- a/litmus-model/src/main/java/com/navi/medici/variants/Payload.java +++ b/litmus-model/src/main/java/com/navi/medici/variants/Payload.java @@ -7,6 +7,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.ToString; import lombok.experimental.FieldDefaults; @AllArgsConstructor @@ -16,6 +17,7 @@ import lombok.experimental.FieldDefaults; @Setter @JsonIgnoreProperties(ignoreUnknown = true) @FieldDefaults(level = AccessLevel.PRIVATE) +@ToString public class Payload { String type; String value; diff --git a/litmus-model/src/main/java/com/navi/medici/variants/Variant.java b/litmus-model/src/main/java/com/navi/medici/variants/Variant.java index 02b60c1..1aa575c 100644 --- a/litmus-model/src/main/java/com/navi/medici/variants/Variant.java +++ b/litmus-model/src/main/java/com/navi/medici/variants/Variant.java @@ -7,6 +7,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.ToString; import lombok.experimental.FieldDefaults; @AllArgsConstructor @@ -16,6 +17,7 @@ import lombok.experimental.FieldDefaults; @Setter @JsonIgnoreProperties(ignoreUnknown = true) @FieldDefaults(level = AccessLevel.PRIVATE) +@ToString public class Variant { String name; Payload payload; diff --git a/litmus-proxy/src/main/java/com/navi/medici/controller/HealthCheckController.java b/litmus-proxy/src/main/java/com/navi/medici/controller/HealthCheckController.java new file mode 100644 index 0000000..c4d1ddf --- /dev/null +++ b/litmus-proxy/src/main/java/com/navi/medici/controller/HealthCheckController.java @@ -0,0 +1,26 @@ +package com.navi.medici.controller; + +import com.navi.medici.util.JacksonUtils; +import java.util.HashMap; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@RequestMapping("/health") +@RequiredArgsConstructor +public class HealthCheckController { + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity ping() { + Map map = new HashMap<>(); + map.put("status", "Ok"); + + return ResponseEntity.ok(JacksonUtils.objectToString(map)); + } +} \ No newline at end of file