Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: upgrade swagger dependencies (#1382) #1382

Merged
merged 1 commit into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions server/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import org.jetbrains.dokka.gradle.DokkaTask
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

plugins {
val kotlinVersion = "1.6.20"
val klintVersion = "10.2.1"
Expand All @@ -14,7 +19,8 @@ plugins {
jacoco
`maven-publish`
signing
id("com.github.ben-manes.versions") version "0.20.0"
eclipse
id("com.github.ben-manes.versions") version "0.42.0"
id("org.jetbrains.dokka") version "1.6.10" apply false

// We apply this so that ktlint can format the top level buildscript
Expand All @@ -40,6 +46,7 @@ subprojects {
apply(plugin = "maven-publish")
apply(plugin = "jacoco")
apply(plugin = "signing")
apply(plugin = "eclipse")

kapt {
includeCompileClasspath = false
Expand Down Expand Up @@ -155,15 +162,17 @@ subprojects {
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.yaml:snakeyaml:1.30")

testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.8.2")
testImplementation("com.jayway.jsonpath:json-path-assert:2.7.0")
testImplementation("org.mockito:mockito-core:2.28.2")
testImplementation("org.mockito:mockito-core:4.4.0")
}

jacoco {
toolVersion = "0.8.2"
toolVersion = "0.8.8"
}

tasks.test {
useJUnitPlatform()
finalizedBy(tasks.jacocoTestReport)
}

Expand All @@ -177,4 +186,10 @@ subprojects {
tasks.jar {
archiveBaseName.set(project.name)
}

eclipse {
project {
natures.add("org.jetbrains.kotlin.core.kotlinNature")
}
}
}
7 changes: 4 additions & 3 deletions server/zally-core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
dependencies {
kapt("com.google.auto.service:auto-service:1.0-rc6")
kapt("com.google.auto.service:auto-service:1.0.1")

api(project(":zally-rule-api"))
api("io.swagger.parser.v3:swagger-parser:2.0.26")
api("io.swagger.parser.v3:swagger-parser:2.0.32")
api("io.github.config4k:config4k:0.4.2")
implementation("com.google.auto.service:auto-service:1.0-rc6")
implementation("com.google.auto.service:auto-service:1.0.1")

testImplementation(project(":zally-test"))
testImplementation("org.junit.jupiter:junit-jupiter")
}
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class CaseChecker(
check: CaseCheck?
): List<Violation> = context.api
.getAllParameters()
.filter { type.toLowerCase() == it.`in` }
.filter { type.lowercase() == it.`in` }
.flatMap { param ->
check("$type parameter", "$type parameters", check, param.name)
?.let { context.violations(it, param) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.zalando.zally.core

import com.fasterxml.jackson.core.JsonPointer
import org.zalando.zally.rule.api.Context
import org.zalando.zally.rule.api.Violation

/**
* This validator validates a given OpenAPI definition based
Expand All @@ -14,13 +15,16 @@ class ContextRulesValidator(

override fun parse(content: String, authorization: String?): ContentParseResult<Context> {
// first try to parse an OpenAPI (version 3+)
return when (val parsedAsOpenApi = defaultContextFactory.parseOpenApiContext(content, authorization)) {
is ContentParseResult.NotApplicable ->
// if content was no OpenAPI, try to parse a Swagger (version 2)
defaultContextFactory.parseSwaggerContext(content)
else ->
parsedAsOpenApi
val parsedAsOpenApi = defaultContextFactory.parseOpenApiContext(content, authorization)
if (parsedAsOpenApi !is ContentParseResult.NotApplicable) {
return parsedAsOpenApi
}
// if content was no OpenAPI, try to parse a Swagger (version 2)
val parsedAsSwagger = defaultContextFactory.parseSwaggerContext(content)
if (parsedAsSwagger !is ContentParseResult.NotApplicable) {
return parsedAsSwagger
}
return ContentParseResult.ParsedWithErrors(listOf(Violation("No valid Open API specification", EMPTY_JSON_POINTER)))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how the violation is triggered on the failed parsing.

}

override fun ignore(root: Context, pointer: JsonPointer, ruleId: String) = root.isIgnored(pointer, ruleId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class JsonSchemaValidator(val schema: JsonNode, schemaRedirects: Map<String, Str
private fun toValidationMessage(processingMessage: ProcessingMessage): Violation {
val node = processingMessage.asJson()
val keyword = node.path("keyword").textValue()
val message = node.path("message").textValue().capitalize()
val message = node.path("message").textValue().replaceFirstChar({ it.uppercase() })
val pointer = node.at("/instance/pointer")?.textValue()?.toJsonPointer()
?: JsonPointer.empty()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class RulesManager(val config: Config, val rules: List<RuleDetails>) {

companion object {
fun fromClassLoader(config: Config) =
javaClass.classLoader
this::class.java.classLoader
.getResources("META-INF/services/${Rule::class.java.name}")
.asSequence()
.flatMap { it.readText().lineSequence() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ abstract class RulesValidator<RootT : Any>(val rules: RulesManager) : ApiValidat
parseResult.violations.map { violation ->
Result(
id = "InternalRuleSet",
url = URI.create("https://github.com/zalando/zally/blob/master/server/rules.md"),
title = "Unable to parse API specification",
url = URI.create("https://zalando.github.io/restful-api-guidelines/#101"),
title = "provide API specification using OpenAPI",
description = violation.description,
violationType = Severity.MUST,
pointer = violation.pointer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class ReverseAstBuilder<T : Any> internal constructor(root: T) {
val nextPath = m.name
.takeIf { it !in this.extensionMethodNames }
?.removePrefix("get")
?.decapitalize()
?.replaceFirstChar({ it.lowercase() })
tkrop marked this conversation as resolved.
Show resolved Hide resolved
?: ""

nodes.push(Node(value, pointer + nextPath.toEscapedJsonPointer(), marker))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.zalando.zally.core.ContentParseResultAssert.Companion.assertThat
import org.assertj.core.api.Assertions.assertThat
import org.intellij.lang.annotations.Language
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Disabled

class DefaultContextFactoryTest {

Expand All @@ -26,7 +27,74 @@ class DefaultContextFactoryTest {
}

@Test
fun `OPEN API -- openapi specification without info and paths succeeds with messages`() {
fun `OPEN API -- OpenAPI 3-1 is not applicable`() {
// The parsing results in no OpenAPI 3.1 object model until the latest
// parser is providing support. Than we can remove this test case and
// and enable the subsequent tests.
@Language("YAML")
val content = """
openapi: 3.1.0
"""
val result = defaultContextFactory.parseOpenApiContext(content)
assertThat(result).resultsInNotApplicable()
}

@Test
@Disabled("OpenAPI 3.1 is not supported by latest swagger parser yet")
fun `OPEN API -- OpenAPI 3-1 without info and paths succeeds with messages`() {
// The parsing results in a valid OpenAPI 3.1 object model, but
// with messages that `info` and `paths` are missing. Let the
// rules check that out.
@Language("YAML")
val content = """
openapi: 3.1.0
"""
val result = defaultContextFactory.parseOpenApiContext(content)
assertThat(result).resultsInSuccess()
val success = result as ContentParseResult.ParsedSuccessfully
assertThat(success.result.isOpenAPI3()).isTrue()
}

@Test
@Disabled("OpenAPI 3.1 is not supported by latest swagger parser yet")
fun `OPEN API -- OpenAPI 3-1 with oauth but without scopes succeeds`() {
@Language("YAML")
val content = """
openapi: 3.1.0
info:
title: Foo
version: 1.0.0
security:
- type: oauth2
flow: implicit
authorizationUrl: https://identity.some-server/auth
paths: {}
"""
val result = defaultContextFactory.parseOpenApiContext(content)
assertThat(result).resultsInSuccess()
val success = result as ContentParseResult.ParsedSuccessfully
assertThat(success.result.isOpenAPI3()).isTrue()
}

@Test
@Disabled("OpenAPI 3.1 is not supported by latest swagger parser yet")
fun `OPEN API -- OpenAPI 3-1 is recognised as an OpenAPI3 spec`() {
@Language("YAML")
val content = """
openapi: 3.1.0
info:
title: Foo
version: 1.0.0
paths: {}
"""
val result = defaultContextFactory.parseOpenApiContext(content)
assertThat(result).resultsInSuccess()
val success = result as ContentParseResult.ParsedSuccessfully
assertThat(success.result.isOpenAPI3()).isTrue()
}

@Test
fun `OPEN API -- OpenAPI 3-0-0 without info and paths succeeds`() {
// The parsing results in a valid OpenAPI 3 object model, but
// with messages that `info` and `paths` are missing. Let the
// rules check that out.
Expand All @@ -36,10 +104,57 @@ class DefaultContextFactoryTest {
"""
val result = defaultContextFactory.parseOpenApiContext(content)
assertThat(result).resultsInSuccess()
val success = result as ContentParseResult.ParsedSuccessfully
assertThat(success.result.isOpenAPI3()).isTrue()
}

@Test
fun `OPEN API -- OpenAPI 3-0-1 without info and paths succeeds`() {
// The parsing results in a valid OpenAPI 3 object model, but
// with messages that `info` and `paths` are missing. Let the
// rules check that out.
@Language("YAML")
val content = """
openapi: 3.0.1
"""
val result = defaultContextFactory.parseOpenApiContext(content)
assertThat(result).resultsInSuccess()
val success = result as ContentParseResult.ParsedSuccessfully
assertThat(success.result.isOpenAPI3()).isTrue()
}

@Test
fun `OPEN API -- OpenAPI 3-0-2 without info and paths succeeds`() {
// The parsing results in a valid OpenAPI 3 object model, but
// with messages that `info` and `paths` are missing. Let the
// rules check that out.
@Language("YAML")
val content = """
openapi: 3.0.2
"""
val result = defaultContextFactory.parseOpenApiContext(content)
assertThat(result).resultsInSuccess()
val success = result as ContentParseResult.ParsedSuccessfully
assertThat(success.result.isOpenAPI3()).isTrue()
}

@Test
fun `OPEN API -- OpenAPI 3-0-3 without info and paths succeeds`() {
// The parsing results in a valid OpenAPI 3 object model, but
// with messages that `info` and `paths` are missing. Let the
// rules check that out.
@Language("YAML")
val content = """
openapi: 3.0.3
"""
val result = defaultContextFactory.parseOpenApiContext(content)
assertThat(result).resultsInSuccess()
val success = result as ContentParseResult.ParsedSuccessfully
assertThat(success.result.isOpenAPI3()).isTrue()
}

@Test
fun `OPEN API -- oauth without scopes succeeds`() {
fun `OPEN API -- OpenAPI 3-0-x with oauth but without scopes succeeds`() {
@Language("YAML")
val content = """
openapi: 3.0.0
Expand All @@ -54,10 +169,12 @@ class DefaultContextFactoryTest {
"""
val result = defaultContextFactory.parseOpenApiContext(content)
assertThat(result).resultsInSuccess()
val success = result as ContentParseResult.ParsedSuccessfully
assertThat(success.result.isOpenAPI3()).isTrue()
}

@Test
fun `OPEN API -- OpenAPI is recognised as an OpenAPI3 spec`() {
fun `OPEN API -- OpenAPI 3-0-x is recognised as an OpenAPI3 spec`() {
@Language("YAML")
val content = """
openapi: 3.0.0
Expand All @@ -73,7 +190,7 @@ class DefaultContextFactoryTest {
}

@Test
fun `OPEN API -- does not recognize a Swagger file`() {
fun `OPEN API -- OpenAPI 2-0 is not recognize as OpenAPI3 spec`() {
@Language("YAML")
val content = """
swagger: '2.0'
Expand Down Expand Up @@ -103,7 +220,17 @@ class DefaultContextFactoryTest {
}

@Test
fun `SWAGGER -- error when info and path objects are missing`() {
fun `SWAGGER -- OpenAPI 1-0 without info and path objects succeeds`() {
@Language("YAML")
val content = """
swagger: 1.0
"""
val result = defaultContextFactory.parseSwaggerContext(content)
assertThat(result).resultsInSuccess()
}

@Test
fun `SWAGGER -- OpenAPI 2-0 without info and path objects succeeds`() {
@Language("YAML")
val content = """
swagger: 2.0
Expand All @@ -113,7 +240,7 @@ class DefaultContextFactoryTest {
}

@Test
fun `SWAGGER -- error when securityDefinition type is missing`() {
fun `SWAGGER -- OpenAPI 2-0 without security definition type succeeds`() {
@Language("YAML")
val content = """
swagger: 2.0
Expand All @@ -129,7 +256,7 @@ class DefaultContextFactoryTest {
}

@Test
fun `SWAGGER -- error when oauth elements are missing`() {
fun `SWAGGER -- OpenAPI 2-0 without oauth elements succeeds`() {
// Specific case where converting from Swagger to OpenAPI 3 (using the `Context`
// object) would throw an exception. New behaviour tested here: the returned `Context`
// is null because the file was not parsed (convertible, here).
Expand All @@ -151,7 +278,7 @@ class DefaultContextFactoryTest {
}

@Test
fun `SWAGGER -- minimal Swagger API is not recognized as an OpenAPI3 spec`() {
fun `SWAGGER -- OpenAPI 2-0 is not recognized as an OpenAPI3 spec`() {
@Language("YAML")
val content = """
swagger: 2.0
Expand All @@ -167,7 +294,7 @@ class DefaultContextFactoryTest {
}

@Test
fun `SWAGGER -- recursive-model-extension`() {
fun `SWAGGER -- OpenAPI 2-0 with recursive-model-extension succeeds`() {
@Language("YAML")
val content = """
swagger: '2.0'
Expand Down Expand Up @@ -215,6 +342,7 @@ class DefaultContextFactoryTest {
// This Swagger, after being converted, causes the `components` property to exist (not
// null), but having a null `schemas`, which causes the NPE.
val ref = "\$ref"

@Language("YAML")
val content = """
swagger: '2.0'
Expand Down
Loading