diff --git a/.github/workflows/deploy-run-test.yml b/.github/workflows/deploy-run-test.yml
new file mode 100644
index 000000000..2a4134ddb
--- /dev/null
+++ b/.github/workflows/deploy-run-test.yml
@@ -0,0 +1,38 @@
+name: Docker Deploy and Test
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ types: [ opened, synchronize, reopened ]
+jobs:
+ test:
+ name: Docker Deploy and Test
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v3
+ with:
+ java-version: 17
+ distribution: 'temurin'
+
+ - name: Run Internal Test
+ run: mvn test && echo "Maven Run Internal Test succeeded"|| { echo "Run Internal Test failed."; exit 1; }
+
+ - name: Install Docker Compose
+ run: |
+ sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
+ sudo chmod +x /usr/local/bin/docker-compose
+
+ - name: Deploy with Docker Compose
+ run: |
+ cd docker
+ docker-compose up -d
+
+ - name: Run API Test
+ run: mvn test -P flow_api_test -Dapi.url=http://localhost:8080 && echo "Run API Test succeeded" || { echo "Run API Test failed."; exit 1; }
+
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
new file mode 100644
index 000000000..d8c9b0c11
--- /dev/null
+++ b/docker/docker-compose.yml
@@ -0,0 +1,35 @@
+version: '3'
+services:
+ rill-flow:
+ image: weibocom/rill-flow
+ depends_on:
+ - cache
+ - jaeger
+ ports:
+ - "8080:8080"
+ environment:
+ - RILL_FLOW_DESCRIPTOR_REDIS_HOST=cache
+ - RILL_FLOW_DEFAULT_REDIS_HOST=cache
+ - RILL_FLOW_TRACE_ENDPOINT=http://jaeger:4317
+ - RILL_FLOW_CALLBACK_URL=http://rill-flow:8080/flow/finish.json
+ - RILL_FLOW_TRACE_QUERY_HOST=http://jaeger:16686
+ cache:
+ image: redis:6.2-alpine
+ restart: always
+ command: redis-server --save 20 1 --loglevel warning
+ jaeger:
+ image: jaegertracing/all-in-one:1.39
+ restart: always
+ environment:
+ - COLLECTOR_OTLP_ENABLED=true
+ ui:
+ image: weibocom/rill-flow-ui
+ ports:
+ - "8088:80"
+ depends_on:
+ - rill-flow
+ - jaeger
+ environment:
+ - BACKEND_SERVER=http://rill-flow:8080
+ sample-executor:
+ image: weibocom/rill-flow-sample:sample-executor
diff --git a/pom.xml b/pom.xml
index 3bf875c01..602a6ca36 100644
--- a/pom.xml
+++ b/pom.xml
@@ -901,6 +901,12 @@
+
+ flow_api_test
+
+ rill-flow-test
+
+
diff --git a/rill-flow-test/pom.xml b/rill-flow-test/pom.xml
new file mode 100644
index 000000000..24fa50417
--- /dev/null
+++ b/rill-flow-test/pom.xml
@@ -0,0 +1,30 @@
+
+
+ 4.0.0
+
+ com.weibo
+ rill-flow
+ 0.1.6-SNAPSHOT
+
+
+ rill-flow-test
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.14
+
+
+ com.alibaba
+ fastjson
+
+
+ net.sf.json-lib
+ json-lib
+ jdk15
+
+
+
\ No newline at end of file
diff --git a/rill-flow-test/src/test/groovy/com/weibo/rill/flow/sample/SampleApiTest.groovy b/rill-flow-test/src/test/groovy/com/weibo/rill/flow/sample/SampleApiTest.groovy
new file mode 100644
index 000000000..30882dc86
--- /dev/null
+++ b/rill-flow-test/src/test/groovy/com/weibo/rill/flow/sample/SampleApiTest.groovy
@@ -0,0 +1,137 @@
+package com.weibo.rill.flow.sample
+
+import net.sf.json.groovy.JsonSlurper
+import org.apache.http.HttpEntity
+import org.apache.http.HttpResponse
+import org.apache.http.client.HttpClient
+import org.apache.http.client.methods.HttpGet
+import org.apache.http.client.methods.HttpPost
+import org.apache.http.entity.ContentType
+import org.apache.http.entity.StringEntity
+import org.apache.http.impl.client.HttpClientBuilder
+import spock.lang.Specification
+import spock.lang.Stepwise
+import spock.lang.Timeout
+
+@Stepwise
+class SampleApiTest extends Specification {
+
+
+
+ String domain;
+
+ def setup(){
+ domain = System.getProperty("api.url")
+ }
+
+ @Timeout(30)
+
+ def "run choice sample task"() {
+ when:
+ def responseJson = sendPostRequest(domain + "/flow/bg/manage/descriptor/add_descriptor.json?business_id=rillFlowSample&feature_name=choiceSample&alias=release", "text/plain", readFileContent("../docs/samples/choice-sample.yaml"))
+
+ then:
+ responseJson.status == 200
+ responseJson.content.ret == true
+
+ when:
+ def submitResponseJson = sendPostRequest(domain + "/flow/submit.json?descriptor_id=rillFlowSample:choiceSample", "application/json", "{\"input_num\":10}")
+
+ then:
+ submitResponseJson.status == 200
+ submitResponseJson.content.execution_id != ""
+
+ expect:
+ assert checkDagStatus(submitResponseJson.content.execution_id)
+ }
+
+ def "run call api sample task"() {
+ when:
+ def responseJson = sendPostRequest(domain + "/flow/bg/manage/descriptor/add_descriptor.json?business_id=rillFlowSample&feature_name=callApiSample&alias=release", "text/plain", readFileContent("../docs/samples/call-api-sample.yaml"))
+
+ then:
+ responseJson.status == 200
+ responseJson.content.ret == true
+
+ when:
+ def submitResponseJson = sendPostRequest(domain + "/flow/submit.json?descriptor_id=rillFlowSample:callApiSample", "application/json", "{\"input_num\":10}")
+
+ then:
+ submitResponseJson.status == 200
+ submitResponseJson.content.execution_id != ""
+
+ expect:
+ assert checkDagStatus(submitResponseJson.content.execution_id)
+
+ }
+
+ private String readFileContent(String filePath) {
+ try {
+ return new File(filePath).text
+ } catch (IOException e) {
+ e.printStackTrace()
+ return null
+ }
+ }
+
+ private boolean checkDagStatus(String executionId) {
+ def i = 0
+ while (i < 10) {
+ def getResponseJson = sendGetRequest(domain + "/flow/get.json?execution_id=" + executionId, "application/json")
+ if (getResponseJson.content.ret.dag_status == "SUCCEED") {
+ return true
+ }
+ i++
+ println getResponseJson.content.ret.dag_status
+ if (getResponseJson.content.ret.dag_status == "FAILED") {
+ println getResponseJson.content.ret
+ }
+ Thread.sleep(1000)
+ }
+ return false
+ }
+
+ private Map sendPostRequest(String url, String contentType, String requestData) {
+ HttpClient httpClient = HttpClientBuilder.create().build()
+ def result = [:]
+ try {
+ HttpPost httpPost = new HttpPost(url)
+ httpPost.addHeader("Content-Type", contentType)
+
+ httpPost.setEntity(new StringEntity(requestData, ContentType.create(contentType)))
+
+ HttpResponse response = httpClient.execute(httpPost)
+ HttpEntity entity = response.getEntity()
+
+ int statusCode = response.getStatusLine().getStatusCode()
+ def responseContent = new JsonSlurper().parse(entity.content)
+ result.status = statusCode
+ result.content = responseContent
+ result as Map
+ } catch (Exception e) {
+ e.printStackTrace()
+ return null
+ }
+ }
+
+ private Map sendGetRequest(String url, String contentType) {
+ HttpClient httpClient = HttpClientBuilder.create().build()
+ def result = [:]
+ try {
+ HttpGet httpGet = new HttpGet(url)
+ httpGet.addHeader("Content-Type", contentType)
+
+ HttpResponse response = httpClient.execute(httpGet)
+ HttpEntity entity = response.getEntity()
+
+ int statusCode = response.getStatusLine().getStatusCode()
+ def responseContent = new JsonSlurper().parse(entity.content)
+ result.status = statusCode
+ result.content = responseContent
+ result as Map
+ } catch (Exception e) {
+ e.printStackTrace()
+ return null
+ }
+ }
+}
\ No newline at end of file