Skip to content

Commit 472bfa7

Browse files
author
Oleksandr Dzhychko
committed
fix(model-server): respond with error if delta computation fails before creating a flow
Before this fix, the server started responding with status code 200 before even trying to execute `repositoriesManager.computeDelta`.
1 parent 9ff4825 commit 472bfa7

File tree

2 files changed

+52
-8
lines changed

2 files changed

+52
-8
lines changed

model-server/src/main/kotlin/org/modelix/model/server/handlers/ModelReplicationServer.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,11 @@ class ModelReplicationServer(
379379
}
380380

381381
private suspend fun ApplicationCall.respondDeltaAsObjectStream(versionHash: String, baseVersionHash: String?, plainText: Boolean) {
382+
// Call `computeDelta` before starting to respond.
383+
// It could already throw an exception, and in that case we do not want a successful response status.
384+
val objectData = repositoriesManager.computeDelta(versionHash, baseVersionHash)
382385
respondTextWriter(contentType = if (plainText) ContentType.Text.Plain else VersionDeltaStream.CONTENT_TYPE) {
383-
repositoriesManager.computeDelta(versionHash, baseVersionHash).asFlow()
386+
objectData.asFlow()
384387
.flatten()
385388
.withSeparator("\n")
386389
.onEmpty { emit(versionHash) }

model-server/src/test/kotlin/org/modelix/model/server/handlers/ModelReplicationServerTest.kt

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.modelix.model.server.handlers
1717

1818
import io.ktor.client.request.get
19+
import io.ktor.http.HttpStatusCode
1920
import io.ktor.http.appendPathSegments
2021
import io.ktor.http.takeFrom
2122
import io.ktor.server.testing.ApplicationTestBuilder
@@ -34,20 +35,26 @@ import org.modelix.model.server.installDefaultServerPlugins
3435
import org.modelix.model.server.store.InMemoryStoreClient
3536
import org.modelix.model.server.store.LocalModelClient
3637
import kotlin.test.Test
38+
import kotlin.test.assertEquals
3739
import kotlin.test.fail
3840

3941
class ModelReplicationServerTest {
4042

41-
private fun runTest(block: suspend ApplicationTestBuilder.(scope: CoroutineScope) -> Unit) = testApplication {
43+
private fun getDefaultModelReplicationServer(): ModelReplicationServer {
44+
val storeClient = InMemoryStoreClient()
45+
val modelClient = LocalModelClient(storeClient)
46+
val repositoriesManager = RepositoriesManager(modelClient)
47+
return ModelReplicationServer(repositoriesManager, modelClient, InMemoryModels())
48+
}
49+
50+
private fun runTest(
51+
modelReplicationServer: ModelReplicationServer = getDefaultModelReplicationServer(),
52+
block: suspend ApplicationTestBuilder.(scope: CoroutineScope) -> Unit,
53+
) = testApplication {
4254
application {
4355
installAuthentication(unitTestMode = true)
4456
installDefaultServerPlugins()
45-
val storeClient = InMemoryStoreClient()
46-
val modelClient = LocalModelClient(storeClient)
47-
val repositoriesManager = RepositoriesManager(modelClient)
48-
val inMemoryModels = InMemoryModels()
49-
ModelReplicationServer(repositoriesManager, modelClient, inMemoryModels).init(this)
50-
KeyValueLikeModelServer(repositoriesManager, storeClient, inMemoryModels).init(this)
57+
modelReplicationServer.init(this)
5158
}
5259

5360
coroutineScope {
@@ -92,4 +99,38 @@ class ModelReplicationServerTest {
9299
}
93100
}
94101
}
102+
103+
@Test
104+
fun `server responds with error when failing to compute delta before starting to respond`() {
105+
// Arrange
106+
val storeClient = InMemoryStoreClient()
107+
val modelClient = LocalModelClient(storeClient)
108+
val repositoriesManager = RepositoriesManager(modelClient)
109+
val faultyRepositoriesManager = object :
110+
IRepositoriesManager by repositoriesManager {
111+
override suspend fun computeDelta(versionHash: String, baseVersionHash: String?): ObjectData {
112+
error("Unexpected error.")
113+
}
114+
}
115+
val modelReplicationServer = ModelReplicationServer(faultyRepositoriesManager, modelClient, InMemoryModels())
116+
val url = "http://localhost/v2"
117+
val repositoryId = RepositoryId("repo1")
118+
val branchRef = repositoryId.getBranchReference()
119+
120+
runTest(modelReplicationServer) {
121+
repositoriesManager.createRepository(repositoryId, null)
122+
123+
// Act
124+
val response = client.get {
125+
url {
126+
takeFrom(url)
127+
appendPathSegments("repositories", repositoryId.id, "branches", branchRef.branchName)
128+
}
129+
useVersionStreamFormat()
130+
}
131+
132+
// Assert
133+
assertEquals(HttpStatusCode.InternalServerError, response.status)
134+
}
135+
}
95136
}

0 commit comments

Comments
 (0)