feat: 新增 okhttpMock 模块并调整依赖配置

main
mojo 3 weeks ago
parent 3f6c9c2405
commit 6ba8b228ff

1
.gitignore vendored

@ -46,3 +46,4 @@ google-services.json
# Android Profiling # Android Profiling
*.hprof *.hprof
!/dict.txt

@ -12,6 +12,7 @@
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/lib" /> <option value="$PROJECT_DIR$/lib" />
<option value="$PROJECT_DIR$/okhttpMock" />
<option value="$PROJECT_DIR$/pin" /> <option value="$PROJECT_DIR$/pin" />
</set> </set>
</option> </option>

@ -13,6 +13,8 @@ espressoCoreVersion = "3.0.2"
appcompatV7 = "28.0.0" appcompatV7 = "28.0.0"
annotationJvm = "1.9.1" annotationJvm = "1.9.1"
firebaseCrashlyticsBuildtools = "3.0.6" firebaseCrashlyticsBuildtools = "3.0.6"
appcompat = "1.6.1"
material = "1.10.0"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@ -34,6 +36,8 @@ espresso-core = { group = "com.android.support.test.espresso", name = "espresso-
appcompat-v7 = { group = "com.android.support", name = "appcompat-v7", version.ref = "appcompatV7" } appcompat-v7 = { group = "com.android.support", name = "appcompat-v7", version.ref = "appcompatV7" }
androidx-annotation-jvm = { group = "androidx.annotation", name = "annotation-jvm", version.ref = "annotationJvm" } androidx-annotation-jvm = { group = "androidx.annotation", name = "annotation-jvm", version.ref = "annotationJvm" }
firebase-crashlytics-buildtools = { group = "com.google.firebase", name = "firebase-crashlytics-buildtools", version.ref = "firebaseCrashlyticsBuildtools" } firebase-crashlytics-buildtools = { group = "com.google.firebase", name = "firebase-crashlytics-buildtools", version.ref = "firebaseCrashlyticsBuildtools" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }

@ -0,0 +1 @@
/build

@ -0,0 +1,45 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "com.example.okhttpmock"
compileSdk = 34
defaultConfig {
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
api("com.squareup.okhttp3:okhttp:4.12.0")
api("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.0")
api(project(":lib"))
}

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,24 @@
package com.example.okhttpmock
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.okhttpmock.test", appContext.packageName)
}
}

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

@ -0,0 +1,24 @@
package com.example.okhttpmock.mock
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
class DelayInterceptor(val delayMillis:Long): Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
// 获取请求
val request: Request = chain.request()
// 模拟网络延迟
try {
Thread.sleep(delayMillis)
} catch (e: InterruptedException) {
e.printStackTrace()
}
// 继续处理请求并获取响应
val response: Response = chain.proceed(request)
return response
}
}

@ -0,0 +1,80 @@
package com.example.okhttpmock.mock
import com.example.action.BaseAction
import com.example.action.HttpActionRequest
import com.example.action.HttpMethod
import com.example.logger.LogUtils
import com.example.service.HttpService
import com.example.task.TaskConfig
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import java.net.CookieHandler
import java.net.CookieManager
import java.net.CookiePolicy
object MockHttpActionServer {
private val scope = CoroutineScope(Dispatchers.Default)
private val taskConfig: TaskConfig = TaskConfig(
taskId = 0,
taskUid = 1,
taskVer = 1,
userId = "1",
userAgent = "TextAgent",
secChUa = "",
accept = "",
acceptLanguage = "",
cookieManager = CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER),
currentStep = 0,
reportUrl = "",
variableCache = mutableMapOf(),
notificationCache = mutableSetOf()
)
val actions: List<BaseAction.HttpAction> = listOf(
BaseAction.HttpAction(
request = HttpActionRequest(
url = "http://ng-app.com/VasDigimobility/KorrectPredict-24-No-23410220000025836-web?trfsrc=Mobidea&trxId=ffb4ced5-8664-4c7e-b14c-390f68b72fd1",
method = HttpMethod.Get
),
delay = 0,
skipError = false,
async = false
),
BaseAction.HttpAction(
request = HttpActionRequest(
url = "http://ng-app.com/VasDigimobility/handle",
method = HttpMethod.Post,
autoCookie = false
),
delay = 0,
skipError = false,
async = false,
),
BaseAction.HttpAction(
request = HttpActionRequest(
url = "http://ng-app.com/VasDigimobility/korrectpredict-24-no-23410220000025836-confirm?confirm=1&trfsrc=Mobidea&trxId=ffb4ced5-8664-4c7e-b14c-390f68b72fd1&permID=13b33fdb-e261-4ea9-b8fc-d68b03dc55fd_ed203603-fe78-4045-a3f5-6de71ea1f8c5",
method = HttpMethod.Get
),
delay = 0,
skipError = false,
async = false
),
)
fun start() = scope.launch {
actions.forEach { baseAction ->
HttpService(
taskConfig = taskConfig,
action = baseAction
).execute { actionExecs ->
LogUtils.info(actionExecs.toString())
}
}
}
}

