Skip to content

Commit

Permalink
Add tests to Language class (QubitPi#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
QubitPi authored Nov 17, 2024
1 parent aac89a2 commit a4e8730
Show file tree
Hide file tree
Showing 3 changed files with 253 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ dashboard.
### Gateway Registration

```bash
export GATEWAY_PUBLIC_IP=52.53.186.26
export GATEWAY_PUBLIC_IP=<gateway IP>

# vocabulary paged & count
curl -v -i -s -k -X POST https://api.paion-data.dev:8444/services \
Expand Down
87 changes: 87 additions & 0 deletions src/test/groovy/org/qubitpi/wilhelm/LanguageSpec.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright Jiaqi Liu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.qubitpi.wilhelm

import spock.lang.Specification

import java.util.stream.Collectors

class LanguageSpec extends Specification {

def 'There are 3 valid languages'() {
expect:
Language.values().size() == 3
}

def "Only certain languages are supported"() {
given: "all restricted languages"
List<String> allValidDatabaseNames = ["German", "Ancient Greek", "Latin"]
List<String> allValidPathNames = ["german", "ancientGreek", "latin"]

expect: "no other database name is allowed"
allValidDatabaseNames.containsAll(
Arrays.stream(Language.values()).map {it -> it.databaseName}.collect(Collectors.toList())
)

and: "no other API path name is allowed"
allValidPathNames.containsAll(Arrays.stream(Language.values()).map {it -> it.pathName}.collect(Collectors.toList()))
}

def "'#databaseName' can be converted to object"() {
when: "a supported database name is being converted to a Language object"
Language.ofDatabaseName(databaseName)

then: "no error occurs"
noExceptionThrown()

where:
_ | databaseName
_ | "German"
_ | "Ancient Greek"
_ | "Latin"
}

def "'#pathName' can be converted to object"() {
when: "a supported API language name is being converted to a Language object"
Language.ofClientValue(pathName)

then: "no error occurs"
noExceptionThrown()

where:
_ | pathName
_ | "german"
_ | "ancientGreek"
_ | "latin"
}

@SuppressWarnings('GroovyAccessibility')
def "Invalid language cannot construct the object"() {
when: "invalid database name is used to construct the object"
Language.valueOf("foo", (language) -> language.getDatabaseName())

then: "error occurs"
Exception exception = thrown(IllegalArgumentException)
exception.message == "'foo' is not a recognized language. Acceptable ones are German, Ancient Greek, Latin"

when: "invalid API path name is used to construct the object"
Language.valueOf("foo", (language) -> language.getPathName())

then: "error occurs"
exception = thrown(IllegalArgumentException)
exception.message == "'foo' is not a recognized language. Acceptable ones are german, ancientGreek, latin"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* Copyright Jiaqi Liu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.qubitpi.wilhelm.web.filters

import jakarta.ws.rs.container.ContainerRequestContext
import jakarta.ws.rs.container.ContainerResponseContext
import jakarta.ws.rs.core.MultivaluedHashMap
import jakarta.ws.rs.core.MultivaluedMap
import jakarta.ws.rs.core.Response
import spock.lang.Specification
import spock.lang.Unroll

class LanguageCheckFilterSpec extends Specification {

def "When a request #beingPreflight preflight, request #beingAborted aborted"() {
setup: "a request is being configure for being preflight or not"
ContainerRequestContext request = Mock(ContainerRequestContext)

if (isPreflight) {
request.getHeaderString("Origin") >> "some origin"
request.getMethod() >> "OPTIONS"
} else {
request.getHeaderString("Origin") >> null
request.getMethod() >> "POST"
}

when: "the request is pre-matched by CORS filter"
new CorsFilter().filter(request)

then: "preflight request is bounced back and non-preflight request is accepted"
(isPreflight ? 1 : 0) * request.abortWith(_ as Response)

where:
_ | isPreflight
_ | true
_ | false

beingPreflight = isPreflight ? "is" : "is not"
beingAborted = isPreflight ? "is" : "is not"
}

@Unroll
def "When a request #beingCrossOrigin cross-origin and #beingPreflight preflight, response headers are #expectedResponseHeaders"() {
setup: "a request is being configure for being cross-origin/preflight or not"
ContainerRequestContext request = Mock(ContainerRequestContext)
ContainerResponseContext response = Mock(ContainerResponseContext)

if (isCrossOrigin) {
request.getHeaderString("Origin") >>> ["some origin"]
} else {
request.getHeaderString("Origin") >>> [null]
}

if (isPreflight) {
request.getHeaderString("Origin") >>> ["some origin"]
request.getMethod() >> "OPTIONS"
} else {
request.getHeaderString("Origin") >>> [null]
request.getMethod() >> "POST"
}

MultivaluedMap headers = new MultivaluedHashMap()
response.getHeaders() >>> [headers, headers, headers, headers]

when: "a response is being processed by CORS filter"
new CorsFilter().filter(request, response)

then: "the response header gets populated based on cross-origin/preflight nature of the configured request"
response.getHeaders() == expectedResponseHeaders

where:
isCrossOrigin | isPreflight || expectedResponseHeaders
false | false || [:]
false | true || [:]
true | false || accessControlAllowOrigin()
true | true || accessControlAllowHeaders() << accessControlAllowCredentials() << accessControlAllowMethods() << accessControlAllowOrigin()

beingCrossOrigin = isCrossOrigin ? "is" : "is not"
beingPreflight = isPreflight ? "is" : "is not"
}

@SuppressWarnings('GroovyAccessibility')
def "When a request #contains 'Origin' header, it #is a cross origin request"() {
given:
ContainerRequestContext request = Mock(ContainerRequestContext)

if (isCorssOrigin) {
request.getHeaderString("Origin") >> "some origin"
} else {
request.getHeaderString("Origin") >> null
}

expect:
CorsFilter.isCrossOriginRequest(request) == isCorssOrigin

where:
_ || isCorssOrigin
_ || true
_ || false

contains = isCorssOrigin ? "contains" : "does not contain"
is = isCorssOrigin ? "is" : "is not"
}

@SuppressWarnings('GroovyAccessibility')
def "When a request #containsOrigin 'Origin' header and method #isOptions 'OPTIONS', it #is a preflight request"() {
given:
ContainerRequestContext request = Mock(ContainerRequestContext)

if (isCorssOrigin) {
request.getHeaderString("Origin") >> "some origin"
} else {
request.getHeaderString("Origin") >> null
}

if (methodIsOptions) {
request.getMethod() >> "OPTIONS"
} else {
request.getMethod() >> "POST"
}

expect:
CorsFilter.isPreflightRequest(request) == isPreflight

where:
isCorssOrigin | methodIsOptions || isPreflight
false | false || false
false | true || false
true | false || false
true | true || true

containsOrigin = isCorssOrigin ? "contains" : "does not contain"
isOptions = isCorssOrigin ? "is" : "is not"
is = isPreflight ? "is" : "is not"
}

static def accessControlAllowHeaders() {
["Access-Control-Allow-Headers": ["CSRF-Token, X-Requested-By, Authorization, Content-Type"]]
}

static def accessControlAllowCredentials() {
["Access-Control-Allow-Credentials": ["true"]]
}

static def accessControlAllowMethods() {
["Access-Control-Allow-Methods": ["GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH"]]
}

static def accessControlAllowOrigin() {
["Access-Control-Allow-Origin": ["*"]]
}
}

0 comments on commit a4e8730

Please sign in to comment.