UNPKG

@finos/legend-studio

Version:
294 lines (272 loc) 9.44 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { type TestResult, type Service, TestPassed, TestFailed, ServiceTestSuite, TestData, ServiceTest, RunTestsTestableInput, AtomicTestId, DEFAULT_TEST_SUITE_PREFIX, DEFAULT_TEST_PREFIX, TestError, MultiExecutionServiceTestResult, } from '@finos/legend-graph'; import { type GeneratorFn, addUniqueEntry, assertErrorThrown, filterByType, ActionState, deleteEntry, isNonNullable, generateEnumerableNameFromToken, getNullableFirstElement, } from '@finos/legend-shared'; import { action, flow, makeObservable, observable } from 'mobx'; import type { EditorStore } from '../../../../EditorStore.js'; import { service_addTest, service_addTestSuite, service_deleteTestSuite, } from '../../../../graphModifier/DSLService_GraphModifierHelper.js'; import { createEmptyEqualToJsonAssertion } from '../../../../shared/testable/TestableUtils.js'; import type { ServiceEditorState } from '../ServiceEditorState.js'; import { ServiceTestDataState } from './ServiceTestDataState.js'; import { SERIALIZATION_FORMAT, ServiceTestState, } from './ServiceTestEditorState.js'; const createEmptyServiceTestSuite = (service: Service): ServiceTestSuite => { const suite = new ServiceTestSuite(); suite.id = generateEnumerableNameFromToken( service.tests.map((s) => s.id), DEFAULT_TEST_SUITE_PREFIX, ); suite.testData = new TestData(); const test = new ServiceTest(); test.serializationFormat = SERIALIZATION_FORMAT.PURE; test.id = generateEnumerableNameFromToken([], DEFAULT_TEST_PREFIX); test.__parent = suite; suite.tests = [test]; const assertion = createEmptyEqualToJsonAssertion(test); test.assertions = [assertion]; return suite; }; export class ServiceTestSuiteState { readonly editorStore: EditorStore; readonly testableState: ServiceTestableState; suite: ServiceTestSuite; testDataState: ServiceTestDataState; selectedTestState: ServiceTestState | undefined; testStates: ServiceTestState[] = []; testToRename: ServiceTest | undefined; isRunningTest = ActionState.create(); constructor(suite: ServiceTestSuite, testableState: ServiceTestableState) { makeObservable(this, { editorStore: false, testableState: false, testToRename: observable, selectedTestState: observable, setSelectedTestState: action, setTestToRename: action, addServiceTest: action, runSuite: flow, runFailingTests: flow, }); this.editorStore = testableState.editorStore; this.testableState = testableState; this.suite = suite; this.testStates = this.suite.tests .filter(filterByType(ServiceTest)) .map((test) => new ServiceTestState(this, test)); this.selectedTestState = this.testStates[0]; this.testDataState = new ServiceTestDataState(this.suite.testData, this); } setTestToRename(test: ServiceTest | undefined): void { this.testToRename = test; } setSelectedTestState(val: ServiceTestState | undefined): void { this.selectedTestState = val; } addServiceTest(): void { const test = new ServiceTest(); test.serializationFormat = SERIALIZATION_FORMAT.PURE; test.id = generateEnumerableNameFromToken( this.suite.tests.map((t) => t.id), DEFAULT_TEST_PREFIX, ); test.__parent = this.suite; const state = new ServiceTestState(this, test); state.addAssertion(); this.selectedTestState = state; service_addTest(this.suite, test); addUniqueEntry(this.testStates, state); } deleteTest(testState: ServiceTestState): void { deleteEntry(this.suite.tests, testState.test); deleteEntry(this.testStates, testState); this.selectedTestState = this.selectedTestState === testState ? this.testStates[0] : this.selectedTestState; } *runSuite(): GeneratorFn<void> { try { this.isRunningTest.inProgress(); this.testStates.forEach((t) => t.resetResult()); this.testStates.forEach((t) => t.runningTestAction.inProgress()); const service = this.testableState.serviceEditorState.service; const input = new RunTestsTestableInput(service); input.unitTestIds = this.suite.tests.map( (t) => new AtomicTestId(this.suite, t), ); const testResults = (yield this.editorStore.graphManagerState.graphManager.runTests( [input], this.editorStore.graphManagerState.graph, )) as TestResult[]; testResults.forEach((result) => { const state = this.testStates.find( (t) => t.test === result.atomicTestId.atomicTest, ); state?.handleTestResult(result); }); this.isRunningTest.complete(); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.notifyError(error); this.isRunningTest.fail(); } finally { this.testStates.forEach((t) => t.runningTestAction.complete()); } } *runFailingTests(): GeneratorFn<void> { try { this.isRunningTest.inProgress(); const service = this.testableState.serviceEditorState.service; const input = new RunTestsTestableInput(service); input.unitTestIds = this.testStates .map((testState) => { const result = testState.testResultState.result; if (result instanceof TestFailed || result instanceof TestError) { testState.runningTestAction.inProgress(); return new AtomicTestId(this.suite, testState.test); } return undefined; }) .filter(isNonNullable); const testResults = (yield this.editorStore.graphManagerState.graphManager.runTests( [input], this.editorStore.graphManagerState.graph, )) as TestResult[]; testResults.forEach((result) => { const state = this.testStates.find( (t) => t.test === result.atomicTestId.atomicTest, ); state?.handleTestResult(result); }); this.isRunningTest.complete(); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.notifyError(error); this.isRunningTest.fail(); } finally { this.testStates.forEach((t) => t.runningTestAction.complete()); } } get testCount(): number { return this.testStates.length; } get testPassed(): number { return this.testStates.filter( (e) => e.testResultState.result instanceof TestPassed || (e.testResultState.result instanceof MultiExecutionServiceTestResult && Array.from( e.testResultState.result.keyIndexedTestResults.values(), ).every((kv) => kv instanceof TestPassed)), ).length; } get testFailed(): number { return this.testCount - this.testPassed; } } export class ServiceTestableState { readonly editorStore: EditorStore; readonly serviceEditorState: ServiceEditorState; selectedSuiteState: ServiceTestSuiteState | undefined; suiteToRename: ServiceTestSuite | undefined; constructor( editorStore: EditorStore, serviceEditorState: ServiceEditorState, ) { makeObservable(this, { editorStore: false, serviceEditorState: false, selectedSuiteState: observable, suiteToRename: observable, initSuites: action, addTestSuite: action, changeSuite: action, setSuiteToRename: action, deleteSuite: action, }); this.editorStore = editorStore; this.serviceEditorState = serviceEditorState; this.initSuites(); } setSuiteToRename(testSuite: ServiceTestSuite | undefined): void { this.suiteToRename = testSuite; } deleteSuite(testSuite: ServiceTestSuite): void { service_deleteTestSuite(this.serviceEditorState.service, testSuite); if (this.selectedSuiteState?.suite === testSuite) { this.selectedSuiteState = this.serviceEditorState.service.tests.length ? new ServiceTestSuiteState( this.serviceEditorState.service.tests[0] as ServiceTestSuite, this, ) : undefined; } } changeSuite(suite: ServiceTestSuite): void { this.selectedSuiteState = new ServiceTestSuiteState(suite, this); } initSuites(): void { const serviceSuite = getNullableFirstElement( this.serviceEditorState.service.tests, ); if (serviceSuite instanceof ServiceTestSuite) { this.selectedSuiteState = new ServiceTestSuiteState(serviceSuite, this); } else { this.selectedSuiteState = undefined; } } addTestSuite(): void { const suite = createEmptyServiceTestSuite(this.serviceEditorState.service); service_addTestSuite( this.serviceEditorState.service, suite, this.serviceEditorState.editorStore.changeDetectionState.observerContext, ); this.selectedSuiteState = new ServiceTestSuiteState(suite, this); } }