Skip to content

Commit

Permalink
fix: #185 fix conflict in kodemy-search/build.gradle
Browse files Browse the repository at this point in the history
  • Loading branch information
marcin-bn committed Dec 10, 2024
2 parents 60dd1e0 + 35a4f4d commit 9d13aa6
Showing 5 changed files with 332 additions and 1 deletion.
3 changes: 2 additions & 1 deletion kodemy-search/build.gradle
Original file line number Diff line number Diff line change
@@ -76,9 +76,10 @@ dependencies {
testImplementation 'org.springframework.cloud:spring-cloud-stream'
testImplementation 'org.springframework.cloud:spring-cloud-stream-test-binder'

testImplementation 'org.spockframework:spock-spring:2.4-M4-groovy-4.0'
testImplementation "org.apache.groovy:groovy"
testImplementation "org.apache.groovy:groovy-json"
testImplementation 'org.spockframework:spock-spring:2.4-M4-groovy-4.0'
testImplementation "org.testcontainers:spock:1.20.0"

testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package pl.sknikod.kodemysearch

import com.github.tomakehurst.wiremock.WireMockServer
import com.github.tomakehurst.wiremock.core.WireMockConfiguration
import org.springframework.boot.autoconfigure.ImportAutoConfiguration
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.testcontainers.spock.Testcontainers
import spock.lang.Specification

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@ContextConfiguration(classes = KodemySearchApplication.class)
@ImportAutoConfiguration(value = TestChannelBinderConfiguration.class)
@Testcontainers
abstract class SuperclassSpec extends Specification {

protected static final WireMockServer WIREMOCK
protected static int WIREMOCK_PORT = 9999

static {
WIREMOCK = new WireMockServer(
WireMockConfiguration.options()
.port(WIREMOCK_PORT)
)
}

@DynamicPropertySource
private static void containerProperties(DynamicPropertyRegistry registry) {

final String wiremockBaseUrl = "http://localhost:${WIREMOCK_PORT}"

Map.of(
"opensearch.host", wiremockBaseUrl,
"opensearch.username", "admin",
"opensearch.password", "admin",
"opensearch.indices.materials.name", "materials",
"opensearch.indices.materials.alias", "materials-alias",
"service.baseUrl.gateway", "${wiremockBaseUrl}/gateway",
"eureka.client.enabled", false,
).forEach {
key, value -> registry.add(key, { value })
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package pl.sknikod.kodemysearch.module.material

import pl.sknikod.kodemysearch.configuration.LogbookConfiguration
import pl.sknikod.kodemysearch.configuration.OpenSearchConfiguration
import pl.sknikod.kodemysearch.infrastructure.module.material.MaterialSearchService
import pl.sknikod.kodemysearch.infrastructure.module.material.MaterialSearchService$MaterialSearchMapperImpl
import pl.sknikod.kodemysearch.infrastructure.store.MaterialSearchStore
import pl.sknikod.kodemysearch.util.opensearch.OpenSearchClientEnhanced

class MaterialSearchHelper {

static MaterialSearchService createMaterialSearchService(String host = "http://localhost:9999",
String username = "admin",
String password = "admin",
String indexName = "materials",
String aliasName = "materials-alias") {
def properties = new OpenSearchConfiguration.OpenSearchProperties(
host: host,
username: username,
password: password,
indices: [
"materials": new OpenSearchClientEnhanced.Index(
name: indexName,
alias: aliasName
)
]
)

def openSearchClient = new OpenSearchConfiguration().openSearchClient(
properties,
new LogbookConfiguration().logbook()
)

def materialSearchStore = new MaterialSearchStore(openSearchClient)

return new MaterialSearchService(
materialSearchStore,
new MaterialSearchService$MaterialSearchMapperImpl()
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package pl.sknikod.kodemysearch.module.material


import org.springframework.data.domain.PageRequest
import pl.sknikod.kodemysearch.infrastructure.module.material.MaterialSearchService
import pl.sknikod.kodemysearch.infrastructure.module.material.MaterialSearchService$MaterialSearchMapperImpl
import pl.sknikod.kodemysearch.infrastructure.store.MaterialSearchStore
import spock.lang.Specification
import spock.lang.Subject
import spock.lang.Unroll

import static pl.sknikod.kodemysearch.infrastructure.rest.MaterialControllerDefinition.*

class MaterialSearchServiceSpec extends Specification {

def materialSearchStore = Mock(MaterialSearchStore)

@Subject
MaterialSearchService materialSearchService = new MaterialSearchService(materialSearchStore, new MaterialSearchService$MaterialSearchMapperImpl())

@Unroll
def "should create search criteria from filter search params for #description"() {
given:
def filterSearchParams = params
def pageable = PageRequest.of(0, 10)

when:
try {
materialSearchService.search(filterSearchParams as MaterialFilterSearchParams, pageable)
} catch (Exception ignored) {
// We don't care about the result. We only check creating search criteria
}

then: "search criteria are created based on filter search params"
1 * materialSearchStore.search({
it.anyPhrase == filterSearchParams.phrase &&
it.pageable == pageable &&
it.phraseFields.size() == expected.phraseFieldsCount &&
it.phraseFields.any { field -> field.name == "id" && field.value == filterSearchParams.id.toString() } &&
it.phraseFields.any { field -> field.name == "sectionId" && field.value == filterSearchParams.sectionId.toString() } &&
it.arrayFields.size() == expected.arrayFieldsCount &&
it.arrayFields.any { field -> field.name == "categoryId" && field.values == filterSearchParams.categoryIds.collect { it.toString() } } &&
it.rangeFields.size() == expected.rangeFieldsCount &&
it.rangeFields.any { field -> field.name == "avgGrade" && field.from == filterSearchParams.minAvgGrade && field.to == filterSearchParams.maxAvgGrade }
})

where:
[params, expected, description] << searchParamsProvider()
}

def searchParamsProvider() {
return [[
params: new MaterialFilterSearchParams(
phrase: "phrase1",
id: 1L,
sectionId: 1L,
categoryIds: [1L],
minAvgGrade: 2.2f,
maxAvgGrade: 4.2f
),
expected: [
phraseFieldsCount: 2,
arrayFieldsCount: 1,
rangeFieldsCount: 1
],
description: "Standard case with all fields populated"
],
[
params: new MaterialFilterSearchParams(
phrase: "searchText",
id: 10L,
sectionId: 5L,
categoryIds: [3L, 4L, 5L],
minAvgGrade: 1.0f,
maxAvgGrade: 5.0f
),
expected: [
phraseFieldsCount: 2,
arrayFieldsCount: 1,
rangeFieldsCount: 1
],
description: "Case with multiple categories"
]]
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package pl.sknikod.kodemysearch.module.material

import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import pl.sknikod.kodemysearch.SuperclassSpec
import pl.sknikod.kodemysearch.configuration.LogbookConfiguration
import pl.sknikod.kodemysearch.configuration.OpenSearchConfiguration
import pl.sknikod.kodemysearch.infrastructure.module.material.MaterialSearchService
import pl.sknikod.kodemysearch.infrastructure.module.material.MaterialSearchService$MaterialSearchMapperImpl
import pl.sknikod.kodemysearch.infrastructure.module.material.model.MaterialPageable
import pl.sknikod.kodemysearch.infrastructure.rest.MaterialControllerDefinition
import pl.sknikod.kodemysearch.infrastructure.store.MaterialSearchStore
import pl.sknikod.kodemysearch.util.opensearch.OpenSearchClientEnhanced
import spock.lang.Shared
import spock.lang.Subject

import static com.github.tomakehurst.wiremock.client.WireMock.*
import static org.assertj.core.api.Assertions.assertThat
import static pl.sknikod.kodemysearch.module.material.MaterialSearchHelper.createMaterialSearchService

class MaterialSearchServiceWiremockSpec extends SuperclassSpec {

@Subject
MaterialSearchService materialSearchService = createMaterialSearchService()

def setupSpec() {
WIREMOCK.start()
setupWireMockStubs()
}

def cleanupSpec() {
WIREMOCK.stop()
}

def "should search materials and map results correctly"() {
given: "A mocked OpenSearch response"
WIREMOCK.stubFor(post(urlPathMatching("/materials/_search"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/json")
.withBody("""
{
"took": 123,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {"value": 2, "relation": "eq"},
"hits": [
{
"_source": {
"id": 1,
"title": "Material 1",
"description": "Description 1",
"status": "APPROVED",
"active": true,
"avgGrade": 4.5,
"author": {"id": 100, "username": "Author1"},
"createdDate": "2024-12-07T10:00:00Z",
"sectionId": 10,
"categoryId": 20,
"tags": [{"id": 1, "name": "Tag1"}]
}
},
{
"_source": {
"id": 2,
"title": "Material 2",
"description": "Description 2",
"status": "DRAFT",
"isActive": false,
"avgGrade": 3.0,
"author": {"id": 200, "username": "Author2"},
"createdDate": "2024-12-07T10:00:00Z",
"sectionId": 11,
"categoryId": 21,
"tags": [{"id": 2, "name": "Tag2"}]
}
}
]
}
}
""")))

and: "Search criteria and pageable parameters"
def searchParams = new MaterialControllerDefinition.MaterialFilterSearchParams(phrase: "Material")
Pageable pageable = PageRequest.of(0, 10)

when: "The search method is called"
Page<MaterialPageable> result = materialSearchService.search(searchParams, pageable)

then: "The results are correctly mapped"
assertThat(result).isNotNull()
assertThat(result.content).hasSize(2)

with(result.content[0]) {
assertThat(id).isEqualTo(1)
assertThat(title).isEqualTo("Material 1")
assertThat(description).isEqualTo("Description 1")
assertThat(isActive).isTrue()
assertThat(avgGrade).isEqualTo(4.5f)
assertThat(author.username).isEqualTo("Author1")
assertThat(sectionId).isEqualTo(10)
assertThat(categoryId).isEqualTo(20)
assertThat(tags).hasSize(1)
assertThat(tags[0].name).isEqualTo("Tag1")
}

with(result.content[1]) {
assertThat(id).isEqualTo(2)
assertThat(title).isEqualTo("Material 2")
assertThat(description).isEqualTo("Description 2")
assertThat(isActive).isFalse()
assertThat(avgGrade).isEqualTo(3.0f)
assertThat(author.username).isEqualTo("Author2")
assertThat(sectionId).isEqualTo(11)
assertThat(categoryId).isEqualTo(21)
assertThat(tags).hasSize(1)
assertThat(tags[0].name).isEqualTo("Tag2")
}

and: "The correct request was sent to OpenSearch"
WIREMOCK.verify(postRequestedFor(urlPathMatching("/materials/_search"))
.withRequestBody(matching(".*")))
}


private static void setupWireMockStubs() {
WIREMOCK.stubFor(head(urlPathEqualTo("/materials"))
.willReturn(aResponse().withStatus(200)))

WIREMOCK.stubFor(put(urlPathEqualTo("/materials"))
.willReturn(aResponse().withStatus(201).withBody("""
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "materials"
}
""")))

WIREMOCK.stubFor(head(urlPathEqualTo("/materials/_alias/materials-alias"))
.willReturn(aResponse().withStatus(404)))

WIREMOCK.stubFor(post(urlPathEqualTo("/_aliases"))
.willReturn(aResponse().withStatus(200).withBody("""
{
"acknowledged": true
}
""")))
}

}

0 comments on commit 9d13aa6

Please sign in to comment.