diff --git a/.github/workflows/api-test.yml b/.github/workflows/api-test.yml index 48154b73c1..7462619a5e 100644 --- a/.github/workflows/api-test.yml +++ b/.github/workflows/api-test.yml @@ -98,6 +98,8 @@ jobs: class: org.apache.dolphinscheduler.api.test.cases.ProcessDefinitionAPITest - name: Scheduler class: org.apache.dolphinscheduler.api.test.cases.SchedulerAPITest + - name: Executor + class: org.apache.dolphinscheduler.api.test.cases.ExecutorAPITest env: RECORDING_PATH: /tmp/recording-${{ matrix.case.name }} steps: diff --git a/dolphinscheduler-api-test/dolphinscheduler-api-test-case/src/test/java/org/apache/dolphinscheduler/api/test/cases/ExecutorAPITest.java b/dolphinscheduler-api-test/dolphinscheduler-api-test-case/src/test/java/org/apache/dolphinscheduler/api/test/cases/ExecutorAPITest.java new file mode 100644 index 0000000000..3b90131af9 --- /dev/null +++ b/dolphinscheduler-api-test/dolphinscheduler-api-test-case/src/test/java/org/apache/dolphinscheduler/api/test/cases/ExecutorAPITest.java @@ -0,0 +1,148 @@ +/* + * 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.api.test.cases; + +import org.apache.dolphinscheduler.api.test.core.DolphinScheduler; +import org.apache.dolphinscheduler.api.test.entity.HttpResponse; +import org.apache.dolphinscheduler.api.test.entity.LoginResponseData; +import org.apache.dolphinscheduler.api.test.pages.LoginPage; +import org.apache.dolphinscheduler.api.test.pages.project.ProjectPage; +import org.apache.dolphinscheduler.api.test.pages.workflow.ExecutorPage; +import org.apache.dolphinscheduler.api.test.pages.workflow.ProcessDefinitionPage; +import org.apache.dolphinscheduler.api.test.utils.JSONUtils; +import org.apache.dolphinscheduler.common.enums.FailureStrategy; +import org.apache.dolphinscheduler.common.enums.ReleaseState; +import org.apache.dolphinscheduler.common.enums.UserType; +import org.apache.dolphinscheduler.common.enums.WarningType; +import org.apache.dolphinscheduler.dao.entity.Project; +import org.apache.dolphinscheduler.dao.entity.User; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; + +import lombok.extern.slf4j.Slf4j; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.util.EntityUtils; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.List; + +//TODO: Some test cases rely on ProcessInstance APIs. Should complete remaining cases after ProcessInstance related API tests done. +@DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml") +@Slf4j +public class ExecutorAPITest { + + private static final String username = "admin"; + + private static final String password = "dolphinscheduler123"; + + private static String sessionId; + + private static User loginUser; + + private static ExecutorPage executorPage; + + private static ProcessDefinitionPage processDefinitionPage; + + private static ProjectPage projectPage; + + private static long projectCode; + + private static long processDefinitionCode; + + private static long triggerCode; + + @BeforeAll + public static void setup() { + LoginPage loginPage = new LoginPage(); + HttpResponse loginHttpResponse = loginPage.login(username, password); + sessionId = JSONUtils.convertValue(loginHttpResponse.getBody().getData(), LoginResponseData.class).getSessionId(); + executorPage = new ExecutorPage(sessionId); + processDefinitionPage = new ProcessDefinitionPage(sessionId); + projectPage = new ProjectPage(sessionId); + loginUser = new User(); + loginUser.setUserName("admin"); + loginUser.setId(1); + loginUser.setUserType(UserType.ADMIN_USER); + } + + @AfterAll + public static void cleanup() { + log.info("success cleanup"); + } + + @Test + @Order(1) + public void testStartProcessInstance() { + try { + // create test project + HttpResponse createProjectResponse = projectPage.createProject(loginUser, "project-test"); + HttpResponse queryAllProjectListResponse = projectPage.queryAllProjectList(loginUser); + Assertions.assertTrue(queryAllProjectListResponse.getBody().getSuccess()); + projectCode = (long) ((LinkedHashMap) ((List) queryAllProjectListResponse.getBody().getData()).get(0)).get("code"); + + // upload test workflow definition json + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource("workflow-json/test.json").getFile()); + CloseableHttpResponse importProcessDefinitionResponse = processDefinitionPage + .importProcessDefinition(loginUser, projectCode, file); + String data = EntityUtils.toString(importProcessDefinitionResponse.getEntity()); + Assertions.assertTrue(data.contains("\"success\":true")); + + // get workflow definition code + HttpResponse queryAllProcessDefinitionByProjectCodeResponse = processDefinitionPage.queryAllProcessDefinitionByProjectCode(loginUser, projectCode); + Assertions.assertTrue(queryAllProcessDefinitionByProjectCodeResponse.getBody().getSuccess()); + Assertions.assertTrue(queryAllProcessDefinitionByProjectCodeResponse.getBody().getData().toString().contains("hello world")); + processDefinitionCode = (long) ((LinkedHashMap) ((LinkedHashMap) ((List) queryAllProcessDefinitionByProjectCodeResponse.getBody().getData()).get(0)).get("processDefinition")).get("code"); + + // release test workflow + HttpResponse releaseProcessDefinitionResponse = processDefinitionPage.releaseProcessDefinition(loginUser, projectCode, processDefinitionCode, ReleaseState.ONLINE); + Assertions.assertTrue(releaseProcessDefinitionResponse.getBody().getSuccess()); + + // trigger workflow instance + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date date = new Date(); + String scheduleTime = String.format("%s,%s", formatter.format(date), formatter.format(date)); + log.info("use current time {} as scheduleTime", scheduleTime); + HttpResponse startProcessInstanceResponse = executorPage.startProcessInstance(loginUser, projectCode, processDefinitionCode, scheduleTime, FailureStrategy.END, WarningType.NONE); + Assertions.assertTrue(startProcessInstanceResponse.getBody().getSuccess()); + + triggerCode = (long) startProcessInstanceResponse.getBody().getData(); + } catch (Exception e) { + log.error("failed", e); + Assertions.fail(); + } + } + + @Test + @Order(2) + public void testStartCheckProcessDefinition() { + HttpResponse testStartCheckProcessDefinitionResponse = executorPage.startCheckProcessDefinition(loginUser, projectCode, processDefinitionCode); + Assertions.assertTrue(testStartCheckProcessDefinitionResponse.getBody().getSuccess()); + } + +} diff --git a/dolphinscheduler-api-test/dolphinscheduler-api-test-case/src/test/java/org/apache/dolphinscheduler/api/test/pages/workflow/ExecutorPage.java b/dolphinscheduler-api-test/dolphinscheduler-api-test-case/src/test/java/org/apache/dolphinscheduler/api/test/pages/workflow/ExecutorPage.java new file mode 100644 index 0000000000..7ae09cafea --- /dev/null +++ b/dolphinscheduler-api-test/dolphinscheduler-api-test-case/src/test/java/org/apache/dolphinscheduler/api/test/pages/workflow/ExecutorPage.java @@ -0,0 +1,110 @@ +/* + * 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.api.test.pages.workflow; + +import org.apache.dolphinscheduler.api.enums.ExecuteType; +import org.apache.dolphinscheduler.api.test.core.Constants; +import org.apache.dolphinscheduler.api.test.entity.HttpResponse; +import org.apache.dolphinscheduler.api.test.utils.RequestClient; +import org.apache.dolphinscheduler.common.enums.FailureStrategy; +import org.apache.dolphinscheduler.common.enums.TaskDependType; +import org.apache.dolphinscheduler.common.enums.WarningType; +import org.apache.dolphinscheduler.dao.entity.User; + +import java.util.HashMap; +import java.util.Map; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +@AllArgsConstructor +public class ExecutorPage { + + private String sessionId; + + public HttpResponse startProcessInstance(User loginUser, long projectCode, long processDefinitionCode, String scheduleTime, FailureStrategy failureStrategy, WarningType warningType) { + Map params = new HashMap<>(); + params.put("loginUser", loginUser); + params.put("processDefinitionCode", processDefinitionCode); + params.put("scheduleTime", scheduleTime); + params.put("failureStrategy", failureStrategy); + params.put("warningType", warningType); + Map headers = new HashMap<>(); + headers.put(Constants.SESSION_ID_KEY, sessionId); + + RequestClient requestClient = new RequestClient(); + String url = String.format("/projects/%s/executors/start-process-instance", projectCode); + return requestClient.post(url, headers, params); + } + + public HttpResponse queryExecutingWorkflow(User loginUser, long projectCode, long processInstanceCode) { + Map params = new HashMap<>(); + params.put("loginUser", loginUser); + params.put("id", processInstanceCode); + Map headers = new HashMap<>(); + headers.put(Constants.SESSION_ID_KEY, sessionId); + RequestClient requestClient = new RequestClient(); + String url = String.format("/projects/%s/executors/query-executing-workflow", projectCode); + return requestClient.get(url, headers, params); + } + + public HttpResponse execute(User loginUser, long projectCode, int processInstanceId, ExecuteType executeType) { + Map params = new HashMap<>(); + params.put("loginUser", loginUser); + params.put("projectCode", projectCode); + params.put("processInstanceId", processInstanceId); + params.put("executeType", executeType); + Map headers = new HashMap<>(); + headers.put(Constants.SESSION_ID_KEY, sessionId); + + RequestClient requestClient = new RequestClient(); + String url = String.format("/projects/%s/executors/execute", projectCode); + return requestClient.post(url, headers, params); + } + + public HttpResponse startCheckProcessDefinition(User loginUser, long projectCode, long processDefinitionCode) { + Map params = new HashMap<>(); + params.put("loginUser", loginUser); + params.put("processDefinitionCode", processDefinitionCode); + Map headers = new HashMap<>(); + headers.put(Constants.SESSION_ID_KEY, sessionId); + + RequestClient requestClient = new RequestClient(); + String url = String.format("/projects/%s/executors/start-check", projectCode); + return requestClient.post(url, headers, params); + } + + public HttpResponse executeTask(User loginUser, long projectCode, int processInstanceId, String startNodeList, TaskDependType taskDependType) { + Map params = new HashMap<>(); + params.put("loginUser", loginUser); + params.put("processInstanceId", processInstanceId); + params.put("startNodeList", startNodeList); + params.put("taskDependType", taskDependType); + Map headers = new HashMap<>(); + headers.put(Constants.SESSION_ID_KEY, sessionId); + + RequestClient requestClient = new RequestClient(); + String url = String.format("/projects/%s/executors/execute-task", projectCode); + return requestClient.post(url, headers, params); + } + +} \ No newline at end of file