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

[3.0.0] Kotlin version #46

Merged
merged 25 commits into from
Jan 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0f5ce50
Added Develop to all pipelines
bfresnel Oct 5, 2022
d753cb7
Added kotlin jvm plugin
bfresnel Oct 5, 2022
9b33e12
Added Main.kt
bfresnel Oct 5, 2022
101ce0d
Fixing warning error
bfresnel Oct 5, 2022
f11bfa4
Migrating Main class to kotlin
bfresnel Dec 7, 2022
ea350f5
Updated tests
bfresnel Dec 8, 2022
1504ac4
Implementing spring data jpa for kotlin
bfresnel Dec 8, 2022
b12b5f7
Migrating all repositories to kotlin
bfresnel Dec 8, 2022
2f65a06
Changed some service and object to kotlin
bfresnel Dec 25, 2022
5dc309d
Continuing migration
bfresnel Dec 29, 2022
f8f9dc0
changing json changelogs to xml changelogs
bfresnel Dec 30, 2022
c3334a2
removing unused import
bfresnel Dec 30, 2022
0917017
create gradle.properties to avoid metaspace error in github action
bfresnel Dec 30, 2022
e205c4e
Finishing migrating business code to kotlin
bfresnel Dec 30, 2022
6828d51
[LT-1] Removed MainClass test
bfresnel Dec 30, 2022
4f5492e
Added tests for LootService class
bfresnel Dec 30, 2022
1789e1e
Added jacoco report for sonarcloud
bfresnel Dec 30, 2022
537cdca
Added new test for LootController
bfresnel Dec 30, 2022
5d30370
[LT-2] Optimizing the loot controller (#43)
bfresnel Jan 2, 2023
1dac570
[LT-3] Cleaning the gradle.build file (#44)
bfresnel Jan 2, 2023
c7df225
[LT-4] Update README.md (#45)
bfresnel Jan 2, 2023
835343e
[LT-2] Optimizing the loot controller (#43)
bfresnel Jan 2, 2023
0ea5e06
[LT-3] Cleaning the gradle.build file (#44)
bfresnel Jan 2, 2023
f0a194d
[LT-4] Update README.md (#45)
bfresnel Jan 2, 2023
4ec545e
Merge branch 'develop' of https://github.com/bfresnel/loot-table-poc …
bfresnel Jan 2, 2023
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
23 changes: 7 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# 🎰 LOOT-TABLE 🎰

[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=bfresnel_loot-table-poc&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=bfresnel_loot-table-poc)
[![Java CI with Gradle](https://github.com/bfresnel/loot-table-poc/actions/workflows/gradle.yml/badge.svg?branch=main)](https://github.com/bfresnel/loot-table-poc/actions/workflows/gradle.yml)
[![CodeQL](https://github.com/bfresnel/loot-table-poc/actions/workflows/codeql-analysis.yml/badge.svg?branch=main)](https://github.com/bfresnel/loot-table-poc/actions/workflows/codeql-analysis.yml)

Expand All @@ -8,19 +9,11 @@
This project was created in order to understand how all looting games are working.
This project could also be updated or not.

**_It has many flaws, like no-real logging, no database etc etc... it's just a personal project._**
**_It has many flaws, it's just a personal project._**

## Principle

We have 2 files that contains data :

* ```characters.json``` : Contains all characters and their rarity
* ```drop-chance.json``` : Contains all percentage for each rarity

⚠️ _**These files can be edited. However, there is absolutely no percentage control for the ```drop-chance.json```
file.**_

For each pull, we retrieve 5 lists of 10 characters.
For each pull, we retrieve a list of 10 characters.
In each list -> we integrate as much character as their rarity in a 100-sized array.

For example :
Expand All @@ -35,10 +28,8 @@ If you liked this, don't forget to add a 🌟 👋

## How to use it

You have to install the java JDK with version >= 16.0.2

Go to the folder where the downloaded jar is located then use the following command :
$ cd loot-table
$ docker-compose up -d .

```
$ java -jar loot-table-1.0.0.jar
```
The last command will build everything under docker including the webapp and the database (it includes a Postgresql
image)
27 changes: 2 additions & 25 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ plugins {
}

group = "fr.bfr"
version = "2.1.1"
version = "3.0.0"
java.sourceCompatibility = JavaVersion.VERSION_16


Expand All @@ -22,17 +22,13 @@ configurations {
}
}

sourceSets.main {
java.srcDirs("src/main/kotlin", "src/main/java")
}

repositories {
mavenCentral()
}

dependencies {
compileOnly("org.projectlombok:lombok:1.18.24")
runtimeOnly("org.postgresql:postgresql")

implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0")
implementation("ch.qos.logback:logback-core:1.2.11")
implementation("org.slf4j:slf4j-api:1.7.36")
Expand All @@ -42,47 +38,28 @@ dependencies {
implementation("org.liquibase:liquibase-core:4.18.0")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")

implementation("org.jetbrains.kotlin:kotlin-reflect")

testCompileOnly("org.projectlombok:lombok:1.18.24")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.0")
testImplementation("com.h2database:h2:2.1.214")
testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0")
testImplementation("org.springframework.boot:spring-boot-starter-test")

annotationProcessor("org.projectlombok:lombok:1.18.24")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
testAnnotationProcessor("org.projectlombok:lombok:1.18.24")
}

tasks.getByName<Test>("test") {
useJUnitPlatform()
}

tasks.getByName<Jar>("jar") {
enabled = false
}

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = JavaVersion.VERSION_16.toString()
}
}

tasks.jar {
manifest {
attributes(
"Main-class" to "fr.bfr.Main",
"Class-Path" to configurations.runtimeClasspath.get()
.filter { it.isFile }
.joinToString(" ") { it.name }
)
}
}

tasks.jacocoTestReport {
reports {
xml.required.set(true)
Expand Down
2 changes: 1 addition & 1 deletion dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ RUN gradle clean build
# Stage 2 : Build the wanted image
FROM eclipse-temurin:16-jdk as CREATE_WEBAPP
ENV APP_HOME=/usr/app
ENV APP_NAME=loot-table-2.1.1.jar
ENV APP_NAME=loot-table-3.0.0.jar
WORKDIR $APP_HOME/
COPY --from=BUILD_JAR $APP_HOME/build/libs/$APP_NAME .
ENTRYPOINT exec java -jar $APP_NAME
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m
org.gradle.jvmargs=-Xmx2048m
4 changes: 2 additions & 2 deletions src/main/kotlin/fr/bfr/api/CharacterRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package fr.bfr.api

import fr.bfr.model.Character
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Service
import org.springframework.stereotype.Repository

@Service
@Repository
interface CharacterRepository : JpaRepository<Character, Long> {
override fun findAll(): List<Character>
}
6 changes: 2 additions & 4 deletions src/main/kotlin/fr/bfr/api/DropRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package fr.bfr.api

import fr.bfr.model.DropChance
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.lang.NonNull
import org.springframework.stereotype.Service
import org.springframework.stereotype.Repository

@Service
@Repository
interface DropChanceRepository : JpaRepository<DropChance, Int> {
@NonNull
override fun findAll(): List<DropChance>
}
3 changes: 1 addition & 2 deletions src/main/kotlin/fr/bfr/api/LootApi.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package fr.bfr.api

import fr.bfr.model.Character
import fr.bfr.model.DropChance

interface LootApi {
fun pull(data: List<Character>, dropChances: List<DropChance>, numberOfPull: Int): List<Character>
fun pull(numberOfPull: Int): List<Character>
}
15 changes: 3 additions & 12 deletions src/main/kotlin/fr/bfr/controller/LootController.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package fr.bfr.controller

import fr.bfr.api.CharacterRepository
import fr.bfr.api.DropChanceRepository
import fr.bfr.model.Character
import fr.bfr.services.LootService
import org.slf4j.LoggerFactory
Expand All @@ -14,21 +12,14 @@ import org.springframework.web.bind.annotation.RestController

@RestController
class LootController @Autowired constructor(
val characterRepository: CharacterRepository,
val dropRepository: DropChanceRepository,
val lootService: LootService
) {
@GetMapping(value = ["/pull"], produces = [MediaType.APPLICATION_JSON_VALUE])
fun pull(): ResponseEntity<List<Character>> {
logger.info("/pull endpoint was called !")
val characters = characterRepository.findAll()
val dropChances = dropRepository.findAll()
var lootedCharacters: List<Character> = ArrayList()
if (characters.isNotEmpty() && dropChances.isNotEmpty()) {
logger.info("Retrieving all looted characters...")
lootedCharacters = lootService.pull(characters, dropChances, 10)
logger.info("Characters looted successfully !")
}
logger.info("Retrieving all looted characters...")
val lootedCharacters: List<Character> = lootService.pull(10)

return ResponseEntity(lootedCharacters, HttpStatus.OK)
}

Expand Down
4 changes: 1 addition & 3 deletions src/main/kotlin/fr/bfr/model/Character.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package fr.bfr.model

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.persistence.Table

@Entity
@Table(name = "t_character")
class Character(
@Id
@GeneratedValue
var id: Long,
var name: String,
var rarity: Int
var rarity: Int,
)
2 changes: 1 addition & 1 deletion src/main/kotlin/fr/bfr/model/DropChance.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import javax.persistence.Table
class DropChance(
@Id
var rarity: Int,
var chance: Double
var chance: Int,
)
15 changes: 10 additions & 5 deletions src/main/kotlin/fr/bfr/services/LootService.kt
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
package fr.bfr.services

import fr.bfr.api.CharacterRepository
import fr.bfr.api.DropChanceRepository
import fr.bfr.api.LootApi
import fr.bfr.model.Character
import fr.bfr.model.DropChance
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.security.SecureRandom

@Service
class LootService : LootApi {
class LootService @Autowired constructor(
val characterRepository: CharacterRepository,
val dropChanceRepository: DropChanceRepository
) : LootApi {
val secureRandom: SecureRandom = SecureRandom()

override fun pull(
data: List<Character>,
dropChances: List<DropChance>,
numberOfPull: Int
): List<Character> {
val data: List<Character> = characterRepository.findAll();
val dropChanceList: List<DropChance> = dropChanceRepository.findAll();
val pulledCharacters: MutableList<Character> = ArrayList()
val charactersListWithDropChance: MutableList<Character> = ArrayList()
var counter = 0

// Setting an array of 100 characters with number of each character matching the chance
for (dropChance in dropChances) {
for (dropChance in dropChanceList) {
while (counter < dropChance.chance) {
charactersListWithDropChance.add(data[dropChance.rarity - 1])
counter++
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/db/scripts/init-database.sql
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
CREATE TABLE public.t_character (
id int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY,
id int8 NOT NULL,
"name" varchar(255) NULL,
rarity int4 NULL,
CONSTRAINT t_character_pkey PRIMARY KEY (id)
);

CREATE TABLE public.t_drop (
rarity int4 NOT NULL,
chance float8 NULL,
chance int4 NULL,
CONSTRAINT t_drop_pkey PRIMARY KEY (rarity)
);
37 changes: 21 additions & 16 deletions src/test/kotlin/controller/LootControllerTest.kt
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
package controller

import fr.bfr.Main
import fr.bfr.controller.LootController
import fr.bfr.model.Character
import org.assertj.core.api.Assertions
import fr.bfr.services.LootService
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.boot.test.web.client.getForEntity
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.springframework.http.HttpStatus
import org.springframework.test.context.ActiveProfiles
import org.springframework.http.ResponseEntity

@SpringBootTest(classes = [Main::class], webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
class LootControllerTest(
@Autowired val restTemplate: TestRestTemplate
) {
class LootControllerTest {

@Test
fun `Integration test of the Pull endpoint`() {
val entity = restTemplate.getForEntity<List<Character>>("/pull")
Assertions.assertThat(entity.statusCode).isEqualTo(HttpStatus.OK)
Assertions.assertThat(entity.body).isEqualTo(emptyList<Character>())
fun `Check if pull endpoint is sending correct data`() {
// Mocking
val mockLootService: LootService = mock()
whenever(mockLootService.pull(any())).thenReturn(listOf(Character(1, "bfr", 1)))
val lootController = LootController(mockLootService)

// Using the method to test
val result: ResponseEntity<List<Character>> = lootController.pull()

// Assertions
Assertions.assertEquals(HttpStatus.OK, result.statusCode)
result.body?.let { Assertions.assertEquals(1, it.size) }
Assertions.assertEquals(true, result.body?.isNotEmpty() ?: false)
}
}
37 changes: 16 additions & 21 deletions src/test/kotlin/services/LootServiceTest.kt
Original file line number Diff line number Diff line change
@@ -1,40 +1,35 @@
package services

import fr.bfr.Main
import fr.bfr.api.CharacterRepository
import fr.bfr.api.DropChanceRepository
import fr.bfr.model.Character
import fr.bfr.model.DropChance
import fr.bfr.services.LootService
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import fr.bfr.model.Character as CharacterBfr

@SpringBootTest(classes = [Main::class])
@ActiveProfiles("test")
class LootServiceTest(@Autowired val lootService: LootService) {
class LootServiceTest {

@Test
fun `Assert pull method is working`() {
//data
val data: List<CharacterBfr> = generateCharacterList()
//DropChance
val dropChance: List<DropChance> = generateDropChanceList()
//NumberOfPull
// Mocking
val mockCharacterRepository: CharacterRepository = mock()
val mockDropChanceRepository: DropChanceRepository = mock()
whenever(mockCharacterRepository.findAll()).thenReturn(listOf(Character(1, "bfr", 1)))
whenever(mockDropChanceRepository.findAll()).thenReturn(listOf(DropChance(1, 100)))
val lootService = LootService(mockCharacterRepository, mockDropChanceRepository)

// NumberOfPull
val numberOfPull = 1
val result: List<CharacterBfr> = lootService.pull(data, dropChance, numberOfPull)
val result: List<CharacterBfr> = lootService.pull(numberOfPull)

// Assertions
Assertions.assertEquals(result.size, 1)
Assertions.assertEquals(result[0].id, 1)
Assertions.assertEquals(result[0].name, "bfr")
Assertions.assertEquals(result[0].rarity, 1)
}

fun generateCharacterList(): List<CharacterBfr> {
return listOf(Character(1, "bfr", 1))
}

fun generateDropChanceList(): List<DropChance> {
return listOf(DropChance(1, 100.0))
}
}