Skip to content

Commit 039f4b1

Browse files
marc0derclaude
andcommitted
refactor: extract idempotent post tests to dedicated spec
Co-Authored-By: Claude <[email protected]>
1 parent 79c9e5d commit 039f4b1

File tree

2 files changed

+153
-132
lines changed

2 files changed

+153
-132
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package io.sdkman
2+
3+
import arrow.core.None
4+
import arrow.core.some
5+
import io.kotest.core.spec.style.ShouldSpec
6+
import io.kotest.matchers.shouldBe
7+
import io.ktor.client.request.header
8+
import io.ktor.client.request.post
9+
import io.ktor.client.request.setBody
10+
import io.ktor.http.ContentType
11+
import io.ktor.http.HttpHeaders
12+
import io.ktor.http.HttpStatusCode
13+
import io.ktor.http.contentType
14+
import io.sdkman.domain.Platform
15+
import io.sdkman.domain.Version
16+
import io.sdkman.support.selectVersion
17+
import io.sdkman.support.toJsonString
18+
import io.sdkman.support.withCleanDatabase
19+
import io.sdkman.support.withTestApplication
20+
21+
// testuser:password123 base64 encoded
22+
private const val BasicAuthHeader = "Basic dGVzdHVzZXI6cGFzc3dvcmQxMjM="
23+
24+
class IdempotentPostVersionApiSpec : ShouldSpec({
25+
26+
should("POST be idempotent - same version posted twice should succeed with 201") {
27+
val version = Version(
28+
candidate = "java",
29+
version = "17.0.2",
30+
platform = Platform.LINUX_X64,
31+
url = "https://java-17.0.2-original",
32+
visible = true,
33+
vendor = "temurin".some(),
34+
md5sum = "original-hash".some()
35+
)
36+
val requestBody = version.toJsonString()
37+
38+
withCleanDatabase {
39+
withTestApplication {
40+
// First POST
41+
val response1 = client.post("/versions") {
42+
contentType(ContentType.Application.Json)
43+
setBody(requestBody)
44+
header(HttpHeaders.Authorization, BasicAuthHeader)
45+
}
46+
response1.status shouldBe HttpStatusCode.Companion.Created
47+
48+
// Second POST (idempotent)
49+
val response2 = client.post("/versions") {
50+
contentType(ContentType.Application.Json)
51+
setBody(requestBody)
52+
header(HttpHeaders.Authorization, BasicAuthHeader)
53+
}
54+
response2.status shouldBe HttpStatusCode.Companion.Created
55+
}
56+
// Verify version exists in database
57+
selectVersion(
58+
candidate = version.candidate,
59+
version = version.version,
60+
vendor = version.vendor,
61+
platform = version.platform
62+
) shouldBe version.some()
63+
}
64+
}
65+
66+
should("POST overwrite existing version with different data") {
67+
val originalVersion = Version(
68+
candidate = "java",
69+
version = "17.0.3",
70+
platform = Platform.LINUX_X64,
71+
url = "https://java-17.0.3-original",
72+
visible = true,
73+
vendor = "temurin".some(),
74+
md5sum = "original-hash".some()
75+
)
76+
77+
val updatedVersion = Version(
78+
candidate = "java",
79+
version = "17.0.3",
80+
platform = Platform.LINUX_X64,
81+
url = "https://java-17.0.3-updated",
82+
visible = false,
83+
vendor = "temurin".some(),
84+
sha256sum = "updated-hash".some()
85+
)
86+
87+
withCleanDatabase {
88+
withTestApplication {
89+
// First POST
90+
val response1 = client.post("/versions") {
91+
contentType(ContentType.Application.Json)
92+
setBody(originalVersion.toJsonString())
93+
header(HttpHeaders.Authorization, BasicAuthHeader)
94+
}
95+
response1.status shouldBe HttpStatusCode.Companion.Created
96+
97+
// Second POST with different data (overwrite)
98+
val response2 = client.post("/versions") {
99+
contentType(ContentType.Application.Json)
100+
setBody(updatedVersion.toJsonString())
101+
header(HttpHeaders.Authorization, BasicAuthHeader)
102+
}
103+
response2.status shouldBe HttpStatusCode.Companion.Created
104+
}
105+
// Verify the updated version is stored
106+
selectVersion(
107+
candidate = updatedVersion.candidate,
108+
version = updatedVersion.version,
109+
vendor = updatedVersion.vendor,
110+
platform = updatedVersion.platform
111+
) shouldBe updatedVersion.some()
112+
}
113+
}
114+
115+
should("POST be idempotent for version without vendor") {
116+
val version = Version(
117+
candidate = "scala",
118+
version = "3.2.0",
119+
platform = Platform.UNIVERSAL,
120+
url = "https://scala-3.2.0",
121+
visible = true,
122+
vendor = None
123+
)
124+
val requestBody = version.toJsonString()
125+
126+
withCleanDatabase {
127+
withTestApplication {
128+
// First POST
129+
val response1 = client.post("/versions") {
130+
contentType(ContentType.Application.Json)
131+
setBody(requestBody)
132+
header(HttpHeaders.Authorization, BasicAuthHeader)
133+
}
134+
response1.status shouldBe HttpStatusCode.Companion.Created
135+
136+
// Second POST (idempotent)
137+
val response2 = client.post("/versions") {
138+
contentType(ContentType.Application.Json)
139+
setBody(requestBody)
140+
header(HttpHeaders.Authorization, BasicAuthHeader)
141+
}
142+
response2.status shouldBe HttpStatusCode.Companion.Created
143+
}
144+
// Verify version exists in database
145+
selectVersion(
146+
candidate = version.candidate,
147+
version = version.version,
148+
vendor = version.vendor,
149+
platform = version.platform
150+
) shouldBe version.some()
151+
}
152+
}
153+
})

