Configuring Solace w/ testcontainers

rothek
rothek Member Posts: 7
edited April 2022 in Connectors & Integrations #1

Hi

I'm trying to configure my Solace that runs on testcontainers and Springboot JMS. The container starts up just fine, but the container is not setup the way I need it. I need it to have some queues and I'm having a hard time finding a way to get it running.

I tried to create one with testcontainers equivalent to docker exec curl ...but unsuccessfully so since the Solace container cant access curl or apt-get (error: starting container process caused: exec: "apt-get": stat apt-get: no such file or directory: unknown)

I tried to create a queue with the JCSMPFactory, but I get a org.springframework.jms.InvalidDestinationException: Error sending message - queue not found (400: Queue Not Found - Topic '#P2P/QUE/MyQueue');

I could try to send POST request to SEMPv2 to set up the Queues but it doesn't feel right to add a foreign dependency just to setup solace.

Does anybody see the reason why my code isn't working?

Is there a way to setup Queues within the container (using docker exec)?

Here's my code:

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
@Testcontainers
@Slf4j
@ExtendWith(SpringExtension.class)
//The AbstractPubSubPlusTestCase is equal to https://github.com/solace-iot-team/pubsubplus-container-junit/blob/main/src/main/java/com/solace/junit/AbstractPubSubPlusTestCase.java
class MessageControllerIT extends AbstractPubSubPlusTestCase {

  @Autowired
  private JmsTemplate jmsTemplate;

  private String inQueue = "MyQueue";
  private String outQueue = "OutQueue";

  private static JCSMPSession session;

  @BeforeAll
  public static void connectSMF() {
    final var properties = new JCSMPProperties();
    properties.setProperty(JCSMPProperties.HOST, String.format("%s:%s", getHost(), getSMFPort()));
    properties.setProperty(JCSMPProperties.USERNAME, "default");
    properties.setProperty(JCSMPProperties.VPN_NAME, "default");
    try {
      session = JCSMPFactory.onlyInstance().createSession(properties);
      session.connect();
    } catch (JCSMPException e) {
      e.printStackTrace();
    }
  }

  @AfterAll
  public static void tearDown() {
    if(Objects.nonNull(session) && !session.isClosed()) {
      session.closeSession();
    }
  }

  @BeforeEach
  void init() {
    var inQ = JCSMPFactory.onlyInstance().createQueue("Q/"+this.inQueue);
    var outQ = JCSMPFactory.onlyInstance().createQueue("Q/"+this.outQueue);

    var inT = JCSMPFactory.onlyInstance().createTopic("T/"+this.inQueue);
    var outT = JCSMPFactory.onlyInstance().createTopic("T/"+this.outQueue);

    session.addSubscribtion(inQ, inT, JCSMPSession.WAIT_FOR_CONFIRM);
    session.addSubscribtion(outQ, outT, JCSMPSession.WAIT_FOR_CONFIRM);
  }

  @DynamicPropertySource
  static void registerDynamicProperties(DynamicPropertyRegistry registry) {
    var host = "smf://" + getHost() + ":" + getSMFPort();
    registry.add("solace.jms.host", () -> host);
  }

  @Test
  void shouldReceiveAndRespond() {
    var incomingMessage = MyMessageSupport.getInstance().getIncomingMessage();
    var expectedMessage = MyMessageSupport.getInstance().getExpectedMessage();

    this.jmsTemplate.convertAndSend("T/"+this.inQueue, incomingMessage);
    this.jmsTemplate.setReceiveTimeout(10_000);

    var ack = this.jmsTemplate.receiveAndConvert("Q/"+this.outQueue);

    assertThat(ack).isNotNull();
  }

}


