[E2E] Add new test of token management (#8161)
parent
4b58df9aa8
commit
63f7efa993
|
|
@ -81,6 +81,8 @@ jobs:
|
|||
class: org.apache.dolphinscheduler.e2e.cases.QueueE2ETest
|
||||
- name: Environment
|
||||
class: org.apache.dolphinscheduler.e2e.cases.EnvironmentE2ETest
|
||||
- name: Token
|
||||
class: org.apache.dolphinscheduler.e2e.cases.TokenE2ETest
|
||||
- name: Workflow
|
||||
class: org.apache.dolphinscheduler.e2e.cases.WorkflowE2ETest
|
||||
- name: FileManage
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Licensed to 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. Apache Software Foundation (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.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.e2e.cases;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
import org.apache.dolphinscheduler.e2e.core.DolphinScheduler;
|
||||
import org.apache.dolphinscheduler.e2e.pages.LoginPage;
|
||||
import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage;
|
||||
import org.apache.dolphinscheduler.e2e.pages.security.TokenPage;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.remote.RemoteWebDriver;
|
||||
|
||||
@DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml")
|
||||
public class TokenE2ETest {
|
||||
|
||||
private static final String userName = "admin";
|
||||
|
||||
private static RemoteWebDriver browser;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
new LoginPage(browser)
|
||||
.login("admin", "dolphinscheduler123")
|
||||
.goToNav(SecurityPage.class)
|
||||
.goToTab(TokenPage.class)
|
||||
;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(10)
|
||||
void testCreateToken() {
|
||||
final TokenPage page = new TokenPage(browser);
|
||||
page.create();
|
||||
|
||||
await().untilAsserted(() -> {
|
||||
browser.navigate().refresh();
|
||||
|
||||
assertThat(page.tokenList())
|
||||
.as("Token list should contain newly-created token")
|
||||
.extracting(WebElement::getText)
|
||||
.anyMatch(it -> it.contains(userName));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(30)
|
||||
void testEditToken() {
|
||||
final TokenPage page = new TokenPage(browser);
|
||||
String oldToken = page.getToken(userName);
|
||||
page.update(userName);
|
||||
|
||||
await().untilAsserted(() -> {
|
||||
browser.navigate().refresh();
|
||||
|
||||
assertThat(page.tokenList())
|
||||
.as("Token list should contain newly-modified token")
|
||||
.extracting(WebElement::getText)
|
||||
.isNotEqualTo(oldToken);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(40)
|
||||
void testDeleteToken() {
|
||||
final TokenPage page = new TokenPage(browser);
|
||||
page.delete(userName);
|
||||
|
||||
await().untilAsserted(() -> {
|
||||
browser.navigate().refresh();
|
||||
|
||||
assertThat(page.tokenList())
|
||||
.noneMatch(it -> it.getText().contains(userName));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.e2e.pages.security;
|
||||
|
||||
import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
|
||||
|
|
@ -26,11 +27,11 @@ import org.openqa.selenium.JavascriptExecutor;
|
|||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.remote.RemoteWebDriver;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class SecurityPage extends NavBarPage implements NavBarItem {
|
||||
@FindBy(className = "tab-tenant-manage")
|
||||
|
|
@ -48,6 +49,9 @@ public class SecurityPage extends NavBarPage implements NavBarItem {
|
|||
@FindBy(className = "tab-environment-manage")
|
||||
private WebElement menuEnvironmentManage;
|
||||
|
||||
@FindBy(className = "tab-token-manage")
|
||||
private WebElement menuTokenManage;
|
||||
|
||||
public SecurityPage(RemoteWebDriver driver) {
|
||||
super(driver);
|
||||
}
|
||||
|
|
@ -56,20 +60,20 @@ public class SecurityPage extends NavBarPage implements NavBarItem {
|
|||
if (tab == TenantPage.class) {
|
||||
WebElement menuTenantManageElement = new WebDriverWait(driver, 60)
|
||||
.until(ExpectedConditions.elementToBeClickable(menuTenantManage));
|
||||
((JavascriptExecutor)driver).executeScript("arguments[0].click();", menuTenantManageElement);
|
||||
((JavascriptExecutor) driver).executeScript("arguments[0].click();", menuTenantManageElement);
|
||||
return tab.cast(new TenantPage(driver));
|
||||
}
|
||||
if (tab == UserPage.class) {
|
||||
WebElement menUserManageElement = new WebDriverWait(driver, 60)
|
||||
.until(ExpectedConditions.elementToBeClickable(menUserManage));
|
||||
((JavascriptExecutor)driver).executeScript("arguments[0].click();", menUserManageElement);
|
||||
((JavascriptExecutor) driver).executeScript("arguments[0].click();", menUserManageElement);
|
||||
new WebDriverWait(driver, 25).until(ExpectedConditions.urlContains("/#/security/users"));
|
||||
return tab.cast(new UserPage(driver));
|
||||
}
|
||||
if (tab == WorkerGroupPage.class) {
|
||||
WebElement menWorkerGroupManageElement = new WebDriverWait(driver, 60)
|
||||
.until(ExpectedConditions.elementToBeClickable(menWorkerGroupManage));
|
||||
((JavascriptExecutor)driver).executeScript("arguments[0].click();", menWorkerGroupManageElement);
|
||||
((JavascriptExecutor) driver).executeScript("arguments[0].click();", menWorkerGroupManageElement);
|
||||
return tab.cast(new WorkerGroupPage(driver));
|
||||
}
|
||||
if (tab == QueuePage.class) {
|
||||
|
|
@ -80,6 +84,10 @@ public class SecurityPage extends NavBarPage implements NavBarItem {
|
|||
menuEnvironmentManage().click();
|
||||
return tab.cast(new EnvironmentPage(driver));
|
||||
}
|
||||
if (tab == TokenPage.class) {
|
||||
menuTokenManage().click();
|
||||
return tab.cast(new TokenPage(driver));
|
||||
}
|
||||
throw new UnsupportedOperationException("Unknown tab: " + tab.getName());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Licensed to 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. Apache Software Foundation (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.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.e2e.pages.security;
|
||||
|
||||
import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
|
||||
import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage.Tab;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.remote.RemoteWebDriver;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.FindBys;
|
||||
import org.openqa.selenium.support.PageFactory;
|
||||
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
@Getter
|
||||
public final class TokenPage extends NavBarPage implements Tab {
|
||||
@FindBy(id = "btnCreateToken")
|
||||
private WebElement buttonCreateToken;
|
||||
|
||||
@FindBy(className = "items")
|
||||
private List<WebElement> tokenList;
|
||||
|
||||
@FindBys({
|
||||
@FindBy(className = "el-popconfirm"),
|
||||
@FindBy(className = "el-button--primary"),
|
||||
})
|
||||
private List<WebElement> buttonConfirm;
|
||||
|
||||
@FindBy(className = "userName")
|
||||
private List<WebElement> userName;
|
||||
|
||||
@FindBy(className = "token")
|
||||
private List<WebElement> token;
|
||||
|
||||
private final TokenForm createTokenForm = new TokenForm();
|
||||
private final TokenForm editTokenForm = new TokenForm();
|
||||
|
||||
public TokenPage(RemoteWebDriver driver) {
|
||||
super(driver);
|
||||
}
|
||||
|
||||
public TokenPage create() {
|
||||
buttonCreateToken().click();
|
||||
createTokenForm().buttonGenerateToken().click();
|
||||
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(createTokenForm.buttonGenerateToken));
|
||||
createTokenForm().buttonSubmit().click();
|
||||
return this;
|
||||
}
|
||||
|
||||
public TokenPage update(String userName) {
|
||||
tokenList().stream()
|
||||
.filter(it -> it.findElement(By.className("userName")).getAttribute("innerHTML").contains(userName))
|
||||
.flatMap(it -> it.findElements(By.className("edit")).stream())
|
||||
.filter(WebElement::isDisplayed)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No edit button in token list"))
|
||||
.click();
|
||||
|
||||
TokenForm editTokenForm = new TokenForm();
|
||||
|
||||
editTokenForm.buttonGenerateToken().click();
|
||||
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(createTokenForm.buttonGenerateToken));
|
||||
editTokenForm.buttonSubmit().click();
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getToken(String userName) {
|
||||
return tokenList().stream()
|
||||
.filter(it -> it.findElement(By.className("userName")).getAttribute("innerHTML").contains(userName))
|
||||
.flatMap(it -> it.findElements(By.className("token")).stream())
|
||||
.filter(it -> !Strings.isNullOrEmpty(it.getAttribute("innerHTML")))
|
||||
.map(it -> it.getAttribute("innerHTML"))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No token for such user: " + userName));
|
||||
}
|
||||
|
||||
public TokenPage delete(String userName) {
|
||||
tokenList()
|
||||
.stream()
|
||||
.filter(it -> it.getText().contains(userName))
|
||||
.flatMap(it -> it.findElements(By.className("delete")).stream())
|
||||
.filter(WebElement::isDisplayed)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No delete button in token list"))
|
||||
.click();
|
||||
|
||||
buttonConfirm()
|
||||
.stream()
|
||||
.filter(WebElement::isDisplayed)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No confirm button when deleting"))
|
||||
.click();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public class TokenForm {
|
||||
TokenForm() {
|
||||
PageFactory.initElements(driver, this);
|
||||
}
|
||||
|
||||
@FindBy(id = "btnGenerateToken")
|
||||
private WebElement buttonGenerateToken;
|
||||
|
||||
@FindBy(id = "btnSubmit")
|
||||
private WebElement buttonSubmit;
|
||||
|
||||
@FindBy(id = "btnCancel")
|
||||
private WebElement buttonCancel;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
<template>
|
||||
<m-popover
|
||||
okId="btnSubmit"
|
||||
cancelId="btnCancel"
|
||||
ref="popover"
|
||||
:ok-text="item ? $t('Edit') : $t('Submit')"
|
||||
@ok="_ok"
|
||||
|
|
@ -59,7 +61,7 @@
|
|||
v-model="token"
|
||||
:placeholder="$t('Please enter token')">
|
||||
</el-input>
|
||||
<el-button size="small" @click="_generateToken" :loading="tokenLoading">{{$t('Generate token')}}</el-button>
|
||||
<el-button id="btnGenerateToken" size="small" @click="_generateToken" :loading="tokenLoading">{{$t('Generate token')}}</el-button>
|
||||
</template>
|
||||
</m-list-box-f>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@
|
|||
<template>
|
||||
<div class="list-model">
|
||||
<div class="table-box">
|
||||
<el-table :data="list" size="mini" style="width: 100%">
|
||||
<el-table :data="list" size="mini" style="width: 100%" row-class-name="items">
|
||||
<el-table-column type="index" :label="$t('#')" width="50"></el-table-column>
|
||||
<el-table-column prop="userName" :label="$t('User')"></el-table-column>
|
||||
<el-table-column prop="token" label="Token" width="300"></el-table-column>
|
||||
<el-table-column prop="userName" :label="$t('User')" class-name="userName"></el-table-column>
|
||||
<el-table-column prop="token" label="Token" width="300" class-name="token"></el-table-column>
|
||||
<el-table-column :label="$t('Expiration time')" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.expireTime | formatDate}}</span>
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
<el-table-column :label="$t('Operation')" width="130">
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip :content="$t('Edit')" placement="top" :enterable="false">
|
||||
<el-button type="primary" size="mini" icon="el-icon-edit-outline" @click="_edit(scope.row)" circle></el-button>
|
||||
<el-button type="primary" size="mini" icon="el-icon-edit-outline" @click="_edit(scope.row)" circle class="edit"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="$t('Delete')" placement="top" :enterable="false">
|
||||
<el-popconfirm
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
:title="$t('Delete?')"
|
||||
@onConfirm="_delete(scope.row,scope.row.id)"
|
||||
>
|
||||
<el-button type="danger" size="mini" icon="el-icon-delete" circle slot="reference"></el-button>
|
||||
<el-button type="danger" size="mini" icon="el-icon-delete" circle slot="reference" class="delete"></el-button>
|
||||
</el-popconfirm>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -19,8 +19,9 @@
|
|||
<template slot="conditions">
|
||||
<m-conditions @on-conditions="_onConditions">
|
||||
<template slot="button-group">
|
||||
<el-button size="mini" @click="_create('')">{{$t('Create token')}}</el-button>
|
||||
<el-button id="btnCreateToken" size="mini" @click="_create('')">{{$t('Create token')}}</el-button>
|
||||
<el-dialog
|
||||
id="dialogGenerateToken"
|
||||
:title="item ? $t('Edit token') : $t('Create token')"
|
||||
v-if="createTokenDialog"
|
||||
:visible.sync="createTokenDialog"
|
||||
|
|
|
|||
|
|
@ -182,9 +182,10 @@ const menu = {
|
|||
id: 2,
|
||||
path: 'token-manage',
|
||||
isOpen: true,
|
||||
enabled: true,
|
||||
icon: 'el-icon-document',
|
||||
children: [],
|
||||
enabled: true
|
||||
classNames: 'tab-token-manage'
|
||||
}
|
||||
],
|
||||
resource: [
|
||||
|
|
|
|||
Loading…
Reference in New Issue