Skip to content

Commit

Permalink
Merge pull request #1471 from znsio/int-ser-clnup
Browse files Browse the repository at this point in the history
 Unify the command line and GUI for the interactive server
  • Loading branch information
joelrosario authored Dec 13, 2024
2 parents 481ddc7 + 8d32e1a commit d745f64
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 267 deletions.
53 changes: 20 additions & 33 deletions application/src/main/kotlin/application/ExamplesCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import io.specmatic.core.Results
import io.specmatic.core.SPECMATIC_STUB_DICTIONARY
import io.specmatic.core.examples.server.ExamplesInteractiveServer
import io.specmatic.core.examples.server.ExamplesInteractiveServer.Companion.externaliseInlineExamples
import io.specmatic.core.examples.server.ExamplesInteractiveServer.Companion.validateSingleExample
import io.specmatic.core.examples.server.ExamplesInteractiveServer.Companion.validateExample
import io.specmatic.core.examples.server.defaultExternalExampleDirFrom
import io.specmatic.core.examples.server.loadExternalExamples
import io.specmatic.core.log.*
Expand Down Expand Up @@ -107,6 +107,13 @@ For example:
)
var filterNot: List<String> = emptyList()

@Option(
names = ["--allow-only-mandatory-keys-in-payload"],
description = ["Generate examples with only mandatory keys in the json request and response payloads"],
required = false
)
var allowOnlyMandatoryKeysInJSONObject: Boolean = false

override fun call(): Int {
if (contractFile == null) {
println("No contract file provided. Use a subcommand or provide a contract file. Use --help for more details.")
Expand All @@ -127,7 +134,7 @@ For example:
ExamplesInteractiveServer.generate(
contractFile!!,
ExamplesInteractiveServer.ScenarioFilter(filterName, filterNotName, filter, filterNot),
extensive,
extensive, allowOnlyMandatoryKeysInJSONObject
)
} catch (e: Throwable) {
logger.log(e)
Expand Down Expand Up @@ -222,6 +229,8 @@ For example:
var filterNotName: String = ""

override fun call(): Int {
configureLogger(this.verbose)

if (contractFile != null && exampleFile != null) return validateExampleFile(contractFile!!, exampleFile)

if (contractFile != null && examplesDir != null) {
Expand Down Expand Up @@ -254,11 +263,8 @@ For example:
return FAILURE_EXIT_CODE
}

configureLogger(this.verbose)

try {
validateSingleExample(contractFile, exampleFile).throwOnFailure()

validateExample(contractFile, exampleFile).throwOnFailure()
logger.log("The provided example ${exampleFile.name} is valid.")
return SUCCESS_EXIT_CODE
} catch (e: ContractException) {
Expand All @@ -268,7 +274,7 @@ For example:
}
}

private fun validateExamplesDir(contractFile: File, examplesDir: File, enableLogging: Boolean = true): Pair<Int, Map<String, Result>> {
private fun validateExamplesDir(contractFile: File, examplesDir: File): Pair<Int, Map<String, Result>> {
val feature = parseContractFileToFeature(contractFile)
val (externalExampleDir, externalExamples) = loadExternalExamples(examplesDir = examplesDir)
if (!externalExampleDir.exists()) {
Expand All @@ -279,18 +285,15 @@ For example:
logger.log("No example files found in $externalExampleDir")
return FAILURE_EXIT_CODE to emptyMap()
}
return SUCCESS_EXIT_CODE to validateExternalExamples(feature, externalExamples, enableLogging)
return SUCCESS_EXIT_CODE to validateExternalExamples(feature, externalExamples)
}

private fun validateAllExamplesAssociatedToEachSpecIn(
specsDir: File,
examplesBaseDir: File
): Int {
private fun validateAllExamplesAssociatedToEachSpecIn(specsDir: File, examplesBaseDir: File): Int {
val validationResults = specsDir.walk().filter { it.isFile }.flatMapIndexed { index, it ->
val associatedExamplesDir = examplesBaseDir.associatedExampleDirFor(it) ?: return@flatMapIndexed emptyList()

logger.log("${index.inc()}. Validating examples in ${associatedExamplesDir.name} associated to ${it.name}...${System.lineSeparator()}")
val results = validateExamplesDir(it, associatedExamplesDir, false).second.entries.map { entry ->
val results = validateExamplesDir(it, associatedExamplesDir).second.entries.map { entry ->
entry.toPair()
}

Expand Down Expand Up @@ -331,38 +334,22 @@ For example:
}

private fun validateInlineExamples(feature: Feature): Map<String, Result> {
return ExamplesInteractiveServer.validateExamples(
return ExamplesInteractiveServer.validateInlineExamples(
feature,
examples = feature.stubsFromExamples.mapValues { (_, stub) ->
stub.map { (request, response) ->
ScenarioStub(request, response)
}
},
inline = true,
scenarioFilter = ExamplesInteractiveServer.ScenarioFilter(
filterName,
filterNotName,
filter,
filterNot
)
scenarioFilter = ExamplesInteractiveServer.ScenarioFilter(filterName, filterNotName, filter, filterNot)
)
}

private fun validateExternalExamples(
feature: Feature,
externalExamples: List<File>,
enableLogging: Boolean = true
): Map<String, Result> {
private fun validateExternalExamples(feature: Feature, externalExamples: List<File>): Map<String, Result> {
return ExamplesInteractiveServer.validateExamples(
feature,
examples = externalExamples,
scenarioFilter = ExamplesInteractiveServer.ScenarioFilter(
filterName,
filterNotName,
filter,
filterNot
),
enableLogging = enableLogging
scenarioFilter = ExamplesInteractiveServer.ScenarioFilter(filterName, filterNotName, filter, filterNot)
)
}

Expand Down
17 changes: 10 additions & 7 deletions core/src/main/kotlin/io/specmatic/conversions/ExampleFromFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package io.specmatic.conversions

import io.specmatic.core.*
import io.specmatic.core.examples.server.SchemaExample
import io.specmatic.core.examples.server.SchemaExample.Companion.SCHEMA_BASED
import io.specmatic.core.log.logger
import io.specmatic.core.pattern.*
import io.specmatic.core.utilities.URIUtils.parseQuery
Expand All @@ -15,6 +14,15 @@ import java.io.File
import java.net.URI

class ExampleFromFile(val json: JSONObjectValue, val file: File) {
companion object {
fun fromFile(file: File): ReturnValue<ExampleFromFile> {
if (SchemaExample.matchesFilePattern(file)) {
return HasFailure("Skipping file ${file.canonicalPath}, because it contains schema-based example")
}
return HasValue(ExampleFromFile(file))
}
}

fun toRow(specmaticConfig: SpecmaticConfig = SpecmaticConfig()): Row {
logger.log("Loading test file ${this.expectationFilePath}")

Expand Down Expand Up @@ -47,12 +55,7 @@ class ExampleFromFile(val json: JSONObjectValue, val file: File) {
).let { ExampleProcessor.resolveLookupIfPresent(it) }
}

constructor(file: File) : this(
json = if (SchemaExample.matchesFilePattern(file)) {
throw ContractException(breadCrumb = SCHEMA_BASED, errorMessage = "Skipping file ${file.canonicalPath}, because it contains schema-based example")
} else attempt("Error reading example file ${file.canonicalPath}") {parsedJSONObject(file.readText()) },
file = file
)
constructor(file: File) : this(json = attempt("Error reading example file ${file.canonicalPath}") { parsedJSONObject(file.readText()) }, file = file)

private fun JSONObjectValue.findByPath(path: String): Value? {
return findFirstChildByPath("partial.$path") ?: findFirstChildByPath(path)
Expand Down
Loading

0 comments on commit d745f64

Please sign in to comment.