@creative-introvert/tons-of-tests 2.1.0 → 3.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +143 -37
- package/dist/cjs/Classify.js +1 -2
- package/dist/cjs/Classify.js.map +1 -1
- package/dist/cjs/RepositoryError.js +24 -33
- package/dist/cjs/RepositoryError.js.map +1 -1
- package/dist/cjs/Show.js +18 -0
- package/dist/cjs/Show.js.map +1 -1
- package/dist/cjs/Test.js +37 -2
- package/dist/cjs/Test.js.map +1 -1
- package/dist/cjs/Test.repository.js +8 -17
- package/dist/cjs/Test.repository.js.map +1 -1
- package/dist/cjs/TestRun.js +20 -0
- package/dist/cjs/TestRun.js.map +1 -0
- package/dist/cjs/TestValueError.js +23 -0
- package/dist/cjs/TestValueError.js.map +1 -0
- package/dist/cjs/index.js +0 -7
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/Classify.js +1 -9
- package/dist/cjs/internal/Classify.js.map +1 -1
- package/dist/cjs/internal/Test.js +236 -93
- package/dist/cjs/internal/Test.js.map +1 -1
- package/dist/cjs/internal/Test.repository.sqlite.js +262 -357
- package/dist/cjs/internal/Test.repository.sqlite.js.map +1 -1
- package/dist/cjs/internal/Test.serialization.js +128 -0
- package/dist/cjs/internal/Test.serialization.js.map +1 -0
- package/dist/cjs/internal/common.js.map +1 -1
- package/dist/cjs/internal/stats.js +29 -1
- package/dist/cjs/internal/stats.js.map +1 -1
- package/dist/cjs/internal/summarize.js +143 -29
- package/dist/cjs/internal/summarize.js.map +1 -1
- package/dist/cjs/internal/test-repository-fixtures.js +31 -0
- package/dist/cjs/internal/test-repository-fixtures.js.map +1 -0
- package/dist/cjs/internal/test-repository-migrations.js +68 -0
- package/dist/cjs/internal/test-repository-migrations.js.map +1 -0
- package/dist/cjs/internal/test-result-stats.js +89 -0
- package/dist/cjs/internal/test-result-stats.js.map +1 -0
- package/dist/dts/Classify.d.ts +0 -1
- package/dist/dts/Classify.d.ts.map +1 -1
- package/dist/dts/RepositoryError.d.ts +19 -20
- package/dist/dts/RepositoryError.d.ts.map +1 -1
- package/dist/dts/Show.d.ts +5 -5
- package/dist/dts/Show.d.ts.map +1 -1
- package/dist/dts/Test.d.ts +120 -14
- package/dist/dts/Test.d.ts.map +1 -1
- package/dist/dts/Test.repository.d.ts +94 -8
- package/dist/dts/Test.repository.d.ts.map +1 -1
- package/dist/dts/TestRun.d.ts +18 -0
- package/dist/dts/TestRun.d.ts.map +1 -0
- package/dist/dts/TestValueError.d.ts +17 -0
- package/dist/dts/TestValueError.d.ts.map +1 -0
- package/dist/dts/index.d.ts +0 -1
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/Classify.d.ts +0 -1
- package/dist/dts/internal/Classify.d.ts.map +1 -1
- package/dist/dts/internal/Test.d.ts +52 -30
- package/dist/dts/internal/Test.d.ts.map +1 -1
- package/dist/dts/internal/Test.repository.sqlite.d.ts +66 -12
- package/dist/dts/internal/Test.repository.sqlite.d.ts.map +1 -1
- package/dist/dts/internal/Test.serialization.d.ts +34 -0
- package/dist/dts/internal/Test.serialization.d.ts.map +1 -0
- package/dist/dts/internal/common.d.ts +1 -1
- package/dist/dts/internal/common.d.ts.map +1 -1
- package/dist/dts/internal/stats.d.ts +15 -1
- package/dist/dts/internal/stats.d.ts.map +1 -1
- package/dist/dts/internal/summarize.d.ts +39 -7
- package/dist/dts/internal/summarize.d.ts.map +1 -1
- package/dist/dts/internal/test-repository-fixtures.d.ts +22 -0
- package/dist/dts/internal/test-repository-fixtures.d.ts.map +1 -0
- package/dist/dts/internal/test-repository-migrations.d.ts +11 -0
- package/dist/dts/internal/test-repository-migrations.d.ts.map +1 -0
- package/dist/dts/internal/test-result-stats.d.ts +7 -0
- package/dist/dts/internal/test-result-stats.d.ts.map +1 -0
- package/dist/esm/Classify.js +0 -1
- package/dist/esm/Classify.js.map +1 -1
- package/dist/esm/RepositoryError.js +14 -29
- package/dist/esm/RepositoryError.js.map +1 -1
- package/dist/esm/Show.js +2 -2
- package/dist/esm/Show.js.map +1 -1
- package/dist/esm/Test.js +34 -1
- package/dist/esm/Test.js.map +1 -1
- package/dist/esm/Test.repository.js +7 -16
- package/dist/esm/Test.repository.js.map +1 -1
- package/dist/esm/TestRun.js +13 -0
- package/dist/esm/TestRun.js.map +1 -0
- package/dist/esm/TestValueError.js +16 -0
- package/dist/esm/TestValueError.js.map +1 -0
- package/dist/esm/index.js +0 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/Classify.js +0 -7
- package/dist/esm/internal/Classify.js.map +1 -1
- package/dist/esm/internal/Test.js +232 -92
- package/dist/esm/internal/Test.js.map +1 -1
- package/dist/esm/internal/Test.repository.sqlite.js +261 -354
- package/dist/esm/internal/Test.repository.sqlite.js.map +1 -1
- package/dist/esm/internal/Test.serialization.js +119 -0
- package/dist/esm/internal/Test.serialization.js.map +1 -0
- package/dist/esm/internal/common.js.map +1 -1
- package/dist/esm/internal/stats.js +27 -0
- package/dist/esm/internal/stats.js.map +1 -1
- package/dist/esm/internal/summarize.js +143 -28
- package/dist/esm/internal/summarize.js.map +1 -1
- package/dist/esm/internal/test-repository-fixtures.js +25 -0
- package/dist/esm/internal/test-repository-fixtures.js.map +1 -0
- package/dist/esm/internal/test-repository-migrations.js +62 -0
- package/dist/esm/internal/test-repository-migrations.js.map +1 -0
- package/dist/esm/internal/test-result-stats.js +83 -0
- package/dist/esm/internal/test-result-stats.js.map +1 -0
- package/package.json +1 -1
- package/dist/cjs/Test.repository.types.js +0 -14
- package/dist/cjs/Test.repository.types.js.map +0 -1
- package/dist/cjs/internal/lib/Schema.js +0 -14
- package/dist/cjs/internal/lib/Schema.js.map +0 -1
- package/dist/dts/Test.repository.types.d.ts +0 -62
- package/dist/dts/Test.repository.types.d.ts.map +0 -1
- package/dist/dts/internal/lib/Schema.d.ts +0 -4
- package/dist/dts/internal/lib/Schema.d.ts.map +0 -1
- package/dist/esm/Test.repository.types.js +0 -7
- package/dist/esm/Test.repository.types.js.map +0 -1
- package/dist/esm/internal/lib/Schema.js +0 -7
- package/dist/esm/internal/lib/Schema.js.map +0 -1
|
@@ -3,398 +3,303 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
|
|
6
|
+
exports.makeTestRepository = exports.TestResultStorage = void 0;
|
|
7
|
+
Object.defineProperty(exports, "tables", {
|
|
7
8
|
enumerable: true,
|
|
8
9
|
get: function () {
|
|
9
|
-
return
|
|
10
|
+
return _testRepositoryMigrations.tables;
|
|
10
11
|
}
|
|
11
12
|
});
|
|
12
|
-
exports.tables = exports.makeTestRepository = void 0;
|
|
13
|
-
var SqlClient = /*#__PURE__*/_interopRequireWildcard(/*#__PURE__*/require("effect/sql/SqlClient"));
|
|
14
13
|
var _effect = /*#__PURE__*/require("effect");
|
|
15
|
-
var
|
|
16
|
-
var
|
|
14
|
+
var _sql = /*#__PURE__*/require("effect/sql");
|
|
15
|
+
var _TestRun = /*#__PURE__*/require("../TestRun.js");
|
|
17
16
|
var _RepositoryError = /*#__PURE__*/require("../RepositoryError.js");
|
|
18
17
|
var _Classify = /*#__PURE__*/require("./Classify.js");
|
|
19
|
-
var
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
testResults: 'test-results',
|
|
24
|
-
testRuns: 'test-runs',
|
|
25
|
-
testRunResults: 'test-run-results'
|
|
26
|
-
};
|
|
27
|
-
const TestResultWriteSchema = /*#__PURE__*/_effect.Schema.Struct({
|
|
18
|
+
var _testRepositoryMigrations = /*#__PURE__*/require("./test-repository-migrations.js");
|
|
19
|
+
var _testResultStats = /*#__PURE__*/require("./test-result-stats.js");
|
|
20
|
+
var _TestSerialization = /*#__PURE__*/require("./Test.serialization.js");
|
|
21
|
+
const TestResultStorage = exports.TestResultStorage = /*#__PURE__*/_effect.Schema.Struct({
|
|
28
22
|
id: _effect.Schema.String,
|
|
29
23
|
hashTestCase: _effect.Schema.String,
|
|
30
24
|
key: _effect.Schema.String,
|
|
25
|
+
input: /*#__PURE__*/_effect.Schema.fromJsonString(_effect.Schema.Json),
|
|
26
|
+
result: /*#__PURE__*/_effect.Schema.fromJsonString(_effect.Schema.Json),
|
|
27
|
+
expected: /*#__PURE__*/_effect.Schema.fromJsonString(_effect.Schema.Json),
|
|
28
|
+
label: _Classify.LabelSchema
|
|
29
|
+
});
|
|
30
|
+
const StoredResult = /*#__PURE__*/_effect.Schema.Struct({
|
|
31
|
+
...TestResultStorage.fields,
|
|
32
|
+
input: _effect.Schema.String,
|
|
33
|
+
result: _effect.Schema.String,
|
|
34
|
+
expected: _effect.Schema.String,
|
|
31
35
|
ordering: _effect.Schema.Int,
|
|
32
36
|
resultOrdering: _effect.Schema.Int,
|
|
33
|
-
|
|
34
|
-
result: /*#__PURE__*/_effect.Schema.fromJsonString(_effect.Schema.Unknown),
|
|
35
|
-
expected: /*#__PURE__*/_effect.Schema.fromJsonString(_effect.Schema.Unknown),
|
|
36
|
-
label: _Classify.LabelSchema,
|
|
37
|
-
tags: /*#__PURE__*/(0, _Schema.split)(','),
|
|
37
|
+
tags: /*#__PURE__*/_effect.Schema.fromJsonString(/*#__PURE__*/_effect.Schema.Array(_effect.Schema.String)),
|
|
38
38
|
timeMillis: _effect.Schema.Finite
|
|
39
39
|
});
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
const encodeResult = /*#__PURE__*/_effect.Schema.encodeEffect(StoredResult);
|
|
41
|
+
const decodeRows = /*#__PURE__*/_effect.Schema.decodeUnknownEffect(/*#__PURE__*/_effect.Schema.Array(StoredResult));
|
|
42
|
+
const decodeRuns = /*#__PURE__*/_effect.Schema.decodeUnknownEffect(/*#__PURE__*/_effect.Schema.Array(_TestRun.TestRun));
|
|
43
|
+
const decodeListedRuns = /*#__PURE__*/_effect.Schema.decodeUnknownEffect(/*#__PURE__*/_effect.Schema.Array(/*#__PURE__*/_effect.Schema.Struct({
|
|
44
|
+
..._TestRun.TestRun.fields,
|
|
45
|
+
isBaseline: /*#__PURE__*/_effect.Schema.Literals([0, 1])
|
|
46
|
+
})));
|
|
47
|
+
const decodeVariantBaselines = /*#__PURE__*/_effect.Schema.decodeUnknownEffect(/*#__PURE__*/_effect.Schema.Array(/*#__PURE__*/_effect.Schema.Struct({
|
|
48
|
+
variant: _effect.Schema.String,
|
|
49
|
+
id: /*#__PURE__*/_effect.Schema.NullOr(_TestRun.TestRun.fields.id),
|
|
50
|
+
name: /*#__PURE__*/_effect.Schema.NullOr(_TestRun.TestRun.fields.name),
|
|
51
|
+
state: /*#__PURE__*/_effect.Schema.NullOr(_TestRun.TestRun.fields.state)
|
|
52
|
+
})));
|
|
53
|
+
const decodeRunLimit = /*#__PURE__*/_effect.Schema.decodeUnknownEffect(/*#__PURE__*/_effect.Schema.Int.check(/*#__PURE__*/_effect.Schema.isBetween({
|
|
54
|
+
minimum: 1,
|
|
55
|
+
maximum: 100
|
|
50
56
|
})));
|
|
51
|
-
const TestRunsReadSchema = /*#__PURE__*/_effect.Schema.Array(_TestRepositoryTypes.TestRun);
|
|
52
|
-
const TestRunResultsSchema = /*#__PURE__*/_effect.Schema.Array(/*#__PURE__*/_effect.Schema.Struct({
|
|
53
|
-
testRun: _effect.Schema.Int,
|
|
54
|
-
testResult: _effect.Schema.String,
|
|
55
|
-
ordering: _effect.Schema.Int,
|
|
56
|
-
resultOrdering: _effect.Schema.Int,
|
|
57
|
-
timeMillis: _effect.Schema.Finite
|
|
58
|
-
}));
|
|
59
|
-
const TableColumnsSchema = /*#__PURE__*/_effect.Schema.Array(/*#__PURE__*/_effect.Schema.Struct({
|
|
60
|
-
name: _effect.Schema.String
|
|
61
|
-
}));
|
|
62
57
|
const makeTestRepository = exports.makeTestRepository = /*#__PURE__*/_effect.Effect.gen(function* () {
|
|
63
|
-
const sql = yield* SqlClient.SqlClient;
|
|
58
|
+
const sql = yield* _sql.SqlClient.SqlClient;
|
|
64
59
|
yield* sql`PRAGMA auto_vacuum = FULL;`;
|
|
65
|
-
yield*
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
FOREIGN KEY (testResult) REFERENCES ${sql(tables.testResults)}(id),
|
|
105
|
-
UNIQUE (testRun, testResult)
|
|
106
|
-
);
|
|
107
|
-
`;
|
|
108
|
-
const resultColumns = yield* _effect.Schema.decodeUnknownEffect(TableColumnsSchema)(yield* sql`PRAGMA table_info(${sql(tables.testResults)});`).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('migrateTestResults')));
|
|
109
|
-
if (!resultColumns.some(column => column.name === 'key')) {
|
|
110
|
-
yield* sql`
|
|
111
|
-
ALTER TABLE ${sql(tables.testResults)}
|
|
112
|
-
ADD COLUMN key TEXT NOT NULL DEFAULT 'result';
|
|
113
|
-
`;
|
|
114
|
-
}
|
|
115
|
-
if (!resultColumns.some(column => column.name === 'resultOrdering')) {
|
|
116
|
-
yield* sql`
|
|
117
|
-
ALTER TABLE ${sql(tables.testResults)}
|
|
118
|
-
ADD COLUMN resultOrdering INTEGER NOT NULL DEFAULT 0;
|
|
119
|
-
`;
|
|
120
|
-
}
|
|
121
|
-
const runResultColumns = yield* _effect.Schema.decodeUnknownEffect(TableColumnsSchema)(yield* sql`PRAGMA table_info(${sql(tables.testRunResults)});`).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('migrateTestRunResults')));
|
|
122
|
-
for (const column of ['ordering', 'resultOrdering', 'timeMillis']) {
|
|
123
|
-
if (runResultColumns.some(existing => existing.name === column)) {
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
yield* sql`
|
|
127
|
-
ALTER TABLE ${sql(tables.testRunResults)}
|
|
128
|
-
ADD COLUMN ${sql(column)} INTEGER NOT NULL DEFAULT 0;
|
|
129
|
-
`;
|
|
130
|
-
yield* sql`
|
|
131
|
-
UPDATE ${sql(tables.testRunResults)} AS runres
|
|
132
|
-
SET ${sql(column)} = (
|
|
133
|
-
SELECT ${sql(column)} FROM ${sql(tables.testResults)} res
|
|
134
|
-
WHERE res.id = runres.testResult
|
|
135
|
-
);
|
|
136
|
-
`;
|
|
137
|
-
}
|
|
138
|
-
// Lookup by the junction's `testResult` column: the existing
|
|
139
|
-
// UNIQUE(testRun, testResult) index is keyed on testRun first, so orphan
|
|
140
|
-
// cleanup (`... NOT IN (SELECT testResult ...)`) and stream joins
|
|
141
|
-
// (`res.id = runres.testResult`) would otherwise full-scan the junction.
|
|
142
|
-
yield* sql`CREATE INDEX IF NOT EXISTS idx_trr_testresult ON ${sql(tables.testRunResults)}(testResult)`;
|
|
143
|
-
yield* sql`CREATE INDEX IF NOT EXISTS idx_tr_hashtestcase ON ${sql(tables.testResults)}(hashTestCase)`;
|
|
144
|
-
}));
|
|
145
|
-
// With 11 result columns and 5 junction columns, batches of 50 rows stay below
|
|
146
|
-
// SQLite's lowest default limit of 999 bound values per statement.
|
|
147
|
-
const INSERT_BATCH_SIZE = 50;
|
|
148
|
-
const insertTestResults = (testResults, testRun) => sql.withTransaction(_effect.Effect.gen(function* () {
|
|
149
|
-
if (testResults.length === 0) return;
|
|
150
|
-
const encoded = yield* _effect.Effect.forEach(testResults, _ => _effect.Schema.encodeEffect(TestResultWriteSchema)(_).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('insertTestResults'))));
|
|
151
|
-
for (let i = 0; i < encoded.length; i += INSERT_BATCH_SIZE) {
|
|
152
|
-
const chunk = encoded.slice(i, i + INSERT_BATCH_SIZE);
|
|
153
|
-
yield* sql`
|
|
154
|
-
INSERT INTO ${sql(tables.testResults)}
|
|
155
|
-
${sql.insert(chunk)}
|
|
60
|
+
yield* _testRepositoryMigrations.migrate;
|
|
61
|
+
const getTestRun = _effect.Effect.fnUntraced(function* (id) {
|
|
62
|
+
return _effect.Array.head(yield* decodeRuns(yield* sql`SELECT * FROM ${sql(_testRepositoryMigrations.tables.testRuns)} WHERE id = ${id};`));
|
|
63
|
+
});
|
|
64
|
+
const insertTestResults = _effect.Effect.fnUntraced(function* (results, run, schemas) {
|
|
65
|
+
const codec = (0, _TestSerialization.makeResultCodec)(schemas, run.name);
|
|
66
|
+
// Each statement stays below SQLite's lowest default limit of 999 parameters.
|
|
67
|
+
for (let offset = 0; offset < Math.max(1, results.length); offset += 50) {
|
|
68
|
+
const encoded = yield* _effect.Effect.forEach(results.slice(offset, offset + 50), _effect.Effect.fnUntraced(function* (result) {
|
|
69
|
+
const encoded = yield* codec.encode(result);
|
|
70
|
+
return yield* encodeResult({
|
|
71
|
+
...encoded,
|
|
72
|
+
input: (0, _TestSerialization.stringifyJson)(encoded.input),
|
|
73
|
+
result: (0, _TestSerialization.stringifyJson)(encoded.result),
|
|
74
|
+
expected: (0, _TestSerialization.stringifyJson)(encoded.expected)
|
|
75
|
+
});
|
|
76
|
+
}));
|
|
77
|
+
yield* sql.withTransaction(_effect.Effect.gen(function* () {
|
|
78
|
+
const saved = yield* getTestRun(run.id);
|
|
79
|
+
if (_effect.Option.isNone(saved)) {
|
|
80
|
+
return yield* new _RepositoryError.TestRunNotFound({
|
|
81
|
+
testRunId: run.id
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (saved.value.state !== 'Running') {
|
|
85
|
+
return yield* _effect.Effect.die(new Error('Only Running test runs accept result writes.'));
|
|
86
|
+
}
|
|
87
|
+
if (encoded.length === 0) return;
|
|
88
|
+
const content = encoded.map(result => ({
|
|
89
|
+
id: result.id,
|
|
90
|
+
hashTestCase: result.hashTestCase,
|
|
91
|
+
key: result.key,
|
|
92
|
+
input: result.input,
|
|
93
|
+
result: result.result,
|
|
94
|
+
expected: result.expected,
|
|
95
|
+
label: result.label
|
|
96
|
+
}));
|
|
97
|
+
yield* sql`
|
|
98
|
+
INSERT INTO ${sql(_testRepositoryMigrations.tables.testResults)} ${sql.insert(content)}
|
|
156
99
|
ON CONFLICT(id) DO NOTHING;
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
for (let i = 0; i < junction.length; i += INSERT_BATCH_SIZE) {
|
|
169
|
-
const chunk = junction.slice(i, i + INSERT_BATCH_SIZE);
|
|
170
|
-
yield* sql`
|
|
171
|
-
INSERT INTO ${sql(tables.testRunResults)}
|
|
172
|
-
${sql.insert(chunk)}
|
|
100
|
+
`;
|
|
101
|
+
const links = encoded.map(result => ({
|
|
102
|
+
testRun: run.id,
|
|
103
|
+
testResult: result.id,
|
|
104
|
+
ordering: result.ordering,
|
|
105
|
+
resultOrdering: result.resultOrdering,
|
|
106
|
+
timeMillis: result.timeMillis,
|
|
107
|
+
tags: result.tags
|
|
108
|
+
}));
|
|
109
|
+
yield* sql`
|
|
110
|
+
INSERT INTO ${sql(_testRepositoryMigrations.tables.testRunResults)} ${sql.insert(links)}
|
|
173
111
|
ON CONFLICT(testRun, testResult) DO UPDATE SET
|
|
174
112
|
ordering = excluded.ordering,
|
|
175
113
|
resultOrdering = excluded.resultOrdering,
|
|
176
|
-
timeMillis = excluded.timeMillis
|
|
177
|
-
|
|
114
|
+
timeMillis = excluded.timeMillis,
|
|
115
|
+
tags = excluded.tags;
|
|
116
|
+
`;
|
|
117
|
+
}));
|
|
178
118
|
}
|
|
179
|
-
})
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
WHERE runs.id = ${testRun.id}
|
|
214
|
-
ORDER BY runres.ordering ASC, runres.resultOrdering ASC;
|
|
215
|
-
`.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getTestResultsStream')));
|
|
216
|
-
const decoded = yield* _effect.Schema.decodeUnknownEffect(RowsSchema)(rows).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getTestResultsStream')));
|
|
217
|
-
return _effect.Stream.fromIterable(decoded);
|
|
119
|
+
});
|
|
120
|
+
const getTestResultsStream = (run, schemas, matching) => {
|
|
121
|
+
if (matching !== undefined && matching.length > 50) {
|
|
122
|
+
return _effect.Stream.die(new Error('Match at most 50 case/key pairs per query.'));
|
|
123
|
+
}
|
|
124
|
+
const codec = (0, _TestSerialization.makeResultCodec)(schemas, run.name);
|
|
125
|
+
const filter = matching === undefined ? sql`1 = 1` : matching.length === 0 ? sql`1 = 0` : sql.or(matching.map(key => sql`res.hashTestCase = ${key.hashTestCase} AND res.key = ${key.key}`));
|
|
126
|
+
// Match case/key pairs first, so each batch avoids scanning the whole prior run.
|
|
127
|
+
// CROSS JOIN keeps SQLite from choosing the run-order index for that lookup.
|
|
128
|
+
const from = matching === undefined ? sql`${sql(_testRepositoryMigrations.tables.testRunResults)} runres
|
|
129
|
+
JOIN ${sql(_testRepositoryMigrations.tables.testResults)} res ON res.id = runres.testResult` : sql`${sql(_testRepositoryMigrations.tables.testResults)} res
|
|
130
|
+
CROSS JOIN ${sql(_testRepositoryMigrations.tables.testRunResults)} runres ON res.id = runres.testResult`;
|
|
131
|
+
// The driver cannot stream a query. Keyset pages keep decoded rows bounded.
|
|
132
|
+
return _effect.Stream.paginate(undefined, _effect.Effect.fnUntraced(function* (after) {
|
|
133
|
+
const rows = yield* decodeRows(yield* sql`
|
|
134
|
+
SELECT res.id, res.hashTestCase, res.key,
|
|
135
|
+
runres.ordering, runres.resultOrdering, res.input, res.result,
|
|
136
|
+
res.expected, res.label, runres.tags, runres.timeMillis
|
|
137
|
+
FROM ${from}
|
|
138
|
+
WHERE runres.testRun = ${run.id} AND ${filter}
|
|
139
|
+
AND ${after === undefined ? sql`1 = 1` : sql`
|
|
140
|
+
(runres.ordering, runres.resultOrdering, runres.testResult) >
|
|
141
|
+
(${after.ordering}, ${after.resultOrdering}, ${after.id})
|
|
142
|
+
`}
|
|
143
|
+
ORDER BY runres.ordering, runres.resultOrdering, runres.testResult
|
|
144
|
+
LIMIT 100;
|
|
145
|
+
`);
|
|
146
|
+
const last = rows[rows.length - 1];
|
|
147
|
+
const decoded = yield* _effect.Effect.forEach(rows, codec.decode);
|
|
148
|
+
return [decoded, rows.length < 100 ? _effect.Option.none() : _effect.Option.some({
|
|
149
|
+
ordering: last.ordering,
|
|
150
|
+
resultOrdering: last.resultOrdering,
|
|
151
|
+
id: last.id
|
|
152
|
+
})];
|
|
218
153
|
}));
|
|
219
154
|
};
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const r = yield* sql`
|
|
230
|
-
SELECT * FROM ${sql(tables.testRuns)}
|
|
231
|
-
WHERE hash IS NOT NULL AND name = ${name}
|
|
232
|
-
ORDER BY id DESC
|
|
233
|
-
LIMIT 1;
|
|
234
|
-
`.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getPreviousTestRun')));
|
|
235
|
-
const p = yield* _effect.Schema.decodeUnknownEffect(TestRunsReadSchema)(r).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getPreviousTestRun')));
|
|
236
|
-
return _effect.Array.head(p);
|
|
237
|
-
});
|
|
238
|
-
const getAllTestRuns = _effect.Effect.gen(function* () {
|
|
239
|
-
const results = yield* sql`
|
|
240
|
-
SELECT * from ${sql(tables.testRuns)};
|
|
241
|
-
`.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getAllTestRuns')));
|
|
242
|
-
return yield* _effect.Schema.decodeUnknownEffect(TestRunsReadSchema)(results).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getAllTestRuns')));
|
|
243
|
-
});
|
|
244
|
-
const getAllTestRunResults = _effect.Effect.gen(function* () {
|
|
245
|
-
const results = yield* sql`
|
|
246
|
-
SELECT * from ${sql(tables.testRunResults)};
|
|
247
|
-
`.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getAllTestRunResults')));
|
|
248
|
-
return yield* _effect.Schema.decodeUnknownEffect(TestRunResultsSchema)(results).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getAllTestRunResults')));
|
|
249
|
-
});
|
|
250
|
-
const getAllTestResults = _effect.Effect.gen(function* () {
|
|
251
|
-
const results = yield* sql`
|
|
252
|
-
SELECT * from ${sql(tables.testResults)};
|
|
253
|
-
`.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getAllTestResults')));
|
|
254
|
-
return yield* _effect.Schema.decodeUnknownEffect(TestResultsSchema)(results).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getAllTestResults')));
|
|
155
|
+
const getLatestTestRun = _effect.Effect.fnUntraced(function* ({
|
|
156
|
+
name,
|
|
157
|
+
variant
|
|
158
|
+
}) {
|
|
159
|
+
return _effect.Array.head(yield* decodeRuns(yield* sql`
|
|
160
|
+
SELECT * FROM ${sql(_testRepositoryMigrations.tables.testRuns)}
|
|
161
|
+
WHERE name = ${name} AND variant = ${variant}
|
|
162
|
+
ORDER BY id DESC LIMIT 1;
|
|
163
|
+
`));
|
|
255
164
|
});
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return _effect.Array.head(runs).pipe(_effect.Option.flatMap(run => _effect.Option.fromNullishOr(run.hash)));
|
|
165
|
+
const getBaselineTestRun = _effect.Effect.fnUntraced(function* ({
|
|
166
|
+
name,
|
|
167
|
+
variant
|
|
168
|
+
}) {
|
|
169
|
+
return _effect.Array.head(yield* decodeRuns(yield* sql`
|
|
170
|
+
SELECT run.* FROM ${sql(_testRepositoryMigrations.tables.testBaselines)} baseline
|
|
171
|
+
JOIN ${sql(_testRepositoryMigrations.tables.testRuns)} run ON run.id = baseline.testRun
|
|
172
|
+
WHERE baseline.name = ${name} AND baseline.variant = ${variant};
|
|
173
|
+
`));
|
|
266
174
|
});
|
|
267
|
-
const
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const current = yield* _effect.Schema.decodeUnknownEffect(TestRunsReadSchema)(currentRaw).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getOrCreateCurrentTestRun')));
|
|
276
|
-
const existing = _effect.Array.head(current);
|
|
277
|
-
if (_effect.Option.isSome(existing)) {
|
|
278
|
-
return existing.value;
|
|
279
|
-
}
|
|
280
|
-
const insertedRaw = yield* sql`
|
|
281
|
-
INSERT INTO ${sql(tables.testRuns)}
|
|
282
|
-
${sql.insert({
|
|
283
|
-
name
|
|
284
|
-
})}
|
|
285
|
-
RETURNING *;
|
|
286
|
-
`.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('getOrCreateCurrentTestRun')));
|
|
287
|
-
const inserted = yield* _effect.Schema.decodeUnknownEffect(TestRunsReadSchema)(insertedRaw).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getOrCreateCurrentTestRun')));
|
|
175
|
+
const createTestRun = _effect.Effect.fnUntraced(function* (input) {
|
|
176
|
+
const inserted = yield* decodeRuns(yield* sql`
|
|
177
|
+
INSERT INTO ${sql(_testRepositoryMigrations.tables.testRuns)}
|
|
178
|
+
${sql.insert({
|
|
179
|
+
...input,
|
|
180
|
+
state: 'Running'
|
|
181
|
+
})} RETURNING *;
|
|
182
|
+
`);
|
|
288
183
|
return yield* _effect.Effect.fromOption(_effect.Array.head(inserted)).pipe(_effect.Effect.mapError(() => new _RepositoryError.TestRunNotCreated({
|
|
289
|
-
testSuiteName: name
|
|
184
|
+
testSuiteName: input.name
|
|
290
185
|
})));
|
|
291
|
-
}
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
LIMIT -1 OFFSET ${keep};
|
|
302
|
-
`.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('clearStale')));
|
|
303
|
-
const staleTestRuns = yield* _effect.Schema.decodeUnknownEffect(TestRunsReadSchema)(raw).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('clearStale')));
|
|
304
|
-
if (staleTestRuns.length === 0) {
|
|
305
|
-
return;
|
|
186
|
+
}, sql.withTransaction);
|
|
187
|
+
const finishTestRun = _effect.Effect.fnUntraced(function* (run, state) {
|
|
188
|
+
const updated = _effect.Array.head(yield* decodeRuns(yield* sql`
|
|
189
|
+
UPDATE ${sql(_testRepositoryMigrations.tables.testRuns)} SET state = ${state}
|
|
190
|
+
WHERE id = ${run.id} AND state = 'Running' RETURNING *;
|
|
191
|
+
`));
|
|
192
|
+
if (_effect.Option.isNone(updated)) {
|
|
193
|
+
return yield* new _RepositoryError.TestRunNotFound({
|
|
194
|
+
testRunId: run.id
|
|
195
|
+
});
|
|
306
196
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
return;
|
|
197
|
+
}, sql.withTransaction);
|
|
198
|
+
const withTestRun = (input, execute) => _effect.Effect.acquireUseRelease(createTestRun(input), run => _effect.Effect.suspend(() => execute(run)).pipe(_effect.Effect.map(value => ({
|
|
199
|
+
run,
|
|
200
|
+
value
|
|
201
|
+
}))), (run, exit) => finishTestRun(run, _effect.Exit.isSuccess(exit) ? 'Complete' : 'Failed')).pipe(_effect.Effect.map(({
|
|
202
|
+
run,
|
|
203
|
+
value
|
|
204
|
+
}) => ({
|
|
205
|
+
run: new _TestRun.TestRun({
|
|
206
|
+
id: run.id,
|
|
207
|
+
name: run.name,
|
|
208
|
+
variant: run.variant,
|
|
209
|
+
state: 'Complete'
|
|
210
|
+
}),
|
|
211
|
+
value
|
|
212
|
+
})));
|
|
213
|
+
const commitTestRun = _effect.Effect.fnUntraced(function* (id) {
|
|
214
|
+
const found = yield* getTestRun(id);
|
|
215
|
+
if (_effect.Option.isNone(found)) {
|
|
216
|
+
return yield* new _RepositoryError.TestRunNotFound({
|
|
217
|
+
testRunId: id
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
const run = found.value;
|
|
221
|
+
if (run.state !== 'Complete') {
|
|
222
|
+
return yield* new _RepositoryError.TestRunIncomplete({
|
|
223
|
+
testSuiteName: run.name,
|
|
224
|
+
testRunId: run.id,
|
|
225
|
+
variant: run.variant
|
|
226
|
+
});
|
|
338
227
|
}
|
|
339
228
|
yield* sql`
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const commitCurrentTestRun = _effect.Effect.fnUntraced(function* ({
|
|
229
|
+
INSERT INTO ${sql(_testRepositoryMigrations.tables.testBaselines)}
|
|
230
|
+
${sql.insert({
|
|
231
|
+
name: run.name,
|
|
232
|
+
variant: run.variant,
|
|
233
|
+
testRun: run.id
|
|
234
|
+
})}
|
|
235
|
+
ON CONFLICT(name, variant) DO UPDATE SET testRun = excluded.testRun;
|
|
236
|
+
`;
|
|
237
|
+
}, sql.withTransaction);
|
|
238
|
+
const listTestRuns = _effect.Effect.fnUntraced(function* ({
|
|
351
239
|
name,
|
|
352
|
-
|
|
240
|
+
variant,
|
|
241
|
+
before,
|
|
242
|
+
limit
|
|
353
243
|
}) {
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
yield* sql`
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
244
|
+
const parsedLimit = yield* decodeRunLimit(limit);
|
|
245
|
+
const runs = yield* decodeListedRuns(yield* sql`
|
|
246
|
+
SELECT run.*, EXISTS(
|
|
247
|
+
SELECT 1 FROM ${sql(_testRepositoryMigrations.tables.testBaselines)} baseline
|
|
248
|
+
WHERE baseline.name = run.name AND baseline.variant = run.variant
|
|
249
|
+
AND baseline.testRun = run.id
|
|
250
|
+
) AS isBaseline
|
|
251
|
+
FROM ${sql(_testRepositoryMigrations.tables.testRuns)} run
|
|
252
|
+
WHERE run.name = ${name}
|
|
253
|
+
AND ${variant === undefined ? sql`1 = 1` : sql`run.variant = ${variant}`}
|
|
254
|
+
AND ${before === undefined ? sql`1 = 1` : sql`run.id < ${before}`}
|
|
255
|
+
ORDER BY run.id DESC LIMIT ${parsedLimit};
|
|
256
|
+
`);
|
|
257
|
+
return runs.map(({
|
|
258
|
+
isBaseline,
|
|
259
|
+
...run
|
|
260
|
+
}) => Object.assign(new _TestRun.TestRun(run), {
|
|
261
|
+
isBaseline: isBaseline === 1
|
|
262
|
+
}));
|
|
263
|
+
});
|
|
264
|
+
const listVariantBaselines = _effect.Effect.fnUntraced(function* (name) {
|
|
265
|
+
const variants = yield* decodeVariantBaselines(yield* sql`
|
|
266
|
+
SELECT variants.variant, run.id, run.name, run.state
|
|
267
|
+
FROM (
|
|
268
|
+
SELECT DISTINCT variant FROM ${sql(_testRepositoryMigrations.tables.testRuns)}
|
|
269
|
+
WHERE name = ${name}
|
|
270
|
+
) variants
|
|
271
|
+
LEFT JOIN ${sql(_testRepositoryMigrations.tables.testBaselines)} baseline
|
|
272
|
+
ON baseline.name = ${name} AND baseline.variant = variants.variant
|
|
273
|
+
LEFT JOIN ${sql(_testRepositoryMigrations.tables.testRuns)} run ON run.id = baseline.testRun
|
|
274
|
+
ORDER BY variants.variant;
|
|
275
|
+
`);
|
|
276
|
+
return variants.map(({
|
|
277
|
+
variant,
|
|
278
|
+
id,
|
|
279
|
+
name,
|
|
280
|
+
state
|
|
281
|
+
}) => ({
|
|
282
|
+
variant,
|
|
283
|
+
baseline: id === null || name === null || state === null ? _effect.Option.none() : _effect.Option.some(new _TestRun.TestRun({
|
|
284
|
+
id,
|
|
285
|
+
name,
|
|
286
|
+
variant,
|
|
287
|
+
state
|
|
288
|
+
}))
|
|
289
|
+
}));
|
|
382
290
|
});
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
getLastTestRunHash,
|
|
391
|
-
getPreviousTestRun,
|
|
291
|
+
return {
|
|
292
|
+
commitTestRun,
|
|
293
|
+
getTestRun,
|
|
294
|
+
getLatestTestRun,
|
|
295
|
+
getBaselineTestRun,
|
|
296
|
+
listTestRuns,
|
|
297
|
+
listVariantBaselines,
|
|
392
298
|
getTestResultsStream,
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
insertTestResults,
|
|
396
|
-
|
|
299
|
+
withTestRun,
|
|
300
|
+
withStats: use => (0, _testResultStats.withStats)(use).pipe(_effect.Effect.provideService(_sql.SqlClient.SqlClient, sql)),
|
|
301
|
+
insertTestResult: (result, run, schemas) => insertTestResults([result], run, schemas),
|
|
302
|
+
insertTestResults
|
|
397
303
|
};
|
|
398
|
-
return service;
|
|
399
304
|
});
|
|
400
305
|
//# sourceMappingURL=Test.repository.sqlite.js.map
|