Skip to content

Commit a3c9936

Browse files
author
Guilherme Biff Zarelli
authored
Merge pull request #15 from helpdeveloper/gz-spring
feat: resolv spring build with feign module
2 parents f876043 + bf8ab34 commit a3c9936

File tree

16 files changed

+261
-28
lines changed

16 files changed

+261
-28
lines changed

.github/workflows/maven.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,8 @@ jobs:
3333
restore-keys: |
3434
${{ runner.os }}-maven-
3535
36-
- name: Run Tests
36+
- name: Run Tests with Quarkus (default)
3737
run: mvn --batch-mode verify coveralls:report -DrepoToken=${{ secrets.COVERALLS_REPO_TOKEN }}
38+
39+
- name: Run Tests with Spring Boot
40+
run: mvn --batch-mode verify -Pspring

Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ RUN curl https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/${FLYWAY
5757
# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
5858
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
5959
ENV JAVA_APP_JAR="quarkus-run.jar"
60+
6061
COPY app/quarkus-app/target/quarkus-app/ /deployments/
6162
COPY resources/flyway/db/migration /flyway/sql
6263

README.md

+1-6
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ Fornecendo toda infraestrutura necessária para o desenvolvedor.
8989
O framework é definido pelo profile, sendo que o default é do Quarkus.
9090

9191
#### Quarkus
92+
9293
```bash
9394
mvn clean install -Pquarkus
9495
# or by default:
@@ -97,12 +98,6 @@ mvn clean install
9798

9899
#### Spring boot
99100

100-
Nota: O projeto com Spring Boot não está finalizado. No caso o profile do Spring está sem o módulo
101-
de output: `restclient-http-service`, pois o Spring Boot não tem uma implementação para o microprofile-restclient
102-
no caso, o ideal seria a criação de um modulo com o Feign para implementar a porta do use-case: `ProtocolGeneratorClient`
103-
Porém, atualmente para o projeto rodar, essa porta foi implementada como um fake no modulo da app `spring-app` no seguinte package: ` br.com.helpdev.protocolgenerator`.
104-
Mas o módulo de `acceptance-test` irá falhar, pois o mesmo faz um mock desse serviço;
105-
106101
```bash
107102
mvn clean install -Pspring
108103
```

acceptance-test/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@
144144
<groupId>org.apache.maven.plugins</groupId>
145145
<artifactId>maven-failsafe-plugin</artifactId>
146146
<version>${maven-failsafe-plugin.version}</version>
147+
<configuration>
148+
<systemPropertyVariables>
149+
<profileId>${project.activeProfiles[0].id}</profileId>
150+
</systemPropertyVariables>
151+
</configuration>
147152
<executions>
148153
<execution>
149154
<goals>

acceptance-test/src/test/java/br/com/helpdev/atdd/DefaultContainerStarterTest.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ abstract class DefaultContainerStarterTest {
2222
private static final GenericContainer<?> MYSQL_CONTAINER;
2323
private static final Network NETWORK = Network.newNetwork();
2424
protected static final WireMockServer MOCK_SERVER;
25+
private static final String PROFILE_ID_SPRING = "spring";
26+
public static final String PROP_PROFILE_ID = "profileId";
2527

2628
/* Containers are initialized in static block to create only once in test execution */
2729
static {
@@ -66,8 +68,10 @@ private static GenericContainer<?> buildAppContainer(final Startable... dependsO
6668
.withEnv("MYSQL_PASSWORD", "test")
6769
.withEnv("MYSQL_URL", "jdbc:mysql://testdb:" + MySQLContainer.MYSQL_PORT + "/test?autoReconnect=true&useSSL=false")
6870
.withExposedPorts(8080)
69-
//TODO: change to: '/actuator/health' if you use spring
70-
.waitingFor(Wait.forHttp("/q/health/ready").forStatusCode(200))
71+
.waitingFor(System.getProperty(PROP_PROFILE_ID).equals(PROFILE_ID_SPRING) ?
72+
Wait.forHttp("/actuator/health").forStatusCode(200) :
73+
Wait.forHttp("/q/health/ready").forStatusCode(200)
74+
)
7175
.withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("APP_CONTAINER")));
7276
}
7377

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>modular-architecture</artifactId>
7+
<groupId>br.com.helpdev</groupId>
8+
<version>0.0.4-SNAPSHOT</version>
9+
<relativePath>../../../pom.xml</relativePath>
10+
</parent>
11+
<modelVersion>4.0.0</modelVersion>
12+
13+
<artifactId>feign-http-services</artifactId>
14+
15+
<properties>
16+
<maven.compiler.source>17</maven.compiler.source>
17+
<maven.compiler.target>17</maven.compiler.target>
18+
<coverage.exclude.code>**/*Dto.*</coverage.exclude.code>
19+
<mutation.excluded.code>**.dto.*</mutation.excluded.code>
20+
<feign-jaxrs.version>12.1</feign-jaxrs.version>
21+
</properties>
22+
23+
<dependencyManagement>
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.springframework.cloud</groupId>
27+
<artifactId>spring-cloud-dependencies</artifactId>
28+
<version>${spring-cloud.version}</version>
29+
<type>pom</type>
30+
<scope>import</scope>
31+
</dependency>
32+
</dependencies>
33+
</dependencyManagement>
34+
<dependencies>
35+
<dependency>
36+
<groupId>javax.ws.rs</groupId>
37+
<artifactId>javax.ws.rs-api</artifactId>
38+
</dependency>
39+
<dependency>
40+
<groupId>com.fasterxml.jackson.core</groupId>
41+
<artifactId>jackson-databind</artifactId>
42+
<scope>provided</scope>
43+
</dependency>
44+
45+
<dependency>
46+
<groupId>org.springframework.cloud</groupId>
47+
<artifactId>spring-cloud-starter-openfeign</artifactId>
48+
</dependency>
49+
50+
<dependency>
51+
<groupId>io.github.openfeign</groupId>
52+
<artifactId>feign-jaxrs</artifactId>
53+
<version>${feign-jaxrs.version}</version>
54+
</dependency>
55+
56+
<!-- Project dependencies-->
57+
<dependency>
58+
<groupId>br.com.helpdev</groupId>
59+
<artifactId>use-case</artifactId>
60+
</dependency>
61+
62+
<!-- Tests dependencies -->
63+
<dependency>
64+
<groupId>org.junit.jupiter</groupId>
65+
<artifactId>junit-jupiter-api</artifactId>
66+
<scope>test</scope>
67+
</dependency>
68+
<dependency>
69+
<groupId>org.junit.jupiter</groupId>
70+
<artifactId>junit-jupiter-engine</artifactId>
71+
<scope>test</scope>
72+
</dependency>
73+
<dependency>
74+
<groupId>org.mockito</groupId>
75+
<artifactId>mockito-core</artifactId>
76+
<scope>test</scope>
77+
</dependency>
78+
<dependency>
79+
<groupId>org.mockito</groupId>
80+
<artifactId>mockito-junit-jupiter</artifactId>
81+
<scope>test</scope>
82+
</dependency>
83+
<dependency>
84+
<groupId>org.assertj</groupId>
85+
<artifactId>assertj-core</artifactId>
86+
<scope>test</scope>
87+
</dependency>
88+
<dependency>
89+
<groupId>org.slf4j</groupId>
90+
<artifactId>slf4j-simple</artifactId>
91+
<scope>test</scope>
92+
</dependency>
93+
94+
</dependencies>
95+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package br.com.helpdev.output.feign;
2+
3+
4+
import br.com.helpdev.output.feign.client.RandomDataApiClient;
5+
import br.com.helpdev.usecase.port.ProtocolGeneratorClient;
6+
import javax.enterprise.context.ApplicationScoped;
7+
import javax.inject.Inject;
8+
import javax.inject.Named;
9+
10+
@ApplicationScoped
11+
@Named
12+
public class ProtocolGeneratorClientImpl implements ProtocolGeneratorClient {
13+
14+
private final RandomDataApiClient randomDataApiClient;
15+
16+
@Inject
17+
public ProtocolGeneratorClientImpl(final RandomDataApiClient randomDataApiClient) {
18+
this.randomDataApiClient = randomDataApiClient;
19+
}
20+
21+
@Override
22+
public String generateNewProtocol() {
23+
/* Generate US-SSN to simulate protocol */
24+
return randomDataApiClient.generate().getValidUsSsn();
25+
}
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package br.com.helpdev.output.feign.client;
2+
3+
import br.com.helpdev.output.feign.client.dto.RandomIdNumberDto;
4+
import javax.ws.rs.GET;
5+
import javax.ws.rs.Produces;
6+
import org.springframework.cloud.openfeign.FeignClient;
7+
8+
@FeignClient(name = "random-data-api", url = "${random-data-api.url}", path = "/api/id_number/random_id_number")
9+
public interface RandomDataApiClient {
10+
11+
@GET
12+
@Produces("application/json")
13+
RandomIdNumberDto generate();
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package br.com.helpdev.output.feign.client.dto;
2+
3+
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
4+
import com.fasterxml.jackson.databind.annotation.JsonNaming;
5+
import lombok.Data;
6+
7+
@Data
8+
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
9+
public class RandomIdNumberDto {
10+
private String id;
11+
private String uid;
12+
private String validUsSsn;
13+
private String invalidUsSsn;
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package br.com.helpdev.output.feign.config;
2+
3+
import feign.Contract;
4+
import feign.jaxrs.JAXRSContract;
5+
import org.springframework.cloud.openfeign.EnableFeignClients;
6+
import org.springframework.context.annotation.Bean;
7+
import org.springframework.context.annotation.Configuration;
8+
9+
10+
@Configuration
11+
@EnableFeignClients(
12+
basePackages = {"br.com.helpdev.output.feign"}
13+
)
14+
public class FeignContractConfiguration {
15+
16+
@Bean
17+
Contract contract() {
18+
return new JAXRSContract();
19+
}
20+
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package br.com.helpdev.output.feign;
2+
3+
import static org.mockito.Mockito.mock;
4+
import static org.mockito.Mockito.when;
5+
6+
import br.com.helpdev.output.feign.client.RandomDataApiClient;
7+
import br.com.helpdev.output.feign.client.dto.RandomIdNumberDto;
8+
import org.assertj.core.api.Assertions;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.extension.ExtendWith;
11+
import org.mockito.InjectMocks;
12+
import org.mockito.Mock;
13+
import org.mockito.junit.jupiter.MockitoExtension;
14+
15+
@ExtendWith(MockitoExtension.class)
16+
class ProtocolGeneratorClientImplTest {
17+
18+
@Mock
19+
private RandomDataApiClient randomDataApiClient;
20+
21+
@InjectMocks
22+
private ProtocolGeneratorClientImpl protocolGeneratorClient;
23+
24+
@Test
25+
void shouldGeneratedProtocolWithSuccess() {
26+
final var randomIdNumberDto = mock(RandomIdNumberDto.class);
27+
final var expectedProtocol = "xpto";
28+
29+
when(randomDataApiClient.generate()).thenReturn(randomIdNumberDto);
30+
when(randomIdNumberDto.getValidUsSsn()).thenReturn(expectedProtocol);
31+
32+
final var result = protocolGeneratorClient.generateNewProtocol();
33+
34+
Assertions.assertThat(result).isEqualTo(expectedProtocol);
35+
}
36+
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package br.com.helpdev.output.feign.config;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import feign.jaxrs.JAXRSContract;
6+
import org.junit.jupiter.api.Test;
7+
import org.junit.jupiter.api.extension.ExtendWith;
8+
import org.mockito.InjectMocks;
9+
import org.mockito.junit.jupiter.MockitoExtension;
10+
11+
@ExtendWith(MockitoExtension.class)
12+
class FeignContractConfigurationTest {
13+
@InjectMocks
14+
private FeignContractConfiguration feignContractConfiguration;
15+
16+
@Test
17+
void shouldGeneratedNonNullJaxRsContract() {
18+
final var contract = feignContractConfiguration.contract();
19+
20+
assertThat(contract)
21+
.isInstanceOf(JAXRSContract.class)
22+
.isNotNull();
23+
}
24+
}

app/spring-app/pom.xml

+4-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@
5858
<groupId>${project.groupId}</groupId>
5959
<artifactId>jpa-mysql-repository</artifactId>
6060
</dependency>
61+
<dependency>
62+
<groupId>${project.groupId}</groupId>
63+
<artifactId>feign-http-services</artifactId>
64+
</dependency>
6165
<dependency>
6266
<groupId>${project.groupId}</groupId>
6367
<artifactId>jaxrs-controller-v1</artifactId>
@@ -79,7 +83,6 @@
7983
<groupId>io.micrometer</groupId>
8084
<artifactId>micrometer-registry-prometheus</artifactId>
8185
</dependency>
82-
8386
<dependency>
8487
<groupId>ch.qos.logback</groupId>
8588
<artifactId>logback-core</artifactId>

app/spring-app/src/main/java/br/com/helpdev/protocolgenerator/FakeProtocolGenerator.java

-16
This file was deleted.

app/spring-app/src/main/resources/application.properties

+2
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ spring.datasource.password=${MYSQL_PASSWORD:pass123}
66

77
management.metrics.enable.all=true
88
management.endpoints.web.exposure.include=*
9+
10+
random-data-api.url=${RANDOM_DATA_API_URL:https://random-data-api.com}

pom.xml

+6-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@
4444
<module>core/use-case</module>
4545
<module>adapter/input/jaxrs-controller-v1</module>
4646
<module>adapter/output/jpa-mysql-repository</module>
47-
<!--TODO: The restclient don't work in Spring; In this sample, the implementation about ProtocolGeneratorClient is in the spring-app module ( br.com.helpdev.protocolgenerator )-->
48-
<!--<module>adapter/output/restclient-http-services</module>-->
47+
<module>adapter/output/feign-http-services</module>
4948
<module>app/spring-app</module>
5049
<module>acceptance-test</module>
5150
</modules>
@@ -149,6 +148,11 @@
149148
<artifactId>restclient-http-services</artifactId>
150149
<version>${project.version}</version>
151150
</dependency>
151+
<dependency>
152+
<groupId>${project.groupId}</groupId>
153+
<artifactId>feign-http-services</artifactId>
154+
<version>${project.version}</version>
155+
</dependency>
152156
<dependency>
153157
<groupId>org.projectlombok</groupId>
154158
<artifactId>lombok</artifactId>

0 commit comments

Comments
 (0)