src/test/kotlin/io/sdkman/PostVersionApiSpec.kt

Lines changed: 0 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -103,137 +103,5 @@ class PostVersionApiSpec : ShouldSpec({
103103
}
104104
}
105105
}
106-
107-
//TODO: Move this into a new IdempotentVersionPostApiSpec
108-
should("POST be idempotent - same version posted twice should succeed with 201") {
109-
val version = Version(
110-
candidate = "java",
111-
version = "17.0.2",
112-
platform = Platform.LINUX_X64,
113-
url = "https://java-17.0.2-original",
114-
visible = true,
115-
vendor = "temurin".some(),
116-
md5sum = "original-hash".some()
117-
)
118-
val requestBody = version.toJsonString()
119-
120-
withCleanDatabase {
121-
withTestApplication {
122-
// First POST
123-
val response1 = client.post("/versions") {
124-
contentType(ContentType.Application.Json)
125-
setBody(requestBody)
126-
header(Authorization, BasicAuthHeader)
127-
}
128-
response1.status shouldBe HttpStatusCode.Created
129-
130-
// Second POST (idempotent)
131-
val response2 = client.post("/versions") {
132-
contentType(ContentType.Application.Json)
133-
setBody(requestBody)
134-
header(Authorization, BasicAuthHeader)
135-
}
136-
response2.status shouldBe HttpStatusCode.Created
137-
}
138-
// Verify version exists in database
139-
selectVersion(
140-
candidate = version.candidate,
141-
version = version.version,
142-
vendor = version.vendor,
143-
platform = version.platform
144-
) shouldBe version.some()
145-
}
146-
}
147-
148-
//TODO: Move this into a new IdempotentVersionPostApiSpec
149-
should("POST overwrite existing version with different data") {
150-
val originalVersion = Version(
151-
candidate = "java",
152-
version = "17.0.3",
153-
platform = Platform.LINUX_X64,
154-
url = "https://java-17.0.3-original",
155-
visible = true,
156-
vendor = "temurin".some(),
157-
md5sum = "original-hash".some()
158-
)
159-
160-
val updatedVersion = Version(
161-
candidate = "java",
162-
version = "17.0.3",
163-
platform = Platform.LINUX_X64,
164-
url = "https://java-17.0.3-updated",
165-
visible = false,
166-
vendor = "temurin".some(),
167-
sha256sum = "updated-hash".some()
168-
)
169-
170-
withCleanDatabase {
171-
withTestApplication {
172-
// First POST
173-
val response1 = client.post("/versions") {
174-
contentType(ContentType.Application.Json)
175-
setBody(originalVersion.toJsonString())
176-
header(Authorization, BasicAuthHeader)
177-
}
178-
response1.status shouldBe HttpStatusCode.Created
179-
180-
// Second POST with different data (overwrite)
181-
val response2 = client.post("/versions") {
182-
contentType(ContentType.Application.Json)
183-
setBody(updatedVersion.toJsonString())
184-
header(Authorization, BasicAuthHeader)
185-
}
186-
response2.status shouldBe HttpStatusCode.Created
187-
}
188-
// Verify the updated version is stored
189-
selectVersion(
190-
candidate = updatedVersion.candidate,
191-
version = updatedVersion.version,
192-
vendor = updatedVersion.vendor,
193-
platform = updatedVersion.platform
194-
) shouldBe updatedVersion.some()
195-
}
196-
}
197-
198-
//TODO: Move this into a new IdempotentVersionPostApiSpec
199-
should("POST be idempotent for version without vendor") {
200-
val version = Version(
201-
candidate = "scala",
202-
version = "3.2.0",
203-
platform = Platform.UNIVERSAL,
204-
url = "https://scala-3.2.0",
205-
visible = true,
206-
vendor = None
207-
)
208-
val requestBody = version.toJsonString()
209-
210-
withCleanDatabase {
211-
withTestApplication {
212-
// First POST
213-
val response1 = client.post("/versions") {
214-
contentType(ContentType.Application.Json)
215-
setBody(requestBody)
216-
header(Authorization, BasicAuthHeader)
217-
}
218-
response1.status shouldBe HttpStatusCode.Created
219-
220-
// Second POST (idempotent)
221-
val response2 = client.post("/versions") {
222-
contentType(ContentType.Application.Json)
223-
setBody(requestBody)
224-
header(Authorization, BasicAuthHeader)
225-
}
226-
response2.status shouldBe HttpStatusCode.Created
227-
}
228-
// Verify version exists in database
229-
selectVersion(
230-
candidate = version.candidate,
231-
version = version.version,
232-
vendor = version.vendor,
233-
platform = version.platform
234-
) shouldBe version.some()
235-
}
236-
}
237-
238106
})
239107

0 commit comments

Comments
 (0)