Skip to content

Commit 9c36212

Browse files
authored
Merge pull request #614 from codecentric/add-events-to-habit-service
Add events to habit service
2 parents d1384da + cf56aa9 commit 9c36212

File tree

47 files changed

+693
-432
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+693
-432
lines changed

infrastructure/docker/docker-compose.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ services:
7171
- habit-db
7272
environment:
7373
DB_HOST: habit-db
74+
KAFKA_BOOTSTRAP_SERVERS: kafka:11001
7475
networks:
7576
- habitcentric-net
7677
habit-db:
@@ -124,8 +125,8 @@ services:
124125
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:11001,EXTERNAL://localhost:11003
125126
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:11002
126127
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
127-
- KAFKA_CLIENT_USERS=track,kafka-ui
128-
- KAFKA_CLIENT_PASSWORDS=track,kafka-ui
128+
- KAFKA_CLIENT_USERS=habit,track,kafka-ui
129+
- KAFKA_CLIENT_PASSWORDS=habit,track,kafka-ui
129130
networks:
130131
- habitcentric-net
131132
kafka-ui:

infrastructure/istio/config/23-mtls-authz-policies.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ spec:
6464
- from:
6565
- source:
6666
principals:
67+
- cluster.local/ns/hc-habit/sa/habit
6768
- cluster.local/ns/hc-track/sa/track
6869
---
6970
apiVersion: security.istio.io/v1beta1

infrastructure/kubernetes/helmfile.d/values/habit-values.yaml.gotmpl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ image:
1818

1919
## habitcentric habit service configuration
2020

21-
{{- if (eq .Environment.Name "traefik-mesh") }}
2221
extraEnv:
22+
- name: KAFKA_BOOTSTRAP_SERVERS
23+
value: kafka.hc-kafka.svc.cluster.local:9092
24+
{{- if (eq .Environment.Name "traefik-mesh") }}
2325
- name: MANAGEMENT_ZIPKIN_TRACING_ENDPOINT
2426
value: http://jaeger-collector.traefik-mesh.svc.cluster.local:9411
2527
{{- end }}

infrastructure/kubernetes/helmfile.d/values/kafka-values.yaml.gotmpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ sasl:
1010
password: "kafka"
1111
client:
1212
users:
13+
- "habit"
1314
- "track"
1415
passwords:
16+
- "habit"
1517
- "track"
1618

1719
externalAccess:

services/habit/build.gradle

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,19 @@ ext {
8383
ext['junit-jupiter.version'] = versions.junitJupiter
8484
ext['jna.version'] = versions.jna // Required for Docker on ARM
8585

86+
dependencyManagement {
87+
imports {
88+
mavenBom 'org.springframework.modulith:spring-modulith-bom:1.1.0'
89+
}
90+
}
91+
8692
dependencies {
93+
// Spring Modulith
94+
implementation "org.springframework.modulith:spring-modulith-starter-core"
95+
implementation "org.springframework.modulith:spring-modulith-starter-jpa"
96+
implementation "org.springframework.modulith:spring-modulith-events-kafka"
97+
intTestImplementation "org.springframework.modulith:spring-modulith-starter-test"
98+
8799
implementation 'org.springframework.boot:spring-boot-starter-actuator'
88100
implementation 'org.springframework.boot:spring-boot-starter-validation'
89101
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

services/habit/docker-compose.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,31 @@ services:
88
environment:
99
POSTGRESQL_PASSWORD: postgres
1010
POSTGRESQL_PORT_NUMBER: 10001
11+
12+
kafka:
13+
image: 'bitnami/kafka:latest'
14+
ports:
15+
- "11003:11003"
16+
environment:
17+
- KAFKA_CFG_NODE_ID=0
18+
- KAFKA_CFG_PROCESS_ROLES=controller,broker
19+
- KAFKA_CFG_LISTENERS=PLAINTEXT://:11001,CONTROLLER://:11002,EXTERNAL://:11003
20+
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:SASL_PLAINTEXT,EXTERNAL:SASL_PLAINTEXT
21+
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:11001,EXTERNAL://localhost:11003
22+
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:11002
23+
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
24+
- KAFKA_CLIENT_USERS=habit,kafka-ui
25+
- KAFKA_CLIENT_PASSWORDS=habit,kafka-ui
26+
27+
kafka-ui:
28+
container_name: kafka-ui
29+
image: provectuslabs/kafka-ui:latest
30+
ports:
31+
- "11004:11004"
32+
environment:
33+
SERVER_PORT: 11004
34+
DYNAMIC_CONFIG_ENABLED: 'true'
35+
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:11001
36+
KAFKA_CLUSTERS_0_PROPERTIES_SECURITY_PROTOCOL: SASL_PLAINTEXT
37+
KAFKA_CLUSTERS_0_PROPERTIES_SASL_MECHANISM: PLAIN
38+
KAFKA_CLUSTERS_0_PROPERTIES_SASL_JAAS_CONFIG: 'org.apache.kafka.common.security.plain.PlainLoginModule required username="kafka-ui" password="kafka-ui";'

services/habit/habit-requests.http

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,8 @@ Content-Type: application/json
1616
"frequency": "MONTHLY"
1717
}
1818
}
19+
20+
### Delete habit
21+
# Retrieve the ID by fetching the habits first
22+
DELETE http://localhost:9001/habits/8ffa23a1-e91b-45a3-9060-3b0f53c0c6f3
23+
X-User-Id: default

