You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by ke...@apache.org on 2022/01/30 04:35:02 UTC

[dolphinscheduler] branch dev updated: [E2E] Add new test of token management (#8161)

This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new 63f7efa  [E2E] Add new test of token management (#8161)
63f7efa is described below

commit 63f7efa99374be3410aa7c9007ebbeb0cbe69a06
Author: QuakeWang <45...@users.noreply.github.com>
AuthorDate: Sun Jan 30 12:34:50 2022 +0800

    [E2E] Add new test of token management (#8161)
---
 .github/workflows/e2e.yml                          |   2 +
 .../dolphinscheduler/e2e/cases/TokenE2ETest.java   |  99 +++++++++++++++
 .../e2e/pages/security/SecurityPage.java           |  18 ++-
 .../e2e/pages/security/TokenPage.java              | 138 +++++++++++++++++++++
 .../pages/user/pages/token/_source/createToken.vue |   4 +-
 .../home/pages/user/pages/token/_source/list.vue   |  10 +-
 .../js/conf/home/pages/user/pages/token/index.vue  |   3 +-
 .../components/secondaryMenu/_source/menu.js       |   3 +-
 8 files changed, 264 insertions(+), 13 deletions(-)

diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index 118bf77..d9ae393 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -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
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/TokenE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/TokenE2ETest.java
new file mode 100644
index 0000000..530f493
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/TokenE2ETest.java
@@ -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));
+        });
+    }
+
+}
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java
index 942ae2c..2bbdd7b 100644
--- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java
@@ -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());
     }
 
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TokenPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TokenPage.java
new file mode 100644
index 0000000..a3873b6
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TokenPage.java
@@ -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;
+
+    }
+}
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/_source/createToken.vue b/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/_source/createToken.vue
index a76283c..f8cab2c 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/_source/createToken.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/_source/createToken.vue
@@ -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>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/_source/list.vue
index 300e1ef..d3b397b 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/_source/list.vue
@@ -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>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/index.vue
index b48f70f..76fa9d2 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/user/pages/token/index.vue
@@ -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"
diff --git a/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js b/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
index 6996c83..16ef1fb 100644
--- a/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
+++ b/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
@@ -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: [