You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2023/04/21 06:46:21 UTC
[camel-quarkus] branch main updated: Snmp: Extend test coverage #4797
This is an automated email from the ASF dual-hosted git repository.
jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/main by this push:
new ee6cadb250 Snmp: Extend test coverage #4797
ee6cadb250 is described below
commit ee6cadb250713b78e8a3e45a5bee3bd508d04ca2
Author: JiriOndrusek <on...@gmail.com>
AuthorDate: Thu Apr 20 15:31:01 2023 +0200
Snmp: Extend test coverage #4797
---
integration-tests-jvm/snmp/pom.xml | 5 +
.../quarkus/component/snmp/it/SnmpResource.java | 120 ++++++++++++++++--
.../camel/quarkus/component/snmp/it/SnmpRoute.java | 64 ++++++++++
.../camel/quarkus/component/snmp/it/SnmpTest.java | 67 +++++++++-
.../component/snmp/it/SnmpTestResource.java | 135 +++++++++++++++++++++
5 files changed, 375 insertions(+), 16 deletions(-)
diff --git a/integration-tests-jvm/snmp/pom.xml b/integration-tests-jvm/snmp/pom.xml
index b64813cbfb..effa7b4291 100644
--- a/integration-tests-jvm/snmp/pom.xml
+++ b/integration-tests-jvm/snmp/pom.xml
@@ -46,6 +46,11 @@
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.awaitility</groupId>
+ <artifactId>awaitility</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
diff --git a/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpResource.java b/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpResource.java
index 8ff7bcda6f..5b573a6f1d 100644
--- a/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpResource.java
+++ b/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpResource.java
@@ -16,35 +16,129 @@
*/
package org.apache.camel.quarkus.component.snmp.it;
+import java.util.Deque;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
+import jakarta.inject.Named;
import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
-import org.apache.camel.CamelContext;
-import org.jboss.logging.Logger;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.snmp.SnmpMessage;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.snmp4j.PDU;
+import org.snmp4j.PDUv1;
+import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.smi.OID;
+import org.snmp4j.smi.OctetString;
+import org.snmp4j.smi.TimeTicks;
+import org.snmp4j.smi.Variable;
+import org.snmp4j.smi.VariableBinding;
@Path("/snmp")
@ApplicationScoped
public class SnmpResource {
- private static final Logger LOG = Logger.getLogger(SnmpResource.class);
+ @ConfigProperty(name = "snmpListenAddress")
+ String snmpListenAddress;
+
+ @Inject
+ @Named("snmpTrapResults")
+ Map<String, Deque<SnmpMessage>> snmpResults;
- private static final String COMPONENT_SNMP = "snmp";
@Inject
- CamelContext context;
+ ProducerTemplate producerTemplate;
- @Path("/load/component/snmp")
+ @Path("/producePDU")
@GET
@Produces(MediaType.TEXT_PLAIN)
- public Response loadComponentSnmp() throws Exception {
- /* This is an autogenerated test */
- if (context.getComponent(COMPONENT_SNMP) != null) {
- return Response.ok().build();
- }
- LOG.warnf("Could not load [%s] from the Camel context", COMPONENT_SNMP);
- return Response.status(500, COMPONENT_SNMP + " could not be loaded from the Camel context").build();
+ public Response producePDU() {
+ String url = String.format("snmp://%s?retries=1", snmpListenAddress);
+ SnmpMessage pdu = producerTemplate.requestBody(url, "", SnmpMessage.class);
+
+ String response = pdu.getSnmpMessage().getVariableBindings().stream()
+ .filter(vb -> vb.getOid().equals(SnmpConstants.sysDescr))
+ .map(vb -> vb.getVariable().toString())
+ .collect(Collectors.joining());
+
+ return Response.ok(response).build();
+ }
+
+ @Path("/sendPoll")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response sendPoll() {
+ SnmpMessage pdu = producerTemplate.requestBody("direct:producePoll", "", SnmpMessage.class);
+
+ String response = pdu.getSnmpMessage().getVariableBindings().stream()
+ .filter(vb -> vb.getOid().equals(SnmpConstants.sysDescr))
+ .map(vb -> vb.getVariable().toString())
+ .collect(Collectors.joining());
+
+ return Response.ok(response).build();
+ }
+
+ @Path("/getNext")
+ @POST
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response getNext(String payload) {
+ String url = String.format("snmp://%s?type=GET_NEXT&retries=1&protocol=udp&oids=%s", snmpListenAddress,
+ SnmpConstants.sysDescr);
+ List<SnmpMessage> pdu = producerTemplate.requestBody(url, "", List.class);
+
+ String response = pdu.stream()
+ .flatMap(m -> m.getSnmpMessage().getVariableBindings().stream())
+ .filter(vb -> vb.getOid().equals(SnmpConstants.sysDescr))
+ .map(vb -> vb.getVariable().toString())
+ .collect(Collectors.joining(","));
+
+ return Response.ok(response).build();
+ }
+
+ @Path("/produceTrap")
+ @POST
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response sendTrap(String payload) {
+ String url = "snmp:127.0.0.1:1662?protocol=udp&type=TRAP&snmpVersion=0)";
+ PDU trap = createTrap(payload);
+
+ producerTemplate.sendBody(url, trap);
+
+ return Response.ok().build();
+ }
+
+ @Path("/results")
+ @POST
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response results(String from) throws Exception {
+ OID oid = "trap".equals(from) ? new OID("1.2.3.4.5") : SnmpConstants.sysDescr;
+ String result = snmpResults.get(from).stream().map(m -> m.getSnmpMessage().getVariable(oid).toString())
+ .collect(Collectors.joining(","));
+
+ return Response.ok(result).build();
+ }
+
+ public PDU createTrap(String payload) {
+ PDUv1 trap = new PDUv1();
+ trap.setGenericTrap(PDUv1.ENTERPRISE_SPECIFIC);
+ trap.setSpecificTrap(1);
+
+ OID oid = new OID("1.2.3.4.5");
+ trap.add(new VariableBinding(SnmpConstants.snmpTrapOID, oid));
+ trap.add(new VariableBinding(SnmpConstants.sysUpTime, new TimeTicks(5000))); // put your uptime here
+ trap.add(new VariableBinding(SnmpConstants.sysDescr, new OctetString("System Description")));
+ trap.setEnterprise(oid);
+
+ //Add Payload
+ Variable var = new OctetString(payload);
+ trap.add(new VariableBinding(oid, var));
+ return trap;
}
}
diff --git a/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpRoute.java b/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpRoute.java
new file mode 100644
index 0000000000..445d6a456f
--- /dev/null
+++ b/integration-tests-jvm/snmp/src/main/java/org/apache/camel/quarkus/component/snmp/it/SnmpRoute.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.quarkus.component.snmp.it;
+
+import java.util.Deque;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedDeque;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+import jakarta.inject.Singleton;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.snmp.SnmpMessage;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+
+@ApplicationScoped
+public class SnmpRoute extends RouteBuilder {
+
+ @ConfigProperty(name = "snmpListenAddress")
+ String snmpListenAddress;
+
+ @Inject
+ @Named("snmpTrapResults")
+ Map<String, Deque<SnmpMessage>> snmpResults;
+
+ @Override
+ public void configure() {
+ //TRAP consumer
+ from("snmp:0.0.0.0:1662?protocol=udp&type=TRAP&snmpVersion=0")
+ .process(e -> snmpResults.get("trap").add(e.getIn().getBody(SnmpMessage.class)));
+
+ //POLL consumer
+ from("snmp://" + snmpListenAddress + "?protocol=udp&type=POLL&snmpVersion=0&oids=1.3.6.1.2.1.1.5.0")
+ .process(e -> snmpResults.get("poll").add(e.getIn().getBody(SnmpMessage.class)));
+ }
+
+ static class Producers {
+ @jakarta.enterprise.inject.Produces
+ @Singleton
+ @Named("snmpTrapResults")
+ Map<String, Deque<SnmpMessage>> snmpResults() {
+ Map<String, Deque<SnmpMessage>> map = new ConcurrentHashMap<>();
+ map.put("trap", new ConcurrentLinkedDeque());
+ map.put("poll", new ConcurrentLinkedDeque());
+ return map;
+ }
+ }
+}
diff --git a/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTest.java b/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTest.java
index 046ed5b620..83194f0a89 100644
--- a/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTest.java
+++ b/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTest.java
@@ -16,19 +16,80 @@
*/
package org.apache.camel.quarkus.component.snmp.it;
+import java.util.concurrent.TimeUnit;
+
+import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
+import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
+import static org.awaitility.Awaitility.await;
+
+/**
+ * There is a responder defined in the test resource. Which returns 2 responses without a delay and the third one
+ * with delay longer then default timeout. This means following behavior:
+ * - send PDU will receive 1 response
+ * - get_next will receive 2 responses (the third one reaches timeout)
+ * - poll returns unending stream of responses
+ */
@QuarkusTest
+@QuarkusTestResource(SnmpTestResource.class)
class SnmpTest {
@Test
- public void loadComponentSnmp() {
- /* A simple autogenerated test */
- RestAssured.get("/snmp/load/component/snmp")
+ public void testSendReceiveTrap() throws Exception {
+
+ RestAssured.given()
+ .body("TEXT")
+ .post("/snmp/produceTrap")
.then()
.statusCode(200);
+
+ await().atMost(10L, TimeUnit.SECONDS).pollDelay(100, TimeUnit.MILLISECONDS).until(() -> {
+ String result = RestAssured.given()
+ .body("trap")
+ .post("/snmp/results")
+ .then()
+ .statusCode(200)
+ .extract().body().asString();
+
+ return result.contains("TEXT");
+ });
+ }
+
+ @Test
+ public void testPoll() throws Exception {
+ await().atMost(10L, TimeUnit.SECONDS).pollDelay(100, TimeUnit.MILLISECONDS).until(() -> {
+ String result = RestAssured.given()
+ .body("poll")
+ .post("/snmp/results")
+ .then()
+ .statusCode(200)
+ .extract().body().asString();
+
+ return result.startsWith("Response from the test #1,Response from the test #2,Response from the test #3");
+ });
}
+ @Test
+ public void testProducePDU() {
+
+ RestAssured
+ .get("/snmp/producePDU")
+ .then()
+ .statusCode(200)
+ .body(Matchers.equalTo("Response from the test #1"));
+ }
+
+ @Test
+ public void testGetNext() {
+
+ RestAssured.given()
+ .body("TEXT")
+ .post("/snmp/getNext")
+ .then()
+ .statusCode(200)
+ .body(Matchers.equalTo("Response from the test #1,Response from the test #2"));
+ }
}
diff --git a/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTestResource.java b/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTestResource.java
new file mode 100644
index 0000000000..504e4f6250
--- /dev/null
+++ b/integration-tests-jvm/snmp/src/test/java/org/apache/camel/quarkus/component/snmp/it/SnmpTestResource.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.quarkus.component.snmp.it;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+import org.apache.camel.util.CollectionHelper;
+import org.junit.jupiter.api.Assertions;
+import org.snmp4j.CommandResponder;
+import org.snmp4j.CommandResponderEvent;
+import org.snmp4j.MessageException;
+import org.snmp4j.PDU;
+import org.snmp4j.Snmp;
+import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.mp.StatusInformation;
+import org.snmp4j.smi.OID;
+import org.snmp4j.smi.OctetString;
+import org.snmp4j.smi.UdpAddress;
+import org.snmp4j.smi.VariableBinding;
+import org.snmp4j.transport.DefaultUdpTransportMapping;
+
+public class SnmpTestResource implements QuarkusTestResourceLifecycleManager {
+
+ public static final String LISTEN_ADDRESS = "snmpListenAddress";
+ public static final String LOCAL_ADDRESS = "127.0.0.1/0";
+
+ Snmp snmpResponder;
+
+ @Override
+ public Map<String, String> start() {
+ DefaultUdpTransportMapping udpTransportMapping;
+ try {
+ udpTransportMapping = new DefaultUdpTransportMapping(new UdpAddress(LOCAL_ADDRESS));
+ snmpResponder = new Snmp(udpTransportMapping);
+
+ TestCommandResponder responder = new TestCommandResponder(snmpResponder);
+ snmpResponder.addCommandResponder(responder);
+
+ snmpResponder.listen();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return CollectionHelper.mapOf(LISTEN_ADDRESS, udpTransportMapping.getListenAddress().toString().replaceFirst("/", ":"));
+ }
+
+ @Override
+ public void stop() {
+ if (snmpResponder != null) {
+ try {
+ snmpResponder.close();
+ } catch (IOException e) {
+ //do nothing
+ }
+ }
+ }
+
+ static class TestCommandResponder implements CommandResponder {
+
+ private final Snmp commandResponder;
+ private final Map<String, Integer> counts = new ConcurrentHashMap<>();
+
+ public TestCommandResponder(Snmp commandResponder) {
+ this.commandResponder = commandResponder;
+ }
+
+ @Override
+ public synchronized void processPdu(CommandResponderEvent event) {
+ PDU pdu = event.getPDU();
+ Vector<? extends VariableBinding> vbs = Optional.ofNullable(pdu.getVariableBindings()).orElse(new Vector<>(0));
+ String key = vbs.stream().sequential().map(vb -> vb.getOid().toString()).collect(Collectors.joining(","));
+ int numberOfSent = counts.getOrDefault(key, 0);
+
+ //if 3 responses were already sent for the OID, do not respond anymore
+ if (numberOfSent > 3) {
+ return;
+ }
+ //first 2 responses are quick, the third response takes 3000ms (so there is a timeout with default 1500ms) ->
+ // getNext producer will receive only 2 messages
+ // poll consumer should receive all of them
+ if (numberOfSent % 3 == 2) {
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ //nothing
+ }
+ }
+
+ PDU response = makeResponse(++numberOfSent, SnmpConstants.version1);
+ if (response != null) {
+ try {
+ response.setRequestID(pdu.getRequestID());
+ commandResponder.getMessageDispatcher().returnResponsePdu(
+ event.getMessageProcessingModel(), event.getSecurityModel(),
+ event.getSecurityName(), event.getSecurityLevel(),
+ response, event.getMaxSizeResponsePDU(),
+ event.getStateReference(), new StatusInformation());
+ } catch (MessageException e) {
+ Assertions.assertNull(e);
+ }
+ counts.put(key, numberOfSent);
+ }
+ }
+
+ private PDU makeResponse(int counter, int version) {
+ PDU responsePDU = new PDU();
+ responsePDU.setType(PDU.RESPONSE);
+ responsePDU.setErrorStatus(PDU.noError);
+ responsePDU.setErrorIndex(0);
+ responsePDU.add(new VariableBinding(new OID(SnmpConstants.sysDescr),
+ new OctetString("Response from the test #" + counter)));
+ return responsePDU;
+ }
+ }
+}