BAEL-1554 - Guide to Flips (#3827)

* BAEL-1554 - Flips code

* BAEL-1554 - Flips code, round 2

* BAEL-1554 - Guide to Flips

* BAEL-1554 - update read me

* BAEL-1554 - rename "Thing" to "Foo"
This commit is contained in:
Eric Goebelbecker 2018-03-16 19:06:38 -04:00 committed by maibin
parent d9e4ec2d2d
commit 2b50c4c341
11 changed files with 305 additions and 0 deletions

2
flips/README.md Normal file
View File

@ -0,0 +1,2 @@
### Relevant Articles:
- [Guide to Flips For Spring](http://www.baeldung.com/guide-to-flips-for-spring/)

65
flips/pom.xml Normal file
View File

@ -0,0 +1,65 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>flips</groupId>
<artifactId>flips</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>flips</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.5.9.RELEASE</version>
</dependency>
<dependency>
<groupId>com.github.feature-flip</groupId>
<artifactId>flips-web</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!-- Check for the most recent available version: https://projectlombok.org/changelog.html -->
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,15 @@
package com.baeldung.flips;
import org.flips.describe.config.FlipWebContextConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
@SpringBootApplication
@Import(FlipWebContextConfiguration.class)
public class ApplicationConfig {
public static void main(String[] args) {
SpringApplication.run(ApplicationConfig.class, args);
}
}

View File

@ -0,0 +1,65 @@
package com.baeldung.flips.controller;
import com.baeldung.flips.model.Foo;
import com.baeldung.flips.service.FlipService;
import org.flips.annotation.FlipOnDateTime;
import org.flips.annotation.FlipOnDaysOfWeek;
import org.flips.annotation.FlipOnEnvironmentProperty;
import org.flips.annotation.FlipOnProfiles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.time.DayOfWeek;
import java.util.List;
@RestController
public class FlipController {
private FlipService flipService;
@Autowired
public FlipController(FlipService flipService) {
this.flipService = flipService;
}
@RequestMapping(value = "/foos", method = RequestMethod.GET)
@FlipOnProfiles(activeProfiles = "dev")
public List<Foo> getAllFoos() {
return flipService.getAllFoos();
}
@RequestMapping(value = "/foo/{id}", method = RequestMethod.GET)
@FlipOnDaysOfWeek(daysOfWeek = {
DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY,
DayOfWeek.FRIDAY, DayOfWeek.SATURDAY, DayOfWeek.SUNDAY
})
public Foo getFooByNewId(@PathVariable int id) {
return flipService.getFooById(id).orElse(new Foo("Not Found", -1));
}
@RequestMapping(value = "/foo/last", method = RequestMethod.GET)
@FlipOnDateTime(cutoffDateTimeProperty = "last.active.after")
public Foo getLastFoo() {
return flipService.getLastFoo();
}
@RequestMapping(value = "/foo/first", method = RequestMethod.GET)
@FlipOnDateTime(cutoffDateTimeProperty = "first.active.after")
public Foo getFirstFoo() {
return flipService.getLastFoo();
}
@RequestMapping(value = "/foos/{id}", method = RequestMethod.GET)
@FlipOnEnvironmentProperty(property = "feature.foo.by.id", expectedValue = "Y")
public Foo getFooById(@PathVariable int id) {
return flipService.getFooById(id).orElse(new Foo("Not Found", -1));
}
@RequestMapping(value = "/foo/new", method = RequestMethod.GET)
public Foo getNewThing() {
return flipService.getNewFoo();
}
}

View File

@ -0,0 +1,11 @@
package com.baeldung.flips.model;
import lombok.Data;
import lombok.RequiredArgsConstructor;
@Data
@RequiredArgsConstructor
public class Foo {
private final String name;
private final int id;
}

View File

@ -0,0 +1,50 @@
package com.baeldung.flips.service;
import com.baeldung.flips.model.Foo;
import org.flips.annotation.FlipBean;
import org.flips.annotation.FlipOnSpringExpression;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
public class FlipService {
private final List<Foo> foos;
public FlipService() {
foos = new ArrayList<>();
foos.add(new Foo("Foo1", 1));
foos.add(new Foo("Foo2", 2));
foos.add(new Foo("Foo3", 3));
foos.add(new Foo("Foo4", 4));
foos.add(new Foo("Foo5", 5));
foos.add(new Foo("Foo6", 6));
}
public List<Foo> getAllFoos() {
return foos;
}
public Optional<Foo> getFooById(int id) {
return foos.stream().filter(foo -> (foo.getId() == id)).findFirst();
}
@FlipBean(with = NewFlipService.class)
@FlipOnSpringExpression(expression = "(2 + 2) == 4")
public Foo getNewFoo() {
return new Foo("New Foo!", 99);
}
public Foo getLastFoo() {
return foos.get(foos.size() - 1);
}
public Foo getFirstFoo() {
return foos.get(0);
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.flips.service;
import com.baeldung.flips.model.Foo;
import org.springframework.stereotype.Service;
@Service
public class NewFlipService {
public Foo getNewFoo() {
return new Foo("Shiny New Foo!", 100);
}
}

View File

@ -0,0 +1,5 @@
feature.foo.by.id=Y
feature.new.foo=Y
last.active.after=2018-03-14T00:00:00Z
first.active.after=2999-03-15T00:00:00Z
logging.level.org.flips=info

View File

@ -0,0 +1,74 @@
package com.baeldung.flips.controller;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@RunWith(SpringRunner.class)
@SpringBootTest(properties = {
"feature.foo.by.id=Y",
"feature.new.foo=Y",
"last.active.after=2018-03-14T00:00:00Z",
"first.active.after=2999-03-15T00:00:00Z",
"logging.level.org.flips=info"
})
@AutoConfigureMockMvc
@ActiveProfiles("dev")
public class FlipControllerTest {
@Autowired private MockMvc mvc;
@Test
public void givenValidDayOfWeek_APIAvailable() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/foo/1"))
.andExpect(MockMvcResultMatchers.status().is(200))
.andExpect(MockMvcResultMatchers.jsonPath("$.name", Matchers.equalTo("Foo1")))
.andExpect(MockMvcResultMatchers.jsonPath("$.id", Matchers.equalTo(1)));
}
@Test
public void givenValidDate_APIAvailable() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/foo/last"))
.andExpect(MockMvcResultMatchers.status().is(200))
.andExpect(MockMvcResultMatchers.jsonPath("$.name", Matchers.equalTo("Foo6")))
.andExpect(MockMvcResultMatchers.jsonPath("$.id", Matchers.equalTo(6)));
}
@Test
public void givenInvalidDate_APINotAvailable() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/foo/first"))
.andExpect(MockMvcResultMatchers.status().is(501));
}
@Test
public void givenCorrectProfile_APIAvailable() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/foos"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(6)));
}
@Test
public void givenPropertySet_APIAvailable() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/foos/1"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.name", Matchers.equalTo("Foo1")))
.andExpect(MockMvcResultMatchers.jsonPath("$.id", Matchers.equalTo(1)));
}
@Test
public void getValidExpression_FlipBean() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/foo/new"))
.andExpect(MockMvcResultMatchers.status().is(200))
.andExpect(MockMvcResultMatchers.jsonPath("$.name", Matchers.equalTo("Shiny New Foo!")))
.andExpect(MockMvcResultMatchers.jsonPath("$.id", Matchers.equalTo(100)));
}
}

View File

@ -0,0 +1,4 @@
package com.baeldung.flips;
public class TestFlipsBean {
}

View File

@ -64,6 +64,7 @@
<!--<module>ejb</module> -->
<module>feign</module>
<module>flips</module>
<!-- <module>testing-modules/gatling</module> --> <!-- not meant to run as part of the standard build -->