Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

integration test setup #11

Merged
merged 1 commit into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions compose/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ services:
- "5432:5432"
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: oppivelvollisuus_it
POSTGRES_USER: oppivelvollisuus
POSTGRES_PASSWORD: postgres

oppivelvollisuus-db-it:
image: postgres:15.4-alpine3.18
ports:
- "6432:5432"
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: oppivelvollisuus
POSTGRES_USER: oppivelvollisuus
Expand All @@ -15,3 +26,5 @@ services:
volumes:
db-data:
driver: local
db-it-data:
driver: local
6 changes: 6 additions & 0 deletions service/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ repositories {
}

dependencies {
api(kotlin("stdlib"))
implementation("org.jetbrains.kotlin:kotlin-reflect")

implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
Expand All @@ -37,6 +38,9 @@ dependencies {

implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

testImplementation(kotlin("test"))
testImplementation(kotlin("test-junit5"))
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

Expand All @@ -49,6 +53,8 @@ tasks.withType<KotlinCompile> {

tasks.withType<Test> {
useJUnitPlatform()
testClassesDirs = sourceSets["test"].output.classesDirs
classpath = sourceSets["test"].runtimeClasspath
}

tasks.getByName<Jar>("jar") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,25 @@ fun main(args: Array<String>) {
}

@RestController
class HelloWorldController {
class MainController {
@Autowired
lateinit var jdbi: Jdbi

data class StudentInput(
val firstName: String,
val lastName: String
)

@PostMapping("/students")
fun createStudent(@RequestBody body: StudentInput): UUID {
val id = UUID.randomUUID()
jdbi.inTransactionUnchecked { tx ->
tx.createUpdate("""
tx.createUpdate(
"""
INSERT INTO students (id, first_name, last_name)
VALUES (:id, :firstName, :lastName)
""")
"""
)
.bind("id", id)
.bindKotlin(body)
.execute()
Expand All @@ -53,6 +56,7 @@ class HelloWorldController {
val firstName: String,
val lastName: String
)

@GetMapping("/students")
fun getStudents(): List<StudentBasics> {
return jdbi.inTransactionUnchecked { tx ->
Expand All @@ -61,14 +65,17 @@ class HelloWorldController {
.list()
}
}

@GetMapping("/students/{id}")
fun getStudent(@PathVariable id: UUID): StudentBasics {
return jdbi.inTransactionUnchecked { tx ->
tx.createQuery("""
tx.createQuery(
"""
SELECT id, first_name, last_name
FROM students
WHERE id = :id
""".trimIndent())
""".trimIndent()
)
.bind("id", id)
.mapTo<StudentBasics>()
.findOne()
Expand All @@ -78,32 +85,37 @@ class HelloWorldController {
}

@PutMapping("/students/{id}")
fun updateStudent(@PathVariable id: UUID, @RequestBody body: StudentInput): Unit {
fun updateStudent(@PathVariable id: UUID, @RequestBody body: StudentInput) {
jdbi.inTransactionUnchecked { tx ->
tx.createUpdate("""
tx.createUpdate(
"""
UPDATE students
SET first_name = :firstName, last_name = :lastName
WHERE id = :id
""")
"""
)
.bind("id", id)
.bindKotlin(body)
.execute()
.also { if(it != 1) error("not found") }
.also { if (it != 1) error("not found") }
}
}

data class StudentCaseInput(
val openedAt: LocalDate,
val info: String
)

@PostMapping("/students/{studentId}/cases")
fun createStudentCase(@PathVariable studentId: UUID, @RequestBody body: StudentCaseInput): UUID {
val id = UUID.randomUUID()
jdbi.inTransactionUnchecked { tx ->
tx.createUpdate("""
tx.createUpdate(
"""
INSERT INTO student_cases (id, student_id, opened_at, info)
VALUES (:id, :studentId, :openedAt, :info)
""")
"""
)
.bind("id", id)
.bind("studentId", studentId)
.bindKotlin(body)
Expand All @@ -118,14 +130,17 @@ class HelloWorldController {
val openedAt: LocalDate,
val info: String
)

@GetMapping("/students/{studentId}/cases")
fun getStudentCasesByStudent(@PathVariable studentId: UUID): List<StudentCase> {
return jdbi.inTransactionUnchecked { tx ->
tx.createQuery("""
tx.createQuery(
"""
SELECT id, student_id, opened_at, info
FROM student_cases
WHERE student_id = :studentId
""".trimIndent())
""".trimIndent()
)
.bind("studentId", studentId)
.mapTo<StudentCase>()
.list()
Expand All @@ -139,18 +154,20 @@ class HelloWorldController {
@RequestBody body: StudentCaseInput
) {
jdbi.inTransactionUnchecked { tx ->
tx.createUpdate("""
tx.createUpdate(
"""
UPDATE student_cases
SET
opened_at = :openedAt,
info = :info
WHERE id = :id AND student_id = :studentId
""")
"""
)
.bind("id", id)
.bind("studentId", studentId)
.bindKotlin(body)
.execute()
.also { if(it != 1) error("not found") }
.also { if (it != 1) error("not found") }
}
}

Expand All @@ -161,17 +178,19 @@ class HelloWorldController {
val lastName: String,
val openedAt: LocalDate
)

@GetMapping("/students-cases")
fun getStudentCases(): List<StudentCaseSummary> {
return jdbi.inTransactionUnchecked { tx ->
tx.createQuery("""
tx.createQuery(
"""
SELECT c.id, student_id, first_name, last_name, opened_at, info
FROM student_cases c
JOIN students s on s.id = c.student_id
""".trimIndent())
""".trimIndent()
)
.mapTo<StudentCaseSummary>()
.list()
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package fi.espoo.oppivelvollisuus

import org.jdbi.v3.core.Jdbi
import org.jdbi.v3.core.kotlin.withHandleUnchecked
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.TestInstance
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
abstract class FullApplicationTest {
@Autowired
protected lateinit var jdbi: Jdbi

@BeforeAll
fun beforeAll() {
jdbi.withHandleUnchecked { tx ->
tx.execute(
"""
CREATE OR REPLACE FUNCTION reset_database() RETURNS void AS ${'$'}${'$'}
BEGIN
EXECUTE (
SELECT 'TRUNCATE TABLE ' || string_agg(quote_ident(table_name), ', ') || ' CASCADE'
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_type = 'BASE TABLE'
AND table_name <> 'flyway_schema_history'
);
EXECUTE (
SELECT 'SELECT ' || coalesce(string_agg(format('setval(%L, %L, false)', sequence_name, start_value), ', '), '')
FROM information_schema.sequences
WHERE sequence_schema = 'public'
);
END ${'$'}${'$'} LANGUAGE plpgsql;
""".trimIndent()
)
}
}

@BeforeEach
fun beforeEach() {
jdbi.withHandleUnchecked { tx ->
tx.execute("SELECT reset_database()")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package fi.espoo.oppivelvollisuus

import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.beans.factory.annotation.Autowired
import kotlin.test.assertEquals

@SpringBootTest
class ServiceApplicationTests {
class ServiceApplicationTests : FullApplicationTest() {
@Autowired
lateinit var controller: MainController

@Test
fun contextLoads() {
fun `get empty list of students`() {
assertEquals(emptyList(), controller.getStudents())
}
}
5 changes: 5 additions & 0 deletions service/src/test/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
spring:
datasource:
url: "jdbc:postgresql://localhost:6432/oppivelvollisuus_it"
username: "oppivelvollisuus"
password: "postgres"