From 8692ed55c3c843862a02776615c4e66131d172d0 Mon Sep 17 00:00:00 2001 From: Override-6 Date: Sun, 29 Jan 2023 18:53:05 +0100 Subject: [PATCH] writting some tests --- Core/src/org/tbasket/Main.scala | 4 +-- ...hentificator.scala => Authenticator.scala} | 12 ++++--- Core/src/org/tbasket/endpoint/Endpoint.scala | 4 +-- .../tbasket/handler/LoginPageHandler.scala | 8 ++--- .../tbasket/handler/RegisterPageHandler.scala | 6 ++-- drone/image/tbasket-backend.dockerfile | 2 +- target/test-reports-zio/output.json | 32 ++++++++++------- tests/resources/generate_keys.sh | 12 +++---- tests/resources/test_dataset.sql | 3 ++ tests/src/org/tbasket/test/TestLayers.scala | 31 +++++++++++++--- .../test/pages/LoginPageHandlerTests.scala | 35 ++++++++++++------- 11 files changed, 98 insertions(+), 51 deletions(-) rename Core/src/org/tbasket/auth/{Authentificator.scala => Authenticator.scala} (94%) mode change 100644 => 100755 tests/resources/generate_keys.sh create mode 100644 tests/resources/test_dataset.sql diff --git a/Core/src/org/tbasket/Main.scala b/Core/src/org/tbasket/Main.scala index cbba504..ebf2087 100644 --- a/Core/src/org/tbasket/Main.scala +++ b/Core/src/org/tbasket/Main.scala @@ -1,7 +1,7 @@ package org.tbasket import org.apache.logging.log4j.LogManager -import org.tbasket.auth.Authentificator +import org.tbasket.auth.Authenticator import org.tbasket.config.{FileServerConfig, ServerConfig} import org.tbasket.data.Database import org.tbasket.endpoint.Endpoint @@ -44,7 +44,7 @@ object Main extends ZIOAppDefault: private def setupAuth(config: ServerConfig) = ZIO.attempt { val publicKey = config.emitterCertificate.getPublicKey - val auth = new Authentificator(config.emitterURL, publicKey, config.emitterKeyAlgorithm) + val auth = new Authenticator(config.emitterURL, publicKey, config.emitterKeyAlgorithm) ZLayer.succeed(auth) } diff --git a/Core/src/org/tbasket/auth/Authentificator.scala b/Core/src/org/tbasket/auth/Authenticator.scala similarity index 94% rename from Core/src/org/tbasket/auth/Authentificator.scala rename to Core/src/org/tbasket/auth/Authenticator.scala index 123cdb1..eae3886 100644 --- a/Core/src/org/tbasket/auth/Authentificator.scala +++ b/Core/src/org/tbasket/auth/Authenticator.scala @@ -9,7 +9,7 @@ import io.getquill.context.qzio.ZioJdbcContext import io.getquill.context.sql.idiom.SqlIdiom import org.apache.logging.log4j.LogManager import org.tbasket.InternalBasketServerException -import org.tbasket.auth.Authentificator.* +import org.tbasket.auth.Authenticator.* import org.tbasket.data.{DatabaseContext, User} import org.tbasket.error.AuthException.* import org.tbasket.error.ExceptionEnum @@ -31,18 +31,20 @@ import javax.sql.DataSource import scala.collection.immutable.HashMap -case class JwtContent(uuid: UUID) -object Authentificator: +object Authenticator: private final val LOG = LogManager.getLogger("Authentification") private final val ValidMailPattern = "^\\w+([.-]?\\w+)*@\\w+([.-]?\\w+)*(\\.\\w{2,3})+$".r private final val ValidPasswordPattern = ".{6,}".r + + case class JwtContent(uuid: UUID) + -class Authentificator(url: URL, key: PublicKey, algorithm: JwtAsymmetricAlgorithm) { +class Authenticator(url: URL, key: PublicKey, algorithm: JwtAsymmetricAlgorithm) { private def defineCustomClaims(user: User): String = { - JwtContent(user.id).asJson.noSpaces.toString + JwtContent(user.id).asJson.noSpaces } private def mkRequest(user: User): Request = { diff --git a/Core/src/org/tbasket/endpoint/Endpoint.scala b/Core/src/org/tbasket/endpoint/Endpoint.scala index 203b7ed..07c6f4b 100644 --- a/Core/src/org/tbasket/endpoint/Endpoint.scala +++ b/Core/src/org/tbasket/endpoint/Endpoint.scala @@ -5,7 +5,7 @@ import io.getquill.context.sql.idiom.SqlIdiom import io.getquill.idiom.Idiom import io.getquill.{Literal, NamingStrategy, SqliteDialect} import org.apache.logging.log4j.LogManager -import org.tbasket.auth.Authentificator +import org.tbasket.auth.Authenticator import org.tbasket.data.DatabaseContext import org.tbasket.endpoint.Endpoint.LOG import org.tbasket.handler.LoginPageHandler @@ -77,7 +77,7 @@ class Endpoint(port: Int): Server.install(app).flatMap { port => LOG.info(s"Listening API entries on $port") ZIO.never - }.provideSome[DatabaseContext & Authentificator & DataSource]( + }.provideSome[DatabaseContext & Authenticator & DataSource]( Scope.default, serverConfigLayer, ConnectionPool.fixed(4), diff --git a/Core/src/org/tbasket/handler/LoginPageHandler.scala b/Core/src/org/tbasket/handler/LoginPageHandler.scala index 640fed2..e670624 100644 --- a/Core/src/org/tbasket/handler/LoginPageHandler.scala +++ b/Core/src/org/tbasket/handler/LoginPageHandler.scala @@ -5,7 +5,7 @@ import io.getquill.context.ZioJdbc.* import io.getquill.context.qzio.{ZioContext, ZioJdbcContext} import io.getquill.context.sql.idiom.SqlIdiom import org.apache.logging.log4j.LogManager -import org.tbasket.auth.Authentificator +import org.tbasket.auth.Authenticator import org.tbasket.data.{DatabaseContext, User} import org.tbasket.error.AuthException.* import org.tbasket.error.ExceptionEnum @@ -17,7 +17,7 @@ import zio.http.model.{Cookie, Header, Headers, Status} import zio.json.* import zio.json.ast.Json.Str import zio.json.ast.{Json, JsonCursor} -import zio.{ZEnvironment, ZIO, *} +import zio.* import java.sql.SQLException import java.util.UUID @@ -28,7 +28,7 @@ object LoginPageHandler extends PageHandler: private val LOG = LogManager.getLogger("Login") private def getUser(json: Json) = - ZIO.serviceWithZIO[Authentificator] { auth => + ZIO.serviceWithZIO[Authenticator] { auth => for mail <- HandlerUtils.parseAttribute(json, "email", JsonCursor.field("email").isString) password <- HandlerUtils.parseAttribute(json, "password", JsonCursor.field("password").isString) @@ -49,7 +49,7 @@ object LoginPageHandler extends PageHandler: .mapError(InvalidRequest("Invalid JSON body", _)) user <- getUser(json) - jwt <- ZIO.serviceWithZIO[Authentificator](_.requestNewJwt(user)) + jwt <- ZIO.serviceWithZIO[Authenticator](_.requestNewJwt(user)) yield Response( status = Status.Found, headers = Headers.location("/") ++ //login successful, go back to main page diff --git a/Core/src/org/tbasket/handler/RegisterPageHandler.scala b/Core/src/org/tbasket/handler/RegisterPageHandler.scala index ab632b1..1adf3b9 100644 --- a/Core/src/org/tbasket/handler/RegisterPageHandler.scala +++ b/Core/src/org/tbasket/handler/RegisterPageHandler.scala @@ -1,6 +1,6 @@ package org.tbasket.handler -import org.tbasket.auth.Authentificator +import org.tbasket.auth.Authenticator import org.tbasket.data.User import org.tbasket.error.RegularException.InvalidRequest import org.tbasket.handler.HandlerUtils.parseAttribute @@ -25,8 +25,8 @@ object RegisterPageHandler extends PageHandler { mail <- parseAttribute(json, "email", JsonCursor.field("email").isString) password <- parseAttribute(json, "password", JsonCursor.field("password").isString) - user <- ZIO.serviceWithZIO[Authentificator](_.registerUser(name, forename, mail, password)) - jwt <- ZIO.serviceWithZIO[Authentificator](_.requestNewJwt(user)) + user <- ZIO.serviceWithZIO[Authenticator](_.registerUser(name, forename, mail, password)) + jwt <- ZIO.serviceWithZIO[Authenticator](_.requestNewJwt(user)) yield Response( status = Status.Found, headers = Headers.location("/") ++ //register successful, go back to main page diff --git a/drone/image/tbasket-backend.dockerfile b/drone/image/tbasket-backend.dockerfile index 6eacd8f..2a1faec 100644 --- a/drone/image/tbasket-backend.dockerfile +++ b/drone/image/tbasket-backend.dockerfile @@ -3,6 +3,6 @@ FROM ubuntu:latest RUN apt update RUN apt install openjdk-19-jdk -y -RUN apt install openssh-client -y +RUN apt install openssh-client curl wget -y diff --git a/target/test-reports-zio/output.json b/target/test-reports-zio/output.json index 6323981..cf8bdd4 100644 --- a/target/test-reports-zio/output.json +++ b/target/test-reports-zio/output.json @@ -3,42 +3,50 @@ { "name" : "Test Task name not available here/\/login page handler/login situation tests/login with unknown account", "status" : "Success", - "durationMillis" : "3658", + "durationMillis" : "4103", "annotations" : "", "fullyQualifiedClassName" : "Test Task name not available here", "labels" : ["\/login page handler", "login situation tests", "login with unknown account"] }, { - "name" : "Test Task name not available here/\/login page handler/erroned request body tests/with invalid json", - "status" : "Success", - "durationMillis" : "2587", + "name" : "Test Task name not available here/\/login page handler/login situation tests/login with known account", + "status" : "Failure", + "durationMillis" : "1", "annotations" : "", "fullyQualifiedClassName" : "Test Task name not available here", - "labels" : ["\/login page handler", "erroned request body tests", "with invalid json"] + "labels" : ["\/login page handler", "login situation tests", "login with known account"] }, { - "name" : "Test Task name not available here/\/login page handler/erroned request body tests/with no mail attribute", + "name" : "Test Task name not available here/\/login page handler/erroned request body tests/with no password attribute", "status" : "Success", - "durationMillis" : "2629", + "durationMillis" : "2681", "annotations" : "", "fullyQualifiedClassName" : "Test Task name not available here", - "labels" : ["\/login page handler", "erroned request body tests", "with no mail attribute"] + "labels" : ["\/login page handler", "erroned request body tests", "with no password attribute"] }, { "name" : "Test Task name not available here/\/login page handler/erroned request body tests/empty packet", "status" : "Success", - "durationMillis" : "2633", + "durationMillis" : "2697", "annotations" : "", "fullyQualifiedClassName" : "Test Task name not available here", "labels" : ["\/login page handler", "erroned request body tests", "empty packet"] }, { - "name" : "Test Task name not available here/\/login page handler/erroned request body tests/with no password attribute", + "name" : "Test Task name not available here/\/login page handler/erroned request body tests/with no mail attribute", "status" : "Success", - "durationMillis" : "2619", + "durationMillis" : "2702", "annotations" : "", "fullyQualifiedClassName" : "Test Task name not available here", - "labels" : ["\/login page handler", "erroned request body tests", "with no password attribute"] + "labels" : ["\/login page handler", "erroned request body tests", "with no mail attribute"] + }, + { + "name" : "Test Task name not available here/\/login page handler/erroned request body tests/with invalid json", + "status" : "Success", + "durationMillis" : "2717", + "annotations" : "", + "fullyQualifiedClassName" : "Test Task name not available here", + "labels" : ["\/login page handler", "erroned request body tests", "with invalid json"] } ] diff --git a/tests/resources/generate_keys.sh b/tests/resources/generate_keys.sh old mode 100644 new mode 100755 index 6165fda..f56a12a --- a/tests/resources/generate_keys.sh +++ b/tests/resources/generate_keys.sh @@ -2,16 +2,16 @@ echo GENERATING TEMPORARY KEY PAIRS FOR TESTS -rm -r /tmp/keys -mkdir /tmp/keys +rm -r /tmp/keys &> /dev/null +mkdir -p /tmp/keys cd /tmp/keys keytool -genkey -noprompt \ -alias key \ -keyalg RSA \ - -validity 1 \ + -validity 2 \ -keystore test.keystore \ -storetype PKCS12 \ - -dname "CN=mqttserver.ibm.com, OU=ID, O=IBM, L=Hursley, S=Hants, C=GB" \ + -dname "CN=x.y.com, OU=TB, O=TBA, L=dzqdz, S=dqzdzq, C=GB" \ -storepass 123456789 \ -keypass 123456789 @@ -23,5 +23,5 @@ keytool -noprompt -export \ -keypass 123456789 \ -storepass 123456789 -echo "123456789" | openssl pkcs12 -in test.keystore -nodes -nocerts -out private.pcks 2> /dev/null -echo "123456789" | openssl pkcs12 -in test.keystore -nokeys -out public.cert 2> /dev/null +openssl pkcs12 -in test.keystore -nodes -nocerts -out private.pcks -passin pass:123456789 +openssl pkcs12 -in test.keystore -nokeys -out public.cert -passin pass:123456789 diff --git a/tests/resources/test_dataset.sql b/tests/resources/test_dataset.sql new file mode 100644 index 0000000..d97a03a --- /dev/null +++ b/tests/resources/test_dataset.sql @@ -0,0 +1,3 @@ +INSERT INTO user +VALUES ('1daf7878-8ede-46ed-8b3e-120d37bf6819','maximebatista18@gmail.com', 'batista', 'maxime', 1450575459) + diff --git a/tests/src/org/tbasket/test/TestLayers.scala b/tests/src/org/tbasket/test/TestLayers.scala index 55cc535..cfef489 100644 --- a/tests/src/org/tbasket/test/TestLayers.scala +++ b/tests/src/org/tbasket/test/TestLayers.scala @@ -1,10 +1,13 @@ package org.tbasket.test -import org.tbasket.auth.Authentificator +import org.tbasket.auth.Authenticator import org.tbasket.config.ServerConfig import org.tbasket.data.Database import zio.{Task, ZLayer} +import java.nio.file.{Files, Path} +import java.sql.{DriverManager, Statement} + /* * Defines required test service layers * */ @@ -13,13 +16,33 @@ object TestLayers { val auth = { val publicKey = TestServerConfig.emitterCertificate.getPublicKey - val auth = new Authentificator(TestServerConfig.emitterURL, publicKey, TestServerConfig.emitterKeyAlgorithm) + val auth = new Authenticator(TestServerConfig.emitterURL, publicKey, TestServerConfig.emitterKeyAlgorithm) ZLayer.succeed(auth) } val db = { - new Database(TestServerConfig) + //ensure that the test table is always new in order to make tests on the same dataset all the time. + Files.deleteIfExists(Path.of("/tmp/test-database.sqlite")) + + //open database + val db = new Database(TestServerConfig) + + //fill the test database with a test dataset + val connection = DriverManager.getConnection("jdbc:sqlite:/tmp/test-database.sqlite") + val stmnt = connection.createStatement() + executeFile(stmnt, "table_init.sql") + executeFile(stmnt, "test_dataset.sql") + stmnt.close() + connection.close() + + db } - + private def executeFile(statement: Statement, url: String) = + val in = getClass.getClassLoader.getResourceAsStream(url) + val bytes = in.readAllBytes() + in.close() + + val requests = new String(bytes).split(';') + requests.foreach(statement.execute) } diff --git a/tests/src/org/tbasket/test/pages/LoginPageHandlerTests.scala b/tests/src/org/tbasket/test/pages/LoginPageHandlerTests.scala index f6828bb..a88b881 100644 --- a/tests/src/org/tbasket/test/pages/LoginPageHandlerTests.scala +++ b/tests/src/org/tbasket/test/pages/LoginPageHandlerTests.scala @@ -2,13 +2,14 @@ package org.tbasket.test.pages import io.getquill.jdbczio.Quill import io.getquill.{SnakeCase, SqliteZioJdbcContext} -import org.tbasket.auth.Authentificator +import org.tbasket.auth.Authenticator import org.tbasket.data.{Database, DatabaseContext} import org.tbasket.error.RegularException.InvalidRequest import org.tbasket.handler.HandlerUtils.parseAttribute import org.tbasket.handler.LoginPageHandler import org.tbasket.handler.LoginPageHandler.post import org.tbasket.test.TestLayers +import org.tbasket.test.pages.LoginPageHandlerTests.test import zio.* import zio.http.netty.client.ConnectionPool import zio.http.* @@ -16,10 +17,11 @@ import zio.http.model.{HeaderNames, Headers} import zio.http.model.Headers.Header import zio.json.* import zio.json.ast.{Json, JsonCursor} -import zio.test.{TestAspect, *} +import zio.test.* import zio.test.Assertion.* object LoginPageHandlerTests extends ZIOSpecDefault { + import LoginPageHandler.post import TestLayers.* @@ -48,29 +50,38 @@ object LoginPageHandlerTests extends ZIOSpecDefault { ) private def loginSpec = { - suite("login situation tests") ( + suite("login situation tests")( test("login with unknown account") { for - response <- post(Request.post(Body.fromString("""{"password":"123456","email":"maximebatista18@gmail.com"}"""), URL.empty)) + response <- post(Request.post(Body.fromString("""{"password":"123456","email":"unknownaccount@gmail.com"}"""), URL.empty)) json <- getJsonBody(response) errorType <- parseAttribute(json, "error", JsonCursor.field("error").isString) yield //assert that the response error is of type unauthorized and headers are Location: /register assert(errorType)(equalTo("unauthorized")) && assert(response)(hasField("headers", _.headers, hasSameElements(Headers.location("/register")))) + }, + + test("login with known account") { + for + response <- post(Request.post(Body.fromString("""{"password":"123456","email":"maximebatista18@gmail.com"}"""), URL.empty)) + json <- getJsonBody(response) + //errorType <- parseAttribute(json, "error", JsonCursor.field("error").isString) + yield + assert(response)(hasField("headers", _.headers, exists(hasField("key", _.key, equalTo(HeaderNames.setCookie))))) } ) } - override def spec = suite("/login page handler") ( + override def spec = suite("/login page handler")( requestsSpec, loginSpec ).provide( - db.datasourceLayer, - db.contextLayer, - auth, - ConnectionPool.fixed(1), - Scope.default, - ClientConfig.default, - Client.live) + db.datasourceLayer, + db.contextLayer, + auth, + ConnectionPool.fixed(1), + Scope.default, + ClientConfig.default, + Client.live) }