Skip to content

Commit 633593e

Browse files
committed
Fix tests:
* Since the acceptance and unit test from different bounded context run in parallel, I had to split the acceptance ones in a different database * Move the docker things to the root directory in order to follow the same convention as with other DDD example repos * Update MySQL container image version and connector library in order to avoid SSL errors (not acomplished, so disabled SSL. It's due to an error with JVM >= 11) * Rename project from Scala HTTP API to CQRS DDD Scala Example in the `README.md` and other points such as the container names and application JAR * Fix run command trying to run a non existing `Launcher` class (it was named after `Starter`, now it's renamed) * Fix backoffice consumers application launching
1 parent cc15167 commit 633593e

File tree

22 files changed

+109
-81
lines changed

22 files changed

+109
-81
lines changed

.env.dist

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Define here your desired values for each variable
2+
# and copy this `.env.dist` file to this very same directory with the `.env` name
3+
# in order to be used by the `docker-compose.yml`
4+
5+
# MySQL container variables
6+
MYSQL_HOST=codelytv-cqrs_ddd_scala_example-mysql
7+
MYSQL_PORT=3306
8+
MYSQL_ROOT_PASSWORD=c0d3ly
9+
MYSQL_DATABASE=cqrs_ddd_scala_example
10+
11+
PHP_IDE_CONFIG=serverName=CodelyTvCqrsDddScalaExample
12+
13+
# RabbitMQ container variables
14+
RABBITMQ_DEFAULT_USER=codelytv
15+
RABBITMQ_DEFAULT_PASS=c0d3ly

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ src/*/target
1414
app/target
1515

1616
# Environment variables file intended for customize the Docker containers parameters letting each developer has its own values.
17-
docker/.env
17+
.env
1818

1919
# Application log file and compressed previous logs (see conf/logback.xml)
2020
var/log/app_log.json

.travis.yml

-2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ cache:
2121
- $HOME/.sbt/boot/
2222

2323
before_install:
24-
- cd docker/
2524
- cp .env.dist .env
2625
- docker-compose up -d
27-
- cd ..
2826
- sbt "shared/createDbTables"
2927

3028
script:

README.md

+16-10
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ One of the goals of this project is to serve as an example for the [course on Sc
4444
| JSON marshalling | [Spray JSON](https://github.com/spray/spray-json) | [User](src/main/tv/codely/scala_http_api/module/user/infrastructure/marshaller/UserJsonFormatMarshaller.scala) & [User attributes](src/main/tv/codely/scala_http_api/module/user/infrastructure/marshaller/UserNameJsonFormatMarshaller.scala) marshallers |
4545
| Database integration | [Doobie](http://tpolecat.github.io/doobie/) | [Video repository](src/main/tv/codely/scala_http_api/module/video/infrastructure/repository/DoobieMySqlVideoRepository.scala) & [its corresponding integration test](src/test/tv/codely/scala_http_api/module/video/infrastructure/repository/DoobieMySqlVideoRepositoryShould.scala) |
4646
| Domain events publishing | [Akka RabbitMQ](https://github.com/NewMotion/akka-rabbitmq) | [Publisher implementation](src/main/tv/codely/scala_http_api/module/shared/infrastructure/message_broker/rabbitmq/RabbitMqMessagePublisher.scala) & [its corresponding integration test](src/test/tv/codely/scala_http_api/module/shared/infrastructure/message_broker/rabbitmq/RabbitMqMessagePublisherShould.scala) |
47-
| Infrastructure management | [Docker](https://www.docker.com/) | [Docker Compose definition](docker/docker-compose.yml) |
47+
| Infrastructure management | [Docker](https://www.docker.com/) | [Docker Compose definition](docker-compose.yml) |
4848
| Logging | [ScalaLogging](https://github.com/typesafehub/scala-logging)<br> + [Logback](https://logback.qos.ch/)<br> + [Logstash encoder](https://github.com/logstash/logstash-logback-encoder) | [Logback configuration](conf/logback.xml), [logger implementation](src/main/tv/codely/scala_http_api/module/shared/infrastructure/logger/scala_logging/ScalaLoggingLogger.scala) & [its corresponding integration test](src/test/tv/codely/scala_http_api/module/shared/infrastructure/logger/scala_logging/ScalaLoggingLoggerShould.scala) |
4949
| Command line command | [Scopt](https://github.com/scopt/scopt) | [Database tables creation script](src/main/tv/codely/scala_http_api/entry_point/cli/DbTablesCreator.scala) |
5050
| Distribution/deploy | [SBT Native packager](http://sbt-native-packager.readthedocs.io/en/latest/) | [Build & deploy instructions](#Deploy) |
@@ -57,23 +57,29 @@ One of the goals of this project is to serve as an example for the [course on Sc
5757
## Environment setup
5858

5959
### Install the needed tools
60-
1. Clone this repository: `git clone https://github.com/CodelyTV/scala-http-api.git scala-http-api`
60+
1. Clone this repository: `git clone https://github.com/CodelyTV/cqrs-ddd-scala-example.git cqrs-ddd-scala-example`
6161
2. Download and install [Docker compose](https://docs.docker.com/compose/install/). We'll need it in order to run all the project infrastructure.
6262
3. Download and install [SBT](http://www.scala-sbt.org/download.html)
6363

6464
### Prepare the application environment
65-
1. Copy [the Docker environment variables config file](docker/.env.dist) and tune it with your desired values: `cp docker/.env.dist docker/.env`
66-
2. Start Docker and bring up the project needed containers: `cd docker/; docker-compose up -d; cd ..`
65+
1. Copy [the Docker environment variables config file](.env.dist) and tune it with your desired values: `cp .env.dist .env`
66+
2. Start Docker and bring up the project needed containers: `docker-compose up -d`
6767
3. Create the database tables in your Docker MySQL container: `sbt createDbTables`
6868

6969
### Run the tests and start the HTTP server
7070
1. Enter into the SBT console: `sbt`
7171
2. Run the tests: `t`
72-
3. Start the local server: `run`
72+
3. Start the local server: `app/run mooc-api` (if you run the app from outside SBT: `sbt "app/run mooc-api"`)
7373
4. Request for the server status: `curl http://localhost:8080/status`
7474
5. Take a look at the courses related to this repository (Spanish) just in case you're interested into them!
7575
* [Introducción a Scala](https://pro.codely.tv/library/introduccion-a-scala/63278/about/)
7676
* [API HTTP con Scala y Akka](https://pro.codely.tv/library/api-http-con-scala-y-akka/66747/about/)
77+
* [Programación funcional: Refactorizando código orientado a objetos con TypeClasses](https://pro.codely.tv/library/programacion-funcional-refactorizando-codigo-orientado-a-objetos-con-typeclasses/about/)
78+
* [Principios SOLID Aplicados](https://pro.codely.tv/library/principios-solid-aplicados/77070/about/)
79+
* [Arquitectura Hexagonal](https://pro.codely.tv/library/arquitectura-hexagonal/66748/about/)
80+
* [Command Query Responsibility Segregation](https://pro.codely.tv/library/cqrs-command-query-responsibility-segregation-3719e4aa/62554/about/)
81+
* [Comunicación entre microservicios: Event-Driven Architecture](https://pro.codely.tv/library/comunicacion-entre-microservicios-event-driven-architecture/74823/about/)
82+
* [Domain-Driven Design](https://pro.codely.tv/library/domain-driven-design-ddd/87157/about/)
7783

7884
### Pre-push Git hook
7985

@@ -100,17 +106,17 @@ If you want more information on the logging policies and appenders, [take a look
100106
We use [SBT Native Packager](http://sbt-native-packager.readthedocs.io/en/latest/) in order to package the app in single Jar file that you can execute.
101107

102108
1. Create the universal package: `sbt universal:packageBin`.
103-
2. Extract the generated zip: `unzip target/universal/codelytv-scala-http-api-1.0.zip -d ~/var/www/` which will contain:
109+
2. Extract the generated zip: `unzip target/universal/codelytv-cqrs-ddd-scala-example-1.0.zip -d ~/var/www/` which will contain:
104110
* `bin/`: All the executable binaries of our main classes in Unix and Windows (bat) format
105111
* `lib/`: All the project dependencies jar files.
106112
3. Run the main app binary:
107-
* Without specifying any parameters (OK for this example app): `~/var/www/codelytv-scala-http-api-1.0/bin/codelytv-scala-http-api`
108-
* Specifying parameters for the JVM: `~/var/www/codelytv-scala-http-api-1.0/bin/codelytv-scala-http-api -Dconfig.resource=application/$CONFIG_PATH`
109-
* Specifying application parameters: `~/var/www/codelytv-scala-http-api-1.0/bin/codelytv-scala-http-api -Dconfig.resource=application/$CONFIG_PATH -- -appParam`
113+
* Without specifying any parameters (OK for this example app): `~/var/www/codelytv-cqrs-ddd-scala-example-1.0/bin/codelytv-cqrs-ddd-scala-example`
114+
* Specifying parameters for the JVM: `~/var/www/codelytv-cqrs-ddd-scala-example-1.0/bin/codelytv-cqrs-ddd-scala-example -Dconfig.resource=application/$CONFIG_PATH`
115+
* Specifying application parameters: `~/var/www/codelytv-cqrs-ddd-scala-example-1.0/bin/codelytv-cqrs-ddd-scala-example -Dconfig.resource=application/$CONFIG_PATH -- -appParam`
110116

111117
## About
112118

113-
This hopefully helpful utility has been developed by [CodelyTV](https://github.com/CodelyTV) and [contributors](https://github.com/CodelyTV/scala-http-api/graphs/contributors).
119+
This hopefully helpful utility has been developed by [CodelyTV](https://github.com/CodelyTV) and [contributors](https://github.com/CodelyTV/cqrs-ddd-scala-example/graphs/contributors).
114120

115121
We'll try to maintain this project as simple as possible, but Pull Requests are welcome!
116122

app/main/tv/codely/Starter.scala renamed to app/main/tv/codely/Launcher.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import tv.codely.backoffice.consumer.BackofficeConsumerApp
55
import tv.codely.mooc.api.MoocApiApp
66
import tv.codely.mooc.consumer.MoocConsumerApp
77

8-
object Starter {
8+
object Launcher {
99
private val MoocApiArgument = "mooc-api"
1010
private val MoocConsumersArgument = "mooc-consumers"
1111

1212
private val BackofficeApiArgument = "backoffice-api"
13-
private val BackofficeConsumersArgument = "backoffice-api"
13+
private val BackofficeConsumersArgument = "backoffice-consumers"
1414

1515
def main(args: Array[String]): Unit = {
1616
if (args.length != 1) {

app/test/tv/codely/AcceptanceSpec.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ import tv.codely.shared.infrastructure.dependency_injection.SharedModuleDependen
1414
import tv.codely.shared.infrastructure.doobie.{DoobieDbConnection, JdbcConfig}
1515

1616
abstract class AcceptanceSpec extends WordSpec with Matchers with ScalaFutures with ScalatestRouteTest {
17-
private val actorSystemName = "scala-http-api-acceptance-test"
17+
private val actorSystemName = "cqrs-ddd-scala-example-acceptance-test"
1818

1919
private val appConfig = ConfigFactory.load("application")
20-
private val dbConfig = JdbcConfig(appConfig.getConfig("database"))
20+
private val dbConfig = JdbcConfig(appConfig.getConfig("acceptance-tests-database"))
2121
private val publisherConfig = RabbitMqConfig(appConfig.getConfig("message-publisher"))
2222

2323
private val sharedDependencies = new SharedModuleDependencyContainer(actorSystemName, dbConfig, publisherConfig)

database/users.sql

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ CREATE TABLE users (
77
UNIQUE KEY u_user_id (user_id)
88
)
99
ENGINE = InnoDB
10-
DEFAULT CHARSET = utf8mb4;
10+
DEFAULT CHARSET = utf8mb4
11+
COLLATE=utf8mb4_unicode_ci;

database/videos.sql

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ CREATE TABLE videos (
1010
UNIQUE KEY u_video_id (video_id)
1111
)
1212
ENGINE = InnoDB
13-
DEFAULT CHARSET = utf8mb4;
13+
DEFAULT CHARSET = utf8mb4
14+
COLLATE=utf8mb4_unicode_ci;

docker-compose.yml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
version: '3'
2+
3+
services:
4+
mysql:
5+
container_name: codelytv-cqrs_ddd_scala_example-mysql
6+
image: mysql:8.0
7+
restart: unless-stopped
8+
ports:
9+
- "3316:3306"
10+
env_file:
11+
- .env
12+
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
13+
volumes:
14+
- ./etc/infrastructure/mysql/init:/docker-entrypoint-initdb.d
15+
16+
rabbitmq:
17+
container_name: codelytv-cqrs_ddd_scala_example-rabbitmq
18+
image: rabbitmq:3.7-management
19+
restart: unless-stopped
20+
ports:
21+
- "5672:5672"
22+
- "8181:15672"
23+
env_file:
24+
- .env

docker/.env.dist

-10
This file was deleted.

docker/docker-compose.yml

-25
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CREATE DATABASE IF NOT EXISTS `cqrs_ddd_scala_example`;
2+
CREATE DATABASE IF NOT EXISTS `cqrs_ddd_scala_example_acceptance_tests`;
3+
4+
CREATE USER 'root'@'localhost' IDENTIFIED BY 'c0d3ly';
5+
GRANT ALL ON *.* TO 'root'@'%';

project/Dependencies.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ object Dependencies {
1414
"com.typesafe.akka" %% "akka-stream" % Versions.akka, // Explicit dependency due to: https://bit.ly/akka-http-25
1515
"com.typesafe.akka" %% "akka-http-spray-json" % Versions.akkaHttp,
1616
"org.tpolecat" %% "doobie-core" % "0.5.0",
17-
"mysql" % "mysql-connector-java" % "5.1.45",
17+
"mysql" % "mysql-connector-java" % "8.0.15",
1818
"com.github.scopt" %% "scopt" % "3.7.0", // Command Line Commands such as de DbTablesCreator
1919
"ch.qos.logback" % "logback-classic" % "1.2.3", // Logging backend implementation
2020
"com.typesafe.scala-logging" %% "scala-logging" % "3.7.2", // SLF4J Scala wrapper

src/mooc/main/tv/codely/mooc/shared/infrastructure/marshaller/DomainEventsMarshaller.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ object DomainEventsMarshaller {
1616
}
1717

1818
override def read(jv: JsValue): Message = jv.asJsObject.getFields("type") match {
19-
case Seq(JsString("codelytv_scala_api.video_created")) => jv.convertTo[VideoCreated]
20-
case Seq(JsString("codelytv_scala_api.user_registered")) => jv.convertTo[UserRegistered]
19+
case Seq(JsString("cqrs_ddd_scala_example.video_created")) => jv.convertTo[VideoCreated]
20+
case Seq(JsString("cqrs_ddd_scala_example.user_registered")) => jv.convertTo[UserRegistered]
2121
case Seq(JsString(unknown)) =>
2222
throw DeserializationException(s"Unknown message type to read <$unknown>")
2323
}

src/shared/conf/application.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ include "akka-http"
22
include "database"
33
include "message-publisher"
44

5-
main-actor-system.name = "scala-http-api"
5+
main-actor-system.name = "cqrs-ddd-scala-example"

src/shared/conf/database.conf

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
database {
2-
driver = "com.mysql.jdbc.Driver",
3-
url = "jdbc:mysql://127.0.0.1:3316/codelytv_scala_api?useUnicode=true&character_set_server=utf8mb4&verifyServerCertificate=false&useSSL=true",
4-
user = "codelytv",
2+
driver = "com.mysql.cj.jdbc.Driver",
3+
url = "jdbc:mysql://127.0.0.1:3316/cqrs_ddd_scala_example?useUnicode=true&character_set_server=utf8mb4&sslMode=DISABLED",
4+
user = "root",
5+
password = "c0d3ly"
6+
}
7+
acceptance-tests-database {
8+
driver = "com.mysql.cj.jdbc.Driver",
9+
url = "jdbc:mysql://127.0.0.1:3316/cqrs_ddd_scala_example_acceptance_tests?useUnicode=true&character_set_server=utf8mb4&sslMode=DISABLED",
10+
user = "root",
511
password = "c0d3ly"
612
}

src/shared/main/tv/codely/shared/domain/bus/Message.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package tv.codely.shared.domain.bus
33
import tv.codely.shared.domain.bus.Message.application
44

55
object Message {
6-
val application: String = "codelytv_scala_api"
6+
val application: String = "cqrs_ddd_scala_example"
77
}
88

99
abstract class Message {

src/shared/main/tv/codely/shared/infrastructure/bus/rabbitmq/RabbitMqMessagePublisher.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ final class RabbitMqMessagePublisher(channelFactory: RabbitMqChannelFactory) ext
99

1010
// Use the default nameless exchange in order to route the published messages based on
1111
// the mapping between the message routing key and the queue names.
12-
// Example: A message with routing key "codelytv_scala_api.video_created"
13-
// will be routed to the "codelytv_scala_api.video_created" queue.
12+
// Example: A message with routing key "cqrs_ddd_scala_example.video_created"
13+
// will be routed to the "cqrs_ddd_scala_example.video_created" queue.
1414
private val exchange = ""
1515

1616
private def createQueueIfNotExists(name: String) = {

src/shared/main/tv/codely/shared/infrastructure/environment/DbTablesCreator.scala

+21-14
Original file line numberDiff line numberDiff line change
@@ -40,26 +40,33 @@ object DbTablesCreator {
4040
}
4141

4242
parser.parse(args, CommandConfig()).fold(println("[ERROR] Invalid parameters")) { commandConfig =>
43-
val dbConfig = JdbcConfig(ConfigFactory.load("application").getConfig("database"))
44-
val dbNameOption = for (grouped <- databaseNameFromUrlRegex findFirstMatchIn dbConfig.url) yield grouped group 1
43+
connectAndExecute(databaseConfigKey = "database", createTables(commandConfig.tablesFolder))
44+
connectAndExecute(databaseConfigKey = "acceptance-tests-database", createTables(commandConfig.tablesFolder))
45+
}
46+
}
4547

46-
dbNameOption.fold(
47-
println(s"[ERROR] We couldn't extract the DB name from the DB URL configuration parameter: ${dbConfig.url}")
48-
) { dbName =>
49-
Try(Class.forName(dbConfig.driver)).toOption.fold(
50-
println(s"[ERROR] Invalid driver specified in the database config: ${dbConfig.driver}")
51-
) { _ =>
52-
val connection = DriverManager.getConnection(dbConfig.url, dbConfig.user, dbConfig.password)
48+
private def connectAndExecute(
49+
databaseConfigKey: String,
50+
commandToExecute: (String, Connection) => Unit
51+
): Unit = {
52+
val dbConfig = JdbcConfig(ConfigFactory.load("application").getConfig(databaseConfigKey))
53+
val dbNameOption = for (grouped <- databaseNameFromUrlRegex findFirstMatchIn dbConfig.url) yield grouped group 1
5354

54-
createTables(dbName, commandConfig.tablesFolder, connection)
55+
dbNameOption.fold(
56+
println(s"[ERROR] We couldn't extract the DB name from the DB URL configuration parameter: ${dbConfig.url}")
57+
) { dbName =>
58+
Try(Class.forName(dbConfig.driver)).toOption.fold(
59+
println(s"[ERROR] Invalid driver specified in the database config: ${dbConfig.driver}")
60+
) { _ =>
61+
val connection = DriverManager.getConnection(dbConfig.url, dbConfig.user, dbConfig.password)
5562

56-
connection.close()
57-
}
63+
commandToExecute(dbName, connection)
64+
65+
connection.close()
5866
}
5967
}
6068
}
61-
62-
private def createTables(dbName: String, tablesFolder: String, connection: Connection): Unit = {
69+
private def createTables(tablesFolder: String)(dbName: String, connection: Connection): Unit = {
6370
val tablesFolderFile = new File(tablesFolder)
6471
val tablesFiles = tablesFolderFile.listFiles()
6572

src/shared/main/tv/codely/shared/infrastructure/logger/ScalaLoggingLogger.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import org.slf4j.MDC
55
import tv.codely.shared.domain.logger.Logger
66

77
final class ScalaLoggingLogger extends Logger {
8-
private val logger = ScalaLogging(name = "codelytv_scala_api")
8+
private val logger = ScalaLogging(name = "cqrs_ddd_scala_example")
99

1010
override def info(message: String, context: Map[String, Any] = Map.empty): Unit =
1111
addContextParameters(context, log = logger.info(message))

src/shared/test/tv/codely/shared/infrastructure/integration/IntegrationTestCase.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import tv.codely.shared.infrastructure.doobie.{DoobieDbConnection, JdbcConfig}
1111
import tv.codely.shared.infrastructure.unit.UnitTestCase
1212

1313
trait IntegrationTestCase extends UnitTestCase {
14-
private val actorSystemName = "scala-http-api-integration-test"
14+
private val actorSystemName = "cqrs-ddd-scala-example-integration-test"
1515

1616
private val appConfig = ConfigFactory.load("application")
1717
private val dbConfig = JdbcConfig(appConfig.getConfig("database"))

src/shared/test/tv/codely/shared/infrastructure/logger/ScalaLoggingLoggerShould.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ final class ScalaLoggingLoggerShould extends IntegrationTestCase {
100100
"@timestamp" -> JsString("We'll not be able to compare this value"),
101101
"@version" -> JsNumber(1),
102102
"message" -> JsString(message),
103-
"logger_name" -> JsString("codelytv_scala_api"),
103+
"logger_name" -> JsString("cqrs_ddd_scala_example"),
104104
"thread_name" -> JsString(currentThreadName),
105105
"level" -> JsString(level),
106106
"level_value" -> JsNumber(levelValue)

0 commit comments

Comments
 (0)