services/habit/pacts/hc-ui-hc-habit.json

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,20 @@
2323
},
2424
"body": [
2525
{
26-
"id": 1,
2726
"name": "Jogging",
2827
"schedule": {
2928
"repetitions": 2,
3029
"frequency": "WEEKLY"
3130
}
3231
},
3332
{
34-
"id": 101,
3533
"name": "Meditate",
3634
"schedule": {
3735
"repetitions": 1,
3836
"frequency": "DAILY"
3937
}
4038
},
4139
{
42-
"id": 51,
4340
"name": "Play guitar",
4441
"schedule": {
4542
"repetitions": 5,
@@ -49,13 +46,13 @@
4946
],
5047
"matchingRules": {
5148
"$.body[0].id": {
52-
"match": "type"
49+
"match": "uuid"
5350
},
5451
"$.body[1].id": {
55-
"match": "type"
52+
"match": "uuid"
5653
},
5754
"$.body[2].id": {
58-
"match": "type"
55+
"match": "uuid"
5956
}
6057
}
6158
}
@@ -84,10 +81,10 @@
8481
},
8582
{
8683
"description": "request to delete the habit with id '123'",
87-
"providerState": "habit with id '123' exists",
84+
"providerState": "habit with id 'd712645f-cd4f-40c4-b171-bb2ea72d180d' exists",
8885
"request": {
8986
"method": "DELETE",
90-
"path": "/habits/123"
87+
"path": "/habits/d712645f-cd4f-40c4-b171-bb2ea72d180d"
9188
},
9289
"response": {
9390
"status": 200,
@@ -101,4 +98,4 @@
10198
"version": "2.0.0"
10299
}
103100
}
104-
}
101+
}

services/habit/src/intTest/java/de/codecentric/hc/habit/habits/HabitControllerIntTest.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
import static de.codecentric.hc.habit.habits.Habit.Schedule.Frequency.DAILY;
44
import static de.codecentric.hc.habit.habits.Habit.Schedule.Frequency.WEEKLY;
5+
import static de.codecentric.hc.habit.testing.CustomMatchers.isValidUuid;
56
import static io.restassured.RestAssured.given;
67
import static io.restassured.RestAssured.when;
78
import static io.restassured.http.ContentType.JSON;
89
import static org.assertj.core.api.Assertions.assertThat;
910
import static org.hamcrest.Matchers.contains;
1011
import static org.hamcrest.Matchers.equalTo;
1112
import static org.hamcrest.Matchers.everyItem;
12-
import static org.hamcrest.Matchers.greaterThan;
1313
import static org.hamcrest.Matchers.isEmptyOrNullString;
1414
import static org.springframework.http.HttpStatus.BAD_REQUEST;
1515
import static org.springframework.http.HttpStatus.CREATED;
@@ -23,6 +23,7 @@
2323
import de.codecentric.hc.habit.testing.RestAssuredTest;
2424
import io.restassured.http.Header;
2525
import java.sql.SQLException;
26+
import java.util.UUID;
2627
import java.util.stream.Stream;
2728
import org.apache.commons.lang3.StringUtils;
2829
import org.junit.jupiter.api.AfterEach;
@@ -61,7 +62,7 @@ public void getHabits() throws InterruptedException {
6162
.then()
6263
.statusCode(200)
6364
.body("name", contains(expected))
64-
.body("id", everyItem(greaterThan(0)));
65+
.body("id", everyItem(isValidUuid()));
6566
}
6667

