Skip to content

Commit

Permalink
[RM-84612] added useTransport option
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikita-Smirnov-Exactpro committed Feb 2, 2024
1 parent c042a17 commit 09bbcb6
Show file tree
Hide file tree
Showing 12 changed files with 430 additions and 163 deletions.
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ This project uses the Schema API to get its settings.
For local run it needs `custom.json`, `grpc.json`, `rabbitMQ.json` and `mq.json` files.

The `custom.json` file contains RemoteHand URLs map and has the following format:
- **session-alias == "th2-hand" by default**

- **session-alias / sessionAlias == "th2-hand" by default** - hand publishes messages related to UI command under this session alias
- **screenshot-session-alias / screenshotSessionAlias = "th2-hand-screenshot" by default** - hand publishes messages with a screenshot under this session alias
- **session-group / sessionGroup = "th2-hand-group" by default** - hand publishes all messages under this session group.
- **message-batch-limit / messageBatchLimit = 1048576 by default** - limit size for batching messages.
- **drivers-mapping / driversMapping** - UI drivers settings.
- **rh-options / rhOptions** - remote hand options settings.
- **response-timeout-sec / responseTimeoutSec = 120 by default** - timeout for waiting result form remote hand.
- **use-transport / useTransport = true by default** - if true, hand used th2 transport protocol to publish messages via MQ.
```
{
"session-alias": "aliasName",
Expand Down Expand Up @@ -98,8 +106,11 @@ Example of `rabbitMQ.json`:

#### Updated lib:
+ bom: `4.5.0`
+ common: 5.8.0-dev
+ grpc-hand: 3.0.0-dev
+ common: `5.8.0-dev`
+ grpc-hand: `3.0.0-dev`

#### Added lib:
+ common-utils: `2.2.2-dev`

#### Added plugin:
+ org.owasp.dependencycheck: `9.0.9`
Expand Down
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ dependencies {
implementation("com.exactpro.th2:common:5.8.0-dev") {
exclude group: "com.google.guava", module: "guava" // for compatibility with Selenium 3.141.59
}
implementation("com.exactpro.th2:common-utils:2.2.2-dev") {
exclude group: "com.google.guava", module: "guava" // for compatibility with Selenium 3.141.59
}

implementation 'org.slf4j:slf4j-api'

Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/exactpro/th2/hand/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,16 @@ public String getSessionGroup() {
return customConfiguration.getSessionGroup();
}

public String getBook() {
return factory.getBoxConfiguration().getBookName();
}

public String getScreenshotSessionAlias() {
return customConfiguration.getScreenshotSessionAlias();
}

public boolean isUseTransport() { return customConfiguration.isUseTransport(); }

public static class DriverMapping {
public final RemoteManagerType type;
public final String url;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 Exactpro (Exactpro Systems Limited)
* Copyright 2020-2024 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,13 +18,12 @@

import com.exactpro.remotehand.Configuration;
import com.exactpro.th2.common.grpc.ConnectionID;
import com.exactpro.th2.common.grpc.Direction;
import com.exactpro.th2.common.grpc.MessageID;
import com.exactpro.th2.common.grpc.RawMessage;
import com.exactpro.th2.common.grpc.RawMessageMetadata;
import com.exactpro.th2.common.grpc.Direction;
import com.exactpro.th2.common.schema.factory.CommonFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.ByteString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -39,23 +38,21 @@

import static com.exactpro.th2.hand.utils.Utils.getTimestamp;

public final class DefaultMessageStoreBuilder implements MessageStoreBuilder<RawMessage> {
private static final Logger logger = LoggerFactory.getLogger(DefaultMessageStoreBuilder.class);
public final class ProtobufMessageStoreBuilder implements MessageStoreBuilder<RawMessage> {
private static final Logger logger = LoggerFactory.getLogger(ProtobufMessageStoreBuilder.class);

// FIXME: use MAPPER from common
private final ObjectMapper mapper = new ObjectMapper();
private final AtomicLong seqNum;
private final CommonFactory factory;

public DefaultMessageStoreBuilder(CommonFactory factory, AtomicLong seqNum) {
public ProtobufMessageStoreBuilder(CommonFactory factory, AtomicLong seqNum) {
this.factory = factory;
this.seqNum = seqNum;
}

@Override
public RawMessage buildMessage(Map<String, Object> fields, Direction direction, String sessionId, String sessionGroup) {
try {
byte[] bytes = mapper.writeValueAsBytes(fields);
byte[] bytes = CommonFactory.MAPPER.writeValueAsBytes(fields);
return buildMessage(bytes, direction, sessionId, sessionGroup);
} catch (JsonProcessingException e) {
logger.error("Could not encode message as JSON", e);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright 2024 Exactpro (Exactpro Systems Limited)
*
* Licensed 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 com.exactpro.th2.hand.builders.mstore;

import com.exactpro.remotehand.Configuration;
import com.exactpro.th2.common.grpc.Direction;
import com.exactpro.th2.common.schema.factory.CommonFactory;
import com.exactpro.th2.common.schema.message.impl.rabbitmq.transport.MessageId;
import com.exactpro.th2.common.schema.message.impl.rabbitmq.transport.RawMessage;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import static com.exactpro.th2.common.schema.message.impl.rabbitmq.transport.TransportUtilsKt.getTransport;

public final class TransportMessageStoreBuilder implements MessageStoreBuilder<RawMessage> {
private static final Logger logger = LoggerFactory.getLogger(TransportMessageStoreBuilder.class);

private final AtomicLong seqNum;

public TransportMessageStoreBuilder(AtomicLong seqNum) {
this.seqNum = seqNum;
}

@Override
public RawMessage buildMessage(Map<String, Object> fields, Direction direction, String sessionId, String sessionGroup) {
try {
byte[] bytes = CommonFactory.MAPPER.writeValueAsBytes(fields);
return buildMessage(bytes, direction, sessionId, sessionGroup);
} catch (JsonProcessingException e) {
logger.error("Could not encode message as JSON", e);
return null;
}
}

@Override
public RawMessage buildMessage(byte[] bytes, Direction direction, String sessionId, String sessionGroup) {
RawMessage.Builder builder = RawMessage.builder()
.setId(MessageId.builder()
.setSessionAlias(sessionId)
.setDirection(getTransport(direction))
.setSequence(seqNum.incrementAndGet())
.setTimestamp(Instant.now())
.build())
.setBody(bytes);
return builder.build();
}

@Override
public RawMessage buildMessageFromFile(Path path, Direction direction, String sessionId, String sessionGroup) {
String protocol = "image/" + Configuration.getInstance().getDefaultScreenWriter().getScreenshotExtension();

try (InputStream is = Files.newInputStream(path)) {
int length = Math.toIntExact(path.toFile().length());
ByteBuf buffer = Unpooled.buffer(length);
buffer.writeBytes(is, length);

return RawMessage.builder()
.setId(MessageId.builder()
.setSessionAlias(sessionId)
.setDirection(getTransport(direction))
.setSequence(seqNum.incrementAndGet())
.setTimestamp(Instant.now())
.build())
.setProtocol(protocol)
.setBody(buffer)
.build();
} catch (IOException e) {
logger.error("Cannot encode screenshot", e);
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 Exactpro (Exactpro Systems Limited)
* Copyright 2020-2024 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,33 +20,48 @@
import java.util.Map;

import com.exactpro.th2.hand.Config;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;

@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
public class CustomConfiguration {
private static final String DEFAULT_SESSION_GROUP = "th2-hand-group";
private static final String DEFAULT_SESSION_ALIAS = "th2-hand";
private static final String DEFAULT_SCREENSHOT_SESSION_ALIAS = "th2-hand-screenshot";
private static final int DEFAULT_RESPONSE_TIMEOUT = 120;
private static final long DEFAULT_MESSAGE_BATCH_LIMIT = 1024 * 1024; // 1 MB

@JsonProperty(value="session-alias", required = true, defaultValue = DEFAULT_SESSION_ALIAS)
@JsonAlias("sessionAlias")
private String sessionAlias = DEFAULT_SESSION_ALIAS;
private String screenshotSessionAlias = null;
@JsonProperty(value="screenshot-session-alias", required = true, defaultValue = DEFAULT_SCREENSHOT_SESSION_ALIAS)
@JsonAlias("screenshotSessionAlias")
private String screenshotSessionAlias = DEFAULT_SCREENSHOT_SESSION_ALIAS;

@JsonProperty(value="sessionGroup")
private String sessionGroup = null;
@JsonProperty(value="session-group", defaultValue = DEFAULT_SESSION_GROUP)
@JsonAlias("sessionGroup")
private String sessionGroup = DEFAULT_SESSION_GROUP;

@JsonProperty(value="message-batch-limit")
@JsonAlias("messageBatchLimit")
private long messageBatchLimit = DEFAULT_MESSAGE_BATCH_LIMIT;

@JsonProperty(value="driversMapping", required = true)
@JsonProperty(value="drivers-mapping", required = true)
@JsonAlias("driversMapping")
private Map<String, Config.DriverMapping> driversMapping;

@JsonProperty(value="rhOptions")
private Map<String, String> rhOptions = Collections.emptyMap();;
@JsonProperty(value="rh-options")
@JsonAlias("rhOptions")
private Map<String, String> rhOptions = Collections.emptyMap();

@JsonProperty(value="responseTimeoutSec")
@JsonProperty(value="response-timeout-sec")
@JsonAlias("responseTimeoutSec")
private int responseTimeout = DEFAULT_RESPONSE_TIMEOUT;

@JsonProperty(value="use-transport")
@JsonAlias("responseTimeoutSec")
private boolean useTransport = true;

public Map<String, Config.DriverMapping> getDriversMapping() {
return driversMapping;
}
Expand Down Expand Up @@ -77,4 +92,8 @@ public String getScreenshotSessionAlias() {
public long getMessageBatchLimit() {
return messageBatchLimit;
}

public boolean isUseTransport() {
return useTransport;
}
}
35 changes: 25 additions & 10 deletions src/main/java/com/exactpro/th2/hand/services/MessageHandler.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 Exactpro (Exactpro Systems Limited)
* Copyright 2020-2024 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,22 +19,25 @@
import com.exactpro.th2.act.grpc.hand.RhActionsBatch;
import com.exactpro.th2.act.grpc.hand.RhBatchResponse;
import com.exactpro.th2.common.schema.factory.CommonFactory;
import com.exactpro.th2.common.utils.message.transport.MessageUtilsKt;
import com.exactpro.th2.hand.Config;
import com.exactpro.th2.hand.RhConnectionManager;
import com.exactpro.th2.hand.builders.events.DefaultEventBuilder;
import com.exactpro.th2.hand.builders.mstore.DefaultMessageStoreBuilder;
import com.exactpro.th2.hand.builders.mstore.ProtobufMessageStoreBuilder;
import com.exactpro.th2.hand.builders.mstore.TransportMessageStoreBuilder;
import com.exactpro.th2.hand.builders.script.ScriptBuilder;
import com.exactpro.th2.hand.requestexecutors.ActionsBatchExecutor;
import com.exactpro.th2.hand.services.estore.EventStoreHandler;
import com.exactpro.th2.hand.services.estore.EventStoreSender;
import com.exactpro.th2.hand.services.mstore.MessageStoreHandler;
import com.exactpro.th2.hand.services.mstore.MessageStoreSender;
import com.exactpro.th2.hand.services.mstore.ProtobufMessageStoreSender;
import com.exactpro.th2.hand.services.mstore.TransportMessageStoreSender;

import java.util.concurrent.atomic.AtomicLong;

public class MessageHandler implements AutoCloseable {
private final Config config;
private final MessageStoreHandler messageStoreHandler;
private final MessageStoreHandler<?> messageStoreHandler;
private final EventStoreHandler eventStoreHandler;
private final RhConnectionManager rhConnectionManager;
private final ScriptBuilder scriptBuilder = new ScriptBuilder();
Expand All @@ -43,15 +46,27 @@ public MessageHandler(Config config, AtomicLong seqNum) {
this.config = config;
rhConnectionManager = new RhConnectionManager(config);
CommonFactory factory = config.getFactory();
this.messageStoreHandler = new MessageStoreHandler(
config.getSessionGroup(),
new MessageStoreSender(factory),
new DefaultMessageStoreBuilder(config.getFactory(), seqNum)
);
if (config.isUseTransport()) {
this.messageStoreHandler = new MessageStoreHandler<>(
config.getSessionGroup(),
new TransportMessageStoreSender(factory),
new TransportMessageStoreBuilder(seqNum),
message -> MessageUtilsKt.toProto(message.getId(), config.getBook(), config.getSessionGroup())
);
} else {
this.messageStoreHandler = new MessageStoreHandler<>(
config.getSessionGroup(),
new ProtobufMessageStoreSender(factory),
new ProtobufMessageStoreBuilder(config.getFactory(), seqNum),
message -> message.getMetadata().getId()
);
}


this.eventStoreHandler = new EventStoreHandler(new EventStoreSender(factory.getEventBatchRouter()), new DefaultEventBuilder(factory));
}

public MessageStoreHandler getMessageStoreHandler() {
public MessageStoreHandler<?> getMessageStoreHandler() {
return messageStoreHandler;
}

Expand Down
Loading

0 comments on commit 09bbcb6

Please sign in to comment.