Skip to content

Commit

Permalink
test: Add basemapsCreatePullRequest.handler smoke test TDE-1030 (#891)
Browse files Browse the repository at this point in the history
#### Motivation

Enable refactoring the handler arguments by verifying a common, simple
use case.

#### Modification

- Mocks all relevant `GithubApi` methods to avoid any online calls.
- Generates random input data to make it clear which parts of the input
are relevant to the test (basically none of it is relevant).

#### Checklist

- [x] Tests updated
- [ ] Docs updated (N/A)
- [x] Issue linked in Title
  • Loading branch information
l0b0 authored Nov 24, 2024
1 parent 37f9030 commit 9b81cd0
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 11 deletions.
76 changes: 76 additions & 0 deletions src/commands/basemaps-github/__test__/create-pr-handler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import assert from 'node:assert';
import { afterEach, it } from 'node:test';

import { TileSetType } from '@basemaps/config/build/config/tile.set.js';
import { EpsgCode } from '@basemaps/geo';
import { fsa } from '@chunkd/fs';
import { StacVersion } from 'stac-ts';

import { anySlug } from '../../../utils/__test__/slugify.test.js';
import { GithubApi } from '../../../utils/github.js';
import { basemapsCreatePullRequest, ConfigType, LinzBasemapsSourceCollectionRel } from '../create-pr.js';
import { Category } from '../make.cog.github.js';

const originalEnv = Object.assign({}, process.env);

afterEach(() => {
process.env = originalEnv;
});

await it('basemapsCreatePullRequest.handler should handle S3 target', async (t) => {
const targetUrl = `s3://linz-basemaps/${EpsgCode.Nztm2000}/${anySlug()}`;
t.mock.method(fsa, 'readJson', () => {
return Promise.resolve({
stac_version: '1.0.0' as StacVersion,
type: 'Collection',
id: 'b871c4a7-2d8e-4cec-997a-ed755cf542b9',
title: 'any-title',
description: 'any-description',
license: 'any-license',
extent: { spatial: { bbox: [[]] }, temporal: { interval: [[null, null]] } },
links: [
{
href: `s3://nz-imagery/${EpsgCode.Wgs84}/${anySlug()}`,
rel: LinzBasemapsSourceCollectionRel,
},
],
});
});
process.env['GITHUB_API_TOKEN'] = 'any-github-api-token';
t.mock.method(GithubApi.prototype, 'getContent', () => {
return Promise.resolve(
Buffer.from(
JSON.stringify({
type: TileSetType.Raster,
format: 'avif',
id: 'b48e08c3-ccef-4b42-870a-9c357cb15d1c',
layers: [],
name: 'any-name',
title: 'any-title',
}),
),
);
});
t.mock.method(GithubApi.prototype, 'createBranch', () => {});
t.mock.method(GithubApi.prototype, 'createBlob', () => {});
t.mock.method(GithubApi.prototype, 'createCommit', () => {});
t.mock.method(GithubApi.prototype, 'updateBranch', () => {});
let createPullRequestCalled = false;
t.mock.method(GithubApi.prototype, 'createPullRequest', () => {
createPullRequestCalled = true;
});
const targetUrlsString = JSON.stringify([targetUrl]);

const result = await basemapsCreatePullRequest.handler({
target: targetUrlsString,
repository: 'any-owner/any-repository',
verbose: false,
category: Category.Satellite,
configType: ConfigType.Raster,
individual: false,
vector: false,
ticket: 'any ticket',
});
assert.equal(result, undefined);
assert.ok(createPullRequestCalled);
});
31 changes: 21 additions & 10 deletions src/commands/basemaps-github/create-pr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import { logger } from '../../log.js';
import { registerCli, verbose } from '../common.js';
import { Category, MakeCogGithub } from './make.cog.github.js';

const validTargetBuckets: Set<string> = new Set(['linz-basemaps', 'linz-basemaps-staging']);
const validSourceBuckets: Set<string> = new Set(['nz-imagery', 'linz-imagery', 'nz-elevation']);
export const ValidTargetBuckets: Set<string> = new Set(['linz-basemaps', 'linz-basemaps-staging']);
export const ValidSourceBuckets: Set<string> = new Set(['nz-imagery', 'linz-imagery', 'nz-elevation']);

export const LinzBasemapsSourceCollectionRel = 'linz_basemaps:source_collection';

export enum ConfigType {
Raster = 'raster',
Expand Down Expand Up @@ -52,6 +54,13 @@ export function parseTargetUrl(target: string, offset: 0 | 1): targetInfo {
const splits = url.pathname.split('/');
const epsg = Epsg.tryGet(Number(splits[1 + offset]));
const name = splits[2 + offset];

//Validate the target information
logger.info({ bucket }, 'CreatePR: Valid the target s3 bucket');
if (bucket == null || !ValidTargetBuckets.has(bucket)) {
throw new Error(`Invalid s3 bucket ${bucket} from the target ${target}.`);
}

if (epsg == null || name == null) throw new Error(`Invalid target ${target} to parse the epsg and imagery name.`);

// Get filename for vector target
Expand All @@ -75,21 +84,23 @@ async function parseRasterTargetInfo(
logger.info({ target }, 'CreatePR: Get the layer information from target');
const { bucket, epsg, name } = parseTargetUrl(target, 0);

assertValidBucket(bucket, validTargetBuckets);
assertValidBucket(bucket, ValidTargetBuckets);

const collectionPath = fsa.join(target, 'collection.json');
const collection = await fsa.readJson<StacCollection>(collectionPath);
if (collection == null) throw new Error(`Failed to get target collection json from ${collectionPath}.`);
const title = collection.title;
if (title == null) throw new Error(`Failed to get imagery title from collection.json.`);
if (title == null) throw new Error(`Failed to get imagery title from collection.json: ${collectionPath}`);

// Validate the source location
const source = collection.links.find((f) => f.rel === 'linz_basemaps:source_collection')?.href;
const source = collection.links.find((f) => f.rel === LinzBasemapsSourceCollectionRel)?.href;
if (source == null) throw new Error(`Failed to get source url from collection.json.`);
const sourceUrl = new URL(source);
const sourceBucket = sourceUrl.hostname;
assertValidBucket(sourceBucket, validSourceBuckets);

logger.info({ bucket: sourceBucket }, 'CreatePR: Validate the source s3 bucket');
if (sourceBucket == null || !ValidSourceBuckets.has(sourceBucket)) {
throw new Error(`Invalid s3 bucket ${sourceBucket} from the source ${sourceUrl.href}.`);
}
// Try to get the region for individual layers
let region;
if (individual) {
Expand All @@ -114,7 +125,7 @@ async function parseVectorTargetInfo(target: string): Promise<{ name: string; ti
logger.info({ target }, 'CreatePR: Get the layer information from target');
const { bucket, epsg, name, filename } = parseTargetUrl(target, 1);

assertValidBucket(bucket, validTargetBuckets);
assertValidBucket(bucket, ValidTargetBuckets);

if (filename == null || !filename.endsWith('.tar.co')) {
throw new Error(`Invalid cotar filename for vector map ${filename}.`);
Expand Down Expand Up @@ -147,7 +158,7 @@ async function parseElevationTargetInfo(
logger.info({ target }, 'CreatePR: Get the layer information from target');
const { bucket, epsg, name } = parseTargetUrl(target, 1);

assertValidBucket(bucket, validTargetBuckets);
assertValidBucket(bucket, ValidTargetBuckets);

const collectionPath = fsa.join(target, 'collection.json');
const collection = await fsa.readJson<StacCollection>(collectionPath);
Expand All @@ -160,7 +171,7 @@ async function parseElevationTargetInfo(
if (source == null) throw new Error(`Failed to get source url from collection.json.`);
const sourceUrl = new URL(source);
const sourceBucket = sourceUrl.hostname;
assertValidBucket(sourceBucket, validSourceBuckets);
assertValidBucket(sourceBucket, ValidSourceBuckets);

// Try to get the region for individual layers
let region;
Expand Down
2 changes: 1 addition & 1 deletion src/utils/__test__/slugify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('slugify', () => {
});
});

function anySlug(): string {
export function anySlug(): string {
const length = 8;
let result = '';
for (let counter = 0; counter < length; counter++) {
Expand Down

0 comments on commit 9b81cd0

Please sign in to comment.