@finos/legend-application-studio 28.13.3 → 28.13.4
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/lib/components/editor/ActivityBar.js +1 -1
- package/lib/components/editor/ActivityBar.js.map +1 -1
- package/lib/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.js +15 -15
- package/lib/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.js.map +1 -1
- package/lib/components/editor/editor-group/function-activator/FunctionEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/function-activator/FunctionEditor.js +10 -10
- package/lib/components/editor/editor-group/function-activator/FunctionEditor.js.map +1 -1
- package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.js +52 -16
- package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts +8 -2
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js +140 -4
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js.map +1 -1
- package/lib/stores/graph-modifier/DomainGraphModifierHelper.d.ts +1 -0
- package/lib/stores/graph-modifier/DomainGraphModifierHelper.d.ts.map +1 -1
- package/lib/stores/graph-modifier/DomainGraphModifierHelper.js +4 -1
- package/lib/stores/graph-modifier/DomainGraphModifierHelper.js.map +1 -1
- package/package.json +4 -4
- package/src/components/editor/ActivityBar.tsx +1 -1
- package/src/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.tsx +36 -36
- package/src/components/editor/editor-group/function-activator/FunctionEditor.tsx +86 -78
- package/src/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.tsx +156 -25
- package/src/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.ts +237 -5
- package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.ts +0 -1
- package/src/stores/graph-modifier/DomainGraphModifierHelper.ts +11 -0
@@ -22,17 +22,37 @@ import {
|
|
22
22
|
isNonNullable,
|
23
23
|
uuid,
|
24
24
|
type GeneratorFn,
|
25
|
+
LogEvent,
|
26
|
+
guaranteeNonNullable,
|
27
|
+
addUniqueEntry,
|
28
|
+
uniq,
|
29
|
+
assertTrue,
|
30
|
+
guaranteeType,
|
25
31
|
} from '@finos/legend-shared';
|
26
32
|
import {
|
27
|
-
FunctionTest,
|
28
33
|
type ConcreteFunctionDefinition,
|
29
34
|
type EmbeddedData,
|
30
|
-
type FunctionStoreTestData,
|
31
|
-
type FunctionTestSuite,
|
32
35
|
type TestResult,
|
33
36
|
type AtomicTest,
|
37
|
+
type EngineRuntime,
|
38
|
+
type ObserverContext,
|
39
|
+
type ValueSpecification,
|
40
|
+
FunctionTest,
|
34
41
|
UniqueTestId,
|
42
|
+
FunctionStoreTestData,
|
43
|
+
FunctionTestSuite,
|
35
44
|
RunTestsTestableInput,
|
45
|
+
RawLambda,
|
46
|
+
PackageableRuntime,
|
47
|
+
SimpleFunctionExpression,
|
48
|
+
LambdaFunctionInstanceValue,
|
49
|
+
SUPPORTED_FUNCTIONS,
|
50
|
+
matchFunctionName,
|
51
|
+
InstanceValue,
|
52
|
+
PackageableElementReference,
|
53
|
+
Database,
|
54
|
+
RelationalCSVData,
|
55
|
+
PackageableElementExplicitReference,
|
36
56
|
} from '@finos/legend-graph';
|
37
57
|
import {
|
38
58
|
TestablePackageableElementEditorState,
|
@@ -43,8 +63,95 @@ import { EmbeddedDataEditorState } from '../../data/DataEditorState.js';
|
|
43
63
|
import {
|
44
64
|
functionTestable_deleteDataStore,
|
45
65
|
functionTestable_setEmbeddedData,
|
66
|
+
function_addTestSuite,
|
46
67
|
} from '../../../../../graph-modifier/DomainGraphModifierHelper.js';
|
47
|
-
import {
|
68
|
+
import {
|
69
|
+
DEFAULT_TEST_ASSERTION_ID,
|
70
|
+
createDefaultEqualToJSONTestAssertion,
|
71
|
+
isTestPassing,
|
72
|
+
} from '../../../../utils/TestableUtils.js';
|
73
|
+
import { LEGEND_STUDIO_APP_EVENT } from '../../../../../../__lib__/LegendStudioEvent.js';
|
74
|
+
import { testSuite_addTest } from '../../../../../graph-modifier/Testable_GraphModifierHelper.js';
|
75
|
+
|
76
|
+
const addToFunctionMap = (
|
77
|
+
val: SimpleFunctionExpression,
|
78
|
+
functions: Map<string, SimpleFunctionExpression[]>,
|
79
|
+
): boolean => {
|
80
|
+
const values = functions.get(val.functionName) ?? [];
|
81
|
+
if (values.includes(val)) {
|
82
|
+
return false;
|
83
|
+
}
|
84
|
+
addUniqueEntry(values, val);
|
85
|
+
functions.set(val.functionName, values);
|
86
|
+
return true;
|
87
|
+
};
|
88
|
+
|
89
|
+
const collectSimpleFunctionExpressions = (
|
90
|
+
val: ValueSpecification,
|
91
|
+
functions: Map<string, SimpleFunctionExpression[]>,
|
92
|
+
): void => {
|
93
|
+
if (val instanceof SimpleFunctionExpression) {
|
94
|
+
const continueProcessing = addToFunctionMap(val, functions);
|
95
|
+
if (continueProcessing) {
|
96
|
+
val.parametersValues.forEach((v) =>
|
97
|
+
collectSimpleFunctionExpressions(v, functions),
|
98
|
+
);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
};
|
102
|
+
|
103
|
+
const resolveRuntimesFromQuery = (
|
104
|
+
func: ConcreteFunctionDefinition,
|
105
|
+
editorStore: EditorStore,
|
106
|
+
): EngineRuntime[] | undefined => {
|
107
|
+
try {
|
108
|
+
const body = func.expressionSequence;
|
109
|
+
const rawLambda = new RawLambda([], body);
|
110
|
+
const functions = new Map<string, SimpleFunctionExpression[]>();
|
111
|
+
const valueSpec =
|
112
|
+
editorStore.graphManagerState.graphManager.buildValueSpecification(
|
113
|
+
editorStore.graphManagerState.graphManager.serializeRawValueSpecification(
|
114
|
+
rawLambda,
|
115
|
+
),
|
116
|
+
editorStore.graphManagerState.graph,
|
117
|
+
);
|
118
|
+
if (valueSpec instanceof LambdaFunctionInstanceValue) {
|
119
|
+
const vals = guaranteeNonNullable(
|
120
|
+
valueSpec.values[0],
|
121
|
+
'function expected to be of type lambda',
|
122
|
+
).expressionSequence;
|
123
|
+
vals.forEach((v) => collectSimpleFunctionExpressions(v, functions));
|
124
|
+
const fromFunctions = Array.from(functions.keys())
|
125
|
+
.filter((v) => matchFunctionName(v, SUPPORTED_FUNCTIONS.FROM))
|
126
|
+
.map((e) => functions.get(e))
|
127
|
+
.flat()
|
128
|
+
.filter(isNonNullable);
|
129
|
+
const runtimeInstance: PackageableRuntime[] = [];
|
130
|
+
fromFunctions.forEach((v) => {
|
131
|
+
v.parametersValues.forEach((p) => {
|
132
|
+
if (p instanceof InstanceValue) {
|
133
|
+
p.values.forEach((pIn) => {
|
134
|
+
if (pIn instanceof PackageableElementReference) {
|
135
|
+
if (pIn.value instanceof PackageableRuntime) {
|
136
|
+
runtimeInstance.push(pIn.value);
|
137
|
+
}
|
138
|
+
}
|
139
|
+
});
|
140
|
+
}
|
141
|
+
});
|
142
|
+
});
|
143
|
+
return uniq(runtimeInstance.map((e) => e.runtimeValue).flat());
|
144
|
+
}
|
145
|
+
return [];
|
146
|
+
} catch (error) {
|
147
|
+
assertErrorThrown(error);
|
148
|
+
editorStore.applicationStore.logService.error(
|
149
|
+
LogEvent.create(LEGEND_STUDIO_APP_EVENT.SERVICE_TEST_SETUP_FAILURE),
|
150
|
+
error,
|
151
|
+
);
|
152
|
+
return undefined;
|
153
|
+
}
|
154
|
+
};
|
48
155
|
|
49
156
|
export class FunctionStoreTestDataState {
|
50
157
|
readonly editorStore: EditorStore;
|
@@ -186,6 +293,25 @@ class FunctionTestDataState {
|
|
186
293
|
}
|
187
294
|
}
|
188
295
|
|
296
|
+
export const createFunctionTest = (
|
297
|
+
id: string,
|
298
|
+
observerContext: ObserverContext,
|
299
|
+
suite?: FunctionTestSuite | undefined,
|
300
|
+
): FunctionTest => {
|
301
|
+
const funcionTest = new FunctionTest();
|
302
|
+
funcionTest.id = id;
|
303
|
+
funcionTest.assertions = [
|
304
|
+
createDefaultEqualToJSONTestAssertion(DEFAULT_TEST_ASSERTION_ID),
|
305
|
+
];
|
306
|
+
if (suite) {
|
307
|
+
funcionTest.__parent = suite;
|
308
|
+
testSuite_addTest(suite, funcionTest, observerContext);
|
309
|
+
}
|
310
|
+
const assertion = createDefaultEqualToJSONTestAssertion(`expectedAssertion`);
|
311
|
+
funcionTest.assertions = [assertion];
|
312
|
+
assertion.parentTest = funcionTest;
|
313
|
+
return funcionTest;
|
314
|
+
};
|
189
315
|
export class FunctionTestSuiteState extends TestableTestSuiteEditorState {
|
190
316
|
readonly functionTestableState: FunctionTestableState;
|
191
317
|
override suite: FunctionTestSuite;
|
@@ -209,9 +335,13 @@ export class FunctionTestSuiteState extends TestableTestSuiteEditorState {
|
|
209
335
|
makeObservable(this, {
|
210
336
|
dataState: observable,
|
211
337
|
showCreateModal: observable,
|
338
|
+
selectTestState: observable,
|
339
|
+
changeTest: observable,
|
212
340
|
buildTestState: action,
|
213
341
|
deleteTest: action,
|
214
342
|
buildTestStates: action,
|
343
|
+
setShowModal: action,
|
344
|
+
addNewTest: action,
|
215
345
|
});
|
216
346
|
this.functionTestableState = functionTestableState;
|
217
347
|
this.suite = suite;
|
@@ -224,6 +354,10 @@ export class FunctionTestSuiteState extends TestableTestSuiteEditorState {
|
|
224
354
|
this.selectTestState = this.testStates[0];
|
225
355
|
}
|
226
356
|
|
357
|
+
setShowModal(val: boolean): void {
|
358
|
+
this.showCreateModal = val;
|
359
|
+
}
|
360
|
+
|
227
361
|
buildTestStates(): FunctionTestState[] {
|
228
362
|
return this.suite.tests
|
229
363
|
.map((t) => this.buildTestState(t))
|
@@ -236,13 +370,34 @@ export class FunctionTestSuiteState extends TestableTestSuiteEditorState {
|
|
236
370
|
}
|
237
371
|
return undefined;
|
238
372
|
}
|
373
|
+
|
374
|
+
addNewTest(id: string): void {
|
375
|
+
const test = createFunctionTest(
|
376
|
+
id,
|
377
|
+
this.editorStore.changeDetectionState.observerContext,
|
378
|
+
this.suite,
|
379
|
+
);
|
380
|
+
|
381
|
+
testSuite_addTest(
|
382
|
+
this.suite,
|
383
|
+
test,
|
384
|
+
this.functionTestableState.editorStore.changeDetectionState
|
385
|
+
.observerContext,
|
386
|
+
);
|
387
|
+
const testState = this.buildTestState(test);
|
388
|
+
if (testState) {
|
389
|
+
this.testStates.push(testState);
|
390
|
+
}
|
391
|
+
this.selectTestState = testState;
|
392
|
+
}
|
239
393
|
}
|
240
394
|
|
241
395
|
export class FunctionTestableState extends TestablePackageableElementEditorState {
|
242
396
|
readonly functionEditorState: FunctionEditorState;
|
397
|
+
declare selectedTestSuite: FunctionTestSuiteState | undefined;
|
243
398
|
|
244
399
|
runningSuite: FunctionTestSuite | undefined;
|
245
|
-
|
400
|
+
createSuiteModal = false;
|
246
401
|
|
247
402
|
constructor(functionEditorState: FunctionEditorState) {
|
248
403
|
super(functionEditorState, functionEditorState.functionElement);
|
@@ -252,12 +407,15 @@ export class FunctionTestableState extends TestablePackageableElementEditorState
|
|
252
407
|
selectedTestSuite: observable,
|
253
408
|
testableResults: observable,
|
254
409
|
runningSuite: observable,
|
410
|
+
createSuiteModal: observable,
|
255
411
|
init: action,
|
256
412
|
buildTestSuiteState: action,
|
257
413
|
deleteTestSuite: action,
|
258
414
|
changeSuite: action,
|
259
415
|
handleNewResults: action,
|
260
416
|
setRenameComponent: action,
|
417
|
+
clearTestResultsForSuite: action,
|
418
|
+
setCreateSuite: action,
|
261
419
|
runTestable: flow,
|
262
420
|
runSuite: flow,
|
263
421
|
runAllFailingSuites: flow,
|
@@ -313,6 +471,80 @@ export class FunctionTestableState extends TestablePackageableElementEditorState
|
|
313
471
|
}
|
314
472
|
}
|
315
473
|
|
474
|
+
setCreateSuite(val: boolean): void {
|
475
|
+
this.createSuiteModal = val;
|
476
|
+
}
|
477
|
+
|
478
|
+
createSuite(suiteName: string, testName: string): void {
|
479
|
+
const functionSuite = new FunctionTestSuite();
|
480
|
+
functionSuite.id = suiteName;
|
481
|
+
const engineRuntimes = resolveRuntimesFromQuery(
|
482
|
+
this.function,
|
483
|
+
this.editorStore,
|
484
|
+
);
|
485
|
+
if (engineRuntimes?.length) {
|
486
|
+
try {
|
487
|
+
assertTrue(
|
488
|
+
engineRuntimes.length === 1,
|
489
|
+
`Function Test Suite Only supports One Runtime at this time. Found ${engineRuntimes.length}`,
|
490
|
+
);
|
491
|
+
const engineRuntime = guaranteeNonNullable(engineRuntimes[0]);
|
492
|
+
assertTrue(
|
493
|
+
!(
|
494
|
+
engineRuntime.connectionStores.length &&
|
495
|
+
engineRuntime.connections.length
|
496
|
+
),
|
497
|
+
`Runtime found has two connection types defined. Please use connection stores only`,
|
498
|
+
);
|
499
|
+
const stores = [
|
500
|
+
...engineRuntime.connections
|
501
|
+
.map((e) =>
|
502
|
+
e.storeConnections.map((s) => s.connection.store.value).flat(),
|
503
|
+
)
|
504
|
+
.flat(),
|
505
|
+
...engineRuntime.connectionStores
|
506
|
+
.map((e) => e.storePointers.map((sPt) => sPt.value))
|
507
|
+
.flat(),
|
508
|
+
];
|
509
|
+
assertTrue(Boolean(stores.length), 'No runtime store found');
|
510
|
+
assertTrue(
|
511
|
+
stores.length === 1,
|
512
|
+
'Only one store supported in runtime for function tests',
|
513
|
+
);
|
514
|
+
const store = guaranteeNonNullable(stores[0]);
|
515
|
+
guaranteeType(
|
516
|
+
store,
|
517
|
+
Database,
|
518
|
+
'Only Database stores supported now for function test',
|
519
|
+
);
|
520
|
+
const relational = new RelationalCSVData();
|
521
|
+
const data = new FunctionStoreTestData();
|
522
|
+
data.store = PackageableElementExplicitReference.create(store);
|
523
|
+
data.data = relational;
|
524
|
+
functionSuite.testData = [data];
|
525
|
+
} catch (error) {
|
526
|
+
assertErrorThrown(error);
|
527
|
+
this.editorStore.applicationStore.notificationService.notifyError(
|
528
|
+
`Unable to create function test suite: ${error.message}`,
|
529
|
+
);
|
530
|
+
return;
|
531
|
+
}
|
532
|
+
}
|
533
|
+
createFunctionTest(
|
534
|
+
testName,
|
535
|
+
this.editorStore.changeDetectionState.observerContext,
|
536
|
+
functionSuite,
|
537
|
+
);
|
538
|
+
// set test suite
|
539
|
+
function_addTestSuite(
|
540
|
+
this.function,
|
541
|
+
functionSuite,
|
542
|
+
this.editorStore.changeDetectionState.observerContext,
|
543
|
+
);
|
544
|
+
this.changeSuite(functionSuite);
|
545
|
+
this.setCreateSuite(false);
|
546
|
+
}
|
547
|
+
|
316
548
|
*runSuite(suite: FunctionTestSuite): GeneratorFn<void> {
|
317
549
|
try {
|
318
550
|
this.runningSuite = suite;
|
@@ -72,6 +72,7 @@ import {
|
|
72
72
|
isStubbed_PackageableElement,
|
73
73
|
getOtherAssociatedProperty,
|
74
74
|
observe_EmbeddedData,
|
75
|
+
observe_FunctionTestSuite,
|
75
76
|
} from '@finos/legend-graph';
|
76
77
|
|
77
78
|
// --------------------------------------------- Packageable Element -------------------------------------
|
@@ -404,6 +405,16 @@ export const functionTestable_deleteDataStore = action(
|
|
404
405
|
},
|
405
406
|
);
|
406
407
|
|
408
|
+
export const function_addTestSuite = action(
|
409
|
+
(
|
410
|
+
_func: ConcreteFunctionDefinition,
|
411
|
+
val: FunctionTestSuite,
|
412
|
+
context: ObserverContext,
|
413
|
+
): void => {
|
414
|
+
addUniqueEntry(_func.tests, observe_FunctionTestSuite(val, context));
|
415
|
+
},
|
416
|
+
);
|
417
|
+
|
407
418
|
// --------------------------------------------- Enumeration -------------------------------------
|
408
419
|
|
409
420
|
export const enum_setName = action((val: Enum, value: string): void => {
|