Skip to content

Commit c15357a

Browse files
jboixMGaetan89
andcommitted
feat: index user ip field and define required properties
Resolves #17 by parsing and indexing the ip property generated by the event dispatcher. - Added `user_ip` as an indexed field. - Added required fields: indexing will fail if any of the required fields is missing. Co-authored-by: Gaëtan Muller <[email protected]>
1 parent 8bc9aa9 commit c15357a

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed

.github/workflows/quality.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
paths: ${{ github.workspace }}/**/build/reports/kover/report.xml
3232
token: ${{ secrets.GITHUB_TOKEN }}
3333
update-comment: true
34+
title: Coverage Report
3435
min-coverage-changed-files: 0
3536
min-coverage-overall: 0
3637

src/main/kotlin/ch/srgssr/pillarbox/monitoring/event/model/EventRequest.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.springframework.data.elasticsearch.annotations.FieldType
2323
* @property sessionId The ID of the session associated with the event.
2424
* @property eventName The name of the event.
2525
* @property timestamp The timestamp of the event in epoch milliseconds.
26+
* @property ip The ip address of the client that generated the event.
2627
* @property data Additional data associated with the event.
2728
* @property session Session data associated with the event, potentially updated later.
2829
*/
@@ -31,18 +32,24 @@ data class EventRequest(
3132
@Id
3233
@JsonIgnore
3334
var id: String? = null,
34-
@JsonProperty("session_id")
35+
@JsonProperty("session_id", required = true)
3536
@Field("session_id")
3637
var sessionId: String,
37-
@JsonProperty("event_name")
38+
@JsonProperty("event_name", required = true)
3839
@Field("event_name")
3940
var eventName: String,
4041
@Field(type = FieldType.Date, format = [DateFormat.epoch_millis], name = "@timestamp")
42+
@JsonProperty(required = true)
4143
var timestamp: Long,
44+
@JsonProperty("user_ip")
45+
@Field("user_ip")
46+
var ip: String?,
47+
@JsonProperty(required = true)
4248
var version: Long,
4349
@JsonDeserialize(using = DataDeserializer::class)
44-
var data: Any? = null,
45-
var session: Any? = null,
50+
@JsonProperty(required = true)
51+
var data: Any,
52+
var session: Any?,
4653
)
4754

4855
/**

src/main/resources/application.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
spring:
22
threads.virtual.enabled: true
33
application.name: pillarbox-monitoring-transfer
4+
jackson.deserialization:
5+
fail-on-null-for-primitives: true
6+
47

58
pillarbox.monitoring:
69
dispatch.uri: "http://localhost:8080/events"

src/test/kotlin/ch/srgssr/pillarbox/monitoring/event/model/EventRequestTest.kt

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package ch.srgssr.pillarbox.monitoring.event.model
22

3+
import com.fasterxml.jackson.databind.JsonMappingException
34
import com.fasterxml.jackson.databind.ObjectMapper
45
import com.fasterxml.jackson.module.kotlin.readValue
6+
import io.kotest.assertions.throwables.shouldThrow
57
import io.kotest.core.spec.style.ShouldSpec
68
import io.kotest.matchers.shouldBe
79
import org.springframework.boot.test.context.SpringBootTest
@@ -10,6 +12,68 @@ import org.springframework.boot.test.context.SpringBootTest
1012
class EventRequestTest(
1113
private val objectMapper: ObjectMapper,
1214
) : ShouldSpec({
15+
should("deserialize successfully if all required fields are present") {
16+
// Given: an event as json
17+
val jsonInput =
18+
"""
19+
{
20+
"session_id": "12345",
21+
"event_name": "START",
22+
"timestamp": 1630000000000,
23+
"user_ip": "127.0.0.1",
24+
"version": 1,
25+
"data": { }
26+
}
27+
}
28+
""".trimIndent()
29+
30+
// When: the event is deserialized
31+
val eventRequest = objectMapper.readValue<EventRequest>(jsonInput)
32+
33+
// Then: The data of the event should be correctly parsed.
34+
eventRequest.sessionId shouldBe "12345"
35+
eventRequest.eventName shouldBe "START"
36+
eventRequest.timestamp shouldBe 1630000000000
37+
eventRequest.ip shouldBe "127.0.0.1"
38+
eventRequest.version shouldBe 1
39+
}
40+
41+
context("fail to deserialize if missing any required field") {
42+
val baseJson =
43+
mapOf(
44+
"session_id" to "\"12345\"",
45+
"event_name" to "\"START\"",
46+
"timestamp" to "1630000000000",
47+
"version" to "1",
48+
"data" to "{}",
49+
)
50+
51+
baseJson.keys.forEach { missingField ->
52+
should("fail if $missingField is missing") {
53+
val jsonInput =
54+
baseJson
55+
.filterKeys { it != missingField } // Exclude the current field
56+
.map { (key, value) -> "\"$key\": $value" }
57+
.joinToString(prefix = "{", postfix = "}")
58+
59+
shouldThrow<JsonMappingException> {
60+
objectMapper.readValue<EventRequest>(jsonInput)
61+
}
62+
}
63+
should("fail if $missingField is null") {
64+
val jsonInput =
65+
baseJson
66+
.map { (key, value) ->
67+
"\"$key\": ${if (key == missingField) "null" else value}"
68+
}.joinToString(prefix = "{", postfix = "}")
69+
70+
shouldThrow<JsonMappingException> {
71+
objectMapper.readValue<EventRequest>(jsonInput)
72+
}
73+
}
74+
}
75+
}
76+
1377
should("deserialize an event and resolve user agent") {
1478
// Given: an input with a user agent
1579
val jsonInput =
@@ -18,6 +82,7 @@ class EventRequestTest(
1882
"session_id": "12345",
1983
"event_name": "START",
2084
"timestamp": 1630000000000,
85+
"user_ip": "127.0.0.1",
2186
"version": 1,
2287
"data": {
2388
"browser": {
@@ -55,6 +120,7 @@ class EventRequestTest(
55120
"session_id": "12345",
56121
"event_name": "START",
57122
"timestamp": 1630000000000,
123+
"user_ip": "127.0.0.1",
58124
"version": 1,
59125
"data": {
60126
"browser": {
@@ -92,6 +158,7 @@ class EventRequestTest(
92158
"session_id": "12345",
93159
"event_name": "START",
94160
"timestamp": 1630000000000,
161+
"user_ip": "127.0.0.1",
95162
"version": 1,
96163
"data": {
97164
"browser": {

0 commit comments

Comments
 (0)