Skip to content

Commit

Permalink
Merge branch 'fix-waiting-for-start-replaying'
Browse files Browse the repository at this point in the history
# Conflicts:
#	pom.xml
#	protocol-common-jdbc/src/main/java/org/kendar/plugins/JdbcRecordPlugin.java
#	protocol-common/src/main/java/org/kendar/plugins/JdbcReplayingPlugin.java
#	protocol-common/src/main/java/org/kendar/plugins/MockPlugin.java
#	protocol-common/src/main/java/org/kendar/plugins/PluginDescriptor.java
#	protocol-common/src/main/java/org/kendar/plugins/ProtocolPluginDescriptor.java
#	protocol-common/src/main/java/org/kendar/plugins/RecordPlugin.java
#	protocol-common/src/main/java/org/kendar/plugins/ReplayPlugin.java
#	protocol-common/src/main/java/org/kendar/plugins/RewritePlugin.java
#	protocol-common/src/main/java/org/kendar/storage/FileStorageRepository.java
#	protocol-common/src/main/java/org/kendar/storage/NullStorageRepository.java
#	protocol-common/src/main/java/org/kendar/storage/generic/StorageRepository.java
#	protocol-http/src/main/java/org/kendar/http/plugins/HttpErrorPlugin.java
#	protocol-http/src/main/java/org/kendar/http/plugins/HttpLatencyPlugin.java
#	protocol-http/src/main/java/org/kendar/http/plugins/HttpRateLimitPlugin.java
#	protocol-http/src/main/java/org/kendar/http/plugins/HttpRecordPlugin.java
#	protocol-http/src/main/java/org/kendar/http/plugins/HttpReplayPlugin.java
#	protocol-http/src/test/java/org/kendar/http/BasicTest.java
#	protocol-http/src/test/java/org/kendar/http/ReplayRecordFilters.java
#	protocol-http/src/test/java/org/kendar/http/RewriterPluginTest.java
#	protocol-http/src/test/java/org/kendar/http/SimpleTest.java
#	protocol-mysql/src/test/java/org/kendar/mysql/BasicTest.java
#	protocol-postgres/src/test/java/org/kendar/postgres/BasicTest.java
#	protocol-runner/src/main/java/org/kendar/Main.java
#	protocol-runner/src/main/java/org/kendar/command/Amqp091Runner.java
#	protocol-runner/src/main/java/org/kendar/command/HttpRunner.java
#	protocol-runner/src/main/java/org/kendar/command/JdbcRunner.java
#	protocol-runner/src/main/java/org/kendar/command/MongoRunner.java
#	protocol-runner/src/main/java/org/kendar/command/MqttRunner.java
#	protocol-runner/src/main/java/org/kendar/command/RedisRunner.java
#	sample-plugins/src/main/java/org/kendar/sample/plugins/Amqp091Filter.java
#	sample-plugins/src/main/java/org/kendar/sample/plugins/HttpFilter.java
#	sample-plugins/src/main/java/org/kendar/sample/plugins/PostgresFilter.java
  • Loading branch information
kendarorg committed Nov 28, 2024
2 parents 0703baf + 82532cf commit 31d6496
Show file tree
Hide file tree
Showing 105 changed files with 1,779 additions and 11,321 deletions.
1 change: 1 addition & 0 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions .idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

![](protocolmaster_s.gif)

"The Protocol Master" is an infrastructure simulator to test effortlessy your app in minutes (with no coding) supporting HTTP, HTTPS, Postgres, MySQL, Redis, Mqtt, RabbitMQ, AMQP 091 ... and all the compatible ones!
"The Protocol Master" is an infrastructure simulator to test effortlessy your app in minutes (with no coding) supporting
HTTP, HTTPS, Postgres, MySQL, Redis, Mqtt, RabbitMQ, AMQP 091 ... and all the compatible ones!

* Simulate wrong scenarios
* Simulate wrong scenarios
* Block troubles before production
* Simulate whole infrastructure
* Make untestable apps testable
* Easy Chaos engineering

Effortlessy and with zero budget

Expand All @@ -32,9 +34,8 @@ Independent from the stack you are using
### Custom Plugins

You can build your own plugins, just place the Jar into the plugins dir
and intercept all it's intercepted by TPM. Add headers, change data,
and intercept all it's intercepted by TPM. Add headers, change data,
simulate specific needs


## Examples

