Compare commits

...

5 Commits

Author SHA1 Message Date
Artyom ad61be705b Create FcmClient class to make integration implementation closed 2022-08-12 15:13:48 +03:00
Artyom 37fb9443ea Update PushMessageProviderServiceFactory implementation 2022-08-12 12:29:30 +03:00
Artyom 5f81afcb08 Update readme 2022-08-11 17:49:47 +03:00
Artyom 1fffef06d9 Add push-message-provider-fcm module 2022-08-11 17:46:56 +03:00
Artyom 47759afac8 Add push-message-provider module 2022-08-11 17:46:54 +03:00
36 changed files with 750 additions and 0 deletions

View File

@ -213,3 +213,29 @@ server.info:
```
3) Implement ServerInfoService (optional. If you want to add other headers)
4) Add dir with impl ServerInfoService in ComponentScan annotation
## push-message-provider
Интерфейсы и компоненты для модулей по обеспечению интеграции с сервисами отправки пуш-уведомлений.
## push-message-provider-fcm
Модуль по обеспечению интеграции с Firebase Cloud Messaging.
1) Подключение компонентов Spring осуществляется при помощи аннотации `@EnablePushMessageProviderFcm`.
2) Необходимо добавление конфигурации для модуля. Пример файла конфигурации в формате yaml:
``` yaml
push-message-provider:
platformProviders:
ANDROID_GOOGLE:
- FCM
IOS:
- FCM
fcm:
appName: ${appName}
auth:
resourcePath: credentials/firebase-admin.json
client:
readTimeout: 10s
connectionTimeout: 1s
```
3) По обозначенному пути `push-message-provider-fcm.auth.resourcePath` добавляется json файл с настройками и доступами из консоли Firebase.

View File

@ -72,6 +72,8 @@ subprojects {
dependency("com.auth0:java-jwt:3.10.3")
dependency("software.amazon.awssdk:s3:2.10.11")
dependency("com.google.firebase:firebase-admin:9.0.0")
}
}

View File

@ -0,0 +1,19 @@
plugins {
id("kotlin")
id("kotlin-spring")
id("maven-publish")
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.springframework.boot:spring-boot")
implementation(project(":logger-spring"))
implementation(project(":push-message-provider"))
implementation("com.google.firebase:firebase-admin")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.testcontainers:junit-jupiter")
}

View File

@ -0,0 +1,8 @@
@file:Suppress("unused")
package ru.touchin.push.message.provider.fcm
import org.springframework.context.annotation.Import
import ru.touchin.push.message.provider.fcm.configurations.PushMessageProviderFcmConfiguration
@Import(value = [PushMessageProviderFcmConfiguration::class])
annotation class EnablePushMessageProviderFcm

View File

@ -0,0 +1,38 @@
package ru.touchin.push.message.provider.fcm.clients
import com.google.firebase.messaging.FirebaseMessaging
import com.google.firebase.messaging.FirebaseMessagingException
import org.springframework.stereotype.Component
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
import ru.touchin.push.message.provider.dto.result.SendPushResult
import ru.touchin.push.message.provider.dto.result.SendPushTokenMessageResult
import ru.touchin.push.message.provider.exceptions.InvalidPushTokenException
import ru.touchin.push.message.provider.exceptions.PushMessageProviderException
import ru.touchin.push.message.provider.fcm.converters.FirebaseMessagingExceptionConverter
import ru.touchin.push.message.provider.fcm.converters.PushTokenMessageConverter
/**
* Service that provides integration with FCM.
* @see <a href="https://firebase.google.com/docs/cloud-messaging">FCM documentation</a>
*/
@Component
class FcmClient(
private val firebaseMessaging: FirebaseMessaging,
private val pushTokenMessageConverter: PushTokenMessageConverter,
private val firebaseMessagingExceptionConverter: FirebaseMessagingExceptionConverter
) {
@Throws(PushMessageProviderException::class, InvalidPushTokenException::class)
fun sendPushTokenMessage(request: PushTokenMessage): SendPushResult {
val message = pushTokenMessageConverter(request)
return try {
val messageId = firebaseMessaging.send(message)
SendPushTokenMessageResult(messageId)
} catch (e: FirebaseMessagingException) {
throw firebaseMessagingExceptionConverter(e)
}
}
}

View File

@ -0,0 +1,37 @@
package ru.touchin.push.message.provider.fcm.configurations
import com.google.auth.oauth2.GoogleCredentials
import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import com.google.firebase.messaging.FirebaseMessaging
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Import
import org.springframework.core.io.ClassPathResource
import ru.touchin.push.message.provider.configurations.PushMessageProviderConfiguration
import ru.touchin.push.message.provider.fcm.properties.PushMessageProviderFcmProperties
@ComponentScan("ru.touchin.push.message.provider.fcm")
@ConfigurationPropertiesScan(basePackages = ["ru.touchin.push.message.provider.fcm"])
@Import(value = [PushMessageProviderConfiguration::class])
class PushMessageProviderFcmConfiguration {
@Bean
fun firebaseMessaging(
properties: PushMessageProviderFcmProperties
): FirebaseMessaging {
val credentials = GoogleCredentials.fromStream(ClassPathResource(properties.auth.resourcePath).inputStream)
val options: FirebaseOptions = FirebaseOptions.builder()
.setCredentials(credentials)
.setConnectTimeout(properties.client.connectionTimeout.toMillis().toInt())
.setReadTimeout(properties.client.readTimeout.toMillis().toInt())
.build()
val firebaseApp: FirebaseApp = FirebaseApp.initializeApp(options, properties.appName)
return FirebaseMessaging.getInstance(firebaseApp)
}
}

View File

@ -0,0 +1,24 @@
package ru.touchin.push.message.provider.fcm.converters
import com.google.firebase.messaging.FirebaseMessagingException
import com.google.firebase.messaging.MessagingErrorCode
import org.springframework.stereotype.Component
import ru.touchin.common.exceptions.CommonException
import ru.touchin.push.message.provider.exceptions.InvalidPushTokenException
import ru.touchin.push.message.provider.exceptions.PushMessageProviderException
@Component
class FirebaseMessagingExceptionConverter {
operator fun invoke(exception: FirebaseMessagingException): CommonException {
return when (exception.messagingErrorCode) {
MessagingErrorCode.INVALID_ARGUMENT,
MessagingErrorCode.UNREGISTERED -> InvalidPushTokenException()
else -> PushMessageProviderException(
description = exception.message.orEmpty(),
cause = exception
)
}
}
}

View File

@ -0,0 +1,18 @@
package ru.touchin.push.message.provider.fcm.converters
import com.google.firebase.messaging.Notification as FcmNotification
import org.springframework.stereotype.Component
import ru.touchin.push.message.provider.dto.Notification
@Component
class NotificationConverter {
operator fun invoke(notification: Notification): FcmNotification {
return FcmNotification.builder()
.setTitle(notification.title)
.setBody(notification.description)
.setImage(notification.imageUrl)
.build()
}
}

View File

@ -0,0 +1,29 @@
package ru.touchin.push.message.provider.fcm.converters
import com.google.firebase.messaging.Message
import org.springframework.stereotype.Component
import ru.touchin.push.message.provider.dto.Notification
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
@Component
class PushTokenMessageConverter(
private val notificationConverter: NotificationConverter
) {
operator fun invoke(request: PushTokenMessage): Message {
return Message.builder()
.setToken(request.token)
.setIfExists(request.notification)
.putAllData(request.data)
.build()
}
private fun Message.Builder.setIfExists(notification: Notification?): Message.Builder {
return if (notification != null) {
setNotification(notificationConverter(notification))
} else {
this
}
}
}

View File

@ -0,0 +1,31 @@
package ru.touchin.push.message.provider.fcm.properties
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.ConstructorBinding
import ru.touchin.push.message.provider.enums.PlatformType
import ru.touchin.push.message.provider.enums.PushMessageProviderType
import ru.touchin.push.message.provider.properties.PushMessageProviderProperties
import java.time.Duration
@ConstructorBinding
@ConfigurationProperties(prefix = "push-message-provider.fcm")
class PushMessageProviderFcmProperties(
val appName: String,
val auth: Auth.Credentials,
val client: Client
) {
sealed interface Auth {
data class Credentials(
val resourcePath: String
) : Auth
}
data class Client(
val readTimeout: Duration,
val connectionTimeout: Duration
)
}

View File

@ -0,0 +1,27 @@
package ru.touchin.push.message.provider.fcm.services
import org.springframework.stereotype.Service
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
import ru.touchin.push.message.provider.dto.request.SendPushRequest
import ru.touchin.push.message.provider.dto.result.SendPushResult
import ru.touchin.push.message.provider.enums.PushMessageProviderType
import ru.touchin.push.message.provider.exceptions.InvalidPushTokenException
import ru.touchin.push.message.provider.exceptions.PushMessageProviderException
import ru.touchin.push.message.provider.fcm.clients.FcmClient
import ru.touchin.push.message.provider.services.PushMessageProviderService
@Service
class PushMessageProviderFcmService(
private val fcmClient: FcmClient
) : PushMessageProviderService {
override val type: PushMessageProviderType = PushMessageProviderType.FCM
@Throws(PushMessageProviderException::class, InvalidPushTokenException::class)
override fun send(request: SendPushRequest): SendPushResult {
return when (request) {
is PushTokenMessage -> fcmClient.sendPushTokenMessage(request)
}
}
}

View File

@ -0,0 +1,29 @@
package ru.touchin.push.message.provider.fcm
import com.fasterxml.jackson.annotation.JsonAutoDetect
import com.fasterxml.jackson.annotation.PropertyAccessor
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature
import org.springframework.boot.SpringBootConfiguration
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Import
import org.springframework.test.context.ContextConfiguration
import ru.touchin.push.message.provider.fcm.configurations.PushMessageProviderFcmConfiguration
@TestConfiguration
@SpringBootConfiguration
@EnablePushMessageProviderFcm
class PushMessageProviderFcmTestApplication {
@Bean
fun objectMapper(): ObjectMapper {
return ObjectMapper().apply {
configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
}
}
}

View File

@ -0,0 +1,48 @@
package ru.touchin.push.message.provider.fcm.converters
import com.fasterxml.jackson.databind.ObjectMapper
import org.junit.Assert
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import ru.touchin.push.message.provider.dto.Notification
import com.google.firebase.messaging.Notification as FcmNotification
import org.junit.jupiter.api.DisplayName
@SpringBootTest
class NotificationConverterTest {
@Autowired
lateinit var notificationConverter: NotificationConverter
@Autowired
lateinit var objectMapper: ObjectMapper
@Test
@DisplayName("Конвертация уведомления происходит корректно")
fun invoke_basic() {
val notification = Notification(
title = "title",
description = "description",
imageUrl = "imageUrl"
)
val realResult = notificationConverter(notification)
val realResultJson = objectMapper.writeValueAsString(realResult)
val expectedResult = FcmNotification.builder()
.setTitle(notification.title)
.setBody(notification.description)
.setImage(notification.imageUrl)
.build()
val expectedResultJson = objectMapper.writeValueAsString(expectedResult)
Assert.assertEquals(
"Конвертация некорректна",
realResultJson,
expectedResultJson
)
}
}

View File

@ -0,0 +1,83 @@
package ru.touchin.push.message.provider.fcm.converters
import com.fasterxml.jackson.databind.ObjectMapper
import com.google.firebase.messaging.Message
import org.junit.Assert
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import ru.touchin.push.message.provider.dto.Notification
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
@SpringBootTest
class PushTokenMessageConverterTest {
@Autowired
lateinit var pushTokenMessageConverter: PushTokenMessageConverter
@Autowired
lateinit var notificationConverter: NotificationConverter
@Autowired
lateinit var objectMapper: ObjectMapper
@Test
@DisplayName("Конвертация сообщения с уведомлением происходит корректно")
fun invoke_withNotification() {
val notification = Notification(
title = "title",
description = "description",
imageUrl = "imageUrl"
)
val pushTokenMessage = PushTokenMessage(
token = "token",
notification = notification,
data = mapOf("testKey" to "testvalue")
)
val realResult = pushTokenMessageConverter(pushTokenMessage)
val realResultJson = objectMapper.writeValueAsString(realResult)
val expectedResult = Message.builder()
.setToken(pushTokenMessage.token)
.setNotification(notificationConverter(notification))
.putAllData(pushTokenMessage.data)
.build()
val expectedResultJson = objectMapper.writeValueAsString(expectedResult)
Assert.assertEquals(
"Конвертация некорректна",
realResultJson,
expectedResultJson
)
}
@Test
@DisplayName("Конвертация сообщения без уведомления происходит корректно")
fun invoke_withoutNotification() {
val pushTokenMessage = PushTokenMessage(
token = "token",
notification = null,
data = mapOf("testKey" to "testvalue")
)
val realResult = pushTokenMessageConverter(pushTokenMessage)
val realResultJson = objectMapper.writeValueAsString(realResult)
val expectedResult = Message.builder()
.setToken(pushTokenMessage.token)
.putAllData(pushTokenMessage.data)
.build()
val expectedResultJson = objectMapper.writeValueAsString(expectedResult)
Assert.assertEquals(
"Конвертация некорректна",
realResultJson,
expectedResultJson
)
}
}

View File

@ -0,0 +1,50 @@
package ru.touchin.push.message.provider.fcm.services
import org.junit.Assert
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.Mockito
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.MockBean
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
import ru.touchin.push.message.provider.dto.result.SendPushTokenMessageResult
import ru.touchin.push.message.provider.fcm.clients.FcmClient
import ru.touchin.push.message.provider.services.PushMessageProviderService
@SpringBootTest
class PushMessageProviderFcmServiceTest {
@MockBean
lateinit var fcmClient: FcmClient
@Autowired
lateinit var pushMessageProviderService: PushMessageProviderService
@Test
@DisplayName("Обработка запроса на отправку единичного сообщения происходит корректно")
fun send_basic() {
val request = PushTokenMessage(
token = "testToken",
notification = null,
data = emptyMap()
)
val expectedResult = SendPushTokenMessageResult("testMessageId")
Mockito.`when`(
fcmClient.sendPushTokenMessage(request)
).thenReturn(
expectedResult
)
val realResult = pushMessageProviderService.send(request)
Assert.assertEquals(
"Обработка запроса на отправку единичного сообщения происходит некорректно",
expectedResult,
realResult
)
}
}

View File

@ -0,0 +1,13 @@
push-message-provider:
platformProviders:
ANDROID_GOOGLE:
- FCM
IOS:
- FCM
fcm:
appName: testAppName
auth:
resourcePath: credentials/firebase-admin.json
client:
readTimeout: 10s
connectionTimeout: 1s

View File

@ -0,0 +1,12 @@
{
"type": "service_account",
"project_id": "testProjectId",
"private_key_id": "privateKeyId",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALfBshaLMW2yddmAZJRNXTZzcSbwvY93Dnjj6naWgoBJoB3mOM5bcoyWwBw12A4rwecorz74OUOc6zdqX3j8hwsSyzgAUStKM5PkOvPNRKsI4eXAWU0fmb8h1jyXwftl7EzeBjEMBTpyXkgDk3wLfHN6ciCZrnQndOvS+mMl3b0hAgMBAAECgYEAmIQZByMSrITR0ewCDyFDO52HjhWEkF310hsBkNoNiOMTFZ3vCj/WjJ/W5dM+90wUTYN0KOSnytmkVUNh6K5Yekn+yRg/mBRTwwn88hU6umB8tUqoNz7AyUltAOGyQMWqAAcVgxV+mAp/Y018j69poEHgrW4qKol65/NRZyV7/J0CQQD4rCDjmxGEuA1yMzL2i8NyNl/5vvLVfLcEnVqpHbc1+KfUHZuY7iv38xpzfmErqhCxAXfQ52edq5rXmMIVSbFrAkEAvSvfSSK9XQDJl3NEyfR3BGbsoqKIYOuJAnv4OQPSODZfTNWhc11S8y914qaSWB+Iid9HoLvAIgPH5mrzPzjSowJBAJcw4FZCI+aTmOlEI8ous8gvMy8/X5lZWFUf7s0/2fKgmjmnPsE+ndEFJ6HsxturbLaR8+05pJAClARdRjN3OL0CQGoF+8gmw1ErztCmVyiFbms2MGxagesoN4r/5jg2Tw0YVENg/HMHHCWWNREJ4L2pNsJnNOL+N4oY6mHXEWwesdcCQCUYTfLYxi+Wg/5BSC7fgl/gu0mlx07AzMoMQLDOXdisV5rpxrOoT3BOLBqyccv37AZ3e2gqb8JYyNzO6C0zswQ=\n-----END PRIVATE KEY-----\n",
"client_email": "clientEmail",
"client_id": "clientId",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "clientX509CertUrl"
}

View File

@ -0,0 +1,16 @@
plugins {
id("kotlin")
id("kotlin-spring")
id("maven-publish")
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.springframework.boot:spring-boot")
implementation(project(":common"))
testImplementation("org.testcontainers:junit-jupiter")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

View File

@ -0,0 +1,8 @@
package ru.touchin.push.message.provider.configurations
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.context.annotation.ComponentScan
@ComponentScan("ru.touchin.push.message.provider")
@ConfigurationPropertiesScan(basePackages = ["ru.touchin.push.message.provider"])
class PushMessageProviderConfiguration

View File

@ -0,0 +1,7 @@
package ru.touchin.push.message.provider.dto
class Notification(
val title: String,
val description: String,
val imageUrl: String
)

View File

@ -0,0 +1,9 @@
package ru.touchin.push.message.provider.dto.request
import ru.touchin.push.message.provider.dto.Notification
class PushTokenMessage(
val token: String,
override val notification: Notification?,
override val data: Map<String, String>
) : SendPushRequest

View File

@ -0,0 +1,10 @@
package ru.touchin.push.message.provider.dto.request
import ru.touchin.push.message.provider.dto.Notification
sealed interface SendPushRequest {
val notification: Notification?
val data: Map<String, String>
}

View File

@ -0,0 +1,3 @@
package ru.touchin.push.message.provider.dto.result
sealed interface SendPushResult

View File

@ -0,0 +1,5 @@
package ru.touchin.push.message.provider.dto.result
class SendPushTokenMessageResult(
val messageId: String
) : SendPushResult

View File

@ -0,0 +1,8 @@
package ru.touchin.push.message.provider.enums
enum class PlatformType {
ANDROID_GOOGLE,
IOS
}

View File

@ -0,0 +1,7 @@
package ru.touchin.push.message.provider.enums
enum class PushMessageProviderType {
FCM
}

View File

@ -0,0 +1,5 @@
package ru.touchin.push.message.provider.exceptions
import ru.touchin.common.exceptions.CommonException
class InvalidPushTokenException : CommonException("Invalid push token")

View File

@ -0,0 +1,8 @@
package ru.touchin.push.message.provider.exceptions
import ru.touchin.common.exceptions.CommonException
open class PushMessageProviderException(
description: String,
cause: Throwable?
) : CommonException(description, cause)

View File

@ -0,0 +1,10 @@
package ru.touchin.push.message.provider.factories
import ru.touchin.push.message.provider.enums.PlatformType
import ru.touchin.push.message.provider.services.PushMessageProviderService
interface PushMessageProviderServiceFactory {
fun get(platformType: PlatformType): PushMessageProviderService
}

View File

@ -0,0 +1,25 @@
package ru.touchin.push.message.provider.factories
import org.springframework.stereotype.Component
import ru.touchin.common.exceptions.CommonException
import ru.touchin.push.message.provider.enums.PlatformType
import ru.touchin.push.message.provider.properties.PushMessageProviderProperties
import ru.touchin.push.message.provider.services.PushMessageProviderService
import kotlin.jvm.Throws
@Component
class PushMessageProviderServiceFactoryImpl(
private val pushMessageProviderProperties: PushMessageProviderProperties,
private val pushMessageProviderServices: List<PushMessageProviderService>
) : PushMessageProviderServiceFactory {
@Throws(CommonException::class)
override fun get(platformType: PlatformType): PushMessageProviderService {
val supportedProviderTypes = pushMessageProviderProperties.platformProviders[platformType]?.firstOrNull()
?: throw CommonException("Configuration has no setup for platform '$platformType'")
return pushMessageProviderServices.find { it.type == supportedProviderTypes }
?: throw CommonException("Configuration has no push message provider support for platform '$platformType'")
}
}

View File

@ -0,0 +1,12 @@
package ru.touchin.push.message.provider.properties
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.ConstructorBinding
import ru.touchin.push.message.provider.enums.PlatformType
import ru.touchin.push.message.provider.enums.PushMessageProviderType
@ConstructorBinding
@ConfigurationProperties(prefix = "push-message-provider")
class PushMessageProviderProperties(
val platformProviders: Map<PlatformType, List<PushMessageProviderType>>
)

View File

@ -0,0 +1,13 @@
package ru.touchin.push.message.provider.services
import ru.touchin.push.message.provider.dto.request.SendPushRequest
import ru.touchin.push.message.provider.dto.result.SendPushResult
import ru.touchin.push.message.provider.enums.PushMessageProviderType
interface PushMessageProviderService {
val type: PushMessageProviderType
fun send(request: SendPushRequest): SendPushResult
}

View File

@ -0,0 +1,14 @@
package ru.touchin.push.message.provider
import org.springframework.boot.SpringBootConfiguration
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Import
import org.springframework.test.context.ContextConfiguration
import ru.touchin.push.message.provider.configurations.PushMessageProviderConfiguration
@TestConfiguration
@SpringBootConfiguration
@ContextConfiguration(classes = [PushMessageProviderConfiguration::class])
@Import(PushMessageProviderConfiguration::class)
class PushMessageProviderTestApplication

View File

@ -0,0 +1,88 @@
package ru.touchin.push.message.provider.factories
import org.junit.Assert
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import ru.touchin.common.exceptions.CommonException
import ru.touchin.push.message.provider.dto.request.SendPushRequest
import ru.touchin.push.message.provider.dto.result.SendPushResult
import ru.touchin.push.message.provider.enums.PlatformType
import ru.touchin.push.message.provider.enums.PushMessageProviderType
import ru.touchin.push.message.provider.properties.PushMessageProviderProperties
import ru.touchin.push.message.provider.services.PushMessageProviderService
class PushMessageProviderServiceFactoryImplTest {
private val pushMessageProviderServiceFcm = object : PushMessageProviderService {
override val type: PushMessageProviderType = PushMessageProviderType.FCM
override fun send(request: SendPushRequest): SendPushResult = throw NotImplementedError()
}
@Test
@DisplayName("При отсутствии поддерживаемых платформ выбрасывается исключение")
fun get_platformNotFound() {
val pushMessageProviderServiceFactory = PushMessageProviderServiceFactoryImpl(
pushMessageProviderProperties = PushMessageProviderProperties(
platformProviders = emptyMap()
),
pushMessageProviderServices = listOf(pushMessageProviderServiceFcm)
)
Assert.assertThrows(
"Исключение не выбрасывается или принадлежит иному типу",
CommonException::class.java
) {
pushMessageProviderServiceFactory.get(PlatformType.IOS)
}
}
@Test
@DisplayName("При отсутствии назначенного провайдера у поддерживаемой платформы выбрасывается исключение")
fun get_providerServiceForPlatformNotFound() {
val pushMessageProviderServiceFactory = PushMessageProviderServiceFactoryImpl(
pushMessageProviderProperties = PushMessageProviderProperties(
platformProviders = mapOf(
PlatformType.IOS to emptyList()
)
),
pushMessageProviderServices = listOf(pushMessageProviderServiceFcm)
)
Assert.assertThrows(
"Исключение не выбрасывается или принадлежит иному типу",
CommonException::class.java
) {
pushMessageProviderServiceFactory.get(PlatformType.IOS)
}
}
@Test
@DisplayName("Настроенной платформе назначается первый сервис из доступных")
fun get_firstSupportedProviderService() {
val pushMessageProviderServiceFactory = PushMessageProviderServiceFactoryImpl(
pushMessageProviderProperties = PushMessageProviderProperties(
platformProviders = mapOf(PlatformType.IOS to listOf(PushMessageProviderType.FCM))
),
pushMessageProviderServices = listOf(
pushMessageProviderServiceFcm,
object : PushMessageProviderService {
override val type: PushMessageProviderType = PushMessageProviderType.FCM
override fun send(request: SendPushRequest): SendPushResult = throw NotImplementedError()
}
)
)
Assert.assertEquals(
"Платформе назначен не первый сервис из доступных",
pushMessageProviderServiceFcm,
pushMessageProviderServiceFactory.get(PlatformType.IOS)
)
}
}

View File

@ -0,0 +1,6 @@
push-message-provider:
platformProviders:
ANDROID_GOOGLE:
- FCM
IOS:
- FCM

View File

@ -42,6 +42,8 @@ include("exception-handler-spring-security-web")
include("exception-handler-logger-spring-web")
include("validation-spring")
include("version-spring-web")
include("push-message-provider")
include("push-message-provider-fcm")
include("response-wrapper-spring-web")
include("settings-spring-jpa")
include("security-authorization-server-core")