Initial commit

- Retrofit used to call API
This commit is contained in:
2024-07-18 17:04:56 +01:00
commit 982b4e8d5d
20 changed files with 534 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
package api
import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class BookerApi {
private val baseUrl = "https://restful-booker.herokuapp.com/"
private val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
private fun buildOkHttpClient(timeoutSeconds: Long = 30L): OkHttpClient {
val builder = OkHttpClient.Builder()
builder
.addInterceptor(loggingInterceptor)
.connectTimeout(timeoutSeconds, TimeUnit.SECONDS)
.writeTimeout(timeoutSeconds, TimeUnit.SECONDS)
.readTimeout(timeoutSeconds, TimeUnit.SECONDS)
return builder.build()
}
fun invoke(): RestfulBookerApi {
val okHttpClient = buildOkHttpClient()
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(RestfulBookerApi::class.java)
}
}

View File

@@ -0,0 +1,61 @@
package api
import model.*
import retrofit2.Response
import retrofit2.http.*
interface RestfulBookerApi {
@Headers("Content-Type:application/json")
@POST("auth")
suspend fun createAuthToken(
@Field("username") username: String,
@Field("password") password: String,
): Response<AuthResponse>
@GET("booking")
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>>
@GET("booking/{id}")
suspend fun getSingleBooking(
@Path("id") id: String
): Response<BookingResponse>
@Headers("Content-Type:application/json")
@POST("booking")
suspend fun createBooking(
@Body booking: BookingRequest,
): Response<CreateBookingResponse>
@Headers("Content-Type:application/json", "Accept: application/json")
@PUT("booking/{id}")
suspend fun updateBooking(
@Path("id") id: String,
@Body booking: BookingRequest,
@Header("Authorization") token: String
): Response<BookingResponse>
@Headers("Content-Type:application/json", "Accept: application/json")
@PATCH("booking/{id}")
suspend fun partialUpdateBooking(
@Path("id") id: String,
@Header("Authorization") token: String,
@Field("firstname") firstname: String? = null,
@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>
@DELETE("booking/{id}")
suspend fun deleteBooking(
@Path("id") id: String
): Response<Any>
}

View File

@@ -0,0 +1,5 @@
package model
class AuthResponse {
var token: String? = null
}

View File

@@ -0,0 +1,5 @@
package model
class BookingIdResponse {
var bookingid = 0
}

View File

@@ -0,0 +1,12 @@
package model
data class BookingRequest (
var firstname: String? = null,
var lastname: String? = null,
var totalprice: Int = 0,
var depositpaid: Boolean = false,
var bookingdates: Bookingdates? = null,
var additionalneeds: String? = null,
)

View File

@@ -0,0 +1,11 @@
package model
data class BookingResponse (
var firstname: String? = null,
var lastname: String? = null,
var totalprice: Int = 0,
var depositpaid: Boolean = false,
var bookingdates: Bookingdates? = null,
var additionalneeds: String? = null
)

View File

@@ -0,0 +1,6 @@
package model
data class Bookingdates (
var checkin: String? = null,
var checkout: String? = null,
)

View File

@@ -0,0 +1,6 @@
package model
class CreateBookingResponse {
var bookingid = 0
var booking: BookingResponse? = null
}

View File

@@ -0,0 +1,20 @@
import kotlinx.coroutines.runBlocking
import retrofit2.Response
import java.io.IOException
abstract class NetworkTests {
fun <T : Any> responseUnwrap(
call: suspend () -> Response<T>
): T {
val response = runBlocking { call.invoke() }
if (response.isSuccessful) {
return response.body()!!
} else {
val error = response.errorBody()?.string()
throw IOException(error ?: "Unable to handle end point")
}
}
}

105
src/test/kotlin/Tests.kt Normal file
View File

@@ -0,0 +1,105 @@
import api.BookerApi
import api.RestfulBookerApi
import io.restassured.RestAssured.given
import kotlinx.coroutines.runBlocking
import model.BookingRequest
import model.Bookingdates
import org.apache.logging.log4j.LogManager
import org.junit.FixMethodOrder
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.runners.MethodSorters
import utils.FileReader
@FixMethodOrder(MethodSorters.DEFAULT)
class Tests : NetworkTests(){
companion object {
private lateinit var bookerApi: RestfulBookerApi
private lateinit var fileReader: FileReader
private val logger = LogManager.getLogger(Tests::class.java)
@BeforeAll
@JvmStatic
internal fun beforeAll() {
bookerApi = BookerApi().invoke()
}
@AfterAll
@JvmStatic
internal fun afterAll() {
}
}
/**
* 1. Generate 3 new bookings --> Log below scenarios to a log file
* o All available booking ID's
* o Above added 3 new booking details
*/
@Test()
fun testScenarioOne() {
// Given
val bookingRequestOne = fileReader.readJsonFileFromResources<BookingRequest>("test1")
val bookingRequestTwo = fileReader.readJsonFileFromResources<BookingRequest>("test2")
val bookingRequestThree = BookingRequest(
firstname = "Mark",
lastname = "Wahlberg",
totalprice = 750,
depositpaid = true,
bookingdates = Bookingdates(
checkin = "2025-01-01",
checkout = "2025-01-10"
),
additionalneeds = "Breakfast"
)
// When
val createBookingOneResponse = responseUnwrap { bookerApi.createBooking(bookingRequestOne) }
val createBookingTwoResponse = responseUnwrap { bookerApi.createBooking(bookingRequestTwo) }
val createBookingThreeResponse = responseUnwrap { bookerApi.createBooking(bookingRequestThree) }
// Then
val bookingIds = responseUnwrap { bookerApi.getBookingIds() }
logger.trace("Available booking IDs: ${bookingIds.joinToString()}")
bookingIds.forEach {
val currentBookingResponse = responseUnwrap { bookerApi.getSingleBooking("$it") }
logger.trace(currentBookingResponse)
}
}
/**
* 2. Modify total price for test1 to 1000 and test2 to 1500. Log this data to same log file.
* Test data :
* • Test1 with total price 500 who deposit is paid with random check in and checkout dates and having preference of lunch as additional need.
*
*/
@Test()
fun testScenarioTwo() {
// Given
// When
// Then
}
@Test()
fun testScenarioThree() {
// Given
// When
// Then
}
@Test()
fun testScenarioFour() {
// Given
// When
// Then
}
}

View File

@@ -0,0 +1,21 @@
package utils
import com.google.gson.Gson
import java.io.BufferedReader
import java.lang.reflect.ParameterizedType
class FileReader {
private val gson by lazy { Gson() }
fun <T : Any?> readJsonFileFromResources(fileName: String): T {
val iStream = this::class.java.getResourceAsStream("$fileName.json")
?: throw IllegalStateException("Unable to read the file requested")
val data = iStream.bufferedReader().use(BufferedReader::readText)
val genericType = ((javaClass.genericSuperclass as? ParameterizedType)
?.actualTypeArguments?.getOrNull(0) as? Class<T>)
?: throw IllegalStateException("Can not find class from generic argument")
return gson.fromJson(data, genericType)
}
}

View File

@@ -0,0 +1,11 @@
{
"firstname" : "Jim",
"lastname" : "Brown",
"totalprice" : 500,
"depositpaid" : true,
"bookingdates" : {
"checkin" : "2025-01-01",
"checkout" : "2025-01-10"
},
"additionalneeds" : "Lunch"
}

View File

@@ -0,0 +1,11 @@
{
"firstname" : "Jim",
"lastname" : "Brown",
"totalprice" : 500,
"depositpaid" : true,
"bookingdates" : {
"checkin" : "2025-01-01",
"checkout" : "2025-01-10"
},
"additionalneeds" : "Lunch"
}