Comments

  • marc
    marc Member, Administrator, Moderator, Employee Posts: 889 admin
    edited April 2022 #2

    Hi @rothek,

    I think what is happening here is that JCSMPFactory.createQueue(...) just creates the queue object in your app locally and not on the broker. You'll need to call JCSMPSession.provision(...) to actually create it on the broker. More info on provision here

    Sample code here: https://github.com/SolaceSamples/solace-samples-java-jcsmp/blob/master/src/main/java/com/solace/samples/jcsmp/features/TopicToQueueMapping.java#L103:L118

  • rothek
    rothek Member Posts: 7
    edited April 2022 #3

    I'm still getting an error in the log:

    INFO 639284 --- [2_ReactorThread] c.s.jcsmp.impl.flow.BindRequestTask     : Client-2: Got BIND ('Q/MyQueue') Error Response (503) - Unknown Queue

    And a few lines later:

    [connect_service] c.s.j.protocol.impl.TcpClientChannel    : Client-7: Connection attempt failed to host 'localhost' ReconnectException com.solacesystems.jcsmp.JCSMPTransportException: (Client name: <Client>  Local addr: 127.0.0.1 Local port: 54176  Remote addr: localhost Remote port: 54137) - Error communicating with the router. cause: java.io.IOException: Unable to read enough bytes from stream!

    Even more lines later:

    com.solacesystems.jcsmp.JCSMPTransportException: (JCSMPTransportException) Error receiving data from underlying connection.at com.solacesystems.jcsmp.protocol.impl.TcpClientChannel$ClientChannelReconnect.call(TcpClientChannel.java:2439) ~[sol-jms-10.13.1.jar:na]   at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]   at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]   at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na] Caused by: com.solacesystems.jcsmp.JCSMPTransportException: (Client name: <Client>  Local port: -1  Remote addr: localhost Remote port: 54137) - Error communicating with the router.  at com.solacesystems.jcsmp.protocol.impl.TcpChannel.executePostOnce(TcpChannel.java:251) ~[sol-jms-10.13.1.jar:na]   at com.solacesystems.jcsmp.protocol.impl.ChannelOpStrategyClient.performOpen(ChannelOpStrategyClient.java:97) ~[sol-jms-10.13.1.jar:na]   at com.solacesystems.jcsmp.protocol.impl.TcpClientChannel.performOpenSingle(TcpClientChannel.java:418) ~[sol-jms-10.13.1.jar:na]   at com.solacesystems.jcsmp.protocol.impl.TcpClientChannel.access$800(TcpClientChannel.java:114) ~[sol-jms-10.13.1.jar:na]   at com.solacesystems.jcsmp.protocol.impl.TcpClientChannel$ClientChannelReconnect.call(TcpClientChannel.java:2275) ~[sol-jms-10.13.1.jar:na]   ... 4 common frames omitted

    Caused by: java.nio.channels.AsynchronousCloseException: null   at java.base/java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:202) ~[na:na]   at java.base/sun.nio.ch.SocketChannelImpl.endRead(SocketChannelImpl.java:389) ~[na:na] at java.base/sun.nio.ch.SocketChannelImpl.endConnect(SocketChannelImpl.java:792) ~[na:na]   at java.base/sun.nio.ch.SocketChannelImpl.blockingConnect(SocketChannelImpl.java:1189) ~[na:na]   at java.base/sun.nio.ch.SocketAdaptor.connect(SocketAdaptor.java:98) ~[na:na]   at com.solacesystems.jcsmp.protocol.smf.SimpleSmfClient.open(SimpleSmfClient.java:905) ~[sol-jms-10.13.1.jar:na]   at com.solacesystems.jcsmp.protocol.smf.SimpleSmfClient.doPostNoResponse(SimpleSmfClient.java:318) ~[sol-jms-10.13.1.jar:na]   at com.solacesystems.jcsmp.protocol.smf.SimpleSmfClient.doPost(SimpleSmfClient.java:235) ~[sol-jms-10.13.1.jar:na]   at com.solacesystems.jcsmp.protocol.impl.TcpChannel.executePostOnce(TcpChannel.java:196) ~[sol-jms-10.13.1.jar:na]   ... 8 common frames omitted

    INFO 639284 --- [connect_service] c.s.jcsmp.impl.JCSMPXMLMessageProducer  : Client-7:Flow-3: [Client-7] Transport exception occurred when message Id is not available


    But my tests turn out green for some reason. Note that these are not breaking errors but logged to the console at INFO level.

    My test receives a message on the response queue and tests for null and that the content of the message contains specific strings.

    Any idea why this could be?

  • marc
    marc Member, Administrator, Moderator, Employee Posts: 889 admin

    Weird, does that happen every time you run it?

    It looks like a network issue might have occurred but that doesn't make much sense if you're running against a local broker.

    Another guess is maybe the broker isn't fully started inside of the container yet. Just to test sleep for 30 seconds after solace.start() in AbstractPubSubPlusTestCase. It shouldn't really take 30 seconds but that should be plenty of time to troubleshoot if that is the issue or not and you can shorten the time to see how long it really needs if so.

  • rothek
    rothek Member Posts: 7
    edited April 2022 #5

    Yeah happens every time, even with a 30s sleep after starting the container.

    [Context_4_ReactorThread] INFO com.solacesystems.jcsmp.impl.flow.BindRequestTask - Client-4: Got BIND ('Q/MyQueue') Error Response (503) - Unknown Queue

    I get this error like 3 times until my test for some reason still turn green.

    I mean its ok, since in the end it still works somehow, but it would be nice to reduce logging during tests.

    Maybe the following lines are more helpful?

    [Context_7_ReactorThread] INFO com.solacesystems.jcsmp.protocol.impl.TcpClientChannel - Client-7: (Client name: <Client>  Local port: 65162  Remote addr: localhost Remote port: 65125) - handleException(): Channel Closed Event (smfclient 7)

    [Context_7_ReactorThread] INFO com.solacesystems.jcsmp.protocol.impl.TcpClientChannel - Client-7: handleException(): Channel Closed Event (smfclient 7) with exception: null cur_stack=Thread: "Context_7_ReactorThread" daemon id=176, prio=5:   com.solacesystems.jcsmp.protocol.impl.TcpClientChannel.handleException(TcpClientChannel.java:1374)   com.solacesystems.jcsmp.protocol.impl.TcpClientChannel.handleException(TcpClientChannel.java:1325)   com.solacesystems.jcsmp.protocol.nio.impl.SubscriberMessageReader.handleClosedSocketDuringRead(SubscriberMessageReader.java:203)   com.solacesystems.jcsmp.protocol.smf.SimpleSmfClient.handleClosedSocketDuringRead(SimpleSmfClient.java:1184)   com.solacesystems.jcsmp.protocol.nio.impl.SyncEventDispatcherReactor.processReactorChannels(SyncEventDispatcherReactor.java:229)   com.solacesystems.jcsmp.protocol.nio.impl.SyncEventDispatcherReactor.eventLoop(SyncEventDispatcherReactor.java:157)   com.solacesystems.jcsmp.protocol.nio.impl.SyncEventDispatcherReactor$SEDReactorThread.run(SyncEventDispatcherReactor.java:338)   java.base/java.lang.Thread.run(Thread.java:833)

    (This is logged twice for the same client and no other client)

    I'm also autowiring the JMSTemplate for my message handler with the default ConnectionFactory. I'm trying to find out if this is the culprit.

    Some more info about my setup:

    Running IntelliJ 2022.1 on Win 10, testcontainer on (1.17.1), my solace depencies are

    com.solace.spring.boot:solace-jms-spring-boot-autoconfigure
    com.solace.spring.boot:solace-jms-spring-boot-starter 
    org.springframework.integration:spring-integration-jms 
    

    all on their latest release.

    I have a postgres db and some other containers running which are required for testing (they're not running via testcontainers atm)

  • aditya
    aditya Member Posts: 7

    Hi @rothek, In my case my container is created but as I am trying to login into solace the container is getting exited. I have tried with withStartupCheckStrategy but I am getting the same issue. Please let me know if you have faced similar issue and if so please can you guide me to solve this.