From 376fbdab8588ad02b66912b3628fa6f5951e8de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ola=20Flisb=C3=A4ck?= Date: Wed, 29 Mar 2023 16:50:25 +0200 Subject: [PATCH] feat: add ExperimentStatus class --- src/api.ts | 4 +- src/executionStatus.ts | 40 ++++++++++++++++++++ src/experiment.ts | 5 ++- src/index.ts | 2 + src/types/index.d.ts | 2 +- tests/integration/integration.test.ts | 53 ++++++++++++++++++++++++++- 6 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 src/executionStatus.ts diff --git a/src/api.ts b/src/api.ts index 6954261..f7e488e 100644 --- a/src/api.ts +++ b/src/api.ts @@ -13,7 +13,7 @@ import { CaseId, CaseTrajectories, CustomFunction, - ExecutionStatus, + ExecutionStatusType, ExperimentId, ExperimentTrajectories, WorkspaceDefinition, @@ -385,7 +385,7 @@ class Api { }: { experimentId: ExperimentId workspaceId: WorkspaceId - }): Promise { + }): Promise { return new Promise((resolve, reject) => { this.ensureImpactToken() .then(() => { diff --git a/src/executionStatus.ts b/src/executionStatus.ts new file mode 100644 index 0000000..3ebc51f --- /dev/null +++ b/src/executionStatus.ts @@ -0,0 +1,40 @@ +import { ExecutionStatusType } from './types' + +class ExecutionStatus { + status: ExecutionStatusType + + constructor(status: ExecutionStatusType) { + this.status = status + } + + getNbrCompilationDone = () => + this.status?.progresses?.filter( + (p) => + (p.stage === 'compilation' && p.done) || + p.stage === 'simulation' + ).length || 0 + + getNbrSimulations = () => + this.status?.progresses?.filter((p) => p.stage === 'simulation') + .length || 0 + + getNbrSimulationDone = () => + this.status?.progresses?.filter( + (p) => p.stage === 'simulation' && p.done + ).length || 0 + + getCompilationProgress = () => + this.status?.progresses + ? this.getNbrCompilationDone() / this.status.progresses.length + : 0 + + getSimulationProgress = () => { + if (this.getNbrSimulations() === 0) { + return 0 + } + return this.status?.progresses + ? this.getNbrSimulationDone() / this.getNbrSimulations() + : 0 + } +} +export default ExecutionStatus diff --git a/src/experiment.ts b/src/experiment.ts index 3d65830..4e72bf0 100644 --- a/src/experiment.ts +++ b/src/experiment.ts @@ -6,6 +6,7 @@ import { } from './types' import Api from './api' import Case from './case' +import ExecutionStatus from './executionStatus' const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)) @@ -81,10 +82,12 @@ class Experiment { } async getExecutionStatus() { - return await this.api.getExecutionStatus({ + const status = await this.api.getExecutionStatus({ experimentId: this.id, workspaceId: this.workspaceId, }) + + return new ExecutionStatus(status) } } diff --git a/src/index.ts b/src/index.ts index 621c9ee..91ba50f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ import ExperimentDefinition from './experiment-definition' import { CaseTrajectories, CustomFunction, + ExecutionStatusType, ExperimentId, ExperimentTrajectories, ModelicaExperimentExtensions, @@ -30,6 +31,7 @@ export { CaseTrajectories, Client, CustomFunction, + ExecutionStatusType, ExperimentDefinition, Experiment, ExperimentId, diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 6885996..bdbadf8 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -5,7 +5,7 @@ export type Case = components['schemas']['Case'] export type CustomFunction = operations['getCustomFunction']['responses']['200']['content']['application/json'] -export type ExecutionStatus = +export type ExecutionStatusType = operations['getExecutionStatus']['responses']['200']['content']['application/json'] export type WorkspaceDefinition = components['schemas']['Workspace'] diff --git a/tests/integration/integration.test.ts b/tests/integration/integration.test.ts index ea04e95..5a9fd4d 100644 --- a/tests/integration/integration.test.ts +++ b/tests/integration/integration.test.ts @@ -10,6 +10,8 @@ import basicExperimentDefinition from './basicExperimentDefinition.json' dotenv.config() +const TwentySeconds = 20 * 1000 + const getClient = (options?: { impactApiKey?: string jupyterHubToken?: string @@ -83,7 +85,7 @@ test( const customFunctions = await testWorkspace.getCustomFunctions() expect(customFunctions.length).toBeGreaterThanOrEqual( - ['linearize', 'dynamic', 'steady state'].length + ['dynamic', 'steady state'].length ) try { @@ -149,5 +151,52 @@ test( throw new Error('Caught unexpected error while executing test') } }, - 20 * 1000 + TwentySeconds +) + +test( + 'Run simulation and track progress', + async () => { + const experimentDefinition = ExperimentDefinition.from( + basicExperimentDefinition + ) + + const client = getClient() + const WorkspaceName = 'simulation-progress' + + let testWorkspace + try { + testWorkspace = await client.getWorkspace(WorkspaceName) + } catch (e) { + testWorkspace = await client.createWorkspace({ + name: WorkspaceName, + }) + } + + expect(testWorkspace.name).toEqual(WorkspaceName) + + try { + let done = false + const experiment = await testWorkspace.executeExperiment({ + caseIds: ['case_1', 'case_2'], + experimentDefinition, + }) + while (!done) { + const status = await experiment.getExecutionStatus() + + await new Promise((resolve) => setTimeout(resolve, 100)) + + if (status.getSimulationProgress() === 1) { + expect(status.getCompilationProgress() === 1) + done = true + } + } + } catch (e) { + if (e instanceof Error) { + console.log(e.toString()) + } + throw new Error('Caught unexpected error while executing test') + } + }, + TwentySeconds )