Browse Source
* Add Shell E2E case * Add shell using resource file e2e case * Upgrade checkout from v2 to v4 * Change interval to 500ms * Upgrade actions/upload-artifact --------- Co-authored-by: xiangzihao <460888207@qq.com>dev
Wenjun Ruan
4 months ago
committed by
GitHub
58 changed files with 1109 additions and 183 deletions
@ -0,0 +1,260 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.e2e.cases.tasks; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.e2e.cases.workflow.BaseWorkflowE2ETest; |
||||||
|
import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.ProjectPage; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.workflow.TaskInstanceTab; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowDefinitionTab; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowInstanceTab; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.ShellTaskForm; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.resource.FileManagePage; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.resource.ResourcePage; |
||||||
|
import org.junit.FixMethodOrder; |
||||||
|
import org.junit.jupiter.api.Order; |
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
import org.junit.runners.MethodSorters; |
||||||
|
import org.openqa.selenium.WebElement; |
||||||
|
import org.testcontainers.shaded.org.awaitility.Awaitility; |
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.testcontainers.shaded.org.awaitility.Awaitility.await; |
||||||
|
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING) |
||||||
|
@DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml") |
||||||
|
public class ShellTaskE2ETest extends BaseWorkflowE2ETest { |
||||||
|
|
||||||
|
@Test |
||||||
|
void testRunShellTasks_SuccessCase() { |
||||||
|
WorkflowDefinitionTab workflowDefinitionPage = |
||||||
|
new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName) |
||||||
|
.goToTab(WorkflowDefinitionTab.class); |
||||||
|
|
||||||
|
// todo: use yaml to define the workflow
|
||||||
|
String workflowName = "SuccessCase"; |
||||||
|
String taskName = "ShellSuccess"; |
||||||
|
workflowDefinitionPage |
||||||
|
.createWorkflow() |
||||||
|
.<ShellTaskForm>addTask(WorkflowForm.TaskType.SHELL) |
||||||
|
.script("echo hello world\n") |
||||||
|
.name(taskName) |
||||||
|
.submit() |
||||||
|
|
||||||
|
.submit() |
||||||
|
.name(workflowName) |
||||||
|
.submit(); |
||||||
|
|
||||||
|
untilWorkflowDefinitionExist(workflowName); |
||||||
|
|
||||||
|
workflowDefinitionPage.publish(workflowName); |
||||||
|
|
||||||
|
runWorkflow(workflowName); |
||||||
|
untilWorkflowInstanceExist(workflowName); |
||||||
|
WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceSuccess(workflowName); |
||||||
|
assertThat(workflowInstance.executionTime()).isEqualTo(1); |
||||||
|
|
||||||
|
TaskInstanceTab.Row taskInstance = untilTaskInstanceSuccess(workflowName, taskName); |
||||||
|
assertThat(taskInstance.retryTimes()).isEqualTo(0); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void testRunShellTasks_WorkflowParamsCase() { |
||||||
|
WorkflowDefinitionTab workflowDefinitionPage = |
||||||
|
new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName) |
||||||
|
.goToTab(WorkflowDefinitionTab.class); |
||||||
|
|
||||||
|
// todo: use yaml to define the workflow
|
||||||
|
String workflowName = "WorkflowParamsCase"; |
||||||
|
String taskName = "ShellSuccess"; |
||||||
|
workflowDefinitionPage |
||||||
|
.createWorkflow() |
||||||
|
.<ShellTaskForm>addTask(WorkflowForm.TaskType.SHELL) |
||||||
|
.script("[ \"${name}\" = \"tom\" ] && echo \"success\" || { echo \"failed\"; exit 1; }") |
||||||
|
.name(taskName) |
||||||
|
.submit() |
||||||
|
|
||||||
|
.submit() |
||||||
|
.name(workflowName) |
||||||
|
.addGlobalParam("name", "tom") |
||||||
|
.submit(); |
||||||
|
|
||||||
|
untilWorkflowDefinitionExist(workflowName); |
||||||
|
|
||||||
|
workflowDefinitionPage.publish(workflowName); |
||||||
|
|
||||||
|
runWorkflow(workflowName); |
||||||
|
untilWorkflowInstanceExist(workflowName); |
||||||
|
WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceSuccess(workflowName); |
||||||
|
assertThat(workflowInstance.executionTime()).isEqualTo(1); |
||||||
|
|
||||||
|
TaskInstanceTab.Row taskInstance = untilTaskInstanceSuccess(workflowName, taskName); |
||||||
|
assertThat(taskInstance.retryTimes()).isEqualTo(0); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void testRunShellTasks_LocalParamsCase() { |
||||||
|
WorkflowDefinitionTab workflowDefinitionPage = |
||||||
|
new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName) |
||||||
|
.goToTab(WorkflowDefinitionTab.class); |
||||||
|
|
||||||
|
String workflowName = "LocalParamsCase"; |
||||||
|
String taskName = "ShellSuccess"; |
||||||
|
workflowDefinitionPage |
||||||
|
.createWorkflow() |
||||||
|
.<ShellTaskForm>addTask(WorkflowForm.TaskType.SHELL) |
||||||
|
.script("[ \"${name}\" = \"tom\" ] && echo \"success\" || { echo \"failed\"; exit 1; }") |
||||||
|
.name(taskName) |
||||||
|
.addParam("name", "tom") |
||||||
|
.submit() |
||||||
|
|
||||||
|
.submit() |
||||||
|
.name(workflowName) |
||||||
|
.submit(); |
||||||
|
|
||||||
|
untilWorkflowDefinitionExist(workflowName); |
||||||
|
|
||||||
|
workflowDefinitionPage.publish(workflowName); |
||||||
|
|
||||||
|
runWorkflow(workflowName); |
||||||
|
untilWorkflowInstanceExist(workflowName); |
||||||
|
WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceSuccess(workflowName); |
||||||
|
assertThat(workflowInstance.executionTime()).isEqualTo(1); |
||||||
|
|
||||||
|
TaskInstanceTab.Row taskInstance = untilTaskInstanceSuccess(workflowName, taskName); |
||||||
|
assertThat(taskInstance.retryTimes()).isEqualTo(0); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void testRunShellTasks_GlobalParamsOverrideLocalParamsCase() { |
||||||
|
WorkflowDefinitionTab workflowDefinitionPage = |
||||||
|
new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName) |
||||||
|
.goToTab(WorkflowDefinitionTab.class); |
||||||
|
|
||||||
|
String workflowName = "LocalParamsOverrideWorkflowParamsCase"; |
||||||
|
String taskName = "ShellSuccess"; |
||||||
|
workflowDefinitionPage |
||||||
|
.createWorkflow() |
||||||
|
.<ShellTaskForm>addTask(WorkflowForm.TaskType.SHELL) |
||||||
|
.script("[ \"${name}\" = \"jerry\" ] && echo \"success\" || { echo \"failed\"; exit 1; }") |
||||||
|
.name(taskName) |
||||||
|
.addParam("name", "tom") |
||||||
|
.submit() |
||||||
|
|
||||||
|
.submit() |
||||||
|
.name(workflowName) |
||||||
|
.addGlobalParam("name", "jerry") |
||||||
|
.submit(); |
||||||
|
|
||||||
|
untilWorkflowDefinitionExist(workflowName); |
||||||
|
|
||||||
|
workflowDefinitionPage.publish(workflowName); |
||||||
|
|
||||||
|
runWorkflow(workflowName); |
||||||
|
untilWorkflowInstanceExist(workflowName); |
||||||
|
WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceSuccess(workflowName); |
||||||
|
assertThat(workflowInstance.executionTime()).isEqualTo(1); |
||||||
|
|
||||||
|
TaskInstanceTab.Row taskInstance = untilTaskInstanceSuccess(workflowName, taskName); |
||||||
|
assertThat(taskInstance.retryTimes()).isEqualTo(0); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void testRunShellTasks_UsingResourceFile() { |
||||||
|
String testFileName = "echo"; |
||||||
|
new ResourcePage(browser) |
||||||
|
.goToNav(ResourcePage.class) |
||||||
|
.goToTab(FileManagePage.class) |
||||||
|
.createFileUntilSuccess(testFileName, "echo 123"); |
||||||
|
|
||||||
|
final WorkflowDefinitionTab workflowDefinitionPage = |
||||||
|
new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName) |
||||||
|
.goToTab(WorkflowDefinitionTab.class); |
||||||
|
|
||||||
|
String workflowName = "UsingResourceFile"; |
||||||
|
String taskName = "ShellSuccess"; |
||||||
|
workflowDefinitionPage |
||||||
|
.createWorkflow() |
||||||
|
.<ShellTaskForm>addTask(WorkflowForm.TaskType.SHELL) |
||||||
|
.script("cat " + testFileName + ".sh") |
||||||
|
.name(taskName) |
||||||
|
.selectResource(testFileName) |
||||||
|
.submit() |
||||||
|
|
||||||
|
.submit() |
||||||
|
.name(workflowName) |
||||||
|
.submit(); |
||||||
|
|
||||||
|
untilWorkflowDefinitionExist(workflowName); |
||||||
|
|
||||||
|
workflowDefinitionPage.publish(workflowName); |
||||||
|
|
||||||
|
runWorkflow(workflowName); |
||||||
|
untilWorkflowInstanceExist(workflowName); |
||||||
|
WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceSuccess(workflowName); |
||||||
|
assertThat(workflowInstance.executionTime()).isEqualTo(1); |
||||||
|
|
||||||
|
TaskInstanceTab.Row taskInstance = untilTaskInstanceSuccess(workflowName, taskName); |
||||||
|
assertThat(taskInstance.retryTimes()).isEqualTo(0); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void testRunShellTasks_FailedCase() { |
||||||
|
WorkflowDefinitionTab workflowDefinitionPage = |
||||||
|
new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName) |
||||||
|
.goToTab(WorkflowDefinitionTab.class); |
||||||
|
|
||||||
|
String workflowName = "FailedCase"; |
||||||
|
String taskName = "ShellFailed"; |
||||||
|
workflowDefinitionPage |
||||||
|
.createWorkflow() |
||||||
|
.<ShellTaskForm>addTask(WorkflowForm.TaskType.SHELL) |
||||||
|
.script("echo 'I am failed'\n exit1\n") |
||||||
|
.name(taskName) |
||||||
|
.submit() |
||||||
|
|
||||||
|
.submit() |
||||||
|
.name(workflowName) |
||||||
|
.submit(); |
||||||
|
|
||||||
|
untilWorkflowDefinitionExist(workflowName); |
||||||
|
|
||||||
|
workflowDefinitionPage.publish(workflowName); |
||||||
|
|
||||||
|
runWorkflow(workflowName); |
||||||
|
untilWorkflowInstanceExist(workflowName); |
||||||
|
WorkflowInstanceTab.Row workflowInstance = untilWorkflowInstanceFailed(workflowName); |
||||||
|
assertThat(workflowInstance.executionTime()).isEqualTo(1); |
||||||
|
|
||||||
|
TaskInstanceTab.Row taskInstance = untilTaskInstanceFailed(workflowName, taskName); |
||||||
|
assertThat(taskInstance.retryTimes()).isEqualTo(0); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,219 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.e2e.cases.workflow; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Objects; |
||||||
|
import java.util.UUID; |
||||||
|
import java.util.concurrent.Callable; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.apache.dolphinscheduler.e2e.core.WebDriverHolder; |
||||||
|
import org.apache.dolphinscheduler.e2e.models.tenant.DefaultTenant; |
||||||
|
import org.apache.dolphinscheduler.e2e.models.users.AdminUser; |
||||||
|
import org.apache.dolphinscheduler.e2e.models.users.IUser; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.LoginPage; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.ProjectDetailPage; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.ProjectPage; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.workflow.TaskInstanceTab; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowDefinitionTab; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowInstanceTab; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.security.TenantPage; |
||||||
|
import org.apache.dolphinscheduler.e2e.pages.security.UserPage; |
||||||
|
import org.junit.jupiter.api.AfterAll; |
||||||
|
import org.junit.jupiter.api.BeforeAll; |
||||||
|
import org.openqa.selenium.remote.RemoteWebDriver; |
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.testcontainers.shaded.org.awaitility.Awaitility.await; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
public abstract class BaseWorkflowE2ETest { |
||||||
|
|
||||||
|
protected static String projectName = UUID.randomUUID().toString(); |
||||||
|
|
||||||
|
protected static final AdminUser adminUser = new AdminUser(); |
||||||
|
|
||||||
|
protected static RemoteWebDriver browser; |
||||||
|
|
||||||
|
@BeforeAll |
||||||
|
public static void setup() { |
||||||
|
browser = WebDriverHolder.getWebDriver(); |
||||||
|
|
||||||
|
TenantPage tenantPage = new LoginPage(browser) |
||||||
|
.login(adminUser) |
||||||
|
.goToNav(SecurityPage.class) |
||||||
|
.goToTab(TenantPage.class); |
||||||
|
|
||||||
|
if (tenantPage.tenants().stream().noneMatch(tenant -> tenant.tenantCode().equals(adminUser.getTenant()))) { |
||||||
|
tenantPage |
||||||
|
.create(adminUser.getTenant()) |
||||||
|
.goToNav(SecurityPage.class) |
||||||
|
.goToTab(UserPage.class) |
||||||
|
.update(adminUser); |
||||||
|
} |
||||||
|
tenantPage |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.createProjectUntilSuccess(projectName); |
||||||
|
} |
||||||
|
|
||||||
|
protected void untilWorkflowDefinitionExist(String workflowName) { |
||||||
|
WorkflowDefinitionTab workflowDefinitionPage = new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName) |
||||||
|
.goToTab(WorkflowDefinitionTab.class); |
||||||
|
|
||||||
|
await().untilAsserted(() -> assertThat(workflowDefinitionPage.workflowList()) |
||||||
|
.as("Workflow list should contain newly-created workflow: %s", workflowName) |
||||||
|
.anyMatch( |
||||||
|
it -> it.getText().contains(workflowName) |
||||||
|
)); |
||||||
|
} |
||||||
|
|
||||||
|
protected void runWorkflow(String workflowName) { |
||||||
|
final ProjectDetailPage projectPage = new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName); |
||||||
|
|
||||||
|
projectPage |
||||||
|
.goToTab(WorkflowDefinitionTab.class) |
||||||
|
.run(workflowName) |
||||||
|
.submit(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
protected WorkflowInstanceTab.Row untilWorkflowInstanceExist(String workflowName) { |
||||||
|
final ProjectDetailPage projectPage = new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName); |
||||||
|
|
||||||
|
return await() |
||||||
|
.until(() -> { |
||||||
|
browser.navigate().refresh(); |
||||||
|
return projectPage |
||||||
|
.goToTab(WorkflowInstanceTab.class) |
||||||
|
.instances() |
||||||
|
.stream() |
||||||
|
.filter(it -> it.workflowInstanceName().startsWith(workflowName)) |
||||||
|
.findFirst() |
||||||
|
.orElse(null); |
||||||
|
}, Objects::nonNull); |
||||||
|
} |
||||||
|
|
||||||
|
protected WorkflowInstanceTab.Row untilWorkflowInstanceSuccess(String workflowName) { |
||||||
|
final ProjectDetailPage projectPage = new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName); |
||||||
|
return await() |
||||||
|
.until(() -> { |
||||||
|
browser.navigate().refresh(); |
||||||
|
return projectPage |
||||||
|
.goToTab(WorkflowInstanceTab.class) |
||||||
|
.instances() |
||||||
|
.stream() |
||||||
|
.filter(it -> it.workflowInstanceName().startsWith(workflowName)) |
||||||
|
.filter(WorkflowInstanceTab.Row::isSuccess) |
||||||
|
.findFirst() |
||||||
|
.orElse(null); |
||||||
|
}, Objects::nonNull); |
||||||
|
} |
||||||
|
|
||||||
|
protected WorkflowInstanceTab.Row untilWorkflowInstanceFailed(String workflowName) { |
||||||
|
final ProjectDetailPage projectPage = new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName); |
||||||
|
return await() |
||||||
|
.until(() -> { |
||||||
|
browser.navigate().refresh(); |
||||||
|
List<WorkflowInstanceTab.Row> workflowInstances = projectPage |
||||||
|
.goToTab(WorkflowInstanceTab.class) |
||||||
|
.instances() |
||||||
|
.stream() |
||||||
|
.filter(it -> it.workflowInstanceName().startsWith(workflowName)) |
||||||
|
.filter(WorkflowInstanceTab.Row::isFailed) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
if (workflowInstances.isEmpty()) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (workflowInstances.size() > 1) { |
||||||
|
throw new RuntimeException("More than one failed workflow instance found: " + |
||||||
|
workflowInstances.stream() |
||||||
|
.map(WorkflowInstanceTab.Row::workflowInstanceName).collect(Collectors.joining(", "))); |
||||||
|
} |
||||||
|
return workflowInstances.get(0); |
||||||
|
}, Objects::nonNull); |
||||||
|
} |
||||||
|
|
||||||
|
protected TaskInstanceTab.Row untilTaskInstanceSuccess(String workflowName, String taskName) { |
||||||
|
final ProjectDetailPage projectPage = new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName); |
||||||
|
return await() |
||||||
|
.until(() -> { |
||||||
|
browser.navigate().refresh(); |
||||||
|
List<TaskInstanceTab.Row> taskInstances = projectPage |
||||||
|
.goToTab(TaskInstanceTab.class) |
||||||
|
.instances() |
||||||
|
.stream() |
||||||
|
.filter(it -> it.taskInstanceName().startsWith(taskName)) |
||||||
|
.filter(it -> it.workflowInstanceName().startsWith(workflowName)) |
||||||
|
.filter(TaskInstanceTab.Row::isSuccess) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
|
||||||
|
if (taskInstances.isEmpty()) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (taskInstances.size() > 1) { |
||||||
|
throw new RuntimeException("More than one failed task instance found: " + |
||||||
|
taskInstances.stream() |
||||||
|
.map(TaskInstanceTab.Row::taskInstanceName).collect(Collectors.joining(", "))); |
||||||
|
} |
||||||
|
return taskInstances.get(0); |
||||||
|
}, Objects::nonNull); |
||||||
|
} |
||||||
|
|
||||||
|
protected TaskInstanceTab.Row untilTaskInstanceFailed(String workflowName, String taskName) { |
||||||
|
final ProjectDetailPage projectPage = new ProjectPage(browser) |
||||||
|
.goToNav(ProjectPage.class) |
||||||
|
.goTo(projectName); |
||||||
|
return await() |
||||||
|
.until(() -> { |
||||||
|
browser.navigate().refresh(); |
||||||
|
List<TaskInstanceTab.Row> taskInstances = projectPage |
||||||
|
.goToTab(TaskInstanceTab.class) |
||||||
|
.instances() |
||||||
|
.stream() |
||||||
|
.filter(it -> it.taskInstanceName().startsWith(taskName)) |
||||||
|
.filter(it -> it.workflowInstanceName().startsWith(workflowName)) |
||||||
|
.filter(TaskInstanceTab.Row::isFailed) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
|
||||||
|
if (taskInstances.isEmpty()) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (taskInstances.size() > 1) { |
||||||
|
throw new RuntimeException("More than one failed task instance found: " + |
||||||
|
taskInstances.stream() |
||||||
|
.map(TaskInstanceTab.Row::taskInstanceName).collect(Collectors.joining(", "))); |
||||||
|
} |
||||||
|
return taskInstances.get(0); |
||||||
|
}, Objects::nonNull); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.e2e.models.tenant; |
||||||
|
|
||||||
|
public class BootstrapTenant implements ITenant { |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getTenantCode() { |
||||||
|
return System.getProperty("user.name"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getDescription() { |
||||||
|
return "bootstrap tenant"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.e2e.models.tenant; |
||||||
|
|
||||||
|
public class DefaultTenant implements ITenant { |
||||||
|
@Override |
||||||
|
public String getTenantCode() { |
||||||
|
return "default"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getDescription() { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.e2e.models.tenant; |
||||||
|
|
||||||
|
public interface ITenant { |
||||||
|
|
||||||
|
String getTenantCode(); |
||||||
|
|
||||||
|
String getDescription(); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.e2e.models.users; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
import org.apache.dolphinscheduler.e2e.models.tenant.BootstrapTenant; |
||||||
|
import org.apache.dolphinscheduler.e2e.models.tenant.ITenant; |
||||||
|
|
||||||
|
@Data |
||||||
|
public class AdminUser implements IUser { |
||||||
|
|
||||||
|
private String userName; |
||||||
|
|
||||||
|
private String password; |
||||||
|
|
||||||
|
private String email; |
||||||
|
|
||||||
|
private String phone; |
||||||
|
|
||||||
|
private ITenant tenant; |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getUserName() { |
||||||
|
return "admin"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getPassword() { |
||||||
|
return "dolphinscheduler123"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getEmail() { |
||||||
|
return "admin@gmail.com"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getPhone() { |
||||||
|
return "15800000000"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getTenant() { |
||||||
|
return new BootstrapTenant().getTenantCode(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.e2e.models.users; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.e2e.models.tenant.ITenant; |
||||||
|
|
||||||
|
public interface IUser { |
||||||
|
|
||||||
|
String getUserName(); |
||||||
|
|
||||||
|
String getPassword(); |
||||||
|
|
||||||
|
String getEmail(); |
||||||
|
|
||||||
|
String getPhone(); |
||||||
|
|
||||||
|
String getTenant(); |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.e2e.core; |
||||||
|
|
||||||
|
import org.openqa.selenium.remote.RemoteWebDriver; |
||||||
|
|
||||||
|
public class WebDriverHolder { |
||||||
|
|
||||||
|
public static RemoteWebDriver browser; |
||||||
|
|
||||||
|
public static void setWebDriver(RemoteWebDriver driver) { |
||||||
|
browser = driver; |
||||||
|
} |
||||||
|
|
||||||
|
public static RemoteWebDriver getWebDriver() { |
||||||
|
return browser; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.e2e.core; |
||||||
|
|
||||||
|
import java.time.Duration; |
||||||
|
import org.openqa.selenium.WebDriver; |
||||||
|
import org.openqa.selenium.support.ui.WebDriverWait; |
||||||
|
|
||||||
|
public class WebDriverWaitFactory { |
||||||
|
|
||||||
|
private static final Duration DEFAULT_INTERVAL = Duration.ofMillis(500); |
||||||
|
|
||||||
|
private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(60); |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a WebDriverWait instance with default timeout 60s and interval 100ms. |
||||||
|
*/ |
||||||
|
public static WebDriverWait createWebDriverWait(WebDriver driver) { |
||||||
|
return createWebDriverWait(driver, DEFAULT_TIMEOUT); |
||||||
|
} |
||||||
|
|
||||||
|
public static WebDriverWait createWebDriverWait(WebDriver driver, Duration timeout) { |
||||||
|
return new WebDriverWait(driver, timeout, DEFAULT_INTERVAL); |
||||||
|
} |
||||||
|
|
||||||
|
public static WebDriverWait createWebDriverWait(WebDriver driver, Duration timeout, Duration interval) { |
||||||
|
return new WebDriverWait(driver, timeout, interval); |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue