Fix 2
This commit is contained in:
parent
767372be54
commit
4e7fd5a9f7
@ -61,6 +61,9 @@ dependencies {
|
||||
testImplementation("io.github.classgraph:classgraph:4.8.184")
|
||||
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")
|
||||
testImplementation("io.mockk:mockk:1.13.9")
|
||||
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.17.0")
|
||||
testImplementation("org.reflections:reflections:0.10.2")
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import no.iktdev.eventi.models.store.TaskStatus
|
||||
/**
|
||||
* Base class, should not be serialized into
|
||||
*/
|
||||
abstract class TaskResultEvent(
|
||||
open val status: TaskStatus,
|
||||
open val error: String? = null
|
||||
open class TaskResultEvent(
|
||||
val status: TaskStatus,
|
||||
val error: String? = null
|
||||
) : Event()
|
||||
|
||||
@ -3,10 +3,10 @@ package no.iktdev.mediaprocessing.shared.common.event_task_contract.events
|
||||
import no.iktdev.eventi.models.store.TaskStatus
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.TaskResultEvent
|
||||
|
||||
data class ConvertTaskResultEvent(
|
||||
class ConvertTaskResultEvent(
|
||||
val data: ConvertedData?,
|
||||
override val status: TaskStatus,
|
||||
override val error: String? = null,
|
||||
status: TaskStatus,
|
||||
error: String? = null,
|
||||
): TaskResultEvent(status, error) {
|
||||
data class ConvertedData(
|
||||
val language: String,
|
||||
|
||||
@ -4,8 +4,8 @@ import com.google.gson.JsonObject
|
||||
import no.iktdev.eventi.models.store.TaskStatus
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.TaskResultEvent
|
||||
|
||||
data class CoordinatorReadStreamsResultEvent(
|
||||
class CoordinatorReadStreamsResultEvent(
|
||||
val data: JsonObject? = null,
|
||||
override val status: TaskStatus,
|
||||
override val error: String? = null
|
||||
status: TaskStatus,
|
||||
error: String? = null
|
||||
) : TaskResultEvent(status, error)
|
||||
|
||||
@ -3,10 +3,10 @@ package no.iktdev.mediaprocessing.shared.common.event_task_contract.events
|
||||
import no.iktdev.eventi.models.store.TaskStatus
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.TaskResultEvent
|
||||
|
||||
data class CoverDownloadResultEvent(
|
||||
class CoverDownloadResultEvent(
|
||||
val data: CoverDownloadedData? = null,
|
||||
override val status: TaskStatus,
|
||||
override val error: String? = null
|
||||
status: TaskStatus,
|
||||
error: String? = null
|
||||
) : TaskResultEvent(status, error){
|
||||
data class CoverDownloadedData(
|
||||
val source: String,
|
||||
|
||||
@ -6,11 +6,11 @@ import no.iktdev.mediaprocessing.shared.common.event_task_contract.TaskResultEve
|
||||
import no.iktdev.mediaprocessing.shared.common.model.MediaType
|
||||
import java.util.*
|
||||
|
||||
data class MetadataSearchResultEvent(
|
||||
class MetadataSearchResultEvent(
|
||||
val results: List<SearchResult> = emptyList(),
|
||||
val recommended: SearchResult? = null,
|
||||
override val status: TaskStatus,
|
||||
override val error: String? = null
|
||||
status: TaskStatus,
|
||||
error: String? = null
|
||||
) : TaskResultEvent(status, error) {
|
||||
data class SearchResult(
|
||||
val simpleScore: Int,
|
||||
|
||||
@ -4,13 +4,13 @@ import no.iktdev.eventi.models.store.TaskStatus
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.TaskResultEvent
|
||||
import no.iktdev.mediaprocessing.shared.common.model.MigrateStatus
|
||||
|
||||
data class MigrateContentToStoreTaskResultEvent(
|
||||
class MigrateContentToStoreTaskResultEvent(
|
||||
val collection: String,
|
||||
val videoMigrate: FileMigration,
|
||||
val subtitleMigrate: List<SubtitleMigration>,
|
||||
val coverMigrate: List<FileMigration>,
|
||||
override val status: TaskStatus,
|
||||
override val error: String? = null
|
||||
status: TaskStatus,
|
||||
error: String? = null
|
||||
) : TaskResultEvent(status, error) {
|
||||
data class FileMigration(
|
||||
val storedUri: String?,
|
||||
|
||||
@ -3,10 +3,10 @@ package no.iktdev.mediaprocessing.shared.common.event_task_contract.events
|
||||
import no.iktdev.eventi.models.store.TaskStatus
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.TaskResultEvent
|
||||
|
||||
data class ProcesserEncodeResultEvent(
|
||||
class ProcesserEncodeResultEvent(
|
||||
val data: EncodeResult? = null,
|
||||
override val status: TaskStatus,
|
||||
override val error: String? = null
|
||||
status: TaskStatus,
|
||||
error: String? = null
|
||||
) : TaskResultEvent(status, error) {
|
||||
data class EncodeResult(
|
||||
val cachedOutputFile: String? = null
|
||||
|
||||
@ -3,10 +3,10 @@ package no.iktdev.mediaprocessing.shared.common.event_task_contract.events
|
||||
import no.iktdev.eventi.models.store.TaskStatus
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.TaskResultEvent
|
||||
|
||||
data class ProcesserExtractResultEvent(
|
||||
class ProcesserExtractResultEvent(
|
||||
val data: ExtractResult? = null,
|
||||
override val status: TaskStatus,
|
||||
override val error: String? = null
|
||||
status: TaskStatus,
|
||||
error: String? = null
|
||||
) : TaskResultEvent(status, error) {
|
||||
data class ExtractResult(
|
||||
val language: String,
|
||||
|
||||
@ -3,8 +3,8 @@ package no.iktdev.mediaprocessing.shared.common.event_task_contract.events
|
||||
import no.iktdev.eventi.models.store.TaskStatus
|
||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.TaskResultEvent
|
||||
|
||||
data class StoreContentAndMetadataTaskResultEvent(
|
||||
override val status: TaskStatus,
|
||||
override val error: String? = null
|
||||
class StoreContentAndMetadataTaskResultEvent(
|
||||
status: TaskStatus,
|
||||
error: String? = null
|
||||
) : TaskResultEvent(status, error){
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
package no.iktdev.mediaprocessing.shared.common.event_task_contract
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.databind.SerializationFeature
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinFeature
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializer
|
||||
import no.iktdev.eventi.models.store.TaskStatus
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertDoesNotThrow
|
||||
import org.reflections.Reflections
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
|
||||
class TaskResultEventSerializationTest {
|
||||
|
||||
val gson = GsonBuilder()
|
||||
.registerTypeAdapter(Instant::class.java, JsonSerializer<Instant> { src, _, _ ->
|
||||
JsonPrimitive(src.toString())
|
||||
})
|
||||
.registerTypeAdapter(Instant::class.java, JsonDeserializer { json, _, _ ->
|
||||
Instant.parse(json.asString)
|
||||
})
|
||||
.create()
|
||||
|
||||
val jackson = ObjectMapper()
|
||||
.registerModule(JavaTimeModule())
|
||||
.registerModule(
|
||||
KotlinModule.Builder()
|
||||
.configure(KotlinFeature.NullToEmptyCollection, false)
|
||||
.configure(KotlinFeature.NullToEmptyMap, false)
|
||||
.configure(KotlinFeature.NullIsSameAsDefault, false)
|
||||
.configure(KotlinFeature.StrictNullChecks, true)
|
||||
.configure(KotlinFeature.UseJavaDurationConversion, true)
|
||||
.build()
|
||||
)
|
||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||
|
||||
|
||||
@Test
|
||||
fun `all TaskResultEvent subclasses must serialize with Gson and Jackson`() {
|
||||
val reflections = Reflections("no.iktdev.mediaprocessing") // rotpakken din
|
||||
val subclasses = reflections.getSubTypesOf(TaskResultEvent::class.java)
|
||||
|
||||
require(subclasses.isNotEmpty()) {
|
||||
"Fant ingen subklasser av TaskResultEvent — er pakken riktig?"
|
||||
}
|
||||
|
||||
subclasses.forEach { clazz ->
|
||||
assertDoesNotThrow("Serialization failed for ${clazz.simpleName}") {
|
||||
val instance = createDummyInstance(clazz)
|
||||
val jsonGson = gson.toJson(instance)
|
||||
gson.fromJson(jsonGson, clazz)
|
||||
|
||||
val jsonJackson = jackson.writeValueAsString(instance)
|
||||
jackson.readValue(jsonJackson, clazz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lager en dummy-instans av en TaskResultEvent-subklasse.
|
||||
* Forutsetter at alle event-klasser har en primary constructor.
|
||||
*/
|
||||
private fun createDummyInstance(clazz: Class<*>): Any {
|
||||
val kClass = clazz.kotlin
|
||||
val ctor = kClass.primaryConstructor
|
||||
?: error("Klassen ${clazz.simpleName} mangler primary constructor")
|
||||
|
||||
val args = ctor.parameters.associateWith { param ->
|
||||
val kType = param.type
|
||||
val classifier = kType.classifier
|
||||
|
||||
// --- 1. Handle concrete known types first ---
|
||||
if (classifier == String::class) return@associateWith "dummy"
|
||||
if (classifier == Int::class) return@associateWith 1
|
||||
if (classifier == Long::class) return@associateWith 1L
|
||||
if (classifier == Boolean::class) return@associateWith false
|
||||
if (classifier == Double::class) return@associateWith 1.0
|
||||
if (classifier == UUID::class) return@associateWith UUID.randomUUID()
|
||||
if (classifier == Instant::class) return@associateWith Instant.now()
|
||||
if (classifier == TaskStatus::class) return@associateWith TaskStatus.Completed
|
||||
if (classifier == Float::class) return@associateWith 1.0f
|
||||
|
||||
|
||||
// --- 2. Generic enum support ---
|
||||
if (classifier is KClass<*> && classifier.java.isEnum) {
|
||||
return@associateWith classifier.java.enumConstants.first()
|
||||
}
|
||||
|
||||
// --- 3. Lists and maps ---
|
||||
if (classifier == List::class) return@associateWith emptyList<Any>()
|
||||
if (classifier == Map::class) return@associateWith emptyMap<String, Any>()
|
||||
|
||||
// --- 4. Nested data classes ---
|
||||
if (classifier is KClass<*> && classifier.isData) {
|
||||
return@associateWith createDummyInstance(classifier.java)
|
||||
}
|
||||
|
||||
// --- 5. Fallback ---
|
||||
null
|
||||
}
|
||||
|
||||
return ctor.callBy(args)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user