This is an automated email from the ASF dual-hosted git repository. SvenO3 pushed a commit to branch 4491-create-e2e-tests-for-critical-adapter-and-pipeline-updates in repository https://gitbox.apache.org/repos/asf/streampipes.git
commit 6f3a94af0c8ba73202c34a85aae22793c6a8c1b1 Author: Sven Oehler <[email protected]> AuthorDate: Wed May 20 14:57:47 2026 +0200 Add cypress tests for adapter schema updates --- ui/cypress/support/utils/chart/ChartBtns.ts | 8 + ui/cypress/support/utils/connect/ConnectBtns.ts | 16 ++ ui/cypress/support/utils/pipeline/PipelineBtns.ts | 68 ++++++++ .../editAdapterDataLakeSchemaUpdate.spec.ts | 149 +++++++++++++++++ .../editAdapterSettingsAndPipeline.smoke.spec.ts | 15 +- .../chart-view/chart-view.component.html | 13 ++ ...adapter-started-update-migration.component.html | 179 +++++++++++++++------ .../pipeline-started-status.component.html | 4 +- .../measurement-update-dialog.component.html | 15 +- .../pipeline-notifications.component.html | 3 +- 10 files changed, 409 insertions(+), 61 deletions(-) diff --git a/ui/cypress/support/utils/chart/ChartBtns.ts b/ui/cypress/support/utils/chart/ChartBtns.ts index 1d7df66aa4..cf51949cae 100644 --- a/ui/cypress/support/utils/chart/ChartBtns.ts +++ b/ui/cypress/support/utils/chart/ChartBtns.ts @@ -106,6 +106,14 @@ export class ChartBtns { return cy.dataCy('edit-data-view-' + dataViewName.replaceAll(' ', '')); } + public static chartSyncProblemIcon() { + return cy.dataCy('chart-sync-problem-icon', { timeout: 60000 }); + } + + public static chartRequiresAttentionWarning() { + return cy.dataCy('chart-requires-attention-warning'); + } + public static editWidget(widgetName: string) { return cy.dataCy('edit-' + widgetName); } diff --git a/ui/cypress/support/utils/connect/ConnectBtns.ts b/ui/cypress/support/utils/connect/ConnectBtns.ts index 3ef596ba0f..6d300ea502 100644 --- a/ui/cypress/support/utils/connect/ConnectBtns.ts +++ b/ui/cypress/support/utils/connect/ConnectBtns.ts @@ -72,6 +72,22 @@ export class ConnectBtns { return cy.dataCy('btn-update-adapter-migrate-pipelines'); } + public static adapterEditWarning() { + return cy.dataCy('sp-connect-adapter-edit-warning', { timeout: 10000 }); + } + + public static adapterManualPipelineMigrationWarning() { + return cy.dataCy('adapter-manual-pipeline-migration-warning', { + timeout: 10000, + }); + } + + public static adapterChartEditWarning() { + return cy.dataCy('sp-connect-adapter-chart-edit-warning', { + timeout: 10000, + }); + } + public static nextBtn() { return cy.get('button').contains('Next').parent(); } diff --git a/ui/cypress/support/utils/pipeline/PipelineBtns.ts b/ui/cypress/support/utils/pipeline/PipelineBtns.ts index 0f8ca3487c..b40d50fc1b 100644 --- a/ui/cypress/support/utils/pipeline/PipelineBtns.ts +++ b/ui/cypress/support/utils/pipeline/PipelineBtns.ts @@ -57,6 +57,27 @@ export class PipelineBtns { public static saveElementConfigBtn() { return cy.dataCy('sp-element-configuration-save'); } + + public static mappingCheckbox(fieldName: string) { + return cy.dataCy(fieldName).find('.mdc-checkbox'); + } + + public static staticPropertyInput(fieldName: string) { + return cy.dataCy(fieldName); + } + + public static outputAddField() { + return cy.dataCy('add-field'); + } + + public static outputRuntimeName() { + return cy.dataCy('runtime-name'); + } + + public static outputRuntimeType() { + return cy.dataCy('runtime-type'); + } + public static savePipelineBtn() { return cy.dataCy('sp-editor-save-pipeline'); } @@ -73,6 +94,53 @@ export class PipelineBtns { return cy.dataCy('sp-editor-apply'); } + public static pipelineStartedError() { + return cy.dataCy('sp-pipeline-started-error', { timeout: 15000 }); + } + + public static updateAndMigratePipeline() { + return cy.dataCy('btn-update-pipeline-migrate'); + } + + public static pipelineEditWarning() { + return cy.dataCy('sp-pipeline-edit-warning', { timeout: 60000 }); + } + + public static pipelineMeasurementEditWarning() { + return cy.dataCy('sp-pipeline-measurement-edit-warning', { + timeout: 60000, + }); + } + + public static pipelineChartEditWarning() { + return cy.dataCy('sp-pipeline-chart-edit-warning', { + timeout: 60000, + }); + } + + public static pipelineWarningIcon() { + return cy.dataCy('pipeline-warning-icon', { timeout: 60000 }); + } + + public static pipelineSyncProblemIcon() { + return cy.dataCy('pipeline-sync-problem-icon', { timeout: 60000 }); + } + + public static pipelineNotification() { + return cy.dataCy('pipeline-notification'); + } + + public static acknowledgePipelineNotification() { + return cy.dataCy('acknowledge-pipeline-notification-btn'); + } + + public static pipelineMeasurementUpdateDialog() { + return cy.dataCy('measurement-update-dialog'); + } + public static measurementUpdateDialogEditPipelineBtn() { + return cy.dataCy('edit-pipeline-btn'); + } + public static navigateToPipelineOverview() { return cy.dataCy('sp-navigate-to-pipeline-overview', { timeout: 15000, diff --git a/ui/cypress/tests/connect/editAdapterDataLakeSchemaUpdate.spec.ts b/ui/cypress/tests/connect/editAdapterDataLakeSchemaUpdate.spec.ts new file mode 100644 index 0000000000..2a9488bb67 --- /dev/null +++ b/ui/cypress/tests/connect/editAdapterDataLakeSchemaUpdate.spec.ts @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 { ConnectUtils } from '../../support/utils/connect/ConnectUtils'; +import { ConnectBtns } from '../../support/utils/connect/ConnectBtns'; +import { PipelineUtils } from '../../support/utils/pipeline/PipelineUtils'; +import { PipelineBtns } from '../../support/utils/pipeline/PipelineBtns'; +import { ChartUtils } from '../../support/utils/chart/ChartUtils'; +import { ChartBtns } from '../../support/utils/chart/ChartBtns'; +import { SharedUtils } from '../../support/utils/shared/SharedUtils'; +import { SharedBtns } from '../../support/utils/shared/SharedBtns'; +import { CompactAdapterUtils } from '../../support/utils/connect/CompactAdapterUtils'; + +describe('Test adapter updates with data lake schema changes', () => { + const adapterName = 'Test'; + const chartName = 'Chart Density'; + + beforeEach('Setup Test', () => { + cy.initStreamPipesTest(); + }); + + it('Test adapter update with a field datatype change', () => { + createAdapter(); + + updateAdapterTransformationScript( + 'event.density = "test";\n out.collect(event);\n', + ); + + ConnectBtns.adapterEditWarning().should('be.visible'); + ConnectBtns.adapterManualPipelineMigrationWarning().should( + 'be.visible', + ); + + ConnectBtns.adapterChartEditWarning().should('not.exist'); + ConnectBtns.updateAndMigratePipelines().click(); + ConnectBtns.connectAdapterAddedSuccessfully().should('be.visible'); + ConnectUtils.closeAdapterPreview(); + + PipelineUtils.goToPipelines(); + PipelineBtns.pipelineSyncProblemIcon().should('be.visible'); + PipelineBtns.pipelineWarningIcon().should('be.visible'); + + PipelineBtns.pipelineWarningIcon().click(); + PipelineBtns.pipelineNotification().contains( + 'density (http://www.w3.org/2001/XMLSchema#float -> http://www.w3.org/2001/XMLSchema#string)', + ); + PipelineBtns.acknowledgePipelineNotification().click(); + + PipelineBtns.pipelineSyncProblemIcon().click(); + PipelineBtns.pipelineMeasurementUpdateDialog().should('be.visible'); + PipelineBtns.measurementUpdateDialogEditPipelineBtn().click(); + + PipelineBtns.savePipelineBtn().click(); + PipelineBtns.editorApplyBtn().click(); + PipelineBtns.pipelineStartedError(); + }); + + it('Test adapter update with a chart field deletion', () => { + createAdapter(); + addTableChart(adapterName); + + updateAdapterTransformationScript( + 'delete event.density;\n out.collect(event);\n', + ); + + ConnectBtns.adapterEditWarning().should('be.visible'); + ConnectBtns.adapterChartEditWarning().contains(chartName); + ConnectBtns.adapterChartEditWarning().contains('density'); + ConnectBtns.updateAndMigratePipelines().click(); + ConnectBtns.connectAdapterAddedSuccessfully().should('be.visible'); + ConnectUtils.closeAdapterPreview(); + + ChartUtils.goToDatalake(); + ChartBtns.chartSyncProblemIcon().should('be.visible'); + ChartBtns.chartSyncProblemIcon().click(); + + ChartBtns.chartRequiresAttentionWarning().should('be.visible'); + ChartBtns.chartRequiresAttentionWarning().contains('density'); + }); + + it('Test adapter update with an added field', () => { + createAdapter(); + addTableChart(adapterName); + + updateAdapterTransformationScript( + 'event.adapter_added = 1;\n out.collect(event);\n', + ); + + ConnectBtns.adapterEditWarning().should('not.exist'); + ConnectBtns.adapterManualPipelineMigrationWarning().should('not.exist'); + ConnectBtns.adapterChartEditWarning().should('not.exist'); + ConnectUtils.closeAdapterPreview(); + + PipelineUtils.goToPipelines(); + PipelineBtns.pipelineSyncProblemIcon().should('not.exist'); + PipelineBtns.pipelineWarningIcon().should('not.exist'); + + ChartUtils.goToDatalake(); + ChartBtns.chartSyncProblemIcon().should('not.exist'); + }); + + function updateAdapterTransformationScript(script: string) { + ConnectUtils.goToConnect(); + ConnectBtns.openActionsMenu(adapterName); + ConnectBtns.editAdapter().click(); + + ConnectBtns.adapterSettingsNextBtn().click(); + ConnectBtns.scriptActiveToggle().click(); + ConnectUtils.replaceAdapterScript(script); + ConnectBtns.configureSchemaRunScriptBtn().click(); + + ConnectBtns.configureSchemaNextBtn().click(); + SharedUtils.confirmDialogVisible(); + SharedBtns.confirmDialogConfirmBtn().click(); + + ConnectUtils.finishConfigureFieldsConfiguration(); + ConnectBtns.storeEditAdapter().click(); + } + + function addTableChart(measurementName: string) { + ChartUtils.addDataViewAndTableWidget(chartName, measurementName, true); + ChartUtils.saveDataViewConfiguration(); + ChartUtils.checkAmount(1); + } + + function createAdapter() { + const compactAdapter = CompactAdapterUtils.getMachineDataSimulator() + .withTimestampProperty('timestamp') + .setStart() + .setPersist() + .build(); + CompactAdapterUtils.storeCompactAdapter(compactAdapter); + } +}); diff --git a/ui/cypress/tests/connect/editAdapterSettingsAndPipeline.smoke.spec.ts b/ui/cypress/tests/connect/editAdapterSettingsAndPipeline.smoke.spec.ts index 51d0ca9f8f..25976d49f0 100644 --- a/ui/cypress/tests/connect/editAdapterSettingsAndPipeline.smoke.spec.ts +++ b/ui/cypress/tests/connect/editAdapterSettingsAndPipeline.smoke.spec.ts @@ -53,7 +53,7 @@ describe('Test Edit Adapter and Pipeline', () => { }); it('Edit adapter and test Pipeline behaviour', () => { - // Edit Apater and select pressure + // Edit Adapter and select pressure ConnectUtils.goToConnect(); ConnectBtns.openActionsMenu('simulator'); ConnectBtns.editAdapter().should('not.be.disabled'); @@ -80,9 +80,7 @@ describe('Test Edit Adapter and Pipeline', () => { ConnectBtns.storeEditAdapter().click(); // Check for warning message - cy.dataCy('sp-connect-adapter-edit-warning', { - timeout: 60000, - }).should('be.visible'); + ConnectBtns.adapterEditWarning().should('be.visible'); ConnectBtns.updateAndMigratePipelines().click(); ConnectUtils.closeAdapterPreview(); cy.wait(2000); @@ -90,13 +88,8 @@ describe('Test Edit Adapter and Pipeline', () => { // Go to pipelines, check for warning icon and edit pipeline PipelineUtils.goToPipelines(); - cy.dataCy('pipeline-warning-icon', { - timeout: 60000, - }).should('be.visible'); - - cy.dataCy('pipeline-sync-problem-icon', { - timeout: 60000, - }).should('be.visible'); + PipelineBtns.pipelineWarningIcon().should('be.visible'); + PipelineBtns.pipelineSyncProblemIcon().should('be.visible'); GeneralUtils.openMenuForRow('Pipeline Test'); PipelineBtns.modifyPipeline().click(); diff --git a/ui/src/app/chart/components/chart-view/chart-view.component.html b/ui/src/app/chart/components/chart-view/chart-view.component.html index 18885ba522..43df8f265d 100644 --- a/ui/src/app/chart/components/chart-view/chart-view.component.html +++ b/ui/src/app/chart/components/chart-view/chart-view.component.html @@ -57,6 +57,19 @@ </sp-alert-banner> </div> } + @if (showRequiresAttentionWarning) { + <div + class="p-10" + data-cy="chart-requires-attention-warning" + > + <sp-alert-banner + type="warning" + icon="warning" + [title]="'Chart requires attention' | translate" + [description]="requiresAttentionDescription" + ></sp-alert-banner> + </div> + } <mat-drawer-container fxFlex="100" fxLayout="column" diff --git a/ui/src/app/connect/dialog/adapter-started/adapter-started-update-migration/adapter-started-update-migration.component.html b/ui/src/app/connect/dialog/adapter-started/adapter-started-update-migration/adapter-started-update-migration.component.html index d238c41d14..4775d0f3db 100644 --- a/ui/src/app/connect/dialog/adapter-started/adapter-started-update-migration/adapter-started-update-migration.component.html +++ b/ui/src/app/connect/dialog/adapter-started/adapter-started-update-migration/adapter-started-update-migration.component.html @@ -16,53 +16,140 @@ ~ --> -<div fxLayout="column" fxLayoutAlign="start center"> - @if (adapterPipelineUpdateInfos.length > 1) { - <h4> - {{ 'This adapter is used by' | translate }} - {{ adapterPipelineUpdateInfos.length }} - {{ 'pipeline' | translate }}. - </h4> - } @else { - {{ 'This adapter is used by' | translate }} - {{ adapterPipelineUpdateInfos.length }} {{ 'pipelines' | translate }}. ‚ +<div class="migration-view" fxLayout="column" fxLayoutAlign="start stretch"> + @if (adapterPipelineUpdateInfos.length > 0) { + <div class="migration-summary" fxLayout="column" fxLayoutGap="4px"> + @if (adapterPipelineUpdateInfos.length > 1) { + <h4> + {{ 'This adapter is used by' | translate }} + {{ adapterPipelineUpdateInfos.length }} + {{ 'pipelines' | translate }}. + </h4> + } @else { + <h4> + {{ 'This adapter is used by' | translate }} + {{ adapterPipelineUpdateInfos.length }} + {{ 'pipeline' | translate }}. + </h4> + } + </div> + <div class="migration-infos" fxLayout="column" fxLayoutGap="12px"> + @for (updateInfo of adapterPipelineUpdateInfos; track updateInfo) { + <div + class="pipeline-update-info" + data-cy="sp-connect-adapter-edit-warning" + > + @if (updateInfo.canAutoMigrate) { + <div + class="pipeline-status" + fxLayoutAlign="start center" + > + <mat-icon class="status-icon status-icon-ok"> + check_circle + </mat-icon> + <div> + <div class="pipeline-title"> + {{ 'Pipeline' | translate }} + <b>{{ updateInfo.pipelineName }}</b> + </div> + <div class="pipeline-description"> + {{ + 'This pipeline will be automatically migrated.' + | translate + }} + </div> + </div> + </div> + } + @if (!updateInfo.canAutoMigrate) { + <div + class="pipeline-status" + fxLayoutAlign="start center" + data-cy="adapter-manual-pipeline-migration-warning" + > + <mat-icon class="status-icon status-icon-warning"> + warning + </mat-icon> + <div> + <div class="pipeline-title"> + {{ 'Pipeline' | translate }} + <b>{{ updateInfo.pipelineName }}</b> + </div> + <div class="pipeline-description"> + {{ + 'This pipeline will be stopped and needs manual review.' + | translate + }} + </div> + </div> + </div> + } + @if (updateInfo.chartSchemaUpdateInfos?.length > 0) { + <div class="affected-charts" fxLayout="column"> + <div + class="affected-charts-title" + fxLayoutAlign="start center" + > + <mat-icon class="affected-charts-icon"> + query_stats + </mat-icon> + {{ 'Affected charts' | translate }} + </div> + @for ( + chartUpdateInfo of updateInfo.chartSchemaUpdateInfos; + track chartUpdateInfo + ) { + <div + class="affected-chart" + data-cy="sp-connect-adapter-chart-edit-warning" + > + <div + class="affected-chart-title" + fxLayoutAlign="start center" + > + <mat-icon class="chart-warning-icon"> + warning + </mat-icon> + <span> + {{ 'Chart' | translate }} + <b>{{ + chartUpdateInfo.chartTitle + }}</b> + {{ + 'needs manual review after this update.' + | translate + }} + </span> + </div> + @if ( + chartUpdateInfo.affectedFields?.length > + 0 + ) { + <div class="affected-fields"> + <span class="affected-fields-label"> + {{ + 'Deleted fields' + | translate + }}: + </span> + <span> + {{ + getAffectedFieldsText( + chartUpdateInfo.affectedFields + ) + }} + </span> + </div> + } + </div> + } + </div> + } + </div> + } + </div> } - <div class="migration-infos"> - @for (updateInfo of adapterPipelineUpdateInfos; track updateInfo) { - <div data-cy="sp-connect-adapter-edit-warning"> - @if (updateInfo.canAutoMigrate) { - <div fxLayoutAlign="start center"> - <i class="material-icons">check</i> {{ - 'Pipeline' | translate - }} <b>{{ updateInfo.pipelineName }}</b - > {{ - 'will be automatically migrated' | translate - }}. - </div> - } - @if (!updateInfo.canAutoMigrate) { - <div fxLayoutAlign="start center"> - <i class="material-icons">warning</i> - {{ 'Pipeline' | translate }} <b>{{ - updateInfo.pipelineName - }}</b - > {{ - 'will be stopped and needs manual review' - | translate - }}. - </div> - } - </div> - } - </div> - <div class="migration-infos" fxLayoutAlign="start center"> - <i class="material-icons">warning</i> - {{ - 'Please check and possibly modify existing dashboards and data views afterwards.' - | translate - }} - </div> - <div> + <div class="migration-actions"> <button mat-button mat-flat-button diff --git a/ui/src/app/core-ui/pipeline/pipeline-started-status/pipeline-started-status.component.html b/ui/src/app/core-ui/pipeline/pipeline-started-status/pipeline-started-status.component.html index a73fb1e48e..065c598477 100644 --- a/ui/src/app/core-ui/pipeline/pipeline-started-status/pipeline-started-status.component.html +++ b/ui/src/app/core-ui/pipeline/pipeline-started-status/pipeline-started-status.component.html @@ -31,7 +31,9 @@ > } @if (!pipelineOperationStatus()?.success) { - <mat-icon style="color: red">error</mat-icon> + <mat-icon data-cy="sp-pipeline-started-error" style="color: red" + >error</mat-icon + > } <span> {{ pipelineOperationStatus()?.title }}.</span> </div> diff --git a/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.html b/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.html index cc9064c75f..3f4139e199 100644 --- a/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.html +++ b/ui/src/app/pipelines/dialog/measurement-update/measurement-update-dialog.component.html @@ -133,15 +133,26 @@ fxLayoutAlign="end center" fxLayoutGap="0.5rem" > - <button mat-flat-button class="mat-basic" (click)="close()"> + <button + mat-flat-button + class="mat-basic" + data-cy="close-measurement-update-btn" + (click)="close()" + > {{ 'Close' | translate }} </button> - <button mat-flat-button color="accent" (click)="close('edit-pipeline')"> + <button + mat-flat-button + color="accent" + data-cy="edit-pipeline-btn" + (click)="close('edit-pipeline')" + > {{ 'Edit pipeline' | translate }} </button> <button mat-flat-button color="accent" + data-cy="manage-datasets-btn" (click)="close('manage-datasets')" > {{ 'Manage datasets' | translate }} diff --git a/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.html b/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.html index ad095a0cb7..98d1f27723 100644 --- a/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.html +++ b/ui/src/app/pipelines/dialog/pipeline-notifications/pipeline-notifications.component.html @@ -29,7 +29,7 @@ notification of pipeline.pipelineNotifications; track notification ) { - <span class="text-xs"> + <span class="text-xs" data-cy="pipeline-notification"> {{ notification }} </span> <br /> @@ -42,6 +42,7 @@ mat-button mat-flat-button color="accent" + data-cy="acknowledge-pipeline-notification-btn" (click)="acknowledgeAndClose()" > {{ 'Acknowledge' | translate }}