Expand Down Expand Up @@ -87,6 +88,7 @@ java -jar protocol-runner.jar -protocol http -proxy 9999 \
* Translate postgres and MySQL to any Jdbc supported db like Oracle!
* Plugin-based architecture
* Custom maven repository on [https://maven.kendar.org](https://maven.kendar.org/maven2/releases/org/kendar/protocol/)
* More than 70% Instructions coverage

The configuration is based on command line parameters or a json properties file
for the usage check [here](docs/properties.md)
Expand Down Expand Up @@ -121,15 +123,24 @@ If you want to go on the specific functions by protocol:

## How it was Born

I had an always missing QA environment and all changes should be checked by legal (it was in Electronic ID field). I needed to simulate APIs, Database calls, and full scenarios, from UI to the DB.
I had an always missing QA environment and all changes should be checked by legal (it was in Electronic ID field). I
needed to simulate APIs, Database calls, and full scenarios, from UI to the DB.

I started developing a series of docker container in PHP to intercept all incoming and outgoing HTTP/S call, with DNS server and certificates, you can find it [here](https://github.com/kendarorg/HttpAnsweringMachine.php).
I started developing a series of docker container in PHP to intercept all incoming and outgoing HTTP/S call, with DNS
server and certificates, you can find it [here](https://github.com/kendarorg/HttpAnsweringMachine.php).

Becoming the thing too hard to cope with i started the development of a Java integrated version with fancy UI and all integrated service, the [HttpAnsweringMachine](https://github.com/kendarorg/HttpAnsweringMachine) based on Spring-Boot and leveraging a custom routing system, dns server and so on.
Becoming the thing too hard to cope with i started the development of a Java integrated version with fancy UI and all
integrated service, the [HttpAnsweringMachine](https://github.com/kendarorg/HttpAnsweringMachine) based on Spring-Boot
and leveraging a custom routing system, dns server and so on.

But that was too really hard to interact with. I started developing a JDBC->HTTP->JDBC driver, [Janus-Jdbc](https://github.com/kendarorg/janus-jdbc) from scratch, then started creating a similar thing for .NET, thing went rogues in a short time with [Janus-Ado](https://github.com/kendarorg/janus-ado). But i started understanding Postgres protocol.
But that was too really hard to interact with. I started developing a JDBC->HTTP->JDBC
driver, [Janus-Jdbc](https://github.com/kendarorg/janus-jdbc) from scratch, then started creating a similar thing for
.NET, thing went rogues in a short time with [Janus-Ado](https://github.com/kendarorg/janus-ado). But i started
understanding Postgres protocol.

I started then with a command line utility to parse and translate binary protocols and that's how "The Protocol Master" was born. Always with a plugin-based architecture. Then i started adapting all the knowledge of HttpAnsweringMachine inside it to handle HTTP/S.
I started then with a command line utility to parse and translate binary protocols and that's how "The Protocol Master"
was born. Always with a plugin-based architecture. Then i started adapting all the knowledge of HttpAnsweringMachine
inside it to handle HTTP/S.

## If you like it Buy me a coffe :)

Expand Down
5 changes: 2 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
* Expose the connections for protocol on apis
* Send mock messages amqp,mqtt,redis
* Remove spring boot
* Cleanup setSettings
* Common
* Test internal apis
* Remove withstorage
* Http
* test brotli compression
* Use anonymous Object for serialization for HTTP Multipart
Expand All @@ -27,6 +25,7 @@ STATE CHARTS:
* https://en.wikipedia.org/wiki/DOT_(graph_description_language)

Dev proxy like

* https://learn.microsoft.com/en-us/microsoft-cloud/dev/dev-proxy/technical-reference/authplugin
* https://learn.microsoft.com/en-us/microsoft-cloud/dev/dev-proxy/technical-reference/cachingguidanceplugin
* https://learn.microsoft.com/en-us/microsoft-cloud/dev/dev-proxy/technical-reference/executionsummaryplugin
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package org.kendar.amqp.v09.plugins;

import com.fasterxml.jackson.databind.JsonNode;
import org.kendar.plugins.RecordingPlugin;
import org.kendar.plugins.RecordPlugin;
import org.kendar.plugins.settings.BasicRecordPluginSettings;
import org.kendar.storage.CompactLine;
import org.kendar.storage.StorageItem;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AmqpRecordingPlugin extends RecordingPlugin {
public class AmqpRecordPlugin extends RecordPlugin<BasicRecordPluginSettings> {
private static final List<String> toAvoid = List.of("byte[]",
"ConnectionStartOk", "ConnectionTuneOk", "ConnectionOpen", "ChannelOpen", "BasicPublish",
"HeaderFrame", "BasicPublish", "BodyFrame", "BasicAck", "ChannelClose", "ConnectionClose",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,24 @@
import org.kendar.amqp.v09.messages.frames.HeaderFrame;
import org.kendar.amqp.v09.messages.methods.basic.BasicCancel;
import org.kendar.amqp.v09.messages.methods.basic.BasicDeliver;
import org.kendar.plugins.ReplayingPlugin;
import org.kendar.plugins.ReplayPlugin;
import org.kendar.plugins.settings.BasicReplayPluginSettings;
import org.kendar.protocol.context.ProtoContext;
import org.kendar.protocol.messages.ReturnMessage;
import org.kendar.proxy.PluginContext;
import org.kendar.storage.StorageItem;
import org.kendar.storage.generic.LineToRead;
import org.kendar.utils.JsonMapper;
import org.kendar.utils.Sleeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

public class AmqpReplayingPlugin extends ReplayingPlugin {
public class AmqpReplayPlugin extends ReplayPlugin<BasicReplayPluginSettings> {
protected static final JsonMapper mapper = new JsonMapper();
private static final Logger log = LoggerFactory.getLogger(AmqpReplayingPlugin.class);
private static final Logger log = LoggerFactory.getLogger(AmqpReplayPlugin.class);

@Override
public String getProtocol() {
Expand All @@ -33,7 +36,7 @@ protected boolean hasCallbacks() {
}

@Override
protected void buildState(PluginContext pluginContext, ProtoContext context, Object in, Object outObj, Object toread) {
protected void buildState(PluginContext pluginContext, ProtoContext context, Object in, Object outObj, Object toread, LineToRead lineToRead) {
if (outObj == null) return;
if (toread == null) return;
var out = mapper.toJsonNode(outObj);
Expand All @@ -49,7 +52,19 @@ protected void buildState(PluginContext pluginContext, ProtoContext context, Obj
@Override
protected void sendBackResponses(ProtoContext context, List<StorageItem> storageItems) {
if (storageItems.isEmpty()) return;
long lastTimestamp =0;
for (var item : storageItems) {
if(getSettings().isRespectCallDuration()) {
if (lastTimestamp == 0) {
lastTimestamp = item.getTimestamp();
} else if (item.getTimestamp() > 0) {
var wait = item.getTimestamp() - lastTimestamp;
lastTimestamp = item.getTimestamp();
if (wait > 0) {
Sleeper.sleep(wait);
}
}
}
var out = mapper.toJsonNode(item.getOutput());
var clazz = item.getOutputType();
ReturnMessage fr = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@

import com.rabbitmq.client.ConnectionFactory;
import org.junit.jupiter.api.TestInfo;
import org.kendar.amqp.v09.plugins.AmqpRecordingPlugin;
import org.kendar.amqp.v09.plugins.AmqpRecordPlugin;
import org.kendar.plugins.settings.BasicRecordPluginSettings;
import org.kendar.server.TcpServer;
import org.kendar.settings.ByteProtocolSettingsWithLogin;
import org.kendar.settings.GlobalSettings;
import org.kendar.storage.FileStorageRepository;
import org.kendar.storage.NullStorageRepository;
import org.kendar.storage.generic.StorageRepository;
Expand Down Expand Up @@ -70,7 +73,9 @@ public static void beforeEachBase(TestInfo testInfo) {
}
}
storage.initialize();
var pl = new AmqpRecordingPlugin().withStorage(storage);
var gs = new GlobalSettings();
gs.putService("storage",storage);
var pl = new AmqpRecordPlugin().initialize(gs,new ByteProtocolSettingsWithLogin(),new BasicRecordPluginSettings());;
proxy.setPlugins(List.of(
pl));
pl.setActive(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.kendar.amqp.v09.plugins.AmqpReplayingPlugin;
import org.kendar.amqp.v09.plugins.AmqpReplayPlugin;
import org.kendar.plugins.settings.BasicReplayPluginSettings;
import org.kendar.server.TcpServer;
import org.kendar.settings.ByteProtocolSettingsWithLogin;
import org.kendar.settings.GlobalSettings;
import org.kendar.storage.FileStorageRepository;
import org.kendar.storage.generic.StorageRepository;
import org.kendar.utils.Sleeper;
Expand Down Expand Up @@ -66,7 +69,9 @@ void test2_differentChannelAndConnection() throws Exception {
StorageRepository storage = new FileStorageRepository(Path.of("src",
"test", "resources", "test2_differentChannelAndConnection"));
storage.initialize();
var pl = new AmqpReplayingPlugin().withStorage(storage);
var gs = new GlobalSettings();
gs.putService("storage",storage);
var pl = new AmqpReplayPlugin().initialize(gs,new ByteProtocolSettingsWithLogin(),new BasicReplayPluginSettings());
proxy.setPlugins(List.of(pl));
pl.setActive(true);

Expand Down Expand Up @@ -150,7 +155,9 @@ void test5_noPublish() throws Exception {
StorageRepository storage = new FileStorageRepository(Path.of("src",
"test", "resources", "test5_noPublish"));
storage.initialize();
var pl = new AmqpReplayingPlugin().withStorage(storage);
var gs = new GlobalSettings();
gs.putService("storage",storage);
var pl = new AmqpReplayPlugin().initialize(gs,new ByteProtocolSettingsWithLogin(),new BasicReplayPluginSettings());
proxy.setPlugins(List.of(pl));
pl.setActive(true);

Expand Down Expand Up @@ -224,7 +231,9 @@ void test3_openConnection() throws Exception {
StorageRepository storage = new FileStorageRepository(Path.of("src",
"test", "resources", "test3_openConnection"));
storage.initialize();
var pl = new AmqpReplayingPlugin().withStorage(storage);
var gs = new GlobalSettings();
gs.putService("storage",storage);
var pl = new AmqpReplayPlugin().initialize(gs,new ByteProtocolSettingsWithLogin(),new BasicReplayPluginSettings());
proxy.setPlugins(List.of(pl));
pl.setActive(true);

Expand Down
45 changes: 45 additions & 0 deletions protocol-common-jdbc/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.kendar.protocol</groupId>
<artifactId>protocol-master</artifactId>
<version>${revision}</version>
</parent>

<artifactId>protocol-common-jdbc</artifactId>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.pf4j</groupId>
<artifactId>pf4j</artifactId>
<version>${pl4j.version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.api.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.kendar.protocol</groupId>
<artifactId>protocol-common</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.kendar.protocol</groupId>
<artifactId>protocol-test</artifactId>
<version>${revision}</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.kendar.plugins;

import org.kendar.plugins.settings.BasicReplayPluginSettings;
import org.kendar.protocol.context.ProtoContext;
import org.kendar.proxy.PluginContext;
import org.kendar.sql.jdbc.SelectResult;
import org.kendar.sql.jdbc.proxy.JdbcCall;
import org.kendar.sql.jdbc.storage.JdbcResponse;
import org.kendar.storage.generic.LineToRead;

public abstract class JdbcReplayPlugin extends ReplayPlugin<BasicReplayPluginSettings>{

public abstract String getProtocol();

@Override
protected void buildState(PluginContext pluginContext, ProtoContext context, Object in, Object outputItem, Object aClass, LineToRead lineToRead) {
var outObj = (SelectResult)aClass;
var req = (JdbcCall)in;
if (lineToRead != null && lineToRead.getStorageItem() != null
&& lineToRead.getStorageItem().getOutput() != null) {
var source = lineToRead.getStorageItem().retrieveOutAs(JdbcResponse.class);
outObj.fill(source.getSelectResult());
} else if (lineToRead != null && lineToRead.getCompactLine() != null) {// if(in.getQuery().trim().toLowerCase().startsWith("set")){
//completedIndexes.add((int) lineToRead.getCompactLine().getIndex());
if (lineToRead.getCompactLine().getTags().get("isIntResult").equalsIgnoreCase("true")) {
SelectResult resultset = new SelectResult();
resultset.setIntResult(true);
resultset.setCount(Integer.parseInt(lineToRead.getCompactLine().getTags().get("resultsCount")));
outObj.fill(resultset);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import java.util.List;

public abstract class JdbcRewritePlugin extends RewritePlugin<JdbcCall, SelectResult, String> {
public abstract class JdbcRewritePlugin extends RewritePlugin<JdbcCall, SelectResult, RewritePluginSettings, String> {
@Override
protected void replaceData(ReplacerItemInstance item, String toReplace, JdbcCall request, SelectResult response) {
var replaced = item.run(toReplace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@ public static String parseParameters(String query, SqlStringParser parser) {
} else {
realQuery.append(item);
}
realQuery.append(" ");
}
query = realQuery.toString();
query = realQuery.toString().trim();
return query;
}

Expand Down
Loading

0 comments on commit 31d6496

Please sign in to comment.