Increment now working, tests redacted, Currently configuring CI/CD
continuous-integration/drone/push Build is failing Details

production
Override-6 2 years ago
parent 798fbe9347
commit 83836d13f6

@ -0,0 +1,31 @@
kind: pipeline
type: docker
name: Deployment
trigger:
branch:
- production
- dev
steps:
- name: 'Unit Tests'
image: ubuntu:latest
commands:
- apt update && apt install openjdk-11-jdk -y
- ./gradlew :test
- name: deploy to server
image: ubuntu:latest
depends_on:
- 'Unit Tests'
environment:
SSH_PRIVATE_KEY:
from_secret: ???
SSH_PUBLIC_KEY:
from_secret: ???
USER:
from_secret: ???
IP:
from_secret: ???
commands:
- drone/deliver.sh $DRONE_BRANCH

1
.gitignore vendored

@ -2,3 +2,4 @@ build
.gradle
.idea
*/.gradle/
/log

@ -1,36 +1,58 @@
package org.tbasket.api
import org.apache.logging.log4j.LogManager
import org.tbasket.api.Endpoint.LOG
import org.tbasket.api.compute.APIRequestHandler
import zio._
import zio.http.ServerConfig.LeakDetectionLevel
import zio.http._
import zio.http.model.Method.{GET, POST}
import zio.http.model.Status
import scala.collection.mutable
class Endpoint(hostname: String, port: Int, rootPath: Option[String]) extends ZIOAppDefault {
class Endpoint(hostname: String, port: Int) extends ZIOAppDefault {
private val Root: Path = rootPath.map(Path.decode).getOrElse(Path.root)
private val handlers = mutable.HashMap.empty[String, APIRequestHandler]
def bind(path: String)(handler: APIRequestHandler): Unit = {
handlers.put(path, handler)
}
private val app = Http.collectZIO[Request] {
case r@_ -> Root / path if handlers.contains(path) =>
handlers(path).handle.provideEnvironment(ZEnvironment(r))
case _ -> path =>
ZIO.fail(new APIException(s"Unable to find a handler for page '$path'"))
//set generic required headers
private def transform(response: Response): Response = {
response.withAccessControlAllowOrigin("*")
}
private val app = Http.collect[Request] {
case r@GET -> _ / path if handlers.contains(path) =>
transform(handlers(path).get(r))
case r@POST -> _ / path if handlers.contains(path) =>
transform(handlers(path).post(r))
case r@method -> path =>
val ipInsights = r.remoteAddress
.map(ip => s": request received from $ip.")
.getOrElse("")
LOG.error(s"Was unable to find a handler for request '$path' with method $method ${ipInsights}")
Response(Status.NotFound)
}
val run = {
val config = ServerConfig.default
.port(port)
.leakDetection(LeakDetectionLevel.PARANOID)
val configLayer = ServerConfig.live(config)
(Server.install(app).flatMap { port =>
Console.printLine(s"Listening API entries on $hostname:$port$rootPath")
} *> ZIO.never).provide(configLayer, Server.live)
Server.install(app).flatMap { port =>
LOG.info(s"Listening API entries on $hostname:$port")
ZIO.never
}.provide(configLayer, Server.live)
}
}
object Endpoint {
final val LOG = LogManager.getLogger("API")
}

@ -1,11 +1,12 @@
package org.tbasket.api.compute
import org.tbasket.api.APIException
import zio.ZIO
import zio.http.model.Status
import zio.http.{Request, Response}
trait APIRequestHandler {
def handle: ZIO[Request, APIException, Response]
def get(request: Request): Response = Response(Status.MethodNotAllowed)
def post(request: Request): Response = Response(Status.MethodNotAllowed)
}

@ -2,7 +2,9 @@ plugins {
id 'java'
id 'java-library'
id 'scala'
id 'application'
id 'application' //for 'run' task
id 'com.adarshr.test-logger' version '3.2.0' //fancy prints during tests
id 'com.github.johnrengelman.shadow' version '7.1.2' //for optimised jar
}
final var scalaVersion = "2.13"
@ -15,15 +17,27 @@ repositories {
mavenCentral()
}
shadowJar {
archivesBaseName = "server"
}
dependencies {
implementation project(':API')
implementation project(':DB')
implementation "io.circe:circe-core_$scalaVersion:0.15.0-M1"
testImplementation "io.circe:circe-core_$scalaVersion:0.15.0-M1"
testImplementation "io.circe:circe-parser_$scalaVersion:0.15.0-M1"
}
testlogger {
theme 'mocha'
}
test {
useJUnitPlatform()
testlogger {
theme 'standard-parallel'
}
}
run {
@ -33,7 +47,6 @@ run {
allprojects {
apply plugin: 'scala'
apply plugin: 'java-library'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
@ -43,6 +56,9 @@ allprojects {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
implementation 'org.apache.logging.log4j:log4j-core:2.17.2'
implementation 'org.apache.logging.log4j:log4j-api:2.17.2'
implementation 'org.slf4j:slf4j-simple:2.0.4'
implementation "org.scala-lang:scala-library:$scalaVersion.10"
}

@ -0,0 +1,12 @@
#!/usr/bin/env bash
apt update && apt install openjdk-11-jdk sftp -y
PATH="$PATH:."
gradlew :shadowJar
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
echo "$SSH_PUBLIC_KEY" > ~/.ssh/id_rsa.pub
sftp "$USER@$IP:tbasket/" <<< $'put build/libs/server-all.jar drone/deploy.sh'

@ -0,0 +1,19 @@
SERVER_JAR_NAME="server-all.jar"
OLD_PID=$(ps -aux | grep "-jar $SERVER_JAR_NAME" | tr -s " " | cut -d " " -f2)
#if $OLD_PID is not empty but isn't a number, something went wrong
if [ "$OLD_PID" ] && ! grep -E -q "^[0-9]+$"; then
echo "error, unable to retrieve old server pid: $OLD_PID" >&2
exit 2
fi
if [ "$OLD_PID" ]; then
#will cause the old server to gracefully shutdown
echo "shutting down old server version ..."
kill SIGQUIT "$OLD_PID"
wait "$OLD_PID"
fi

@ -0,0 +1,40 @@
<?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 name="Database" additivity="false" includeLocation="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="LogFile"/>
</Logger>
<Logger name="API" additivity="false" includeLocation="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="LogFile"/>
</Logger>
<Logger name="Core" additivity="false" includeLocation="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="LogFile"/>
</Logger>
<Root level="ALL" includeLocation="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="LogFile"/>
</Root>
</Loggers>
</Configuration>

@ -11,7 +11,7 @@ object EndpointSetup {
final val EndpointUrlDefault = s"localhost:48485"
def setupEndpoint(): Endpoint = {
println("Initializing API endpoint...")
Main.LOG.debug("Initializing API endpoint...")
val endpoint = createEndpoint()
endpoint.bind("counter")(IncrementHandler)
endpoint
@ -21,13 +21,12 @@ object EndpointSetup {
val properties = new Properties()
val in = getClass.getClassLoader.getResourceAsStream("server.properties")
properties.load(in)
val (hostname, port, endpointPath) = properties
val (hostname, port) = properties
.getProperty(EndpointUrl, EndpointUrlDefault) match {
case s"$ip:$port/$endpointPath" => (ip, port.toInt, Some(endpointPath))
case s"$ip:$port" => (ip, port.toInt, None)
case s"$ip:$port" => (ip, port.toInt)
case v => throw new InternalBasketServerException(s"$EndpointUrl property value is wrong: $v must be <ip>:<port>/[endpointPath]")
}
new Endpoint(hostname, port, endpointPath)
new Endpoint(hostname, port)
}
}

@ -1,14 +1,18 @@
package org.tbasket
import org.apache.logging.log4j.LogManager
import zio._
import java.lang
import scala.io.StdIn
import scala.util.control.NonFatal
object Main {
final val LOG = LogManager.getLogger("Core")
def main(args: Array[String]): Unit = {
LOG.info("Starting server")
val endpoint = EndpointSetup.setupEndpoint()
val runtime = Runtime.default
Unsafe.unsafe { implicit u =>
@ -18,9 +22,12 @@ object Main {
throw e
}
}
LOG.info("Server successfully started")
println("enter to exit")
StdIn.readLine()
}
//add a shutdown hook to log when the server is about to get killed
lang.Runtime.getRuntime.addShutdownHook(new Thread(() => LOG.info("Server shutdowns")))
}

@ -1,23 +1,21 @@
package org.tbasket.compute
import org.tbasket.api.APIException
import org.tbasket.api.compute.APIRequestHandler
import zio.ZIO
import zio.http.model.Method._
import zio.http.{Request, Response}
object IncrementHandler extends APIRequestHandler {
private var i = 0
@volatile private var i = 0
def getCounter: Int = i
override def handle: ZIO[Request, APIException, Response] = {r: Request =>
r match {
case Request(_, _, GET, _, _, _) =>
ZIO.succeed(Response.json(s"value: $i"))
case Request(_, _, POST, _, _, _) =>
i += 1
ZIO.succeed(Response.ok)
Console
override def get(request: Request): Response = {
Response.json(s"{\"value\": $i}")
}
override def post(request: Request): Response = {
i += 1
println(s"Counter is now $i")
Response.ok
}
}

@ -0,0 +1,39 @@
package org.tbasket.test
import io.circe.parser._
import org.junit.jupiter.api.{Assertions, Test}
import org.tbasket.compute.IncrementHandler
import zio.http.model.Status
import zio.http.{Body, Path, Request, URL}
class IncrementRequestHandler {
private val url = URL(Path.decode("counter"))
@Test
def testMakeIncrement(): Unit = {
val last = IncrementHandler.getCounter
val response = IncrementHandler.post(Request.post(Body.empty, url))
Assertions.assertEquals(response.status, Status.Ok)
Assertions.assertEquals(last + 1, IncrementHandler.getCounter)
}
@Test
def testGetIncrement(): Unit = {
val counter = IncrementHandler.getCounter
val response = IncrementHandler.get(Request.post(Body.empty, url))
for {
json <- response.body.asString
} yield parse(json) match {
case Left(failure) => Assertions.fail(s"returned json is invalid ($failure)")
case Right(json) =>
val valueJsons = json.findAllByKey("value")
Assertions.assertEquals(1, valueJsons.size)
val valueCounter = valueJsons.head.asNumber.get.toInt.get
Assertions.assertEquals(counter, valueCounter)
}
Assertions.assertEquals(response.status, Status.Ok)
Assertions.assertEquals(counter, IncrementHandler.getCounter)
}
}