add send method to product service

This commit is contained in:
Savosin Denis
2025-06-03 11:34:28 +07:00
parent 1bda2e1d21
commit a8639f8d15
8 changed files with 80 additions and 19 deletions

View File

@@ -3,11 +3,10 @@ version = "single-version"
dependencies {
implementation(project(":db"))
implementation(project(":edge-producing"))
implementation(rootProject.libs.spring.boot.starter.actuator)
implementation(rootProject.libs.spring.boot.starter.jdbc)
implementation(rootProject.libs.spring.boot.starter.validation)
implementation(rootProject.libs.json.schema.validator)
testImplementation(rootProject.libs.spring.boot.starter.actuatorAutoconfigure)
}

View File

@@ -0,0 +1,6 @@
package com.github.dannecron.demo.core.exceptions
class InvalidDataException(
override val message: String,
override val cause: Throwable?,
) : RuntimeException(message, cause)

View File

@@ -1,3 +1,3 @@
package com.github.dannecron.demo.core.exceptions
class ProductNotFoundException: ModelNotFoundException("product")
class ProductNotFoundException: ModelNotFoundException("json-schemas/kafka/product")

View File

@@ -2,6 +2,7 @@ package com.github.dannecron.demo.core.services.product
import com.github.dannecron.demo.core.dto.Product
import com.github.dannecron.demo.core.exceptions.AlreadyDeletedException
import com.github.dannecron.demo.core.exceptions.InvalidDataException
import com.github.dannecron.demo.core.exceptions.ProductNotFoundException
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
@@ -16,4 +17,7 @@ interface ProductService {
@Throws(ProductNotFoundException::class, AlreadyDeletedException::class)
fun delete(guid: UUID): Product
@Throws(ProductNotFoundException::class, InvalidDataException::class)
fun send(guid: UUID, topic: String?)
}

View File

@@ -2,21 +2,26 @@ package com.github.dannecron.demo.core.services.product
import com.github.dannecron.demo.core.dto.Product
import com.github.dannecron.demo.core.exceptions.AlreadyDeletedException
import com.github.dannecron.demo.core.exceptions.InvalidDataException
import com.github.dannecron.demo.core.exceptions.ProductNotFoundException
import com.github.dannecron.demo.core.services.generation.CommonGenerator
import com.github.dannecron.demo.core.utils.LoggerDelegate
import com.github.dannecron.demo.db.entity.ProductEntity
import com.github.dannecron.demo.db.repository.ProductRepository
import com.github.dannecron.demo.edgeproducing.dto.ProductDto
import com.github.dannecron.demo.edgeproducing.producer.ProductProducer
import net.logstash.logback.marker.Markers
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import java.time.format.DateTimeFormatter
import java.util.UUID
@Service
class ProductServiceImpl(
private val productRepository: ProductRepository,
private val commonGenerator: CommonGenerator,
private val productProducer: ProductProducer,
): ProductService {
private val logger by LoggerDelegate()
@@ -58,6 +63,13 @@ class ProductServiceImpl(
.toCore()
}
@Throws(ProductNotFoundException::class, InvalidDataException::class)
override fun send(guid: UUID, topic: String?) {
val product = findByGuid(guid) ?: throw ProductNotFoundException()
productProducer.produceProductSync(product.toProducingDto())
}
private fun ProductEntity.toCore() = Product(
id = id!!,
guid = guid,
@@ -79,4 +91,15 @@ class ProductServiceImpl(
updatedAt = updatedAt,
deletedAt = deletedAt,
)
private fun Product.toProducingDto() = ProductDto(
id = id,
guid = guid.toString(),
name = name,
description = description,
price = price,
createdAt = createdAt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
updatedAt = updatedAt?.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
deletedAt = deletedAt?.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
)
}

View File

@@ -6,6 +6,8 @@ import com.github.dannecron.demo.core.exceptions.ProductNotFoundException
import com.github.dannecron.demo.core.services.generation.CommonGenerator
import com.github.dannecron.demo.db.entity.ProductEntity
import com.github.dannecron.demo.db.repository.ProductRepository
import com.github.dannecron.demo.edgeproducing.dto.ProductDto
import com.github.dannecron.demo.edgeproducing.producer.ProductProducer
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.mockito.kotlin.any
@@ -14,8 +16,10 @@ import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoInteractions
import org.mockito.kotlin.whenever
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
import java.util.UUID
import kotlin.test.assertEquals
@@ -24,6 +28,7 @@ class ProductServiceImplTest {
private val mockCurrentTime = OffsetDateTime.now()
private val productRepository: ProductRepository = mock()
private val productProducer: ProductProducer = mock()
private val commonGenerator: CommonGenerator = mock {
on { generateUUID() } doReturn mockGuid
on { generateCurrentTime() } doReturn mockCurrentTime
@@ -32,6 +37,7 @@ class ProductServiceImplTest {
private val productService = ProductServiceImpl(
productRepository = productRepository,
commonGenerator = commonGenerator,
productProducer = productProducer,
)
private val guid = UUID.randomUUID()
@@ -55,6 +61,16 @@ class ProductServiceImplTest {
updatedAt = mockCurrentTime.minusHours(2),
deletedAt = null,
)
private val producingProductDto = ProductDto(
id = 123,
guid = guid.toString(),
name = "name",
description = "description",
price = 10050,
createdAt = mockCurrentTime.minusDays(1).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
updatedAt = mockCurrentTime.minusHours(2).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
deletedAt = null,
)
@Test
fun create() {
@@ -127,4 +143,30 @@ class ProductServiceImplTest {
verify(productRepository, times(1)).findByGuid(guid)
verify(productRepository, never()).save(any())
}
@Test
fun `send - success`() {
val topic = "some-topic"
whenever(productRepository.findByGuid(any())).thenReturn(productEntity)
productService.send(guid, topic)
verify(productRepository, times(1)).findByGuid(guid)
verify(productProducer, times(1)).produceProductSync(producingProductDto)
}
@Test
fun `send - not found`() {
val topic = "some-topic"
whenever(productRepository.findByGuid(any())).thenReturn(null)
assertThrows<ProductNotFoundException> {
productService.send(guid, topic)
}
verify(productRepository, times(1)).findByGuid(guid)
verifyNoInteractions(productProducer)
}
}