Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/docker-CI.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Docker Build and Push

on:
push:
branches: [ main, develop ]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Extract branch name
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
id: extract_branch
- name: Build the Docker image
run: |
docker build -t registry.tech4comp.dbis.rwth-aachen.de/rwthacis/api-testing-bot:${{ steps.extract_branch.outputs.branch }} .
- name: Push to registry
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PW: ${{ secrets.DOCKER_PW }}
run: |
docker login -u $DOCKER_USERNAME -p $DOCKER_PW registry.tech4comp.dbis.rwth-aachen.de
docker push registry.tech4comp.dbis.rwth-aachen.de/rwthacis/api-testing-bot:${{ steps.extract_branch.outputs.branch }}
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/template_project/output/
/template_project/export/
/api-testing-bot/output/
/api-testing-bot/export/
/node-storage/
/.las2peer/
/tmp/
/log/
/template_project/log/
/api-testing-bot/log/
/lib/
/etc/ivy/ivy.jar
/service/
Expand Down
2 changes: 1 addition & 1 deletion api-testing-bot/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ dependencies {
// compileOnly will be moved into the lib dir afterwards
compileOnly "i5:las2peer-bundle:${project.property('core.version')}"

implementation "org.openapitools.openapidiff:openapi-diff-core:2.1.0-beta.2"
implementation "org.openapitools.openapidiff:openapi-diff-core:2.1.0-beta.3"
implementation "com.googlecode.json-simple:json-simple:1.1.1"
implementation "com.konghq:unirest-java:3.13.10"
implementation "i5:las2peer-api-test-model:0.1.6"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,93 @@
package i5.las2peer.services.apiTestingBot;

import i5.las2peer.api.Context;
import i5.las2peer.api.ManualDeployment;
import i5.las2peer.api.logging.MonitoringEvent;
import i5.las2peer.restMapper.RESTService;
import i5.las2peer.restMapper.annotations.ServicePath;
import i5.las2peer.services.apiTestingBot.context.TestModelingContext;
import i5.las2peer.services.apiTestingBot.util.OpenAPIUtils;
import io.swagger.annotations.Api;
import org.json.simple.JSONObject;

import java.util.HashMap;

@Api
@ServicePath("/apitestingbot")
@ManualDeployment
public class APITestingBot extends RESTService {

public static HashMap<String, TestModelingContext> channelModelingContexts = new HashMap<>();

private String botManagerURL;
private String caeBackendURL;

public APITestingBot() {
setFieldValues();
}

@Override
protected void initResources() {
getResourceConfig().register(RESTResources.class);
}

/**
* Sends a chat message describing the changes between the two given OpenAPI documents.
* @param openAPIDocOld Old OpenAPI document.
* @param openAPIDocUpdated Updated OpenAPI document.
* @param sbfBotName Name of the bot that should send the message.
* @param messenger Messenger that should be used by the bot.
* @param channel Channel to which the message should be posted.
*/
public void sendAPIDocChangesMessage(String openAPIDocOld, String openAPIDocUpdated, String sbfBotName,
String messenger, String channel) {
// only send a message if document has changed
if (OpenAPIUtils.docUnchanged(openAPIDocOld, openAPIDocUpdated)) return;

String message = OpenAPIUtils.getDiffDescriptionMessage(openAPIDocOld, openAPIDocUpdated, messenger);

// create monitoring message that triggers a webhook call to the SBF
// this will trigger a chat message
String webhookUrl = botManagerURL + "/bots/" + sbfBotName + "/webhook";
JSONObject webhook = createWebhook(webhookUrl, createWebhookPayload(message, messenger, channel));
JSONObject monitoringMessage = new JSONObject();
monitoringMessage.put("webhook", webhook);

Context.get().monitorEvent(MonitoringEvent.SERVICE_CUSTOM_MESSAGE_1, monitoringMessage.toJSONString());
}

/**
* Creates a JSONObject that can be used as the content of a monitoring message to trigger a webhook call.
*
* @param url Webhook URL
* @param webhookPayload Payload of the webhook call
* @return JSONObject that can be used as the content of a monitoring message to trigger a webhook call.
*/
private JSONObject createWebhook(String url, JSONObject webhookPayload) {
JSONObject webhook = new JSONObject();
webhook.put("url", url);
webhook.put("payload", webhookPayload);
return webhook;
}

/**
* Creates the payload for a webhook call to the SBF that will trigger a chat message.
*
* @param message Message that the bot should send.
* @param messenger Messenger that should be used by the bot.
* @param channel Channel to which the message should be posted.
* @return JSONObject representing the payload for a webhook call to the SBF that will trigger a chat message.
*/
private JSONObject createWebhookPayload(String message, String messenger, String channel) {
JSONObject webhookPayload = new JSONObject();
webhookPayload.put("event", "chat_message");
webhookPayload.put("message", message);
webhookPayload.put("messenger", messenger);
webhookPayload.put("channel", channel);
return webhookPayload;
}

public String getCaeBackendURL() {
return caeBackendURL;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package i5.las2peer.services.apiTestingBot;

import i5.las2peer.api.Context;
import i5.las2peer.services.apiTestingBot.chat.Intent;
import i5.las2peer.services.apiTestingBot.chat.MessageHandler;
import i5.las2peer.services.apiTestingBot.context.TestModelingContext;
import i5.las2peer.services.apiTestingBot.context.TestModelingState;
import io.swagger.annotations.Api;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

import static i5.las2peer.services.apiTestingBot.context.TestModelingState.*;

@Api
@Path("/")
public class RESTResources {

@GET
@Path("/")
public Response get() {
return Response.status(200).entity("API-Testing-Bot service is running!").build();
}

@POST
@Path("/test/model")
public Response modelTest(String body) {
JSONObject bodyJSON = (JSONObject) JSONValue.parse(body);
String intent = (String) bodyJSON.get("intent");
String message = (String) bodyJSON.get("msg");
String channel = (String) bodyJSON.get("channel");

// get current modeling context for this channel
TestModelingContext context;
if(!APITestingBot.channelModelingContexts.containsKey(channel)) APITestingBot.channelModelingContexts.put(channel, new TestModelingContext());
context = APITestingBot.channelModelingContexts.get(channel);

// get the initial state of the context (at the beginning of this execution)
TestModelingState initialState = context.getState();

boolean handleNextState = false;

StringBuilder responseMessageSB = new StringBuilder();
APITestingBot service = (APITestingBot) Context.get().getService();
MessageHandler messageHandler = new MessageHandler(service.getCaeBackendURL());

do {
if (initialState == INIT && intent.equals(Intent.MODEL_TEST)) {
handleNextState = messageHandler.handleInit(responseMessageSB, context, channel);
}

if ((handleNextState && context.getState() == SELECT_PROJECT) || initialState == SELECT_PROJECT) {
handleNextState = messageHandler.handleProjectSelection(responseMessageSB, context, message);
}

if ((handleNextState && context.getState() == SELECT_MICROSERVICE) || initialState == SELECT_MICROSERVICE) {
handleNextState = messageHandler.handleMicroserviceSelection(responseMessageSB, context, message);
}

if (initialState == NAME_TEST_CASE) {
handleNextState = messageHandler.handleTestCaseName(responseMessageSB, context, message);
}

if (initialState == SELECT_METHOD) {
handleNextState = messageHandler.handleMethodSelection(responseMessageSB, context, message);
}

if ((handleNextState && context.getState() == ENTER_PATH_PARAMS) || initialState == ENTER_PATH_PARAMS) {
handleNextState = messageHandler.handlePathParams(responseMessageSB, context, message);
}

if ((handleNextState && context.getState() == BODY_QUESTION)) {
handleNextState = messageHandler.handleBodyQuestion(responseMessageSB);
}

if (!handleNextState && initialState == BODY_QUESTION) {
handleNextState = messageHandler.handleBodyQuestionAnswer(responseMessageSB, context, intent);
}

if (initialState == ENTER_BODY) {
handleNextState = messageHandler.handleBody(responseMessageSB, context, message);
}

if (handleNextState && context.getState() == ASSERTIONS_QUESTION) {
handleNextState = messageHandler.handleAssertionsQuestion(responseMessageSB);
}

if (initialState == ASSERTIONS_QUESTION) {
handleNextState = messageHandler.handleAssertionsQuestionAnswer(responseMessageSB, context, intent);
}

if (handleNextState && context.getState() == ASSERTION_TYPE_QUESTION) {
handleNextState = messageHandler.handleAssertionTypeQuestion(responseMessageSB);
}

if (initialState == ASSERTION_TYPE_QUESTION) {
handleNextState = messageHandler.handleAssertionTypeQuestionAnswer(responseMessageSB, context, message);
}

if (handleNextState && context.getState() == ENTER_STATUS_CODE) {
handleNextState = messageHandler.handleStatusCodeQuestion(responseMessageSB);
}

if (initialState == ENTER_STATUS_CODE) {
handleNextState = messageHandler.handleStatusCodeInput(responseMessageSB, context, message);
}

if (handleNextState && context.getState() == ASSERTIONS_OVERVIEW) {
handleNextState = messageHandler.handleAssertionsOverview(responseMessageSB, context);
}

if (handleNextState && context.getState() == ADD_ANOTHER_ASSERTION_QUESTION) {
handleNextState = messageHandler.handleAddAssertionQuestion(responseMessageSB);
}

if (initialState == ADD_ANOTHER_ASSERTION_QUESTION) {
handleNextState = messageHandler.handleAddAssertionQuestionAnswer(responseMessageSB, context, intent);
}

if(handleNextState && context.getState() == BODY_ASSERTION_TYPE_QUESTION) {
handleNextState = messageHandler.handleBodyAssertionTypeQuestion(responseMessageSB);
}

if(initialState == BODY_ASSERTION_TYPE_QUESTION) {
handleNextState = messageHandler.handleBodyAssertionTypeInput(responseMessageSB, context, message);
}

if(handleNextState && context.getState() == ENTER_BODY_ASSERTION_PART) {
handleNextState = messageHandler.handleBodyAssertionPartQuestion(responseMessageSB, context);
}

if(initialState == ENTER_BODY_ASSERTION_PART) {
handleNextState = messageHandler.handleBodyAssertionPartInput(responseMessageSB, context, message, intent);
}

if(handleNextState && context.getState() == END_OF_BODY_ASSERTION_QUESTION) {
handleNextState = messageHandler.handleEndOfBodyAssertionQuestion(responseMessageSB, context);
}

if(initialState == END_OF_BODY_ASSERTION_QUESTION) {
handleNextState = messageHandler.handleEndOfBodyAssertionQuestionAnswer(responseMessageSB, context, intent);
}

// set initial state to final (otherwise problems occur in the next loop iterations)
initialState = FINAL;

} while(handleNextState);
String responseMessage = responseMessageSB.toString();

if(responseMessage.isEmpty()) responseMessage = "Error!";

System.out.println("New state is: " + APITestingBot.channelModelingContexts.get(channel).getState().name());

JSONObject res = new JSONObject();
res.put("text", responseMessage);
res.put("closeContext", context.getState() == FINAL);

if(context.getState() == FINAL) {
APITestingBot.channelModelingContexts.remove(channel);
}

return Response.status(200).entity(res.toJSONString()).build();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package i5.las2peer.services.apiTestingBot.chat;

/**
* Rasa intents related to the API testing bot.
*/
public class Intent {
public static String MODEL_TEST = "modeltest";
public static String YES = "yes";
public static String NO = "no";
}
Loading