Skip to content

Commit c691edc

Browse files
authored
Merge pull request #6 from rwth-acis/develop
First Release
2 parents 707d2b1 + 38d35c4 commit c691edc

17 files changed

+1696
-4
lines changed

.github/workflows/docker-CI.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Docker Build and Push
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v2
12+
- name: Extract branch name
13+
shell: bash
14+
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
15+
id: extract_branch
16+
- name: Build the Docker image
17+
run: |
18+
docker build -t registry.tech4comp.dbis.rwth-aachen.de/rwthacis/api-testing-bot:${{ steps.extract_branch.outputs.branch }} .
19+
- name: Push to registry
20+
env:
21+
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
22+
DOCKER_PW: ${{ secrets.DOCKER_PW }}
23+
run: |
24+
docker login -u $DOCKER_USERNAME -p $DOCKER_PW registry.tech4comp.dbis.rwth-aachen.de
25+
docker push registry.tech4comp.dbis.rwth-aachen.de/rwthacis/api-testing-bot:${{ steps.extract_branch.outputs.branch }}

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
/template_project/output/
2-
/template_project/export/
1+
/api-testing-bot/output/
2+
/api-testing-bot/export/
33
/node-storage/
44
/.las2peer/
55
/tmp/
66
/log/
7-
/template_project/log/
7+
/api-testing-bot/log/
88
/lib/
99
/etc/ivy/ivy.jar
1010
/service/

