Commit 4b4bf31b authored by Andreas Muttscheller's avatar Andreas Muttscheller

Add more integration tests and make use of aws sdk instead of environment variables

parent 9571ad6a
......@@ -48,6 +48,7 @@ lazy val root = (project in file("."))
"com.amazonaws" % "aws-java-sdk-sns" % "1.11.488",
"com.amazonaws" % "aws-java-sdk-lambda" % "1.11.488",
"com.amazonaws" % "aws-java-sdk-elasticsearch" % "1.11.488",
"com.amazonaws" % "aws-java-sdk-api-gateway" % "1.11.488",
"com.amazonaws" % "aws-lambda-java-events" % "2.2.5",
"com.amazonaws" % "aws-lambda-java-core" % "1.2.0",
......
......@@ -27,14 +27,6 @@ provider:
IS_SERVERLESS: "true"
SERVERLESS_SERVICE: ${self:service}
SERVERLESS_STAGE: ${self:provider.stage}
ELASTICSEARCH_URL:
Fn::GetAtt: ["DelayInformationSearch", "DomainEndpoint"]
APIGATEWAY_URL:
Fn::Join:
- ""
- - "https://"
- Ref: "ApiGatewayRestApi"
- ".execute-api.${self:provider.region}.amazonaws.com/${self:provider.stage}"
# you can add packaging information here
......
......@@ -2,18 +2,30 @@ package de.codecentric.amuttsch.bahndelayinfo
import com.amazonaws.services.dynamodbv2.document.{DynamoDB, Table}
import com.amazonaws.services.dynamodbv2.{AmazonDynamoDB, AmazonDynamoDBClientBuilder}
import com.sksamuel.elastic4s.http.count.CountResponse
import com.sksamuel.elastic4s.http.search.SearchResponse
import com.sksamuel.elastic4s.http.{ElasticClient, RequestFailure, RequestSuccess}
import com.softwaremill.sttp._
import de.codecentric.amuttsch.bahndelayinfo.aws.{StationImporter, getServerlessServiceName}
import de.codecentric.amuttsch.bahndelayinfo.models.Station
import org.json4s.native.JsonMethods.parse
import org.json4s.{CustomSerializer, DefaultFormats, Formats, JNothing, JString}
import org.scalatest.{BeforeAndAfterAll, FunSpec}
import scala.io.Source
import scala.io.{BufferedSource, Source}
class StationImporterTest extends FunSpec with BeforeAndAfterAll {
private val customSerializer = new CustomSerializer[String](_ => (
{ case JString(s) => s },
{ case "" => JNothing case s: String => JString(s) }
import com.sksamuel.elastic4s.http.ElasticDsl._
private implicit val backend: SttpBackend[Id, Nothing] = HttpURLConnectionBackend()
private val customSerializer = new CustomSerializer[String](_ => ( {
case JString(s) => s
}, {
case "" => JNothing
case s: String => JString(s)
}
))
private implicit val jsonFormats: Formats = DefaultFormats + customSerializer
......@@ -21,23 +33,103 @@ class StationImporterTest extends FunSpec with BeforeAndAfterAll {
val ddb: DynamoDB = new DynamoDB(ddbClient)
val tableStations: Table = ddb.getTable(getServerlessServiceName("Stations"))
val stationJsonResource: BufferedSource = Source.fromResource("dbStations.json")
val stationJsonString: String = stationJsonResource.getLines().mkString("")
val stationJson: List[Station] = parse(stationJsonString).extract[List[Station]]
val esClient: ElasticClient = aws.elasticSearchClient()
override def beforeAll(): Unit = {
StationImporter.main(Array.empty)
StationImporter.main(Array.empty)
// Sleep a bit to allow ElasticSearch to refresh its index and make the results visible
Thread.sleep(2000)
}
override def afterAll(): Unit = {
esClient.close()
}
describe("StationImporter") {
it("should contain all elements from the json") {
it("should contain all elements from the json in DynamoDB") {
var itemCount = 0
tableStations.scan().forEach(_ => itemCount += 1)
val jsonResource = Source.fromResource("dbStations.json")
val jsonString = jsonResource.getLines().mkString("")
assert(stationJson.size == itemCount)
}
val json = parse(jsonString).extract[List[Station]]
it("should contain all elements from the json in ElasticSearch") {
val resp = esClient.execute {
count("stations")
}.await
var itemCount = 0
tableStations.scan().forEach(_ => itemCount += 1)
resp match {
case e: RequestFailure =>
fail(e.error.reason)
case results: RequestSuccess[CountResponse] =>
val jsonSize = stationJson.size
assert(jsonSize == results.result.count)
}
}
assert(json.size == itemCount)
it("should contain Frankfurt(Main)Hbf in DynamoDB") {
val ffmStation = stationJson.filter(_.eva == 8000105).head
val ffmItem = tableStations.getItem("eva", 8000105)
val ffmItemStation = parse(ffmItem.toJSON).extract[Station]
assert(ffmItemStation == ffmStation)
}
it("should contain Frankfurt(Main)Hbf in ElasticSearch") {
val ffmStation = stationJson.filter(_.eva == 8000105).head
val resp = esClient.execute {
search("stations") matchQuery("name", "Frankfurt(Main)Hbf")
}.await
val esStationList = resp match {
case _: RequestFailure =>
List()
case results: RequestSuccess[SearchResponse] =>
results.result.hits.hits.map(r => parse(r.sourceAsString).extract[Station]).toList
}
assert(esStationList.contains(ffmStation))
}
}
it("should contain Frankfurt(Main)Hbf in HTTP service with eva query") {
val ffmStation = stationJson.filter(_.eva == 8000105).head
val apiGatewayUrl = aws.getApiGatewayUrl
val response = sttp
.get(uri"$apiGatewayUrl/stations/?eva=8000105")
.send()
response.body match {
case Left(e) =>
fail(e)
case Right(body) =>
assert(parse(body).extract[Station] == ffmStation)
}
}
it("should contain Frankfurt(Main)Hbf in HTTP service with string query") {
val ffmStation = stationJson.filter(_.eva == 8000105).head
val apiGatewayUrl = aws.getApiGatewayUrl
val response = sttp
.get(uri"$apiGatewayUrl/stations/?q=Frankfurt(Main)Hbf")
.send()
response.body match {
case Left(e) =>
fail(e)
case Right(body) =>
val apiStationList = parse(body).extract[List[Station]]
assert(apiStationList.contains(ffmStation))
}
}
}
}
......@@ -22,6 +22,9 @@ object StationImporter extends App {
val tableStations: Table = ddb.getTable(getServerlessServiceName("Stations"))
val esClient = aws.elasticSearchClient()
esClient.execute {
deleteIndex("stations")
}.await
esClient.execute {
createIndex("stations")
}.await
......
package de.codecentric.amuttsch.bahndelayinfo
import com.amazonaws.regions.DefaultAwsRegionProviderChain
import com.amazonaws.services.apigateway.AmazonApiGatewayClientBuilder
import com.amazonaws.services.apigateway.model.GetRestApisRequest
import com.amazonaws.services.dynamodbv2.document.{Item, ItemCollection, ScanOutcome}
import com.amazonaws.services.elasticsearch.AWSElasticsearchClientBuilder
import com.amazonaws.services.elasticsearch.model.DescribeElasticsearchDomainRequest
import com.sksamuel.elastic4s.aws.Aws4ElasticClient
import com.sksamuel.elastic4s.http.{ElasticClient, ElasticProperties}
import scala.collection.JavaConverters._
import scala.collection.mutable
package object aws {
......@@ -40,4 +44,21 @@ package object aws {
val esEndpoint = s"${esProperties.protocol}://${esProperties.host}:${esProperties.port}"
Aws4ElasticClient(esEndpoint)
}
def getApiGatewayUrl: String = {
val service = scala.util.Properties.envOrElse("SERVERLESS_SERVICE", "")
val stage = scala.util.Properties.envOrElse("SERVERLESS_STAGE", "")
val agwClient = AmazonApiGatewayClientBuilder.standard().build()
val restApis = agwClient.getRestApis(new GetRestApisRequest().withLimit(500)).getItems.asScala
val region = new DefaultAwsRegionProviderChain().getRegion
restApis.find(_.getName == s"$stage-$service") match {
case Some(ra) =>
s"https://${ra.getId}.execute-api.$region.amazonaws.com/$stage"
case None =>
throw new RuntimeException(s"Environment variables SERVERLESS_SERVICE ($service) or SERVERLESS_STAGE ($stage) missing!")
}
}
}
......@@ -25,7 +25,7 @@ class Repository {
}
def searchStationByName(station: String): List[Station] = {
val apiGatewayUrl = scala.util.Properties.envOrElse("APIGATEWAY_URL", "")
val apiGatewayUrl = aws.getApiGatewayUrl
val response = sttp
.get(uri"$apiGatewayUrl/stations/?q=$station")
.send()
......
......@@ -72,7 +72,7 @@ sealed trait StationFinder extends SlackCommand with DynamoDbConnection {
if (stations.size == 1) {
Right(stations.head)
} else {
val apiGatewayUrl = scala.util.Properties.envOrElse("APIGATEWAY_URL", "")
val apiGatewayUrl = aws.getApiGatewayUrl
val response = sttp
.get(uri"$apiGatewayUrl/stations/?q=$station")
.send()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment