Skip to content
Snippets Groups Projects
Commit 2d49478b authored by Colin DAMON's avatar Colin DAMON
Browse files

Expose activity WebService

parent f5c4b9ea
No related branches found
No related tags found
1 merge request!42Resolve "Borestop part 4"
Showing
with 269 additions and 38 deletions
...@@ -12,9 +12,7 @@ Création en live d'une application pour montrer l'apport de valeur pas différe ...@@ -12,9 +12,7 @@ Création en live d'une application pour montrer l'apport de valeur pas différe
## Partie 2 ## Partie 2
API utilisée : Utilisation de [BoredAPI](https://www.boredapi.com/api/activity/) :
- https://www.boredapi.com/api/activity/
- **Auteurs** : Hippolyte DURIX && Colin DAMON - **Auteurs** : Hippolyte DURIX && Colin DAMON
- **Date** : 02/09/2020 - **Date** : 02/09/2020
...@@ -24,7 +22,7 @@ API utilisée : ...@@ -24,7 +22,7 @@ API utilisée :
## Partie 3 ## Partie 3
Appel à boredapi avec des [patterns anti-fragiles](https://github.com/resilience4j/resilience4j) Appel à [BoredAPI](https://www.boredapi.com/api/activity/) avec des [patterns anti-fragiles](https://github.com/resilience4j/resilience4j)
- **Auteurs** : Hippolyte DURIX && Colin DAMON - **Auteurs** : Hippolyte DURIX && Colin DAMON
- **Date** : 18/11/2020 - **Date** : 18/11/2020
......
package com.ippon.borestop.activity.application;
import com.ippon.borestop.activity.domain.ActivitiesFactory;
import com.ippon.borestop.activity.domain.Activity;
import com.ippon.borestop.activity.domain.IdeasRepository;
import com.ippon.borestop.activity.domain.PartnersRepository;
import org.springframework.stereotype.Service;
@Service
public class ActivitesApplicationService {
private final ActivitiesFactory activities;
public ActivitesApplicationService(IdeasRepository ideas, PartnersRepository partners) {
activities = new ActivitiesFactory(ideas, partners);
}
public Activity next() {
return activities.next();
}
}
package com.ippon.borestop.activity.domain;
public class ActivitiesFactory {
private final IdeasRepository ideas;
private final PartnersRepository partners;
public ActivitiesFactory(IdeasRepository ideas, PartnersRepository partners) {
this.ideas = ideas;
this.partners = partners;
}
public Activity next() {
Idea idea = ideas.next();
Partners partners = this.partners.find(idea.getCategory());
return new Activity(idea, partners);
}
}
package com.ippon.borestop.activity.infrastructure.primary;
import com.ippon.borestop.activity.application.ActivitesApplicationService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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
@Api(tags = "Activities")
@RequestMapping("/api/activity")
class ActivitesResource {
private final ActivitesApplicationService activites;
public ActivitesResource(ActivitesApplicationService activites) {
this.activites = activites;
}
@GetMapping
@ApiOperation("Get an activity")
public ResponseEntity<RestActivity> getActivity() {
return ResponseEntity.ok(RestActivity.from(activites.next()));
}
}
package com.ippon.borestop.activity.infrastructure.primary;
import com.ippon.borestop.activity.domain.Activity;
import io.swagger.annotations.ApiModel;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@ApiModel(value = "Activity", description = "An ideal activity for you!")
class RestActivity {
private final String label;
private final Collection<RestPartner> partners;
private RestActivity(String label, Collection<RestPartner> partners) {
this.label = label;
this.partners = partners;
}
public static RestActivity from(Activity activity) {
if (activity == null) {
return null;
}
List<RestPartner> partners = activity.getPartners().stream().map(RestPartner::from).collect(Collectors.toList());
return new RestActivity(activity.getLabel(), partners);
}
public String getLabel() {
return label;
}
public Collection<RestPartner> getPartners() {
return partners;
}
}
package com.ippon.borestop.activity.infrastructure.primary;
import com.ippon.borestop.activity.domain.Partner;
import io.swagger.annotations.ApiModel;
@ApiModel(value = "Partner", description = "Partner for an idea")
class RestPartner {
private final String name;
private final String website;
private RestPartner(String name, String website) {
this.name = name;
this.website = website;
}
static RestPartner from(Partner partner) {
return new RestPartner(partner.getName(), partner.getWebsite());
}
public String getName() {
return name;
}
public String getWebsite() {
return website;
}
}
package com.ippon.borestop.activity.infrastructure.secondary;
import com.ippon.borestop.activity.domain.Category;
import com.ippon.borestop.activity.domain.Partner;
import com.ippon.borestop.activity.domain.Partners;
import com.ippon.borestop.activity.domain.PartnersRepository;
import org.springframework.stereotype.Service;
@Service
class InMemoryPartnersRepository implements PartnersRepository {
@Override
public Partners find(Category category) {
// TODO: partners by category
Partner beerHunter = Partner.builder().name("Beer Hunter").website("https://beerhunter.fr").build();
return Partners.builder().add(beerHunter).build();
}
}
...@@ -86,6 +86,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { ...@@ -86,6 +86,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.antMatchers("/api/activate").permitAll() .antMatchers("/api/activate").permitAll()
.antMatchers("/api/account/reset-password/init").permitAll() .antMatchers("/api/account/reset-password/init").permitAll()
.antMatchers("/api/account/reset-password/finish").permitAll() .antMatchers("/api/account/reset-password/finish").permitAll()
.antMatchers("/api/activity").permitAll()
.antMatchers("/api/**").authenticated() .antMatchers("/api/**").authenticated()
.antMatchers("/management/health").permitAll() .antMatchers("/management/health").permitAll()
.antMatchers("/management/info").permitAll() .antMatchers("/management/info").permitAll()
......
Feature: Get an activity
Scenario: Should get beer activity
When I get an activity
Then My activity should be "Beer"
And My partners should be
| Name | Website |
| Beer Hunter | https://beerhunter.fr |
package com.ippon.borestop.activity.domain; package com.ippon.borestop.activity.domain;
public final class PartnersFixture { public final class ActivitiesFixture {
private PartnersFixture() {} private ActivitiesFixture() {}
public static Activity activity() {
return new Activity(idea(), threePartners());
}
public static Idea idea() {
return new Idea(label(), Category.RELAXATION);
}
public static String label() {
return "This is my idea";
}
public static Partners threePartners() { public static Partners threePartners() {
return Partners.builder().add(firstPartner()).add(secondPartner()).add(thirdPartner()).build(); return Partners.builder().add(firstPartner()).add(secondPartner()).add(thirdPartner()).build();
...@@ -19,4 +31,12 @@ public final class PartnersFixture { ...@@ -19,4 +31,12 @@ public final class PartnersFixture {
public static Partner firstPartner() { public static Partner firstPartner() {
return Partner.builder().name("name").website("http://name.com").build(); return Partner.builder().name("name").website("http://name.com").build();
} }
public static Partners partners() {
return threePartners();
}
public static Partners emptyPartners() {
return Partners.empty();
}
} }
package com.ippon.borestop.activity.domain; package com.ippon.borestop.activity.domain;
import static com.ippon.borestop.activity.domain.IdeasFixture.idea; import static com.ippon.borestop.activity.domain.ActivitiesFixture.*;
import static com.ippon.borestop.activity.domain.IdeasFixture.label;
import static com.ippon.borestop.activity.domain.PartnersFixture.firstPartner;
import static com.ippon.borestop.activity.domain.PartnersFixture.secondPartner;
import static com.ippon.borestop.activity.domain.PartnersFixture.thirdPartner;
import static com.ippon.borestop.activity.domain.PartnersFixture.threePartners;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
......
package com.ippon.borestop.activity.domain; package com.ippon.borestop.activity.domain;
import static com.ippon.borestop.activity.domain.IdeasFixture.*; import static com.ippon.borestop.activity.domain.ActivitiesFixture.*;
import static com.ippon.borestop.activity.domain.PartnersFixture.*;
import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.*;
import com.ippon.borestop.common.domain.error.MissingMandatoryValueException; import com.ippon.borestop.common.domain.error.MissingMandatoryValueException;
...@@ -33,19 +32,11 @@ class ActivityUnitTest { ...@@ -33,19 +32,11 @@ class ActivityUnitTest {
@Test @Test
void shouldBuildActivityWithThreePartnersInCategory() { void shouldBuildActivityWithThreePartnersInCategory() {
Activity activity = new Activity(idea(), threePartners()); Activity activity = activity();
assertThat(activity.getLabel()).isEqualTo(label()); assertThat(activity.getLabel()).isEqualTo(label());
assertThat(activity.getPartners()) assertThat(activity.getPartners())
.usingFieldByFieldElementComparator() .usingFieldByFieldElementComparator()
.containsExactly(firstPartner(), secondPartner(), thirdPartner()); .containsExactly(firstPartner(), secondPartner(), thirdPartner());
} }
private Partners partners() {
return threePartners();
}
private Partners emptyPartners() {
return Partners.empty();
}
} }
package com.ippon.borestop.activity.domain;
public final class IdeasFixture {
private IdeasFixture() {}
public static Idea idea() {
return new Idea(label(), Category.RELAXATION);
}
public static String label() {
return "This is my idea";
}
}
package com.ippon.borestop.activity.infrastructure.primary;
import static org.assertj.core.api.Assertions.*;
import com.ippon.borestop.common.infrastructure.primary.CucumberTestContext;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.web.client.TestRestTemplate;
public class ActivitiesStep {
@Autowired
private TestRestTemplate rest;
@When("I get an activity")
public void getActivity() {
rest.getForEntity("/api/activity", Void.class);
}
@Then("My activity should be {string}")
public void shouldGetActivity(String activity) {
assertThat(CucumberTestContext.getElement("$.label")).isEqualTo(activity);
}
@Then("My partners should be")
public void shouldGetPartners(List<Map<String, String>> partners) {
for (int line = 0; line < partners.size(); line++) {
String partnerPath = "$.partners[" + line + "]";
assertThat(CucumberTestContext.getElement(partnerPath + ".name")).isEqualTo(partners.get(line).get("Name"));
assertThat(CucumberTestContext.getElement(partnerPath + ".website")).isEqualTo(partners.get(line).get("Website"));
}
}
}
package com.ippon.borestop.activity.infrastructure.primary;
import static com.ippon.borestop.activity.domain.ActivitiesFixture.*;
import static org.assertj.core.api.Assertions.*;
import com.ippon.borestop.common.infrastructure.primary.TestJson;
import org.junit.jupiter.api.Test;
class RestActivityUnitTest {
@Test
void shouldConvertToNullFromNullDomain() {
assertThat(RestActivity.from(null)).isNull();
}
@Test
void shouldSerializeToJson() {
assertThat(defaultActivity()).isEqualTo(json());
}
private String defaultActivity() {
return TestJson.writeAsString(RestActivity.from(activity()));
}
private String json() {
return "{\"label\":\"This is my idea\",\"partners\":[{\"name\":\"name\",\"website\":\"http://name.com\"},{\"name\":\"second\",\"website\":\"http://second.com\"},{\"name\":\"third\",\"website\":\"http://third.com\"}]}";
}
}
package com.ippon.borestop.cucumber; package com.ippon.borestop.cucumber;
import static org.mockito.Mockito.*;
import com.ippon.borestop.BorestopApp; import com.ippon.borestop.BorestopApp;
import com.ippon.borestop.activity.domain.Category;
import com.ippon.borestop.activity.domain.Idea;
import com.ippon.borestop.activity.domain.IdeasRepository;
import com.ippon.borestop.common.infrastructure.primary.CucumberTestContext; import com.ippon.borestop.common.infrastructure.primary.CucumberTestContext;
import com.ippon.borestop.cucumber.CucumberConfiguration.CucumberMocksConfiguration;
import com.ippon.borestop.cucumber.CucumberConfiguration.CucumberSecurityContextConfiguration; import com.ippon.borestop.cucumber.CucumberConfiguration.CucumberSecurityContextConfiguration;
import io.cucumber.java.Before; import io.cucumber.java.Before;
import io.cucumber.spring.CucumberContextConfiguration; import io.cucumber.spring.CucumberContextConfiguration;
...@@ -28,7 +34,10 @@ import org.springframework.web.client.RestTemplate; ...@@ -28,7 +34,10 @@ import org.springframework.web.client.RestTemplate;
@CucumberContextConfiguration @CucumberContextConfiguration
@ActiveProfiles(JHipsterConstants.SPRING_PROFILE_TEST) @ActiveProfiles(JHipsterConstants.SPRING_PROFILE_TEST)
@SpringBootTest(classes = { BorestopApp.class, CucumberSecurityContextConfiguration.class }, webEnvironment = WebEnvironment.RANDOM_PORT) @SpringBootTest(
classes = { BorestopApp.class, CucumberSecurityContextConfiguration.class, CucumberMocksConfiguration.class },
webEnvironment = WebEnvironment.RANDOM_PORT
)
public class CucumberConfiguration { public class CucumberConfiguration {
@Autowired @Autowired
private TestRestTemplate rest; private TestRestTemplate rest;
...@@ -61,6 +70,20 @@ public class CucumberConfiguration { ...@@ -61,6 +70,20 @@ public class CucumberConfiguration {
}; };
} }
@TestConfiguration
public static class CucumberMocksConfiguration {
@Bean
@Primary
public IdeasRepository ideasRepository() {
IdeasRepository repository = mock(IdeasRepository.class);
when(repository.next()).thenReturn(new Idea("Beer", Category.RELAXATION));
return repository;
}
}
@TestConfiguration @TestConfiguration
public static class CucumberSecurityContextConfiguration { public static class CucumberSecurityContextConfiguration {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment