mirror of
https://github.com/hmalik144/api-testing-automation-framework.git
synced 2025-12-10 02:55:21 +00:00
Tests pass but logging is still required
This commit is contained in:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -8,7 +8,7 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_20" default="true" project-jdk-name="20" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17 (2)" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
47
pom.xml
47
pom.xml
@@ -65,6 +65,14 @@
|
|||||||
<mainClass>MainKt</mainClass>
|
<mainClass>MainKt</mainClass>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>8</source>
|
||||||
|
<target>8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
@@ -81,18 +89,17 @@
|
|||||||
<version>5.10.0</version>
|
<version>5.10.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>5.10.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<artifactId>kotlin-stdlib</artifactId>
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
<version>1.9.0</version>
|
<version>1.9.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/io.rest-assured/rest-assured -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.rest-assured</groupId>
|
|
||||||
<artifactId>rest-assured</artifactId>
|
|
||||||
<version>5.5.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<!-- jUnit -->
|
<!-- jUnit -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
@@ -111,6 +118,12 @@
|
|||||||
<artifactId>retrofit</artifactId>
|
<artifactId>retrofit</artifactId>
|
||||||
<version>2.11.0</version>
|
<version>2.11.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.retrofit2</groupId>
|
||||||
|
<artifactId>converter-gson</artifactId>
|
||||||
|
<version>2.9.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.squareup.okhttp3</groupId>
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
<artifactId>logging-interceptor</artifactId>
|
<artifactId>logging-interceptor</artifactId>
|
||||||
@@ -121,19 +134,11 @@
|
|||||||
<artifactId>api-testing-automation-framework</artifactId>
|
<artifactId>api-testing-automation-framework</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.squareup.retrofit2</groupId>
|
|
||||||
<artifactId>converter-gson</artifactId>
|
|
||||||
<version>2.11.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.kotlinx</groupId>
|
<groupId>org.jetbrains.kotlinx</groupId>
|
||||||
<artifactId>kotlinx-coroutines-core</artifactId>
|
<artifactId>kotlinx-coroutines-core</artifactId>
|
||||||
<version>1.6.2</version>
|
<version>1.6.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
<artifactId>log4j-core</artifactId>
|
<artifactId>log4j-core</artifactId>
|
||||||
@@ -144,6 +149,18 @@
|
|||||||
<artifactId>log4j-api</artifactId>
|
<artifactId>log4j-api</artifactId>
|
||||||
<version>2.19.0</version>
|
<version>2.19.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.assertj</groupId>
|
||||||
|
<artifactId>assertj-core</artifactId>
|
||||||
|
<version>3.26.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sf.jasperreports</groupId>
|
||||||
|
<artifactId>jasperreports</artifactId>
|
||||||
|
<version>6.20.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -1,26 +1,54 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import java.security.cert.CertificateException
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.net.ssl.SSLContext
|
||||||
|
import javax.net.ssl.TrustManager
|
||||||
|
import javax.net.ssl.X509TrustManager
|
||||||
|
|
||||||
|
|
||||||
class BookerApi {
|
class BookerApi {
|
||||||
private val baseUrl = "https://restful-booker.herokuapp.com/"
|
private val baseUrl = "https://restful-booker.herokuapp.com/"
|
||||||
|
|
||||||
private val loggingInterceptor = HttpLoggingInterceptor().apply {
|
var trustAllCerts = arrayOf<TrustManager>(
|
||||||
level = HttpLoggingInterceptor.Level.BODY
|
object : X509TrustManager {
|
||||||
|
@Throws(CertificateException::class)
|
||||||
|
override fun checkClientTrusted(chain: Array<X509Certificate?>?, authType: String?) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(CertificateException::class)
|
||||||
|
override fun checkServerTrusted(chain: Array<X509Certificate?>?, authType: String?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAcceptedIssuers(): Array<X509Certificate?> {
|
||||||
|
return arrayOfNulls<X509Certificate>(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var gson = GsonBuilder()
|
||||||
|
.setLenient()
|
||||||
|
.create()
|
||||||
|
|
||||||
|
|
||||||
private fun buildOkHttpClient(timeoutSeconds: Long = 30L): OkHttpClient {
|
private fun buildOkHttpClient(timeoutSeconds: Long = 30L): OkHttpClient {
|
||||||
val builder = OkHttpClient.Builder()
|
val builder = OkHttpClient.Builder()
|
||||||
|
|
||||||
|
val sslContext = SSLContext.getInstance("SSL")
|
||||||
|
sslContext.init(null, trustAllCerts, SecureRandom())
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.addInterceptor(loggingInterceptor)
|
|
||||||
.connectTimeout(timeoutSeconds, TimeUnit.SECONDS)
|
.connectTimeout(timeoutSeconds, TimeUnit.SECONDS)
|
||||||
.writeTimeout(timeoutSeconds, TimeUnit.SECONDS)
|
.writeTimeout(timeoutSeconds, TimeUnit.SECONDS)
|
||||||
.readTimeout(timeoutSeconds, TimeUnit.SECONDS)
|
.readTimeout(timeoutSeconds, TimeUnit.SECONDS)
|
||||||
|
.sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager)
|
||||||
|
.hostnameVerifier { _, _ -> true }
|
||||||
|
|
||||||
return builder.build()
|
return builder.build()
|
||||||
}
|
}
|
||||||
@@ -30,7 +58,7 @@ class BookerApi {
|
|||||||
return Retrofit.Builder()
|
return Retrofit.Builder()
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.baseUrl(baseUrl)
|
.baseUrl(baseUrl)
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create(gson))
|
||||||
.build()
|
.build()
|
||||||
.create(RestfulBookerApi::class.java)
|
.create(RestfulBookerApi::class.java)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,19 +6,15 @@ import retrofit2.http.*
|
|||||||
|
|
||||||
interface RestfulBookerApi {
|
interface RestfulBookerApi {
|
||||||
|
|
||||||
@Headers("Content-Type:application/json")
|
@Headers("Content-Type:application/json", "Accept: application/json")
|
||||||
@POST("auth")
|
@POST("auth")
|
||||||
suspend fun createAuthToken(
|
suspend fun createAuthToken(
|
||||||
@Field("username") username: String,
|
@Body authRequest: AuthRequest
|
||||||
@Field("password") password: String,
|
|
||||||
): Response<AuthResponse>
|
): Response<AuthResponse>
|
||||||
|
|
||||||
@GET("booking")
|
@GET("booking")
|
||||||
suspend fun getBookingIds(
|
suspend fun getBookingIds(
|
||||||
@Field("firstname") firstname: String? = null,
|
|
||||||
@Field("lastname") lastname: String? = null,
|
|
||||||
@Field("checkin") checkin: String? = null,
|
|
||||||
@Field("checkout") checkout: String? = null,
|
|
||||||
): Response<List<BookingIdResponse>>
|
): Response<List<BookingIdResponse>>
|
||||||
|
|
||||||
@GET("booking/{id}")
|
@GET("booking/{id}")
|
||||||
@@ -26,7 +22,7 @@ interface RestfulBookerApi {
|
|||||||
@Path("id") id: String
|
@Path("id") id: String
|
||||||
): Response<BookingResponse>
|
): Response<BookingResponse>
|
||||||
|
|
||||||
@Headers("Content-Type:application/json")
|
@Headers("Content-Type:application/json", "Accept: application/json")
|
||||||
@POST("booking")
|
@POST("booking")
|
||||||
suspend fun createBooking(
|
suspend fun createBooking(
|
||||||
@Body booking: BookingRequest,
|
@Body booking: BookingRequest,
|
||||||
@@ -45,17 +41,12 @@ interface RestfulBookerApi {
|
|||||||
suspend fun partialUpdateBooking(
|
suspend fun partialUpdateBooking(
|
||||||
@Path("id") id: String,
|
@Path("id") id: String,
|
||||||
@Header("Authorization") token: String,
|
@Header("Authorization") token: String,
|
||||||
@Field("firstname") firstname: String? = null,
|
@Body update: UpdateBookingRequest
|
||||||
@Field("lastname") lastname: String? = null,
|
|
||||||
@Field("totalprice") totalprice: Float? = null,
|
|
||||||
@Field("depositpaid") depositpaid: Boolean? = null,
|
|
||||||
@Field("checkin") checkin: String? = null,
|
|
||||||
@Field("checkout") checkout: String? = null,
|
|
||||||
@Field("additionalneeds") additionalneeds: String? = null
|
|
||||||
): Response<BookingResponse>
|
): Response<BookingResponse>
|
||||||
|
|
||||||
@DELETE("booking/{id}")
|
@DELETE("booking/{id}")
|
||||||
suspend fun deleteBooking(
|
suspend fun deleteBooking(
|
||||||
@Path("id") id: String
|
@Path("id") id: String,
|
||||||
|
@Header("Authorization") token: String
|
||||||
): Response<Any>
|
): Response<Any>
|
||||||
}
|
}
|
||||||
6
src/main/kotlin/model/AuthRequest.kt
Normal file
6
src/main/kotlin/model/AuthRequest.kt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
data class AuthRequest(
|
||||||
|
val username: String,
|
||||||
|
val password: String
|
||||||
|
)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
class AuthResponse {
|
data class AuthResponse (
|
||||||
var token: String? = null
|
val token: String
|
||||||
}
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
class BookingIdResponse {
|
data class BookingIdResponse(
|
||||||
var bookingid = 0
|
val bookingid: Int
|
||||||
}
|
)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
data class BookingRequest (
|
data class BookingRequest (
|
||||||
var firstname: String? = null,
|
var firstname: String,
|
||||||
var lastname: String? = null,
|
var lastname: String,
|
||||||
var totalprice: Int = 0,
|
var totalprice: Int,
|
||||||
var depositpaid: Boolean = false,
|
var depositpaid: Boolean,
|
||||||
var bookingdates: Bookingdates? = null,
|
var bookingdates: Bookingdates,
|
||||||
var additionalneeds: String? = null,
|
var additionalneeds: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package model
|
|||||||
|
|
||||||
|
|
||||||
data class BookingResponse(
|
data class BookingResponse(
|
||||||
var firstname: String? = null,
|
var firstname: String,
|
||||||
var lastname: String? = null,
|
var lastname: String,
|
||||||
var totalprice: Int = 0,
|
var totalprice: Int,
|
||||||
var depositpaid: Boolean = false,
|
var depositpaid: Boolean,
|
||||||
var bookingdates: Bookingdates? = null,
|
var bookingdates: Bookingdates,
|
||||||
var additionalneeds: String? = null
|
var additionalneeds: String
|
||||||
)
|
)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
data class Bookingdates (
|
data class Bookingdates (
|
||||||
var checkin: String? = null,
|
var checkin: String,
|
||||||
var checkout: String? = null,
|
var checkout: String,
|
||||||
)
|
)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
class CreateBookingResponse {
|
data class CreateBookingResponse(
|
||||||
var bookingid = 0
|
var bookingid: Int,
|
||||||
var booking: BookingResponse? = null
|
var booking: BookingResponse
|
||||||
}
|
)
|
||||||
10
src/main/kotlin/model/UpdateBookingRequest.kt
Normal file
10
src/main/kotlin/model/UpdateBookingRequest.kt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
data class UpdateBookingRequest(
|
||||||
|
var firstname: String? = null,
|
||||||
|
var lastname: String? = null,
|
||||||
|
var totalprice: Int? = null,
|
||||||
|
var depositpaid: Boolean? = null,
|
||||||
|
var bookingdates: Bookingdates? = null,
|
||||||
|
var additionalneeds: String? = null,
|
||||||
|
)
|
||||||
92
src/main/kotlin/storage/OrdersDatabase.kt
Normal file
92
src/main/kotlin/storage/OrdersDatabase.kt
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package storage
|
||||||
|
|
||||||
|
import model.BookingResponse
|
||||||
|
import model.Bookingdates
|
||||||
|
|
||||||
|
class OrdersDatabase {
|
||||||
|
private val storage = mutableMapOf<Int, BookingResponse>()
|
||||||
|
|
||||||
|
// Create
|
||||||
|
fun insertBooking(id: Int, booking: BookingResponse) {
|
||||||
|
if (storage.contains(id)) {
|
||||||
|
storage.replace(id, booking)
|
||||||
|
} else {
|
||||||
|
storage[id] = booking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read
|
||||||
|
fun getIdsOfBookingsAvailable() = storage.keys.toList()
|
||||||
|
fun getBookingsAvailable() = storage.values.toList()
|
||||||
|
fun getIdsAndBookings() = storage.toMap()
|
||||||
|
|
||||||
|
fun getIdsOfOrderBasedOnValues(
|
||||||
|
firstname: String? = null,
|
||||||
|
lastname: String? = null,
|
||||||
|
totalprice: Int? = null,
|
||||||
|
depositpaid: Boolean? = null,
|
||||||
|
checkin: String? = null,
|
||||||
|
checkout: String? = null,
|
||||||
|
additionalneeds: String? = null
|
||||||
|
): List<Int> {
|
||||||
|
return storage.filterValues {
|
||||||
|
firstname?.let { f -> f == it.firstname } ?: true &&
|
||||||
|
lastname?.let { f -> f == it.lastname } ?: true &&
|
||||||
|
totalprice?.let { f -> f == it.totalprice } ?: true &&
|
||||||
|
depositpaid?.let { f -> f == it.depositpaid } ?: true &&
|
||||||
|
checkin?.let { f -> f == it.bookingdates.checkin } ?: true &&
|
||||||
|
checkout?.let { f -> f == it.bookingdates.checkout } ?: true &&
|
||||||
|
additionalneeds?.let { f -> f == it.additionalneeds } ?: true
|
||||||
|
}.keys.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getIdsOfOrderBasedOnValues(
|
||||||
|
id: Int
|
||||||
|
): BookingResponse? {
|
||||||
|
return storage[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update
|
||||||
|
fun updateCompleteOrder(id: Int, newBookingResponse: BookingResponse) {
|
||||||
|
insertBooking(id, newBookingResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateOrderPartial(
|
||||||
|
id: Int,
|
||||||
|
firstname: String? = null,
|
||||||
|
lastname: String? = null,
|
||||||
|
totalprice: Int? = null,
|
||||||
|
depositpaid: Boolean? = null,
|
||||||
|
checkin: String? = null,
|
||||||
|
checkout: String? = null,
|
||||||
|
additionalneeds: String? = null
|
||||||
|
) {
|
||||||
|
if (storage.keys.remove(id)) {
|
||||||
|
storage.compute(id) { k, v ->
|
||||||
|
val mFirstName = firstname ?: v!!.firstname
|
||||||
|
val mlastname = lastname ?: v!!.lastname
|
||||||
|
val mTotalprice = totalprice ?: v!!.totalprice
|
||||||
|
val mDepositpaid = depositpaid ?: v!!.depositpaid
|
||||||
|
val mCheckin = checkin ?: v!!.bookingdates.checkin
|
||||||
|
val mCheckout = checkout ?: v!!.bookingdates.checkout
|
||||||
|
val mAdditionalneeds = additionalneeds ?: v!!.additionalneeds
|
||||||
|
BookingResponse(
|
||||||
|
firstname = mFirstName,
|
||||||
|
lastname = mlastname,
|
||||||
|
totalprice = mTotalprice,
|
||||||
|
depositpaid = mDepositpaid,
|
||||||
|
bookingdates = Bookingdates(
|
||||||
|
checkin = mCheckin,
|
||||||
|
checkout = mCheckout
|
||||||
|
),
|
||||||
|
additionalneeds = mAdditionalneeds
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
fun clearAllData() = storage.clear()
|
||||||
|
|
||||||
|
fun deleteSingleEntry(id: Int) = storage.remove(id)
|
||||||
|
}
|
||||||
27
src/main/resources/Log4j2.xml
Normal file
27
src/main/resources/Log4j2.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Configuration status="warn">
|
||||||
|
<Properties>
|
||||||
|
<Property name="basePath">C:\\logs</Property>
|
||||||
|
</Properties>
|
||||||
|
<Appenders>
|
||||||
|
<RollingFile name="fileLogger" fileName="${basePath}/app-info.html"
|
||||||
|
filePattern="${basePath}/app-info-%d{yyyy-MM-dd}.html">
|
||||||
|
<HTMLLayout charset="UTF-8" title="Howtodoinjava Info Logs" locationInfo="true" />
|
||||||
|
<Policies>
|
||||||
|
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
|
||||||
|
<SizeBasedTriggeringPolicy size="10 MB" />
|
||||||
|
</Policies>
|
||||||
|
</RollingFile>
|
||||||
|
<Console name="console" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" />
|
||||||
|
</Console>
|
||||||
|
</Appenders>
|
||||||
|
<Loggers>
|
||||||
|
<Logger name="com.howtodoinjava" level="debug" additivity="false">
|
||||||
|
<appender-ref ref="fileLogger" level="debug" />
|
||||||
|
</Logger>
|
||||||
|
<Root level="debug" additivity="false">
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
</Root>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
@@ -4,6 +4,7 @@ import java.io.IOException
|
|||||||
|
|
||||||
abstract class NetworkTests {
|
abstract class NetworkTests {
|
||||||
|
|
||||||
|
// Call retrofit API and unwrap response or throw exception
|
||||||
fun <T : Any> responseUnwrap(
|
fun <T : Any> responseUnwrap(
|
||||||
call: suspend () -> Response<T>
|
call: suspend () -> Response<T>
|
||||||
): T {
|
): T {
|
||||||
@@ -12,9 +13,11 @@ abstract class NetworkTests {
|
|||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
return response.body()!!
|
return response.body()!!
|
||||||
} else {
|
} else {
|
||||||
val error = response.errorBody()?.string()
|
val error = StringBuilder().append(response.code()).append(" : ")
|
||||||
|
.append(response.errorBody()?.string() ?: "Unable to handle end point").toString()
|
||||||
|
print(response.raw())
|
||||||
|
throw IOException(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw IOException(error ?: "Unable to handle end point")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,35 +1,56 @@
|
|||||||
import api.BookerApi
|
import api.BookerApi
|
||||||
import api.RestfulBookerApi
|
import api.RestfulBookerApi
|
||||||
import io.restassured.RestAssured.given
|
import model.AuthRequest
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import model.BookingRequest
|
import model.BookingRequest
|
||||||
import model.Bookingdates
|
import model.Bookingdates
|
||||||
|
import model.UpdateBookingRequest
|
||||||
|
import net.sf.jasperreports.engine.JasperCompileManager
|
||||||
|
import net.sf.jasperreports.engine.JasperFillManager
|
||||||
|
import net.sf.jasperreports.engine.JasperReport
|
||||||
|
import net.sf.jasperreports.engine.export.HtmlExporter
|
||||||
|
import net.sf.jasperreports.engine.util.JRSaver
|
||||||
|
import net.sf.jasperreports.export.SimpleHtmlExporterOutput
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.junit.FixMethodOrder
|
import org.apache.logging.log4j.message.MessageFormatMessage
|
||||||
import org.junit.jupiter.api.AfterAll
|
import org.assertj.core.api.AssertionsForClassTypes.assertThat
|
||||||
import org.junit.jupiter.api.BeforeAll
|
import org.junit.jupiter.api.*
|
||||||
import org.junit.jupiter.api.Test
|
import storage.OrdersDatabase
|
||||||
import org.junit.runners.MethodSorters
|
|
||||||
import utils.FileReader
|
import utils.FileReader
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
@FixMethodOrder(MethodSorters.DEFAULT)
|
|
||||||
|
@TestMethodOrder(MethodOrderer.OrderAnnotation::class)
|
||||||
class Tests : NetworkTests() {
|
class Tests : NetworkTests() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private lateinit var bookerApi: RestfulBookerApi
|
private lateinit var bookerApi: RestfulBookerApi
|
||||||
private lateinit var fileReader: FileReader
|
private val fileReader = FileReader()
|
||||||
private val logger = LogManager.getLogger(Tests::class.java)
|
private val logger = LogManager.getLogger("Test")
|
||||||
|
|
||||||
|
val bookingsReportStream: InputStream = javaClass.getResourceAsStream("/bookingsReport.jrxml")
|
||||||
|
val jasperReport: JasperReport = JasperCompileManager.compileReport(bookingsReportStream)
|
||||||
|
|
||||||
|
private val storage = OrdersDatabase()
|
||||||
|
|
||||||
|
private lateinit var bookingRequestTestOne: BookingRequest
|
||||||
|
private lateinit var bookingRequestTestTwo: BookingRequest
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
internal fun beforeAll() {
|
internal fun beforeAll() {
|
||||||
bookerApi = BookerApi().invoke()
|
bookerApi = BookerApi().invoke()
|
||||||
|
|
||||||
|
bookingRequestTestOne = fileReader.readJsonFileFromResources("test1", BookingRequest::class.java)
|
||||||
|
bookingRequestTestTwo = fileReader.readJsonFileFromResources("test2", BookingRequest::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
internal fun afterAll() {
|
internal fun afterAll() {
|
||||||
|
storage.clearAllData()
|
||||||
|
|
||||||
|
JRSaver.saveObject(jasperReport, "bookingReport.jasper");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,10 +61,11 @@ class Tests : NetworkTests(){
|
|||||||
* o Above added 3 new booking details
|
* o Above added 3 new booking details
|
||||||
*/
|
*/
|
||||||
@Test()
|
@Test()
|
||||||
|
@Order(1)
|
||||||
fun testScenarioOne() {
|
fun testScenarioOne() {
|
||||||
// Given
|
/*
|
||||||
val bookingRequestOne = fileReader.readJsonFileFromResources<BookingRequest>("test1")
|
* Given
|
||||||
val bookingRequestTwo = fileReader.readJsonFileFromResources<BookingRequest>("test2")
|
*/
|
||||||
val bookingRequestThree = BookingRequest(
|
val bookingRequestThree = BookingRequest(
|
||||||
firstname = "Mark",
|
firstname = "Mark",
|
||||||
lastname = "Wahlberg",
|
lastname = "Wahlberg",
|
||||||
@@ -56,17 +78,36 @@ class Tests : NetworkTests(){
|
|||||||
additionalneeds = "Breakfast"
|
additionalneeds = "Breakfast"
|
||||||
)
|
)
|
||||||
|
|
||||||
// When
|
/*
|
||||||
val createBookingOneResponse = responseUnwrap { bookerApi.createBooking(bookingRequestOne) }
|
* When
|
||||||
val createBookingTwoResponse = responseUnwrap { bookerApi.createBooking(bookingRequestTwo) }
|
*/
|
||||||
|
val createBookingOneResponse = responseUnwrap { bookerApi.createBooking(bookingRequestTestOne) }
|
||||||
|
val createBookingTwoResponse = responseUnwrap { bookerApi.createBooking(bookingRequestTestTwo) }
|
||||||
val createBookingThreeResponse = responseUnwrap { bookerApi.createBooking(bookingRequestThree) }
|
val createBookingThreeResponse = responseUnwrap { bookerApi.createBooking(bookingRequestThree) }
|
||||||
|
val bookingResponses = listOf(createBookingOneResponse, createBookingTwoResponse, createBookingThreeResponse)
|
||||||
|
|
||||||
// Then
|
/*
|
||||||
|
* Then
|
||||||
|
*/
|
||||||
val bookingIds = responseUnwrap { bookerApi.getBookingIds() }
|
val bookingIds = responseUnwrap { bookerApi.getBookingIds() }
|
||||||
|
assertThat(bookingIds.size)
|
||||||
|
.withFailMessage("Did not find 3 bookings")
|
||||||
|
.isGreaterThanOrEqualTo(3)
|
||||||
|
|
||||||
|
JasperFillManager.
|
||||||
logger.trace("Available booking IDs: ${bookingIds.joinToString()}")
|
logger.trace("Available booking IDs: ${bookingIds.joinToString()}")
|
||||||
bookingIds.forEach {
|
|
||||||
val currentBookingResponse = responseUnwrap { bookerApi.getSingleBooking("$it") }
|
// Add the booking details and idea for later
|
||||||
logger.trace(currentBookingResponse)
|
bookingResponses.forEach { response ->
|
||||||
|
storage.insertBooking(response.bookingid, response.booking)
|
||||||
|
|
||||||
|
logger.trace(
|
||||||
|
MessageFormatMessage(
|
||||||
|
"Booking with ID: {0} has been added: {1}",
|
||||||
|
response.bookingid,
|
||||||
|
response.booking
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,29 +118,133 @@ class Tests : NetworkTests(){
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Test()
|
@Test()
|
||||||
|
@Order(2)
|
||||||
fun testScenarioTwo() {
|
fun testScenarioTwo() {
|
||||||
// Given
|
/*
|
||||||
|
* Given
|
||||||
|
*/
|
||||||
|
// Find my booking ids
|
||||||
|
val orderIdTestOne = storage.getIdsOfOrderBasedOnValues(
|
||||||
|
firstname = bookingRequestTestOne.firstname,
|
||||||
|
lastname = bookingRequestTestOne.lastname,
|
||||||
|
checkin = bookingRequestTestOne.bookingdates.checkin,
|
||||||
|
checkout = bookingRequestTestOne.bookingdates.checkout
|
||||||
|
).first()
|
||||||
|
val orderIdTestTwo = storage.getIdsOfOrderBasedOnValues(
|
||||||
|
firstname = bookingRequestTestTwo.firstname,
|
||||||
|
lastname = bookingRequestTestTwo.lastname,
|
||||||
|
checkin = bookingRequestTestTwo.bookingdates.checkin,
|
||||||
|
checkout = bookingRequestTestTwo.bookingdates.checkout
|
||||||
|
).first()
|
||||||
|
|
||||||
// When
|
/*
|
||||||
|
* When
|
||||||
|
*/
|
||||||
|
val auth = responseUnwrap {
|
||||||
|
bookerApi.createAuthToken(
|
||||||
|
AuthRequest(
|
||||||
|
UUID.randomUUID().toString(),
|
||||||
|
UUID.randomUUID().toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val tokenBuilder =
|
||||||
|
StringBuilder("Basic ").append(Base64.getEncoder().encodeToString("admin:password123".toByteArray()))
|
||||||
|
.toString()
|
||||||
|
val updateTestOneResponse = responseUnwrap {
|
||||||
|
bookerApi.partialUpdateBooking(
|
||||||
|
id = orderIdTestOne.toString(),
|
||||||
|
token = tokenBuilder,
|
||||||
|
update = UpdateBookingRequest(
|
||||||
|
totalprice = 1000
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}.also {
|
||||||
|
storage.updateCompleteOrder(orderIdTestOne, it)
|
||||||
|
}
|
||||||
|
val updateTestTwoResponse = responseUnwrap {
|
||||||
|
bookerApi.partialUpdateBooking(
|
||||||
|
id = orderIdTestTwo.toString(),
|
||||||
|
token = tokenBuilder,
|
||||||
|
update = UpdateBookingRequest(
|
||||||
|
totalprice = 1500
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}.also {
|
||||||
|
storage.updateCompleteOrder(orderIdTestTwo, it)
|
||||||
|
}
|
||||||
|
val updateResponseList = listOf(updateTestOneResponse, updateTestTwoResponse)
|
||||||
|
|
||||||
// Then
|
/*
|
||||||
|
* Then
|
||||||
|
*/
|
||||||
|
logger.trace(
|
||||||
|
MessageFormatMessage(
|
||||||
|
"Booking with ID: {0} has been updated to the following: {1}",
|
||||||
|
orderIdTestOne,
|
||||||
|
updateTestOneResponse
|
||||||
|
)
|
||||||
|
)
|
||||||
|
logger.trace(
|
||||||
|
MessageFormatMessage(
|
||||||
|
"Booking with ID: {0} has been updated to the following: {1}",
|
||||||
|
orderIdTestTwo,
|
||||||
|
updateTestTwoResponse
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test()
|
@Test()
|
||||||
|
@Order(3)
|
||||||
fun testScenarioThree() {
|
fun testScenarioThree() {
|
||||||
// Given
|
/*
|
||||||
|
* Given
|
||||||
|
*/
|
||||||
|
val idOfAny = storage.getIdsOfBookingsAvailable().random()
|
||||||
|
val tokenBuilder =
|
||||||
|
StringBuilder("Basic ").append(Base64.getEncoder().encodeToString("admin:password123".toByteArray()))
|
||||||
|
.toString()
|
||||||
|
|
||||||
// When
|
/*
|
||||||
|
* When
|
||||||
|
*/
|
||||||
|
val deleteResponse = responseUnwrap {
|
||||||
|
bookerApi.deleteBooking(id = idOfAny.toString(), tokenBuilder)
|
||||||
|
}.also { storage.deleteSingleEntry(id = idOfAny) }
|
||||||
|
|
||||||
// Then
|
/*
|
||||||
|
* Then
|
||||||
|
*/
|
||||||
|
logger.trace(
|
||||||
|
MessageFormatMessage(
|
||||||
|
"Booking with ID: {0} has been delete and given the following response: {1}",
|
||||||
|
idOfAny,
|
||||||
|
deleteResponse
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test()
|
@Test()
|
||||||
|
@Order(4)
|
||||||
fun testScenarioFour() {
|
fun testScenarioFour() {
|
||||||
// Given
|
/*
|
||||||
|
* Given
|
||||||
|
*/
|
||||||
|
|
||||||
// When
|
/*
|
||||||
|
* When
|
||||||
|
*/
|
||||||
|
|
||||||
// Then
|
/*
|
||||||
|
* Then
|
||||||
|
*/
|
||||||
|
val exporter = HtmlExporter()
|
||||||
|
|
||||||
|
// Set input ...
|
||||||
|
|
||||||
|
// Set input ...
|
||||||
|
exporter.exporterOutput = SimpleHtmlExporterOutput("bookingsReport.html")
|
||||||
|
|
||||||
|
exporter.exportReport()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,19 +3,19 @@ package utils
|
|||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.lang.reflect.ParameterizedType
|
import java.lang.reflect.ParameterizedType
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class FileReader {
|
class FileReader {
|
||||||
|
|
||||||
private val gson by lazy { Gson() }
|
private val gson by lazy { Gson() }
|
||||||
|
|
||||||
fun <T : Any?> readJsonFileFromResources(fileName: String): T {
|
/**
|
||||||
val iStream = this::class.java.getResourceAsStream("$fileName.json")
|
* Read json files from resources and turn into object of type <T>
|
||||||
|
*/
|
||||||
|
fun <T : Any?> readJsonFileFromResources(fileName: String, clazz: Class<T>): T {
|
||||||
|
val iStream = this::class.java.getResourceAsStream("/$fileName.json")
|
||||||
?: throw IllegalStateException("Unable to read the file requested")
|
?: throw IllegalStateException("Unable to read the file requested")
|
||||||
val data = iStream.bufferedReader().use(BufferedReader::readText)
|
val data = iStream.bufferedReader().use(BufferedReader::readText)
|
||||||
val genericType = ((javaClass.genericSuperclass as? ParameterizedType)
|
return gson.fromJson(data, clazz)
|
||||||
?.actualTypeArguments?.getOrNull(0) as? Class<T>)
|
|
||||||
?: throw IllegalStateException("Can not find class from generic argument")
|
|
||||||
|
|
||||||
return gson.fromJson(data, genericType)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
28
src/test/resources/reportTemplate.jrxml
Normal file
28
src/test/resources/reportTemplate.jrxml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<jasperReport>
|
||||||
|
<field name="FIRST_NAME" class="java.lang.String"/>
|
||||||
|
<field name="LAST_NAME" class="java.lang.String"/>
|
||||||
|
<field name="SALARY" class="java.lang.Double"/>
|
||||||
|
<field name="ID" class="java.lang.Integer"/>
|
||||||
|
<detail>
|
||||||
|
<band height="51" splitType="Stretch">
|
||||||
|
<textField>
|
||||||
|
<reportElement x="0" y="0" width="100" height="20"/>
|
||||||
|
<textElement/>
|
||||||
|
<textFieldExpression class="java.lang.String">
|
||||||
|
<![CDATA[$F{FIRST_NAME}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<textField>
|
||||||
|
<reportElement x="100" y="0" width="100" height="20"/>
|
||||||
|
<textElement/>
|
||||||
|
<textFieldExpression class="java.lang.String">
|
||||||
|
<![CDATA[$F{LAST_NAME}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<textField>
|
||||||
|
<reportElement x="200" y="0" width="100" height="20"/>
|
||||||
|
<textElement/>
|
||||||
|
<textFieldExpression class="java.lang.String">
|
||||||
|
<![CDATA[$F{SALARY}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
</band>
|
||||||
|
</detail>
|
||||||
|
</jasperReport>
|
||||||
11
src/test/resources/test3.json
Normal file
11
src/test/resources/test3.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"firstname" : "Jim",
|
||||||
|
"lastname" : "Brown",
|
||||||
|
"totalprice" : 500,
|
||||||
|
"depositpaid" : true,
|
||||||
|
"bookingdates" : {
|
||||||
|
"checkin" : "2025-01-01",
|
||||||
|
"checkout" : "2025-01-10"
|
||||||
|
},
|
||||||
|
"additionalneeds" : "Lunch"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user