Added message and description to CallResponse
This commit is contained in:
parent
191fa0ef44
commit
a272599b09
4 changed files with 181 additions and 154 deletions
|
@ -2,7 +2,7 @@ package com.example
|
||||||
|
|
||||||
import net.thauvin.erik.bitly.Bitly
|
import net.thauvin.erik.bitly.Bitly
|
||||||
import net.thauvin.erik.bitly.Methods
|
import net.thauvin.erik.bitly.Methods
|
||||||
import net.thauvin.erik.bitly.Utils.Companion.toEndPoint
|
import net.thauvin.erik.bitly.Utils.toEndPoint
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ fun main() {
|
||||||
val bitly = Bitly(/* "YOUR_API_ACCESS_TOKEN from https://bitly.is/accesstoken" */)
|
val bitly = Bitly(/* "YOUR_API_ACCESS_TOKEN from https://bitly.is/accesstoken" */)
|
||||||
|
|
||||||
// See https://dev.bitly.com/v4/#operation/getBitlink
|
// See https://dev.bitly.com/v4/#operation/getBitlink
|
||||||
val response = bitly.call("/bitlinks/bit.ly/380ojFd".toEndPoint(), method = Methods.GET)
|
val response = bitly.call("/bitlinks/bit.ly/380ojFd", method = Methods.GET)
|
||||||
|
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
val json = JSONObject(response.body)
|
val json = JSONObject(response.body)
|
||||||
|
@ -18,7 +18,7 @@ fun main() {
|
||||||
println("URL : " + json.getString("long_url"))
|
println("URL : " + json.getString("long_url"))
|
||||||
println("By : " + json.getString("created_by"))
|
println("By : " + json.getString("created_by"))
|
||||||
} else {
|
} else {
|
||||||
println("Invalid Response: ${response.resultCode}")
|
println("${response.message}: ${response.description} (${response.statusCode})")
|
||||||
}
|
}
|
||||||
|
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
package net.thauvin.erik.bitly
|
package net.thauvin.erik.bitly
|
||||||
|
|
||||||
|
import net.thauvin.erik.bitly.Utils.toEndPoint
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
@ -107,13 +108,13 @@ open class Bitly() {
|
||||||
/**
|
/**
|
||||||
* Executes an API call.
|
* Executes an API call.
|
||||||
*
|
*
|
||||||
* @param endPoint The REST endpoint. (eg. `https://api-ssl.bitly.com/v4/shorten`)
|
* @param endPoint The REST endpoint path. (eg. `shorten`, `expand`, etc.)
|
||||||
* @param params The request parameters key/value map.
|
* @param params The request parameters key/value map.
|
||||||
* @param method The submission [Method][Methods].
|
* @param method The submission [Method][Methods].
|
||||||
* @return A [CallResponse] object.
|
* @return A [CallResponse] object.
|
||||||
*/
|
*/
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun call(endPoint: String, params: Map<String, Any> = emptyMap(), method: Methods = Methods.POST): CallResponse {
|
fun call(endPoint: String, params: Map<String, Any> = emptyMap(), method: Methods = Methods.POST): CallResponse {
|
||||||
return Utils.call(accessToken, endPoint, params, method)
|
return Utils.call(accessToken, endPoint.toEndPoint(), params, method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
package net.thauvin.erik.bitly
|
package net.thauvin.erik.bitly
|
||||||
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
@ -46,157 +46,146 @@ import java.util.logging.Level
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|
||||||
/** Provides useful generic functions. */
|
/** Provides useful generic functions. */
|
||||||
open class Utils private constructor() {
|
object Utils {
|
||||||
companion object {
|
/** The logger instance. */
|
||||||
/** The logger instance. */
|
@JvmStatic
|
||||||
val logger: Logger by lazy { Logger.getLogger(Utils::class.java.name) }
|
val logger: Logger by lazy { Logger.getLogger(Utils::class.java.name) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes an API call.
|
* Executes an API call.
|
||||||
*
|
*
|
||||||
* @param accessToken The API access token.
|
* @param accessToken The API access token.
|
||||||
* @param endPoint The REST endpoint. (eg. `https://api-ssl.bitly.com/v4/shorten`)
|
* @param endPoint The REST endpoint URI. (eg. `https://api-ssl.bitly.com/v4/shorten`)
|
||||||
* @param params The request parameters key/value map.
|
* @param params The request parameters key/value map.
|
||||||
* @param method The submission [Method][Methods].
|
* @param method The submission [Method][Methods].
|
||||||
* @return A [CallResponse] object.
|
* @return A [CallResponse] object.
|
||||||
*/
|
*/
|
||||||
@JvmOverloads
|
@JvmStatic
|
||||||
fun call(
|
@JvmOverloads
|
||||||
accessToken: String,
|
fun call(
|
||||||
endPoint: String,
|
accessToken: String,
|
||||||
params: Map<String, Any> = emptyMap(),
|
endPoint: String,
|
||||||
method: Methods = Methods.POST
|
params: Map<String, Any> = emptyMap(),
|
||||||
): CallResponse {
|
method: Methods = Methods.POST
|
||||||
val response = CallResponse()
|
): CallResponse {
|
||||||
if (validateCall(accessToken, endPoint)) {
|
require(endPoint.isNotBlank()) { "A valid API endpoint must be specified." }
|
||||||
endPoint.toHttpUrlOrNull()?.let { apiUrl ->
|
require(accessToken.isNotBlank()) { "A valid API access token must be provided." }
|
||||||
val builder = when (method) {
|
|
||||||
Methods.POST, Methods.PATCH -> {
|
|
||||||
val formBody = JSONObject(params).toString()
|
|
||||||
.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
|
|
||||||
Request.Builder().apply {
|
|
||||||
url(apiUrl.newBuilder().build())
|
|
||||||
if (method == Methods.POST) {
|
|
||||||
post(formBody)
|
|
||||||
} else {
|
|
||||||
patch(formBody)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Methods.DELETE -> Request.Builder().url(apiUrl.newBuilder().build()).delete()
|
endPoint.toHttpUrl().let { apiUrl ->
|
||||||
else -> { // Methods.GET
|
val builder = when (method) {
|
||||||
val httpUrl = apiUrl.newBuilder().apply {
|
Methods.POST, Methods.PATCH -> {
|
||||||
params.forEach {
|
val formBody = JSONObject(params).toString()
|
||||||
if (it.value is String) {
|
.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
|
||||||
addQueryParameter(it.key, it.value.toString())
|
Request.Builder().apply {
|
||||||
}
|
url(apiUrl.newBuilder().build())
|
||||||
}
|
if (method == Methods.POST) {
|
||||||
}.build()
|
post(formBody)
|
||||||
Request.Builder().url(httpUrl)
|
} else {
|
||||||
}
|
patch(formBody)
|
||||||
}.addHeader("Authorization", "Bearer $accessToken")
|
|
||||||
|
|
||||||
val result = createHttpClient().newCall(builder.build()).execute()
|
|
||||||
return CallResponse(parseBody(endPoint, result), result.code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createHttpClient(): OkHttpClient {
|
|
||||||
return OkHttpClient.Builder().apply {
|
|
||||||
if (logger.isLoggable(Level.FINE)) {
|
|
||||||
addInterceptor(HttpLoggingInterceptor().apply {
|
|
||||||
level = HttpLoggingInterceptor.Level.BODY
|
|
||||||
redactHeader("Authorization")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseBody(endPoint: String, result: Response): String {
|
|
||||||
result.body?.string()?.let { body ->
|
|
||||||
if (!result.isSuccessful && body.isNotEmpty()) {
|
|
||||||
try {
|
|
||||||
with(JSONObject(body)) {
|
|
||||||
if (logger.isSevereLoggable()) {
|
|
||||||
if (has("message")) {
|
|
||||||
logger.severe(getString("message") + " (${result.code})")
|
|
||||||
}
|
|
||||||
if (has("description")) {
|
|
||||||
logger.severe(getString("description"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (jse: JSONException) {
|
|
||||||
if (logger.isSevereLoggable()) {
|
|
||||||
logger.log(
|
|
||||||
Level.SEVERE,
|
|
||||||
"An error occurred parsing the error response from Bitly. [$endPoint]",
|
|
||||||
jse
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return body
|
|
||||||
|
Methods.DELETE -> Request.Builder().url(apiUrl.newBuilder().build()).delete()
|
||||||
|
else -> { // Methods.GET
|
||||||
|
val httpUrl = apiUrl.newBuilder().apply {
|
||||||
|
params.forEach {
|
||||||
|
if (it.value is String) {
|
||||||
|
addQueryParameter(it.key, it.value.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
Request.Builder().url(httpUrl)
|
||||||
|
}
|
||||||
|
}.addHeader("Authorization", "Bearer $accessToken")
|
||||||
|
|
||||||
|
newHttpClient().newCall(builder.build()).execute().use {
|
||||||
|
return parseResponse(it, endPoint)
|
||||||
}
|
}
|
||||||
return Constants.EMPTY
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
private fun newHttpClient(): OkHttpClient {
|
||||||
* Is [Level.SEVERE] logging enabled.
|
return OkHttpClient.Builder().apply {
|
||||||
*/
|
if (logger.isLoggable(Level.FINE)) {
|
||||||
fun Logger.isSevereLoggable(): Boolean = this.isLoggable(Level.SEVERE)
|
addInterceptor(HttpLoggingInterceptor().apply {
|
||||||
|
level = HttpLoggingInterceptor.Level.BODY
|
||||||
|
redactHeader("Authorization")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
private fun parseResponse(response: Response, endPoint: String): CallResponse {
|
||||||
* Validates a URL.
|
var message = response.message
|
||||||
*/
|
var description = ""
|
||||||
fun String.isValidUrl(): Boolean {
|
var json = Constants.EMPTY_JSON
|
||||||
if (this.isNotBlank()) {
|
response.body?.string()?.let { body ->
|
||||||
|
json = body
|
||||||
|
if (!response.isSuccessful && body.isNotEmpty()) {
|
||||||
try {
|
try {
|
||||||
URL(this)
|
with(JSONObject(body)) {
|
||||||
return true
|
if (has("message")) {
|
||||||
} catch (e: MalformedURLException) {
|
message = getString("message")
|
||||||
if (logger.isLoggable(Level.WARNING)) {
|
}
|
||||||
logger.log(Level.WARNING, "Invalid URL: $this", e)
|
if (has("description")) {
|
||||||
|
description = getString("description")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (jse: JSONException) {
|
||||||
|
if (logger.isSevereLoggable()) {
|
||||||
|
logger.log(
|
||||||
|
Level.SEVERE,
|
||||||
|
"An error occurred parsing the error response from Bitly. [$endPoint]",
|
||||||
|
jse
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
return CallResponse(json, message, description, response.code)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes http(s) scheme from string.
|
* Determines if [Level.SEVERE] logging is enabled.
|
||||||
*/
|
*/
|
||||||
fun String.removeHttp(): String {
|
fun Logger.isSevereLoggable(): Boolean = this.isLoggable(Level.SEVERE)
|
||||||
return this.replaceFirst("^[Hh][Tt]{2}[Pp][Ss]?://".toRegex(), "")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the full API endpoint URL using the [Constants.API_BASE_URL].
|
* Validates a URL.
|
||||||
*/
|
*/
|
||||||
fun String.toEndPoint(): String {
|
@JvmStatic
|
||||||
return if (this.startsWith('/')) {
|
fun String.isValidUrl(): Boolean {
|
||||||
"${Constants.API_BASE_URL}$this"
|
if (this.isNotBlank()) {
|
||||||
} else {
|
try {
|
||||||
"${Constants.API_BASE_URL}/$this"
|
URL(this)
|
||||||
|
return true
|
||||||
|
} catch (e: MalformedURLException) {
|
||||||
|
if (logger.isLoggable(Level.WARNING)) {
|
||||||
|
logger.log(Level.WARNING, "Invalid URL: $this", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private fun validateCall(accessToken: String, endPoint: String): Boolean {
|
/**
|
||||||
when {
|
* Removes http(s) scheme from string.
|
||||||
endPoint.isBlank() -> {
|
*/
|
||||||
if (logger.isSevereLoggable()) logger.severe("Please specify a valid API endpoint.")
|
@JvmStatic
|
||||||
}
|
fun String.removeHttp(): String {
|
||||||
|
return this.replaceFirst("^[Hh][Tt]{2}[Pp][Ss]?://".toRegex(), "")
|
||||||
|
}
|
||||||
|
|
||||||
accessToken.isBlank() -> {
|
/**
|
||||||
if (logger.isSevereLoggable()) logger.severe("Please specify a valid API access token.")
|
* Builds the full API endpoint URL using the [Constants.API_BASE_URL].
|
||||||
}
|
*/
|
||||||
|
@JvmStatic
|
||||||
else -> return true
|
fun String.toEndPoint(): String {
|
||||||
}
|
return if (this.isBlank() || this.startsWith("http", true)) {
|
||||||
return false
|
this
|
||||||
|
} else {
|
||||||
|
"${Constants.API_BASE_URL}/${this.removePrefix("/")}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,22 +34,27 @@ package net.thauvin.erik.bitly
|
||||||
import assertk.all
|
import assertk.all
|
||||||
import assertk.assertThat
|
import assertk.assertThat
|
||||||
import assertk.assertions.contains
|
import assertk.assertions.contains
|
||||||
|
import assertk.assertions.isEmpty
|
||||||
import assertk.assertions.isEqualTo
|
import assertk.assertions.isEqualTo
|
||||||
import assertk.assertions.isFalse
|
import assertk.assertions.isFalse
|
||||||
|
import assertk.assertions.isNotEqualTo
|
||||||
import assertk.assertions.isTrue
|
import assertk.assertions.isTrue
|
||||||
import assertk.assertions.matches
|
import assertk.assertions.matches
|
||||||
import assertk.assertions.prop
|
import assertk.assertions.prop
|
||||||
import net.thauvin.erik.bitly.Utils.Companion.isValidUrl
|
import assertk.assertions.startsWith
|
||||||
import net.thauvin.erik.bitly.Utils.Companion.removeHttp
|
import net.thauvin.erik.bitly.Utils.isValidUrl
|
||||||
import net.thauvin.erik.bitly.Utils.Companion.toEndPoint
|
import net.thauvin.erik.bitly.Utils.removeHttp
|
||||||
|
import net.thauvin.erik.bitly.Utils.toEndPoint
|
||||||
|
import net.thauvin.erik.bitly.config.CreateConfig
|
||||||
|
import net.thauvin.erik.bitly.config.UpdateConfig
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertNotEquals
|
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class BitlyTest {
|
class BitlyTest {
|
||||||
|
@ -76,7 +81,12 @@ class BitlyTest {
|
||||||
if (System.getenv("CI") == "true") {
|
if (System.getenv("CI") == "true") {
|
||||||
test.accessToken = Constants.EMPTY
|
test.accessToken = Constants.EMPTY
|
||||||
}
|
}
|
||||||
assertEquals(longUrl, test.bitlinks().shorten(longUrl))
|
assertFailsWith(IllegalArgumentException::class) {
|
||||||
|
test.bitlinks().shorten(longUrl)
|
||||||
|
}
|
||||||
|
assertFailsWith(IllegalArgumentException::class, "Utils.call()") {
|
||||||
|
Utils.call("", "foo")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -100,7 +110,19 @@ class BitlyTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `endPoint should be specified`() {
|
fun `endPoint should be specified`() {
|
||||||
assertThat(bitly.call("")).prop(CallResponse::isSuccessful).isFalse()
|
assertFailsWith(IllegalArgumentException::class, "bitly.call()") {
|
||||||
|
bitly.call("")
|
||||||
|
}
|
||||||
|
assertFailsWith(IllegalArgumentException::class, "Utils.call()") {
|
||||||
|
Utils.call("1234568", "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `endPoint conversion`() {
|
||||||
|
assertThat(Constants.API_BASE_URL.toEndPoint()).isEqualTo(Constants.API_BASE_URL)
|
||||||
|
assertThat("path".toEndPoint()).isEqualTo("${Constants.API_BASE_URL}/path")
|
||||||
|
assertThat("/path".toEndPoint()).isEqualTo("${Constants.API_BASE_URL}/path")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -110,16 +132,18 @@ class BitlyTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `as json`() {
|
fun `shorten as json`() {
|
||||||
assertTrue(bitly.bitlinks().shorten(longUrl, toJson = true).startsWith("{\"created_at\":"))
|
assertTrue(bitly.bitlinks().shorten(longUrl, toJson = true).startsWith("{\"created_at\":"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get user`() {
|
fun `get user`() {
|
||||||
assertThat(bitly.call("user".toEndPoint(), method = Methods.GET), "call(user)")
|
assertThat(bitly.call("user", method = Methods.GET), "call(user)")
|
||||||
.prop(CallResponse::isSuccessful).isTrue()
|
|
||||||
assertThat(Utils.call(bitly.accessToken, "/user".toEndPoint(), method = Methods.GET), "call(/user)")
|
|
||||||
.prop(CallResponse::isSuccessful).isTrue()
|
.prop(CallResponse::isSuccessful).isTrue()
|
||||||
|
assertThat(Utils.call(bitly.accessToken, "user".toEndPoint(), method = Methods.GET), "call(/user)").all {
|
||||||
|
prop(CallResponse::isSuccessful).isTrue()
|
||||||
|
prop(CallResponse::body).contains("login")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -128,7 +152,7 @@ class BitlyTest {
|
||||||
"ethauvin",
|
"ethauvin",
|
||||||
JSONObject(
|
JSONObject(
|
||||||
bitly.call(
|
bitly.call(
|
||||||
"/bitlinks/${shortUrl.removeHttp()}".toEndPoint(),
|
"/bitlinks/${shortUrl.removeHttp()}",
|
||||||
method = Methods.GET
|
method = Methods.GET
|
||||||
).body
|
).body
|
||||||
).getString("created_by")
|
).getString("created_by")
|
||||||
|
@ -151,22 +175,31 @@ class BitlyTest {
|
||||||
bl.shorten(longUrl, domain = "bit.ly")
|
bl.shorten(longUrl, domain = "bit.ly")
|
||||||
assertThat(bl.lastCallResponse, "shorten(longUrl)").all {
|
assertThat(bl.lastCallResponse, "shorten(longUrl)").all {
|
||||||
prop(CallResponse::isSuccessful).isTrue()
|
prop(CallResponse::isSuccessful).isTrue()
|
||||||
prop(CallResponse::resultCode).isEqualTo(200)
|
prop(CallResponse::statusCode).isEqualTo(200)
|
||||||
prop(CallResponse::body).contains("\"link\":\"$shortUrl\"")
|
prop(CallResponse::body).contains("\"link\":\"$shortUrl\"")
|
||||||
|
prop(CallResponse::message).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
bl.shorten(shortUrl)
|
bl.shorten(shortUrl)
|
||||||
assertThat(bl.lastCallResponse, "shorten(shortUrl)").all {
|
assertThat(bl.lastCallResponse, "shorten(shortUrl)").all {
|
||||||
prop(CallResponse::isSuccessful).isFalse()
|
prop(CallResponse::isSuccessful).isFalse()
|
||||||
prop(CallResponse::resultCode).isEqualTo(400)
|
prop(CallResponse::statusCode).isEqualTo(400)
|
||||||
prop(CallResponse::isBadRequest).isTrue()
|
prop(CallResponse::isBadRequest).isTrue()
|
||||||
prop(CallResponse::body).contains("ALREADY_A_BITLY_LINK")
|
prop(CallResponse::message).isEqualTo("ALREADY_A_BITLY_LINK")
|
||||||
|
prop(CallResponse::description).isEqualTo("The value provided is invalid.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicks summary`() {
|
fun `clicks summary`() {
|
||||||
assertNotEquals(Constants.EMPTY, bitly.bitlinks().clicks(shortUrl))
|
val bl = bitly.bitlinks()
|
||||||
|
assertThat(bl.clicks(shortUrl)).isNotEqualTo(Constants.EMPTY)
|
||||||
|
bl.clicks(shortUrl, unit = Units.MONTH, units = 6)
|
||||||
|
assertThat(bl.lastCallResponse).all {
|
||||||
|
prop(CallResponse::isUpgradeRequired)
|
||||||
|
prop(CallResponse::statusCode).isEqualTo(402)
|
||||||
|
prop(CallResponse::description).startsWith("Metrics")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -233,7 +266,9 @@ class BitlyTest {
|
||||||
bl.update("bit.ly/407GjJU", id = "foo")
|
bl.update("bit.ly/407GjJU", id = "foo")
|
||||||
assertThat(bl.lastCallResponse).all {
|
assertThat(bl.lastCallResponse).all {
|
||||||
prop(CallResponse::isForbidden).isTrue()
|
prop(CallResponse::isForbidden).isTrue()
|
||||||
prop(CallResponse::resultCode).isEqualTo(403)
|
prop(CallResponse::statusCode).isEqualTo(403)
|
||||||
|
prop(CallResponse::message).isEqualTo("FORBIDDEN")
|
||||||
|
prop(CallResponse::description).contains("forbidden")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +299,9 @@ class BitlyTest {
|
||||||
|
|
||||||
assertThat(bl.lastCallResponse).all {
|
assertThat(bl.lastCallResponse).all {
|
||||||
prop(CallResponse::isUnprocessableEntity).isTrue()
|
prop(CallResponse::isUnprocessableEntity).isTrue()
|
||||||
prop(CallResponse::resultCode).isEqualTo(422)
|
prop(CallResponse::statusCode).isEqualTo(422)
|
||||||
|
prop(CallResponse::message).isEqualTo("UNPROCESSABLE_ENTITY")
|
||||||
|
prop(CallResponse::description).contains("JSON")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue