From 6bc304476e608db0a769e82f8a3794b303509279 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Wed, 1 Nov 2017 23:49:37 +0100 Subject: [PATCH 01/32] Adding GET login test --- backend/build.gradle | 1 + .../jetbrains/demo/thinkter/LoginKtTest.kt | 180 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt diff --git a/backend/build.gradle b/backend/build.gradle index 6097f03..576ad62 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -17,6 +17,7 @@ dependencies { testCompile("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" + testCompile "io.mockk:mockk:1.1" compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt new file mode 100644 index 0000000..b77795b --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -0,0 +1,180 @@ +package org.jetbrains.demo.thinkter + +import io.mockk.* +import io.mockk.junit.MockKJUnit4Runner +import kotlinx.coroutines.experimental.runBlocking +import org.jetbrains.demo.thinkter.dao.ThinkterStorage +import org.jetbrains.demo.thinkter.model.LoginResponse +import org.jetbrains.demo.thinkter.model.User +import org.jetbrains.ktor.application.ApplicationCall +import org.jetbrains.ktor.application.ApplicationFeature +import org.jetbrains.ktor.http.HttpMethod +import org.jetbrains.ktor.http.HttpStatusCode +import org.jetbrains.ktor.locations.Locations +import org.jetbrains.ktor.pipeline.PipelineContext +import org.jetbrains.ktor.pipeline.PipelineInterceptor +import org.jetbrains.ktor.routing.HttpMethodRouteSelector +import org.jetbrains.ktor.routing.RouteSelector +import org.jetbrains.ktor.routing.Routing +import org.jetbrains.ktor.util.Attributes +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.reflect.KClass + +@RunWith(MockKJUnit4Runner::class) +class LoginKtTest { + val route = mockk() + val dao = mockk() + val hash = mockk<(String) -> String>() + val locations = mockk() + + lateinit var getLogin: AppCallSlot + lateinit var postLogin: AppCallSlot + lateinit var postLogout: AppCallSlot + + @Before + fun setUp() { + every { + route + .application + .attributes + .childAs(Attributes::class.java) + .get(ApplicationFeature.registry) + .childAs(Locations::class.java) + .get(Locations.key) + } returns locations + + getLogin = route.mockCall( + locations, + Login::class, + HttpMethodRouteSelector(HttpMethod.Get)) + + postLogin = route.mockCall( + locations, + Login::class, + HttpMethodRouteSelector(HttpMethod.Post)) + + postLogout = route.mockCall( + locations, + Logout::class, + HttpMethodRouteSelector(HttpMethod.Post)) + + route.login(dao, hash) + + } + + @Test + fun testLoginForbidden() { + getLogin.issueCall(locations, + Login("abc", + "def", + "ghi")) { handle -> + every { + attributes.contains(match { it!!.name == "Session" }) + } returns false + + coEvery { + respond(any()) + } returns null + + handle() + + coVerify { + respond(HttpStatusCode.Forbidden) + } + } + } + + @Test + fun testLoginOk() { + val user = User("userId", + "email", + "display", + "pwd") + every { + dao.user("userId", any()) + } returns user + + getLogin.issueCall(locations, + Login("abc", + "def", + "ghi")) { handle -> + every { + attributes.contains(match { it!!.name == "Session" }) + } returns true + + every { + attributes.get(match { it!!.name == "Session" }) + } returns Session("userId") + + coEvery { + respond(any()) + } returns null + + handle() + + coVerify { + respond(LoginResponse(user)) + } + } + } + + private fun Routing.mockCall(locations: Locations, + dataClass: KClass, + selector: RouteSelector): CapturingSlot> { + + every { + this@mockCall + .application + .attributes + .childAs(Attributes::class.java) + .get(ApplicationFeature.registry) + .childAs(Locations::class.java) + .get(Locations.key) + } returns locations + + + every { + locations.createEntry(this@mockCall, dataClass) + .select(selector) + .parent + } returns this + + val lambda = slot>() + every { + locations.createEntry(this@mockCall, dataClass) + .select(selector) + .handle(capture(lambda)) + } returns null + return lambda + } +} + +typealias AppCallSlot = CapturingSlot> + +private fun AppCallSlot.issueCall(locations: Locations, + data: Any, + block: ApplicationCall.(() -> Unit) -> Unit) { + + runBlocking { + val ctx = mockk>() + val call = mockk() + every { + locations.childAs(data.javaClass) + .resolve(data.javaClass.kotlin, call) + } returns data + + every { + ctx.childAs(ApplicationCall::class.java) + .subject + } returns call + + call.block({ + runBlocking { + captured!!.invoke(ctx, call) + } + }) + } + +} From c993d0bd1ed28d214c0606eab24dc8425880e00a Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Thu, 2 Nov 2017 07:37:18 +0100 Subject: [PATCH 02/32] Covered Login with tests --- .../jetbrains/demo/thinkter/LoginKtTest.kt | 216 ++++++++++++++---- 1 file changed, 167 insertions(+), 49 deletions(-) diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index b77795b..56a8099 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -16,6 +16,7 @@ import org.jetbrains.ktor.pipeline.PipelineInterceptor import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.RouteSelector import org.jetbrains.ktor.routing.Routing +import org.jetbrains.ktor.sessions.SessionConfig import org.jetbrains.ktor.util.Attributes import org.junit.Before import org.junit.Test @@ -29,9 +30,9 @@ class LoginKtTest { val hash = mockk<(String) -> String>() val locations = mockk() - lateinit var getLogin: AppCallSlot - lateinit var postLogin: AppCallSlot - lateinit var postLogout: AppCallSlot + lateinit var getLogin: DslRouteSlot + lateinit var postLogin: DslRouteSlot + lateinit var postLogout: DslRouteSlot @Before fun setUp() { @@ -45,17 +46,17 @@ class LoginKtTest { .get(Locations.key) } returns locations - getLogin = route.mockCall( + getLogin = route.captureDslRoute( locations, Login::class, HttpMethodRouteSelector(HttpMethod.Get)) - postLogin = route.mockCall( + postLogin = route.captureDslRoute( locations, Login::class, HttpMethodRouteSelector(HttpMethod.Post)) - postLogout = route.mockCall( + postLogout = route.captureDslRoute( locations, Logout::class, HttpMethodRouteSelector(HttpMethod.Post)) @@ -65,14 +66,26 @@ class LoginKtTest { } @Test - fun testLoginForbidden() { + fun testGetLoginOk() { + val user = User("userId", + "email", + "display", + "pwd") + every { + dao.user("userId", any()) + } returns user + getLogin.issueCall(locations, Login("abc", "def", "ghi")) { handle -> every { attributes.contains(match { it!!.name == "Session" }) - } returns false + } returns true + + every { + attributes.get(match { it!!.name == "Session" }) + } returns Session("userId") coEvery { respond(any()) @@ -81,32 +94,53 @@ class LoginKtTest { handle() coVerify { - respond(HttpStatusCode.Forbidden) + respond(LoginResponse(user)) } } } @Test - fun testLoginOk() { - val user = User("userId", - "email", - "display", - "pwd") - every { - dao.user("userId", any()) - } returns user - + fun testGetLoginForbidden() { getLogin.issueCall(locations, Login("abc", "def", "ghi")) { handle -> every { attributes.contains(match { it!!.name == "Session" }) - } returns true + } returns false + + coEvery { + respond(any()) + } returns null + handle() + + coVerify { + respond(HttpStatusCode.Forbidden) + } + } + } + + @Test + fun testPostLoginOk() { + postLogin.issueCall(locations, + Login("abcdef", + "ghiklm")) { handle -> + + every { hash.childAs(String::class.java).invoke("ghiklm") } returns "mlkihg" + val user = User("abcdef", "abc@def", "Abc Def", "mlkihg") every { - attributes.get(match { it!!.name == "Session" }) - } returns Session("userId") + dao.user("abcdef", "mlkihg") + } returns user + every { + val cfg = attributes + .childAs(SessionConfig::class.java) + .get(match({ it!!.name == "SessionConfig" })) as SessionConfig<*> + cfg.sessionType + } returns Session::class + every { + attributes.put(match({ it!!.name == "Session" }), any()) + } returns null coEvery { respond(any()) @@ -117,45 +151,129 @@ class LoginKtTest { coVerify { respond(LoginResponse(user)) } + + coVerify { + attributes.put(match({ it!!.name == "Session" }), Session("abcdef")) + } } } - private fun Routing.mockCall(locations: Locations, - dataClass: KClass, - selector: RouteSelector): CapturingSlot> { + @Test + fun testPostLoginShortUsername() { + postLogin.issueCall(locations, + Login("abc", + "defghi")) { handle -> - every { - this@mockCall - .application - .attributes - .childAs(Attributes::class.java) - .get(ApplicationFeature.registry) - .childAs(Locations::class.java) - .get(Locations.key) - } returns locations + coEvery { + respond(any()) + } returns null + handle() - every { - locations.createEntry(this@mockCall, dataClass) - .select(selector) - .parent - } returns this + coVerify { + respond(LoginResponse(error = "Invalid username or password")) + } + } + } - val lambda = slot>() - every { - locations.createEntry(this@mockCall, dataClass) - .select(selector) - .handle(capture(lambda)) - } returns null - return lambda + @Test + fun testPostLoginShortPassword() { + postLogin.issueCall(locations, + Login("abcdef", + "ghi")) { handle -> + + coEvery { + respond(any()) + } returns null + + handle() + + coVerify { + respond(LoginResponse(error = "Invalid username or password")) + } + } + } + + @Test + fun testPostLoginWrongUsername() { + postLogin.issueCall(locations, + Login("#!$%#$$@#", + "defghi")) { handle -> + + coEvery { + respond(any()) + } returns null + + handle() + + coVerify { + respond(LoginResponse(error = "Invalid username or password")) + } + } + } + + @Test + fun testPostLogoutOk() { + postLogout.issueCall(locations, + Logout()) { handle -> + + every { hash.childAs(String::class.java).invoke("ghiklm") } returns "mlkihg" + val user = User("abcdef", "abc@def", "Abc Def", "mlkihg") + every { + dao.user("abcdef", "mlkihg") + } returns user + every { + attributes + .childAs(SessionConfig::class.java) + .getOrNull(match({ it!!.name == "SessionConfig" })) as SessionConfig<*> + } returns null + every { + attributes.remove(match({ it!!.name == "Session" })) + } returns null + + coEvery { + respond(any()) + } returns null + + handle() + + coVerify { + respond(HttpStatusCode.OK) + } + + verify { + attributes.remove(match({ it!!.name == "Session" })) + } + } } + + +} + +private fun Routing.captureDslRoute(locations: Locations, + dataClass: KClass, + selector: RouteSelector): DslRouteSlot { + + every { + locations.createEntry(this@captureDslRoute, dataClass) + .select(selector) + .parent + } returns this + + val lambda = slot>() + every { + locations.createEntry(this@captureDslRoute, dataClass) + .select(selector) + .handle(capture(lambda)) + } returns null + return lambda } -typealias AppCallSlot = CapturingSlot> +typealias DslRouteSlot = CapturingSlot> -private fun AppCallSlot.issueCall(locations: Locations, - data: Any, - block: ApplicationCall.(() -> Unit) -> Unit) { +private fun DslRouteSlot.issueCall(locations: Locations, + data: Any, + block: ApplicationCall.(() -> Unit) -> Unit) { runBlocking { val ctx = mockk>() From cdac7fb4a1098ede65914de4e4c2a294f848951e Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Thu, 2 Nov 2017 08:07:26 +0100 Subject: [PATCH 03/32] Refactoring LoginKtTest --- .../jetbrains/demo/thinkter/LoginKtTest.kt | 109 ++++++------------ 1 file changed, 38 insertions(+), 71 deletions(-) diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 56a8099..1698f5b 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -17,6 +17,7 @@ import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.RouteSelector import org.jetbrains.ktor.routing.Routing import org.jetbrains.ktor.sessions.SessionConfig +import org.jetbrains.ktor.util.AttributeKey import org.jetbrains.ktor.util.Attributes import org.junit.Before import org.junit.Test @@ -79,23 +80,15 @@ class LoginKtTest { Login("abc", "def", "ghi")) { handle -> - every { - attributes.contains(match { it!!.name == "Session" }) - } returns true + every { attributes.contains(sessionMatcher()) } returns true - every { - attributes.get(match { it!!.name == "Session" }) - } returns Session("userId") + every { attributes.get(sessionMatcher()) } returns Session("userId") - coEvery { - respond(any()) - } returns null + coEvery { respond(any()) } returns null handle() - coVerify { - respond(LoginResponse(user)) - } + coVerify { respond(LoginResponse(user)) } } } @@ -105,19 +98,13 @@ class LoginKtTest { Login("abc", "def", "ghi")) { handle -> - every { - attributes.contains(match { it!!.name == "Session" }) - } returns false + every { attributes.contains(sessionMatcher()) } returns false - coEvery { - respond(any()) - } returns null + coEvery { respond(any()) } returns null handle() - coVerify { - respond(HttpStatusCode.Forbidden) - } + coVerify { respond(HttpStatusCode.Forbidden) } } } @@ -129,32 +116,25 @@ class LoginKtTest { every { hash.childAs(String::class.java).invoke("ghiklm") } returns "mlkihg" val user = User("abcdef", "abc@def", "Abc Def", "mlkihg") - every { - dao.user("abcdef", "mlkihg") - } returns user + + every { dao.user("abcdef", "mlkihg") } returns user + every { val cfg = attributes .childAs(SessionConfig::class.java) - .get(match({ it!!.name == "SessionConfig" })) as SessionConfig<*> + .get(sessionConfigMatcher()) as SessionConfig<*> cfg.sessionType } returns Session::class - every { - attributes.put(match({ it!!.name == "Session" }), any()) - } returns null - coEvery { - respond(any()) - } returns null + every { attributes.put(sessionMatcher(), any()) } returns null + + coEvery { respond(any()) } returns null handle() - coVerify { - respond(LoginResponse(user)) - } + coVerify { respond(LoginResponse(user)) } - coVerify { - attributes.put(match({ it!!.name == "Session" }), Session("abcdef")) - } + coVerify { attributes.put(sessionMatcher(), Session("abcdef")) } } } @@ -164,15 +144,11 @@ class LoginKtTest { Login("abc", "defghi")) { handle -> - coEvery { - respond(any()) - } returns null + coEvery { respond(any()) } returns null handle() - coVerify { - respond(LoginResponse(error = "Invalid username or password")) - } + coVerify { respond(LoginResponse(error = "Invalid username or password")) } } } @@ -182,15 +158,11 @@ class LoginKtTest { Login("abcdef", "ghi")) { handle -> - coEvery { - respond(any()) - } returns null + coEvery { respond(any()) } returns null handle() - coVerify { - respond(LoginResponse(error = "Invalid username or password")) - } + coVerify { respond(LoginResponse(error = "Invalid username or password")) } } } @@ -200,15 +172,11 @@ class LoginKtTest { Login("#!$%#$$@#", "defghi")) { handle -> - coEvery { - respond(any()) - } returns null + coEvery { respond(any()) } returns null handle() - coVerify { - respond(LoginResponse(error = "Invalid username or password")) - } + coVerify { respond(LoginResponse(error = "Invalid username or password")) } } } @@ -219,34 +187,33 @@ class LoginKtTest { every { hash.childAs(String::class.java).invoke("ghiklm") } returns "mlkihg" val user = User("abcdef", "abc@def", "Abc Def", "mlkihg") - every { - dao.user("abcdef", "mlkihg") - } returns user + + every { dao.user("abcdef", "mlkihg") } returns user + every { attributes .childAs(SessionConfig::class.java) - .getOrNull(match({ it!!.name == "SessionConfig" })) as SessionConfig<*> - } returns null - every { - attributes.remove(match({ it!!.name == "Session" })) + .getOrNull(sessionConfigMatcher()) as SessionConfig<*> } returns null - coEvery { - respond(any()) - } returns null + every { attributes.remove(sessionMatcher()) } returns null + + coEvery { respond(any()) } returns null handle() - coVerify { - respond(HttpStatusCode.OK) - } + coVerify { respond(HttpStatusCode.OK) } - verify { - attributes.remove(match({ it!!.name == "Session" })) - } + verify { attributes.remove(sessionMatcher()) } } } + private inline fun MockKScope.sessionMatcher(): AttributeKey = + match({ it!!.name == "Session" }) + + private inline fun MockKScope.sessionConfigMatcher(): AttributeKey = + match({ it!!.name == "SessionConfig" }) + } From 1e8db37b9f5447238a16eb7d56b968c95a2f99e8 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Thu, 2 Nov 2017 08:17:22 +0100 Subject: [PATCH 04/32] Refactoring LoginKtTest --- .../org/jetbrains/demo/thinkter/LoginKtTest.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 1698f5b..8728ef6 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -82,7 +82,11 @@ class LoginKtTest { "ghi")) { handle -> every { attributes.contains(sessionMatcher()) } returns true - every { attributes.get(sessionMatcher()) } returns Session("userId") + every { + attributes + .childAs(Session::class.java) + .get(sessionMatcher()) + } returns Session("userId") coEvery { respond(any()) } returns null @@ -120,10 +124,10 @@ class LoginKtTest { every { dao.user("abcdef", "mlkihg") } returns user every { - val cfg = attributes + attributes .childAs(SessionConfig::class.java) - .get(sessionConfigMatcher()) as SessionConfig<*> - cfg.sessionType + .get(sessionConfigMatcher()) + .sessionType } returns Session::class every { attributes.put(sessionMatcher(), any()) } returns null @@ -193,7 +197,7 @@ class LoginKtTest { every { attributes .childAs(SessionConfig::class.java) - .getOrNull(sessionConfigMatcher()) as SessionConfig<*> + .getOrNull(sessionConfigMatcher()) } returns null every { attributes.remove(sessionMatcher()) } returns null @@ -211,7 +215,7 @@ class LoginKtTest { private inline fun MockKScope.sessionMatcher(): AttributeKey = match({ it!!.name == "Session" }) - private inline fun MockKScope.sessionConfigMatcher(): AttributeKey = + private inline fun MockKScope.sessionConfigMatcher(): AttributeKey> = match({ it!!.name == "SessionConfig" }) From d870b5377d2bc3c12b3c2c316e83d50ed31eb548 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Thu, 2 Nov 2017 17:52:52 +0100 Subject: [PATCH 05/32] Covered IndexKt with tests --- backend/build.gradle | 1 + .../jetbrains/demo/thinkter/IndexKtTest.kt | 201 ++++++++++++++++++ .../jetbrains/demo/thinkter/KtorTestKit.kt | 96 +++++++++ .../jetbrains/demo/thinkter/LoginKtTest.kt | 37 ---- gradle/wrapper/gradle-wrapper.properties | 3 +- 5 files changed, 300 insertions(+), 38 deletions(-) create mode 100644 backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt create mode 100644 backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt diff --git a/backend/build.gradle b/backend/build.gradle index 576ad62..bd892e6 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -18,6 +18,7 @@ dependencies { testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" testCompile "io.mockk:mockk:1.1" + testCompile 'com.willowtreeapps.assertk:assertk:0.9' compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt new file mode 100644 index 0000000..a2ef690 --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt @@ -0,0 +1,201 @@ +package org.jetbrains.demo.thinkter + +import assertk.assertions.contains +import assertk.assertions.containsAll +import assertk.assertions.isEqualTo +import io.mockk.* +import io.mockk.junit.MockKJUnit4Runner +import kotlinx.coroutines.experimental.runBlocking +import org.jetbrains.demo.thinkter.dao.ThinkterStorage +import org.jetbrains.demo.thinkter.model.IndexResponse +import org.jetbrains.demo.thinkter.model.PollResponse +import org.jetbrains.demo.thinkter.model.Thought +import org.jetbrains.demo.thinkter.model.User +import org.jetbrains.ktor.cio.ByteBufferWriteChannel +import org.jetbrains.ktor.html.HtmlContent +import org.jetbrains.ktor.http.HttpHeaders +import org.jetbrains.ktor.http.HttpMethod +import org.jetbrains.ktor.locations.Locations +import org.jetbrains.ktor.routing.HttpHeaderRouteSelector +import org.jetbrains.ktor.routing.HttpMethodRouteSelector +import org.jetbrains.ktor.routing.Routing +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import java.nio.charset.Charset +import java.time.* +import java.time.format.DateTimeFormatter + +@RunWith(MockKJUnit4Runner::class) +class IndexKtTest { + val route = mockk() + val dao = mockk() + val locations = mockk() + + val getHtmlIndex = DslRouteSlot() + val getJsonIndex = DslRouteSlot() + val getJsonPoll = DslRouteSlot() + + @Before + fun setUp() { + route.mockDsl(locations) { + mockSelect(HttpHeaderRouteSelector(HttpHeaders.Accept, "text/html")) { + mockObj { + mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { + captureHandle(getHtmlIndex) + } + } + } + mockSelect(HttpHeaderRouteSelector(HttpHeaders.Accept, "application/json")) { + mockObj { + mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { + captureHandle(getJsonIndex) + } + } + mockObj { + mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { + captureHandle(getJsonPoll) + } + } + } + } + + route.index(dao) + + } + + @Test + fun testGetIndexHtml() { + getHtmlIndex.issueCall(locations, Index()) { handle -> + val html = slot() + coEvery { respond(any()) } answers { + runBlocking { + val htmlContent = firstArg() + val channel = ByteBufferWriteChannel() + htmlContent.writeTo(channel) + html.captured = channel.toString(Charset.defaultCharset()) + } + nothing + } + + handle() + + assertk.assert(html.captured!!) + .contains("Thinkter") + } + } + + @Test + fun testGetIndexJson() { + getJsonIndex.issueCall(locations, Index()) { handle -> + every { attributes.contains(sessionMatcher()) } returns true + + every { + attributes + .childAs(Session::class.java) + .get(sessionMatcher()) + } returns Session("userId") + + every { dao.user("userId") } returns User("userId", + "email", + "User", + "pwd") + + every { dao.top(10) } returns (1..10).toList() + + every { dao.latest(10) } returns (1..10).toList() + + every { dao.getThought(any()) } answers { + Thought(firstArg(), + "user" + firstArg(), + "text", + "date", + null) + } + + coEvery { respond(any()) } returns null + + every { response.pipeline.intercept(any(), any()) } returns null + + handle() + + coVerify { + respond(match { + val oneToTen = (1..10).toList().toTypedArray() + + assertk.assert(it!!.top.map { it.id }) + .containsAll(*oneToTen) + + assertk.assert(it.latest.map { it.id }) + .containsAll(*oneToTen) + true + }) + } + } + } + + @Test + fun testGetPollJsonBlank() { + getJsonPoll.issueCall(locations, Poll("")) { handle -> + coEvery { respond(any()) } returns null + + handle() + + coVerify { + respond(match { + assertk.assert(it!!.count) + .isEqualTo("0") + true + }) + } + } + } + + @Test + fun testGetPollJsonOne() { + checkPoll("9", "1") + } + + @Test + fun testGetPollJsonFive() { + checkPoll("5", "5") + } + + @Test + fun testGetPollJsonTenPlus() { + checkPoll("0", "10+") + } + + private fun checkPoll(pollTime: String, responseCount: String) { + getJsonPoll.issueCall(locations, Poll(pollTime)) { handle -> + every { dao.latest(10) } returns (1..10).toList() + every { dao.getThought(any()) } answers { + Thought(firstArg(), + "userId", + "text", + formatDate(firstArg().toLong()), + null) + } + + coEvery { respond(any()) } returns null + + handle() + + coVerify { + respond(match { + assertk.assert(it!!.count) + .isEqualTo(responseCount) + true + }) + } + } + } + + private fun formatDate(date: Long): String { + return Instant.ofEpochMilli(date) + .atZone(ZoneId.systemDefault()) + .toOffsetDateTime() + .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + } +} + diff --git a/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt b/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt new file mode 100644 index 0000000..56c0f7e --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt @@ -0,0 +1,96 @@ +package org.jetbrains.demo.thinkter + +import io.mockk.CapturingSlot +import io.mockk.MockKScope +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.experimental.runBlocking +import org.jetbrains.ktor.application.ApplicationCall +import org.jetbrains.ktor.application.ApplicationFeature +import org.jetbrains.ktor.locations.Locations +import org.jetbrains.ktor.pipeline.PipelineContext +import org.jetbrains.ktor.pipeline.PipelineInterceptor +import org.jetbrains.ktor.routing.Route +import org.jetbrains.ktor.routing.RouteSelector +import org.jetbrains.ktor.routing.Routing +import org.jetbrains.ktor.routing.application +import org.jetbrains.ktor.sessions.SessionConfig +import org.jetbrains.ktor.util.AttributeKey +import org.jetbrains.ktor.util.Attributes +import kotlin.reflect.KClass + +fun Route.mockDsl(locations: Locations, block: RouteDslMock.() -> Unit) = RouteDslMock(this, locations).block() + +typealias DslRouteSlot = CapturingSlot> + +class RouteDslMock(val route: Route, val locations: Locations) { + init { + every { + route + .application + .attributes + .childAs(Attributes::class.java) + .get(ApplicationFeature.registry) + .childAs(Locations::class.java) + .get(Locations.key) + } returns locations + } + + inline fun RouteDslMock.mockObj(noinline block: RouteDslMock.() -> Unit) { + mockObj(this.route, T::class, block) + } + + @PublishedApi + internal fun mockObj(route: Route, dataClass: KClass<*>, block: RouteDslMock.() -> Unit) { + val nextRoute = mockk() + every { locations.createEntry(route, dataClass) } returns nextRoute + every { nextRoute.parent } returns route + + RouteDslMock(nextRoute, locations).block() + } + + fun RouteDslMock.mockSelect(selector: RouteSelector, block: RouteDslMock.() -> Unit) { + val nextRoute = mockk() + every { this@mockSelect.route.select(selector) } returns nextRoute + every { nextRoute.parent } returns this@mockSelect.route + + RouteDslMock(nextRoute, locations).block() + } + + fun RouteDslMock.captureHandle(slot: DslRouteSlot) { + every { this@captureHandle.route.handle(capture(slot)) } returns null + } +} + +fun DslRouteSlot.issueCall(locations: Locations, + data: Any, + block: ApplicationCall.(() -> Unit) -> Unit) { + + runBlocking { + val ctx = mockk>() + val call = mockk() + every { + locations.childAs(data.javaClass) + .resolve(data.javaClass.kotlin, call) + } returns data + + every { + ctx.childAs(ApplicationCall::class.java) + .subject + } returns call + + call.block({ + runBlocking { + captured!!.invoke(ctx, call) + } + }) + } + +} + +inline fun MockKScope.sessionMatcher(): AttributeKey = + match({ it!!.name == "Session" }) + +inline fun MockKScope.sessionConfigMatcher(): AttributeKey> = + match({ it!!.name == "SessionConfig" }) + diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 8728ef6..6df44fd 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -2,7 +2,6 @@ package org.jetbrains.demo.thinkter import io.mockk.* import io.mockk.junit.MockKJUnit4Runner -import kotlinx.coroutines.experimental.runBlocking import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.LoginResponse import org.jetbrains.demo.thinkter.model.User @@ -11,7 +10,6 @@ import org.jetbrains.ktor.application.ApplicationFeature import org.jetbrains.ktor.http.HttpMethod import org.jetbrains.ktor.http.HttpStatusCode import org.jetbrains.ktor.locations.Locations -import org.jetbrains.ktor.pipeline.PipelineContext import org.jetbrains.ktor.pipeline.PipelineInterceptor import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.RouteSelector @@ -211,14 +209,6 @@ class LoginKtTest { verify { attributes.remove(sessionMatcher()) } } } - - private inline fun MockKScope.sessionMatcher(): AttributeKey = - match({ it!!.name == "Session" }) - - private inline fun MockKScope.sessionConfigMatcher(): AttributeKey> = - match({ it!!.name == "SessionConfig" }) - - } private fun Routing.captureDslRoute(locations: Locations, @@ -240,30 +230,3 @@ private fun Routing.captureDslRoute(locations: Locations, return lambda } -typealias DslRouteSlot = CapturingSlot> - -private fun DslRouteSlot.issueCall(locations: Locations, - data: Any, - block: ApplicationCall.(() -> Unit) -> Unit) { - - runBlocking { - val ctx = mockk>() - val call = mockk() - every { - locations.childAs(data.javaClass) - .resolve(data.javaClass.kotlin, call) - } returns data - - every { - ctx.childAs(ApplicationCall::class.java) - .subject - } returns call - - call.block({ - runBlocking { - captured!!.invoke(ctx, call) - } - }) - } - -} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 74bb778..d0eceb6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Thu Nov 02 14:14:21 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-all.zip From b8b3149250140edd039e74abec2cefab5d32fab6 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Thu, 2 Nov 2017 23:21:56 +0100 Subject: [PATCH 06/32] Upgrade to MockK 1.2 --- backend/build.gradle | 2 +- .../jetbrains/demo/thinkter/IndexKtTest.kt | 34 ++++++------------ .../jetbrains/demo/thinkter/KtorTestKit.kt | 19 +++++----- .../jetbrains/demo/thinkter/LoginKtTest.kt | 35 +++++++++---------- 4 files changed, 37 insertions(+), 53 deletions(-) diff --git a/backend/build.gradle b/backend/build.gradle index bd892e6..483f0a0 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -17,7 +17,7 @@ dependencies { testCompile("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" - testCompile "io.mockk:mockk:1.1" + testCompile "io.mockk:mockk:1.2" testCompile 'com.willowtreeapps.assertk:assertk:0.9' compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" diff --git a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt index a2ef690..7e998b2 100644 --- a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt @@ -92,7 +92,7 @@ class IndexKtTest { every { attributes - .childAs(Session::class.java) + .hint(Session::class) .get(sessionMatcher()) } returns Session("userId") @@ -113,22 +113,18 @@ class IndexKtTest { null) } - coEvery { respond(any()) } returns null + coEvery { respond(any()) } just Runs - every { response.pipeline.intercept(any(), any()) } returns null + every { response.pipeline.intercept(any(), any()) } just Runs handle() coVerify { - respond(match { - val oneToTen = (1..10).toList().toTypedArray() + respond(assert(msg = "response should have top and latest with ids from one to ten") { + val oneToTen = (1..10).toList() - assertk.assert(it!!.top.map { it.id }) - .containsAll(*oneToTen) - - assertk.assert(it.latest.map { it.id }) - .containsAll(*oneToTen) - true + it!!.top.map { it.id }.containsAll(oneToTen) + && it.latest.map { it.id }.containsAll(oneToTen) }) } } @@ -137,16 +133,12 @@ class IndexKtTest { @Test fun testGetPollJsonBlank() { getJsonPoll.issueCall(locations, Poll("")) { handle -> - coEvery { respond(any()) } returns null + coEvery { respond(any()) } just Runs handle() coVerify { - respond(match { - assertk.assert(it!!.count) - .isEqualTo("0") - true - }) + respond(assert { it!!.count == "0" }) } } } @@ -177,16 +169,12 @@ class IndexKtTest { null) } - coEvery { respond(any()) } returns null + coEvery { respond(any()) } just Runs handle() coVerify { - respond(match { - assertk.assert(it!!.count) - .isEqualTo(responseCount) - true - }) + respond(assert { it!!.count == responseCount }) } } } diff --git a/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt b/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt index 56c0f7e..c543804 100644 --- a/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt +++ b/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt @@ -1,9 +1,6 @@ package org.jetbrains.demo.thinkter -import io.mockk.CapturingSlot -import io.mockk.MockKScope -import io.mockk.every -import io.mockk.mockk +import io.mockk.* import kotlinx.coroutines.experimental.runBlocking import org.jetbrains.ktor.application.ApplicationCall import org.jetbrains.ktor.application.ApplicationFeature @@ -29,9 +26,9 @@ class RouteDslMock(val route: Route, val locations: Locations) { route .application .attributes - .childAs(Attributes::class.java) + .hint(Attributes::class) .get(ApplicationFeature.registry) - .childAs(Locations::class.java) + .hint(Locations::class) .get(Locations.key) } returns locations } @@ -58,7 +55,7 @@ class RouteDslMock(val route: Route, val locations: Locations) { } fun RouteDslMock.captureHandle(slot: DslRouteSlot) { - every { this@captureHandle.route.handle(capture(slot)) } returns null + every { this@captureHandle.route.handle(capture(slot)) } just Runs } } @@ -70,12 +67,12 @@ fun DslRouteSlot.issueCall(locations: Locations, val ctx = mockk>() val call = mockk() every { - locations.childAs(data.javaClass) + locations.hint(data.javaClass.kotlin) .resolve(data.javaClass.kotlin, call) } returns data every { - ctx.childAs(ApplicationCall::class.java) + ctx.hint(ApplicationCall::class) .subject } returns call @@ -88,9 +85,9 @@ fun DslRouteSlot.issueCall(locations: Locations, } -inline fun MockKScope.sessionMatcher(): AttributeKey = +inline fun MockKMatcherScope.sessionMatcher(): AttributeKey = match({ it!!.name == "Session" }) -inline fun MockKScope.sessionConfigMatcher(): AttributeKey> = +inline fun MockKMatcherScope.sessionConfigMatcher(): AttributeKey> = match({ it!!.name == "SessionConfig" }) diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 6df44fd..2ae083e 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -15,7 +15,6 @@ import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.RouteSelector import org.jetbrains.ktor.routing.Routing import org.jetbrains.ktor.sessions.SessionConfig -import org.jetbrains.ktor.util.AttributeKey import org.jetbrains.ktor.util.Attributes import org.junit.Before import org.junit.Test @@ -39,9 +38,9 @@ class LoginKtTest { route .application .attributes - .childAs(Attributes::class.java) + .hint(Attributes::class) .get(ApplicationFeature.registry) - .childAs(Locations::class.java) + .hint(Locations::class) .get(Locations.key) } returns locations @@ -82,11 +81,11 @@ class LoginKtTest { every { attributes - .childAs(Session::class.java) + .hint(Session::class) .get(sessionMatcher()) } returns Session("userId") - coEvery { respond(any()) } returns null + coEvery { respond(any()) } just Runs handle() @@ -102,7 +101,7 @@ class LoginKtTest { "ghi")) { handle -> every { attributes.contains(sessionMatcher()) } returns false - coEvery { respond(any()) } returns null + coEvery { respond(any()) } just Runs handle() @@ -116,21 +115,21 @@ class LoginKtTest { Login("abcdef", "ghiklm")) { handle -> - every { hash.childAs(String::class.java).invoke("ghiklm") } returns "mlkihg" + every { hash.hint(String::class).invoke("ghiklm") } returns "mlkihg" val user = User("abcdef", "abc@def", "Abc Def", "mlkihg") every { dao.user("abcdef", "mlkihg") } returns user every { attributes - .childAs(SessionConfig::class.java) + .hint(SessionConfig::class) .get(sessionConfigMatcher()) .sessionType } returns Session::class - every { attributes.put(sessionMatcher(), any()) } returns null + every { attributes.put(sessionMatcher(), any()) } just Runs - coEvery { respond(any()) } returns null + coEvery { respond(any()) } just Runs handle() @@ -146,7 +145,7 @@ class LoginKtTest { Login("abc", "defghi")) { handle -> - coEvery { respond(any()) } returns null + coEvery { respond(any()) } just Runs handle() @@ -160,7 +159,7 @@ class LoginKtTest { Login("abcdef", "ghi")) { handle -> - coEvery { respond(any()) } returns null + coEvery { respond(any()) } just Runs handle() @@ -174,7 +173,7 @@ class LoginKtTest { Login("#!$%#$$@#", "defghi")) { handle -> - coEvery { respond(any()) } returns null + coEvery { respond(any()) } just Runs handle() @@ -187,20 +186,20 @@ class LoginKtTest { postLogout.issueCall(locations, Logout()) { handle -> - every { hash.childAs(String::class.java).invoke("ghiklm") } returns "mlkihg" + every { hash.hint(String::class).invoke("ghiklm") } returns "mlkihg" val user = User("abcdef", "abc@def", "Abc Def", "mlkihg") every { dao.user("abcdef", "mlkihg") } returns user every { attributes - .childAs(SessionConfig::class.java) + .hint(SessionConfig::class) .getOrNull(sessionConfigMatcher()) } returns null - every { attributes.remove(sessionMatcher()) } returns null + every { attributes.remove(sessionMatcher()) } just Runs - coEvery { respond(any()) } returns null + coEvery { respond(any()) } just Runs handle() @@ -226,7 +225,7 @@ private fun Routing.captureDslRoute(locations: Locations, locations.createEntry(this@captureDslRoute, dataClass) .select(selector) .handle(capture(lambda)) - } returns null + } just Runs return lambda } From 19b90d397065bd57c69fb48a50c2f72db8d99486 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Fri, 3 Nov 2017 07:27:06 +0100 Subject: [PATCH 07/32] Using newer mockDsl in LoginKtTest --- .../jetbrains/demo/thinkter/LoginKtTest.kt | 71 +++++-------------- 1 file changed, 18 insertions(+), 53 deletions(-) diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 2ae083e..3f57c01 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -5,21 +5,15 @@ import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.LoginResponse import org.jetbrains.demo.thinkter.model.User -import org.jetbrains.ktor.application.ApplicationCall -import org.jetbrains.ktor.application.ApplicationFeature import org.jetbrains.ktor.http.HttpMethod import org.jetbrains.ktor.http.HttpStatusCode import org.jetbrains.ktor.locations.Locations -import org.jetbrains.ktor.pipeline.PipelineInterceptor import org.jetbrains.ktor.routing.HttpMethodRouteSelector -import org.jetbrains.ktor.routing.RouteSelector import org.jetbrains.ktor.routing.Routing import org.jetbrains.ktor.sessions.SessionConfig -import org.jetbrains.ktor.util.Attributes import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import kotlin.reflect.KClass @RunWith(MockKJUnit4Runner::class) class LoginKtTest { @@ -28,36 +22,27 @@ class LoginKtTest { val hash = mockk<(String) -> String>() val locations = mockk() - lateinit var getLogin: DslRouteSlot - lateinit var postLogin: DslRouteSlot - lateinit var postLogout: DslRouteSlot + val getLogin = DslRouteSlot() + val postLogin = DslRouteSlot() + val postLogout = DslRouteSlot() @Before fun setUp() { - every { - route - .application - .attributes - .hint(Attributes::class) - .get(ApplicationFeature.registry) - .hint(Locations::class) - .get(Locations.key) - } returns locations - - getLogin = route.captureDslRoute( - locations, - Login::class, - HttpMethodRouteSelector(HttpMethod.Get)) - - postLogin = route.captureDslRoute( - locations, - Login::class, - HttpMethodRouteSelector(HttpMethod.Post)) - - postLogout = route.captureDslRoute( - locations, - Logout::class, - HttpMethodRouteSelector(HttpMethod.Post)) + route.mockDsl(locations) { + mockObj { + mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { + captureHandle(getLogin) + } + mockSelect(HttpMethodRouteSelector(HttpMethod.Post)) { + captureHandle(postLogin) + } + } + mockObj { + mockSelect(HttpMethodRouteSelector(HttpMethod.Post)) { + captureHandle(postLogout) + } + } + } route.login(dao, hash) @@ -209,23 +194,3 @@ class LoginKtTest { } } } - -private fun Routing.captureDslRoute(locations: Locations, - dataClass: KClass, - selector: RouteSelector): DslRouteSlot { - - every { - locations.createEntry(this@captureDslRoute, dataClass) - .select(selector) - .parent - } returns this - - val lambda = slot>() - every { - locations.createEntry(this@captureDslRoute, dataClass) - .select(selector) - .handle(capture(lambda)) - } just Runs - return lambda -} - From daa51669a247746d5f825c251fec8b7e280573c9 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Fri, 3 Nov 2017 07:42:47 +0100 Subject: [PATCH 08/32] Adding PostThoughtKtTest --- .../org/jetbrains/demo/thinkter/Common.kt | 21 ++++++ .../jetbrains/demo/thinkter/IndexKtTest.kt | 13 +--- .../demo/thinkter/PostThoughtKtTest.kt | 67 +++++++++++++++++++ 3 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 backend/test/org/jetbrains/demo/thinkter/Common.kt create mode 100644 backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt diff --git a/backend/test/org/jetbrains/demo/thinkter/Common.kt b/backend/test/org/jetbrains/demo/thinkter/Common.kt new file mode 100644 index 0000000..8cac0dc --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/Common.kt @@ -0,0 +1,21 @@ +package org.jetbrains.demo.thinkter + +import io.mockk.every +import org.jetbrains.demo.thinkter.dao.ThinkterStorage +import org.jetbrains.demo.thinkter.model.User +import org.jetbrains.ktor.application.ApplicationCall + +fun ApplicationCall.mockSessionReturningUser(dao: ThinkterStorage) { + every { attributes.contains(sessionMatcher()) } returns true + + every { + attributes + .hint(Session::class) + .get(sessionMatcher()) + } returns Session("userId") + + every { dao.user("userId") } returns User("userId", + "email", + "User", + "pwd") +} diff --git a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt index 7e998b2..56dbf89 100644 --- a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt @@ -88,18 +88,7 @@ class IndexKtTest { @Test fun testGetIndexJson() { getJsonIndex.issueCall(locations, Index()) { handle -> - every { attributes.contains(sessionMatcher()) } returns true - - every { - attributes - .hint(Session::class) - .get(sessionMatcher()) - } returns Session("userId") - - every { dao.user("userId") } returns User("userId", - "email", - "User", - "pwd") + mockSessionReturningUser(dao) every { dao.top(10) } returns (1..10).toList() diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt new file mode 100644 index 0000000..1e3eb0c --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -0,0 +1,67 @@ +package org.jetbrains.demo.thinkter + +import io.mockk.* +import io.mockk.junit.MockKJUnit4Runner +import org.jetbrains.demo.thinkter.dao.ThinkterStorage +import org.jetbrains.demo.thinkter.model.PostThoughtToken +import org.jetbrains.ktor.http.HttpHeaders +import org.jetbrains.ktor.http.HttpMethod +import org.jetbrains.ktor.locations.Locations +import org.jetbrains.ktor.request.host +import org.jetbrains.ktor.routing.HttpMethodRouteSelector +import org.jetbrains.ktor.routing.Routing +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(MockKJUnit4Runner::class) +class PostThoughtKtTest { + val route = mockk() + val dao = mockk() + val hash = mockk<(String) -> String>() + val locations = mockk() + + val getPostThought = DslRouteSlot() + val postPostThought = DslRouteSlot() + + @Before + fun setUp() { + route.mockDsl(locations) { + mockObj { + mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { + captureHandle(getPostThought) + } + mockSelect(HttpMethodRouteSelector(HttpMethod.Post)) { + captureHandle(postPostThought) + } + } + } + + route.postThought(dao, hash) + } + + @Test + fun testGetPostThought() { + getPostThought.issueCall(locations, PostThought()) { handle -> + mockSessionReturningUser(dao) + + every { request.host() } returns "host" + + every { request.headers[HttpHeaders.Referrer] } returns "abc" + + every { hash.hint(String::class).invoke(any()) } answers { firstArg().reversed() } + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(assert { + it!!.user == "userId" && + it.code.contains("llun:tsoh:dIresu") + }) + } + } + } + +} \ No newline at end of file From 73034a1803c4657c61a0e455bd1dff26f1f7d0f5 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Fri, 3 Nov 2017 08:07:41 +0100 Subject: [PATCH 09/32] Adding forbidden case --- .../test/org/jetbrains/demo/thinkter/Common.kt | 5 +++++ .../jetbrains/demo/thinkter/PostThoughtKtTest.kt | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/backend/test/org/jetbrains/demo/thinkter/Common.kt b/backend/test/org/jetbrains/demo/thinkter/Common.kt index 8cac0dc..7dcce4f 100644 --- a/backend/test/org/jetbrains/demo/thinkter/Common.kt +++ b/backend/test/org/jetbrains/demo/thinkter/Common.kt @@ -19,3 +19,8 @@ fun ApplicationCall.mockSessionReturningUser(dao: ThinkterStorage) { "User", "pwd") } + + +fun ApplicationCall.mockSessionReturningNothing() { + every { attributes.contains(sessionMatcher()) } returns false +} diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt index 1e3eb0c..88c5f73 100644 --- a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -4,8 +4,10 @@ import io.mockk.* import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.PostThoughtToken +import org.jetbrains.ktor.application.ApplicationCall import org.jetbrains.ktor.http.HttpHeaders import org.jetbrains.ktor.http.HttpMethod +import org.jetbrains.ktor.http.HttpStatusCode import org.jetbrains.ktor.locations.Locations import org.jetbrains.ktor.request.host import org.jetbrains.ktor.routing.HttpMethodRouteSelector @@ -41,7 +43,7 @@ class PostThoughtKtTest { } @Test - fun testGetPostThought() { + fun testGetPostThoughtOk() { getPostThought.issueCall(locations, PostThought()) { handle -> mockSessionReturningUser(dao) @@ -64,4 +66,16 @@ class PostThoughtKtTest { } } + @Test + fun testGetPostThoughtForbidden() { + getPostThought.issueCall(locations, PostThought()) { handle -> + mockSessionReturningNothing() + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { respond(HttpStatusCode.Forbidden) } + } + } } \ No newline at end of file From c91da6738ac5059f7284087d84b21828a7472f5d Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Fri, 3 Nov 2017 22:39:19 +0100 Subject: [PATCH 10/32] Added PostThoughtKtTest --- .../jetbrains/demo/thinkter/IndexKtTest.kt | 23 +++---- .../jetbrains/demo/thinkter/KtorTestKit.kt | 12 ++-- .../jetbrains/demo/thinkter/LoginKtTest.kt | 26 ++++---- .../demo/thinkter/PostThoughtKtTest.kt | 66 ++++++++++++++++--- 4 files changed, 86 insertions(+), 41 deletions(-) diff --git a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt index 56dbf89..54e9bf6 100644 --- a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt @@ -1,8 +1,6 @@ package org.jetbrains.demo.thinkter import assertk.assertions.contains -import assertk.assertions.containsAll -import assertk.assertions.isEqualTo import io.mockk.* import io.mockk.junit.MockKJUnit4Runner import kotlinx.coroutines.experimental.runBlocking @@ -10,7 +8,6 @@ import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.IndexResponse import org.jetbrains.demo.thinkter.model.PollResponse import org.jetbrains.demo.thinkter.model.Thought -import org.jetbrains.demo.thinkter.model.User import org.jetbrains.ktor.cio.ByteBufferWriteChannel import org.jetbrains.ktor.html.HtmlContent import org.jetbrains.ktor.http.HttpHeaders @@ -32,9 +29,9 @@ class IndexKtTest { val dao = mockk() val locations = mockk() - val getHtmlIndex = DslRouteSlot() - val getJsonIndex = DslRouteSlot() - val getJsonPoll = DslRouteSlot() + val getHtmlIndex = RouteBlockSlot() + val getJsonIndex = RouteBlockSlot() + val getJsonPoll = RouteBlockSlot() @Before fun setUp() { @@ -42,19 +39,19 @@ class IndexKtTest { mockSelect(HttpHeaderRouteSelector(HttpHeaders.Accept, "text/html")) { mockObj { mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { - captureHandle(getHtmlIndex) + captureBlock(getHtmlIndex) } } } mockSelect(HttpHeaderRouteSelector(HttpHeaders.Accept, "application/json")) { mockObj { mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { - captureHandle(getJsonIndex) + captureBlock(getJsonIndex) } } mockObj { mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { - captureHandle(getJsonPoll) + captureBlock(getJsonPoll) } } } @@ -66,7 +63,7 @@ class IndexKtTest { @Test fun testGetIndexHtml() { - getHtmlIndex.issueCall(locations, Index()) { handle -> + getHtmlIndex.invokeBlock(locations, Index()) { handle -> val html = slot() coEvery { respond(any()) } answers { runBlocking { @@ -87,7 +84,7 @@ class IndexKtTest { @Test fun testGetIndexJson() { - getJsonIndex.issueCall(locations, Index()) { handle -> + getJsonIndex.invokeBlock(locations, Index()) { handle -> mockSessionReturningUser(dao) every { dao.top(10) } returns (1..10).toList() @@ -121,7 +118,7 @@ class IndexKtTest { @Test fun testGetPollJsonBlank() { - getJsonPoll.issueCall(locations, Poll("")) { handle -> + getJsonPoll.invokeBlock(locations, Poll("")) { handle -> coEvery { respond(any()) } just Runs handle() @@ -148,7 +145,7 @@ class IndexKtTest { } private fun checkPoll(pollTime: String, responseCount: String) { - getJsonPoll.issueCall(locations, Poll(pollTime)) { handle -> + getJsonPoll.invokeBlock(locations, Poll(pollTime)) { handle -> every { dao.latest(10) } returns (1..10).toList() every { dao.getThought(any()) } answers { Thought(firstArg(), diff --git a/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt b/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt index c543804..f328abc 100644 --- a/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt +++ b/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt @@ -18,7 +18,7 @@ import kotlin.reflect.KClass fun Route.mockDsl(locations: Locations, block: RouteDslMock.() -> Unit) = RouteDslMock(this, locations).block() -typealias DslRouteSlot = CapturingSlot> +typealias RouteBlockSlot = CapturingSlot> class RouteDslMock(val route: Route, val locations: Locations) { init { @@ -54,14 +54,14 @@ class RouteDslMock(val route: Route, val locations: Locations) { RouteDslMock(nextRoute, locations).block() } - fun RouteDslMock.captureHandle(slot: DslRouteSlot) { - every { this@captureHandle.route.handle(capture(slot)) } just Runs + fun RouteDslMock.captureBlock(slot: RouteBlockSlot) { + every { this@captureBlock.route.handle(capture(slot)) } just Runs } } -fun DslRouteSlot.issueCall(locations: Locations, - data: Any, - block: ApplicationCall.(() -> Unit) -> Unit) { +fun RouteBlockSlot.invokeBlock(locations: Locations, + data: Any, + block: ApplicationCall.(() -> Unit) -> Unit) { runBlocking { val ctx = mockk>() diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 3f57c01..809ed15 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -22,24 +22,24 @@ class LoginKtTest { val hash = mockk<(String) -> String>() val locations = mockk() - val getLogin = DslRouteSlot() - val postLogin = DslRouteSlot() - val postLogout = DslRouteSlot() + val getLogin = RouteBlockSlot() + val postLogin = RouteBlockSlot() + val postLogout = RouteBlockSlot() @Before fun setUp() { route.mockDsl(locations) { mockObj { mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { - captureHandle(getLogin) + captureBlock(getLogin) } mockSelect(HttpMethodRouteSelector(HttpMethod.Post)) { - captureHandle(postLogin) + captureBlock(postLogin) } } mockObj { mockSelect(HttpMethodRouteSelector(HttpMethod.Post)) { - captureHandle(postLogout) + captureBlock(postLogout) } } } @@ -58,7 +58,7 @@ class LoginKtTest { dao.user("userId", any()) } returns user - getLogin.issueCall(locations, + getLogin.invokeBlock(locations, Login("abc", "def", "ghi")) { handle -> @@ -80,7 +80,7 @@ class LoginKtTest { @Test fun testGetLoginForbidden() { - getLogin.issueCall(locations, + getLogin.invokeBlock(locations, Login("abc", "def", "ghi")) { handle -> @@ -96,7 +96,7 @@ class LoginKtTest { @Test fun testPostLoginOk() { - postLogin.issueCall(locations, + postLogin.invokeBlock(locations, Login("abcdef", "ghiklm")) { handle -> @@ -126,7 +126,7 @@ class LoginKtTest { @Test fun testPostLoginShortUsername() { - postLogin.issueCall(locations, + postLogin.invokeBlock(locations, Login("abc", "defghi")) { handle -> @@ -140,7 +140,7 @@ class LoginKtTest { @Test fun testPostLoginShortPassword() { - postLogin.issueCall(locations, + postLogin.invokeBlock(locations, Login("abcdef", "ghi")) { handle -> @@ -154,7 +154,7 @@ class LoginKtTest { @Test fun testPostLoginWrongUsername() { - postLogin.issueCall(locations, + postLogin.invokeBlock(locations, Login("#!$%#$$@#", "defghi")) { handle -> @@ -168,7 +168,7 @@ class LoginKtTest { @Test fun testPostLogoutOk() { - postLogout.issueCall(locations, + postLogout.invokeBlock(locations, Logout()) { handle -> every { hash.hint(String::class).invoke("ghiklm") } returns "mlkihg" diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt index 88c5f73..35faa13 100644 --- a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -3,8 +3,9 @@ package org.jetbrains.demo.thinkter import io.mockk.* import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage +import org.jetbrains.demo.thinkter.model.PostThoughtResult import org.jetbrains.demo.thinkter.model.PostThoughtToken -import org.jetbrains.ktor.application.ApplicationCall +import org.jetbrains.demo.thinkter.model.Thought import org.jetbrains.ktor.http.HttpHeaders import org.jetbrains.ktor.http.HttpMethod import org.jetbrains.ktor.http.HttpStatusCode @@ -23,18 +24,18 @@ class PostThoughtKtTest { val hash = mockk<(String) -> String>() val locations = mockk() - val getPostThought = DslRouteSlot() - val postPostThought = DslRouteSlot() + val getPostThought = RouteBlockSlot() + val postPostThought = RouteBlockSlot() @Before fun setUp() { route.mockDsl(locations) { mockObj { mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { - captureHandle(getPostThought) + captureBlock(getPostThought) } mockSelect(HttpMethodRouteSelector(HttpMethod.Post)) { - captureHandle(postPostThought) + captureBlock(postPostThought) } } } @@ -44,12 +45,12 @@ class PostThoughtKtTest { @Test fun testGetPostThoughtOk() { - getPostThought.issueCall(locations, PostThought()) { handle -> + getPostThought.invokeBlock(locations, PostThought()) { handle -> mockSessionReturningUser(dao) every { request.host() } returns "host" - every { request.headers[HttpHeaders.Referrer] } returns "abc" + every { request.headers[HttpHeaders.Referrer] } returns "http://abc/referrer" every { hash.hint(String::class).invoke(any()) } answers { firstArg().reversed() } @@ -60,7 +61,7 @@ class PostThoughtKtTest { coVerify { respond(assert { it!!.user == "userId" && - it.code.contains("llun:tsoh:dIresu") + it.code.contains("cba:tsoh:dIresu") }) } } @@ -68,7 +69,54 @@ class PostThoughtKtTest { @Test fun testGetPostThoughtForbidden() { - getPostThought.issueCall(locations, PostThought()) { handle -> + getPostThought.invokeBlock(locations, PostThought()) { handle -> + mockSessionReturningNothing() + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { respond(HttpStatusCode.Forbidden) } + } + } + + @Test + fun testPostPostThoughtOk() { + val ts = System.currentTimeMillis() - 6000 + val data = PostThought("text", ts, "cba:tsoh:dIresu:" + ts.toString().reversed(), null) + postPostThought.invokeBlock(locations, data) { handle -> + mockSessionReturningUser(dao) + + every { request.host() } returns "host" + + every { request.headers[HttpHeaders.Referrer] } returns "http://abc/referrer" + + every { hash.hint(String::class).invoke(any()) } answers { firstArg().reversed() } + + every { + dao.createThought("userId", "text", any(), any()) + } returns 1 + + every { + dao.getThought(1) + } answers { Thought(1, "userId", "text", ts.toString(), null) } + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(assert { + it!!.thought.id == 1 && + it.thought.text == "text" + }) + } + } + } + + @Test + fun testPostPostThoughtForbidden() { + postPostThought.invokeBlock(locations, PostThought()) { handle -> mockSessionReturningNothing() coEvery { respond(any()) } just Runs From cfbbbca84e91c81b828770f88ea392e44e3d420a Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Fri, 3 Nov 2017 22:47:12 +0100 Subject: [PATCH 11/32] Ignoring test till next release --- backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt index 35faa13..deef250 100644 --- a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -14,6 +14,7 @@ import org.jetbrains.ktor.request.host import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.Routing import org.junit.Before +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith @@ -81,6 +82,7 @@ class PostThoughtKtTest { } @Test + @Ignore // need to wait till next release fun testPostPostThoughtOk() { val ts = System.currentTimeMillis() - 6000 val data = PostThought("text", ts, "cba:tsoh:dIresu:" + ts.toString().reversed(), null) From 841757aa9883f76c33d2c856133181f572554b75 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Fri, 3 Nov 2017 22:50:00 +0100 Subject: [PATCH 12/32] Revert: gradle-wrapper.properties --- gradle/wrapper/gradle-wrapper.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d0eceb6..74bb778 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Nov 02 14:14:21 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-bin.zip From d98ed9d50e05e35a21df8ecfebfb9050336f2a1a Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Sat, 4 Nov 2017 06:06:01 +0100 Subject: [PATCH 13/32] Adding DeleteKtTest --- .../org/jetbrains/demo/thinkter/Common.kt | 34 +++++- .../jetbrains/demo/thinkter/DeleteKtTest.kt | 111 ++++++++++++++++++ .../jetbrains/demo/thinkter/KtorTestKit.kt | 7 -- .../jetbrains/demo/thinkter/LoginKtTest.kt | 8 +- .../demo/thinkter/PostThoughtKtTest.kt | 35 +----- 5 files changed, 155 insertions(+), 40 deletions(-) create mode 100644 backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt diff --git a/backend/test/org/jetbrains/demo/thinkter/Common.kt b/backend/test/org/jetbrains/demo/thinkter/Common.kt index 7dcce4f..e454285 100644 --- a/backend/test/org/jetbrains/demo/thinkter/Common.kt +++ b/backend/test/org/jetbrains/demo/thinkter/Common.kt @@ -1,9 +1,21 @@ package org.jetbrains.demo.thinkter -import io.mockk.every +import io.mockk.* import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.User import org.jetbrains.ktor.application.ApplicationCall +import org.jetbrains.ktor.http.HttpHeaders +import org.jetbrains.ktor.http.HttpStatusCode +import org.jetbrains.ktor.request.host +import org.jetbrains.ktor.sessions.SessionConfig +import org.jetbrains.ktor.util.AttributeKey + +fun MockKMatcherScope.sessionMatcher(): AttributeKey = + match({ it!!.name == "Session" }) + +fun MockKMatcherScope.sessionConfigMatcher(): AttributeKey> = + match({ it!!.name == "SessionConfig" }) + fun ApplicationCall.mockSessionReturningUser(dao: ThinkterStorage) { every { attributes.contains(sessionMatcher()) } returns true @@ -24,3 +36,23 @@ fun ApplicationCall.mockSessionReturningUser(dao: ThinkterStorage) { fun ApplicationCall.mockSessionReturningNothing() { every { attributes.contains(sessionMatcher()) } returns false } + + + +fun ApplicationCall.checkForbiddenIfSesionReturningNothing(handle: () -> Unit) { + mockSessionReturningNothing() + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { respond(HttpStatusCode.Forbidden) } +} + +fun ApplicationCall.mockHostReferrerHash(hash: (String) -> String) { + every { request.host() } returns "host" + + every { request.headers[HttpHeaders.Referrer] } returns "http://abc/referrer" + + every { hash.hint(String::class).invoke(any()) } answers { firstArg().reversed() } +} diff --git a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt new file mode 100644 index 0000000..86fdb5e --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt @@ -0,0 +1,111 @@ +package org.jetbrains.demo.thinkter + +import io.mockk.* +import io.mockk.junit.MockKJUnit4Runner +import org.jetbrains.demo.thinkter.dao.ThinkterStorage +import org.jetbrains.demo.thinkter.model.PostThoughtResult +import org.jetbrains.demo.thinkter.model.PostThoughtToken +import org.jetbrains.demo.thinkter.model.RpcData +import org.jetbrains.demo.thinkter.model.Thought +import org.jetbrains.ktor.http.HttpMethod +import org.jetbrains.ktor.locations.Locations +import org.jetbrains.ktor.routing.HttpMethodRouteSelector +import org.jetbrains.ktor.routing.Routing +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(MockKJUnit4Runner::class) +class DeleteKtTest { + val route = mockk() + val dao = mockk() + val hash = mockk<(String) -> String>() + val locations = mockk() + + val getThoughtDelete = RouteBlockSlot() + val postThoughtDelete = RouteBlockSlot() + + @Before + fun setUp() { + route.mockDsl(locations) { + mockObj { + mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { + captureBlock(getThoughtDelete) + } + mockSelect(HttpMethodRouteSelector(HttpMethod.Post)) { + captureBlock(postThoughtDelete) + } + } + } + + route.delete(dao, hash) + } + + @Test + fun testGetThoughtDeleteOk() { + val data = ThoughtDelete(1, System.currentTimeMillis() - 6000, "abc") + getThoughtDelete.invokeBlock(locations, data) { handle -> + mockSessionReturningUser(dao) + mockHostReferrerHash(hash) + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(assert { + it!!.user == "userId" && + it.code.contains("cba:tsoh:dIresu") + }) + } + } + } + + @Test + fun testGetThoughtDeleteForbidden() { + val data = ThoughtDelete(0, 0, "abc") + getThoughtDelete.invokeBlock(locations, data) { handle -> + checkForbiddenIfSesionReturningNothing(handle) + } + } + + @Test + fun testPostThoughtDeleteOk() { + val ts = System.currentTimeMillis() - 6000 + val data = ThoughtDelete(1, ts, "cba:tsoh:dIresu:" + ts.toString().reversed()) + postThoughtDelete.invokeBlock(locations, data) { handle -> + mockSessionReturningUser(dao) + mockHostReferrerHash(hash) + + every { + dao.getThought(1) + } answers { Thought(1, "userId", "text", ts.toString(), null) } + + every { + dao.deleteThought(1) + } just Runs + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(ofType(RpcData::class.java)) + } + } + } + + @Test + fun testPostThoughtDeleteForbidden() { + val data = ThoughtDelete(1, 0, "abc") + val ts = System.currentTimeMillis() + postThoughtDelete.invokeBlock(locations, data) { handle -> + every { + dao.getThought(1) + } answers { Thought(1, "userId", "text", ts.toString(), null) } + + checkForbiddenIfSesionReturningNothing(handle) + } + } + +} \ No newline at end of file diff --git a/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt b/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt index f328abc..d48292b 100644 --- a/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt +++ b/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt @@ -84,10 +84,3 @@ fun RouteBlockSlot.invokeBlock(locations: Locations, } } - -inline fun MockKMatcherScope.sessionMatcher(): AttributeKey = - match({ it!!.name == "Session" }) - -inline fun MockKMatcherScope.sessionConfigMatcher(): AttributeKey> = - match({ it!!.name == "SessionConfig" }) - diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 809ed15..e8a66c2 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -172,9 +172,13 @@ class LoginKtTest { Logout()) { handle -> every { hash.hint(String::class).invoke("ghiklm") } returns "mlkihg" - val user = User("abcdef", "abc@def", "Abc Def", "mlkihg") - every { dao.user("abcdef", "mlkihg") } returns user + every { + dao.user("abcdef", "mlkihg") + } returns User("abcdef", + "abc@def", + "Abc Def", + "mlkihg") every { attributes diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt index deef250..81154cf 100644 --- a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -6,11 +6,8 @@ import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.PostThoughtResult import org.jetbrains.demo.thinkter.model.PostThoughtToken import org.jetbrains.demo.thinkter.model.Thought -import org.jetbrains.ktor.http.HttpHeaders import org.jetbrains.ktor.http.HttpMethod -import org.jetbrains.ktor.http.HttpStatusCode import org.jetbrains.ktor.locations.Locations -import org.jetbrains.ktor.request.host import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.Routing import org.junit.Before @@ -48,12 +45,7 @@ class PostThoughtKtTest { fun testGetPostThoughtOk() { getPostThought.invokeBlock(locations, PostThought()) { handle -> mockSessionReturningUser(dao) - - every { request.host() } returns "host" - - every { request.headers[HttpHeaders.Referrer] } returns "http://abc/referrer" - - every { hash.hint(String::class).invoke(any()) } answers { firstArg().reversed() } + mockHostReferrerHash(hash) coEvery { respond(any()) } just Runs @@ -71,13 +63,7 @@ class PostThoughtKtTest { @Test fun testGetPostThoughtForbidden() { getPostThought.invokeBlock(locations, PostThought()) { handle -> - mockSessionReturningNothing() - - coEvery { respond(any()) } just Runs - - handle() - - coVerify { respond(HttpStatusCode.Forbidden) } + checkForbiddenIfSesionReturningNothing(handle) } } @@ -88,12 +74,7 @@ class PostThoughtKtTest { val data = PostThought("text", ts, "cba:tsoh:dIresu:" + ts.toString().reversed(), null) postPostThought.invokeBlock(locations, data) { handle -> mockSessionReturningUser(dao) - - every { request.host() } returns "host" - - every { request.headers[HttpHeaders.Referrer] } returns "http://abc/referrer" - - every { hash.hint(String::class).invoke(any()) } answers { firstArg().reversed() } + mockHostReferrerHash(hash) every { dao.createThought("userId", "text", any(), any()) @@ -119,13 +100,7 @@ class PostThoughtKtTest { @Test fun testPostPostThoughtForbidden() { postPostThought.invokeBlock(locations, PostThought()) { handle -> - mockSessionReturningNothing() - - coEvery { respond(any()) } just Runs - - handle() - - coVerify { respond(HttpStatusCode.Forbidden) } + checkForbiddenIfSesionReturningNothing(handle) } } -} \ No newline at end of file +} From f6a7cd3021815b651378d795d3acae75a961cce7 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Sat, 4 Nov 2017 06:33:57 +0100 Subject: [PATCH 14/32] Adding ViewThoughtKtTest --- .../org/jetbrains/demo/thinkter/Common.kt | 24 +++++- .../jetbrains/demo/thinkter/DeleteKtTest.kt | 6 +- .../jetbrains/demo/thinkter/IndexKtTest.kt | 26 +----- .../demo/thinkter/PostThoughtKtTest.kt | 5 +- .../demo/thinkter/ViewThoughtKtTest.kt | 80 +++++++++++++++++++ 5 files changed, 109 insertions(+), 32 deletions(-) create mode 100644 backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt diff --git a/backend/test/org/jetbrains/demo/thinkter/Common.kt b/backend/test/org/jetbrains/demo/thinkter/Common.kt index e454285..e160227 100644 --- a/backend/test/org/jetbrains/demo/thinkter/Common.kt +++ b/backend/test/org/jetbrains/demo/thinkter/Common.kt @@ -2,6 +2,7 @@ package org.jetbrains.demo.thinkter import io.mockk.* import org.jetbrains.demo.thinkter.dao.ThinkterStorage +import org.jetbrains.demo.thinkter.model.Thought import org.jetbrains.demo.thinkter.model.User import org.jetbrains.ktor.application.ApplicationCall import org.jetbrains.ktor.http.HttpHeaders @@ -9,6 +10,9 @@ import org.jetbrains.ktor.http.HttpStatusCode import org.jetbrains.ktor.request.host import org.jetbrains.ktor.sessions.SessionConfig import org.jetbrains.ktor.util.AttributeKey +import java.time.Instant +import java.time.ZoneId +import java.time.format.DateTimeFormatter fun MockKMatcherScope.sessionMatcher(): AttributeKey = match({ it!!.name == "Session" }) @@ -38,7 +42,6 @@ fun ApplicationCall.mockSessionReturningNothing() { } - fun ApplicationCall.checkForbiddenIfSesionReturningNothing(handle: () -> Unit) { mockSessionReturningNothing() @@ -56,3 +59,22 @@ fun ApplicationCall.mockHostReferrerHash(hash: (String) -> String) { every { hash.hint(String::class).invoke(any()) } answers { firstArg().reversed() } } + +fun mockGetThought(dao: ThinkterStorage, ts: Long) { + every { + dao.getThought(any()) + } answers { Thought(firstArg(), + "userId", + "text", + formatDate(ts + firstArg()), + null) } +} + +private fun formatDate(date: Long): String { + return Instant.ofEpochMilli(date) + .atZone(ZoneId.systemDefault()) + .toOffsetDateTime() + .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) +} + + diff --git a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt index 86fdb5e..a396301 100644 --- a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt @@ -3,7 +3,6 @@ package org.jetbrains.demo.thinkter import io.mockk.* import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage -import org.jetbrains.demo.thinkter.model.PostThoughtResult import org.jetbrains.demo.thinkter.model.PostThoughtToken import org.jetbrains.demo.thinkter.model.RpcData import org.jetbrains.demo.thinkter.model.Thought @@ -76,10 +75,7 @@ class DeleteKtTest { postThoughtDelete.invokeBlock(locations, data) { handle -> mockSessionReturningUser(dao) mockHostReferrerHash(hash) - - every { - dao.getThought(1) - } answers { Thought(1, "userId", "text", ts.toString(), null) } + mockGetThought(dao, ts) every { dao.deleteThought(1) diff --git a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt index 54e9bf6..d7e6f65 100644 --- a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt @@ -86,19 +86,12 @@ class IndexKtTest { fun testGetIndexJson() { getJsonIndex.invokeBlock(locations, Index()) { handle -> mockSessionReturningUser(dao) + mockGetThought(dao, 0) every { dao.top(10) } returns (1..10).toList() every { dao.latest(10) } returns (1..10).toList() - every { dao.getThought(any()) } answers { - Thought(firstArg(), - "user" + firstArg(), - "text", - "date", - null) - } - coEvery { respond(any()) } just Runs every { response.pipeline.intercept(any(), any()) } just Runs @@ -110,7 +103,7 @@ class IndexKtTest { val oneToTen = (1..10).toList() it!!.top.map { it.id }.containsAll(oneToTen) - && it.latest.map { it.id }.containsAll(oneToTen) + && it.latest.map { it.id }.containsAll(oneToTen) }) } } @@ -146,14 +139,9 @@ class IndexKtTest { private fun checkPoll(pollTime: String, responseCount: String) { getJsonPoll.invokeBlock(locations, Poll(pollTime)) { handle -> + mockGetThought(dao, 0) + every { dao.latest(10) } returns (1..10).toList() - every { dao.getThought(any()) } answers { - Thought(firstArg(), - "userId", - "text", - formatDate(firstArg().toLong()), - null) - } coEvery { respond(any()) } just Runs @@ -165,11 +153,5 @@ class IndexKtTest { } } - private fun formatDate(date: Long): String { - return Instant.ofEpochMilli(date) - .atZone(ZoneId.systemDefault()) - .toOffsetDateTime() - .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) - } } diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt index 81154cf..64e44c4 100644 --- a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -5,7 +5,6 @@ import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.PostThoughtResult import org.jetbrains.demo.thinkter.model.PostThoughtToken -import org.jetbrains.demo.thinkter.model.Thought import org.jetbrains.ktor.http.HttpMethod import org.jetbrains.ktor.locations.Locations import org.jetbrains.ktor.routing.HttpMethodRouteSelector @@ -75,14 +74,12 @@ class PostThoughtKtTest { postPostThought.invokeBlock(locations, data) { handle -> mockSessionReturningUser(dao) mockHostReferrerHash(hash) + mockGetThought(dao, ts) every { dao.createThought("userId", "text", any(), any()) } returns 1 - every { - dao.getThought(1) - } answers { Thought(1, "userId", "text", ts.toString(), null) } coEvery { respond(any()) } just Runs diff --git a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt new file mode 100644 index 0000000..d6b6655 --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt @@ -0,0 +1,80 @@ +package org.jetbrains.demo.thinkter + +import io.mockk.Runs +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.junit.MockKJUnit4Runner +import io.mockk.mockk +import org.jetbrains.demo.thinkter.dao.ThinkterStorage +import org.jetbrains.demo.thinkter.model.ViewThoughtResponse +import org.jetbrains.ktor.http.HttpMethod +import org.jetbrains.ktor.locations.Locations +import org.jetbrains.ktor.routing.HttpMethodRouteSelector +import org.jetbrains.ktor.routing.Routing +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(MockKJUnit4Runner::class) +class ViewThoughtKtTest { + val route = mockk() + val dao = mockk() + val hash = mockk<(String) -> String>() + val locations = mockk() + + val getViewThought = RouteBlockSlot() + val postViewThought = RouteBlockSlot() + + @Before + fun setUp() { + route.mockDsl(locations) { + mockObj { + mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { + captureBlock(getViewThought) + } + mockSelect(HttpMethodRouteSelector(HttpMethod.Post)) { + captureBlock(postViewThought) + } + } + } + + route.viewThought(dao, hash) + } + + @Test + fun testGetPostThoughtOk() { + getViewThought.invokeBlock(locations, ViewThought(1)) { handle -> + mockSessionReturningUser(dao) + mockHostReferrerHash(hash) + mockGetThought(dao, 0) + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(assert { + it!!.thought.userId == "userId" && + it.code!!.contains("cba:tsoh:dIresu") + }) + } + } + } + + @Test + fun testGetPostThoughtForbidden() { + getViewThought.invokeBlock(locations, ViewThought(1)) { handle -> + mockGetThought(dao, 0) + mockSessionReturningNothing() + coEvery { respond(any()) } just Runs + handle() + coVerify { + respond(assert { + it!!.thought.id == 1 && + it.code == null + }) + } + } + } + +} \ No newline at end of file From 313c9617bddd21e88a92c5bb1aa5d6459be14386 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Sat, 4 Nov 2017 06:50:22 +0100 Subject: [PATCH 15/32] Adding UserPageKt --- .../org/jetbrains/demo/thinkter/Common.kt | 5 ++ .../jetbrains/demo/thinkter/DeleteKtTest.kt | 4 +- .../jetbrains/demo/thinkter/LoginKtTest.kt | 5 +- .../demo/thinkter/PostThoughtKtTest.kt | 4 +- .../jetbrains/demo/thinkter/UserPageKtTest.kt | 76 +++++++++++++++++++ .../demo/thinkter/ViewThoughtKtTest.kt | 5 +- 6 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt diff --git a/backend/test/org/jetbrains/demo/thinkter/Common.kt b/backend/test/org/jetbrains/demo/thinkter/Common.kt index e160227..3fecc23 100644 --- a/backend/test/org/jetbrains/demo/thinkter/Common.kt +++ b/backend/test/org/jetbrains/demo/thinkter/Common.kt @@ -78,3 +78,8 @@ private fun formatDate(date: Long): String { } +fun mockUser(dao: ThinkterStorage, pwdHash: String? = null): User { + val user = User("abcdef", "abc@def", "Abc Def", pwdHash ?: "") + every { dao.user("abcdef", pwdHash) } returns user + return user +} diff --git a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt index a396301..23175f0 100644 --- a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt @@ -61,7 +61,7 @@ class DeleteKtTest { } @Test - fun testGetThoughtDeleteForbidden() { + fun testGetThoughtDeleteNotLoggedIn() { val data = ThoughtDelete(0, 0, "abc") getThoughtDelete.invokeBlock(locations, data) { handle -> checkForbiddenIfSesionReturningNothing(handle) @@ -92,7 +92,7 @@ class DeleteKtTest { } @Test - fun testPostThoughtDeleteForbidden() { + fun testPostThoughtDeleteNotLoggedIn() { val data = ThoughtDelete(1, 0, "abc") val ts = System.currentTimeMillis() postThoughtDelete.invokeBlock(locations, data) { handle -> diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index e8a66c2..0017e80 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -79,7 +79,7 @@ class LoginKtTest { } @Test - fun testGetLoginForbidden() { + fun testGetLoginNotLoggedIn() { getLogin.invokeBlock(locations, Login("abc", "def", @@ -101,9 +101,8 @@ class LoginKtTest { "ghiklm")) { handle -> every { hash.hint(String::class).invoke("ghiklm") } returns "mlkihg" - val user = User("abcdef", "abc@def", "Abc Def", "mlkihg") - every { dao.user("abcdef", "mlkihg") } returns user + val user = mockUser(dao, "mlkihg") every { attributes diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt index 64e44c4..4bccb1d 100644 --- a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -60,7 +60,7 @@ class PostThoughtKtTest { } @Test - fun testGetPostThoughtForbidden() { + fun testGetPostThoughtNotLoggedIn() { getPostThought.invokeBlock(locations, PostThought()) { handle -> checkForbiddenIfSesionReturningNothing(handle) } @@ -95,7 +95,7 @@ class PostThoughtKtTest { } @Test - fun testPostPostThoughtForbidden() { + fun testPostPostThoughtNotLoggedIn() { postPostThought.invokeBlock(locations, PostThought()) { handle -> checkForbiddenIfSesionReturningNothing(handle) } diff --git a/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt new file mode 100644 index 0000000..a9eda32 --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt @@ -0,0 +1,76 @@ +package org.jetbrains.demo.thinkter + +import io.mockk.* +import io.mockk.junit.MockKJUnit4Runner +import org.jetbrains.demo.thinkter.dao.ThinkterStorage +import org.jetbrains.demo.thinkter.model.PostThoughtToken +import org.jetbrains.demo.thinkter.model.Thought +import org.jetbrains.demo.thinkter.model.UserThoughtsResponse +import org.jetbrains.ktor.http.HttpMethod +import org.jetbrains.ktor.http.HttpStatusCode +import org.jetbrains.ktor.locations.Locations +import org.jetbrains.ktor.routing.HttpMethodRouteSelector +import org.jetbrains.ktor.routing.Routing +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(MockKJUnit4Runner::class) +class UserPageKtTest { + val route = mockk() + val dao = mockk() + val hash = mockk<(String) -> String>() + val locations = mockk() + + val getUserThoughts = RouteBlockSlot() + + @Before + fun setUp() { + route.mockDsl(locations) { + mockObj { + mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { + captureBlock(getUserThoughts) + } + } + } + + route.userPage(dao) + } + + @Test + fun testGetUserThoughtsOk() { + getUserThoughts.invokeBlock(locations, UserThoughts("abcdef")) { handle -> + mockHostReferrerHash(hash) + mockUser(dao) + mockGetThought(dao, 0) + + every { dao.userThoughts("abcdef") } returns listOf(1, 2, 3) + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(assert { + it!!.thoughts.any { it.id == 2 && it.text == "text" } + }) + } + } + } + + @Test + fun testGetUserThoughtsNoUserFound() { + getUserThoughts.invokeBlock(locations, UserThoughts("abcdef")) { handle -> + every { dao.user("abcdef") } returns null + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(HttpStatusCode.NotFound.description("User abcdef doesn't exist")) + } + } + } + +} \ No newline at end of file diff --git a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt index d6b6655..65edfdb 100644 --- a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt @@ -62,12 +62,15 @@ class ViewThoughtKtTest { } @Test - fun testGetPostThoughtForbidden() { + fun testGetPostThoughtNotLoggedIn() { getViewThought.invokeBlock(locations, ViewThought(1)) { handle -> mockGetThought(dao, 0) mockSessionReturningNothing() + coEvery { respond(any()) } just Runs + handle() + coVerify { respond(assert { it!!.thought.id == 1 && From 00a05002935794e9be9a67a7d62d27ab03cf1200 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Sat, 4 Nov 2017 07:35:35 +0100 Subject: [PATCH 16/32] Adding ApplicationPageTest --- backend/build.gradle | 18 ++++++- .../demo/thinkter/ApplicationPageTest.kt | 47 +++++++++++++++++++ .../jetbrains/demo/thinkter/DeleteKtTest.kt | 2 +- .../demo/thinkter/PostThoughtKtTest.kt | 1 - 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt diff --git a/backend/build.gradle b/backend/build.gradle index 483f0a0..d45ac1b 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -1,3 +1,8 @@ +plugins { + id "jacoco" + id "com.zoltu.application-agent" version "1.0.8" +} + group = 'org.jetbrains.demo.thinkter' version = '0.0.1-SNAPSHOT' @@ -5,6 +10,8 @@ apply plugin: 'kotlin' apply plugin: 'application' dependencies { + agent "io.mockk:mockk-agent:1.3-SNAPSHOT" + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" @@ -17,7 +24,7 @@ dependencies { testCompile("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" - testCompile "io.mockk:mockk:1.2" + testCompile "io.mockk:mockk:1.3-SNAPSHOT" testCompile 'com.willowtreeapps.assertk:assertk:0.9' compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" @@ -44,3 +51,12 @@ kotlin { } mainClassName = 'org.jetbrains.ktor.jetty.DevelopmentHost' + +jacocoTestReport { + reports { + xml.enabled true + html.enabled true + } +} + +check.dependsOn jacocoTestReport diff --git a/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt b/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt new file mode 100644 index 0000000..b9ca0b4 --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt @@ -0,0 +1,47 @@ +package org.jetbrains.demo.thinkter + +import assertk.assertions.contains +import io.mockk.Runs +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockk +import kotlinx.coroutines.experimental.runBlocking +import kotlinx.html.html +import kotlinx.html.stream.appendHTML +import org.jetbrains.ktor.application.ApplicationCall +import org.jetbrains.ktor.cio.ByteBufferWriteChannel +import org.jetbrains.ktor.cio.toOutputStream +import org.jetbrains.ktor.html.HtmlContent +import org.jetbrains.ktor.html.respondHtmlTemplate +import org.junit.Assert.* +import org.junit.Test +import java.nio.charset.Charset + +class ApplicationPageTest { + val appCall = mockk() + + @Test + fun testRenderHTML() { + coEvery { appCall.respond(any()) } just Runs + + runBlocking { + appCall.respondHtmlTemplate(ApplicationPage()) { + caption { +"caption" } + } + } + + val channel = ByteBufferWriteChannel() + coVerify { + appCall.respond(coAny { + it!!.writeTo(channel) + }) + } + + val generatedPage = channel.toString(Charset.defaultCharset()) + + assertk.assert(generatedPage) + .contains("caption") + assertk.assert(generatedPage) + .contains("yui.yahooapis.com") + } +} \ No newline at end of file diff --git a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt index 23175f0..5ae4154 100644 --- a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt @@ -86,7 +86,7 @@ class DeleteKtTest { handle() coVerify { - respond(ofType(RpcData::class.java)) + respond(ofType(RpcData::class)) } } } diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt index 4bccb1d..0f5d3ec 100644 --- a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -67,7 +67,6 @@ class PostThoughtKtTest { } @Test - @Ignore // need to wait till next release fun testPostPostThoughtOk() { val ts = System.currentTimeMillis() - 6000 val data = PostThought("text", ts, "cba:tsoh:dIresu:" + ts.toString().reversed(), null) From e00e79e610aef611fb440477fd26aa5e93d4c69a Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Sat, 4 Nov 2017 10:57:54 +0100 Subject: [PATCH 17/32] Adding RegisterKtTest --- .../org/jetbrains/demo/thinkter/Register.kt | 3 +- .../org/jetbrains/demo/thinkter/Common.kt | 13 + .../jetbrains/demo/thinkter/LoginKtTest.kt | 10 +- .../jetbrains/demo/thinkter/RegisterKtTest.kt | 240 ++++++++++++++++++ .../{KtorTestKit.kt => RouteMockDsl.kt} | 23 +- gradle/wrapper/gradle-wrapper.properties | 4 +- 6 files changed, 272 insertions(+), 21 deletions(-) create mode 100644 backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt rename backend/test/org/jetbrains/demo/thinkter/{KtorTestKit.kt => RouteMockDsl.kt} (81%) diff --git a/backend/src/org/jetbrains/demo/thinkter/Register.kt b/backend/src/org/jetbrains/demo/thinkter/Register.kt index 0752763..db70d0e 100644 --- a/backend/src/org/jetbrains/demo/thinkter/Register.kt +++ b/backend/src/org/jetbrains/demo/thinkter/Register.kt @@ -11,8 +11,6 @@ import org.jetbrains.ktor.util.* fun Route.register(dao: ThinkterStorage, hashFunction: (String) -> String) { post { form -> - val vm = call.request.content.get() - val user = call.sessionOrNull()?.let { dao.user(it.userId) } if (user != null) { call.redirect(LoginResponse(user)) @@ -40,6 +38,7 @@ fun Route.register(dao: ThinkterStorage, hashFunction: (String) -> String) { application.environment.log.error("Failed to register user", e) call.respond(LoginResponse(error = "Failed to register")) } + return@post } call.session(Session(newUser.userId)) diff --git a/backend/test/org/jetbrains/demo/thinkter/Common.kt b/backend/test/org/jetbrains/demo/thinkter/Common.kt index 3fecc23..b48cdda 100644 --- a/backend/test/org/jetbrains/demo/thinkter/Common.kt +++ b/backend/test/org/jetbrains/demo/thinkter/Common.kt @@ -60,6 +60,7 @@ fun ApplicationCall.mockHostReferrerHash(hash: (String) -> String) { every { hash.hint(String::class).invoke(any()) } answers { firstArg().reversed() } } + fun mockGetThought(dao: ThinkterStorage, ts: Long) { every { dao.getThought(any()) @@ -83,3 +84,15 @@ fun mockUser(dao: ThinkterStorage, pwdHash: String? = null): User { every { dao.user("abcdef", pwdHash) } returns user return user } + +fun ApplicationCall.mockPutSession() { + every { + attributes + .hint(SessionConfig::class) + .get(sessionConfigMatcher()) + .sessionType + } returns Session::class + + every { attributes.put(sessionMatcher(), any()) } just Runs +} + diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 0017e80..191e7c2 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -5,6 +5,7 @@ import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.LoginResponse import org.jetbrains.demo.thinkter.model.User +import org.jetbrains.ktor.application.ApplicationCall import org.jetbrains.ktor.http.HttpMethod import org.jetbrains.ktor.http.HttpStatusCode import org.jetbrains.ktor.locations.Locations @@ -104,14 +105,7 @@ class LoginKtTest { val user = mockUser(dao, "mlkihg") - every { - attributes - .hint(SessionConfig::class) - .get(sessionConfigMatcher()) - .sessionType - } returns Session::class - - every { attributes.put(sessionMatcher(), any()) } just Runs + mockPutSession() coEvery { respond(any()) } just Runs diff --git a/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt new file mode 100644 index 0000000..8111114 --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt @@ -0,0 +1,240 @@ +package org.jetbrains.demo.thinkter + +import io.mockk.* +import io.mockk.junit.MockKJUnit4Runner +import org.jetbrains.demo.thinkter.dao.ThinkterStorage +import org.jetbrains.demo.thinkter.model.LoginResponse +import org.jetbrains.demo.thinkter.model.User +import org.jetbrains.ktor.application.ApplicationFeature +import org.jetbrains.ktor.http.HttpHeaders +import org.jetbrains.ktor.http.HttpMethod +import org.jetbrains.ktor.http.HttpStatusCode +import org.jetbrains.ktor.locations.Locations +import org.jetbrains.ktor.routing.HttpMethodRouteSelector +import org.jetbrains.ktor.routing.Routing +import org.jetbrains.ktor.routing.application +import org.jetbrains.ktor.util.Attributes +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(MockKJUnit4Runner::class) +class RegisterKtTest { + val route = mockk() + val dao = mockk() + val hash = mockk<(String) -> String>() + val locations = mockk() + + val getRegister = RouteBlockSlot() + val postRegister = RouteBlockSlot() + + @Before + fun setUp() { + route.mockDsl(locations) { + mockObj { + mockSelect(HttpMethodRouteSelector(HttpMethod.Post)) { + captureBlock(postRegister) + } + mockSelect(HttpMethodRouteSelector(HttpMethod.Get)) { + captureBlock(getRegister) + } + } + } + + route.register(dao, hash) + } + + @Test + fun testPostRegisterOk() { + val data = Register(userId = "abcdef", password = "abcdefghi") + postRegister.invokeBlock(locations, data) { handle -> + mockSessionReturningNothing() + mockHostReferrerHash(hash) + mockPutSession() + + every { dao.user("abcdef") } returns null + + every { dao.createUser(any()) } just Runs + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(assert { + it?.user?.userId == "abcdef" + }) + } + + } + } + + @Test + fun testPostRegisterLoggedIn() { + val data = Register() + postRegister.invokeBlock(locations, data) { handle -> + mockSessionReturningUser(dao) + + every { request.headers[HttpHeaders.Host] } returns "host" + + every { + application + .attributes + .hint(Attributes::class) + .get(ApplicationFeature.registry) + .hint(Locations::class) + .get(Locations.key) + .href(any()) + } returns "/redirect" + + every { + response.headers.append(any(), any()) + } just Runs + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + response.headers.append(HttpHeaders.Location, "http://host/redirect") + respond(HttpStatusCode.Found) + } + } + } + + + @Test + fun testPostRegisterPasswordSize() { + checkRegisterError( + Register(userId = "abcdefghi", password = "abcd"), + "Password should be at least 6 characters long") + } + + @Test + fun testPostRegisterLoginSize() { + checkRegisterError( + Register(userId = "abc", password = "abcdefghi"), + "Login should be at least 4 characters long") + } + + @Test + fun testPostRegisterLoginConsistsOfDigitsLetters() { + checkRegisterError( + Register(userId = "#@!$!#$", password = "abcdefghi"), + "Login should be consists of digits, letters, dots or underscores") + } + + private fun checkRegisterError(data: Register, msg: String) { + postRegister.invokeBlock(locations, data) { handle -> + mockSessionReturningNothing() + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(LoginResponse(error = msg)) + } + } + } + + @Test + fun testPostRegisterSameUserRegistered() { + val data = Register(userId = "abcdef", password = "abcdefghi") + postRegister.invokeBlock(locations, data) { handle -> + mockSessionReturningNothing() + mockHostReferrerHash(hash) + + val user = User("abcdef", "abc@def", "Abc Def", "") + every { dao.user("abcdef") } returnsMany listOf(null, user) + + every { dao.createUser(any()) } throws RuntimeException("failed to create user") + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(LoginResponse(error = "User with the following login is already registered")) + } + + } + } + + @Test + fun testPostRegisterSameEmailUserRegistered() { + val data = Register(userId = "abcdef", password = "abcdefghi", email = "user@email") + postRegister.invokeBlock(locations, data) { handle -> + mockSessionReturningNothing() + mockHostReferrerHash(hash) + + every { dao.user(any()) } returns null + + every { dao.createUser(any()) } throws RuntimeException("failed to create user") + + every { dao.userByEmail("user@email") } returns mockk() + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(LoginResponse(error = "User with the following email user@email is already registered")) + } + } + } + + @Test + fun testPostRegisterFailed() { + val data = Register(userId = "abcdef", password = "abcdefghi", email = "user@email") + postRegister.invokeBlock(locations, data) { handle -> + mockSessionReturningNothing() + mockHostReferrerHash(hash) + + every { dao.user(any()) } returns null + + every { dao.createUser(any()) } throws RuntimeException("failed to create user") + + every { dao.userByEmail("user@email") } returns null + + every { route.application.environment.log.error(any()) } just Runs + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(LoginResponse(error = "Failed to register")) + } + } + } + + @Test + fun testPostRegisterUserExists() { + val data = Register(userId = "abcdef", password = "abcdefghi") + postRegister.invokeBlock(locations, data) { handle -> + mockSessionReturningNothing() + mockUser(dao) + + coEvery { respond(any()) } just Runs + + handle() + + coVerify { + respond(LoginResponse(error = "User with the following login is already registered")) + } + + } + } + + @Test + fun testGetRegisterNotAllowed() { + getRegister.invokeBlock(locations, Register()) { handle -> + coEvery { respond(any()) } just Runs + + handle() + + coVerify { respond(HttpStatusCode.MethodNotAllowed) } + } + } +} \ No newline at end of file diff --git a/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt b/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt similarity index 81% rename from backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt rename to backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt index d48292b..6509ae2 100644 --- a/backend/test/org/jetbrains/demo/thinkter/KtorTestKit.kt +++ b/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt @@ -11,8 +11,6 @@ import org.jetbrains.ktor.routing.Route import org.jetbrains.ktor.routing.RouteSelector import org.jetbrains.ktor.routing.Routing import org.jetbrains.ktor.routing.application -import org.jetbrains.ktor.sessions.SessionConfig -import org.jetbrains.ktor.util.AttributeKey import org.jetbrains.ktor.util.Attributes import kotlin.reflect.KClass @@ -48,27 +46,32 @@ class RouteDslMock(val route: Route, val locations: Locations) { fun RouteDslMock.mockSelect(selector: RouteSelector, block: RouteDslMock.() -> Unit) { val nextRoute = mockk() - every { this@mockSelect.route.select(selector) } returns nextRoute - every { nextRoute.parent } returns this@mockSelect.route + every { route.select(selector) } returns nextRoute + every { nextRoute.parent } returns route RouteDslMock(nextRoute, locations).block() } fun RouteDslMock.captureBlock(slot: RouteBlockSlot) { - every { this@captureBlock.route.handle(capture(slot)) } just Runs + every { route.handle(capture(slot)) } just Runs } } +typealias CallInvoker = () -> Unit + fun RouteBlockSlot.invokeBlock(locations: Locations, data: Any, - block: ApplicationCall.(() -> Unit) -> Unit) { + block: ApplicationCall.(CallInvoker) -> Unit) { runBlocking { val ctx = mockk>() + val call = mockk() + every { - locations.hint(data.javaClass.kotlin) - .resolve(data.javaClass.kotlin, call) + val dataCls = data.javaClass.kotlin + locations.hint(dataCls) + .resolve(dataCls, call) } returns data every { @@ -76,11 +79,11 @@ fun RouteBlockSlot.invokeBlock(locations: Locations, .subject } returns call - call.block({ + call.block { runBlocking { captured!!.invoke(ctx, call) } - }) + } } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 74bb778..3f4ba8a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ +#Fri Nov 03 23:52:00 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-all.zip + From bd4b5828a1be7e4c69fb3c4c73ed8fac5d04448e Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Sun, 5 Nov 2017 10:46:30 +0100 Subject: [PATCH 18/32] Using non-Nullable, getting rid of assertk --- backend/build.gradle | 1 - .../demo/thinkter/ApplicationPageTest.kt | 19 +++-------- .../org/jetbrains/demo/thinkter/Common.kt | 4 +-- .../jetbrains/demo/thinkter/DeleteKtTest.kt | 2 +- .../jetbrains/demo/thinkter/IndexKtTest.kt | 32 +++++++------------ .../demo/thinkter/PostThoughtKtTest.kt | 5 +-- .../jetbrains/demo/thinkter/RegisterKtTest.kt | 2 +- .../jetbrains/demo/thinkter/RouteMockDsl.kt | 2 +- .../jetbrains/demo/thinkter/UserPageKtTest.kt | 2 +- .../demo/thinkter/ViewThoughtKtTest.kt | 4 +-- 10 files changed, 28 insertions(+), 45 deletions(-) diff --git a/backend/build.gradle b/backend/build.gradle index d45ac1b..ebbd94b 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -25,7 +25,6 @@ dependencies { testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" testCompile "io.mockk:mockk:1.3-SNAPSHOT" - testCompile 'com.willowtreeapps.assertk:assertk:0.9' compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt b/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt index b9ca0b4..cf34762 100644 --- a/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt @@ -1,19 +1,14 @@ package org.jetbrains.demo.thinkter -import assertk.assertions.contains import io.mockk.Runs import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk import kotlinx.coroutines.experimental.runBlocking -import kotlinx.html.html -import kotlinx.html.stream.appendHTML import org.jetbrains.ktor.application.ApplicationCall import org.jetbrains.ktor.cio.ByteBufferWriteChannel -import org.jetbrains.ktor.cio.toOutputStream import org.jetbrains.ktor.html.HtmlContent import org.jetbrains.ktor.html.respondHtmlTemplate -import org.junit.Assert.* import org.junit.Test import java.nio.charset.Charset @@ -30,18 +25,14 @@ class ApplicationPageTest { } } - val channel = ByteBufferWriteChannel() coVerify { - appCall.respond(coAny { - it!!.writeTo(channel) + appCall.respond(coAssert { + val channel = ByteBufferWriteChannel() + it.writeTo(channel) + val html = channel.toString(Charset.defaultCharset()) + html.contains("caption") && html.contains("yui.yahooapis.com") }) } - val generatedPage = channel.toString(Charset.defaultCharset()) - - assertk.assert(generatedPage) - .contains("caption") - assertk.assert(generatedPage) - .contains("yui.yahooapis.com") } } \ No newline at end of file diff --git a/backend/test/org/jetbrains/demo/thinkter/Common.kt b/backend/test/org/jetbrains/demo/thinkter/Common.kt index b48cdda..8ac9fd5 100644 --- a/backend/test/org/jetbrains/demo/thinkter/Common.kt +++ b/backend/test/org/jetbrains/demo/thinkter/Common.kt @@ -15,10 +15,10 @@ import java.time.ZoneId import java.time.format.DateTimeFormatter fun MockKMatcherScope.sessionMatcher(): AttributeKey = - match({ it!!.name == "Session" }) + match({ it.name == "Session" }) fun MockKMatcherScope.sessionConfigMatcher(): AttributeKey> = - match({ it!!.name == "SessionConfig" }) + match({ it.name == "SessionConfig" }) fun ApplicationCall.mockSessionReturningUser(dao: ThinkterStorage) { diff --git a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt index 5ae4154..70576b4 100644 --- a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt @@ -53,7 +53,7 @@ class DeleteKtTest { coVerify { respond(assert { - it!!.user == "userId" && + it.user == "userId" && it.code.contains("cba:tsoh:dIresu") }) } diff --git a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt index d7e6f65..043f65a 100644 --- a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt @@ -1,13 +1,10 @@ package org.jetbrains.demo.thinkter -import assertk.assertions.contains import io.mockk.* import io.mockk.junit.MockKJUnit4Runner -import kotlinx.coroutines.experimental.runBlocking import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.IndexResponse import org.jetbrains.demo.thinkter.model.PollResponse -import org.jetbrains.demo.thinkter.model.Thought import org.jetbrains.ktor.cio.ByteBufferWriteChannel import org.jetbrains.ktor.html.HtmlContent import org.jetbrains.ktor.http.HttpHeaders @@ -20,8 +17,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import java.nio.charset.Charset -import java.time.* -import java.time.format.DateTimeFormatter @RunWith(MockKJUnit4Runner::class) class IndexKtTest { @@ -64,21 +59,18 @@ class IndexKtTest { @Test fun testGetIndexHtml() { getHtmlIndex.invokeBlock(locations, Index()) { handle -> - val html = slot() - coEvery { respond(any()) } answers { - runBlocking { - val htmlContent = firstArg() - val channel = ByteBufferWriteChannel() - htmlContent.writeTo(channel) - html.captured = channel.toString(Charset.defaultCharset()) - } - nothing - } + coEvery { respond(any()) } just Runs handle() - assertk.assert(html.captured!!) - .contains("Thinkter") + coVerify { + respond(coAssert { + val channel = ByteBufferWriteChannel() + it.writeTo(channel) + val html = channel.toString(Charset.defaultCharset()) + html.contains("Thinkter") + }) + } } } @@ -102,7 +94,7 @@ class IndexKtTest { respond(assert(msg = "response should have top and latest with ids from one to ten") { val oneToTen = (1..10).toList() - it!!.top.map { it.id }.containsAll(oneToTen) + it.top.map { it.id }.containsAll(oneToTen) && it.latest.map { it.id }.containsAll(oneToTen) }) } @@ -117,7 +109,7 @@ class IndexKtTest { handle() coVerify { - respond(assert { it!!.count == "0" }) + respond(assert { it.count == "0" }) } } } @@ -148,7 +140,7 @@ class IndexKtTest { handle() coVerify { - respond(assert { it!!.count == responseCount }) + respond(assert { it.count == responseCount }) } } } diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt index 0f5d3ec..2b4fcdf 100644 --- a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -5,6 +5,7 @@ import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.PostThoughtResult import org.jetbrains.demo.thinkter.model.PostThoughtToken +import org.jetbrains.demo.thinkter.model.Thought import org.jetbrains.ktor.http.HttpMethod import org.jetbrains.ktor.locations.Locations import org.jetbrains.ktor.routing.HttpMethodRouteSelector @@ -52,7 +53,7 @@ class PostThoughtKtTest { coVerify { respond(assert { - it!!.user == "userId" && + it.user == "userId" && it.code.contains("cba:tsoh:dIresu") }) } @@ -86,7 +87,7 @@ class PostThoughtKtTest { coVerify { respond(assert { - it!!.thought.id == 1 && + it.thought.id == 1 && it.thought.text == "text" }) } diff --git a/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt index 8111114..f370b7f 100644 --- a/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt @@ -62,7 +62,7 @@ class RegisterKtTest { coVerify { respond(assert { - it?.user?.userId == "abcdef" + it.user?.userId == "abcdef" }) } diff --git a/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt b/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt index 6509ae2..3080efe 100644 --- a/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt +++ b/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt @@ -81,7 +81,7 @@ fun RouteBlockSlot.invokeBlock(locations: Locations, call.block { runBlocking { - captured!!.invoke(ctx, call) + captured.invoke(ctx, call) } } } diff --git a/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt index a9eda32..22bbee2 100644 --- a/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt @@ -52,7 +52,7 @@ class UserPageKtTest { coVerify { respond(assert { - it!!.thoughts.any { it.id == 2 && it.text == "text" } + it.thoughts.any { it.id == 2 && it.text == "text" } }) } } diff --git a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt index 65edfdb..8ea551d 100644 --- a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt @@ -54,7 +54,7 @@ class ViewThoughtKtTest { coVerify { respond(assert { - it!!.thought.userId == "userId" && + it.thought.userId == "userId" && it.code!!.contains("cba:tsoh:dIresu") }) } @@ -73,7 +73,7 @@ class ViewThoughtKtTest { coVerify { respond(assert { - it!!.thought.id == 1 && + it.thought.id == 1 && it.code == null }) } From c901dbb427cc406c861bad125a9568c5d501d9ee Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Sun, 5 Nov 2017 17:59:56 +0100 Subject: [PATCH 19/32] Logging config for tests --- backend/testResources/logback-test.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 backend/testResources/logback-test.xml diff --git a/backend/testResources/logback-test.xml b/backend/testResources/logback-test.xml new file mode 100644 index 0000000..d2ff316 --- /dev/null +++ b/backend/testResources/logback-test.xml @@ -0,0 +1,18 @@ + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + \ No newline at end of file From 90ac181495ed32254b6d57451bdc08d5b5ea129f Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Sun, 5 Nov 2017 22:11:23 +0100 Subject: [PATCH 20/32] Logging config for tests --- backend/testResources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/testResources/logback-test.xml b/backend/testResources/logback-test.xml index d2ff316..ab4454b 100644 --- a/backend/testResources/logback-test.xml +++ b/backend/testResources/logback-test.xml @@ -11,7 +11,7 @@ - + From ad5a990d68dfd4bb69ba59af562873c3fee6ae74 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Sun, 5 Nov 2017 22:38:21 +0100 Subject: [PATCH 21/32] Release version of MockK --- backend/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/build.gradle b/backend/build.gradle index ebbd94b..9ceb497 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -24,7 +24,7 @@ dependencies { testCompile("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" - testCompile "io.mockk:mockk:1.3-SNAPSHOT" + testCompile "io.mockk:mockk:1.3" compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' From 38e88d156cea55dc9340e36ec9623bd5468d1bfa Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Mon, 6 Nov 2017 03:45:23 +0100 Subject: [PATCH 22/32] Adding ThinkerDatabaseTest --- .../demo/thinkter/dao/ThinkterDatabaseTest.kt | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt diff --git a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt new file mode 100644 index 0000000..f0fbe3d --- /dev/null +++ b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt @@ -0,0 +1,88 @@ +package org.jetbrains.demo.thinkter.dao + +import io.mockk.Runs +import io.mockk.every +import io.mockk.junit.MockKJUnit4Runner +import io.mockk.mockk +import io.mockk.verify +import org.jetbrains.demo.thinkter.model.Thought +import org.jetbrains.squash.connection.DatabaseConnection +import org.jetbrains.squash.dialect.BaseSQLDialect +import org.jetbrains.squash.results.Response +import org.jetbrains.squash.results.ResultRow +import org.jetbrains.squash.results.get +import org.jetbrains.squash.statements.InsertQueryStatement +import org.jetbrains.squash.statements.InsertValuesStatement +import org.jetbrains.squash.statements.QueryStatement +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(MockKJUnit4Runner::class) +class ThinkterDatabaseTest { + val connection = mockk("db") + fun tx() = connection.createTransaction() + + init { + every { tx().databaseSchema().create(any()) } just Runs + every { tx().close() } just Runs + } + + val database = ThinkterDatabase(connection) + + @Test + fun countReplies() { + val response = mockk() + val row = mockk() + every { + with(tx()) { + any().hint(Response::class).execute() + } + } returns response + + every { + response.iterator().hasNext() + } returnsMany listOf(true, false) + + every { + response.iterator().hint(ResultRow::class).next() + } returnsMany listOf(row, null) + + every { + row.hint(Int::class).get(0) + } returns 3 + + val nReplies = database.countReplies(1) + assertEquals(3, nReplies) + + verify { + with(connection.createTransaction()) { + assert { + "SELECT COUNT(Thoughts.id), Thoughts.reply_to = ? FROM Thoughts" == + BaseSQLDialect("dialect").statementSQL(it).sql + }.hint(Response::class).execute() + } + } + } + + @Test + fun createThought() { + every { + with(tx()) { + any>().hint(Int::class).execute() + } + } returns 1 + + database.createThought("userId", "text") + + verify { + with(connection.createTransaction()) { + assert> { + println(BaseSQLDialect("dialect").statementSQL(it).sql) + "INSERT INTO Thoughts (user_id, \"date\", reply_to, text) VALUES (?, ?, NULL, ?)" == + BaseSQLDialect("dialect").statementSQL(it).sql + }.hint(Int::class).execute() + } + } + } +} From b09f9dec38719d9fd4b91dac4f676e614d416ebc Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Mon, 6 Nov 2017 07:49:18 +0100 Subject: [PATCH 23/32] Adding tests to ThinkerDatabaseTest --- .../demo/thinkter/dao/ThinkterDatabaseTest.kt | 196 ++++++++++++++++-- 1 file changed, 182 insertions(+), 14 deletions(-) diff --git a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt index f0fbe3d..061010e 100644 --- a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt @@ -5,16 +5,17 @@ import io.mockk.every import io.mockk.junit.MockKJUnit4Runner import io.mockk.mockk import io.mockk.verify -import org.jetbrains.demo.thinkter.model.Thought +import org.jetbrains.demo.thinkter.model.User import org.jetbrains.squash.connection.DatabaseConnection import org.jetbrains.squash.dialect.BaseSQLDialect import org.jetbrains.squash.results.Response import org.jetbrains.squash.results.ResultRow import org.jetbrains.squash.results.get -import org.jetbrains.squash.statements.InsertQueryStatement +import org.jetbrains.squash.statements.DeleteQueryStatement import org.jetbrains.squash.statements.InsertValuesStatement import org.jetbrains.squash.statements.QueryStatement -import org.junit.Assert.* +import org.junit.Assert +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith @@ -40,23 +41,17 @@ class ThinkterDatabaseTest { } } returns response - every { - response.iterator().hasNext() - } returnsMany listOf(true, false) - - every { - response.iterator().hint(ResultRow::class).next() - } returnsMany listOf(row, null) + mockSingleRowResponse(response, row) every { row.hint(Int::class).get(0) } returns 3 val nReplies = database.countReplies(1) - assertEquals(3, nReplies) + Assert.assertEquals(3, nReplies) verify { - with(connection.createTransaction()) { + with(tx()) { assert { "SELECT COUNT(Thoughts.id), Thoughts.reply_to = ? FROM Thoughts" == BaseSQLDialect("dialect").statementSQL(it).sql @@ -76,13 +71,186 @@ class ThinkterDatabaseTest { database.createThought("userId", "text") verify { - with(connection.createTransaction()) { + with(tx()) { assert> { - println(BaseSQLDialect("dialect").statementSQL(it).sql) "INSERT INTO Thoughts (user_id, \"date\", reply_to, text) VALUES (?, ?, NULL, ?)" == BaseSQLDialect("dialect").statementSQL(it).sql }.hint(Int::class).execute() } } } + + @Test + fun deleteThought() { + every { + with(tx()) { + any>().hint(Int::class).execute() + } + } just Runs + + database.deleteThought(1) + + verify { + with(tx()) { + assert> { + "DELETE FROM Thoughts WHERE Thoughts.id = ?" == + BaseSQLDialect("dialect").statementSQL(it).sql + }.hint(Response::class).execute() + } + } + } + + @Test + @Ignore("requires mockk 1.4-SNAPSHOT") + fun getThought() { + val response = mockk() + val row = mockk() + every { + with(tx()) { + any().hint(Response::class).execute() + } + } returns response + + mockSingleRowResponse(response, row) + + + every { row.hint(String::class)[Thoughts.user] } returns "user" + every { row.hint(String::class)[Thoughts.text] } returns "text" + +// val localDateTimeRegistration = registerInstanceFactory(LocalDateTime::class, { LocalDateTime.now() }) +// +// localDateTimeRegistration.use { +// every { +// row.hint(LocalDateTime::class)[Thoughts.date] +// } returns LocalDateTime.now() +// } + + every { row.hint(Int::class)[Thoughts.replyTo] } returns null + + database.getThought(1) + + verify { + with(tx()) { + assert { + "SELECT * FROM Thoughts WHERE Thoughts.id = ?" == + BaseSQLDialect("dialect").statementSQL(it).sql + }.hint(Response::class).execute() + } + } + } + + @Test + fun userThoughts() { + val response = mockk() + val row = mockk() + every { + with(tx()) { + any().hint(Response::class).execute() + } + } returns response + + mockSingleRowResponse(response, row) + + every { row.hint(Int::class)[Thoughts.id] } returns 1 + + database.userThoughts("id") + + verify { + with(tx()) { + assert { + "SELECT Thoughts.id FROM Thoughts WHERE Thoughts.user_id = ? ORDER BY Thoughts.\"date\" DESC NULLS LAST LIMIT ?" == + BaseSQLDialect("dialect").statementSQL(it).sql + }.hint(Response::class).execute() + } + } + } + + @Test + fun user() { + val response = mockk() + val row = mockk() + every { + with(tx()) { + any().hint(Response::class).execute() + } + } returns response + + mockSingleRowResponse(response, row) + + + every { row.hint(String::class)[Users.email] } returns "email" + every { row.hint(String::class)[Users.displayName] } returns "user" + every { row.hint(String::class)[Users.passwordHash] } returns "hash" + + database.user("user", "hash") + + verify { + with(tx()) { + assert { + "SELECT * FROM Users WHERE Users.id = ?" == + BaseSQLDialect("dialect").statementSQL(it).sql + }.hint(Response::class).execute() + } + } + } + + @Test + fun userByEmail() { + val response = mockk() + val row = mockk() + every { + with(tx()) { + any().hint(Response::class).execute() + } + } returns response + + mockSingleRowResponse(response, row) + + + every { row.hint(String::class)[Users.id] } returns "user" + every { row.hint(String::class)[Users.email] } returns "email" + every { row.hint(String::class)[Users.displayName] } returns "user" + every { row.hint(String::class)[Users.passwordHash] } returns "hash" + + database.userByEmail("email") + + verify { + with(tx()) { + assert { + "SELECT * FROM Users WHERE Users.email = ?" == + BaseSQLDialect("dialect").statementSQL(it).sql + }.hint(Response::class).execute() + } + } + } + + @Test + fun createUser() { + every { + with(tx()) { + any>().hint(Int::class).execute() + } + } returns 1 + + database.createUser(User("id", "email", "name", "pwd")) + + verify { + with(tx()) { + assert> { + "INSERT INTO Users (id, display_name, email, password_hash) VALUES (?, ?, ?, ?)" == + BaseSQLDialect("dialect").statementSQL(it).sql + }.hint(Int::class).execute() + } + } + } + + private fun mockSingleRowResponse(response: Response, row: ResultRow) { + every { + response.iterator().hasNext() + } returnsMany listOf(true, false) + + every { + response.iterator().hint(ResultRow::class).next() + } returnsMany listOf(row, null) + } } From a69a90dde4ebbc5379dcfcb8c8c5f42b4a89f156 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Mon, 6 Nov 2017 20:24:18 +0100 Subject: [PATCH 24/32] Adding tests to ThinkerDatabaseTest --- .../demo/thinkter/dao/ThinkterDatabaseTest.kt | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt index 061010e..e691aa4 100644 --- a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt @@ -8,6 +8,8 @@ import io.mockk.verify import org.jetbrains.demo.thinkter.model.User import org.jetbrains.squash.connection.DatabaseConnection import org.jetbrains.squash.dialect.BaseSQLDialect +import org.jetbrains.squash.expressions.alias +import org.jetbrains.squash.expressions.invoke import org.jetbrains.squash.results.Response import org.jetbrains.squash.results.ResultRow import org.jetbrains.squash.results.get @@ -244,6 +246,60 @@ class ThinkterDatabaseTest { } } + @Test + fun top() { + val response = mockk() + val row = mockk() + every { + with(tx()) { + any().hint(Response::class).execute() + } + } returns response + + mockSingleRowResponse(response, row) + + val k2 = Thoughts.alias("k2") + every { row.hint(Int::class)[Thoughts.id(k2)] } returns 1 + + database.top() + + verify { + with(tx()) { + assert { + "SELECT Thoughts.id, COUNT(k2.id) FROM Thoughts LEFT OUTER JOIN Thoughts AS k2 ON Thoughts.id = k2.reply_to GROUP BY Thoughts.id ORDER BY COUNT(k2.id) DESC NULLS LAST LIMIT ?" == + BaseSQLDialect("dialect").statementSQL(it).sql + }.hint(Response::class).execute() + } + } + } + + @Test + fun latest() { + val response = mockk() + val row = mockk() + every { + with(tx()) { + any().hint(Response::class).execute() + } + } returns response + + mockSingleRowResponse(response, row) + + every { row.hint(Int::class)[Thoughts.id] } returns 1 + + database.latest(1) + + verify { + with(tx()) { + assert { + "SELECT Thoughts.id FROM Thoughts WHERE Thoughts.\"date\" > ? ORDER BY Thoughts.\"date\" DESC NULLS LAST LIMIT ?" == + BaseSQLDialect("dialect").statementSQL(it).sql + }.hint(Response::class).execute() + } + } + } + + private fun mockSingleRowResponse(response: Response, row: ResultRow) { every { response.iterator().hasNext() From ccd8402f577fe85c741d463ed6b896833a6503f4 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Mon, 6 Nov 2017 20:31:20 +0100 Subject: [PATCH 25/32] Revert: gradle-wrapper.properties --- gradle/wrapper/gradle-wrapper.properties | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3f4ba8a..74bb778 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,5 @@ -#Fri Nov 03 23:52:00 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-all.zip - +distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-bin.zip From ff25f46301a98119f375cc0ede1055db9b58419b Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Thu, 9 Nov 2017 23:44:55 +0100 Subject: [PATCH 26/32] Upgrade to version 1.4 --- backend/build.gradle | 5 +++-- .../demo/thinkter/dao/ThinkterDatabaseTest.kt | 17 +++++------------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/backend/build.gradle b/backend/build.gradle index 9ceb497..6782ed2 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -10,7 +10,7 @@ apply plugin: 'kotlin' apply plugin: 'application' dependencies { - agent "io.mockk:mockk-agent:1.3-SNAPSHOT" + agent "io.mockk:mockk-agent:1.4" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" @@ -24,7 +24,8 @@ dependencies { testCompile("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" - testCompile "io.mockk:mockk:1.3" + + testCompile "io.mockk:mockk:1.4" compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt index e691aa4..5f4f0ef 100644 --- a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt @@ -1,10 +1,7 @@ package org.jetbrains.demo.thinkter.dao -import io.mockk.Runs -import io.mockk.every +import io.mockk.* import io.mockk.junit.MockKJUnit4Runner -import io.mockk.mockk -import io.mockk.verify import org.jetbrains.demo.thinkter.model.User import org.jetbrains.squash.connection.DatabaseConnection import org.jetbrains.squash.dialect.BaseSQLDialect @@ -20,6 +17,7 @@ import org.junit.Assert import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith +import java.time.LocalDateTime @RunWith(MockKJUnit4Runner::class) class ThinkterDatabaseTest { @@ -103,7 +101,6 @@ class ThinkterDatabaseTest { } @Test - @Ignore("requires mockk 1.4-SNAPSHOT") fun getThought() { val response = mockk() val row = mockk() @@ -119,13 +116,9 @@ class ThinkterDatabaseTest { every { row.hint(String::class)[Thoughts.user] } returns "user" every { row.hint(String::class)[Thoughts.text] } returns "text" -// val localDateTimeRegistration = registerInstanceFactory(LocalDateTime::class, { LocalDateTime.now() }) -// -// localDateTimeRegistration.use { -// every { -// row.hint(LocalDateTime::class)[Thoughts.date] -// } returns LocalDateTime.now() -// } + every { + row.hint(LocalDateTime::class)[Thoughts.date] + } returns LocalDateTime.now() every { row.hint(Int::class)[Thoughts.replyTo] } returns null From 8e092526e667bda87923d58f1f6582d6de724e3c Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Thu, 16 Nov 2017 07:46:37 +0100 Subject: [PATCH 27/32] Upgrade to version 1.5 --- .idea/runConfigurations/Backend____Jetty.xml | 19 ------------------- backend/build.gradle | 4 +--- .../jetbrains/demo/thinkter/DeleteKtTest.kt | 1 - .../jetbrains/demo/thinkter/IndexKtTest.kt | 1 - .../jetbrains/demo/thinkter/LoginKtTest.kt | 1 - .../demo/thinkter/PostThoughtKtTest.kt | 1 - .../jetbrains/demo/thinkter/RegisterKtTest.kt | 1 - .../jetbrains/demo/thinkter/UserPageKtTest.kt | 1 - .../demo/thinkter/ViewThoughtKtTest.kt | 1 - .../demo/thinkter/dao/ThinkterDatabaseTest.kt | 1 - gradle/wrapper/gradle-wrapper.properties | 3 ++- 11 files changed, 3 insertions(+), 31 deletions(-) delete mode 100644 .idea/runConfigurations/Backend____Jetty.xml diff --git a/.idea/runConfigurations/Backend____Jetty.xml b/.idea/runConfigurations/Backend____Jetty.xml deleted file mode 100644 index 17fe544..0000000 --- a/.idea/runConfigurations/Backend____Jetty.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/backend/build.gradle b/backend/build.gradle index 6782ed2..48b0417 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -1,6 +1,5 @@ plugins { id "jacoco" - id "com.zoltu.application-agent" version "1.0.8" } group = 'org.jetbrains.demo.thinkter' @@ -10,7 +9,6 @@ apply plugin: 'kotlin' apply plugin: 'application' dependencies { - agent "io.mockk:mockk-agent:1.4" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" @@ -25,7 +23,7 @@ dependencies { testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" - testCompile "io.mockk:mockk:1.4" + testCompile "io.mockk:mockk:1.5" compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt index 70576b4..3cf2515 100644 --- a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt @@ -14,7 +14,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -@RunWith(MockKJUnit4Runner::class) class DeleteKtTest { val route = mockk() val dao = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt index 043f65a..a66de72 100644 --- a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt @@ -18,7 +18,6 @@ import org.junit.Test import org.junit.runner.RunWith import java.nio.charset.Charset -@RunWith(MockKJUnit4Runner::class) class IndexKtTest { val route = mockk() val dao = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 191e7c2..056a93b 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -16,7 +16,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -@RunWith(MockKJUnit4Runner::class) class LoginKtTest { val route = mockk() val dao = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt index 2b4fcdf..518ae2e 100644 --- a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -15,7 +15,6 @@ import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith -@RunWith(MockKJUnit4Runner::class) class PostThoughtKtTest { val route = mockk() val dao = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt index f370b7f..6218e8e 100644 --- a/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt @@ -18,7 +18,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -@RunWith(MockKJUnit4Runner::class) class RegisterKtTest { val route = mockk() val dao = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt index 22bbee2..9ed1b13 100644 --- a/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt @@ -15,7 +15,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -@RunWith(MockKJUnit4Runner::class) class UserPageKtTest { val route = mockk() val dao = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt index 8ea551d..6a76451 100644 --- a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt @@ -15,7 +15,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -@RunWith(MockKJUnit4Runner::class) class ViewThoughtKtTest { val route = mockk() val dao = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt index 5f4f0ef..bd0a61c 100644 --- a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt @@ -19,7 +19,6 @@ import org.junit.Test import org.junit.runner.RunWith import java.time.LocalDateTime -@RunWith(MockKJUnit4Runner::class) class ThinkterDatabaseTest { val connection = mockk("db") fun tx() = connection.createTransaction() diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 74bb778..5281128 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Wed Nov 08 07:41:52 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-all.zip From a25bd5bcdc36c23fa67fbd6b134606a060054f71 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Fri, 17 Nov 2017 09:12:11 +0100 Subject: [PATCH 28/32] Upgrade to version 1.5.1 Auto-hinting --- backend/build.gradle | 2 +- .../org/jetbrains/demo/thinkter/Common.kt | 4 +- .../jetbrains/demo/thinkter/LoginKtTest.kt | 6 +- .../jetbrains/demo/thinkter/RegisterKtTest.kt | 2 - .../jetbrains/demo/thinkter/RouteMockDsl.kt | 10 +-- .../demo/thinkter/dao/ThinkterDatabaseTest.kt | 76 +++++++++---------- 6 files changed, 44 insertions(+), 56 deletions(-) diff --git a/backend/build.gradle b/backend/build.gradle index 48b0417..6ead117 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -23,7 +23,7 @@ dependencies { testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" - testCompile "io.mockk:mockk:1.5" + testCompile "io.mockk:mockk:1.5.1-SNAPSHOT" compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/backend/test/org/jetbrains/demo/thinkter/Common.kt b/backend/test/org/jetbrains/demo/thinkter/Common.kt index 8ac9fd5..fd5110f 100644 --- a/backend/test/org/jetbrains/demo/thinkter/Common.kt +++ b/backend/test/org/jetbrains/demo/thinkter/Common.kt @@ -26,7 +26,6 @@ fun ApplicationCall.mockSessionReturningUser(dao: ThinkterStorage) { every { attributes - .hint(Session::class) .get(sessionMatcher()) } returns Session("userId") @@ -57,7 +56,7 @@ fun ApplicationCall.mockHostReferrerHash(hash: (String) -> String) { every { request.headers[HttpHeaders.Referrer] } returns "http://abc/referrer" - every { hash.hint(String::class).invoke(any()) } answers { firstArg().reversed() } + every { hash(any()) } answers { firstArg().reversed() } } @@ -88,7 +87,6 @@ fun mockUser(dao: ThinkterStorage, pwdHash: String? = null): User { fun ApplicationCall.mockPutSession() { every { attributes - .hint(SessionConfig::class) .get(sessionConfigMatcher()) .sessionType } returns Session::class diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 056a93b..90111cb 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -66,7 +66,6 @@ class LoginKtTest { every { attributes - .hint(Session::class) .get(sessionMatcher()) } returns Session("userId") @@ -100,7 +99,7 @@ class LoginKtTest { Login("abcdef", "ghiklm")) { handle -> - every { hash.hint(String::class).invoke("ghiklm") } returns "mlkihg" + every { hash.invoke("ghiklm") } returns "mlkihg" val user = mockUser(dao, "mlkihg") @@ -163,7 +162,7 @@ class LoginKtTest { postLogout.invokeBlock(locations, Logout()) { handle -> - every { hash.hint(String::class).invoke("ghiklm") } returns "mlkihg" + every { hash.invoke("ghiklm") } returns "mlkihg" every { dao.user("abcdef", "mlkihg") @@ -174,7 +173,6 @@ class LoginKtTest { every { attributes - .hint(SessionConfig::class) .getOrNull(sessionConfigMatcher()) } returns null diff --git a/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt index 6218e8e..5814221 100644 --- a/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt @@ -79,9 +79,7 @@ class RegisterKtTest { every { application .attributes - .hint(Attributes::class) .get(ApplicationFeature.registry) - .hint(Locations::class) .get(Locations.key) .href(any()) } returns "/redirect" diff --git a/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt b/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt index 3080efe..4f24d10 100644 --- a/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt +++ b/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt @@ -24,9 +24,7 @@ class RouteDslMock(val route: Route, val locations: Locations) { route .application .attributes - .hint(Attributes::class) .get(ApplicationFeature.registry) - .hint(Locations::class) .get(Locations.key) } returns locations } @@ -70,14 +68,10 @@ fun RouteBlockSlot.invokeBlock(locations: Locations, every { val dataCls = data.javaClass.kotlin - locations.hint(dataCls) - .resolve(dataCls, call) + locations.resolve(dataCls, call) } returns data - every { - ctx.hint(ApplicationCall::class) - .subject - } returns call + every { ctx.subject } returns call call.block { runBlocking { diff --git a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt index bd0a61c..2ca40c5 100644 --- a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt @@ -36,14 +36,14 @@ class ThinkterDatabaseTest { val row = mockk() every { with(tx()) { - any().hint(Response::class).execute() + any().execute() } } returns response mockSingleRowResponse(response, row) every { - row.hint(Int::class).get(0) + row.get(0) } returns 3 val nReplies = database.countReplies(1) @@ -54,7 +54,7 @@ class ThinkterDatabaseTest { assert { "SELECT COUNT(Thoughts.id), Thoughts.reply_to = ? FROM Thoughts" == BaseSQLDialect("dialect").statementSQL(it).sql - }.hint(Response::class).execute() + }.execute() } } } @@ -63,7 +63,7 @@ class ThinkterDatabaseTest { fun createThought() { every { with(tx()) { - any>().hint(Int::class).execute() + any>().execute() } } returns 1 @@ -74,7 +74,7 @@ class ThinkterDatabaseTest { assert> { "INSERT INTO Thoughts (user_id, \"date\", reply_to, text) VALUES (?, ?, NULL, ?)" == BaseSQLDialect("dialect").statementSQL(it).sql - }.hint(Int::class).execute() + }.execute() } } } @@ -83,7 +83,7 @@ class ThinkterDatabaseTest { fun deleteThought() { every { with(tx()) { - any>().hint(Int::class).execute() + any>().execute() } } just Runs @@ -94,7 +94,7 @@ class ThinkterDatabaseTest { assert> { "DELETE FROM Thoughts WHERE Thoughts.id = ?" == BaseSQLDialect("dialect").statementSQL(it).sql - }.hint(Response::class).execute() + }.execute() } } } @@ -105,21 +105,21 @@ class ThinkterDatabaseTest { val row = mockk() every { with(tx()) { - any().hint(Response::class).execute() + any().execute() } } returns response mockSingleRowResponse(response, row) - every { row.hint(String::class)[Thoughts.user] } returns "user" - every { row.hint(String::class)[Thoughts.text] } returns "text" + every { row[Thoughts.user] } returns "user" + every { row[Thoughts.text] } returns "text" every { - row.hint(LocalDateTime::class)[Thoughts.date] + row[Thoughts.date] } returns LocalDateTime.now() - every { row.hint(Int::class)[Thoughts.replyTo] } returns null + every { row[Thoughts.replyTo] } returns null database.getThought(1) @@ -128,7 +128,7 @@ class ThinkterDatabaseTest { assert { "SELECT * FROM Thoughts WHERE Thoughts.id = ?" == BaseSQLDialect("dialect").statementSQL(it).sql - }.hint(Response::class).execute() + }.execute() } } } @@ -139,13 +139,13 @@ class ThinkterDatabaseTest { val row = mockk() every { with(tx()) { - any().hint(Response::class).execute() + any().execute() } } returns response mockSingleRowResponse(response, row) - every { row.hint(Int::class)[Thoughts.id] } returns 1 + every { row[Thoughts.id] } returns 1 database.userThoughts("id") @@ -154,7 +154,7 @@ class ThinkterDatabaseTest { assert { "SELECT Thoughts.id FROM Thoughts WHERE Thoughts.user_id = ? ORDER BY Thoughts.\"date\" DESC NULLS LAST LIMIT ?" == BaseSQLDialect("dialect").statementSQL(it).sql - }.hint(Response::class).execute() + }.execute() } } } @@ -165,16 +165,16 @@ class ThinkterDatabaseTest { val row = mockk() every { with(tx()) { - any().hint(Response::class).execute() + any().execute() } } returns response mockSingleRowResponse(response, row) - every { row.hint(String::class)[Users.email] } returns "email" - every { row.hint(String::class)[Users.displayName] } returns "user" - every { row.hint(String::class)[Users.passwordHash] } returns "hash" + every { row[Users.email] } returns "email" + every { row[Users.displayName] } returns "user" + every { row[Users.passwordHash] } returns "hash" database.user("user", "hash") @@ -183,7 +183,7 @@ class ThinkterDatabaseTest { assert { "SELECT * FROM Users WHERE Users.id = ?" == BaseSQLDialect("dialect").statementSQL(it).sql - }.hint(Response::class).execute() + }.execute() } } } @@ -194,17 +194,17 @@ class ThinkterDatabaseTest { val row = mockk() every { with(tx()) { - any().hint(Response::class).execute() + any().execute() } } returns response mockSingleRowResponse(response, row) - every { row.hint(String::class)[Users.id] } returns "user" - every { row.hint(String::class)[Users.email] } returns "email" - every { row.hint(String::class)[Users.displayName] } returns "user" - every { row.hint(String::class)[Users.passwordHash] } returns "hash" + every { row[Users.id] } returns "user" + every { row[Users.email] } returns "email" + every { row[Users.displayName] } returns "user" + every { row[Users.passwordHash] } returns "hash" database.userByEmail("email") @@ -213,7 +213,7 @@ class ThinkterDatabaseTest { assert { "SELECT * FROM Users WHERE Users.email = ?" == BaseSQLDialect("dialect").statementSQL(it).sql - }.hint(Response::class).execute() + }.execute() } } } @@ -222,18 +222,18 @@ class ThinkterDatabaseTest { fun createUser() { every { with(tx()) { - any>().hint(Int::class).execute() + any>().execute() } - } returns 1 + } just Runs database.createUser(User("id", "email", "name", "pwd")) verify { with(tx()) { - assert> { + assert> { "INSERT INTO Users (id, display_name, email, password_hash) VALUES (?, ?, ?, ?)" == BaseSQLDialect("dialect").statementSQL(it).sql - }.hint(Int::class).execute() + }.execute() } } } @@ -244,14 +244,14 @@ class ThinkterDatabaseTest { val row = mockk() every { with(tx()) { - any().hint(Response::class).execute() + any().execute() } } returns response mockSingleRowResponse(response, row) val k2 = Thoughts.alias("k2") - every { row.hint(Int::class)[Thoughts.id(k2)] } returns 1 + every { row[Thoughts.id(k2)] } returns 1 database.top() @@ -260,7 +260,7 @@ class ThinkterDatabaseTest { assert { "SELECT Thoughts.id, COUNT(k2.id) FROM Thoughts LEFT OUTER JOIN Thoughts AS k2 ON Thoughts.id = k2.reply_to GROUP BY Thoughts.id ORDER BY COUNT(k2.id) DESC NULLS LAST LIMIT ?" == BaseSQLDialect("dialect").statementSQL(it).sql - }.hint(Response::class).execute() + }.execute() } } } @@ -271,13 +271,13 @@ class ThinkterDatabaseTest { val row = mockk() every { with(tx()) { - any().hint(Response::class).execute() + any().execute() } } returns response mockSingleRowResponse(response, row) - every { row.hint(Int::class)[Thoughts.id] } returns 1 + every { row[Thoughts.id] } returns 1 database.latest(1) @@ -286,7 +286,7 @@ class ThinkterDatabaseTest { assert { "SELECT Thoughts.id FROM Thoughts WHERE Thoughts.\"date\" > ? ORDER BY Thoughts.\"date\" DESC NULLS LAST LIMIT ?" == BaseSQLDialect("dialect").statementSQL(it).sql - }.hint(Response::class).execute() + }.execute() } } } @@ -298,7 +298,7 @@ class ThinkterDatabaseTest { } returnsMany listOf(true, false) every { - response.iterator().hint(ResultRow::class).next() + response.iterator().next() } returnsMany listOf(row, null) } } From fac616a98294ab96cfe7d0c119a1c89c53da503f Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Fri, 17 Nov 2017 09:16:11 +0100 Subject: [PATCH 29/32] Upgrade to version 1.5.1 --- backend/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/build.gradle b/backend/build.gradle index 6ead117..9b9fcf2 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -23,7 +23,7 @@ dependencies { testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" - testCompile "io.mockk:mockk:1.5.1-SNAPSHOT" + testCompile "io.mockk:mockk:1.5.1" compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' From 5688aa5f16acf55adeb4ca7998b6dd3d51afce80 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Fri, 17 Nov 2017 22:32:55 +0100 Subject: [PATCH 30/32] Upgrade to Version 1.5.2 --- backend/build.gradle | 2 +- backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt | 4 ++-- backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt | 4 ++-- .../org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/build.gradle b/backend/build.gradle index 9b9fcf2..ca91e2a 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -23,7 +23,7 @@ dependencies { testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" - testCompile "io.mockk:mockk:1.5.1" + testCompile "io.mockk:mockk:1.5.2" compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt index 9ed1b13..66ceda5 100644 --- a/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt @@ -62,11 +62,11 @@ class UserPageKtTest { getUserThoughts.invokeBlock(locations, UserThoughts("abcdef")) { handle -> every { dao.user("abcdef") } returns null - coEvery { respond(any()) } just Runs + coEvery { respond(any()) } just Runs handle() - coVerify { + coVerify { respond(HttpStatusCode.NotFound.description("User abcdef doesn't exist")) } } diff --git a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt index 6a76451..4fb4a40 100644 --- a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt @@ -66,11 +66,11 @@ class ViewThoughtKtTest { mockGetThought(dao, 0) mockSessionReturningNothing() - coEvery { respond(any()) } just Runs + coEvery { respond(any()) } just Runs handle() - coVerify { + coVerify { respond(assert { it.thought.id == 1 && it.code == null diff --git a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt index 2ca40c5..72fefe5 100644 --- a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt @@ -299,6 +299,6 @@ class ThinkterDatabaseTest { every { response.iterator().next() - } returnsMany listOf(row, null) + } returnsMany listOf(row) } } From d3a1ca9e3e2d005a2258c6f6cc43ee4dcd994d10 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Tue, 21 Nov 2017 06:46:22 +0100 Subject: [PATCH 31/32] Upgrade to Version 1.5.3 --- backend/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/build.gradle b/backend/build.gradle index ca91e2a..0e40925 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -23,7 +23,7 @@ dependencies { testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" - testCompile "io.mockk:mockk:1.5.2" + testCompile "io.mockk:mockk:1.5.3" compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' From 58afe2d3dc449bcde36caefe0125ded9ab5ed372 Mon Sep 17 00:00:00 2001 From: Oleksiy Pylypenko Date: Sun, 17 Feb 2019 14:24:36 +0100 Subject: [PATCH 32/32] Upgrade to 1.9.1 --- .idea/vcs.xml | 2 +- backend/build.gradle | 2 +- .../org/jetbrains/demo/thinkter/ApplicationPageTest.kt | 5 +---- backend/test/org/jetbrains/demo/thinkter/Common.kt | 4 ++-- backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt | 2 -- backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt | 2 -- backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt | 4 ---- .../test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt | 4 ---- backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt | 6 +----- backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt | 1 - backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt | 4 ---- .../test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt | 7 +------ .../jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt | 3 --- 13 files changed, 7 insertions(+), 39 deletions(-) diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/backend/build.gradle b/backend/build.gradle index 0e40925..d854fb4 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -23,7 +23,7 @@ dependencies { testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version" testCompile "org.jsoup:jsoup:1.9.1" - testCompile "io.mockk:mockk:1.5.3" + testCompile "io.mockk:mockk:1.9.1.kotlin12" compile "org.jetbrains.ktor:ktor-jetty:$ktor_version" compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt b/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt index cf34762..bfb7c40 100644 --- a/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/ApplicationPageTest.kt @@ -1,9 +1,6 @@ package org.jetbrains.demo.thinkter -import io.mockk.Runs -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.mockk +import io.mockk.* import kotlinx.coroutines.experimental.runBlocking import org.jetbrains.ktor.application.ApplicationCall import org.jetbrains.ktor.cio.ByteBufferWriteChannel diff --git a/backend/test/org/jetbrains/demo/thinkter/Common.kt b/backend/test/org/jetbrains/demo/thinkter/Common.kt index fd5110f..2b7130c 100644 --- a/backend/test/org/jetbrains/demo/thinkter/Common.kt +++ b/backend/test/org/jetbrains/demo/thinkter/Common.kt @@ -15,10 +15,10 @@ import java.time.ZoneId import java.time.format.DateTimeFormatter fun MockKMatcherScope.sessionMatcher(): AttributeKey = - match({ it.name == "Session" }) + match { it.name == "Session" } fun MockKMatcherScope.sessionConfigMatcher(): AttributeKey> = - match({ it.name == "SessionConfig" }) + match { it.name == "SessionConfig" } fun ApplicationCall.mockSessionReturningUser(dao: ThinkterStorage) { diff --git a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt index 3cf2515..d0197b5 100644 --- a/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/DeleteKtTest.kt @@ -1,7 +1,6 @@ package org.jetbrains.demo.thinkter import io.mockk.* -import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.PostThoughtToken import org.jetbrains.demo.thinkter.model.RpcData @@ -12,7 +11,6 @@ import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.Routing import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith class DeleteKtTest { val route = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt index a66de72..06b190d 100644 --- a/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/IndexKtTest.kt @@ -1,7 +1,6 @@ package org.jetbrains.demo.thinkter import io.mockk.* -import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.IndexResponse import org.jetbrains.demo.thinkter.model.PollResponse @@ -15,7 +14,6 @@ import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.Routing import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith import java.nio.charset.Charset class IndexKtTest { diff --git a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt index 90111cb..346d0e3 100644 --- a/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/LoginKtTest.kt @@ -1,20 +1,16 @@ package org.jetbrains.demo.thinkter import io.mockk.* -import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.LoginResponse import org.jetbrains.demo.thinkter.model.User -import org.jetbrains.ktor.application.ApplicationCall import org.jetbrains.ktor.http.HttpMethod import org.jetbrains.ktor.http.HttpStatusCode import org.jetbrains.ktor.locations.Locations import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.Routing -import org.jetbrains.ktor.sessions.SessionConfig import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith class LoginKtTest { val route = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt index 518ae2e..ff13962 100644 --- a/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/PostThoughtKtTest.kt @@ -1,19 +1,15 @@ package org.jetbrains.demo.thinkter import io.mockk.* -import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.PostThoughtResult import org.jetbrains.demo.thinkter.model.PostThoughtToken -import org.jetbrains.demo.thinkter.model.Thought import org.jetbrains.ktor.http.HttpMethod import org.jetbrains.ktor.locations.Locations import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.Routing import org.junit.Before -import org.junit.Ignore import org.junit.Test -import org.junit.runner.RunWith class PostThoughtKtTest { val route = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt index 5814221..28fabf2 100644 --- a/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/RegisterKtTest.kt @@ -1,7 +1,6 @@ package org.jetbrains.demo.thinkter import io.mockk.* -import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.LoginResponse import org.jetbrains.demo.thinkter.model.User @@ -12,11 +11,8 @@ import org.jetbrains.ktor.http.HttpStatusCode import org.jetbrains.ktor.locations.Locations import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.Routing -import org.jetbrains.ktor.routing.application -import org.jetbrains.ktor.util.Attributes import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith class RegisterKtTest { val route = mockk() @@ -196,7 +192,7 @@ class RegisterKtTest { every { route.application.environment.log.error(any()) } just Runs - coEvery { respond(any()) } just Runs + coEvery { respond(any()) } just Runs handle() diff --git a/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt b/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt index 4f24d10..f2f597b 100644 --- a/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt +++ b/backend/test/org/jetbrains/demo/thinkter/RouteMockDsl.kt @@ -11,7 +11,6 @@ import org.jetbrains.ktor.routing.Route import org.jetbrains.ktor.routing.RouteSelector import org.jetbrains.ktor.routing.Routing import org.jetbrains.ktor.routing.application -import org.jetbrains.ktor.util.Attributes import kotlin.reflect.KClass fun Route.mockDsl(locations: Locations, block: RouteDslMock.() -> Unit) = RouteDslMock(this, locations).block() diff --git a/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt index 66ceda5..c36b7f6 100644 --- a/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/UserPageKtTest.kt @@ -1,10 +1,7 @@ package org.jetbrains.demo.thinkter import io.mockk.* -import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.dao.ThinkterStorage -import org.jetbrains.demo.thinkter.model.PostThoughtToken -import org.jetbrains.demo.thinkter.model.Thought import org.jetbrains.demo.thinkter.model.UserThoughtsResponse import org.jetbrains.ktor.http.HttpMethod import org.jetbrains.ktor.http.HttpStatusCode @@ -13,7 +10,6 @@ import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.Routing import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith class UserPageKtTest { val route = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt index 4fb4a40..cefe093 100644 --- a/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/ViewThoughtKtTest.kt @@ -1,10 +1,6 @@ package org.jetbrains.demo.thinkter -import io.mockk.Runs -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.junit.MockKJUnit4Runner -import io.mockk.mockk +import io.mockk.* import org.jetbrains.demo.thinkter.dao.ThinkterStorage import org.jetbrains.demo.thinkter.model.ViewThoughtResponse import org.jetbrains.ktor.http.HttpMethod @@ -13,7 +9,6 @@ import org.jetbrains.ktor.routing.HttpMethodRouteSelector import org.jetbrains.ktor.routing.Routing import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith class ViewThoughtKtTest { val route = mockk() diff --git a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt index 72fefe5..7f7f89e 100644 --- a/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt +++ b/backend/test/org/jetbrains/demo/thinkter/dao/ThinkterDatabaseTest.kt @@ -1,7 +1,6 @@ package org.jetbrains.demo.thinkter.dao import io.mockk.* -import io.mockk.junit.MockKJUnit4Runner import org.jetbrains.demo.thinkter.model.User import org.jetbrains.squash.connection.DatabaseConnection import org.jetbrains.squash.dialect.BaseSQLDialect @@ -14,9 +13,7 @@ import org.jetbrains.squash.statements.DeleteQueryStatement import org.jetbrains.squash.statements.InsertValuesStatement import org.jetbrains.squash.statements.QueryStatement import org.junit.Assert -import org.junit.Ignore import org.junit.Test -import org.junit.runner.RunWith import java.time.LocalDateTime class ThinkterDatabaseTest {