api-testing-bot/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ dependencies {
2525
// compileOnly will be moved into the lib dir afterwards
2626
compileOnly "i5:las2peer-bundle:${project.property('core.version')}"
2727

28-
implementation "org.openapitools.openapidiff:openapi-diff-core:2.1.0-beta.2"
28+
implementation "org.openapitools.openapidiff:openapi-diff-core:2.1.0-beta.3"
2929
implementation "com.googlecode.json-simple:json-simple:1.1.1"
3030
implementation "com.konghq:unirest-java:3.13.10"
3131
implementation "i5:las2peer-api-test-model:0.1.6"
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,93 @@
11
package i5.las2peer.services.apiTestingBot;
22

3+
import i5.las2peer.api.Context;
34
import i5.las2peer.api.ManualDeployment;
5+
import i5.las2peer.api.logging.MonitoringEvent;
46
import i5.las2peer.restMapper.RESTService;
57
import i5.las2peer.restMapper.annotations.ServicePath;
8+
import i5.las2peer.services.apiTestingBot.context.TestModelingContext;
9+
import i5.las2peer.services.apiTestingBot.util.OpenAPIUtils;
610
import io.swagger.annotations.Api;
11+
import org.json.simple.JSONObject;
12+
13+
import java.util.HashMap;
714

815
@Api
916
@ServicePath("/apitestingbot")
1017
@ManualDeployment
1118
public class APITestingBot extends RESTService {
1219

20+
public static HashMap<String, TestModelingContext> channelModelingContexts = new HashMap<>();
21+
1322
private String botManagerURL;
23+
private String caeBackendURL;
1424

1525
public APITestingBot() {
1626
setFieldValues();
1727
}
1828

29+
@Override
30+
protected void initResources() {
31+
getResourceConfig().register(RESTResources.class);
32+
}
33+
34+
/**
35+
* Sends a chat message describing the changes between the two given OpenAPI documents.
36+
* @param openAPIDocOld Old OpenAPI document.
37+
* @param openAPIDocUpdated Updated OpenAPI document.
38+
* @param sbfBotName Name of the bot that should send the message.
39+
* @param messenger Messenger that should be used by the bot.
40+
* @param channel Channel to which the message should be posted.
41+
*/
42+
public void sendAPIDocChangesMessage(String openAPIDocOld, String openAPIDocUpdated, String sbfBotName,
43+
String messenger, String channel) {
44+
// only send a message if document has changed
45+
if (OpenAPIUtils.docUnchanged(openAPIDocOld, openAPIDocUpdated)) return;
46+
47+
String message = OpenAPIUtils.getDiffDescriptionMessage(openAPIDocOld, openAPIDocUpdated, messenger);
48+
49+
// create monitoring message that triggers a webhook call to the SBF
50+
// this will trigger a chat message
51+
String webhookUrl = botManagerURL + "/bots/" + sbfBotName + "/webhook";
52+
JSONObject webhook = createWebhook(webhookUrl, createWebhookPayload(message, messenger, channel));
53+
JSONObject monitoringMessage = new JSONObject();
54+
monitoringMessage.put("webhook", webhook);
55+
56+
Context.get().monitorEvent(MonitoringEvent.SERVICE_CUSTOM_MESSAGE_1, monitoringMessage.toJSONString());
57+
}
58+
59+
/**
60+
* Creates a JSONObject that can be used as the content of a monitoring message to trigger a webhook call.
61+
*
62+
* @param url Webhook URL
63+
* @param webhookPayload Payload of the webhook call
64+
* @return JSONObject that can be used as the content of a monitoring message to trigger a webhook call.
65+
*/
66+
private JSONObject createWebhook(String url, JSONObject webhookPayload) {
67+
JSONObject webhook = new JSONObject();
68+
webhook.put("url", url);
69+
webhook.put("payload", webhookPayload);
70+
return webhook;
71+
}
72+
73+
/**
74+
* Creates the payload for a webhook call to the SBF that will trigger a chat message.
75+
*
76+
* @param message Message that the bot should send.
77+
* @param messenger Messenger that should be used by the bot.
78+
* @param channel Channel to which the message should be posted.
79+
* @return JSONObject representing the payload for a webhook call to the SBF that will trigger a chat message.
80+
*/
81+
private JSONObject createWebhookPayload(String message, String messenger, String channel) {
82+
JSONObject webhookPayload = new JSONObject();
83+
webhookPayload.put("event", "chat_message");
84+
webhookPayload.put("message", message);
85+
webhookPayload.put("messenger", messenger);
86+
webhookPayload.put("channel", channel);
87+
return webhookPayload;
88+
}
89+
90+
public String getCaeBackendURL() {
91+
return caeBackendURL;
92+
}
1993
}
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package i5.las2peer.services.apiTestingBot;
2+
3+
import i5.las2peer.api.Context;
4+
import i5.las2peer.services.apiTestingBot.chat.Intent;
5+
import i5.las2peer.services.apiTestingBot.chat.MessageHandler;
6+
import i5.las2peer.services.apiTestingBot.context.TestModelingContext;
7+
import i5.las2peer.services.apiTestingBot.context.TestModelingState;
8+
import io.swagger.annotations.Api;
9+
import org.json.simple.JSONObject;
10+
import org.json.simple.JSONValue;
11+
12+
import javax.ws.rs.GET;
13+
import javax.ws.rs.POST;
14+
import javax.ws.rs.Path;
15+
import javax.ws.rs.core.Response;
16+
17+
import static i5.las2peer.services.apiTestingBot.context.TestModelingState.*;
18+
19+
@Api
20+
@Path("/")
21+
public class RESTResources {
22+
23+
@GET
24+
@Path("/")
25+
public Response get() {
26+
return Response.status(200).entity("API-Testing-Bot service is running!").build();
27+
}
28+
29+
@POST
30+
@Path("/test/model")
31+
public Response modelTest(String body) {
32+
JSONObject bodyJSON = (JSONObject) JSONValue.parse(body);
33+
String intent = (String) bodyJSON.get("intent");
34+
String message = (String) bodyJSON.get("msg");
35+
String channel = (String) bodyJSON.get("channel");
36+
37+
// get current modeling context for this channel
38+
TestModelingContext context;
39+
if(!APITestingBot.channelModelingContexts.containsKey(channel)) APITestingBot.channelModelingContexts.put(channel, new TestModelingContext());
40+
context = APITestingBot.channelModelingContexts.get(channel);
41+
42+
// get the initial state of the context (at the beginning of this execution)
43+
TestModelingState initialState = context.getState();
44+
45+
boolean handleNextState = false;
46+
47+
StringBuilder responseMessageSB = new StringBuilder();
48+
APITestingBot service = (APITestingBot) Context.get().getService();
49+
MessageHandler messageHandler = new MessageHandler(service.getCaeBackendURL());
50+
51+
do {
52+
if (initialState == INIT && intent.equals(Intent.MODEL_TEST)) {
53+
handleNextState = messageHandler.handleInit(responseMessageSB, context, channel);
54+
}
55+
56+
if ((handleNextState && context.getState() == SELECT_PROJECT) || initialState == SELECT_PROJECT) {
57+
handleNextState = messageHandler.handleProjectSelection(responseMessageSB, context, message);
58+
}
59+
60+
if ((handleNextState && context.getState() == SELECT_MICROSERVICE) || initialState == SELECT_MICROSERVICE) {
61+
handleNextState = messageHandler.handleMicroserviceSelection(responseMessageSB, context, message);
62+
}
63+
64+
if (initialState == NAME_TEST_CASE) {
65+
handleNextState = messageHandler.handleTestCaseName(responseMessageSB, context, message);
66+
}
67+
68+
if (initialState == SELECT_METHOD) {
69+
handleNextState = messageHandler.handleMethodSelection(responseMessageSB, context, message);
70+
}
71+
72+
if ((handleNextState && context.getState() == ENTER_PATH_PARAMS) || initialState == ENTER_PATH_PARAMS) {
73+
handleNextState = messageHandler.handlePathParams(responseMessageSB, context, message);
74+
}
75+
76+
if ((handleNextState && context.getState() == BODY_QUESTION)) {
77+
handleNextState = messageHandler.handleBodyQuestion(responseMessageSB);
78+
}
79+
80+
if (!handleNextState && initialState == BODY_QUESTION) {
81+
handleNextState = messageHandler.handleBodyQuestionAnswer(responseMessageSB, context, intent);
82+
}
83+
84+
if (initialState == ENTER_BODY) {
85+
handleNextState = messageHandler.handleBody(responseMessageSB, context, message);
86+
}
87+
88+
if (handleNextState && context.getState() == ASSERTIONS_QUESTION) {
89+
handleNextState = messageHandler.handleAssertionsQuestion(responseMessageSB);
90+
}
91+
92+
if (initialState == ASSERTIONS_QUESTION) {
93+
handleNextState = messageHandler.handleAssertionsQuestionAnswer(responseMessageSB, context, intent);
94+
}
95+
96+
if (handleNextState && context.getState() == ASSERTION_TYPE_QUESTION) {
97+
handleNextState = messageHandler.handleAssertionTypeQuestion(responseMessageSB);
98+
}
99+
100+
if (initialState == ASSERTION_TYPE_QUESTION) {
101+
handleNextState = messageHandler.handleAssertionTypeQuestionAnswer(responseMessageSB, context, message);
102+
}
103+
104+
if (handleNextState && context.getState() == ENTER_STATUS_CODE) {
105+
handleNextState = messageHandler.handleStatusCodeQuestion(responseMessageSB);
106+
}
107+
108+
if (initialState == ENTER_STATUS_CODE) {
109+
handleNextState = messageHandler.handleStatusCodeInput(responseMessageSB, context, message);
110+
}
111+
112+
if (handleNextState && context.getState() == ASSERTIONS_OVERVIEW) {
113+
handleNextState = messageHandler.handleAssertionsOverview(responseMessageSB, context);
114+
}
115+
116+
if (handleNextState && context.getState() == ADD_ANOTHER_ASSERTION_QUESTION) {
117+
handleNextState = messageHandler.handleAddAssertionQuestion(responseMessageSB);
118+
}
119+
120+
if (initialState == ADD_ANOTHER_ASSERTION_QUESTION) {
121+
handleNextState = messageHandler.handleAddAssertionQuestionAnswer(responseMessageSB, context, intent);
122+
}
123+
124+
if(handleNextState && context.getState() == BODY_ASSERTION_TYPE_QUESTION) {
125+
handleNextState = messageHandler.handleBodyAssertionTypeQuestion(responseMessageSB);
126+
}
127+
128+
if(initialState == BODY_ASSERTION_TYPE_QUESTION) {
129+
handleNextState = messageHandler.handleBodyAssertionTypeInput(responseMessageSB, context, message);
130+
}
131+
132+
if(handleNextState && context.getState() == ENTER_BODY_ASSERTION_PART) {
133+
handleNextState = messageHandler.handleBodyAssertionPartQuestion(responseMessageSB, context);
134+
}
135+
136+
if(initialState == ENTER_BODY_ASSERTION_PART) {
137+
handleNextState = messageHandler.handleBodyAssertionPartInput(responseMessageSB, context, message, intent);
138+
}
139+
140+
if(handleNextState && context.getState() == END_OF_BODY_ASSERTION_QUESTION) {
141+
handleNextState = messageHandler.handleEndOfBodyAssertionQuestion(responseMessageSB, context);
142+
}
143+
144+
if(initialState == END_OF_BODY_ASSERTION_QUESTION) {
145+
handleNextState = messageHandler.handleEndOfBodyAssertionQuestionAnswer(responseMessageSB, context, intent);
146+
}
147+
148+
// set initial state to final (otherwise problems occur in the next loop iterations)
149+
initialState = FINAL;
150+
151+
} while(handleNextState);
152+
String responseMessage = responseMessageSB.toString();
153+
154+
if(responseMessage.isEmpty()) responseMessage = "Error!";
155+
156+
System.out.println("New state is: " + APITestingBot.channelModelingContexts.get(channel).getState().name());
157+
158+
JSONObject res = new JSONObject();
159+
res.put("text", responseMessage);
160+
res.put("closeContext", context.getState() == FINAL);
161+
162+
if(context.getState() == FINAL) {
163+
APITestingBot.channelModelingContexts.remove(channel);
164+
}
165+
166+
return Response.status(200).entity(res.toJSONString()).build();
167+
}
168+
169+
170+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package i5.las2peer.services.apiTestingBot.chat;
2+
3+
/**
4+
* Rasa intents related to the API testing bot.
5+
*/
6+
public class Intent {
7+
public static String MODEL_TEST = "modeltest";
8+
public static String YES = "yes";
9+
public static String NO = "no";
10+
}

0 commit comments

Comments
 (0)