Skip to content

Commit 6559fc2

Browse files
authored
Added logic to fail test compilation if test SQL or expected SQL are empty (#2082)
* Added logic to fail test compilation if test SQL or expected SQL are empty * Addressed PR comments * Fix pr comments
1 parent f552c10 commit 6559fc2

2 files changed

Lines changed: 284 additions & 4 deletions

File tree

core/actions/test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,20 @@ export class Test extends ActionBuilder<dataform.Test> {
192192
}
193193
this.proto.expectedOutputQuery = testContext.apply(this.contextableQuery);
194194

195+
// Check if the test query and expected output query are non-empty.
196+
if (!this.proto.testQuery.trim()) {
197+
this.session.compileError(
198+
new Error("Test query is empty."),
199+
this.proto.fileName
200+
);
201+
}
202+
if (!this.proto.expectedOutputQuery.trim()) {
203+
this.session.compileError(
204+
new Error("Expected query is empty."),
205+
this.proto.fileName
206+
);
207+
}
208+
195209
return verifyObjectMatchesProto(
196210
dataform.Test,
197211
this.proto,

core/actions/test_test.ts

Lines changed: 270 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,271 @@
1-
import { suite } from "df/testing";
1+
// tslint:disable tsr-detect-non-literal-fs-filename
2+
import { expect } from "chai";
3+
import * as fs from "fs-extra";
4+
import * as path from "path";
25

3-
suite("test", () => {
4-
// This action currently has no unit tests!
5-
});
6+
import { asPlainObject, suite, test } from "df/testing";
7+
import { TmpDirFixture } from "df/testing/fixtures";
8+
import {
9+
coreExecutionRequestFromPath,
10+
runMainInVm,
11+
VALID_WORKFLOW_SETTINGS_YAML
12+
} from "df/testing/run_core";
13+
14+
suite("test", ({ afterEach }) => {
15+
const tmpDirFixture = new TmpDirFixture(afterEach);
16+
17+
test(`test with no inputs`, () => {
18+
const projectDir = tmpDirFixture.createNewTmpDir();
19+
const workflowSettingsPath = path.join(projectDir, "workflow_settings.yaml");
20+
const definitionsDir = path.join(projectDir, "definitions");
21+
const actionsYamlPath = path.join(definitionsDir, "actions.yaml");
22+
const actionSqlPath = path.join(definitionsDir, "action.sql");
23+
const actionTestSqlxPath = path.join(definitionsDir, "action_test.sqlx");
24+
25+
fs.writeFileSync(workflowSettingsPath, VALID_WORKFLOW_SETTINGS_YAML);
26+
fs.mkdirSync(definitionsDir);
27+
fs.writeFileSync(actionsYamlPath, `
28+
actions:
29+
- table:
30+
filename: action.sql`
31+
);
32+
fs.writeFileSync(actionSqlPath, "SELECT 1");
33+
fs.writeFileSync(actionTestSqlxPath, `
34+
config {
35+
type: "test",
36+
dataset: "action"
37+
}
38+
SELECT 1`);
39+
40+
const result = runMainInVm(coreExecutionRequestFromPath(projectDir));
41+
42+
expect(result.compile.compiledGraph.graphErrors.compilationErrors).deep.equals([]);
43+
expect(asPlainObject(result.compile.compiledGraph.tests)).deep.equals(
44+
asPlainObject([
45+
{
46+
// Original test properties
47+
name: "action_test",
48+
testQuery: "SELECT 1",
49+
expectedOutputQuery: "\n\nSELECT 1",
50+
fileName: "definitions/action_test.sqlx",
51+
}
52+
])
53+
);
54+
expect(asPlainObject(result.compile.compiledGraph.tables)).deep.equals(
55+
asPlainObject([
56+
{
57+
"target": {
58+
"database": "defaultProject",
59+
"name": "action",
60+
"schema": "defaultDataset"
61+
},
62+
"canonicalTarget": {
63+
"database": "defaultProject",
64+
"name": "action",
65+
"schema": "defaultDataset"
66+
},
67+
"disabled": false,
68+
"enumType": "TABLE",
69+
"fileName": "definitions/action.sql",
70+
"hermeticity": "NON_HERMETIC",
71+
"query": "SELECT 1",
72+
"type": "table"
73+
}
74+
]));
75+
});
76+
77+
test(`test with multiple_inputs input`, () => {
78+
const projectDir = tmpDirFixture.createNewTmpDir();
79+
const workflowSettingsPath = path.join(projectDir, "workflow_settings.yaml");
80+
const definitionsDir = path.join(projectDir, "definitions");
81+
const actionsYamlPath = path.join(definitionsDir, "actions.yaml");
82+
const action1SqlxPath = path.join(definitionsDir, "action1.sqlx");
83+
const action1TestSqlxPath = path.join(definitionsDir, "action1_test.sqlx");
84+
const action2SqlxPath = path.join(definitionsDir, "action2.sqlx");
85+
const action2TestSqlxPath = path.join(definitionsDir, "action2_test.sqlx");
86+
87+
fs.writeFileSync(workflowSettingsPath, VALID_WORKFLOW_SETTINGS_YAML);
88+
fs.mkdirSync(definitionsDir);
89+
90+
// Add a declaration
91+
fs.writeFileSync(actionsYamlPath, `
92+
actions:
93+
- declaration:
94+
name: a_declaration`
95+
);
96+
97+
// Add an action with a test, reads from declaration
98+
fs.writeFileSync(action1SqlxPath, `
99+
config {
100+
type: "table",
101+
}
102+
SELECT a,b,c FROM \${ref("a_declaration")}
103+
`);
104+
fs.writeFileSync(action1TestSqlxPath, `
105+
config {
106+
type: "test",
107+
dataset: "action1"
108+
}
109+
input "a_declaration" {
110+
SELECT 1 AS a, 2 AS b, 3 AS c, 4 AS d
111+
}
112+
SELECT 1 AS a, 2 AS b, 3 AS c`);
113+
114+
115+
// Add an action with a test, reads from previous action
116+
fs.writeFileSync(action2SqlxPath, `
117+
config {
118+
type: "table",
119+
}
120+
SELECT a,b FROM \${ref("action1")}
121+
`);
122+
fs.writeFileSync(action2TestSqlxPath, `
123+
config {
124+
type: "test",
125+
dataset: "action2"
126+
}
127+
input "action1" {
128+
SELECT 1 AS a, 2 AS b, 3 AS c
129+
}
130+
SELECT 1 AS a, 2 AS b`);
131+
132+
const result = runMainInVm(coreExecutionRequestFromPath(projectDir));
133+
134+
expect(result.compile.compiledGraph.graphErrors.compilationErrors).deep.equals([]);
135+
expect(asPlainObject(result.compile.compiledGraph.tests)).deep.equals(
136+
asPlainObject([
137+
{
138+
// Original test properties
139+
name: "action1_test",
140+
testQuery: "\n\nSELECT a,b,c FROM (\n SELECT 1 AS a, 2 AS b, 3 AS c, 4 AS d\n)\n ",
141+
expectedOutputQuery: "\n\n\nSELECT 1 AS a, 2 AS b, 3 AS c",
142+
fileName: "definitions/action1_test.sqlx",
143+
},
144+
{
145+
// Original test properties
146+
name: "action2_test",
147+
testQuery: "\n\nSELECT a,b FROM (\n SELECT 1 AS a, 2 AS b, 3 AS c\n)\n ",
148+
expectedOutputQuery: "\n\n\nSELECT 1 AS a, 2 AS b",
149+
fileName: "definitions/action2_test.sqlx",
150+
}
151+
])
152+
);
153+
expect(asPlainObject(result.compile.compiledGraph.tables)).deep.equals(
154+
asPlainObject([
155+
{
156+
"target": {
157+
"database": "defaultProject",
158+
"name": "action1",
159+
"schema": "defaultDataset"
160+
},
161+
"canonicalTarget": {
162+
"database": "defaultProject",
163+
"name": "action1",
164+
"schema": "defaultDataset"
165+
},
166+
"dependencyTargets": [
167+
{
168+
"database": "defaultProject",
169+
"name": "a_declaration",
170+
"schema": "defaultDataset"
171+
}
172+
],
173+
"disabled": false,
174+
"enumType": "TABLE",
175+
"fileName": "definitions/action1.sqlx",
176+
"hermeticity": "NON_HERMETIC",
177+
"query": "\n\nSELECT a,b,c FROM `defaultProject.defaultDataset.a_declaration`\n ",
178+
"type": "table"
179+
},
180+
{
181+
"target": {
182+
"database": "defaultProject",
183+
"name": "action2",
184+
"schema": "defaultDataset"
185+
},
186+
"canonicalTarget": {
187+
"database": "defaultProject",
188+
"name": "action2",
189+
"schema": "defaultDataset"
190+
},
191+
"dependencyTargets": [
192+
{
193+
"database": "defaultProject",
194+
"name": "action1",
195+
"schema": "defaultDataset"
196+
}
197+
],
198+
"disabled": false,
199+
"enumType": "TABLE",
200+
"fileName": "definitions/action2.sqlx",
201+
"hermeticity": "NON_HERMETIC",
202+
"query": "\n\nSELECT a,b FROM `defaultProject.defaultDataset.action1`\n ",
203+
"type": "table"
204+
}
205+
])
206+
);
207+
});
208+
209+
test(`test with empty test sql`, () => {
210+
const projectDir = tmpDirFixture.createNewTmpDir();
211+
const workflowSettingsPath = path.join(projectDir, "workflow_settings.yaml");
212+
const definitionsDir = path.join(projectDir, "definitions");
213+
const actionsYamlPath = path.join(definitionsDir, "actions.yaml");
214+
const action1SqlxPath = path.join(definitionsDir, "action1.sqlx");
215+
const action1TestSqlxPath = path.join(definitionsDir, "action1_test.sqlx");
216+
const action2SqlxPath = path.join(definitionsDir, "action2.sqlx");
217+
const action2TestSqlxPath = path.join(definitionsDir, "action2_test.sqlx");
218+
219+
fs.writeFileSync(workflowSettingsPath, VALID_WORKFLOW_SETTINGS_YAML);
220+
fs.mkdirSync(definitionsDir);
221+
222+
// Add a declaration
223+
fs.writeFileSync(actionsYamlPath, `
224+
actions:
225+
- declaration:
226+
name: a_declaration`
227+
);
228+
229+
// Add an action with a test, reads from declaration
230+
fs.writeFileSync(action1SqlxPath, `
231+
config {
232+
type: "table",
233+
}
234+
SELECT a,b,c FROM \${ref("a_declaration")}
235+
`);
236+
fs.writeFileSync(action1TestSqlxPath, `
237+
config {
238+
type: "test",
239+
dataset: "action1"
240+
}
241+
input "a_declaration" {
242+
SELECT 1 AS a, 2 AS b, 3 AS c, 4 AS d
243+
}
244+
`);
245+
246+
247+
// Add an action with a test, reads from previous action
248+
fs.writeFileSync(action2SqlxPath, `
249+
config {
250+
type: "table",
251+
}
252+
SELECT a,b FROM \${ref("action1")}
253+
`);
254+
fs.writeFileSync(action2TestSqlxPath, `
255+
config {
256+
type: "test",
257+
dataset: "action2"
258+
}
259+
input "action1" {
260+
SELECT 1 AS a, 2 AS b, 3 AS c
261+
}
262+
SELECT 1 AS a, 2 AS b`);
263+
264+
const result = runMainInVm(coreExecutionRequestFromPath(projectDir));
265+
266+
expect(result.compile.compiledGraph.graphErrors.compilationErrors.length).equals(1);
267+
expect(result.compile.compiledGraph.graphErrors.compilationErrors[0].message).contains(
268+
`Expected query is empty.`
269+
);
270+
});
271+
});

0 commit comments

Comments
 (0)