From 423239af8eb223d427a933afd80a0cd5fadd8433 Mon Sep 17 00:00:00 2001
From: Artem Sidorkin <artem.sidorkin@digitalarrowtech.com>
Date: Fri, 4 Dec 2020 18:09:12 +0300
Subject: [PATCH] Added db id migration testing.

---
 _build-and-test-all.sh                        | 23 +++++++++++
 build-and-test-all-mysql.sh                   |  1 +
 build-and-test-all-postgres.sh                |  1 +
 build.gradle                                  |  5 ++-
 docker-compose-env-files/db-id-gen.env        |  1 +
 docker-compose-env-files/empty.env            |  0
 docker-compose-mysql.yml                      |  5 +++
 docker-compose-postgres.yml                   |  5 +++
 gradle.properties                             |  9 ++---
 migration-tests/build.gradle                  | 18 +++++++++
 .../DbIdMigrationVerificationTest.java        | 39 +++++++++++++++++++
 .../resources/application-mssql.properties    |  4 ++
 .../resources/application-postgres.properties |  4 ++
 .../src/test/resources/application.properties |  4 ++
 settings.gradle                               |  2 +
 wait-for-services.sh                          | 21 +++++++---
 16 files changed, 130 insertions(+), 12 deletions(-)
 create mode 100644 docker-compose-env-files/db-id-gen.env
 create mode 100644 docker-compose-env-files/empty.env
 create mode 100644 migration-tests/build.gradle
 create mode 100644 migration-tests/src/test/java/io/eventuate/examples/tram/sagas/ordersandcustomers/migration/DbIdMigrationVerificationTest.java
 create mode 100644 migration-tests/src/test/resources/application-mssql.properties
 create mode 100644 migration-tests/src/test/resources/application-postgres.properties
 create mode 100644 migration-tests/src/test/resources/application.properties

diff --git a/_build-and-test-all.sh b/_build-and-test-all.sh
index 6c0610e5..9c387b3d 100755
--- a/_build-and-test-all.sh
+++ b/_build-and-test-all.sh
@@ -27,4 +27,27 @@ ${dockerall}Up
 
 ./gradlew :end-to-end-tests:cleanTest :end-to-end-tests:test
 
+./wait-for-services.sh localhost readers/${READER}/finished "8099"
+
+migration_file="migration_scripts/${DATABASE}/migration.sql"
+
+rm -f $migration_file
+if [ "${DATABASE}" == "mysql" ]; then
+  curl https://raw.githubusercontent.com/eventuate-foundation/eventuate-common/wip-db-id-gen/mysql/4.initialize-database-db-id.sql --output $migration_file --create-dirs
+  cat $migration_file | ./mysql-cli.sh -i
+elif [ "${DATABASE}" == "postgres" ]; then
+  curl https://raw.githubusercontent.com/eventuate-foundation/eventuate-common/wip-db-id-gen/postgres/5.initialize-database-db-id.sql --output $migration_file --create-dirs
+  cat $migration_file | ./postgres-cli.sh -i
+else
+  echo "Unknown Database"
+  exit 99
+fi
+rm -f $migration_file
+
+${dockerall}Up -P envFile=docker-compose-env-files/db-id-gen.env
+
+./gradlew :end-to-end-tests:cleanTest :end-to-end-tests:test
+
+./gradlew -P verifyDbIdMigration=true :migration-tests:cleanTest migration-tests:test
+
 ${dockerall}Down
\ No newline at end of file
diff --git a/build-and-test-all-mysql.sh b/build-and-test-all-mysql.sh
index f022feb0..45d2c8f8 100755
--- a/build-and-test-all-mysql.sh
+++ b/build-and-test-all-mysql.sh
@@ -3,5 +3,6 @@
 set -e
 
 export DATABASE=mysql
+export READER=MySqlReader
 
 ./_build-and-test-all.sh
diff --git a/build-and-test-all-postgres.sh b/build-and-test-all-postgres.sh
index 26bd526e..6e7a5bd5 100755
--- a/build-and-test-all-postgres.sh
+++ b/build-and-test-all-postgres.sh
@@ -3,6 +3,7 @@
 set -e
 
 export DATABASE=postgres
+export READER=PostgresPollingReader
 
 export SPRING_PROFILES_ACTIVE=postgres
 
diff --git a/build.gradle b/build.gradle
index 959b98a1..274b8a12 100644
--- a/build.gradle
+++ b/build.gradle
@@ -35,11 +35,14 @@ subprojects {
 
 dockerCompose {
     environment.put "EVENTUATE_COMMON_VERSION", eventuateCommonImageVersion
-    environment.put "EVENTUATE_KAFKA_VERSION", eventuateMessagingKafkaImageVersion
     environment.put "EVENTUATE_CDC_VERSION", eventuateCdcImageVersion
     environment.put "EVENTUATE_SAGA_VERSION", eventuateTramSagasImageVersion
     environment.put "EVENTUATE_JAVA_BASE_IMAGE_VERSION", eventuateExamplesBaseImageVersion
 
+    if (project.ext.has("envFile")) {
+        environment.put "ENV_FILE", project.ext.envFile
+    }
+
     mysqlinfrastructure {
         projectName = null
         useComposeFiles = ["docker-compose-mysql.yml"]
diff --git a/docker-compose-env-files/db-id-gen.env b/docker-compose-env-files/db-id-gen.env
new file mode 100644
index 00000000..dece4185
--- /dev/null
+++ b/docker-compose-env-files/db-id-gen.env
@@ -0,0 +1 @@
+EVENTUATE_OUTBOX_ID=1
\ No newline at end of file
diff --git a/docker-compose-env-files/empty.env b/docker-compose-env-files/empty.env
new file mode 100644
index 00000000..e69de29b
diff --git a/docker-compose-mysql.yml b/docker-compose-mysql.yml
index 9b93bf66..15cb4d51 100755
--- a/docker-compose-mysql.yml
+++ b/docker-compose-mysql.yml
@@ -1,6 +1,8 @@
 version: '3.5'
 services:
   order-service:
+    env_file:
+      - ${ENV_FILE:-docker-compose-env-files/empty.env}
     build:
       context: ./order-service/
       args:
@@ -24,6 +26,8 @@ services:
       SPRING_ZIPKIN_BASE_URL: http://zipkin:9411/
 
   customer-service:
+    env_file:
+      - ${ENV_FILE:-docker-compose-env-files/empty.env}
     build:
       context: ./customer-service/
       args:
@@ -115,6 +119,7 @@ services:
       EVENTUATELOCAL_CDC_OFFSET_STORE_KEY: MySqlBinlog
       EVENTUATELOCAL_CDC_MYSQL_BINLOG_CLIENT_UNIQUE_ID: 1234567890
       EVENTUATELOCAL_CDC_READ_OLD_DEBEZIUM_DB_OFFSET_STORAGE_TOPIC: "false"
+      EVENTUATE_OUTBOX_ID: 1
       JAVA_OPTS: -Xmx64m
 
   zipkin:
diff --git a/docker-compose-postgres.yml b/docker-compose-postgres.yml
index 1b322b56..e8515895 100755
--- a/docker-compose-postgres.yml
+++ b/docker-compose-postgres.yml
@@ -1,6 +1,8 @@
 version: '3'
 services:
   order-service:
+    env_file:
+      - ${ENV_FILE:-docker-compose-env-files/empty.env}
     build:
       context: ./order-service/
       args:
@@ -21,6 +23,8 @@ services:
       EVENTUATELOCAL_ZOOKEEPER_CONNECTION_STRING: zookeeper:2181
 
   customer-service:
+    env_file:
+      - ${ENV_FILE:-docker-compose-env-files/empty.env}
     build:
       context: ./customer-service/
       args:
@@ -104,4 +108,5 @@ services:
       EVENTUATELOCAL_ZOOKEEPER_CONNECTION_STRING: zookeeper:2181
       EVENTUATELOCAL_CDC_READER_NAME: PostgresPollingReader
       SPRING_PROFILES_ACTIVE: EventuatePolling
+      EVENTUATE_OUTBOX_ID: 1
       JAVA_OPTS: -Xmx64m
diff --git a/gradle.properties b/gradle.properties
index 7711178d..ba4a6737 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -9,13 +9,12 @@ springCloudGatewayVersion=2.2.2.RELEASE
 springCloudContractDependenciesVersion=2.2.0.RELEASE
 eventuateUtilVersion=0.7.0.RELEASE
 
-eventuateTramSagasImageVersion=0.15.2.RELEASE
+eventuateTramSagasImageVersion=0.16.0.DB_ID_GEN.BUILD-SNAPSHOT
 
-eventuateCommonImageVersion=0.12.0.RELEASE
-eventuateMessagingKafkaImageVersion=0.12.0.RELEASE
-eventuateCdcImageVersion=0.9.0.RELEASE
+eventuateCommonImageVersion=0.13.0.DB_ID_GEN.BUILD-SNAPSHOT
+eventuateCdcImageVersion=0.10.0.DB_ID_GEN.BUILD-SNAPSHOT
 
-eventuatePlatformVersion=2020.3.RELEASE
+eventuatePlatformVersion=2020.4.DB_ID_GEN.BUILD-SNAPSHOT
 
 swaggerUiVersion=3.23.11
 eventuateExamplesBaseImageVersion=BUILD-5
diff --git a/migration-tests/build.gradle b/migration-tests/build.gradle
new file mode 100644
index 00000000..22548365
--- /dev/null
+++ b/migration-tests/build.gradle
@@ -0,0 +1,18 @@
+dependencies {
+    testCompile "org.springframework.boot:spring-boot-starter-jdbc:${springBootVersion}"
+    testCompile "org.springframework.boot:spring-boot-starter-test:${springBootVersion}"
+
+    testRuntime 'mysql:mysql-connector-java:5.1.36'
+    testRuntime ('org.postgresql:postgresql:9.4-1200-jdbc41') {
+        exclude group: "org.slf4j", module: "slf4j-simple"
+    }
+    testRuntime 'com.microsoft.sqlserver:mssql-jdbc:7.2.1.jre8'
+}
+
+test {
+    if (!project.ext.has("verifyDbIdMigration")) {
+        exclude '**/DbIdMigrationVerificationTest**'
+    }
+
+    forkEvery 1
+}
\ No newline at end of file
diff --git a/migration-tests/src/test/java/io/eventuate/examples/tram/sagas/ordersandcustomers/migration/DbIdMigrationVerificationTest.java b/migration-tests/src/test/java/io/eventuate/examples/tram/sagas/ordersandcustomers/migration/DbIdMigrationVerificationTest.java
new file mode 100644
index 00000000..b9c07178
--- /dev/null
+++ b/migration-tests/src/test/java/io/eventuate/examples/tram/sagas/ordersandcustomers/migration/DbIdMigrationVerificationTest.java
@@ -0,0 +1,39 @@
+package io.eventuate.examples.tram.sagas.ordersandcustomers.migration;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.List;
+import java.util.Map;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(classes = DbIdMigrationVerificationTest.Config.class)
+public class DbIdMigrationVerificationTest {
+
+  @Configuration
+  @EnableAutoConfiguration
+  public static class Config {}
+
+  @Autowired
+  private JdbcTemplate jdbcTemplate;
+
+  @Test
+  //after first call of e2e tests (before migration), messages should have ids, after second call (after migration) don't
+  public void testThatMessagesAreMigrated() {
+    List<Map<String, Object>> messagesWithEmptyId =
+            jdbcTemplate.queryForList("select * from eventuate.message where destination <> 'CDC-IGNORED' and id = ''");
+
+    List<Map<String, Object>> messagesWithNotEmptyId =
+            jdbcTemplate.queryForList("select * from eventuate.message where destination <> 'CDC-IGNORED' and id <> ''");
+
+    Assert.assertTrue(messagesWithEmptyId.size() > 0);
+    Assert.assertEquals(messagesWithEmptyId.size(), messagesWithNotEmptyId.size());
+  }
+}
diff --git a/migration-tests/src/test/resources/application-mssql.properties b/migration-tests/src/test/resources/application-mssql.properties
new file mode 100644
index 00000000..d61e4995
--- /dev/null
+++ b/migration-tests/src/test/resources/application-mssql.properties
@@ -0,0 +1,4 @@
+spring.datasource.url=jdbc:sqlserver://${DOCKER_HOST_IP:localhost}:1433;databaseName=eventuate
+spring.datasource.username=sa
+spring.datasource.password=Eventuate123!
+spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
\ No newline at end of file
diff --git a/migration-tests/src/test/resources/application-postgres.properties b/migration-tests/src/test/resources/application-postgres.properties
new file mode 100644
index 00000000..8338266b
--- /dev/null
+++ b/migration-tests/src/test/resources/application-postgres.properties
@@ -0,0 +1,4 @@
+spring.datasource.url=jdbc:postgresql://${DOCKER_HOST_IP:localhost}/eventuate
+spring.datasource.username=eventuate
+spring.datasource.password=eventuate
+spring.datasource.driver-class-name=org.postgresql.Driver
\ No newline at end of file
diff --git a/migration-tests/src/test/resources/application.properties b/migration-tests/src/test/resources/application.properties
new file mode 100644
index 00000000..d22736bf
--- /dev/null
+++ b/migration-tests/src/test/resources/application.properties
@@ -0,0 +1,4 @@
+spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/eventuate
+spring.datasource.username=mysqluser
+spring.datasource.password=mysqlpw
+spring.datasource.driver-class-name=com.mysql.jdbc.Driver
diff --git a/settings.gradle b/settings.gradle
index 61601060..7a052cc8 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -13,3 +13,5 @@ include 'api-gateway-service-api-web'
 include 'api-gateway-service'
 
 include 'end-to-end-tests'
+
+include 'migration-tests'
diff --git a/wait-for-services.sh b/wait-for-services.sh
index 7efdd39f..362919a8 100755
--- a/wait-for-services.sh
+++ b/wait-for-services.sh
@@ -1,14 +1,23 @@
 #! /bin/bash
 
-host=$1
-ports=$2
+done=false
 
-shift 2
+echo waiting for: $*
+
+host=${1?}
+shift
+health_url=${1?}
+shift
+ports=$*
+
+if [ -z "$ports" ] ; then
+	echo no ports
+	exit 99
+fi
 
-done=false
 while [[ "$done" = false ]]; do
 	for port in $ports; do
-		curl -q http://${host}:${port}/health >& /dev/null
+		curl --fail http://${host}:${port}/${health_url} >& /dev/null
 		if [[ "$?" -eq "0" ]]; then
 			done=true
 		else
@@ -17,7 +26,7 @@ while [[ "$done" = false ]]; do
 		fi
 	done
 	if [[ "$done" = true ]]; then
-		echo services are started
+		echo connected
 		break;
   fi
 	echo -n .