Skip to content

Commit 18afa5c

Browse files
authored
Merge pull request #5 from TheMeinerLP/feature/unit-tests
Add unit tests
2 parents 39a13a7 + c218a2b commit 18afa5c

File tree

17 files changed

+477
-21
lines changed

17 files changed

+477
-21
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Check if code still running
2+
3+
on: pull_request
4+
5+
concurrency:
6+
group: pr-${{ github.base_ref }}-${{ github.head_ref }}
7+
cancel-in-progress: true
8+
9+
jobs:
10+
detekt:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v2
14+
- name: Set up JDK 1.8
15+
uses: actions/setup-java@v1
16+
with:
17+
java-version: 1.8
18+
- name: Run Tests
19+
run: gradle test
20+
- name: Publish Unit Test Results
21+
uses: EnricoMi/publish-unit-test-result-action@v1
22+
if: always()
23+
with:
24+
check_name: 'unit test results'
25+
files: build/test-results/**/*.xml
26+
ktlint:
27+
name: ktlint
28+
runs-on: ubuntu-latest
29+
30+
steps:
31+
- name: Clone repo
32+
uses: actions/checkout@master
33+
with:
34+
fetch-depth: 1
35+
- name: ktlint
36+
uses: ScaCap/action-ktlint@master
37+
with:
38+
github_token: ${{ secrets.GITHUB_TOKEN }}
39+
reporter: github-pr-review

build.gradle.kts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ plugins {
88
id("org.openapi.generator") version "5.3.0"
99
id("org.hidetake.swagger.generator") version "2.18.2"
1010
id("org.jetbrains.changelog") version "1.3.1"
11+
id("io.gitlab.arturbosch.detekt") version "1.17.1"
1112

1213

1314
kotlin("jvm") version "1.5.31"
@@ -61,8 +62,15 @@ dependencies {
6162

6263
swaggerUI("org.webjars:swagger-ui:3.52.5")
6364
swaggerCodegen("io.swagger.codegen.v3:swagger-codegen-cli:3.0.28")
64-
//testImplementation("org.springframework.boot:spring-boot-starter-test")
65-
//testImplementation("io.projectreactor:reactor-test")
65+
66+
// Unit Testing
67+
testImplementation("org.springframework.boot:spring-boot-starter-test")
68+
69+
// Test Containers
70+
testImplementation("org.testcontainers:testcontainers-bom:1.16.2")
71+
testImplementation("org.testcontainers:junit-jupiter:1.16.2")
72+
testApi("org.testcontainers:mongodb:1.16.2")
73+
6674
}
6775

6876

@@ -75,10 +83,6 @@ tasks {
7583
jvmTarget = "1.8"
7684
}
7785
}
78-
79-
test {
80-
useJUnitPlatform()
81-
}
8286
bootBuildImage {
8387
imageName = if (System.getenv("repository") != null) {
8488
"ghcr.io/${System.getenv("repository").toLowerCase()}/${project.name.toLowerCase()}:${project.version}"
@@ -95,6 +99,9 @@ tasks {
9599
}
96100
isPublish = true
97101
}
102+
test {
103+
useJUnitPlatform()
104+
}
98105
}
99106

