Skip to content

Commit

Permalink
Merge pull request #1817 from weather-gov/jt/api-interop-test-alert-g…
Browse files Browse the repository at this point in the history
…eometries

API interop tests: alert geometries
  • Loading branch information
jamestranovich-noaa committed Sep 26, 2024
2 parents 9a65274 + ab92b77 commit 6f9db40
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 216 deletions.
144 changes: 0 additions & 144 deletions api-interop-layer/_tests_to_copy/Test/AlertUtilityGeometry.php.test

This file was deleted.

72 changes: 72 additions & 0 deletions api-interop-layer/data/alerts/geometry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const unwindGeometryCollection = (geojson, parentIsCollection = false) => {
if (geojson.type === "GeometryCollection") {
const geometries = geojson.geometries.flatMap((geometry) =>
unwindGeometryCollection(geometry, true),
);
if (parentIsCollection) {
return geometries;
}

geojson.geometries = geometries;
return geojson;
}

return geojson;
};

export const generateAlertGeometry = async (db, rawAlert) => {
// if the alert already has geometry, nothing to do
if (rawAlert.geometry) {
return unwindGeometryCollection(rawAlert.geometry);
}

// if we have affected zones, generate a geometry from zones
const zones = rawAlert.properties.affectedZones;
if (Array.isArray(zones) && zones.length > 0) {
const sql = `
SELECT ST_ASGEOJSON(
ST_SIMPLIFY(
ST_SRID(
ST_COLLECT(shape),
0
),
0.003
)
)
AS shape
FROM weathergov_geo_zones
WHERE id IN (${zones.map(() => "?").join(",")})`;
const [{ shape }] = await db.query(sql, zones);
if (shape) {
return unwindGeometryCollection(shape);
}
}

// if all geocodes are the same, generate a geometry from geocodes
const counties = rawAlert.properties.geocode?.SAME;
if (Array.isArray(counties) && counties.length > 0) {
const sql = `
SELECT ST_ASGEOJSON(
ST_SIMPLIFY(
ST_SRID(
ST_COLLECT(shape),
0
),
0.003
)
)
AS shape
FROM weathergov_geo_counties
WHERE countyFips IN (${counties.map((c) => `'${c.slice(1)}'`).join(",")})`;
const [{ shape }] = await db.query(sql);

if (shape) {
return unwindGeometryCollection(shape);
}
}

// we cannot generate a geometry.
return null;
}

export default { generateAlertGeometry };
100 changes: 100 additions & 0 deletions api-interop-layer/data/alerts/geometry.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import sinon from "sinon";
import { expect } from "chai";
import * as mariadb from "mariadb";
import { generateAlertGeometry } from "./geometry.js";

describe("alert geometries", () => {
const sandbox = sinon.createSandbox();
const db = {
query: sandbox.stub(),
end: () => Promise.resolve(),
};

// Do this before everything, so it'll happen before any describe blocks run,
// otherwise the connection creation won't be stubbed when the script is first
// imported below.
before(() => {
mariadb.default.createConnection.resolves(db);
});

beforeEach(() => {
sandbox.resetBehavior();
sandbox.resetHistory();
});

it("returns an alert with a geometry as-is", async () => {
const rawAlert = {
geometry: "existing geometry",
};

const geometry = await generateAlertGeometry(db, rawAlert);
expect(geometry).to.equal("existing geometry");
});

it("autogenerates a geometry from affected zones", async () => {
const affectedZones = ["zone 1", "zone 2", "zone 3"];
const rawAlert = {
geometry: false,
properties: {
affectedZones,
},
};
const query = `SELECT ST_ASGEOJSON(
ST_SIMPLIFY(
ST_SRID(
ST_COLLECT(shape),
0
),
0.003
)
)
AS shape
FROM weathergov_geo_zones
WHERE id IN (?,?,?)`;
db.query.withArgs(sinon.match(query), sinon.match.same(affectedZones))
.resolves([{ shape: { combined: "zones" } }]);

const geometry = await generateAlertGeometry(db, rawAlert);
expect(geometry).to.eql({ combined: "zones" });
});

it("autogenerates a geometry from same geocodes if no zones are present", async () => {
const rawAlert = {
geometry: false,
properties: {
geocode: {
// SAME code is FIPS code with a leading zero. The leading
// zero gets stripped out, so we need to include it here
// so we get what we expect later.
"SAME": ["0county 1", "0county 2", "0county 3"],
},
},
};
const query = `SELECT ST_ASGEOJSON(
ST_SIMPLIFY(
ST_SRID(
ST_COLLECT(shape),
0
),
0.003
)
)
AS shape
FROM weathergov_geo_counties
WHERE countyFips IN ('county 1','county 2','county 3')`;
db.query.withArgs(sinon.match(query)).resolves([{ shape: { combined: "county" } }]);

const geometry = await generateAlertGeometry(db, rawAlert);
expect(geometry).to.eql({ combined: "county" });
});

it("returns null geometry if no zones or different geocodes are present", async () => {
const rawAlert = {
geometry: false,
properties: {},
};

const geometry = await generateAlertGeometry(db, rawAlert);
expect(geometry).to.be.null;
});
});
Loading

0 comments on commit 6f9db40

Please sign in to comment.