Skip to content

házi #6

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
15 changes: 15 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
val kotlinVersion = "1.9.23"
kotlin("jvm") version kotlinVersion
Expand All @@ -15,8 +17,13 @@ dependencies {
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.springframework.boot:spring-boot-starter-mustache")
implementation("com.google.code.gson:gson:2.10.1")
implementation("org.danilopianini:khttp:1.6.1")
testImplementation(kotlin("test"))
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("io.mockk:mockk:1.4.1")
implementation(kotlin("stdlib-jdk8"))
}

tasks.test {
Expand All @@ -26,3 +33,11 @@ tasks.test {
kotlin {
jvmToolchain(17)
}
val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions {
jvmTarget = "17"
}
val compileTestKotlin: KotlinCompile by tasks
compileTestKotlin.kotlinOptions {
jvmTarget = "17"
}
35 changes: 35 additions & 0 deletions app/src/main/kotlin/HtmlController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package hu.vanio.kotlin.feladat.ms

import com.google.gson.Gson
import khttp.get
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.ui.set

@Controller
class HtmlController {

@Autowired
lateinit var weatherAppService: WeatherAppService

@GetMapping("/")
fun index(model: Model): String {
model["title"] = "Average Daily temperature list"
val latitude = 47.4984
val longitude = 19.0404
val apiUrl = "https://api.open-meteo.com/v1/forecast?latitude=$latitude&longitude=$longitude&hourly=temperature_2m&timezone=auto"
try {
val meteoData = weatherAppService.fetchMeteoData(apiUrl)
model["averageTempList"] = weatherAppService.displayTemperatureDailyAverage(meteoData)
} catch (exception: Exception) {
println("Exception occured while fetching meteo data. Exception message: " + exception.message)
model["averageTempList"] = arrayListOf("Exception occured while fetching meteo data.")
}
return "index"
}



}
23 changes: 23 additions & 0 deletions app/src/main/kotlin/MeteoResponseData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package hu.vanio.kotlin.feladat.ms

data class MeteoResponseData(
val latitude: Double,
val longitude: Double,
val generationtime_ms: Double,
val utc_offset_seconds: Int,
val timezone: String,
val timezone_abbreviation: String,
val elevation: Double,
val hourly_units: HourlyUnits,
val hourly: Hourly
)

data class HourlyUnits(
val time: String,
val temperature_2m: String
)

data class Hourly(
val time: List<String>,
val temperature_2m: List<Double>
)
7 changes: 7 additions & 0 deletions app/src/main/kotlin/WeatherApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ package hu.vanio.kotlin.feladat.ms

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import com.google.gson.Gson
import khttp.get
import org.springframework.http.HttpStatusCode

@SpringBootApplication
class WeatherApp

fun main() {
runApplication<WeatherApp>()
println("STARTUP")


}


57 changes: 57 additions & 0 deletions app/src/main/kotlin/WeatherAppService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package hu.vanio.kotlin.feladat.ms

import com.google.gson.Gson
import khttp.get
import org.springframework.http.HttpStatusCode
import org.springframework.http.converter.HttpMessageNotReadableException
import org.springframework.stereotype.Service
import org.springframework.web.client.HttpClientErrorException
import org.springframework.web.client.HttpServerErrorException

@Service
class WeatherAppService {
fun displayTemperatureDailyAverage(meteoData: MeteoResponseData?): List<String> {
val dailyAverage = mutableListOf<String>()
if (meteoData != null) {
var dailySum = 0.0
var actualDay = meteoData.hourly.time[0].substring(0, 10)
var dailyIndex = 0
meteoData.hourly.temperature_2m.forEachIndexed { index, temperature ->
val dayToCheck = meteoData.hourly.time[index].substring(0, 10)
if (dayToCheck != actualDay) {
if (dailySum != 0.0) {
val actualAverage = actualDay + " temperature: " + dailySum / dailyIndex
println(actualAverage)
dailyAverage.add(actualAverage)
}
dailySum = 0.0
dailyIndex = 0
actualDay = dayToCheck
}
dailyIndex++
dailySum += temperature
}

//last day too
if (dailySum != 0.0) {
val actualAverage = actualDay + " temperature: " + dailySum / dailyIndex
println(actualAverage)
dailyAverage.add(actualAverage)
}
return dailyAverage
} else {
println("Failed to calculate the daily average temperature.")
throw Exception("Failed to calculate the daily average temperature.")
}
}

fun fetchMeteoData(apiUrl: String): MeteoResponseData? {
val response = get(apiUrl)
if (response.statusCode == 200) {
return Gson().fromJson(response.text, MeteoResponseData::class.java)
} else {
throw HttpServerErrorException(HttpStatusCode.valueOf(response.statusCode))
}

}
}
2 changes: 2 additions & 0 deletions app/src/main/resources/templates/footer.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
</body>
</html>
5 changes: 5 additions & 0 deletions app/src/main/resources/templates/header.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<head>
<title>{{title}}</title>
</head>
<body>
9 changes: 9 additions & 0 deletions app/src/main/resources/templates/index.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{{> header}}

<h1>{{title}}</h1>

{{#averageTempList}}
<h3>{{.}}</h3>
{{/averageTempList}}

{{> footer}}
70 changes: 70 additions & 0 deletions app/src/test/kotlin/WeatherAppServiceTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package hu.vanio.kotlin.feladat.ms

import com.google.gson.Gson
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import java.net.UnknownHostException

class WeatherAppServiceTest {

var weatherAppService = WeatherAppService()
@Test
fun fetchDataTest() {
val latitude = 47.4984
val longitude = 19.0404
val apiUrl = "https://api.open-meteo.com/v1/forecast?latitude=$latitude&longitude=$longitude&hourly=temperature_2m&timezone=auto"

val meteoData = weatherAppService.fetchMeteoData(apiUrl)

assertTrue(meteoData != null)
assertEquals(24*7, meteoData!!.hourly.time.size)
assertEquals(24*7, meteoData!!.hourly.temperature_2m.size)
}

@Test
fun fetchDataTestBadUrl() {
val apiUrl = "https://badApi"
assertThrows(UnknownHostException::class.java) {
weatherAppService.fetchMeteoData(apiUrl)
}
}

@Test
fun displayTemperatureDailyAverageTest() {
val formattedString = """{
"latitude":47.5,
"longitude":19.0625,
"generationtime_ms":0.026941299438476562,
"utc_offset_seconds":3600,
"timezone":"Europe/Budapest",
"timezone_abbreviation":"CET",
"elevation":124.0,
"hourly_units":{
"time":"iso8601",
"temperature_2m":"°C"
},
"hourly":{
"time":[
"2024-03-19T00:00",
"2024-03-19T01:00",
"2024-03-19T02:00",
"2024-03-20T02:00",
"2024-03-20T03:00",
"2024-03-20T04:00"
],
"temperature_2m":[
3.4,
3.2,
2.9,
2.7,
2.5,
2.6
]
}
}"""
val meteoResponse = Gson().fromJson(formattedString, MeteoResponseData::class.java)
val result = weatherAppService.displayTemperatureDailyAverage(meteoResponse)
assertEquals("2024-03-19 temperature: 3.1666666666666665", result[0])
assertEquals("2024-03-20 temperature: 2.6", result[1])
}
}
72 changes: 70 additions & 2 deletions app/src/test/kotlin/WeatherAppTest.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,79 @@
package hu.vanio.kotlin.feladat.ms

import org.assertj.core.api.Assertions.assertThat
import org.mockito.Mock
import org.mockito.Mockito
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.springframework.http.HttpStatus
import kotlin.test.Test
import org.mockito.Mockito.`when`
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.http.HttpStatusCode
import org.springframework.test.web.servlet.MockMvc
import org.springframework.web.client.HttpServerErrorException
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status


@WebMvcTest(controllers = [HtmlController::class])
class WeatherAppTest{

@MockBean
lateinit var weatherAppService: WeatherAppService

@MockBean
lateinit var meteoResponseData: MeteoResponseData

@Autowired
lateinit var mockMvc: MockMvc

object MockitoHelper {
fun <T> anyObject(): T {
Mockito.any<T>()
return uninitialized()
}
@Suppress("UNCHECKED_CAST")
fun <T> uninitialized(): T = null as T
}

class WeatherAppTest {

@Test fun `sikeres lekerdezes`() {
TODO()
mockMvc.perform(get("/")).andExpect(status().isOk)
.andExpect(content()
.string("<html>\n" +
"<head>\n" +
" <title>Average Daily temperature list</title>\n" +
"</head>\n" +
"<body>\n" +
"\n" +
"<h1>Average Daily temperature list</h1>\n" +
"\n" +
"\n" +
"</body>\n" +
"</html>"))
}

@Test fun `sikertelen lekerdezes`() {
`when`(weatherAppService.fetchMeteoData(MockitoHelper.anyObject())).thenThrow(HttpServerErrorException(
HttpStatusCode.valueOf(500)))
mockMvc.perform(get("/")).andExpect(status().isOk)
.andExpect(content()
.string("<html>\n" +
"<head>\n" +
" <title>Average Daily temperature list</title>\n" +
"</head>\n" +
"<body>\n" +
"\n" +
"<h1>Average Daily temperature list</h1>\n" +
"\n" +
"<h3>Exception occured while fetching meteo data.</h3>\n" +
"\n" +
"</body>\n" +
"</html>"))
}
}