From 3073b8f1c11228ad70166067fc4618e276090522 Mon Sep 17 00:00:00 2001 From: Maxim Tschumak Date: Fri, 24 Aug 2018 14:20:42 +0200 Subject: [PATCH] feat(server): migrate pascal case http headers rule to context object to support openapi 3 (#714) --- .../rule/zalando/PascalCaseHttpHeadersRule.kt | 29 +++---- .../java/de/zalando/zally/util/OpenApiUtil.kt | 6 +- .../zalando/PascalCaseHttpHeadersRuleTest.kt | 77 +++++++------------ 3 files changed, 42 insertions(+), 70 deletions(-) diff --git a/server/src/main/java/de/zalando/zally/rule/zalando/PascalCaseHttpHeadersRule.kt b/server/src/main/java/de/zalando/zally/rule/zalando/PascalCaseHttpHeadersRule.kt index f19a6956b..86fbe2bcf 100644 --- a/server/src/main/java/de/zalando/zally/rule/zalando/PascalCaseHttpHeadersRule.kt +++ b/server/src/main/java/de/zalando/zally/rule/zalando/PascalCaseHttpHeadersRule.kt @@ -1,31 +1,24 @@ package de.zalando.zally.rule.zalando -import com.typesafe.config.Config -import de.zalando.zally.rule.HttpHeadersRule import de.zalando.zally.rule.api.Check +import de.zalando.zally.rule.api.Context import de.zalando.zally.rule.api.Severity import de.zalando.zally.rule.api.Violation import de.zalando.zally.rule.api.Rule import de.zalando.zally.util.PatternUtil -import io.swagger.models.Swagger -import org.springframework.beans.factory.annotation.Autowired +import de.zalando.zally.util.getAllHeaders @Rule( - ruleSet = ZalandoRuleSet::class, - id = "132", - severity = Severity.SHOULD, - title = "Prefer Hyphenated-Pascal-Case for HTTP header fields" + ruleSet = ZalandoRuleSet::class, + id = "132", + severity = Severity.SHOULD, + title = "Prefer Hyphenated-Pascal-Case for HTTP header fields" ) -class PascalCaseHttpHeadersRule(@Autowired rulesConfig: Config) : HttpHeadersRule(rulesConfig) { +class PascalCaseHttpHeadersRule { @Check(severity = Severity.SHOULD) - override fun validate(swagger: Swagger): Violation? { - return super.validate(swagger) - } - - override fun isViolation(header: String) = !PatternUtil.isHyphenatedPascalCase(header) - - override fun createViolation(paths: List): Violation { - return Violation("Header is not Hyphenated-Pascal-Case", paths) - } + fun checkHttpHeaders(context: Context): List = + context.api.getAllHeaders() + .filterNot { PatternUtil.isHyphenatedPascalCase(it.name) } + .map { context.violation("Header has to be Hyphenated-Pascal-Case", it.element) } } diff --git a/server/src/main/java/de/zalando/zally/util/OpenApiUtil.kt b/server/src/main/java/de/zalando/zally/util/OpenApiUtil.kt index ad655a804..c73c34c65 100644 --- a/server/src/main/java/de/zalando/zally/util/OpenApiUtil.kt +++ b/server/src/main/java/de/zalando/zally/util/OpenApiUtil.kt @@ -22,7 +22,7 @@ fun OpenAPI.getAllHeaders(): Set { .map { HeaderElement(it.key, it.value) } .toSet() - val fromParams = components.parameters.orEmpty().values.extractHeaders() + val fromComponentsParams = components.parameters.orEmpty().values.extractHeaders() val fromPaths = paths.orEmpty().flatMap { (_, path) -> val fromPathParameters = path.parameters.extractHeaders() @@ -34,7 +34,9 @@ fun OpenAPI.getAllHeaders(): Set { fromPathParameters + fromOperations } - return fromParams + fromPaths + val fromComponentsHeaders = components.headers.orEmpty().map { HeaderElement(it.key, it.value) } + + return fromComponentsParams + fromPaths + fromComponentsHeaders } /** diff --git a/server/src/test/java/de/zalando/zally/rule/zalando/PascalCaseHttpHeadersRuleTest.kt b/server/src/test/java/de/zalando/zally/rule/zalando/PascalCaseHttpHeadersRuleTest.kt index a0e2c9154..a2738694d 100644 --- a/server/src/test/java/de/zalando/zally/rule/zalando/PascalCaseHttpHeadersRuleTest.kt +++ b/server/src/test/java/de/zalando/zally/rule/zalando/PascalCaseHttpHeadersRuleTest.kt @@ -1,68 +1,45 @@ package de.zalando.zally.rule.zalando -import de.zalando.zally.getFixture -import de.zalando.zally.swaggerWithHeaderParams -import de.zalando.zally.testConfig -import io.swagger.models.Swagger +import de.zalando.zally.getOpenApiContextFromContent import org.assertj.core.api.Assertions.assertThat +import org.intellij.lang.annotations.Language import org.junit.Test class PascalCaseHttpHeadersRuleTest { - private val rule = PascalCaseHttpHeadersRule(testConfig) + private val rule = PascalCaseHttpHeadersRule() @Test - fun simplePositiveCase() { - val swagger = swaggerWithHeaderParams("Right-Name") - assertThat(rule.validate(swagger)).isNull() - } + fun `checkHttpHeaders should return violation if not pascal case is used`() { + @Language("YAML") + val spec = """ + openapi: 3.0.1 + components: + headers: + not-pascal-case-header: {} + """.trimIndent() + val context = getOpenApiContextFromContent(spec) - @Test - fun simpleNegativeCase() { - val swagger = swaggerWithHeaderParams("kebap-case-name") - val result = rule.validate(swagger)!! - assertThat(result.paths).hasSameElementsAs(listOf("parameters kebap-case-name")) - } + val violations = rule.checkHttpHeaders(context) - @Test - fun mustAcceptETag() { - val swagger = swaggerWithHeaderParams("ETag") - assertThat(rule.validate(swagger)).isNull() + assertThat(violations).isNotEmpty + assertThat(violations[0].description).isEqualTo("Header has to be Hyphenated-Pascal-Case") + assertThat(violations[0].pointer.toString()).isEqualTo("/components/headers/not-pascal-case-header") } @Test - fun mustAcceptZalandoHeaders() { - val swagger = swaggerWithHeaderParams("X-Flow-ID", "X-UID", "X-Tenant-ID", "X-Sales-Channel", "X-Frontend-Type", - "X-Device-Type", "X-Device-OS", "X-App-Domain") - assertThat(rule.validate(swagger)).isNull() - } + fun `checkHttpHeaders should return no violation if all headers are pascal case`() { + @Language("YAML") + val spec = """ + openapi: 3.0.1 + components: + headers: + Hyphenated-Pascal-Case-Header: {} + """.trimIndent() + val context = getOpenApiContextFromContent(spec) - @Test - fun mustAcceptRateLimitHeaders() { - val swagger = swaggerWithHeaderParams("X-RateLimit-Limit", "X-RateLimit-Remaining", "X-RateLimit-Reset") - assertThat(rule.validate(swagger)).isNull() - } + val violations = rule.checkHttpHeaders(context) - @Test - fun mustAcceptDigits() { - val swagger = swaggerWithHeaderParams("X-P1n-Id") - assertThat(rule.validate(swagger)).isNull() - } - - @Test - fun emptySwaggerShouldPass() { - assertThat(rule.validate(Swagger())).isNull() - } - - @Test - fun positiveCaseSpp() { - val swagger = getFixture("api_spp.json") - assertThat(rule.validate(swagger)).isNull() - } - - @Test - fun positiveCaseTinbox() { - val swagger = getFixture("api_tinbox.yaml") - assertThat(rule.validate(swagger)).isNull() + assertThat(violations).isEmpty() } }