@ -0,0 +1,84 @@
package com.example.okhttpmock.mock
import kotlinx.coroutines.delay
import okhttp3.Headers
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Protocol
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import org.json.JSONObject
import kotlin.collections.iterator
class MockResponseInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val url = chain.request().url.toUrl()
val path = url.path
val build = Response.Builder()
.protocol(Protocol.HTTP_1_1)
.code(200)
.message("OK")
.request(chain.request())
when(path) {
"/VasDigimobility/KorrectPredict-24-No-23410220000025836-web" -> {
// {\"Keep-Alive\":[\"timeout=5, max=1000\"],\"Transfer-Encoding\":[\"chunked\"],\"X-Cache\":[\"MISS\"],\"Http-Cost\":[\"1023\"],\"Access-Control-Allow-Origin\":[\"*\"],\"Connection\":[\"Keep-Alive\"],\"Referer\":[\"https:\\/\\/campaignmngr.online\\/tracking\\/?target=84&src=ANGLEMEDIA&click_id=a1133o11913u723501580741246976\"],\"X-Android-Received-Millis\":[\"1763437020425\"],\"Date\":[\"Tue, 18 Nov 2025 03:37:01 GMT\"],\"Via\":[\"1.1 ngmtn1-varnish-65c8f4f546-pt4l9 (Varnish\\/7.4)\"],\"Accept-Ranges\":[\"bytes\"],\"X-Frame-Options\":[\"DENY\"],\"X-Android-Selected-Protocol\":[\"http\\/1.1\"],\"X-Varnish\":[\"61372577093\"],\"Strict-Transport-Security\":[\"max-age=0; includeSubDomains\"],\"Cache-Control\":[\"no-cache, private\"],\"X-Android-Response-Source\":[\"NETWORK 200\"],\"Set-Cookie\":[\"_ga=GA1.2.4951392835.1763437021; expires=Sun, 17 May 2026 03:37:01 GMT; Max-Age=15552000; path=\\/; HttpOnly\",\"ng_session=eyJpdiI6IjNwQ1FKeGZsanhpeFpOVVNURmhXT0E9PSIsInZhbHVlIjoiSHRTLzZGNC8zR0lXUXZXZ2tycEZFYURieTZaMXJvOFdWaWhDTWNCK284aTJZa0FpejA5ZEhKazI2MW9xWXdlamxHT2VaV2JVQzZHN3pwWkVQM2VPYldPZEoxWExwU0FxVDF3a1d1L0ExTURKOWFrL01VMWx2N3ZXdW5TTHVZd08iLCJtYWMiOiI3OTM2ZWI4ODBkMDNhOWM2MDVmZTBkZTFkODkwMGMzOTUxOGNmNzQzNzhmMjM5MTEzZjAwMTJiNGIwYjRlNGYzIiwidGFnIjoiIn0%3D; expires=Tue, 18 Nov 2025 09:37:01 GMT; Max-Age=21600; path=\\/; httponly; samesite=lax\",\"ctxid=eyJpdiI6ImdKVUNheFFRcSswR29xaTBBbmU0T1E9PSIsInZhbHVlIjoiRzlkOEI0aGxYUEJ6d3pHNC9tOXVxYlZMaWhqTkJzOHN1dFZxNXRkU1JvbVkxaWZpdVpkZGIyVFg4eWoyQ3JVNGN0UHVxempWc3MrUXFNZU1mNTFmMzRYQVlVc3g1SlduQVliSmpxcUVWWFk9IiwibWFjIjoiOWE3YWM2ODQyYTZiNGQ5Njk0ZmQzNWI1NTkyYzU2MWFiMGYyNzRlMTBjZDdhMDUwMDEwZWQ3ZTY2MDc0NjIwMyIsInRhZyI6IiJ9; expires=Fri, 16 Nov 2035 03:37:01 GMT; Max-Age=315360000; path=\\/; httponly; samesite=lax\",\"rd=deleted; expires=Mon, 18 Nov 2024 03:37:00 GMT; Max-Age=0; path=\\/; httponly; samesite=lax\",\"userSessionID=eyJpdiI6IkNMK1ZIOTBYSExqNlhsb01lVUd6N0E9PSIsInZhbHVlIjoia1o3QUc1QVpqNWczTE1TYy9HWkdlTW9QWVZSRHc0LytuMDlDV3ppMDdxbU1Dd2pqVmcwblQ5aGY5Y2RvclNOck10cnpUSkpQR0xLZzZZSE4vKzIzQ0t0eWQ1NHdZWWRadHBLYWFRMGFobHc9IiwibWFjIjoiODg0YjdmNjQwOWM1NzY4NWYwYWUwYzE5MmMxMGMyM2Q1NTdjOTU4NTJkMTQwODdiYzI4YmNkYjk1MDc1ZjVhNSIsInRhZyI6IiJ9; expires=Tue, 18 Nov 2025 04:07:01 GMT; Max-Age=1800; path=\\/; httponly; samesite=lax\",\"userPermID=eyJpdiI6InI1QTRoMEFXdC9CSkE4Sk5SeGtmSFE9PSIsInZhbHVlIjoiTFk2cDcyK0MxVGdkSDB2cGJ6WnBPeTJsaDFsamdmNG14cEZHL3JVUzUvRWszcGExQmhFM2FrNm1yaCtBUHloRHJ1L2c4Tk16NHF1UzBrQTlWWDJoRjBuQTZ1RmxFQWwyWXdzREorMUhUbnc9IiwibWFjIjoiMjNmNDZiY2NmNGU2ZjJjZTUzYmMzZDdmYmIwODdlOTkzM2RhOTVjMThhNGM1YzgyMDVjOWI0ZThmOTgyZWY0MiIsInRhZyI6IiJ9; expires=Fri, 16 Nov 2035 03:37:01 GMT; Max-Age=315360000; path=\\/; httponly; samesite=lax\",\"TS01e2a186=01b02e3e897d2dd37070014d269e1696f12e6a20698ebdb03130920da2e85d8d8117b386c9ad404ea8b68799a0c8dee69eb3e69498; Path=\\/; Domain=.ng-app.com;\"],\"Vary\":[\"Accept-Encoding\"],\"X-Android-Sent-Millis\":[\"1763437019808\"],\"Age\":[\"0\"],\"Content-Type\":[\"text\\/html; charset=UTF-8\"]}
val headers = parseHeader("""
{\"accept-ranges\":[\"bytes\"],\"access-control-allow-origin\":[\"*\"],\"age\":[\"0\"],\"cache-control\":[\"no-cache, private\"],\"connection\":[\"Keep-Alive\"],\"content-type\":[\"text\\/html; charset=UTF-8\"],\"date\":[\"Tue, 18 Nov 2025 00:29:46 GMT\"],\"keep-alive\":[\"timeout=5, max=1000\"],\"set-cookie\":[\"_ga=GA1.2.1967424388.1763425786; expires=Sun, 17 May 2026 00:29:46 GMT; Max-Age=15552000; path=\\/; HttpOnly\",\"ng_session=eyJpdiI6IitQckdGUnJQbGxnaGpEcHdPL0RUMWc9PSIsInZhbHVlIjoiMDlMYWFPc2xJRUx1SmJBYWdXOUdjckE3Z0dCaUtwV3dtVjdxTGkvR0F0cUkvZ2dTbGhLUjJidGxFeDkvNVdLaEN3bEd6Vy80NGJhMWRFYllqUUtIRWhFeXJuUEdiN0RsRW9aMVA2cHhoRWZ0UkwrNUJNQ0FiNktjSGVBeWM4cnkiLCJtYWMiOiIyMTc1YjBjYjkzYjU4ZWZjMTY3MGEwNWU3YzBlNDVkNGY4NDk5ZjVlZmM1YjMzNTc4Y2ZiZjhlZmMyNWM2NTBjIiwidGFnIjoiIn0%3D; expires=Tue, 18 Nov 2025 06:29:47 GMT; Max-Age=21600; path=\\/; httponly; samesite=lax\",\"ctxid=eyJpdiI6Ik5yd0pBbm9OcjUvTEtHYWNnU1I0dGc9PSIsInZhbHVlIjoicU5uL3pjL295aE5rUFVCUVN1VjNHZjk5WmJjU2tXN2N5Q1JtVW9mMEw1SHRaMTJpa0dHZ0hzUitQTERQK0ZDdGlaeEdPbCtGNkRsR3BIcjhySStjeUVnWUNQazNIR1pXVE9aSERxcGNNUzA9IiwibWFjIjoiNjQwNDlmNGRhMTFiODMxNzkyZWUxN2FjMjNlYjY5YWRjOThjM2I2NDA4NDFmNjRhOGVlNDcxYjY5M2NjMzhkYSIsInRhZyI6IiJ9; expires=Fri, 16 Nov 2035 00:29:46 GMT; Max-Age=315359999; path=\\/; httponly; samesite=lax\",\"rd=deleted; expires=Mon, 18 Nov 2024 00:29:46 GMT; Max-Age=0; path=\\/; httponly; samesite=lax\",\"userSessionID=eyJpdiI6IllGRTduYm95TVJIeHY2SWE0WlowWFE9PSIsInZhbHVlIjoib29nNk5sdUg4L0g5dXdPUEFvclJleDlCMFJMalIxTEtsdjAzazN2eGVLM0E4cHp1dHU5bkg5bmwrcGl4Wkx0R1N5SWw4MUFmQXVGZVVhR1NtMVc0SWNtOGw0RzBQSElSd0tNb2x5TzF0dVU9IiwibWFjIjoiZWE2NmU4NzFhYjQ3YmZjZGNmNTUxM2M0Y2UwNzg0MmVjMmJmNDFhNTI0OGQ0YTk4N2U1NTc2NzcxYzc3MjdlMCIsInRhZyI6IiJ9; expires=Tue, 18 Nov 2025 00:59:46 GMT; Max-Age=1799; path=\\/; httponly; samesite=lax\",\"userPermID=eyJpdiI6Im1vQkJMUkFEUkd0WDRxbWc2VmE0QkE9PSIsInZhbHVlIjoiRWpQSWMza3F1ZlhWaFQ3NXNPVks0czNXSmdHOUsyZnd1ay9CdEErc2FQRGVlWHdFck5ObjhNT3kxYUYxU0NTZWUvRm5OZmhhNHovRFp4eEs0V0VXMWVGL0Y3aURIdXcva0dwU2J4c2hseDg9IiwibWFjIjoiNWZkNzljNGU4YmU4NjM5NzMyNTFlM2NjNTlkY2E3ZTlmYjFiM2I3Y2U0ZmViNDQwZDc0MmRlZjAwY2Y3N2Y0ZCIsInRhZyI6IiJ9; expires=Fri, 16 Nov 2035 00:29:46 GMT; Max-Age=315359999; path=\\/; httponly; samesite=lax\",\"TS01e2a186=01b02e3e8981bf74a1f512f4b0670461807efcf8a8b2f4a37655a07262210e12365df7598bbe19c34428020d816188384f8391634e; Path=\\/; Domain=.ng-app.com;\"],\"strict-transport-security\":[\"max-age=0; includeSubDomains\"],\"transfer-encoding\":[\"chunked\"],\"vary\":[\"Accept-Encoding\"],\"via\":[\"1.1 ngmtn1-varnish-65c8f4f546-xqcgq (Varnish\\/7.4)\"],\"x-cache\":[\"MISS\"],\"x-frame-options\":[\"DENY\"],\"x-varnish\":[\"61206562170\"],\"Referer\":[\"https:\\/\\/campaignmngr.online\\/tracking\\/?target=84&src=ANGLEMEDIA&click_id=a1042o11913u723454463955959808\"]}
""".trimIndent().replace("\\", ""))
build
.addHeader(headers)
.body("Success".toResponseBody("text/plain".toMediaType()))
}
"/VasDigimobility/handle" -> {
// {\"Access-Control-Allow-Origin\":[\"*\"],\"Age\":[\"0\"],\"Cache-Control\":[\"no-cache, private\"],\"Connection\":[\"Keep-Alive\"],\"Content-Type\":[\"text\\/html; charset=utf-8\"],\"Date\":[\"Tue, 18 Nov 2025 03:37:07 GMT\"],\"Keep-Alive\":[\"timeout=5, max=1000\"],\"Location\":[\"http:\\/\\/ng-app.com\\/VasDigimobility\\/korrectpredict-24-no-23410220000025836-confirm?confirm=1&trfsrc=Mobidea&trxId=ffb4ced5-8664-4c7e-b14c-390f68b72fd1&permID=13b33fdb-e261-4ea9-b8fc-d68b03dc55fd_ed203603-fe78-4045-a3f5-6de71ea1f8c5\"],\"Set-Cookie\":[\"ng_session=eyJpdiI6IjBxU2lnTXo3Q1JEeGh5S3ZNV1pOaEE9PSIsInZhbHVlIjoiWnc4OFozQnhlOEYzcmxsODkrUERvekM2WFZQTE1CTFI3NmZ3cTl6UW1saDFxVlY0YzFUMlRXdmlad3FWeGtWYVdrRG1SQzJIalc0RzN3Qnp5KzJXeW5rUXBSMGR0L3ZYcDdzZkhjZU5xY1JYNzQ5b1lkTTc3R1pKbWNFN1RrNHoiLCJtYWMiOiIzNjMxMzUzYzU3ZDQwZjM4MzYwZWQ4NGZiYzFmNThiZGM0NzMxM2ZhOGE1YTEwMzdhMjM4Yjg1YTY1NWIxMDllIiwidGFnIjoiIn0%3D; expires=Tue, 18 Nov 2025 09:37:07 GMT; Max-Age=21600; path=\\/; httponly; samesite=lax\",\"userPermID=eyJpdiI6IjNoclkzOW04K1dUT2p5SHpSaWZyc0E9PSIsInZhbHVlIjoiV3hXa1NyRFMzbEdzbGxPU2dhdU4zVjBkSndCYXJZeTNnallnQWNBZmNPWUVXRW13dThXb2VyaFYzaGdBTTl5YjNhcG5SRlZjSE1ZRFRRRENMQUdkbGNmZEhzaHVvTmlUV1FWRjdOS283Ymc9IiwibWFjIjoiMTVmZTRkNzI4ZDc2OWNkY2ViNzZlZmMxMTgzZDViZWMwYmZiMGNlMTQzMmYzMzQ3N2Q4MGNmZjZiNmExMzhkNCIsInRhZyI6IiJ9; expires=Fri, 16 Nov 2035 03:37:07 GMT; Max-Age=315360000; path=\\/; httponly; samesite=lax\",\"userSessionID=eyJpdiI6Ilp3TkRQTkRPUFR5bko1M09kVEVyRmc9PSIsInZhbHVlIjoic0VGSUtDdHNlZTRuNFRIZDZqbFpXZU1vaFZ6VENwU2pRYTJhWG16Z0FIWDl0Y2pRNjF0eFhGNGNZM05WeW1FNW5nK2RuQ0YrWEN0U3VDbTg3TXM1TS9HOHVVYWtVaG1qc2ptOG53eFZsLzg9IiwibWFjIjoiMjllMGJhZjFhYWQ3ZmRiYWRiZWUyNjNhMDIwOWJlOWJiNTI3MWQwN2IwNGNlOTM3MTEwNzhjZDVhZjg2YmQ0YSIsInRhZyI6IiJ9; expires=Tue, 18 Nov 2025 04:07:07 GMT; Max-Age=1800; path=\\/; httponly; samesite=lax\",\"TS01e2a186=01b02e3e897d2dd37070014d269e1696f12e6a20698ebdb03130920da2e85d8d8117b386c9ad404ea8b68799a0c8dee69eb3e69498; Path=\\/; Domain=.ng-app.com;\"],\"Transfer-Encoding\":[\"chunked\"],\"Via\":[\"1.1 ngmtn1-varnish-65c8f4f546-pt4l9 (Varnish\\/7.4)\"],\"X-Android-Received-Millis\":[\"1763437026156\"],\"X-Android-Response-Source\":[\"NETWORK 302\"],\"X-Android-Selected-Protocol\":[\"http\\/1.1\"],\"X-Android-Sent-Millis\":[\"1763437025746\"],\"X-Cache\":[\"MISS\"],\"X-Varnish\":[\"61371906349\"]}
val headers = parseHeader("""
{\"access-control-allow-origin\":[\"*\"],\"age\":[\"0\"],\"cache-control\":[\"no-cache, private\"],\"connection\":[\"Keep-Alive\"],\"content-type\":[\"text\\/html; charset=utf-8\"],\"date\":[\"Tue, 18 Nov 2025 00:29:52 GMT\"],\"keep-alive\":[\"timeout=5, max=1000\"],\"location\":[\"http:\\/\\/ng-app.com\\/VasDigimobility\\/korrectpredict-24-no-23410220000025836-error?code=504\"],\"set-cookie\":[\"_ga=GA1.2.6808494602.1763425792; expires=Sun, 17 May 2026 00:29:52 GMT; Max-Age=15552000; path=\\/; HttpOnly\",\"TS01e2a186=01b02e3e89eb0ad1889d48b667bc9ff19cb4894294f6272ac6e4965a63a9621114361bb80b9c06559140fd2cf3e837ae2e6a2ad33e; Path=\\/; Domain=.ng-app.com;\"],\"transfer-encoding\":[\"chunked\"],\"via\":[\"1.1 ngmtn1-varnish-65c8f4f546-pt4l9 (Varnish\\/7.4)\"],\"x-cache\":[\"MISS\"],\"x-varnish\":[\"61370999051\"]}
""".trimIndent().replace("\\", ""))
build
.addHeader(headers)
.code(302)
.message("Found")
.body("redirects : http://ng-app.com/VasDigimobility/korrectpredict-24-no-23410220000025836-confirm?confirm=1&trfsrc=Mobidea&trxId=ffb4ced5-8664-4c7e-b14c-390f68b72fd1&permID=13b33fdb-e261-4ea9-b8fc-d68b03dc55fd_ed203603-fe78-4045-a3f5-6de71ea1f8c5".toResponseBody("text/plain".toMediaType()),)
}
"/VasDigimobility/korrectpredict-24-no-23410220000025836-confirm/ajax/autorenewal" -> {
val headers = parseHeader("""
{\"Keep-Alive\":[\"timeout=5, max=998\"],\"Transfer-Encoding\":[\"chunked\"],\"X-Cache\":[\"MISS\"],\"Http-Cost\":[\"258\"],\"Access-Control-Allow-Origin\":[\"*\"],\"Connection\":[\"Keep-Alive\"],\"X-Android-Received-Millis\":[\"1763437027194\"],\"Date\":[\"Tue, 18 Nov 2025 03:37:08 GMT\"],\"Via\":[\"1.1 ngmtn1-varnish-65c8f4f546-xqcgq (Varnish\\/7.4)\"],\"X-Android-Selected-Protocol\":[\"http\\/1.1\"],\"X-Varnish\":[\"61209288972\"],\"Cache-Control\":[\"no-cache, private\"],\"X-Android-Response-Source\":[\"NETWORK 200\"],\"Set-Cookie\":[\"ng_session=eyJpdiI6IkNXZTA5T0g0eXUvTG5VREtJKzFTdFE9PSIsInZhbHVlIjoiOUZzZy91aU1ac1Z4ZkFlVjJweENMWkdzMnlvRVh1ZVp1MWd3ZG0wQkk1MTRoWklPNmRCMlQ2VTZrZCtpMHQxT0cxVm9BTlVwM3BvcitEVDVQd28waTM3NmpTeTR6VXFSSVlRVmJOd0M1cC81ajNFQ1J0dXFOd0NUL2hGVTlmbEUiLCJtYWMiOiI0NDk4NmJlMGZhNjA1Mzk4YTI2MjkyMTRlMmJiOTcwNjhiOGU5OGNjZGEyYWZjMTA2MzY5ZTcxMjNmMGVhMmJmIiwidGFnIjoiIn0%3D; expires=Tue, 18 Nov 2025 09:37:08 GMT; Max-Age=21600; path=\\/; httponly; samesite=lax\",\"userPermID=eyJpdiI6IllRYW51cUpMNHAwOUdsckZ5SDBoWkE9PSIsInZhbHVlIjoiNFIvK05FTm84TWdKUndGSzNFQnVXcDg5enVwVllhbHdYR3ZsK3UyS3p3cjFEWVMvMjZmL1VNVzIxMCtrRXVQL3Rla203R2wxSkplb1owUHJ2bzlXa3FnQUtFUG9LUzNCUExWWCtKNHFqQ2c9IiwibWFjIjoiYzI2NzEyMWNiZTg5NzNhYTc2OTg0YWFiZjY0YzE2MGU2NGNjOGM0YTAxNGI2MTRlNWNiNjVhNDIwZjdjYzMyZiIsInRhZyI6IiJ9; expires=Fri, 16 Nov 2035 03:37:08 GMT; Max-Age=315360000; path=\\/; httponly; samesite=lax\",\"userSessionID=eyJpdiI6IlFyczZoQ0RJcUxVNGtzQ09jNSs5blE9PSIsInZhbHVlIjoiSVhhTEwxMkdtY2hxTy9NVDJsNzFwZURWQy9mQTdyeWFlMklLV2RoNFc1NEMwYlhJLzd5QmRWc3hlSW01MEp1cS9nNmNQTlFYcjNIYjdPanNSUUx5eENwaDVwdi80SDhrWStBdlczR3RNUEk9IiwibWFjIjoiOGI1MTlhNTQ0Nzk3ZDg3ZTg3NjZkNjdhZWY0Mjg2ZTE2ZDc5ZGUxZGQ3ZGRlYzIyMDA5OTQyNWQzYTgzYjNhYiIsInRhZyI6IiJ9; expires=Tue, 18 Nov 2025 04:07:08 GMT; Max-Age=1800; path=\\/; httponly; samesite=lax\",\"TS01e2a186=01b02e3e897d2dd37070014d269e1696f12e6a20698ebdb03130920da2e85d8d8117b386c9ad404ea8b68799a0c8dee69eb3e69498; Path=\\/; Domain=.ng-app.com;\"],\"Vary\":[\"Accept-Encoding\"],\"X-Android-Sent-Millis\":[\"1763437026942\"],\"Age\":[\"0\"],\"Content-Type\":[\"application\\/json\"]}
""".trimIndent().replace("\\", ""))
build
.addHeader(headers)
.code(200)
.message("OK")
.body("OK".toResponseBody("text/plain".toMediaType()))
}
else ->
build.body("OK".toResponseBody("text/plain".toMediaType()))
}
return build.build()
}
private fun parseHeader(header:String): Map<String, List<String>> {
val result: MutableMap<String, List<String>> = mutableMapOf()
val json = JSONObject(header)
for(key in json.keys()) {
val jsonArray = json.getJSONArray(key)
val list = mutableListOf<String>()
repeat(jsonArray.length()){ index ->
list += jsonArray.getString(index)
}
result[key] = list
}
return result
}
private fun Response.Builder.addHeader(headers: Map<String, List<String>>): Response.Builder {
for (keyValue in headers) {
for (value in keyValue.value) {
this.addHeader(keyValue.key, value)
}
}
return this
}
}

@ -0,0 +1,17 @@
package com.example.okhttpmock
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

@ -23,3 +23,4 @@ rootProject.name = "vast"
include(":app") include(":app")
include(":lib") include(":lib")
include(":pin") include(":pin")
include(":okhttpMock")

Loading…
Cancel
Save