From a95f01117b5b461f94b81d5e728fd38c5c6136f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Sat, 11 Apr 2026 16:15:00 +0200 Subject: [PATCH] feat: cross-compile for Scala 2.12 + 2.13 with Java 17 target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate generic-notification-api to support both Scala 2.12.20 and 2.13.16 with Java 17 compilation target. Bump version to 0.9.0. Key changes: - Configs → ConfigReader (configs 0.6.x), kebab-case config aliases - JavaConverters → jdk.CollectionConverters + scala-collection-compat - Stream.continually → Iterator.continually (2.13 deprecation) - Nullary method dotted invocation (.complete()) - .asScala.toSeq for mutable.Buffer compatibility - Dependencies: generic-persistence-api 0.8.1, scheduler 0.8.0, sbt-softnetwork 0.2.0, scalapb-extensions 0.2.0, slf4j 2.0.7, logback 1.4.14, sbt-scoverage 2.3.0 - CI: JDK 17, actions v4, sbt/setup-sbt@v1, cross-compile step Closed Issue #9 Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build.yml | 48 +++++++----- .github/workflows/release.yml | 74 ++++++++++--------- .gitignore | 4 +- build.sbt | 74 ++++++++++++++++--- common/build.sbt | 2 +- .../config/NotificationSettings.scala | 4 +- .../notification/spi/package.scala | 2 +- core/src/main/resources/reference.conf | 7 ++ .../notification/config/MailSettings.scala | 4 +- .../notification/config/PushSettings.scala | 15 +++- .../notification/config/SMSSettings.scala | 4 +- .../notification/spi/ApnsProvider.scala | 14 ++-- .../notification/spi/FcmProvider.scala | 4 +- .../notification/spi/SMSModeProvider.scala | 12 ++- project/Versions.scala | 8 +- project/plugins.sbt | 8 +- testkit/src/main/resources/reference.conf | 4 + .../scalatest/ApnsMockServer.scala | 2 +- .../messaging/MockBatchResponse.scala | 2 +- .../AllNotificationsHandlerSpec.scala | 16 ++-- .../ApnsNotificationsHandlerSpec.scala | 2 +- .../FcmAndApnsNotificationsHandlerSpec.scala | 2 +- .../FcmNotificationsHandlerSpec.scala | 2 +- .../SMSModeNotificationsHandlerSpec.scala | 2 +- .../SimpleMailNotificationsHandlerSpec.scala | 2 +- .../service/NotificationServiceSpec.scala | 6 +- 26 files changed, 212 insertions(+), 112 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f79041..c7fd65d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,12 +8,12 @@ name: Build on: workflow_dispatch: push: - branches: + branches: - '!main' # - '*' # matches every branch that doesn't contain a '/' # - '*/*' # matches every branch containing a single '/' # - '**' # matches every branch -# - '!main' # excludes main +# - '!main' # excludes main pull_request: branches: - '**' @@ -23,27 +23,33 @@ permissions: jobs: test: - runs-on: self-hosted -# runs-on: ubuntu-latest - env: - # define Java options for both official sbt and sbt-extras - JAVA_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8 - JVM_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8 +# runs-on: self-hosted + runs-on: ubuntu-latest steps: + - name: Env + run: | + echo "JFROG_USER=${{ secrets.JFROG_USER }}" >> $GITHUB_ENV + echo "JFROG_PASSWORD=${{ secrets.JFROG_PASSWORD }}" >> $GITHUB_ENV + echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + echo "CODECOV_TOKEN=${{ secrets.CODECOV_TOKEN }}" >> $GITHUB_ENV - name: Checkout - uses: actions/checkout@v3 - - name: Set up JDK 8 - uses: actions/setup-java@v3 + uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 with: - java-version: '8' + java-version: '17' distribution: 'temurin' # cache: 'sbt' + - name: Setup sbt launcher + uses: sbt/setup-sbt@v1 + - name: Cross Compile + run: SBT_OPTS="-Xss4M -Xms1g -Xmx4g -Dfile.encoding=UTF-8" sbt '+ Test/compile' - name: Run tests & Coverage Report - run: sbt coverage test coverageReport + run: SBT_OPTS="-Xss4M -Xms1g -Xmx4g -Dfile.encoding=UTF-8" sbt coverage test coverageReport - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: - files: common/target/scala-2.12/coverage-report/cobertura.xml,core/target/scala-2.12/coverage-report/cobertura.xml,teskit/target/scala-2.12/coverage-report/cobertura.xml + files: common/target/scala-*/coverage-report/cobertura.xml,core/target/scala-*/coverage-report/cobertura.xml,testkit/target/scala-*/coverage-report/cobertura.xml flags: unittests fail_ci_if_error: true verbose: true @@ -52,12 +58,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 - - name: Set up JDK 8 - uses: actions/setup-java@v3 + uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 with: - java-version: '8' + java-version: '17' distribution: 'temurin' # cache: 'sbt' + - name: Setup sbt launcher + uses: sbt/setup-sbt@v1 - name: Formatting - run: sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck \ No newline at end of file + run: sbt scalafmtSbtCheck scalafmtCheck Test/scalafmtCheck diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 840bae5..2de43f3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,55 +8,63 @@ name: Release on: workflow_dispatch: push: - branches: + branches: - 'main' # Run workflow on commits to the `main` branch # - '*' # matches every branch that doesn't contain a '/' # - '*/*' # matches every branch containing a single '/' # - '**' # matches every branch -# - '!main' # excludes main +# - '!main' # excludes main permissions: contents: read jobs: release: - runs-on: self-hosted - # runs-on: ubuntu-latest - env: - # define Java options for both official sbt and sbt-extras - JAVA_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8 - JVM_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8 +# runs-on: self-hosted + runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Set up JDK 8 - uses: actions/setup-java@v3 - with: - java-version: '8' - distribution: 'temurin' - # cache: 'sbt' - - name: Run tests & Coverage Report - run: sbt coverage test coverageReport coverageAggregate - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 - with: - files: common/target/scala-2.12/coverage-report/cobertura.xml,core/target/scala-2.12/coverage-report/cobertura.xml,teskit/target/scala-2.12/coverage-report/cobertura.xml - flags: unittests - fail_ci_if_error: true - verbose: true - - name: Publish - run: sbt publish + - name: Env + run: | + echo "JFROG_USER=${{ secrets.JFROG_USER }}" >> $GITHUB_ENV + echo "JFROG_PASSWORD=${{ secrets.JFROG_PASSWORD }}" >> $GITHUB_ENV + echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV + echo "CODECOV_TOKEN=${{ secrets.CODECOV_TOKEN }}" >> $GITHUB_ENV + - name: Checkout + uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' +# cache: 'sbt' + - name: Setup sbt launcher + uses: sbt/setup-sbt@v1 + - name: Cross Compile + run: SBT_OPTS="-Xss4M -Xms1g -Xmx4g -Dfile.encoding=UTF-8" sbt '+ Test/compile' + - name: Run tests & Coverage Report + run: SBT_OPTS="-Xss4M -Xms1g -Xmx4g -Dfile.encoding=UTF-8" sbt coverage test coverageReport coverageAggregate + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + files: common/target/scala-*/coverage-report/cobertura.xml,core/target/scala-*/coverage-report/cobertura.xml,testkit/target/scala-*/coverage-report/cobertura.xml + flags: unittests + fail_ci_if_error: false + verbose: true + - name: Publish + run: SBT_OPTS="-Xss4M -Xms1g -Xmx4g" sbt '+ publish' lint: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 - - name: Set up JDK 8 - uses: actions/setup-java@v3 + uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 with: - java-version: '8' + java-version: '17' distribution: 'temurin' - # cache: 'sbt' +# cache: 'sbt' + - name: Setup sbt launcher + uses: sbt/setup-sbt@v1 - name: Formatting - run: sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck \ No newline at end of file + run: sbt scalafmtSbtCheck scalafmtCheck Test/scalafmtCheck diff --git a/.gitignore b/.gitignore index 2f2c52c..2f2baaf 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ sbt.json target .metals -*.log \ No newline at end of file +*.log +actions-runner +api/src/main/resources/logback.xml diff --git a/build.sbt b/build.sbt index 2728e50..267cbf6 100644 --- a/build.sbt +++ b/build.sbt @@ -1,14 +1,28 @@ +lazy val scala212 = "2.12.20" +lazy val scala213 = "2.13.16" +lazy val javacCompilerVersion = "17" +lazy val scalacCompilerOptions = Seq("-deprecation", "-feature") + +lazy val moduleSettings = Seq( + crossScalaVersions := Seq(scala212, scala213), + scalacOptions ++= { + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, 12)) => scalacCompilerOptions + case Some((2, 13)) => scalacCompilerOptions :+ s"-release:$javacCompilerVersion" + case _ => Seq.empty + } + } +) + ThisBuild / organization := "app.softnetwork" name := "notification" -ThisBuild / version := "0.8.2" - -ThisBuild / scalaVersion := "2.12.18" +ThisBuild / version := "0.9.0" -ThisBuild / scalacOptions ++= Seq("-deprecation", "-feature", "-target:jvm-1.8") +ThisBuild / scalaVersion := scala212 -ThisBuild / javacOptions ++= Seq("-source", "1.8", "-target", "1.8", "-Xlint") +ThisBuild / javacOptions ++= Seq("-source", javacCompilerVersion, "-target", javacCompilerVersion) ThisBuild / resolvers ++= Seq( "Softnetwork Server" at "https://softnetwork.jfrog.io/artifactory/releases/", @@ -25,21 +39,50 @@ val scalatest = Seq( ThisBuild / libraryDependencies ++= Seq( "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf", - "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.1", + "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2", + "org.scala-lang.modules" %% "scala-collection-compat" % "2.11.0", "org.apache.commons" % "commons-lang3" % "3.15.0", "org.slf4j" % "slf4j-api" % Versions.slf4j, + "ch.qos.logback" % "logback-classic" % Versions.logback, ) ++ scalatest +ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always + +ThisBuild / javaOptions ++= Seq( + "--add-opens=java.base/java.util=ALL-UNNAMED", + "--add-opens=java.base/java.util.concurrent=ALL-UNNAMED", + "--add-opens=java.base/java.lang=ALL-UNNAMED", + "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED", + "--add-opens=java.base/java.math=ALL-UNNAMED", + "--add-opens=java.base/java.io=ALL-UNNAMED", + "--add-opens=java.base/java.net=ALL-UNNAMED", + "--add-opens=java.base/java.nio=ALL-UNNAMED", + "--add-opens=java.base/java.text=ALL-UNNAMED", + "--add-opens=java.base/java.time=ALL-UNNAMED", + "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED" +) + +ThisBuild / Test / fork := true + +ThisBuild / Test / javaOptions ++= (ThisBuild / javaOptions).value + Test / parallelExecution := false lazy val common = project.in(file("common")) .configs(IntegrationTest) - .settings(Defaults.itSettings) + .settings( + Defaults.itSettings, + moduleSettings + ) .enablePlugins(AkkaGrpcPlugin) lazy val core = project.in(file("core")) .configs(IntegrationTest) - .settings(Defaults.itSettings, app.softnetwork.Info.infoSettings) + .settings( + Defaults.itSettings, + app.softnetwork.Info.infoSettings, + moduleSettings + ) .enablePlugins(BuildInfoPlugin) .dependsOn( common % "compile->compile;test->test;it->it" @@ -47,7 +90,10 @@ lazy val core = project.in(file("core")) lazy val testkit = project.in(file("testkit")) .configs(IntegrationTest) - .settings(Defaults.itSettings) + .settings( + Defaults.itSettings, + moduleSettings + ) .enablePlugins(BuildInfoPlugin) .dependsOn( core % "compile->compile;test->test;it->it" @@ -55,7 +101,10 @@ lazy val testkit = project.in(file("testkit")) lazy val api = project.in(file("api")) .configs(IntegrationTest) - .settings(Defaults.itSettings) + .settings( + Defaults.itSettings, + moduleSettings + ) .enablePlugins(DockerPlugin, JavaAppPackaging) .dependsOn( core % "compile->compile;test->test;it->it" @@ -64,4 +113,7 @@ lazy val api = project.in(file("api")) lazy val root = project.in(file(".")) .aggregate(common, core, testkit, api) .configs(IntegrationTest) - .settings(Defaults.itSettings) + .settings( + Defaults.itSettings, + crossScalaVersions := Nil + ) diff --git a/common/build.sbt b/common/build.sbt index e10c48b..39324e2 100644 --- a/common/build.sbt +++ b/common/build.sbt @@ -9,7 +9,7 @@ libraryDependencies ++= Seq( "app.softnetwork.scheduler" %% "scheduler-common" % Versions.scheduler, "app.softnetwork.scheduler" %% "scheduler-common" % Versions.scheduler % "protobuf", "app.softnetwork.api" %% "generic-server-api" % Versions.genericPersistence, - "app.softnetwork.protobuf" %% "scalapb-extensions" % "0.1.7", + "app.softnetwork.protobuf" %% "scalapb-extensions" % "0.2.0", "org.apache.commons" % "commons-email" % "1.5", "com.google.auth" % "google-auth-library-oauth2-http" % "0.20.0" excludeAll guavaExclusion, "io.opencensus" % "opencensus-contrib-http-util" % "0.24.0" excludeAll(guavaExclusion, ExclusionRule(organization = "io.grpc", name="grpc-context")), diff --git a/common/src/main/scala/app/softnetwork/notification/config/NotificationSettings.scala b/common/src/main/scala/app/softnetwork/notification/config/NotificationSettings.scala index 1d0541e..a595822 100644 --- a/common/src/main/scala/app/softnetwork/notification/config/NotificationSettings.scala +++ b/common/src/main/scala/app/softnetwork/notification/config/NotificationSettings.scala @@ -1,12 +1,12 @@ package app.softnetwork.notification.config -import configs.Configs +import configs.ConfigReader import scala.language.{implicitConversions, reflectiveCalls} trait NotificationSettings { _: InternalConfig => lazy val NotificationConfig: NotificationConfig = - Configs[NotificationConfig].get(config, "notification").toEither match { + ConfigReader[NotificationConfig].read(config, "notification").toEither match { case Left(configError) => Console.err.println(s"Something went wrong with the provided arguments $configError") throw configError.configException diff --git a/common/src/main/scala/app/softnetwork/notification/spi/package.scala b/common/src/main/scala/app/softnetwork/notification/spi/package.scala index 6887097..c21bdb4 100644 --- a/common/src/main/scala/app/softnetwork/notification/spi/package.scala +++ b/common/src/main/scala/app/softnetwork/notification/spi/package.scala @@ -214,7 +214,7 @@ package object spi { ) } } - Future.sequence(results).flatMap(results => Future.successful(results)) complete () match { + Future.sequence(results).flatMap(results => Future.successful(results)).complete() match { case Success(s) => val existingResults = ws.results.filterNot(result => s.exists(_.recipient == result.recipient)) diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index d6accd7..ec2c150 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -6,14 +6,20 @@ notification { port = ${?MAIL_PORT} sslPort = 465 sslPort = ${?MAIL_SSL_PORT} + ssl-port = ${notification.mail.sslPort} sslEnabled = true sslEnabled = ${?MAIL_SSL_ENABLED} + ssl-enabled = ${notification.mail.sslEnabled} sslCheckServerIdentity = false sslCheckServerIdentity = ${?MAIL_CHECK_SERVER_IDENTITY} + ssl-check-server-identity = ${notification.mail.sslCheckServerIdentity} startTLSEnabled = false startTLSEnabled = ${?MAIL_START_TLS_ENABLED} + start-tls-enabled = ${notification.mail.startTLSEnabled} socketConnectionTimeout = 2000 + socket-connection-timeout = ${notification.mail.socketConnectionTimeout} socketTimeout = 2000 + socket-timeout = ${notification.mail.socketTimeout} from = ${credentials.mail.username} from = ${?NOTIFICATION_MAIL_FROM} @@ -42,6 +48,7 @@ notification { fcm { databaseUrl = "" databaseUrl = ${?NOTIFICATION_PUSH_FCM_DATABASE_URL} + database-url = ${notification.push.fcm.databaseUrl} google-credentials = "" google-credentials = ${?GOOGLE_APPLICATION_CREDENTIALS} } diff --git a/core/src/main/scala/app/softnetwork/notification/config/MailSettings.scala b/core/src/main/scala/app/softnetwork/notification/config/MailSettings.scala index bd6d4de..70dcd78 100644 --- a/core/src/main/scala/app/softnetwork/notification/config/MailSettings.scala +++ b/core/src/main/scala/app/softnetwork/notification/config/MailSettings.scala @@ -1,13 +1,13 @@ package app.softnetwork.notification.config -import configs.Configs +import configs.ConfigReader import scala.language.reflectiveCalls trait MailSettings extends NotificationSettings { _: InternalConfig => lazy val MailConfig: MailConfig = - Configs[MailConfig].get(config, "notification.mail").toEither match { + ConfigReader[MailConfig].read(config, "notification.mail").toEither match { case Left(configError) => Console.err.println(s"Something went wrong with the provided arguments $configError") throw configError.configException diff --git a/core/src/main/scala/app/softnetwork/notification/config/PushSettings.scala b/core/src/main/scala/app/softnetwork/notification/config/PushSettings.scala index 9df6718..75c26b7 100644 --- a/core/src/main/scala/app/softnetwork/notification/config/PushSettings.scala +++ b/core/src/main/scala/app/softnetwork/notification/config/PushSettings.scala @@ -1,14 +1,14 @@ package app.softnetwork.notification.config -import configs.Configs +import configs.ConfigReader -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ import scala.language.{implicitConversions, reflectiveCalls} trait PushSettings extends NotificationSettings { _: InternalConfig => lazy val DefaultConfig: PushConfig = - Configs[PushConfig].get(config, "notification.push").toEither match { + ConfigReader[PushConfig].read(config, "notification.push").toEither match { case Left(configError) => Console.err.println(s"Something went wrong with the provided arguments $configError") throw configError.configException @@ -19,7 +19,14 @@ trait PushSettings extends NotificationSettings { _: InternalConfig => .getStringList("notification.push.apps") .asScala .toList - .map(app => app -> Configs[PushConfig].get(config, s"notification.push.$app").value) + .map(app => + app -> (ConfigReader[PushConfig].read(config, s"notification.push.$app").toEither match { + case Left(configError) => + Console.err.println(s"Something went wrong with the provided arguments $configError") + throw configError.configException + case Right(r) => r + }) + ) .toMap } diff --git a/core/src/main/scala/app/softnetwork/notification/config/SMSSettings.scala b/core/src/main/scala/app/softnetwork/notification/config/SMSSettings.scala index ea45275..67c3601 100644 --- a/core/src/main/scala/app/softnetwork/notification/config/SMSSettings.scala +++ b/core/src/main/scala/app/softnetwork/notification/config/SMSSettings.scala @@ -1,13 +1,13 @@ package app.softnetwork.notification.config -import configs.Configs +import configs.ConfigReader import scala.language.reflectiveCalls trait SMSSettings extends NotificationSettings { _: InternalConfig => lazy val SMSConfig: SMSConfig = - Configs[SMSConfig].get(config, "notification.sms").toEither match { + ConfigReader[SMSConfig].read(config, "notification.sms").toEither match { case Left(configError) => Console.err.println(s"Something went wrong with the provided arguments $configError") throw configError.configException diff --git a/core/src/main/scala/app/softnetwork/notification/spi/ApnsProvider.scala b/core/src/main/scala/app/softnetwork/notification/spi/ApnsProvider.scala index 7fd70e0..ec21d0b 100644 --- a/core/src/main/scala/app/softnetwork/notification/spi/ApnsProvider.scala +++ b/core/src/main/scala/app/softnetwork/notification/spi/ApnsProvider.scala @@ -131,13 +131,15 @@ trait ApnsProvider extends IosProvider with PushSettings with Completion { ) val results = - Future.sequence(for (to <- tos) yield { - toScala( - client.sendNotification( - new SimpleApnsPushNotification(to, config.topic, payload) + Future + .sequence(for (to <- tos) yield { + toScala( + client.sendNotification( + new SimpleApnsPushNotification(to, config.topic, payload) + ) ) - ) - }) complete () match { + }) + .complete() match { case Success(responses) => for (response <- responses) yield { val result: NotificationStatusResult = response diff --git a/core/src/main/scala/app/softnetwork/notification/spi/FcmProvider.scala b/core/src/main/scala/app/softnetwork/notification/spi/FcmProvider.scala index f39484e..36ab935 100644 --- a/core/src/main/scala/app/softnetwork/notification/spi/FcmProvider.scala +++ b/core/src/main/scala/app/softnetwork/notification/spi/FcmProvider.scala @@ -20,7 +20,7 @@ import app.softnetwork.notification.model.{ import org.slf4j.Logger import scala.annotation.tailrec -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ import scala.language.implicitConversions import scala.util.{Failure, Success, Try} @@ -155,7 +155,7 @@ object FcmProvider { implicit def toNotificationResults( response: BatchResponse )(implicit tokens: Seq[String]): Seq[NotificationStatusResult] = { - for ((r, i) <- response.getResponses.asScala.zipWithIndex) + for ((r, i) <- response.getResponses.asScala.toSeq.zipWithIndex) yield NotificationStatusResult( tokens(i), if (r.isSuccessful) diff --git a/core/src/main/scala/app/softnetwork/notification/spi/SMSModeProvider.scala b/core/src/main/scala/app/softnetwork/notification/spi/SMSModeProvider.scala index 49451e1..57590eb 100644 --- a/core/src/main/scala/app/softnetwork/notification/spi/SMSModeProvider.scala +++ b/core/src/main/scala/app/softnetwork/notification/spi/SMSModeProvider.scala @@ -85,7 +85,11 @@ trait SMSModeProvider extends SMSProvider with SMSSettings { _: InternalConfig = case responseCode if responseCode == 200 || responseCode == 201 => Try { val br = new BufferedReader(new InputStreamReader(connection.getInputStream)) - Stream.continually(br.readLine()).takeWhile(_ != null).mkString("") + try { + Iterator.continually(br.readLine()).takeWhile(_ != null).mkString("") + } finally { + br.close() + } } match { case Success(responseData) => log.info(responseData) @@ -221,7 +225,11 @@ trait SMSModeProvider extends SMSProvider with SMSSettings { _: InternalConfig = case responseCode if responseCode == 200 || responseCode == 201 => Try { val br = new BufferedReader(new InputStreamReader(connection.getInputStream)) - Stream.continually(br.readLine()).takeWhile(_ != null).mkString("") + try { + Iterator.continually(br.readLine()).takeWhile(_ != null).mkString("") + } finally { + br.close() + } } match { case Success(responseData) => log.info(responseData) diff --git a/project/Versions.scala b/project/Versions.scala index 061a020..7dc6558 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -2,11 +2,13 @@ object Versions { val akka = "2.6.20" - val slf4j = "1.7.36" + val slf4j = "2.0.7" - val genericPersistence = "0.7.3" + val logback = "1.4.14" - val scheduler = "0.7.3" + val genericPersistence = "0.8.1" + + val scheduler = "0.8.0" val scalatest = "3.2.16" } diff --git a/project/plugins.sbt b/project/plugins.sbt index 18ae239..70279cf 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -7,11 +7,11 @@ resolvers ++= Seq( "Softnetwork releases" at "https://softnetwork.jfrog.io/artifactory/releases/" ) -addSbtPlugin("app.softnetwork.sbt-softnetwork" % "sbt-softnetwork-git" % "0.1.7") +addSbtPlugin("app.softnetwork.sbt-softnetwork" % "sbt-softnetwork-git" % "0.2.0") -addSbtPlugin("app.softnetwork.sbt-softnetwork" % "sbt-softnetwork-info" % "0.1.7") +addSbtPlugin("app.softnetwork.sbt-softnetwork" % "sbt-softnetwork-info" % "0.2.0") -addSbtPlugin("app.softnetwork.sbt-softnetwork" % "sbt-softnetwork-publish" % "0.1.7") +addSbtPlugin("app.softnetwork.sbt-softnetwork" % "sbt-softnetwork-publish" % "0.2.0") addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.10") @@ -19,4 +19,4 @@ addDependencyTreePlugin //addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.4.0") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.8") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.0") diff --git a/testkit/src/main/resources/reference.conf b/testkit/src/main/resources/reference.conf index 15d03b6..8cecdcf 100644 --- a/testkit/src/main/resources/reference.conf +++ b/testkit/src/main/resources/reference.conf @@ -1,8 +1,11 @@ notification{ mail { sslEnabled = false + ssl-enabled = ${notification.mail.sslEnabled} sslCheckServerIdentity = false + ssl-check-server-identity = ${notification.mail.sslCheckServerIdentity} startTLSEnabled = false + start-tls-enabled = ${notification.mail.startTLSEnabled} } push { @@ -20,6 +23,7 @@ notification{ fcm { databaseUrl = "" databaseUrl = ${?NOTIFICATION_PUSH_FCM_DATABASE_URL} + database-url = ${notification.push.mock.fcm.databaseUrl} google-credentials = "" google-credentials = ${?GOOGLE_APPLICATION_CREDENTIALS} } diff --git a/testkit/src/main/scala/app/softnetwork/notification/scalatest/ApnsMockServer.scala b/testkit/src/main/scala/app/softnetwork/notification/scalatest/ApnsMockServer.scala index 11dbe34..5c088e9 100644 --- a/testkit/src/main/scala/app/softnetwork/notification/scalatest/ApnsMockServer.scala +++ b/testkit/src/main/scala/app/softnetwork/notification/scalatest/ApnsMockServer.scala @@ -52,7 +52,7 @@ trait ApnsMockServer extends PushSettings with MockServer { protected override def start(): Boolean = { maybeServer match { case Some(server) => - toScala(server.start(serverPort)) complete () match { + toScala(server.start(serverPort)).complete() match { case Success(value) => Option(value.toInt).isDefined case Failure(f) => log.error(f.getMessage, f) diff --git a/testkit/src/main/scala/com/google/firebase/messaging/MockBatchResponse.scala b/testkit/src/main/scala/com/google/firebase/messaging/MockBatchResponse.scala index b8382db..29e58b7 100644 --- a/testkit/src/main/scala/com/google/firebase/messaging/MockBatchResponse.scala +++ b/testkit/src/main/scala/com/google/firebase/messaging/MockBatchResponse.scala @@ -1,6 +1,6 @@ package com.google.firebase.messaging -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ import java.util diff --git a/testkit/src/test/scala/app/softnetwork/notification/handlers/AllNotificationsHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/notification/handlers/AllNotificationsHandlerSpec.scala index 682c125..2d40c8f 100644 --- a/testkit/src/test/scala/app/softnetwork/notification/handlers/AllNotificationsHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/notification/handlers/AllNotificationsHandlerSpec.scala @@ -100,14 +100,14 @@ class AllNotificationsHandlerSpec extends AnyWordSpecLike with AllNotificationsT "add mail using client" in { val uuid = "mail" - assert(client.addMail(generateMail(uuid)) complete ()) + assert(client.addMail(generateMail(uuid)).complete()) assert(probe.receiveMessage().schedule.uuid == s"Notification#$uuid#NotificationTimerKey") } "send mail using client" in { val uuid = "mail2" val mail = generateMail(uuid) - client.sendMail(mail) complete () match { + client.sendMail(mail).complete() match { case Success(result) => assert(result.exists(r => r.recipient == mail.to.head && r.status.isSent)) case Failure(_) => fail() @@ -115,12 +115,12 @@ class AllNotificationsHandlerSpec extends AnyWordSpecLike with AllNotificationsT } "remove notification using client" in { - assert(client.removeNotification("mail") complete ()) + assert(client.removeNotification("mail").complete()) } "add sms using client" in { val uuid = "sms" - assert(client.addSMS(generateSMS(uuid)) complete ()) + assert(client.addSMS(generateSMS(uuid)).complete()) assert( probe.receiveMessage().schedule.uuid == s"Notification#$uuid#NotificationTimerKey" ) // pending @@ -132,7 +132,7 @@ class AllNotificationsHandlerSpec extends AnyWordSpecLike with AllNotificationsT "send sms using client" in { val uuid = "sms2" val sms = generateSMS(uuid) - client.sendSMS(sms) complete () match { + client.sendSMS(sms).complete() match { case Success(result) => assert(result.exists(r => r.recipient == sms.to.head && r.status.isPending)) assert( @@ -144,12 +144,12 @@ class AllNotificationsHandlerSpec extends AnyWordSpecLike with AllNotificationsT "add push using client" in { val uuid = "push" - assert(client.addPush(generatePush(uuid, androidDevice, iosDevice)) complete ()) + assert(client.addPush(generatePush(uuid, androidDevice, iosDevice)).complete()) assert(probe.receiveMessage().schedule.uuid == s"Notification#$uuid#NotificationTimerKey") } "retrieve push notification status using client" in { - client.getNotificationStatus("push") complete () match { + client.getNotificationStatus("push").complete() match { case Success(result) => assert(result.exists(r => r.recipient == androidDevice.regId && r.status.isSent)) assert(result.exists(r => r.recipient == iosDevice.regId)) // FIXME && r.status.isSent @@ -160,7 +160,7 @@ class AllNotificationsHandlerSpec extends AnyWordSpecLike with AllNotificationsT "send push using client" in { val uuid = "push2" val push = generatePush(uuid, androidDevice, iosDevice) - client.sendPush(push) complete () match { + client.sendPush(push).complete() match { case Success(result) => assert(result.exists(r => r.recipient == androidDevice.regId && r.status.isSent)) assert(result.exists(r => r.recipient == iosDevice.regId && r.status.isSent)) diff --git a/testkit/src/test/scala/app/softnetwork/notification/handlers/ApnsNotificationsHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/notification/handlers/ApnsNotificationsHandlerSpec.scala index 68dd4bf..ce5eb71 100644 --- a/testkit/src/test/scala/app/softnetwork/notification/handlers/ApnsNotificationsHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/notification/handlers/ApnsNotificationsHandlerSpec.scala @@ -158,7 +158,7 @@ class ApnsNotificationsHandlerSpec "add push" in { val uuid = "push" - assert(client.addPush(generatePush(uuid, iosDevice)) complete ()) + assert(client.addPush(generatePush(uuid, iosDevice)).complete()) assert(probe.receiveMessage().schedule.uuid == s"IosNotification#$uuid#NotificationTimerKey") } } diff --git a/testkit/src/test/scala/app/softnetwork/notification/handlers/FcmAndApnsNotificationsHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/notification/handlers/FcmAndApnsNotificationsHandlerSpec.scala index 1824ed6..08c9f0f 100644 --- a/testkit/src/test/scala/app/softnetwork/notification/handlers/FcmAndApnsNotificationsHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/notification/handlers/FcmAndApnsNotificationsHandlerSpec.scala @@ -151,7 +151,7 @@ class FcmAndApnsNotificationsHandlerSpec "add push" in { val uuid = "push" - assert(client.addPush(generatePush(uuid, iosDevice, androidDevice)) complete ()) + assert(client.addPush(generatePush(uuid, iosDevice, androidDevice)).complete()) assert( probe .receiveMessage() diff --git a/testkit/src/test/scala/app/softnetwork/notification/handlers/FcmNotificationsHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/notification/handlers/FcmNotificationsHandlerSpec.scala index 48b40f1..f7339f0 100644 --- a/testkit/src/test/scala/app/softnetwork/notification/handlers/FcmNotificationsHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/notification/handlers/FcmNotificationsHandlerSpec.scala @@ -164,7 +164,7 @@ class FcmNotificationsHandlerSpec "add push" in { val uuid = "push" - assert(client.addPush(generatePush(uuid, androidDevice)) complete ()) + assert(client.addPush(generatePush(uuid, androidDevice)).complete()) assert( probe.receiveMessage().schedule.uuid == s"AndroidNotification#$uuid#NotificationTimerKey" ) diff --git a/testkit/src/test/scala/app/softnetwork/notification/handlers/SMSModeNotificationsHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/notification/handlers/SMSModeNotificationsHandlerSpec.scala index 98dddc2..5bd7c0e 100644 --- a/testkit/src/test/scala/app/softnetwork/notification/handlers/SMSModeNotificationsHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/notification/handlers/SMSModeNotificationsHandlerSpec.scala @@ -129,7 +129,7 @@ class SMSModeNotificationsHandlerSpec "add sms" in { val uuid = "sms" - assert(client.addSMS(generateSMS(uuid)) complete ()) + assert(client.addSMS(generateSMS(uuid)).complete()) assert(probe.receiveMessage().schedule.uuid == s"SMSNotification#$uuid#NotificationTimerKey") } } diff --git a/testkit/src/test/scala/app/softnetwork/notification/handlers/SimpleMailNotificationsHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/notification/handlers/SimpleMailNotificationsHandlerSpec.scala index da1f56f..74c5ae2 100644 --- a/testkit/src/test/scala/app/softnetwork/notification/handlers/SimpleMailNotificationsHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/notification/handlers/SimpleMailNotificationsHandlerSpec.scala @@ -138,7 +138,7 @@ class SimpleMailNotificationsHandlerSpec "add mail" in { val uuid = "mail" - assert(client.addMail(generateMail(uuid)) complete ()) + assert(client.addMail(generateMail(uuid)).complete()) assert(probe.receiveMessage().schedule.uuid == s"MailNotification#$uuid#NotificationTimerKey") } diff --git a/testkit/src/test/scala/app/softnetwork/notification/service/NotificationServiceSpec.scala b/testkit/src/test/scala/app/softnetwork/notification/service/NotificationServiceSpec.scala index 4c524ea..2dbdfb9 100644 --- a/testkit/src/test/scala/app/softnetwork/notification/service/NotificationServiceSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/notification/service/NotificationServiceSpec.scala @@ -34,14 +34,14 @@ trait NotificationServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] "send message to client" in { val ws = generateWs(clientId) - client.sendWs(ws) complete () match { + client.sendWs(ws).complete() match { case Success(result) => wsClient match { case Some(cli) => assert(result.exists(r => r.recipient == clientId && r.status.isSent)) cli.expectMessage(ws.message) cli.sendCompletion() - client.sendWs(ws) complete () match { + client.sendWs(ws).complete() match { case Success(result) => assert(result.exists(r => r.recipient == clientId && r.status.isRejected)) case Failure(_) => fail() @@ -60,7 +60,7 @@ trait NotificationServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] "send message to channel" in { val ws = generateWs(clientId, Some(channel)).withTo(Seq.empty) - client.sendWs(ws) complete () match { + client.sendWs(ws).complete() match { case Success(result) => wsClient match { case Some(cli) =>