setting up tests
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
parent
d35a61212a
commit
dc501fded6
@ -0,0 +1,20 @@
|
|||||||
|
package org.tbasket.config
|
||||||
|
|
||||||
|
import pdi.jwt.JwtAlgorithm
|
||||||
|
import pdi.jwt.algorithms.JwtAsymmetricAlgorithm
|
||||||
|
import zio.http.URL
|
||||||
|
|
||||||
|
import java.security.cert.Certificate
|
||||||
|
|
||||||
|
trait ServerConfig {
|
||||||
|
def emitterURL: URL
|
||||||
|
|
||||||
|
def emitterCertificate: Certificate
|
||||||
|
|
||||||
|
def emitterKeyAlgorithm: JwtAsymmetricAlgorithm
|
||||||
|
|
||||||
|
def endpointPort: Int
|
||||||
|
|
||||||
|
def databaseConfigName: String
|
||||||
|
|
||||||
|
}
|
@ -1,22 +1,46 @@
|
|||||||
package org.tbasket.data
|
package org.tbasket.data
|
||||||
|
|
||||||
|
import io.getquill.*
|
||||||
import io.getquill.context.ZioJdbc.{DataSourceLayer, QuillZioExt}
|
import io.getquill.context.ZioJdbc.{DataSourceLayer, QuillZioExt}
|
||||||
import io.getquill.context.qzio.ZioContext
|
import io.getquill.context.qzio.ZioContext
|
||||||
import io.getquill.idiom.Idiom
|
import io.getquill.idiom.Idiom
|
||||||
import io.getquill.jdbczio.Quill
|
import io.getquill.jdbczio.Quill
|
||||||
import io.getquill.*
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.sqlite.SQLiteDataSource
|
import org.sqlite.{SQLiteDataSource, SQLiteException}
|
||||||
import org.tbasket.ServerConfig
|
import org.tbasket.config.ServerConfig
|
||||||
|
import org.tbasket.data.Database.LOG
|
||||||
import zio.*
|
import zio.*
|
||||||
|
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
|
import java.sql.SQLException
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
import javax.sql
|
import javax.sql
|
||||||
|
|
||||||
|
//TODO this class is a veritable fraud
|
||||||
class Database(config: ServerConfig):
|
class Database(config: ServerConfig):
|
||||||
|
|
||||||
val contextLayer = ZLayer.succeed(DatabaseContext(new SqliteZioJdbcContext(SnakeCase)))
|
private var initialized = false
|
||||||
val datasourceLayer = Quill.DataSource.fromPrefix("database")
|
|
||||||
|
|
||||||
|
|
||||||
|
val contextLayer = ZLayer.succeed(DatabaseContext(new SqliteZioJdbcContext(SnakeCase)))
|
||||||
|
val datasourceLayer = Quill.DataSource.fromPrefix(config.databaseConfigName).tap { ds =>
|
||||||
|
if (initialized) ZIO.succeed(ds)
|
||||||
|
else ZIO.attempt {
|
||||||
|
initialized = true
|
||||||
|
val requests = new String(getClass.getResourceAsStream("/table_init.sql").readAllBytes()).split(';')
|
||||||
|
val stmnt = ds.get.getConnection
|
||||||
|
.createStatement()
|
||||||
|
requests.foreach { sql =>
|
||||||
|
try {
|
||||||
|
stmnt.execute(sql)
|
||||||
|
} catch {
|
||||||
|
case e: SQLException if e.getMessage.contains("already exists") =>
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmnt.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Database {
|
||||||
|
val LOG = LogManager.getLogger("Database")
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
test-database {
|
||||||
|
dataSourceClassName = org.sqlite.SQLiteDataSource
|
||||||
|
dataSource {
|
||||||
|
url = "jdbc:sqlite:/tmp/test-database.sqlite"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Configuration status="WARN">
|
||||||
|
|
||||||
|
<Appenders>
|
||||||
|
<Console name="Console" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout disableAnsi="false"
|
||||||
|
pattern="%style{[%d{HH:mm:ss,SSS}]}{magenta} [%highlight{%-5p}{FATAL=red, ERROR=red, WARN=yellow, INFO=blue, DEBUG=green, TRACE=normal} _ %-6logger] %style{-}{normal} %highlight{%m%n}{FATAL=red, ERROR=red, WARN=yellow, INFO=blue, DEBUG=green, TRACE=normal}"/>
|
||||||
|
</Console>
|
||||||
|
<RollingFile name="LogFile"
|
||||||
|
fileName="log/server-current.log"
|
||||||
|
filePattern="log/archives/server-%d{yyyy-MM-dd}.log"
|
||||||
|
append="true">
|
||||||
|
<PatternLayout disableAnsi="false"
|
||||||
|
pattern="[%d{HH:mm:ss,SSS}] [%-5p _ %-6logger] - %m%n"/>
|
||||||
|
<Policies>
|
||||||
|
<TimeBasedTriggeringPolicy/>
|
||||||
|
</Policies>
|
||||||
|
</RollingFile>
|
||||||
|
</Appenders>
|
||||||
|
|
||||||
|
<Loggers>
|
||||||
|
<Logger level="WARN" name="JWTEmitter" additivity="false" includeLocation="false">
|
||||||
|
<AppenderRef ref="Console"/>
|
||||||
|
<AppenderRef ref="LogFile"/>
|
||||||
|
</Logger>
|
||||||
|
<Root level="WARN" includeLocation="false">
|
||||||
|
<AppenderRef ref="Console"/>
|
||||||
|
<AppenderRef ref="LogFile"/>
|
||||||
|
</Root>
|
||||||
|
</Loggers>
|
||||||
|
|
||||||
|
</Configuration>
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.tbasket.test
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
object TestEmitter:
|
||||||
|
val PORT = 5455
|
||||||
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
|||||||
|
package org.tbasket.test
|
||||||
|
|
||||||
|
import org.tbasket.auth.Authentificator
|
||||||
|
import org.tbasket.config.ServerConfig
|
||||||
|
import org.tbasket.data.Database
|
||||||
|
import zio.{Task, ZLayer}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Defines required test service layers
|
||||||
|
* */
|
||||||
|
object TestLayers {
|
||||||
|
|
||||||
|
|
||||||
|
val auth = {
|
||||||
|
val publicKey = TestServerConfig.emitterCertificate.getPublicKey
|
||||||
|
val auth = new Authentificator(TestServerConfig.emitterURL, publicKey, TestServerConfig.emitterKeyAlgorithm)
|
||||||
|
ZLayer.succeed(auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
val db = {
|
||||||
|
new Database(TestServerConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package org.tbasket.test
|
||||||
|
|
||||||
|
import org.tbasket.config.ServerConfig
|
||||||
|
import pdi.jwt.JwtAlgorithm
|
||||||
|
import zio.http.URL
|
||||||
|
import TestEmitter.PORT
|
||||||
|
import pdi.jwt.algorithms.JwtAsymmetricAlgorithm
|
||||||
|
|
||||||
|
import java.nio.file.{Files, Path}
|
||||||
|
import java.security.cert.{Certificate, CertificateFactory}
|
||||||
|
|
||||||
|
object TestServerConfig extends ServerConfig {
|
||||||
|
|
||||||
|
private final val CertFactory = CertificateFactory.getInstance("X509")
|
||||||
|
|
||||||
|
override def emitterURL: URL = URL.fromString(s"http://localhost/$PORT").getOrElse(null)
|
||||||
|
|
||||||
|
override def emitterCertificate: Certificate =
|
||||||
|
CertFactory.generateCertificate(Files.newInputStream(Path.of("keys/public.cert")))
|
||||||
|
|
||||||
|
override def emitterKeyAlgorithm: JwtAsymmetricAlgorithm = JwtAlgorithm.RS256
|
||||||
|
|
||||||
|
override def endpointPort: Int = 5454
|
||||||
|
|
||||||
|
override def databaseConfigName: String = "test-database"
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package org.tbasket.test.pages
|
||||||
|
|
||||||
|
import io.getquill.jdbczio.Quill
|
||||||
|
import io.getquill.{SnakeCase, SqliteZioJdbcContext}
|
||||||
|
import org.tbasket.auth.Authentificator
|
||||||
|
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 zio.*
|
||||||
|
import zio.http.netty.client.ConnectionPool
|
||||||
|
import zio.http.*
|
||||||
|
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.Assertion.*
|
||||||
|
|
||||||
|
object LoginPageHandlerTests extends ZIOSpecDefault {
|
||||||
|
import LoginPageHandler.post
|
||||||
|
import TestLayers.*
|
||||||
|
|
||||||
|
private def getJsonBody(r: Response): Task[Json] = {
|
||||||
|
for
|
||||||
|
body <- r.body.asString
|
||||||
|
json <- ZIO.fromEither(body.fromJson[Json]).mapError(new Exception(_))
|
||||||
|
yield json
|
||||||
|
}
|
||||||
|
|
||||||
|
private def requestsSpec = suite("erroned request body tests")(
|
||||||
|
ZIO.attempt(Map(
|
||||||
|
"empty packet" -> Body.empty,
|
||||||
|
"with no mail attribute" -> Body.fromString("""{"password":"1234"}"""),
|
||||||
|
"with no password attribute" -> Body.fromString("""{"email":"valid.mail@x.y"}"""),
|
||||||
|
"with invalid json" -> Body.fromString("""this is a corrupted json""")
|
||||||
|
)).map(_.map((name, body) =>
|
||||||
|
test(name) {
|
||||||
|
for
|
||||||
|
response <- post(Request.post(body, URL.empty))
|
||||||
|
json <- getJsonBody(response)
|
||||||
|
errorType <- parseAttribute(json, "error", JsonCursor.field("error").isString)
|
||||||
|
yield assertTrue(errorType == "invalid request")
|
||||||
|
}
|
||||||
|
))
|
||||||
|
)
|
||||||
|
|
||||||
|
private def loginSpec = {
|
||||||
|
suite("login situation tests") (
|
||||||
|
test("login with unknown 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 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"))))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def spec = suite("/login page handler") (
|
||||||
|
requestsSpec,
|
||||||
|
loginSpec
|
||||||
|
).provide(
|
||||||
|
db.datasourceLayer,
|
||||||
|
db.contextLayer,
|
||||||
|
auth,
|
||||||
|
ConnectionPool.fixed(1),
|
||||||
|
Scope.default,
|
||||||
|
ClientConfig.default,
|
||||||
|
Client.live)
|
||||||
|
}
|
Reference in new issue