6768
@Test
@@ -79,7 +80,7 @@ public void getHabitsOrderedByNameAscending() throws InterruptedException {
7980
.then()
8081
.statusCode(200)
8182
.body("name", contains(expected))
82-
.body("id", everyItem(greaterThan(0)));
83+
.body("id", everyItem(isValidUuid()));
8384
}
8485

8586
@Test
@@ -246,19 +247,20 @@ public void deleteHabit() {
246247

247248
@Test
248249
public void deleteHabitNotFound() {
250+
UUID habitId = UUID.randomUUID();
249251
given()
250252
.header(DEFAULT_USER_ID_HEADER)
251253
.when()
252-
.delete("/habits/{id}", 999)
254+
.delete("/habits/{id}", habitId)
253255
.then()
254256
.statusCode(NOT_FOUND.value())
255-
.body("message", equalTo("Habit '999' could not be found."));
257+
.body("message", equalTo(String.format("Habit '%s' could not be found.", habitId)));
256258
}
257259

258260
@Test
259261
public void deleteHabitWithoutAuthShouldFail() {
260262
when()
261-
.delete("/habits/{id}", 123)
263+
.delete("/habits/{id}", UUID.randomUUID())
262264
.then()
263265
.statusCode(
264266
INTERNAL_SERVER_ERROR.value()) // TODO: HTTP 400 or 401 would be more appropriate

services/habit/src/intTest/java/de/codecentric/hc/habit/habits/HabitControllerJwtIntTest.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static de.codecentric.hc.habit.habits.Habit.Schedule.Frequency.DAILY;
44
import static de.codecentric.hc.habit.habits.Habit.Schedule.Frequency.WEEKLY;
5+
import static de.codecentric.hc.habit.testing.CustomMatchers.isValidUuid;
56
import static io.restassured.RestAssured.given;
67
import static io.restassured.http.ContentType.JSON;
78
import static org.assertj.core.api.Assertions.assertThat;
@@ -13,6 +14,7 @@
1314
import de.codecentric.hc.habit.testing.RestAssuredTest;
1415
import io.restassured.http.Header;
1516
import java.sql.SQLException;
17+
import java.util.UUID;
1618
import java.util.stream.Stream;
1719
import org.apache.commons.lang3.StringUtils;
1820
import org.junit.jupiter.api.AfterEach;
@@ -57,7 +59,7 @@ public void getHabits() throws InterruptedException {
5759
.then()
5860
.statusCode(OK.value())
5961
.body("name", contains(expected))
60-
.body("id", everyItem(greaterThan(0)));
62+
.body("id", everyItem(isValidUuid()));
6163
}
6264

6365
@Test
@@ -75,7 +77,7 @@ public void getHabitsOrderedByNameAscending() throws InterruptedException {
7577
.then()
7678
.statusCode(OK.value())
7779
.body("name", contains(expected))
78-
.body("id", everyItem(greaterThan(0)));
80+
.body("id", everyItem(isValidUuid()));
7981
}
8082

8183
@Test
@@ -238,13 +240,14 @@ public void deleteHabit() {
238240

239241
@Test
240242
public void deleteHabitNotFound() {
243+
UUID habitId = UUID.randomUUID();
241244
given()
242245
.header(DEFAULT_AUTHORIZATION_HEADER)
243246
.when()
244-
.delete("/habits/{id}", 999)
247+
.delete("/habits/{id}", habitId)
245248
.then()
246249
.statusCode(NOT_FOUND.value())
247-
.body("message", equalTo("Habit '999' could not be found."));
250+
.body("message", equalTo(String.format("Habit '%s' could not be found.", habitId)));
248251
}
249252

250253
private String insertHabit(String name) {

0 commit comments

Comments
 (0)