fix: remove smoke-tests
This is rather useless in the current form since it doesn't actually update the fixtures so the tests don't do anything useful yet. Will reintroduce it at a later point.
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
name: Smoke tests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 6 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
smoke-tests:
|
||||
runs-on: macos-26
|
||||
steps:
|
||||
- name: Setup build environment
|
||||
uses: msfjarvis/compose-lobsters/.github/reusable-workflows/setup-gradle@main
|
||||
with:
|
||||
fetch-depth: 0
|
||||
cache-read-only: true
|
||||
|
||||
- name: Run smoke probe
|
||||
run: ./gradlew --no-configuration-cache --stacktrace :smoke-tests:run
|
||||
@@ -162,6 +162,5 @@ include(
|
||||
"database:core",
|
||||
"database:impl",
|
||||
"model",
|
||||
"smoke-tests",
|
||||
"zipline-parser",
|
||||
)
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright © Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
plugins {
|
||||
java
|
||||
id("dev.msfjarvis.claw.kotlin-jvm")
|
||||
alias(libs.plugins.dependencyAnalysis)
|
||||
alias(libs.plugins.metro)
|
||||
}
|
||||
|
||||
val smokeTestsMainClass = "dev.msfjarvis.claw.smoketests.MainKt"
|
||||
|
||||
tasks.register<JavaExec>("run") {
|
||||
group = "application"
|
||||
description = "Runs the smoke tests application."
|
||||
classpath = sourceSets.main.get().runtimeClasspath
|
||||
mainClass.set(smokeTestsMainClass)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.api)
|
||||
implementation(projects.core)
|
||||
implementation(projects.ziplineParser)
|
||||
implementation(libs.eithernet.integration.retrofit)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.okhttp.core)
|
||||
implementation(libs.retrofit)
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<issues format="6" by="lint 9.4.0-alpha03" type="baseline" client="gradle" dependencies="true" name="AGP (9.4.0-alpha03)" variant="all" version="9.4.0-alpha03">
|
||||
|
||||
</issues>
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright © Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.smoketests
|
||||
|
||||
import dev.msfjarvis.claw.api.LobstersParserClient
|
||||
import dev.msfjarvis.claw.parser.LobstersParserService
|
||||
import dev.msfjarvis.claw.parser.LobstersParserServiceImpl
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.binding
|
||||
|
||||
@Inject
|
||||
@ContributesBinding(AppScope::class, binding = binding<LobstersParserClient>())
|
||||
class JvmParserClient : LobstersParserClient {
|
||||
private val service = LobstersParserServiceImpl()
|
||||
|
||||
override suspend fun service(): LobstersParserService = service
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright © Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.smoketests
|
||||
|
||||
import kotlin.system.exitProcess
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
fun main() {
|
||||
val graph = createSmokeTestsGraph()
|
||||
val result = runBlocking { graph.smokeProbeRunner.run() }
|
||||
if (!result.isSuccess) {
|
||||
System.err.println("Smoke probe failed")
|
||||
result.errors().forEach { System.err.println(it) }
|
||||
exitProcess(1)
|
||||
}
|
||||
println("Smoke probe passed")
|
||||
exitProcess(0)
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright © Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.smoketests
|
||||
|
||||
import com.slack.eithernet.ApiResult
|
||||
import dev.msfjarvis.claw.api.LobstersApi
|
||||
import dev.msfjarvis.claw.model.Comment
|
||||
import dev.msfjarvis.claw.model.LobstersPost
|
||||
import dev.msfjarvis.claw.model.LobstersPostDetails
|
||||
import dev.msfjarvis.claw.model.Tag
|
||||
import dev.zacsweers.metro.Inject
|
||||
|
||||
class SmokeProbeResult(private val errors: List<String>) {
|
||||
val isSuccess: Boolean
|
||||
get() = errors.isEmpty()
|
||||
|
||||
fun errors(): List<String> = errors
|
||||
}
|
||||
|
||||
@Inject
|
||||
class SmokeProbeRunner(private val api: LobstersApi) {
|
||||
suspend fun run(): SmokeProbeResult {
|
||||
val failures = mutableListOf<String>()
|
||||
|
||||
val hottest = probe("getHottestPosts(1)", failures) { api.getHottestPosts(1) }
|
||||
val hottestPosts = hottest?.also { validatePosts("getHottestPosts(1)", it, failures) }.orEmpty()
|
||||
|
||||
probe("getNewestPosts(1)", failures) { api.getNewestPosts(1) }
|
||||
?.also { validatePosts("getNewestPosts(1)", it, failures) }
|
||||
|
||||
probe("getTags()", failures) { api.getTags() }?.also { validateTags(it, failures) }
|
||||
|
||||
probe("getCSRFToken()", failures) { api.getCSRFToken() }
|
||||
?.also { token -> if (token.value.isBlank()) failures += "getCSRFToken(): blank token" }
|
||||
|
||||
val discoveredPost = hottestPosts.firstOrNull {
|
||||
it.shortId.isNotBlank() && it.submitter.isNotBlank()
|
||||
}
|
||||
if (discoveredPost == null) {
|
||||
failures += "discovery: no post with usable id and username"
|
||||
return SmokeProbeResult(failures)
|
||||
}
|
||||
|
||||
probe("getUser(${discoveredPost.submitter})", failures) {
|
||||
api.getUser(discoveredPost.submitter)
|
||||
}
|
||||
?.also { user -> validateUser(discoveredPost.submitter, user.username, failures) }
|
||||
|
||||
probe("getPostDetails(${discoveredPost.shortId})", failures) {
|
||||
api.getPostDetails(discoveredPost.shortId)
|
||||
}
|
||||
?.also { details ->
|
||||
validatePostDetails(discoveredPost.shortId, discoveredPost.submitter, details, failures)
|
||||
}
|
||||
|
||||
return SmokeProbeResult(failures)
|
||||
}
|
||||
|
||||
private suspend fun <T : Any> probe(
|
||||
name: String,
|
||||
failures: MutableList<String>,
|
||||
block: suspend () -> ApiResult<T, Unit>,
|
||||
): T? {
|
||||
return when (val result = block()) {
|
||||
is ApiResult.Success -> {
|
||||
println("PASS $name")
|
||||
result.value
|
||||
}
|
||||
is ApiResult.Failure -> {
|
||||
val message = "FAIL $name: $result"
|
||||
println(message)
|
||||
failures += message
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun validatePosts(name: String, posts: List<LobstersPost>, failures: MutableList<String>) {
|
||||
if (posts.isEmpty()) {
|
||||
failures += "$name: empty posts"
|
||||
return
|
||||
}
|
||||
posts.forEachIndexed { index, post ->
|
||||
if (post.shortId.isBlank()) failures += "$name: post[$index] blank id"
|
||||
if (post.title.isBlank()) failures += "$name: post[$index] blank title"
|
||||
if (post.url.isBlank()) failures += "$name: post[$index] blank url"
|
||||
if (post.tags.isEmpty()) failures += "$name: post[$index] empty tags"
|
||||
post.tags.forEachIndexed { tagIndex, tag ->
|
||||
if (tag.isBlank()) failures += "$name: post[$index] tag[$tagIndex] blank name"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateTags(tags: List<Tag>, failures: MutableList<String>) {
|
||||
if (tags.isEmpty()) {
|
||||
failures += "getTags(): empty tags"
|
||||
return
|
||||
}
|
||||
tags.forEachIndexed { index, tag ->
|
||||
if (tag.tag.isBlank()) failures += "getTags(): tag[$index] blank name"
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateUser(
|
||||
expectedUsername: String,
|
||||
actualUsername: String,
|
||||
failures: MutableList<String>,
|
||||
) {
|
||||
if (actualUsername.isBlank()) failures += "getUser($expectedUsername): blank username"
|
||||
if (actualUsername.isNotBlank() && actualUsername != expectedUsername) {
|
||||
failures += "getUser($expectedUsername): returned username '$actualUsername'"
|
||||
}
|
||||
}
|
||||
|
||||
private fun validatePostDetails(
|
||||
expectedShortId: String,
|
||||
expectedSubmitter: String,
|
||||
details: LobstersPostDetails,
|
||||
failures: MutableList<String>,
|
||||
) {
|
||||
if (details.shortId.isBlank()) failures += "getPostDetails($expectedShortId): blank id"
|
||||
if (details.shortId.isNotBlank() && details.shortId != expectedShortId) {
|
||||
failures += "getPostDetails($expectedShortId): returned id '${details.shortId}'"
|
||||
}
|
||||
if (details.title.isBlank()) failures += "getPostDetails($expectedShortId): blank title"
|
||||
if (details.submitter.isNotBlank() && details.submitter != expectedSubmitter) {
|
||||
failures += "getPostDetails($expectedShortId): returned submitter '${details.submitter}'"
|
||||
}
|
||||
if (details.tags.isEmpty()) failures += "getPostDetails($expectedShortId): empty tags"
|
||||
details.tags.forEachIndexed { index, tag ->
|
||||
if (tag.isBlank()) failures += "getPostDetails($expectedShortId): tag[$index] blank name"
|
||||
}
|
||||
details.comments.forEachIndexed { index, comment ->
|
||||
validateComment(expectedShortId, comment, index, failures)
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateComment(
|
||||
expectedShortId: String,
|
||||
comment: Comment,
|
||||
index: Int,
|
||||
failures: MutableList<String>,
|
||||
) {
|
||||
if (comment.shortId.isBlank())
|
||||
failures += "getPostDetails($expectedShortId): comment[$index] blank id"
|
||||
if (comment.user.isBlank())
|
||||
failures += "getPostDetails($expectedShortId): comment[$index] blank username"
|
||||
if (comment.score < 0)
|
||||
failures += "getPostDetails($expectedShortId): comment[$index] invalid score ${comment.score}"
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright © Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.smoketests
|
||||
|
||||
import dev.msfjarvis.claw.core.network.OkHttpClientConfigurator
|
||||
import dev.msfjarvis.claw.core.network.SessionCookieStore
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.BindingContainer
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import dev.zacsweers.metro.Provides
|
||||
import java.io.File
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
|
||||
@BindingContainer
|
||||
@ContributesTo(AppScope::class)
|
||||
object SmokeTestsBindings {
|
||||
@Provides
|
||||
fun provideCacheDir(): File =
|
||||
File(System.getProperty("java.io.tmpdir"), "claw-smoke-tests").apply {
|
||||
mkdirs()
|
||||
}
|
||||
|
||||
@Provides fun provideSessionCookieStore(): SessionCookieStore = InMemorySessionCookieStore
|
||||
|
||||
@Provides fun provideOkHttpClientConfigurator(): Set<OkHttpClientConfigurator> = emptySet()
|
||||
|
||||
@Provides
|
||||
fun provideLogger(): HttpLoggingInterceptor.Logger = HttpLoggingInterceptor.Logger { _ -> }
|
||||
}
|
||||
|
||||
private object InMemorySessionCookieStore : SessionCookieStore {
|
||||
private var cookie: String? = null
|
||||
private var usernameValue: String? = null
|
||||
private val loggedIn = MutableStateFlow(false)
|
||||
private val usernameFlow = MutableStateFlow<String?>(null)
|
||||
|
||||
override fun get(): String? = cookie
|
||||
|
||||
override fun getUsername(): String? = usernameValue
|
||||
|
||||
override fun set(cookie: String, username: String) {
|
||||
this.cookie = cookie
|
||||
usernameValue = username
|
||||
loggedIn.value = true
|
||||
usernameFlow.value = username
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
cookie = null
|
||||
usernameValue = null
|
||||
loggedIn.value = false
|
||||
usernameFlow.value = null
|
||||
}
|
||||
|
||||
override fun isLoggedIn(): Flow<Boolean> = loggedIn
|
||||
|
||||
override fun username(): Flow<String?> = usernameFlow
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright © Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.smoketests
|
||||
|
||||
import dev.msfjarvis.claw.api.LobstersApi
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.DependencyGraph
|
||||
import dev.zacsweers.metro.createGraphFactory
|
||||
|
||||
@DependencyGraph(AppScope::class)
|
||||
interface SmokeTestsGraph {
|
||||
val lobstersApi: LobstersApi
|
||||
val smokeProbeRunner: SmokeProbeRunner
|
||||
|
||||
@DependencyGraph.Factory
|
||||
fun interface Factory {
|
||||
fun create(): SmokeTestsGraph
|
||||
}
|
||||
}
|
||||
|
||||
fun createSmokeTestsGraph(): SmokeTestsGraph =
|
||||
createGraphFactory<SmokeTestsGraph.Factory>().create()
|
||||
Reference in New Issue
Block a user