New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test coverage for backend #28

Open
wants to merge 31 commits into
base: master
from
Commits
Jump to file or symbol
Failed to load files and symbols.
+1,498 −22
Diff settings

Always

Just for now

This file was deleted.

Oops, something went wrong.
Copy path View file
@@ -1,10 +1,15 @@
plugins {
id "jacoco"
}
group = 'org.jetbrains.demo.thinkter'
version = '0.0.1-SNAPSHOT'
apply plugin: 'kotlin'
apply plugin: 'application'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
@@ -18,6 +23,8 @@ dependencies {
testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version"
testCompile "org.jsoup:jsoup:1.9.1"
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'
}
@@ -42,3 +49,12 @@ kotlin {
}
mainClassName = 'org.jetbrains.ktor.jetty.DevelopmentHost'
jacocoTestReport {
reports {
xml.enabled true
html.enabled true
}
}
check.dependsOn jacocoTestReport
@@ -11,8 +11,6 @@ import org.jetbrains.ktor.util.*
fun Route.register(dao: ThinkterStorage, hashFunction: (String) -> String) {
post<Register> { form ->
val vm = call.request.content.get<ValuesMap>()
val user = call.sessionOrNull<Session>()?.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))
@@ -0,0 +1,38 @@
package org.jetbrains.demo.thinkter
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.mockk
import kotlinx.coroutines.experimental.runBlocking
import org.jetbrains.ktor.application.ApplicationCall
import org.jetbrains.ktor.cio.ByteBufferWriteChannel
import org.jetbrains.ktor.html.HtmlContent
import org.jetbrains.ktor.html.respondHtmlTemplate
import org.junit.Test
import java.nio.charset.Charset
class ApplicationPageTest {
val appCall = mockk<ApplicationCall>()
@Test
fun testRenderHTML() {
coEvery { appCall.respond(any()) } just Runs
runBlocking {
appCall.respondHtmlTemplate(ApplicationPage()) {
caption { +"caption" }
}
}
coVerify {
appCall.respond(coAssert<HtmlContent> {
val channel = ByteBufferWriteChannel()
it.writeTo(channel)
val html = channel.toString(Charset.defaultCharset())
html.contains("caption") && html.contains("yui.yahooapis.com")
})
}
}
}
@@ -0,0 +1,96 @@
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
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<Session> =
match({ it.name == "Session" })
fun MockKMatcherScope.sessionConfigMatcher(): AttributeKey<SessionConfig<*>> =
match({ it.name == "SessionConfig" })
fun ApplicationCall.mockSessionReturningUser(dao: ThinkterStorage) {
every { attributes.contains(sessionMatcher()) } returns true
every {
attributes
.get(sessionMatcher())
} returns Session("userId")
every { dao.user("userId") } returns User("userId",
"email",
"User",
"pwd")
}
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(any()) } answers { firstArg<String>().reversed() }
}
fun mockGetThought(dao: ThinkterStorage, ts: Long) {
every {
dao.getThought(any())
} answers { Thought(firstArg(),
"userId",
"text",
formatDate(ts + firstArg<Int>()),
null) }
}
private fun formatDate(date: Long): String {
return Instant.ofEpochMilli(date)
.atZone(ZoneId.systemDefault())
.toOffsetDateTime()
.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
}
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
}
fun ApplicationCall.mockPutSession() {
every {
attributes
.get(sessionConfigMatcher())
.sessionType
} returns Session::class
every { attributes.put(sessionMatcher(), any()) } just Runs
}
@@ -0,0 +1,106 @@
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
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
class DeleteKtTest {
val route = mockk<Routing>()
val dao = mockk<ThinkterStorage>()
val hash = mockk<(String) -> String>()
val locations = mockk<Locations>()
val getThoughtDelete = RouteBlockSlot()
val postThoughtDelete = RouteBlockSlot()
@Before
fun setUp() {
route.mockDsl(locations) {
mockObj<ThoughtDelete> {
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<PostThoughtToken> {
it.user == "userId" &&
it.code.contains("cba:tsoh:dIresu")
})
}
}
}
@Test
fun testGetThoughtDeleteNotLoggedIn() {
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)
mockGetThought(dao, ts)
every {
dao.deleteThought(1)
} just Runs
coEvery { respond(any()) } just Runs
handle()
coVerify {
respond(ofType(RpcData::class))
}
}
}
@Test
fun testPostThoughtDeleteNotLoggedIn() {
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)
}
}
}
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.