Skip to content

Commit

Permalink
#2151 & #2223: Implement E2E tests for enhanced adapter deletion and …
Browse files Browse the repository at this point in the history
…Extend reset REST endpoint to remove users (#2197)

* implement unit tests for enhanced adapter deletion

* better structure

* fix

* delete other users in reset

* change comment
  • Loading branch information
muyangye authored Nov 26, 2023
1 parent 3e2f706 commit 2762997
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@

package org.apache.streampipes.rest.impl;

import org.apache.streampipes.model.client.user.Principal;
import org.apache.streampipes.model.client.user.PrincipalType;
import org.apache.streampipes.model.message.Notifications;
import org.apache.streampipes.model.message.SuccessMessage;
import org.apache.streampipes.rest.ResetManagement;
import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
import org.apache.streampipes.rest.shared.annotation.JacksonSerialized;
Expand All @@ -34,6 +35,8 @@
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

import java.util.ArrayList;

@Path("/v2/reset")
public class ResetResource extends AbstractAuthGuardedRestResource {
private static final Logger logger = LoggerFactory.getLogger(ResetResource.class);
Expand All @@ -44,7 +47,17 @@ public class ResetResource extends AbstractAuthGuardedRestResource {
@Operation(summary = "Resets StreamPipes instance")
public Response reset() {
ResetManagement.reset(getAuthenticatedUsername());
SuccessMessage message = Notifications.success("Reset of system successfully performed");
var userStorage = getUserStorage();
// Delete all users other than current user (admin) and their resources
var allUsers = new ArrayList<Principal>(userStorage.getAllUsers());
for (var user : allUsers) {
if (user.getPrincipalType() == PrincipalType.USER_ACCOUNT
&& !user.getPrincipalId().equals(getAuthenticatedUserSid())) {
ResetManagement.reset(user.getUsername());
userStorage.deleteUser(user.getPrincipalId());
}
}
var message = Notifications.success("Reset of system successfully performed");
return ok(message);
}

Expand Down
17 changes: 14 additions & 3 deletions ui/cypress/support/utils/UserUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ export class UserUtils {
.addRole(UserRole.ROLE_ADMIN)
.build();

public static adapterAndPipelineAdminUser = UserBuilder.create(
'[email protected]',
)
.setName('anpadmin')
.setPassword('anpadmin')
.addRole(UserRole.ROLE_PIPELINE_ADMIN)
.addRole(UserRole.ROLE_CONNECT_ADMIN)
.build();

public static goToUserConfiguration() {
cy.visit('#/configuration/security');
}
Expand All @@ -42,9 +51,11 @@ export class UserUtils {
cy.dataCy('new-user-password-repeat').type(user.password);

// Set role
cy.dataCy('role-' + user.role[0])
.children()
.click();
for (var i = 0; i < user.role.length; i++) {
cy.dataCy('role-' + user.role[i])
.children()
.click();
}
cy.dataCy('new-user-enabled').children().click();

// Store
Expand Down
73 changes: 70 additions & 3 deletions ui/cypress/support/utils/connect/ConnectUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { ConnectEventSchemaUtils } from '../ConnectEventSchemaUtils';
import { DataLakeUtils } from '../datalake/DataLakeUtils';
import { ConnectBtns } from './ConnectBtns';
import { AdapterBuilder } from '../../builder/AdapterBuilder';
import { UserUtils } from '../UserUtils';
import { PipelineUtils } from '../PipelineUtils';

export class ConnectUtils {
public static testAdapter(adapterConfiguration: AdapterInput) {
Expand Down Expand Up @@ -193,11 +195,10 @@ export class ConnectUtils {

public static deleteAdapter() {
// Delete adapter
cy.visit('#/connect');
this.goToConnect();

cy.dataCy('delete-adapter').should('have.length', 1);
cy.dataCy('delete-adapter').click();
cy.dataCy('delete-adapter-confirmation').click();
this.clickDelete();
cy.dataCy('adapter-deletion-in-progress', { timeout: 10000 }).should(
'be.visible',
);
Expand All @@ -207,6 +208,72 @@ export class ConnectUtils {
);
}

public static deleteAdapterAndAssociatedPipelines(switchUserCheck = false) {
// Delete adapter and associated pipelines
this.goToConnect();
cy.dataCy('delete-adapter').should('have.length', 1);
this.clickDelete();
cy.dataCy('delete-adapter-and-associated-pipelines-confirmation', {
timeout: 10000,
}).should('be.visible');
cy.dataCy(
'delete-adapter-and-associated-pipelines-confirmation',
).click();
cy.dataCy('adapter-deletion-in-progress', { timeout: 10000 }).should(
'be.visible',
);
if (switchUserCheck) {
cy.switchUser(UserUtils.adapterAndPipelineAdminUser);
}
this.checkAdapterAndAssociatedPipelinesDeleted();
}

// NOTE: this function will leave the adapter and associated pipelines running,
// please make sure to clean up after calling this function
public static deleteAdapterAndAssociatedPipelinesPermissionDenied() {
// Associated pipelines not owned by the user (unless admin) should not be deleted during adapter deletion
this.goToConnect();
cy.dataCy('delete-adapter').should('have.length', 1);
this.clickDelete();
cy.dataCy('delete-adapter-and-associated-pipelines-confirmation', {
timeout: 10000,
}).should('be.visible');
cy.dataCy(
'delete-adapter-and-associated-pipelines-confirmation',
).click();
cy.dataCy('adapter-deletion-permission-denied', {
timeout: 10000,
}).should('be.visible');
cy.get('.sp-dialog-actions').click();
this.checkAdapterNotDeleted();
}

public static clickDelete() {
cy.dataCy('delete-adapter').click();
cy.dataCy('delete-adapter-confirmation').click();
}

public static checkAdapterNotDeleted() {
this.goToConnect();
cy.dataCy('delete-adapter', { timeout: 20000 }).should(
'have.length',
1,
);
}

public static checkAdapterAndAssociatedPipelinesDeleted() {
this.goToConnect();
cy.dataCy('delete-adapter', { timeout: 20000 }).should(
'have.length',
0,
);
PipelineUtils.goToPipelines();
cy.dataCy('delete-pipeline', { timeout: 10000 }).should(
'have.length',
0,
);
}

public static setUpPreprocessingRuleTest(): AdapterInput {
const adapterConfiguration = AdapterBuilder.create('File_Stream')
.setStoreInDataLake()
Expand Down
95 changes: 95 additions & 0 deletions ui/cypress/tests/adapter/enhancedDeleteAdapter.smoke.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* 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 { AdapterBuilder } from '../../support/builder/AdapterBuilder';
import { ConnectUtils } from '../../support/utils/connect/ConnectUtils';
import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
import { PipelineElementBuilder } from '../../support/builder/PipelineElementBuilder';
import { UserUtils } from '../../support/utils/UserUtils';
import { PipelineUtils } from '../../support/utils/PipelineUtils';

const adapterName = 'simulator';

const adapterInput = AdapterBuilder.create('Machine_Data_Simulator')
.setName(adapterName)
.addInput('input', 'wait-time-ms', '1000')
.build();

const pipelineInput = PipelineBuilder.create('Pipeline Test')
.addSource(adapterName)
.addProcessingElement(
PipelineElementBuilder.create('field_renamer')
.addInput('drop-down', 'convert-property', 'timestamp')
.addInput('input', 'field-name', 't')
.build(),
)
.addSink(
PipelineElementBuilder.create('data_lake')
.addInput('input', 'db_measurement', 'demo')
.build(),
)
.build();

describe('Test Enhanced Adapter Deletion', () => {
// In the beginning, create the non-admin user
before(() => {
cy.initStreamPipesTest();
UserUtils.addUser(UserUtils.adapterAndPipelineAdminUser);
cy.logout();
});

beforeEach('Setup Test', () => {
cy.visit('#/login');
cy.dataCy('login-email').type(
UserUtils.adapterAndPipelineAdminUser.email,
);
cy.dataCy('login-password').type(
UserUtils.adapterAndPipelineAdminUser.password,
);
cy.dataCy('login-button').click();
cy.wait(1000);
});

it('Test Delete Adapter and Associated Pipelines', () => {
ConnectUtils.testAdapter(adapterInput);
PipelineUtils.addPipeline(pipelineInput);
PipelineUtils.addPipeline(pipelineInput);
ConnectUtils.deleteAdapterAndAssociatedPipelines();
});

it('Test Admin Should Be Able to Delete Adapter and Not Owned Associated Pipelines', () => {
// Let the user create the adapter and the pipeline
ConnectUtils.testAdapter(adapterInput);
PipelineUtils.addPipeline(pipelineInput);
PipelineUtils.addPipeline(pipelineInput);
// Then let the admin delete them
cy.switchUser(UserUtils.adminUser);
ConnectUtils.deleteAdapterAndAssociatedPipelines(true);
});

it('Test Delete Adapter and Associated Pipelines Permission Denied', () => {
// Let the admin create the adapter and the pipeline
cy.switchUser(UserUtils.adminUser);
ConnectUtils.testAdapter(adapterInput);
PipelineUtils.addPipeline(pipelineInput);
PipelineUtils.addPipeline(pipelineInput);
// Then the user shouldn't be able to delete them
cy.switchUser(UserUtils.adapterAndPipelineAdminUser);
ConnectUtils.deleteAdapterAndAssociatedPipelinesPermissionDenied();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ <h4>
fxLayoutAlign="center center"
fxLayout="column"
style="width: 100%"
data-cy="adapter-deletion-permission-denied"
>
<b>
<h4>
Expand Down

0 comments on commit 2762997

Please sign in to comment.