Skip to content

Commit

Permalink
NetworkRequestHandler (#26)
Browse files Browse the repository at this point in the history
* NetworkRequestHandler created with its test

* Kt3k coveralls commented

* Dependencies added

* Commented lines were added

* Documentation added

* Identation was fixed

* Changes in documentation
  • Loading branch information
lmiotti authored Oct 5, 2020
1 parent f67689c commit aebdbf4
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 2 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.3.61'
repositories {
mavenCentral()
google()
Expand All @@ -11,6 +12,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:3.5.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.3'
classpath 'com.dicedmelon.gradle:jacoco-android:0.1.4'
classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.8.3'
Expand Down
11 changes: 9 additions & 2 deletions networking/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'jacoco-android'
apply plugin: 'com.github.kt3k.coveralls'

Expand Down Expand Up @@ -29,19 +32,20 @@ jacocoAndroidUnitTestReport {
excludes = defaultExcludes + ['**/*_Factory.class']
}


coveralls {
jacocoReportPath = "${buildDir}/reports/jacoco/jacocoTestReleaseUnitTestReport/jacocoTestReleaseUnitTestReport.xml"
}

buildscript {
ext.wolmo_version = '4.0.0'
ext.retrofit_version = '2.7.0'
ext.retrofit_version = '2.9.0'
ext.okhttp3_version = '3.9.0'
ext.dagger_version = '2.25.3'
ext.joda_version = '2.10'
ext.findbugs_version = '3.0.2'
ext.junit_version = '4.12'
ext.mockito_inline_version = '2.13.0'
ext.mockito_inline_version = '2.19.0'
ext.assertj_version = '3.9.0'
}

Expand All @@ -64,6 +68,9 @@ dependencies {
api "joda-time:joda-time:$joda_version"
api "com.google.code.findbugs:jsr305:$findbugs_version"

kapt "com.google.dagger:dagger-android-processor:$dagger_version"
kapt "com.google.dagger:dagger-compiler:$dagger_version"

// Test
testImplementation "junit:junit:$junit_version"
testImplementation "org.mockito:mockito-inline:$mockito_inline_version" // Mockito inline adds support for mocking final classes and methods
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package ar.com.wolox.wolmo.networking.retrofit.handler

import retrofit2.Response

/**
* An adapter that converts Retrofit's responses to other, more specific, ones
* depending on network status codes or failures when using Kotlin's Coroutines.
* It will return a [NetworkResponse] object indicating operation result.
*/
object NetworkRequestHandler {

/**
* Static method that allows to execute requests from a [suspend] function of [Response] type
* and returns a [NetworkResponse] object depending on HTTP response.
*/
suspend fun <T : Response<*>> safeApiCall(block: suspend () -> T): NetworkResponse<T> =
try {
val response = block.invoke()
if (response.isSuccessful) {
NetworkResponse.Success(response)
} else {
NetworkResponse.Error(response)
}
} catch (t: Throwable) {
NetworkResponse.Failure(t)
}
}

sealed class NetworkResponse<T> {

/**
* Successful HTTP response from the server.
* The server received the request, answered it and the response is not of an error type.
* It will return a [T] object, the API JSON response converted to a Java/Kotlin object,
* which includes the API response code.
*/
data class Success<T>(val response: T) : NetworkResponse<T>()

/**
* Successful HTTP response from the server, but has an error body.
* The server received the request, answered it and reported an error.
* It will return a [T], the API JSON response converted to a Java/Kotlin object,
* which includes the API response code.
*/
data class Error<T>(val response: T) : NetworkResponse<T>()

/**
* The HTTP request to the server failed on the local device, no data was transmitted.
* Invoked when a network or unexpected exception occurred during the HTTP request, meaning
* that the request couldn't be executed. The cause of the failure will be given through a
* [Throwable] object
*/
data class Failure<T>(val t: Throwable) : NetworkResponse<T>()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package ar.com.wolox.wolmo.networking.retrofit.handler

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
import org.mockito.stubbing.Answer
import retrofit2.Response

@ExperimentalCoroutinesApi
class NetworkRequestHandlerTest {

@Before
fun setup() {
MockitoAnnotations.initMocks(this)
}

@Test
fun `given a succesfull response with code between 200 and 300, NetworkResponse Success state is called`() = runBlocking {
// GIVEN
val apiResponse = mock(Response::class.java) as Response<Any>

// WHEN
`when`(apiResponse.isSuccessful).thenReturn(true)

// THEN
val networkResponse = NetworkRequestHandler.safeApiCall { apiResponse }
assert(networkResponse is NetworkResponse.Success)
}

@Test
fun `given a succesfull response with code above 300, NetworkResponse Error state is called`() = runBlocking {
// GIVEN
val apiResponse = mock(Response::class.java) as Response<Any>

// WHEN
`when`(apiResponse.isSuccessful).thenReturn(false)

// THEN
val networkResponse = NetworkRequestHandler.safeApiCall { apiResponse }
assert(networkResponse is NetworkResponse.Error)
}

@Test
fun `given a non-succesfull response, NetworkResponse Failure state is called`() = runBlocking {
// GIVEN
val answer: Answer<Exception> = Answer { Exception() }
val apiResponse = mock (Response::class.java, answer) as Response<Any>

// THEN
val networkResponse = NetworkRequestHandler.safeApiCall { apiResponse }
assert(networkResponse is NetworkResponse.Failure)
}
}

0 comments on commit aebdbf4

Please sign in to comment.