100107
changelog {

src/main/kotlin/dev/themeinerlp/skinserver/SkinServerApplication.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication
88
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
99
import org.springframework.boot.context.properties.EnableConfigurationProperties
1010
import org.springframework.boot.runApplication
11+
import org.springframework.context.annotation.Bean
12+
import org.springframework.data.mongodb.MongoDatabaseFactory
13+
import org.springframework.data.mongodb.MongoTransactionManager
14+
1115

1216
@OpenAPIDefinition(
1317
info = Info(
@@ -25,7 +29,13 @@ import org.springframework.boot.runApplication
2529
)
2630
@ConfigurationPropertiesScan
2731
@EnableConfigurationProperties(value = [SkinServerProperties::class])
28-
class SkinServerApplication
32+
class SkinServerApplication {
33+
34+
@Bean
35+
fun transactionManager(dbFactory: MongoDatabaseFactory): MongoTransactionManager {
36+
return MongoTransactionManager(dbFactory)
37+
}
38+
}
2939

3040
fun main(args: Array<String>) {
3141
runApplication<SkinServerApplication>(*args)

src/main/kotlin/dev/themeinerlp/skinserver/handler/render/RenderHandlerImpl.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import org.springframework.http.HttpStatus
99
import org.springframework.http.MediaType
1010
import org.springframework.http.ResponseEntity
1111
import org.springframework.stereotype.Component
12-
import org.springframework.web.multipart.MultipartFile
1312
import org.springframework.web.server.ResponseStatusException
13+
import javax.servlet.http.Part
1414

1515
@Component
1616
class RenderHandlerImpl(
@@ -19,19 +19,18 @@ class RenderHandlerImpl(
1919
) : RenderDatabaseHandler {
2020

2121
override fun renderHead(
22-
skin: MultipartFile?,
22+
skin: Part?,
2323
size: Int?,
2424
rotation: HeadView?,
2525
layer: Boolean?
2626
): ResponseEntity<Any> {
2727
size ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Size is empty")
2828
skin ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Skin is empty")
29-
rotation ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Rotation is empty")
3029
if (size < skinServerProperties.minSize || size > skinServerProperties.maxSize) {
3130
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Size are to small or to big")
3231
}
3332
val content = skin.inputStream.use {
34-
this.renderService.renderHeadFromByteArray(size, rotation, it.readBytes(), layer ?: true)
33+
this.renderService.renderHeadFromByteArray(size, rotation ?: HeadView.Front, it.readBytes(), layer ?: true)
3534
}
3635
return ResponseEntity.ok().contentType(MediaType.IMAGE_PNG).body(InputStreamResource(content.inputStream()))
3736
}

src/main/kotlin/dev/themeinerlp/skinserver/spec/dao/skin/Skin.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import org.springframework.data.mongodb.core.mapping.Document
66

77
@Document
88
data class Skin(
9-
@Id val uuid: UUID? = null,
9+
@Id val uuid: UUID? = UUID.randomUUID(),
1010
val skinUrl: String? = null,
1111
val texture: String? = null,
1212
val username: String? = null

src/main/kotlin/dev/themeinerlp/skinserver/spec/handler/render/RenderHandler.kt

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses
99
import org.springframework.beans.factory.annotation.Autowired
1010
import org.springframework.http.MediaType
1111
import org.springframework.http.ResponseEntity
12+
import javax.servlet.http.Part
1213
import org.springframework.web.bind.annotation.*
13-
import org.springframework.web.multipart.MultipartFile
1414

1515
interface RenderDatabaseHandler {
16-
fun renderHead(skin: MultipartFile?, size: Int?, rotation: HeadView?, layer: Boolean?): ResponseEntity<Any>
16+
fun renderHead(skin: Part?, size: Int?, rotation: HeadView?, layer: Boolean?): ResponseEntity<Any>
1717
}
1818

1919
@RestController
@@ -47,11 +47,6 @@ class RenderHandler {
4747
responseCode = "404",
4848
content = []
4949
),
50-
ApiResponse(
51-
description = "view is empty",
52-
responseCode = "404",
53-
content = []
54-
),
5550
ApiResponse(
5651
description = "Size are to small or to big",
5752
responseCode = "500",
@@ -72,7 +67,7 @@ class RenderHandler {
7267
required = true,
7368
)
7469
@RequestPart(required = true)
75-
skin: MultipartFile?,
70+
skin: Part?,
7671
@Parameter(
7772
description = "Head scale, default is 64",
7873
required = true,

src/main/kotlin/dev/themeinerlp/skinserver/spec/repository/skin/SkinRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import dev.themeinerlp.skinserver.spec.dao.skin.Skin
44
import java.util.UUID
55
import org.springframework.data.mongodb.repository.MongoRepository
66

7-
interface SkinRepository : MongoRepository<Skin, String> {
7+
interface SkinRepository : MongoRepository<Skin, UUID> {
88

99
fun findByUuid(uuid: UUID): Skin?
1010
fun findByUsernameIgnoreCase(username: String): Skin?
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package dev.themeinerlp.skinserver
2+
3+
import dev.themeinerlp.skinserver.service.testcontainer.TestContainer
4+
import dev.themeinerlp.skinserver.utils.TestUtilsImplementation
5+
import org.junit.jupiter.api.extension.ExtendWith
6+
import org.springframework.beans.factory.annotation.Autowired
7+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
8+
import org.springframework.boot.test.context.SpringBootTest
9+
import org.springframework.test.context.ActiveProfiles
10+
import org.springframework.test.context.ContextConfiguration
11+
import org.springframework.test.context.junit.jupiter.SpringExtension
12+
import org.springframework.test.web.servlet.MockMvc
13+
14+
15+
@ExtendWith(SpringExtension::class)
16+
@SpringBootTest(classes = [SkinServerApplication::class])
17+
@AutoConfigureMockMvc
18+
@ActiveProfiles("test")
19+
@ContextConfiguration(initializers = [TestContainer::class])
20+
abstract class TestBase {
21+
22+
@Autowired
23+
lateinit var mockMvc: MockMvc
24+
25+
@Autowired
26+
lateinit var testUtilsImplementation: TestUtilsImplementation
27+
28+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package dev.themeinerlp.skinserver.handler.head.integration
2+
3+
import dev.themeinerlp.skinserver.TestBase
4+
import dev.themeinerlp.skinserver.spec.dao.skin.Skin
5+
import dev.themeinerlp.skinserver.spec.repository.skin.SkinRepository
6+
import dev.themeinerlp.skinserver.utils.HeadView
7+
import java.nio.file.Files
8+
import java.util.Base64
9+
import org.junit.jupiter.api.Test
10+
import org.junit.jupiter.params.ParameterizedTest
11+
import org.junit.jupiter.params.provider.EnumSource
12+
import org.springframework.beans.factory.annotation.Autowired
13+
import org.springframework.core.io.ResourceLoader
14+
import org.springframework.http.MediaType
15+
import org.springframework.test.web.servlet.get
16+
import org.springframework.transaction.annotation.Transactional
17+
18+
@Transactional
19+
class HeadHandlerTest : TestBase() {
20+
21+
@Autowired
22+
lateinit var skinRepository: SkinRepository
23+
24+
@Autowired
25+
lateinit var resourceLoader: ResourceLoader
26+
27+
fun createTestData(): Skin {
28+
return skinRepository.save(
29+
Skin(
30+
username = "fakeuser",
31+
skinUrl = "fakeurl",
32+
texture = Base64.getEncoder()
33+
.encodeToString(Files.readAllBytes(resourceLoader.getResource("classpath:fakeuser.png").file.toPath()))
34+
)
35+
)
36+
}
37+
38+
@Test
39+
fun `get Skin by Username`() {
40+
createTestData()
41+
mockMvc.get("/head/username/64/fakeuser/") {
42+
accept(MediaType.IMAGE_PNG)
43+
contentType = MediaType.IMAGE_PNG
44+
}.andExpect {
45+
status {
46+
isOk()
47+
}
48+
}
49+
}
50+
51+
@Test
52+
fun `get Skin by UUID`() {
53+
val uuid = createTestData().uuid
54+
mockMvc.get("/head/uuid/64/$uuid/") {
55+
accept(MediaType.IMAGE_PNG)
56+
contentType = MediaType.IMAGE_PNG
57+
}.andExpect {
58+
status {
59+
isOk()
60+
}
61+
}
62+
}
63+
64+
@ParameterizedTest
65+
@EnumSource(HeadView::class)
66+
fun `get Skin by UUID different rotations`(rotation: HeadView) {
67+
val uuid = createTestData().uuid
68+
mockMvc.get("/head/uuid/64/$uuid/$rotation/") {
69+
accept(MediaType.IMAGE_PNG)
70+
contentType = MediaType.IMAGE_PNG
71+
}.andExpect {
72+
status {
73+
isOk()
74+
}
75+
}
76+
}
77+
78+
@ParameterizedTest
79+
@EnumSource(HeadView::class)
80+
fun `get Skin by Username different rotations`(rotation: HeadView) {
81+
createTestData()
82+
mockMvc.get("/head/username/64/fakeuser/$rotation/") {
83+
accept(MediaType.IMAGE_PNG)
84+
contentType = MediaType.IMAGE_PNG
85+
}.andExpect {
86+
status {
87+
isOk()
88+
}
89+
}
90+
}
91+
92+
}

0 commit comments

Comments
 (0)