From 1cf6dbf1551437266179395b515d8337b66244b2 Mon Sep 17 00:00:00 2001 From: mehedihasanpiash Date: Thu, 19 Sep 2024 00:18:34 +0600 Subject: [PATCH 1/5] - Added test for brand route --- build.gradle.kts | 3 + gradle/libs.versions.toml | 5 + src/test/kotlin/com/piashcse/ConfigureAuth.kt | 73 +++++++ .../com/piashcse/route/BrandRouteTest.kt | 196 ++++++++++++++++++ 4 files changed, 277 insertions(+) create mode 100644 src/test/kotlin/com/piashcse/ConfigureAuth.kt create mode 100644 src/test/kotlin/com/piashcse/route/BrandRouteTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 16a36d2..226ef9e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -55,6 +55,9 @@ dependencies { implementation(libs.ktor.swagger.ui) implementation(libs.swagger.parser) + testImplementation(libs.mockk) + testImplementation(libs.coroutine.test) + testImplementation(libs.ktor.client.mock) } tasks.create("stage") { dependsOn("installDist") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8419e6b..4cfe5c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,6 +14,8 @@ commons-io-version = "2.11.0" ktor-swagger-ui-version = "3.3.1" swagger-parser-version = "2.1.22" shadow-version = "8.1.1" +coroutine = "1.9.0" +mockk = "1.13.5" [libraries] ktor-server-core = { module = "io.ktor:ktor-server-core-jvm", version.ref = "ktor-version" } @@ -46,6 +48,9 @@ valiktor-core = { module = "org.valiktor:valiktor-core", version.ref = "valiktor commons-io = { module = "commons-io:commons-io", version.ref = "commons-io-version" } ktor-swagger-ui = { module = "io.github.smiley4:ktor-swagger-ui", version.ref = "ktor-swagger-ui-version" } swagger-parser= { module = "io.swagger.parser.v3:swagger-parser", version.ref = "swagger-parser-version" } +coroutine-test= { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutine" } +mockk= { module = "io.mockk:mockk", version.ref = "mockk" } +ktor-client-mock= { module = "io.ktor:ktor-client-mock", version.ref = "ktor-version" } [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-version" } diff --git a/src/test/kotlin/com/piashcse/ConfigureAuth.kt b/src/test/kotlin/com/piashcse/ConfigureAuth.kt new file mode 100644 index 0000000..070a142 --- /dev/null +++ b/src/test/kotlin/com/piashcse/ConfigureAuth.kt @@ -0,0 +1,73 @@ +package com.piashcse + +import com.auth0.jwt.JWT +import com.auth0.jwt.JWTVerifier +import com.auth0.jwt.algorithms.Algorithm +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.auth.jwt.* + +fun Application.configureAuthTest() { + install(Authentication) { + jwt("admin") { + realm = "piashcse" + verifier( + jwtBuilder() + ) + validate { credential -> + // Accepting multiple roles + val role = credential.payload.getClaim("role").asString() + if (role in listOf("CUSTOMER", "SELLER", "ADMIN")) { + UserIdPrincipal(credential.payload.subject) + } else { + null + } + } + } + jwt("seller") { + realm = "piashcse" + verifier( + jwtBuilder() + ) + validate { credential -> + // Accepting multiple roles + val role = credential.payload.getClaim("role").asString() + if (role in listOf("CUSTOMER", "SELLER", "ADMIN")) { + UserIdPrincipal(credential.payload.subject) + } else { + null + } + } + } + jwt("customer") { + realm = "piashcse" + verifier( + jwtBuilder() + ) + validate { credential -> + // Accepting multiple roles + val role = credential.payload.getClaim("role").asString() + if (role in listOf("CUSTOMER", "SELLER", "ADMIN")) { + UserIdPrincipal(credential.payload.subject) + } else { + null + } + } + } + } +} + +private const val SECRET = "zAP5MBA4B4Ijz0MZaS48" +fun jwtBuilder(): JWTVerifier { + return JWT.require(Algorithm.HMAC256(SECRET)) + .withIssuer("piashcse") + .build() +} + +fun generateJwtToken(role: String): String { + return JWT.create() + .withIssuer("piashcse") + .withClaim("role", role) // Pass appropriate role + .withSubject("CUSTOMER") // Set subject + .sign(Algorithm.HMAC256(SECRET)) +} \ No newline at end of file diff --git a/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt b/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt new file mode 100644 index 0000000..b21099a --- /dev/null +++ b/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt @@ -0,0 +1,196 @@ + +import com.auth0.jwt.JWT +import com.piashcse.controller.BrandController +import com.piashcse.entities.product.Brand +import com.piashcse.route.brandRoute +import io.ktor.client.* +import io.ktor.client.engine.mock.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.routing.* +import io.ktor.server.testing.* +import io.mockk.coEvery +import io.mockk.mockk +import kotlin.test.Test +import kotlin.test.assertEquals +import com.piashcse.configureAuthTest +import com.piashcse.generateJwtToken + +class BrandRouteTest { + private fun Application.testModule(brandController: BrandController) { + configureAuthTest() + routing { + authenticate("admin", "customer", "seller") { + brandRoute(brandController) + } + } + } + + + @Test + fun `test get routing for Brand`() = testApplication { + val mockBrandController = mockk(relaxed = true) + val brands = listOf( + Brand("1", "Brand A", "logoA.png"), + Brand("2", "Brand B", "logoB.png") + ) + + coEvery { mockBrandController.getBrands(any(), any()) } returns brands + + // Initialize the test application with the mock controller + application { + testModule(mockBrandController) + } + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + if (request.url.encodedPath == "/brand" && + request.url.parameters["limit"] == "10" && + request.url.parameters["offset"] == "0") { + respond( + """{"status":"success","data":[{"id":"1","brandName":"Brand A","brandLogo":"logoA.png"},{"id":"2","brandName":"Brand B","brandLogo":"logoB.png"}]}""", + HttpStatusCode.OK + ) + } else { + respond("Not found", HttpStatusCode.NotFound) + } + } + } + } + + val jwtToken = generateJwtToken("CUSTOMER") // Generate JWT token with the appropriate role + val response: HttpResponse = client.get("/brand?limit=10&offset=0") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + } + assertEquals(HttpStatusCode.OK, response.status) + assertEquals( + """{"status":"success","data":[{"id":"1","brandName":"Brand A","brandLogo":"logoA.png"},{"id":"2","brandName":"Brand B","brandLogo":"logoB.png"}]}""", + response.bodyAsText() + ) + } + + @Test + fun `test post routing for Brand`() = testApplication { + val mockBrandController = mockk(relaxed = true) + + // Mock the behavior of the addBrand function + coEvery { mockBrandController.addBrand(any()) } returns Brand("1", "Brand Added Successfully", null) + + // Initialize the test application with the mock controller + application { + testModule(mockBrandController) + } + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + if (request.url.encodedPath == "/brand" && request.method == HttpMethod.Post) { + respond( + """{"status":"success","data":"Brand Added Successfully"}""", + HttpStatusCode.OK + ) + } else { + respond("Bad Request", HttpStatusCode.BadRequest) + } + } + } + } + + val jwtToken = generateJwtToken("ADMIN") // Use an appropriate role + val response: HttpResponse = client.post("/brand") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + contentType(ContentType.Application.Json) + setBody("""{"brandName":"Brand C"}""") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertEquals( + """{"status":"success","data":"Brand Added Successfully"}""", + response.bodyAsText() + ) + } + + @Test + fun `test put routing for Brand`() = testApplication { + val mockBrandController = mockk(relaxed = true) + + // Mock the behavior of the updateBrand function + coEvery { mockBrandController.updateBrand(any(), any()) } returns Brand("1", "Brand Updated Successfully", null) + + // Initialize the test application with the mock controller + application { + testModule(mockBrandController) + } + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + if (request.url.encodedPath == "/brand/1" && request.method == HttpMethod.Put) { + respond( + """{"status":"success","data":"Brand Updated Successfully"}""", + HttpStatusCode.OK + ) + } else { + respond("Bad Request", HttpStatusCode.BadRequest) + } + } + } + } + + val jwtToken = generateJwtToken("SELLER") // Use an appropriate role + val response: HttpResponse = client.put("/brand/1") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + contentType(ContentType.Application.Json) + setBody("""{"brandName":"Brand Updated"}""") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertEquals( + """{"status":"success","data":"Brand Updated Successfully"}""", + response.bodyAsText() + ) + } + + @Test + fun `test delete routing for Brand`() = testApplication { + val mockBrandController = mockk(relaxed = true) + + // Mock the behavior of the deleteBrand function + coEvery { mockBrandController.deleteBrand(any()) } returns "Brand Deleted Successfully" + + // Initialize the test application with the mock controller + application { + testModule(mockBrandController) + } + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + if (request.url.encodedPath == "/brand/1" && request.method == HttpMethod.Delete) { + respond( + """{"status":"success","data":"Brand Deleted Successfully"}""", + HttpStatusCode.OK + ) + } else { + respond("Bad Request", HttpStatusCode.BadRequest) + } + } + } + } + + val jwtToken = generateJwtToken("ADMIN") // Use an appropriate role + val response: HttpResponse = client.delete("/brand/1") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertEquals( + """{"status":"success","data":"Brand Deleted Successfully"}""", + response.bodyAsText() + ) + } +} \ No newline at end of file From 9f72aad6296f3258adc7a81a18f2cb2e8e3b8409 Mon Sep 17 00:00:00 2001 From: mehedihasanpiash Date: Sat, 21 Sep 2024 12:49:38 +0600 Subject: [PATCH 2/5] - Update Brand testing according role --- src/test/kotlin/com/piashcse/ConfigureAuth.kt | 6 +- .../com/piashcse/route/BrandRouteTest.kt | 178 +++++++++++++----- 2 files changed, 138 insertions(+), 46 deletions(-) diff --git a/src/test/kotlin/com/piashcse/ConfigureAuth.kt b/src/test/kotlin/com/piashcse/ConfigureAuth.kt index 070a142..5ebf4c9 100644 --- a/src/test/kotlin/com/piashcse/ConfigureAuth.kt +++ b/src/test/kotlin/com/piashcse/ConfigureAuth.kt @@ -17,7 +17,7 @@ fun Application.configureAuthTest() { validate { credential -> // Accepting multiple roles val role = credential.payload.getClaim("role").asString() - if (role in listOf("CUSTOMER", "SELLER", "ADMIN")) { + if (role in listOf("ADMIN")) { UserIdPrincipal(credential.payload.subject) } else { null @@ -32,7 +32,7 @@ fun Application.configureAuthTest() { validate { credential -> // Accepting multiple roles val role = credential.payload.getClaim("role").asString() - if (role in listOf("CUSTOMER", "SELLER", "ADMIN")) { + if (role in listOf("SELLER")) { UserIdPrincipal(credential.payload.subject) } else { null @@ -47,7 +47,7 @@ fun Application.configureAuthTest() { validate { credential -> // Accepting multiple roles val role = credential.payload.getClaim("role").asString() - if (role in listOf("CUSTOMER", "SELLER", "ADMIN")) { + if (role in listOf("CUSTOMER")) { UserIdPrincipal(credential.payload.subject) } else { null diff --git a/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt b/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt index b21099a..a3baf0c 100644 --- a/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt +++ b/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt @@ -1,5 +1,3 @@ - -import com.auth0.jwt.JWT import com.piashcse.controller.BrandController import com.piashcse.entities.product.Brand import com.piashcse.route.brandRoute @@ -29,9 +27,22 @@ class BrandRouteTest { } } + private suspend fun validateBrandResponse(role: String, client: HttpClient) { + val token = generateJwtToken(role) // Generate JWT token with the given role + val response: HttpResponse = client.get("/brand?limit=10&offset=0") { + header(HttpHeaders.Authorization, "Bearer $token") + } + + // Validate the response + assertEquals(HttpStatusCode.OK, response.status) + assertEquals( + """{"status":"success","data":[{"id":"1","brandName":"Brand A","brandLogo":"logoA.png"},{"id":"2","brandName":"Brand B","brandLogo":"logoB.png"}]}""", + response.bodyAsText() + ) + } @Test - fun `test get routing for Brand`() = testApplication { + fun `test get routing for Brand as ADMIN, SELLER, CUSTOMER`() = testApplication { val mockBrandController = mockk(relaxed = true) val brands = listOf( Brand("1", "Brand A", "logoA.png"), @@ -48,33 +59,52 @@ class BrandRouteTest { val client = HttpClient(MockEngine) { engine { addHandler { request -> - if (request.url.encodedPath == "/brand" && - request.url.parameters["limit"] == "10" && - request.url.parameters["offset"] == "0") { - respond( - """{"status":"success","data":[{"id":"1","brandName":"Brand A","brandLogo":"logoA.png"},{"id":"2","brandName":"Brand B","brandLogo":"logoB.png"}]}""", - HttpStatusCode.OK - ) + // Extract the Authorization header + val authHeader = request.headers[HttpHeaders.Authorization] + + // Example for GET request with dynamic role handling + if (request.url.encodedPath == "/brand" && request.method == HttpMethod.Get && + request.url.parameters["limit"] == "10" && request.url.parameters["offset"] == "0" + ) { + // Validate the Authorization header + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // Here, you can dynamically generate tokens for different roles + val validRoles = listOf("ADMIN", "CUSTOMER", "SELLER") + + // Loop through valid roles and check if the provided token matches any valid one + val isValidToken = validRoles.any { role -> + val generatedToken = generateJwtToken(role) + token == generatedToken + } + + if (isValidToken) { + respond( + """{"status":"success","data":[{"id":"1","brandName":"Brand A","brandLogo":"logoA.png"},{"id":"2","brandName":"Brand B","brandLogo":"logoB.png"}]}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } } else { - respond("Not found", HttpStatusCode.NotFound) + respond("Bad Request", HttpStatusCode.BadRequest) } } } } - val jwtToken = generateJwtToken("CUSTOMER") // Generate JWT token with the appropriate role - val response: HttpResponse = client.get("/brand?limit=10&offset=0") { - header(HttpHeaders.Authorization, "Bearer $jwtToken") - } - assertEquals(HttpStatusCode.OK, response.status) - assertEquals( - """{"status":"success","data":[{"id":"1","brandName":"Brand A","brandLogo":"logoA.png"},{"id":"2","brandName":"Brand B","brandLogo":"logoB.png"}]}""", - response.bodyAsText() - ) + validateBrandResponse("CUSTOMER", client) + validateBrandResponse("ADMIN", client) + validateBrandResponse("SELLER", client) } + @Test - fun `test post routing for Brand`() = testApplication { + fun `test post routing for Brand as ADMIN`() = testApplication { val mockBrandController = mockk(relaxed = true) // Mock the behavior of the addBrand function @@ -88,11 +118,29 @@ class BrandRouteTest { val client = HttpClient(MockEngine) { engine { addHandler { request -> + // Extract the Authorization header + val authHeader = request.headers[HttpHeaders.Authorization] + if (request.url.encodedPath == "/brand" && request.method == HttpMethod.Post) { - respond( - """{"status":"success","data":"Brand Added Successfully"}""", - HttpStatusCode.OK - ) + // Validate the Authorization header + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // For simplicity, you can check if the token matches a pre-generated token + // In a real-world scenario, you could mock the token validation logic. + val validToken = generateJwtToken("ADMIN") // Assuming a valid token for the test case + + if (token == validToken) { + respond( + """{"status":"success","data":"Brand Added Successfully"}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } } else { respond("Bad Request", HttpStatusCode.BadRequest) } @@ -100,7 +148,7 @@ class BrandRouteTest { } } - val jwtToken = generateJwtToken("ADMIN") // Use an appropriate role + val jwtToken = generateJwtToken("ADMIN") // Generate JWT token for ADMIN role val response: HttpResponse = client.post("/brand") { header(HttpHeaders.Authorization, "Bearer $jwtToken") contentType(ContentType.Application.Json) @@ -115,11 +163,15 @@ class BrandRouteTest { } @Test - fun `test put routing for Brand`() = testApplication { + fun `test put routing for Brand as ADMIN`() = testApplication { val mockBrandController = mockk(relaxed = true) // Mock the behavior of the updateBrand function - coEvery { mockBrandController.updateBrand(any(), any()) } returns Brand("1", "Brand Updated Successfully", null) + coEvery { mockBrandController.updateBrand(any(), any()) } returns Brand( + id = "1", + brandName = "Brand Updated Successfully", + brandLogo = null + ) // Initialize the test application with the mock controller application { @@ -130,10 +182,26 @@ class BrandRouteTest { engine { addHandler { request -> if (request.url.encodedPath == "/brand/1" && request.method == HttpMethod.Put) { - respond( - """{"status":"success","data":"Brand Updated Successfully"}""", - HttpStatusCode.OK - ) + val authHeader = request.headers[HttpHeaders.Authorization] + + // Check if the Authorization header contains the Bearer token + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // Mock token validation logic + val sellerToken = generateJwtToken("ADMIN") + + if (token == sellerToken) { + respond( + """{"status":"success","data":"Brand Updated Successfully"}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } } else { respond("Bad Request", HttpStatusCode.BadRequest) } @@ -141,13 +209,17 @@ class BrandRouteTest { } } - val jwtToken = generateJwtToken("SELLER") // Use an appropriate role + // Generate the JWT token for SELLER + val jwtToken = generateJwtToken("ADMIN") + + // Perform PUT request to update the brand val response: HttpResponse = client.put("/brand/1") { - header(HttpHeaders.Authorization, "Bearer $jwtToken") - contentType(ContentType.Application.Json) - setBody("""{"brandName":"Brand Updated"}""") + header(HttpHeaders.Authorization, "Bearer $jwtToken") // Set the JWT token + contentType(ContentType.Application.Json) // Specify content type + setBody("""{"brandName":"Brand Updated"}""") // Set the request body } + // Validate the response assertEquals(HttpStatusCode.OK, response.status) assertEquals( """{"status":"success","data":"Brand Updated Successfully"}""", @@ -156,7 +228,7 @@ class BrandRouteTest { } @Test - fun `test delete routing for Brand`() = testApplication { + fun `test delete routing for Brand as ADMIN`() = testApplication { val mockBrandController = mockk(relaxed = true) // Mock the behavior of the deleteBrand function @@ -171,10 +243,26 @@ class BrandRouteTest { engine { addHandler { request -> if (request.url.encodedPath == "/brand/1" && request.method == HttpMethod.Delete) { - respond( - """{"status":"success","data":"Brand Deleted Successfully"}""", - HttpStatusCode.OK - ) + val authHeader = request.headers[HttpHeaders.Authorization] + + // Check if the Authorization header contains the Bearer token + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // Mock token validation logic + val adminToken = generateJwtToken("ADMIN") + + if (token == adminToken) { + respond( + """{"status":"success","data":"Brand Deleted Successfully"}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } } else { respond("Bad Request", HttpStatusCode.BadRequest) } @@ -182,11 +270,15 @@ class BrandRouteTest { } } - val jwtToken = generateJwtToken("ADMIN") // Use an appropriate role + // Generate the JWT token for ADMIN + val jwtToken = generateJwtToken("ADMIN") + + // Perform DELETE request to delete the brand val response: HttpResponse = client.delete("/brand/1") { - header(HttpHeaders.Authorization, "Bearer $jwtToken") + header(HttpHeaders.Authorization, "Bearer $jwtToken") // Set the JWT token } + // Validate the response assertEquals(HttpStatusCode.OK, response.status) assertEquals( """{"status":"success","data":"Brand Deleted Successfully"}""", From 1f038eeedd5a91134570c253c28f408f549daded Mon Sep 17 00:00:00 2001 From: mehedihasanpiash Date: Sat, 21 Sep 2024 12:56:41 +0600 Subject: [PATCH 3/5] - Update code --- src/test/kotlin/com/piashcse/route/BrandRouteTest.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt b/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt index a3baf0c..956a4c4 100644 --- a/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt +++ b/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt @@ -7,7 +7,6 @@ import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import io.ktor.server.application.* -import io.ktor.server.auth.* import io.ktor.server.routing.* import io.ktor.server.testing.* import io.mockk.coEvery @@ -21,9 +20,7 @@ class BrandRouteTest { private fun Application.testModule(brandController: BrandController) { configureAuthTest() routing { - authenticate("admin", "customer", "seller") { - brandRoute(brandController) - } + brandRoute(brandController) } } From f43334c6e0171b7f9491034812c5ffec7cdb0d80 Mon Sep 17 00:00:00 2001 From: mehedihasanpiash Date: Sat, 21 Sep 2024 23:02:27 +0600 Subject: [PATCH 4/5] - Implemented test for wishlist --- .../kotlin/com/piashcse/ApplicationTest.kt | 13 - src/test/kotlin/com/piashcse/ConfigureAuth.kt | 19 +- .../com/piashcse/route/BrandRouteTest.kt | 21 +- .../kotlin/com/piashcse/route/WishlistTest.kt | 287 ++++++++++++++++++ 4 files changed, 309 insertions(+), 31 deletions(-) delete mode 100644 src/test/kotlin/com/piashcse/ApplicationTest.kt create mode 100644 src/test/kotlin/com/piashcse/route/WishlistTest.kt diff --git a/src/test/kotlin/com/piashcse/ApplicationTest.kt b/src/test/kotlin/com/piashcse/ApplicationTest.kt deleted file mode 100644 index f105b6c..0000000 --- a/src/test/kotlin/com/piashcse/ApplicationTest.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.piashcse - -class ApplicationTest { - /* @Test - fun testRoot() { - withTestApplication({ configureRouting() }) { - handleRequest(HttpMethod.Get, "/").apply { - assertEquals(HttpStatusCode.OK, response.status()) - assertEquals("Hello World!", response.content) - } - } - }*/ -} \ No newline at end of file diff --git a/src/test/kotlin/com/piashcse/ConfigureAuth.kt b/src/test/kotlin/com/piashcse/ConfigureAuth.kt index 5ebf4c9..953cdfb 100644 --- a/src/test/kotlin/com/piashcse/ConfigureAuth.kt +++ b/src/test/kotlin/com/piashcse/ConfigureAuth.kt @@ -3,14 +3,16 @@ package com.piashcse import com.auth0.jwt.JWT import com.auth0.jwt.JWTVerifier import com.auth0.jwt.algorithms.Algorithm +import com.piashcse.plugins.RoleManagement import io.ktor.server.application.* import io.ktor.server.auth.* import io.ktor.server.auth.jwt.* fun Application.configureAuthTest() { + val authRealm = "piashcse" install(Authentication) { - jwt("admin") { - realm = "piashcse" + jwt(RoleManagement.ADMIN.role) { + realm = authRealm verifier( jwtBuilder() ) @@ -24,8 +26,8 @@ fun Application.configureAuthTest() { } } } - jwt("seller") { - realm = "piashcse" + jwt(RoleManagement.SELLER.role) { + realm = authRealm verifier( jwtBuilder() ) @@ -39,8 +41,8 @@ fun Application.configureAuthTest() { } } } - jwt("customer") { - realm = "piashcse" + jwt(RoleManagement.CUSTOMER.role) { + realm = authRealm verifier( jwtBuilder() ) @@ -58,15 +60,16 @@ fun Application.configureAuthTest() { } private const val SECRET = "zAP5MBA4B4Ijz0MZaS48" +private const val ISSUER = "piashcse" fun jwtBuilder(): JWTVerifier { return JWT.require(Algorithm.HMAC256(SECRET)) - .withIssuer("piashcse") + .withIssuer(ISSUER) .build() } fun generateJwtToken(role: String): String { return JWT.create() - .withIssuer("piashcse") + .withIssuer(ISSUER) .withClaim("role", role) // Pass appropriate role .withSubject("CUSTOMER") // Set subject .sign(Algorithm.HMAC256(SECRET)) diff --git a/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt b/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt index 956a4c4..6426c7b 100644 --- a/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt +++ b/src/test/kotlin/com/piashcse/route/BrandRouteTest.kt @@ -15,6 +15,7 @@ import kotlin.test.Test import kotlin.test.assertEquals import com.piashcse.configureAuthTest import com.piashcse.generateJwtToken +import com.piashcse.plugins.RoleManagement class BrandRouteTest { private fun Application.testModule(brandController: BrandController) { @@ -68,7 +69,7 @@ class BrandRouteTest { val token = authHeader.removePrefix("Bearer ") // Here, you can dynamically generate tokens for different roles - val validRoles = listOf("ADMIN", "CUSTOMER", "SELLER") + val validRoles = listOf(RoleManagement.ADMIN.role, RoleManagement.CUSTOMER.role, RoleManagement.SELLER.role) // Loop through valid roles and check if the provided token matches any valid one val isValidToken = validRoles.any { role -> @@ -94,9 +95,9 @@ class BrandRouteTest { } } - validateBrandResponse("CUSTOMER", client) - validateBrandResponse("ADMIN", client) - validateBrandResponse("SELLER", client) + validateBrandResponse(RoleManagement.ADMIN.role, client) + validateBrandResponse(RoleManagement.SELLER.role, client) + validateBrandResponse(RoleManagement.CUSTOMER.role, client) } @@ -125,7 +126,7 @@ class BrandRouteTest { // For simplicity, you can check if the token matches a pre-generated token // In a real-world scenario, you could mock the token validation logic. - val validToken = generateJwtToken("ADMIN") // Assuming a valid token for the test case + val validToken = generateJwtToken(RoleManagement.ADMIN.role) // Assuming a valid token for the test case if (token == validToken) { respond( @@ -145,7 +146,7 @@ class BrandRouteTest { } } - val jwtToken = generateJwtToken("ADMIN") // Generate JWT token for ADMIN role + val jwtToken = generateJwtToken(RoleManagement.ADMIN.role) // Generate JWT token for ADMIN role val response: HttpResponse = client.post("/brand") { header(HttpHeaders.Authorization, "Bearer $jwtToken") contentType(ContentType.Application.Json) @@ -186,7 +187,7 @@ class BrandRouteTest { val token = authHeader.removePrefix("Bearer ") // Mock token validation logic - val sellerToken = generateJwtToken("ADMIN") + val sellerToken = generateJwtToken(RoleManagement.ADMIN.role) if (token == sellerToken) { respond( @@ -207,7 +208,7 @@ class BrandRouteTest { } // Generate the JWT token for SELLER - val jwtToken = generateJwtToken("ADMIN") + val jwtToken = generateJwtToken(RoleManagement.ADMIN.role) // Perform PUT request to update the brand val response: HttpResponse = client.put("/brand/1") { @@ -247,7 +248,7 @@ class BrandRouteTest { val token = authHeader.removePrefix("Bearer ") // Mock token validation logic - val adminToken = generateJwtToken("ADMIN") + val adminToken = generateJwtToken(RoleManagement.ADMIN.role) if (token == adminToken) { respond( @@ -268,7 +269,7 @@ class BrandRouteTest { } // Generate the JWT token for ADMIN - val jwtToken = generateJwtToken("ADMIN") + val jwtToken = generateJwtToken(RoleManagement.ADMIN.role) // Perform DELETE request to delete the brand val response: HttpResponse = client.delete("/brand/1") { diff --git a/src/test/kotlin/com/piashcse/route/WishlistTest.kt b/src/test/kotlin/com/piashcse/route/WishlistTest.kt new file mode 100644 index 0000000..70bc7f9 --- /dev/null +++ b/src/test/kotlin/com/piashcse/route/WishlistTest.kt @@ -0,0 +1,287 @@ +package com.piashcse.route + +import com.piashcse.configureAuthTest +import com.piashcse.controller.WishListController +import com.piashcse.entities.WishList +import com.piashcse.entities.product.Product +import com.piashcse.generateJwtToken +import com.piashcse.plugins.RoleManagement +import io.ktor.client.* +import io.ktor.client.engine.mock.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.routing.* +import io.ktor.server.testing.* +import io.mockk.coEvery +import io.mockk.mockk +import junit.framework.TestCase.assertEquals +import kotlin.test.Test + +class WishlistTest { + private fun Application.testModule(wishListController: WishListController) { + configureAuthTest() + routing { + wishListRoute(wishListController) + } + } + + @Test + fun `test adding product to wish list`() = testApplication { + val mockWishListController = mockk(relaxed = true) + + // Mock the behavior of the addToWishList function + coEvery { mockWishListController.addToWishList(any(), any()) } returns WishList( + Product( + "1", + " A", + null, + null, + "Product A", + "100", + 1, + "Detail of product", + 100.0, + null, + null, + null, + null, + null, + null, + null, null, null, null, null, null, + ) + ) + + // Initialize the test application with the mock controller + application { + testModule(mockWishListController) + } + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + // Extract the Authorization header + val authHeader = request.headers[HttpHeaders.Authorization] + + if (request.url.encodedPath == "/wishlist" && request.method == HttpMethod.Post) { + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // Here, you can dynamically generate tokens for different roles + val validRoles = listOf(RoleManagement.CUSTOMER.role) + + // Loop through valid roles and check if the provided token matches any valid one + val isValidToken = validRoles.any { role -> + val generatedToken = generateJwtToken(role) + token == generatedToken + } + + if (isValidToken) { + respond( + """{"status":"success","data":{"id":"1","productName":"Product A","productDetail":"Product Detail A"}}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Bad Request", HttpStatusCode.BadRequest) + } + } + } + } + + val jwtToken = generateJwtToken(RoleManagement.CUSTOMER.role) // Generate a token for CUSTOMER role + val response: HttpResponse = client.post("/wishlist") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + contentType(ContentType.Application.Json) + setBody("""{"productId":"1"}""") // Mock request body + } + + assertEquals(HttpStatusCode.OK, response.status) + assertEquals( + """{"status":"success","data":{"id":"1","productName":"Product A","productDetail":"Product Detail A"}}""", + response.bodyAsText() + ) + } + + @Test + fun `test getting wish list items`() = testApplication { + val mockWishListController = mockk(relaxed = true) + + // Mock the behavior of the getWishList function + coEvery { mockWishListController.getWishList(any(), any(), any()) } returns listOf( + Product( + "1", + " A", + null, + null, + "Product A", + "100", + 1, + "Detail Product A", + 100.0, + null, + null, + null, + null, + null, + null, + null, null, null, null, null, null, + ), + Product( + "2", + "B", + null, + null, + "Product B", + "100", + 1, + "Detail Product B", + 100.0, + null, + null, + null, + null, + null, + null, + null, null, null, null, null, null, + ) + ) + + application { + testModule(mockWishListController) + } + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + // Extract the Authorization header + val authHeader = request.headers[HttpHeaders.Authorization] + if (request.url.encodedPath == "/wishlist" && request.method == HttpMethod.Get && + request.url.parameters["limit"] == "10" && request.url.parameters["offset"] == "0" + ) { + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // Here, you can dynamically generate tokens for different roles + val validRoles = listOf(RoleManagement.CUSTOMER.role) + + // Loop through valid roles and check if the provided token matches any valid one + val isValidToken = validRoles.any { role -> + val generatedToken = generateJwtToken(role) + token == generatedToken + } + if (isValidToken) { + respond( + """{"status":"success","data":[{"id":"1","productName":"Product A","productDetail":"Detail Product A"},{"id":"2","productName":"Product B","productDetail":"Detail Product B"}]}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + + } else { + respond("Bad Request", HttpStatusCode.BadRequest) + } + } + } + } + + val jwtToken = generateJwtToken(RoleManagement.CUSTOMER.role) + val response: HttpResponse = client.get("/wishlist?limit=10&offset=0") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertEquals( + """{"status":"success","data":[{"id":"1","productName":"Product A","productDetail":"Detail Product A"},{"id":"2","productName":"Product B","productDetail":"Detail Product B"}]}""", + response.bodyAsText() + ) + } + + @Test + fun `test deleting item from wish list`() = testApplication { + val mockWishListController = mockk(relaxed = true) + + // Mock the behavior of the deleteWishList function + coEvery { mockWishListController.deleteWishList(any(), any()) } returns Product( + "1", + "A", + null, + null, + "Product B", + "100", + 1, + "Detail Product A", + 100.0, + null, + null, + null, + null, + null, + null, + null, null, null, null, null, null, + ) + + application { + testModule(mockWishListController) + } + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + // Extract the Authorization header + val authHeader = request.headers[HttpHeaders.Authorization] + if (request.url.encodedPath == "/wishlist" && request.method == HttpMethod.Delete && + request.url.parameters["productId"] == "1" + ) { + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // Here, you can dynamically generate tokens for different roles + val validRoles = listOf(RoleManagement.CUSTOMER.role) + + // Loop through valid roles and check if the provided token matches any valid one + val isValidToken = validRoles.any { role -> + val generatedToken = generateJwtToken(role) + token == generatedToken + } + if (isValidToken) { + respond( + """{"status":"success","data":{"id":"1","productName":"Product A","productDetail":"Product detail A"}}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + }else{ + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Bad Request", HttpStatusCode.BadRequest) + } + } + } + } + + val jwtToken = generateJwtToken(RoleManagement.CUSTOMER.role) + val response: HttpResponse = client.delete("/wishlist?productId=1") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertEquals( + """{"status":"success","data":{"id":"1","productName":"Product A","productDetail":"Product detail A"}}""", + response.bodyAsText() + ) + } +} \ No newline at end of file From 7f7a673a91af07cdd44e637e8b77676bdd051c1d Mon Sep 17 00:00:00 2001 From: mehedihasanpiash Date: Sat, 21 Sep 2024 23:44:44 +0600 Subject: [PATCH 5/5] - Implemented test for ShopCategory --- .../com/piashcse/route/ShopCategoryTest.kt | 273 ++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 src/test/kotlin/com/piashcse/route/ShopCategoryTest.kt diff --git a/src/test/kotlin/com/piashcse/route/ShopCategoryTest.kt b/src/test/kotlin/com/piashcse/route/ShopCategoryTest.kt new file mode 100644 index 0000000..173229c --- /dev/null +++ b/src/test/kotlin/com/piashcse/route/ShopCategoryTest.kt @@ -0,0 +1,273 @@ +package com.piashcse.route + +import com.piashcse.configureAuthTest +import com.piashcse.controller.ShopCategoryController +import com.piashcse.entities.shop.ShopCategory +import com.piashcse.generateJwtToken +import com.piashcse.plugins.RoleManagement +import io.ktor.client.* +import io.ktor.client.engine.mock.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.routing.* +import io.ktor.server.testing.* +import io.mockk.coEvery +import io.mockk.mockk +import junit.framework.TestCase.assertEquals +import kotlin.test.Test + +class ShopCategoryTest { + private fun Application.testModule(shopCategoryController: ShopCategoryController) { + configureAuthTest() + routing { + shopCategoryRoute(shopCategoryController) + } + } + + @Test + fun `test adding shop category`() = testApplication { + val mockShopCategoryController = mockk(relaxed = true) + + // Mock the behavior of the addShopCategory function + coEvery { mockShopCategoryController.addShopCategory(any()) } returns ShopCategory("1", "Electronics") + + // Initialize the test application with the mock controller + application { + testModule(mockShopCategoryController) + } + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + val authHeader = request.headers[HttpHeaders.Authorization] + if (request.url.encodedPath == "/shop-category" && request.method == HttpMethod.Post) { + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // Here, you can dynamically generate tokens for different roles + val validRoles = listOf(RoleManagement.ADMIN.role) + + // Loop through valid roles and check if the provided token matches any valid one + val isValidToken = validRoles.any { role -> + val generatedToken = generateJwtToken(role) + token == generatedToken + } + + if (isValidToken) { + respond( + """{"status":"success","data":{"id":"1","name":"Electronics"}}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + + } else { + respond("Bad Request", HttpStatusCode.BadRequest) + } + } + } + } + + val jwtToken = generateJwtToken(RoleManagement.ADMIN.role) // Generate a token for ADMIN role + // Send POST request with the authorization header + val response: HttpResponse = client.post("/shop-category") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + contentType(ContentType.Application.Json) + setBody("""{"name":"Electronics"}""") // Mock request body + } + + assertEquals(HttpStatusCode.OK, response.status) + assertEquals( + """{"status":"success","data":{"id":"1","name":"Electronics"}}""", + response.bodyAsText() + ) + } + + @Test + fun `test getting shop categories with authentication in engine`() = testApplication { + val mockShopCategoryController = mockk(relaxed = true) + + // Mock the behavior of the getShopCategories function + coEvery { mockShopCategoryController.getShopCategories(any(), any()) } returns listOf( + ShopCategory("1", "Electronics"), + ShopCategory("2", "Clothing") + ) + + application { + testModule(mockShopCategoryController) + } + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + val authHeader = request.headers[HttpHeaders.Authorization] + if (request.url.encodedPath == "/shop-category" && request.method == HttpMethod.Get && + request.url.parameters["limit"] == "10" && request.url.parameters["offset"] == "0" + ) { + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // Here, you can dynamically generate tokens for different roles + val validRoles = listOf(RoleManagement.ADMIN.role) + + // Loop through valid roles and check if the provided token matches any valid one + val isValidToken = validRoles.any { role -> + val generatedToken = generateJwtToken(role) + token == generatedToken + } + + if (isValidToken) { + respond( + """{"status":"success","data":[{"id":"1","name":"Electronics"},{"id":"2","name":"Clothing"}]}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Bad Request", HttpStatusCode.BadRequest) + } + } + } + } + + val jwtToken = generateJwtToken(RoleManagement.ADMIN.role) // Generate a token for ADMIN role + // Send GET request with the authorization header + val response: HttpResponse = client.get("/shop-category?limit=10&offset=0") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertEquals( + """{"status":"success","data":[{"id":"1","name":"Electronics"},{"id":"2","name":"Clothing"}]}""", + response.bodyAsText() + ) + } + + @Test + fun `test updating shop category with authentication in engine`() = testApplication { + val mockShopCategoryController = mockk(relaxed = true) + + // Mock the behavior of the updateShopCategory function + coEvery { mockShopCategoryController.updateShopCategory(any(), any()) } returns ShopCategory( + "1", + "Updated Electronics" + ) + + application { + testModule(mockShopCategoryController) + } + + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + val authHeader = request.headers[HttpHeaders.Authorization] + if (request.url.encodedPath == "/shop-category/1" && request.method == HttpMethod.Put && + request.url.parameters["name"] == "Updated Electronics" + ) { + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // Here, you can dynamically generate tokens for different roles + val validRoles = listOf(RoleManagement.ADMIN.role) + + // Loop through valid roles and check if the provided token matches any valid one + val isValidToken = validRoles.any { role -> + val generatedToken = generateJwtToken(role) + token == generatedToken + } + + if (isValidToken) { + respond( + """{"status":"success","data":{"id":"1","name":"Updated Electronics"}}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Bad Request", HttpStatusCode.BadRequest) + } + } + } + } + val jwtToken = generateJwtToken(RoleManagement.ADMIN.role) // Generate a token for ADMIN role + + // Send PUT request with the authorization header + val response: HttpResponse = client.put("/shop-category/1?name=Updated Electronics") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertEquals("""{"status":"success","data":{"id":"1","name":"Updated Electronics"}}""", response.bodyAsText()) + } + + @Test + fun `test deleting shop category with authentication in engine`() = testApplication { + val mockShopCategoryController = mockk(relaxed = true) + + // Mock the behavior of the deleteShopCategory function + coEvery { mockShopCategoryController.deleteShopCategory(any()) } returns "1" + + application { + testModule(mockShopCategoryController) + } + + val client = HttpClient(MockEngine) { + engine { + addHandler { request -> + val authHeader = request.headers[HttpHeaders.Authorization] + if (request.url.encodedPath == "/shop-category/1" && request.method == HttpMethod.Delete) { + if (authHeader != null && authHeader.startsWith("Bearer ")) { + val token = authHeader.removePrefix("Bearer ") + + // Here, you can dynamically generate tokens for different roles + val validRoles = listOf(RoleManagement.ADMIN.role) + + // Loop through valid roles and check if the provided token matches any valid one + val isValidToken = validRoles.any { role -> + val generatedToken = generateJwtToken(role) + token == generatedToken + } + + if (isValidToken) { + respond( + """{"status":"success","data":"1"}""", + HttpStatusCode.OK + ) + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Unauthorized", HttpStatusCode.Unauthorized) + } + } else { + respond("Bad Request", HttpStatusCode.BadRequest) + } + } + } + } + + val jwtToken = generateJwtToken(RoleManagement.ADMIN.role) // Generate a token for ADMIN role + // Send DELETE request with the authorization header + val response: HttpResponse = client.delete("/shop-category/1") { + header(HttpHeaders.Authorization, "Bearer $jwtToken") + } + + assertEquals(HttpStatusCode.OK, response.status) + assertEquals("""{"status":"success","data":"1"}""", response.bodyAsText()) + } +} \ No newline at end of file