Skip to content
Snippets Groups Projects
Commit 661e536c authored by Martin Lowe's avatar Martin Lowe :flag_ca:
Browse files

Further upgrade, add tests, update openapi + docs

parent 154cc4eb
No related branches found
No related tags found
1 merge request!21Upgrade to Quarkus 2.6.3, use of common lib
Showing
with 174 additions and 136 deletions
/*
* Copyright (C) 2019 Eclipse Foundation and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.geoip.client.model;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
/**
* Represents an error with a message to be returned with non-200 responses.
* This class is used in place of string entities to simplify returns for JSON
* objects.
*
* @author Martin Lowe
*/
public class Error {
private int statusCode;
private String message;
private String url;
/**
* Creates an error object using the JAX-RS status to fetch the status code.
*
* @param status the JAX-RS status for the error.
* @param message the message to return
*/
public Error(Status status, String message) {
this.statusCode = status.getStatusCode();
this.message = message;
}
/**
* Returns a response object given the fields within as the contents.
*
* @return a JAX-RS Response with the given status code, with this object as the
* message.
*/
public Response asResponse() {
return Response.status(statusCode).entity(this).build();
}
/**
* @return the statusCode
*/
public int getStatusCode() {
return statusCode;
}
/**
* @return the message
*/
public String getMessage() {
return message;
}
/**
* @return the url
*/
public String getUrl() {
return url;
}
}
...@@ -19,8 +19,8 @@ import javax.ws.rs.core.Response.Status; ...@@ -19,8 +19,8 @@ import javax.ws.rs.core.Response.Status;
import com.maxmind.geoip2.record.City; import com.maxmind.geoip2.record.City;
import org.eclipsefoundation.core.model.Error;
import org.eclipsefoundation.geoip.client.helper.InetAddressHelper; import org.eclipsefoundation.geoip.client.helper.InetAddressHelper;
import org.eclipsefoundation.geoip.client.model.Error;
import org.eclipsefoundation.geoip.client.service.GeoIPService; import org.eclipsefoundation.geoip.client.service.GeoIPService;
/** /**
......
...@@ -19,8 +19,8 @@ import javax.ws.rs.core.Response.Status; ...@@ -19,8 +19,8 @@ import javax.ws.rs.core.Response.Status;
import com.maxmind.geoip2.record.Country; import com.maxmind.geoip2.record.Country;
import org.eclipsefoundation.core.model.Error;
import org.eclipsefoundation.geoip.client.helper.InetAddressHelper; import org.eclipsefoundation.geoip.client.helper.InetAddressHelper;
import org.eclipsefoundation.geoip.client.model.Error;
import org.eclipsefoundation.geoip.client.service.GeoIPService; import org.eclipsefoundation.geoip.client.service.GeoIPService;
/** /**
......
/**
* Copyright (c) 2021 Eclipse
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipsefoundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
const toJsonSchema = require('@openapi-contrib/openapi-schema-to-json-schema');
const Resolver = require('@stoplight/json-ref-resolver');
const yaml = require('js-yaml');
const fs = require('fs');
const decamelize = require('decamelize');
const args = require('yargs')
.option('s', {
alias: 'src',
desc: 'The fully qualified path to the YAML spec.',
})
.option('t', {
alias: 'target',
desc: 'The fully qualified path to write the JSON schema to',
}).argv;
if (!args.s || !args.t) {
process.exit(1);
}
run();
/**
* Generates JSON schema files for consumption of the Java tests.
*/
async function run() {
try {
// load in the openapi yaml spec as an object
const doc = yaml.load(fs.readFileSync(args.s, 'utf8'));
// resolve $refs in openapi spec
let resolvedInp = await new Resolver.Resolver().resolve(doc);
const out = toJsonSchema(resolvedInp.result);
// if folder doesn't exist, create it
if (!fs.existsSync(`${args.t}/schemas`)) {
fs.mkdirSync(`${args.t}/schemas`);
}
// for each of the schemas, generate a JSON schema file
for (let schemaName in out.components.schemas) {
fs.writeFileSync(`${args.t}/schemas/${decamelize(schemaName, { separator: '-' })}-schema.json`, JSON.stringify(out.components.schemas[schemaName]));
}
} catch (e) {
console.log(e);
}
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Refresh" content="7; url=//api.eclipse.org" />
</head>
<body>
<p>Please follow <a href="//api.eclipse.org/">this link</a>.</p>
</body>
</html>
\ No newline at end of file
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
package org.eclipsefoundation.geoip.client.resources; package org.eclipsefoundation.geoip.client.resources;
import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.given;
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
import org.eclipsefoundation.geoip.client.test.namespaces.SchemaNamespaceHelper;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.QuarkusTest;
...@@ -19,39 +21,53 @@ import io.quarkus.test.junit.QuarkusTest; ...@@ -19,39 +21,53 @@ import io.quarkus.test.junit.QuarkusTest;
* @author Martin Lowe * @author Martin Lowe
*/ */
@QuarkusTest @QuarkusTest
public class CityResourceTest { class CityResourceTest {
public static final String CITIES_ENDPOINT_URL = "/cities/{ipAddr}";
// Toronto IP address range // Toronto IP address range
private static final String VALID_IPV4_ADDRESS = "72.137.192.0"; private static final String VALID_IPV4_ADDRESS = "72.137.192.0";
// Google IE server address // Google IE server address
private static final String VALID_IPV6_ADDRESS = "2a00:1450:400a:804::2004"; private static final String VALID_IPV6_ADDRESS = "2a00:1450:400a:804::2004";
@Test
void testCities_success() {
given().when().get(CITIES_ENDPOINT_URL, VALID_IPV4_ADDRESS).then().statusCode(200);
given().when().get(CITIES_ENDPOINT_URL, VALID_IPV6_ADDRESS).then().statusCode(200);
}
@Test @Test
public void testCityIPEndpoint() { void testCities_format() {
given().when().get("/cities/"+VALID_IPV4_ADDRESS).then().statusCode(200); given().when().get(CITIES_ENDPOINT_URL, VALID_IPV4_ADDRESS).then().assertThat()
given().when().get("/cities/"+VALID_IPV6_ADDRESS).then().statusCode(200); .body(matchesJsonSchemaInClasspath(SchemaNamespaceHelper.CITY_SCHEMA_PATH));
given().when().get(CITIES_ENDPOINT_URL, VALID_IPV6_ADDRESS).then().assertThat()
.body(matchesJsonSchemaInClasspath(SchemaNamespaceHelper.CITY_SCHEMA_PATH));
} }
@Test @Test
public void testCityBadIPEndpoint() { void testCity_badIPEndpoint() {
// IPv4 tests // IPv4 tests
given().when().get("/cities/bad.ip.add.res").then().statusCode(400); given().when().get(CITIES_ENDPOINT_URL, "bad.ip.add.res").then().statusCode(400);
given().when().get("/cities/300.0.0.0").then().statusCode(400); given().when().get(CITIES_ENDPOINT_URL, "300.0.0.0").then().statusCode(400);
given().when().get("/cities/1.300.0.0").then().statusCode(400); given().when().get(CITIES_ENDPOINT_URL, "1.300.0.0").then().statusCode(400);
given().when().get("/cities/1.0.300.0").then().statusCode(400); given().when().get(CITIES_ENDPOINT_URL, "1.0.300.0").then().statusCode(400);
given().when().get("/cities/1.0.0.300").then().statusCode(400); given().when().get(CITIES_ENDPOINT_URL, "1.0.0.300").then().statusCode(400);
given().when().get("/cities/sample").then().statusCode(400); given().when().get(CITIES_ENDPOINT_URL, "sample").then().statusCode(400);
given().when().get("/cities/"+VALID_IPV4_ADDRESS+":8080").then().statusCode(400); given().when().get(CITIES_ENDPOINT_URL, VALID_IPV4_ADDRESS + ":8080").then().statusCode(400);
// seems to be an issue with Google Guava code, only gets detected by MaxMind // seems to be an issue with Google Guava code, only gets detected by MaxMind
given().when().get("/cities/0.1.1.1").then().statusCode(500); given().when().get(CITIES_ENDPOINT_URL, "0.1.1.1").then().statusCode(500);
// loopback + unspecified address
given().when().get("/cities/127.0.0.1").then().statusCode(400);
given().when().get("/cities/0.0.0.0").then().statusCode(400);
// IPv6 tests // IPv6 tests
given().when().get("/cities/bad:ip:add::res").then().statusCode(400); given().when().get(CITIES_ENDPOINT_URL, "bad:ip:add::res").then().statusCode(400);
}
@Test
void testCities_loopback() {
// loopback + unspecified address
given().when().get(CITIES_ENDPOINT_URL, "127.0.0.1").then().statusCode(400);
given().when().get(CITIES_ENDPOINT_URL, "0.0.0.0").then().statusCode(400);
// loopback + unspecified address // loopback + unspecified address
given().when().get("/cities/::").then().statusCode(400); given().when().get(CITIES_ENDPOINT_URL, "::").then().statusCode(400);
given().when().get("/cities/::1").then().statusCode(400); given().when().get(CITIES_ENDPOINT_URL, "::1").then().statusCode(400);
} }
} }
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
package org.eclipsefoundation.geoip.client.resources; package org.eclipsefoundation.geoip.client.resources;
import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.given;
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
import org.eclipsefoundation.geoip.client.test.namespaces.SchemaNamespaceHelper;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.QuarkusTest;
...@@ -21,37 +23,58 @@ import io.quarkus.test.junit.QuarkusTest; ...@@ -21,37 +23,58 @@ import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest @QuarkusTest
public class CountryResourceTest { public class CountryResourceTest {
public static final String COUNTRY_ENDPOINT_URL = "/countries/{ipAddr}";
// Toronto IP address range // Toronto IP address range
private static final String VALID_IPV4_ADDRESS = "72.137.192.0"; private static final String VALID_IPV4_ADDRESS = "72.137.192.0";
// Google IE server address // Google IE server address
private static final String VALID_IPV6_ADDRESS = "2a00:1450:400a:804::2004"; private static final String VALID_IPV6_ADDRESS = "2a00:1450:400a:804::2004";
@Test
public void testCountries_success() {
given().when().get(COUNTRY_ENDPOINT_URL, VALID_IPV4_ADDRESS).then().statusCode(200);
given().when().get(COUNTRY_ENDPOINT_URL, VALID_IPV6_ADDRESS).then().statusCode(200);
}
@Test @Test
public void testCityIPEndpoint() { void testCountries_format() {
given().when().get("/countries/"+VALID_IPV4_ADDRESS).then().statusCode(200); given().when().get(COUNTRY_ENDPOINT_URL, VALID_IPV4_ADDRESS).then().assertThat()
given().when().get("/countries/"+VALID_IPV6_ADDRESS).then().statusCode(200); .body(matchesJsonSchemaInClasspath(SchemaNamespaceHelper.COUNTRY_SCHEMA_PATH));
given().when().get(COUNTRY_ENDPOINT_URL, VALID_IPV6_ADDRESS).then().assertThat()
.body(matchesJsonSchemaInClasspath(SchemaNamespaceHelper.COUNTRY_SCHEMA_PATH));
} }
@Test @Test
public void testCityBadIPEndpoint() { public void testCountries_badIPEndpoint() {
// IPv4 tests // IPv4 tests
given().when().get("/countries/bad.ip.add.res").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "bad.ip.add.res").then().statusCode(400);
given().when().get("/countries/300.0.0.0").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "300.0.0.0").then().statusCode(400);
given().when().get("/countries/1.300.0.0").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "1.300.0.0").then().statusCode(400);
given().when().get("/countries/1.0.300.0").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "1.0.300.0").then().statusCode(400);
given().when().get("/countries/1.0.0.300").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "1.0.0.300").then().statusCode(400);
given().when().get("/countries/sample").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "sample").then().statusCode(400);
given().when().get("/countries/"+VALID_IPV4_ADDRESS+":8080").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, VALID_IPV4_ADDRESS + ":8080").then().statusCode(400);
// seems to be an issue with Google Guava code, only gets detected by MaxMind // seems to be an issue with Google Guava code, only gets detected by MaxMind
given().when().get("/countries/0.1.1.1").then().statusCode(500); given().when().get(COUNTRY_ENDPOINT_URL, "0.1.1.1").then().statusCode(500);
// loopback + unspecified address // loopback + unspecified address
given().when().get("/countries/127.0.0.1").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "127.0.0.1").then().statusCode(400);
given().when().get("/countries/0.0.0.0").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "0.0.0.0").then().statusCode(400);
// IPv6 tests // IPv6 tests
given().when().get("/countries/bad:ip:add::res").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "bad:ip:add::res").then().statusCode(400);
// loopback + unspecified address
given().when().get(COUNTRY_ENDPOINT_URL, "::").then().statusCode(400);
given().when().get(COUNTRY_ENDPOINT_URL, "::1").then().statusCode(400);
}
@Test
void testCountries_loopback() {
// loopback + unspecified address
given().when().get(COUNTRY_ENDPOINT_URL, "127.0.0.1").then().statusCode(400);
given().when().get(COUNTRY_ENDPOINT_URL, "0.0.0.0").then().statusCode(400);
// loopback + unspecified address // loopback + unspecified address
given().when().get("/countries/::").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "::").then().statusCode(400);
given().when().get("/countries/::1").then().statusCode(400); given().when().get(COUNTRY_ENDPOINT_URL, "::1").then().statusCode(400);
} }
} }
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
package org.eclipsefoundation.geoip.client.resources; package org.eclipsefoundation.geoip.client.resources;
import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.given;
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
import org.eclipsefoundation.geoip.client.test.namespaces.SchemaNamespaceHelper;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.QuarkusTest;
...@@ -21,29 +23,37 @@ import io.quarkus.test.junit.QuarkusTest; ...@@ -21,29 +23,37 @@ import io.quarkus.test.junit.QuarkusTest;
*/ */
@QuarkusTest @QuarkusTest
public class SubnetResourceTest { public class SubnetResourceTest {
public static final String SUBNETS_ENDPOINT_URL = "/subnets/{subnet}/{locale}";
@Test @Test
public void testSubnetsEndpoint() { public void testSubnets_success() {
given().when().get("/subnets/ipv4/ca").then().statusCode(200); given().when().get(SUBNETS_ENDPOINT_URL, "ipv4", "ca").then().statusCode(200);
given().when().get("/subnets/ipv6/ca").then().statusCode(200); given().when().get(SUBNETS_ENDPOINT_URL, "ipv6", "ca").then().statusCode(200);
}
@Test
void testCities_format() {
given().when().get(SUBNETS_ENDPOINT_URL, "ipv4", "ca").then().assertThat()
.body(matchesJsonSchemaInClasspath(SchemaNamespaceHelper.IP_ADDRESSES_SCHEMA_PATH));
given().when().get(SUBNETS_ENDPOINT_URL, "ipv6", "ca").then().assertThat()
.body(matchesJsonSchemaInClasspath(SchemaNamespaceHelper.IP_ADDRESSES_SCHEMA_PATH));
} }
@Test @Test
public void testSubnetsBadLocaleEndpoint() { public void testSubnetsBadLocaleEndpoint() {
// bad ipv4 calls // bad ipv4 calls
given().when().get("/subnets/ipv4/").then().statusCode(500); given().when().get(SUBNETS_ENDPOINT_URL, "ipv4", "").then().statusCode(400);
given().when().get("/subnets/ipv4/can").then().statusCode(500); given().when().get(SUBNETS_ENDPOINT_URL, "ipv4", "can").then().statusCode(400);
given().when().get("/subnets/ipv4/01").then().statusCode(500); given().when().get(SUBNETS_ENDPOINT_URL, "ipv4", "01").then().statusCode(400);
// bad ipv6 calls // bad ipv6 calls
given().when().get("/subnets/ipv6/").then().statusCode(500); given().when().get(SUBNETS_ENDPOINT_URL, "ipv6", "").then().statusCode(400);
given().when().get("/subnets/ipv6/can").then().statusCode(500); given().when().get(SUBNETS_ENDPOINT_URL, "ipv6", "can").then().statusCode(400);
given().when().get("/subnets/ipv6/01").then().statusCode(500); given().when().get(SUBNETS_ENDPOINT_URL, "ipv6", "01").then().statusCode(400);
// check other permutations (regex endpoint) // check other permutations (regex endpoint)
given().when().get("/subnets/ipv5/ca").then().statusCode(500); given().when().get(SUBNETS_ENDPOINT_URL, "ipv5", "ca").then().statusCode(400);
given().when().get("/subnets/ipvfour/ca").then().statusCode(500); given().when().get(SUBNETS_ENDPOINT_URL, "ipvfour", "ca").then().statusCode(400);
given().when().get("/subnets/ipv/ca").then().statusCode(500); given().when().get(SUBNETS_ENDPOINT_URL, "ipv", "ca").then().statusCode(400);
} }
} }
package org.eclipsefoundation.geoip.client.test.namespaces;
public class SchemaNamespaceHelper {
public static final String BASE_SCHEMAS_PATH = "schemas/";
public static final String BASE_SCHEMAS_PATH_SUFFIX = "-schema.json";
public static final String CITY_SCHEMA_PATH = BASE_SCHEMAS_PATH + "city"
+ BASE_SCHEMAS_PATH_SUFFIX;
public static final String COUNTRY_SCHEMA_PATH = BASE_SCHEMAS_PATH + "country"
+ BASE_SCHEMAS_PATH_SUFFIX;
public static final String IP_ADDRESSES_SCHEMA_PATH = BASE_SCHEMAS_PATH + "ip-addresses"
+ BASE_SCHEMAS_PATH_SUFFIX;
}
# Configuration file # Configuration file
quarkus.http.port=8080 quarkus.http.port=8080
eclipse.subnet.ipv4.path=/tmp/maxmind/db/GeoLite2-Country-Blocks-IPv4.csv eclipse.maxmind.root=/tmp/maxmind
eclipse.subnet.ipv6.path=/tmp/maxmind/db/GeoLite2-Country-Blocks-IPv6.csv eclipse.subnet.ipv4.path=${eclipse.maxmind.root}/db/GeoLite2-Country-Blocks-IPv4.csv
eclipse.subnet.countries.path=/tmp/maxmind/db/GeoLite2-Country-Locations-en.csv eclipse.subnet.ipv6.path=${eclipse.maxmind.root}/db/GeoLite2-Country-Blocks-IPv6.csv
eclipse.subnet.countries.path=${eclipse.maxmind.root}/db/GeoLite2-Country-Locations-en.csv
maxmind.database.root=/tmp/maxmind/bin maxmind.database.root=${eclipse.maxmind.root}/bin
maxmind.database.country.file=GeoLite2-Country.mmdb maxmind.database.country.file=GeoLite2-Country.mmdb
maxmind.database.city.file=GeoLite2-City.mmdb maxmind.database.city.file=GeoLite2-City.mmdb
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment