英文:
Ktor testing routes with 'authenticate(){}'
问题
以下是代码部分的翻译:
fun Application.install() {
    routing {
        route("point") {
            authenticate(AUTH_SESSION) {
                post("/test") { testController.test(context) }
            }
        }
    }
}
@Test
fun `test auth route`() = testApplication {
    val client = client()
    client.post("/point/test")
}
请注意,我已经删除了HTML编码字符(")并将其替换为普通引号。如果您需要其他内容的翻译,请提供相关文本。
英文:
What is the appropriate way of unit testing such routes?
fun Application.install() {
    routing {
        route("point") {
            authenticate(AUTH_SESSION) {
                post("/test") { testController.test(context) }
            }
        }
    }
}
The problem is such routes require auth info. This code results in 401 error:
@Test
fun `test auth route`() = testApplication {
    val client = client()
    client.post("/point/test")
}
I use GoogleOneTap auth for a mobile application. From GoogleOneTap jwt token I generate User session with a Bearer. That session expires after some time.
So, such a test user requires manual auth each time session expires? If so, it's not appropriate for a CI.
Should I implement a simple auth with user-password and call auth before each call under authenticate(AUTH_SESSION)?
答案1
得分: 0
这是你要翻译的内容的翻译部分:
Finally, I got it:
1) Read through ktor docs https://ktor.io/docs/testing.html
1) With any auth you have auth route: `post("/auth/myprovider")` which gives you bearer cookie
Your routing:
```kotlin
routing {
    // auth route to get a bearer cookie
    post("/auth/google") { googleAuthController.signIn(context) }
    authenticate(AUTH_SESSION) {
        // these routes need auth bearer cookie
        post("/my/route/requiring/auth")
    }
}
post("/my/route/requiring/auth") uses authentication, hence all testing requests have to have auth bearer cookie. To get it, create a separate test user with test credentials:
class GoogleAuthController(
    private val userDao: UserDao
) {
    suspend fun signIn(call: ApplicationCall) {
        val token = call.parameters["token"]!!
        val userInfo: UserInfo? = verifyTestUsers(token) ?: GoogleAuthVerifier.verify(token)
        if (userInfo != null) {
            // create user
            val userSession = UserSession(
                id = userInfo.id,
                email = userInfo.email,
                name = userInfo.name,
                pictureUrl = userInfo.pictureUrl,
                locale = userInfo.locale
            )
            // save user to db
            userDao.saveUserInfoGoogleOneTap(userSession)
            // set user cookie
            call.sessions.set(userSession)
            call.respond(HttpStatusCode.OK)
        } else {
            throw IllegalArgumentException("Invalid token")
        }
    }
    // testUsers: Map<String, UserInfo>;
    private fun verifyTestUsers(token: String): UserInfo? = testUsers[token]
}
Basically, this is how you can get a cookie for any of your test users.
Next, to make calls, you need a client:
suspend fun ApplicationTestBuilder.myAuthClient(token: String = testUserToken) = createClient {
    install(HttpCookies)
    install(ContentNegotiation) {
        json(Json {
            prettyPrint = true
            isLenient = true
            ignoreUnknownKeys = true
            encodeDefaults = true
        })
    }
}.also {
    it.post("/auth/google") {
        parameter("token", token)
    }
}
Here on each client creation you call your auth method and get credentials for a test user.
Now you are ready to make authenticated calls:
internal class TestAuth {
    @Test
    fun `test auth`() = testApplication {
        val client = myAuthClient() 
        // here `client` already has a Bearer cookie
        
        val response = client.post("/my/route/requiring/auth")
        assert(response.body<String>().isNotEmpty())
    }
}
希望这些翻译对你有所帮助。
英文:
Finally, I got it:
- Read through ktor docs https://ktor.io/docs/testing.html
 - With any auth you have auth route: 
post("/auth/myprovider")which gives you bearer cookie 
Your routing:
routing {
    // auth route to get a bearer cookie
    post("/auth/google") { googleAuthController.signIn(context) }
    authenticate(AUTH_SESSION) {
        // these routes need auth bearer cookie
        post("/my/route/requiring/auth")
    }
}
post("/my/route/requiring/auth") uses authentication, hence all testing requests have to have auth bearer cookie. To get it, create a separate test user with test credentials:
class GoogleAuthController(
    private val userDao: UserDao
) {
    suspend fun signIn(call: ApplicationCall) {
        val token = call.parameters["token"]!!
        val userInfo: UserInfo? = verifyTestUsers(token) ?: GoogleAuthVerifier.verify(token)
        if (userInfo != null) {
            // create user
            val userSession = UserSession(
                id = userInfo.id,
                email = userInfo.email,
                name = userInfo.name,
                pictureUrl = userInfo.pictureUrl,
                locale = userInfo.locale
            )
            // save user to db
            userDao.saveUserInfoGoogleOneTap(userSession)
            // set user cookie
            call.sessions.set(userSession)
            call.respond(HttpStatusCode.OK)
        } else {
            throw IllegalArgumentException("Invalid token")
        }
    }
    // testUsers: Map<String, UserInfo>
    private fun verifyTestUsers(token: String): UserInfo? = testUsers[token]
}
Basically, this is how you can get a cookie for any of your test users.
Next, to make calls, you need a client:
suspend fun ApplicationTestBuilder.myAuthClient(token: String = testUserToken) = createClient {
    install(HttpCookies)
    install(ContentNegotiation) {
        json(Json {
            prettyPrint = true
            isLenient = true
            ignoreUnknownKeys = true
            encodeDefaults = true
        })
    }
}.also {
    it.post("/auth/google") {
        parameter("token", token)
    }
}
Here on each client creation you call your auth method and get credentials for a test user.
Now you are ready to make authenticated calls:
internal class TestAuth {
    @Test
    fun `test auth`() = testApplication {
        val client = myAuthClient() 
        // here `client` already has a Bearer cookie
        
        val response = client.post("/my/route/requiring/auth")
        assert(response.body<String>().isNotEmpty())
    }
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论