Skip to content

Commit

Permalink
feat(server): migrate pascal case http headers rule to context object…
Browse files Browse the repository at this point in the history
… to support openapi 3 (#714)
  • Loading branch information
maxim-tschumak committed Sep 5, 2018
1 parent 9138b05 commit 3073b8f
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 70 deletions.
@@ -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<String>): Violation {
return Violation("Header is not Hyphenated-Pascal-Case", paths)
}
fun checkHttpHeaders(context: Context): List<Violation> =
context.api.getAllHeaders()
.filterNot { PatternUtil.isHyphenatedPascalCase(it.name) }
.map { context.violation("Header has to be Hyphenated-Pascal-Case", it.element) }
}
6 changes: 4 additions & 2 deletions server/src/main/java/de/zalando/zally/util/OpenApiUtil.kt
Expand Up @@ -22,7 +22,7 @@ fun OpenAPI.getAllHeaders(): Set<HeaderElement> {
.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()
Expand All @@ -34,7 +34,9 @@ fun OpenAPI.getAllHeaders(): Set<HeaderElement> {
fromPathParameters + fromOperations
}

return fromParams + fromPaths
val fromComponentsHeaders = components.headers.orEmpty().map { HeaderElement(it.key, it.value) }

return fromComponentsParams + fromPaths + fromComponentsHeaders
}

/**
Expand Down
@@ -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()
}
}

0 comments on commit 3073b8f

Please sign in to comment.