Skip to content

Commit 4e37d3e

Browse files
committed
test: add missing error handling tests for handleExport
- Refactored index.js in dataform-service to export internals for mocking - Created index.test.js with test cases for expected behaviors, focusing on catching simulated errors in the job queue and various request payload malformations. - Updated package.json in dataform-service with `node --test` script.
1 parent 66edb2b commit 4e37d3e

5 files changed

Lines changed: 2162 additions & 63 deletions

File tree

infra/dataform-service/src/index.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import functions from '@google-cloud/functions-framework'
22

33
import { BigQueryExport } from './bigquery.js'
4-
import { callRunJob } from './cloud_run.js'
4+
import * as cloud_run from './cloud_run.js'
55
import { getCompilationResults, runWorkflow } from './dataform.js'
66
import { StorageUpload } from './storage.js'
77

@@ -101,7 +101,7 @@ async function handleExport (req, res) {
101101
} else if (destination === 'firestore') {
102102
console.info('Firestore export')
103103
const jobName = `projects/${projectId}/locations/${location}/jobs/${jobId}`
104-
await callRunJob(jobName, payload)
104+
await internals.callRunJob(jobName, payload)
105105
} else {
106106
throw new Error('Bad Request: destination unknown')
107107
}
@@ -191,7 +191,7 @@ async function handleTrigger (req, res) {
191191
async function executeAction (actionName, actionArgs) {
192192
if (actionName === 'runDataformRepo') {
193193
console.info(`Executing action: ${actionName}`)
194-
await runDataformRepo(actionArgs)
194+
await internals.runDataformRepo(actionArgs)
195195
}
196196
}
197197

@@ -241,6 +241,13 @@ async function mainHandler (req, res) {
241241
}
242242
}
243243

244+
const internals = {
245+
callRunJob: cloud_run.callRunJob,
246+
runDataformRepo
247+
}
248+
249+
export { internals, handleExport, mainHandler }
250+
244251
/**
245252
* Main entry point for the combined Dataform service.
246253
* Handles both trigger and export operations based on the request path.
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import test, { mock } from 'node:test'
2+
import assert from 'node:assert'
3+
import { internals, handleExport } from './index.js'
4+
5+
test('handleExport handles export job error', async () => {
6+
const req = {
7+
body: {
8+
calls: [[{
9+
destination: 'firestore',
10+
config: {},
11+
query: 'SELECT 1'
12+
}]]
13+
}
14+
}
15+
16+
let statusCode = null
17+
let responseData = null
18+
19+
const res = {
20+
status: (code) => {
21+
statusCode = code
22+
return {
23+
json: (data) => {
24+
responseData = data
25+
}
26+
}
27+
}
28+
}
29+
30+
const expectedError = new Error('Mocked error')
31+
mock.method(internals, 'callRunJob', async () => {
32+
throw expectedError
33+
})
34+
35+
await handleExport(req, res)
36+
37+
assert.strictEqual(statusCode, 400)
38+
assert.deepStrictEqual(responseData.replies, [400])
39+
assert.strictEqual(responseData.errorMessage, expectedError)
40+
41+
mock.restoreAll()
42+
})
43+
44+
test('handleExport handles missing payload error', async () => {
45+
const req = {
46+
body: {
47+
calls: [[null]]
48+
}
49+
}
50+
51+
let statusCode = null
52+
let responseData = null
53+
54+
const res = {
55+
status: (code) => {
56+
statusCode = code
57+
return {
58+
json: (data) => {
59+
responseData = data
60+
}
61+
}
62+
}
63+
}
64+
65+
await handleExport(req, res)
66+
67+
assert.strictEqual(statusCode, 400)
68+
assert.deepStrictEqual(responseData.replies, [400])
69+
assert.strictEqual(responseData.errorMessage, 'Bad Request: no payload received, expected JSON object')
70+
})
71+
72+
test('handleExport handles missing required keys error', async () => {
73+
const req = {
74+
body: {
75+
calls: [[{
76+
destination: 'firestore'
77+
// missing config and query
78+
}]]
79+
}
80+
}
81+
82+
let statusCode = null
83+
let responseData = null
84+
85+
const res = {
86+
status: (code) => {
87+
statusCode = code
88+
return {
89+
json: (data) => {
90+
responseData = data
91+
}
92+
}
93+
}
94+
}
95+
96+
await handleExport(req, res)
97+
98+
assert.strictEqual(statusCode, 400)
99+
assert.deepStrictEqual(responseData.replies, [400])
100+
assert.strictEqual(responseData.errorMessage, 'Bad Request: unexpected payload structure, required keys: destination, config, query')
101+
})
102+
103+
test('handleExport handles unknown destination error', async () => {
104+
const req = {
105+
body: {
106+
calls: [[{
107+
destination: 'unknown',
108+
config: {},
109+
query: 'SELECT 1'
110+
}]]
111+
}
112+
}
113+
114+
let statusCode = null
115+
let responseData = null
116+
117+
const res = {
118+
status: (code) => {
119+
statusCode = code
120+
return {
121+
json: (data) => {
122+
responseData = data
123+
}
124+
}
125+
}
126+
}
127+
128+
await handleExport(req, res)
129+
130+
assert.strictEqual(statusCode, 400)
131+
assert.deepStrictEqual(responseData.replies, [400])
132+
assert.ok(responseData.errorMessage instanceof Error)
133+
assert.strictEqual(responseData.errorMessage.message, 'Bad Request: destination unknown')
134+
})

infra/dataform-service/src/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"scripts": {
1515
"start": "npx functions-framework --target=dataform-service --signature-type=http --port=${PORT:-8080}",
1616
"start_dev": "npx functions-framework --target=dataform-service --signature-type=http --port=8080 --debug",
17-
"build": "docker build -t dataform-service ."
17+
"build": "docker build -t dataform-service .",
18+
"test": "node --test"
1819
},
1920
"engines": {
2021
"node": ">=22.0.0"

0 commit comments

Comments
 (0)