Skip to content

Commit

Permalink
test(x2): add test that X2 could be received by the Simulator.
Browse files Browse the repository at this point in the history
To test that we added a REST trigger in the Simulator ("/sip") that receives SIP. It is then encoded to X2 and sent with an x2x3Client to its own X2 interface.

To check if the correct X2 has been received we store
the received X2 in then X2X3Memory component, which we then query with an also new REST call "/x2/last".

Co-authored-by: Sven Uhlig <[email protected]>
  • Loading branch information
towi and sipgate-uhlig committed Sep 30, 2024
1 parent 50e45f8 commit 02f06b7
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 3 deletions.
1 change: 1 addition & 0 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ services:
MVN_ADDITIONAL_ARGS: "-DskipTests"
ports:
- "127.0.0.1:8080:8080"
- "127.0.0.1:42069:42069"
networks:
- li-network
depends_on:
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/sipgate/li/simulator/AppConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import com.sipgate.li.lib.x1.X1Client;
import com.sipgate.li.lib.x1.X1ClientBuilder;
import com.sipgate.li.lib.x1.X1RequestFactory;
import com.sipgate.li.lib.x2x3.X2X3Client;
import com.sipgate.li.lib.x2x3.X2X3Decoder;
import com.sipgate.li.simulator.x2x3.X2X3Server;
import com.sipgate.util.SSLContextBuilder;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
Expand All @@ -12,14 +14,17 @@
import java.nio.file.Path;
import java.security.*;
import java.security.cert.CertificateException;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
@ConfigurationProperties(prefix = "sipgate.li.simulator")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.sipgate.li.simulator.controller;

import static com.sipgate.li.lib.x2x3.PduObject.MANDATORY_HEADER_LENGTH;

import com.sipgate.li.lib.x2x3.PayloadDirection;
import com.sipgate.li.lib.x2x3.PayloadFormat;
import com.sipgate.li.lib.x2x3.PduObject;
import com.sipgate.li.lib.x2x3.PduType;
import com.sipgate.li.lib.x2x3.X2X3Client;
import com.sipgate.li.simulator.x2x3.X2X3Server;
import com.sipgate.util.SSLContextBuilder;
import java.io.IOException;
import java.nio.file.Path;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.UUID;
import javax.net.ssl.SSLContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SipController {

private static final Logger LOGGER = LoggerFactory.getLogger(SipController.class);

private final X2X3Server localX2X3Server;

public SipController(final X2X3Server localX2X3Server) {
this.localX2X3Server = localX2X3Server;
}

@PostMapping("/sip")
public ResponseEntity<String> interceptSip(@RequestBody final String sip) throws Exception {
LOGGER.debug("interceptSip: {}", sip);
try (final var x2X3Client = makeX2X3Client()) {
final byte[] bytes = sip.getBytes();
final var request = new PduObject(
(short) 0,
(short) 5,
PduType.X2_PDU,
MANDATORY_HEADER_LENGTH,
bytes.length,
PayloadFormat.SIP,
PayloadDirection.SENT_FROM_TARGET,
UUID.randomUUID(),
new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 },
new byte[] {},
bytes
);
x2X3Client.send(request);
return ResponseEntity.ok("null");
}
}

private SSLContext makeFlippedS1X2X3SslContext()
throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, NoSuchProviderException, KeyManagementException {
return SSLContextBuilder.newBuilder()
.withKeyStore(Path.of("/mutual-tls-stores/network-element-keystore.p12"), "changeit")
.withTrustStore(Path.of("/mutual-tls-stores/network-element-truststore.jks"), "changeit")
.build();
}

private X2X3Client makeX2X3Client()
throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, NoSuchProviderException, KeyManagementException {
LOGGER.info("Attempting to create local connection, port:{}", localX2X3Server.getPort());
final SSLContext sslContext = makeFlippedS1X2X3SslContext();
return new X2X3Client(sslContext.getSocketFactory(), "localhost", localX2X3Server.getPort());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.sipgate.li.simulator.controller;

import com.sipgate.li.lib.x2x3.PduObject;
import com.sipgate.li.simulator.x2x3.X2X3Memory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/x2")
public class X2Controller {

private final X2X3Memory x2X3Memory;

public X2Controller(final X2X3Memory x2X3Memory) {
this.x2X3Memory = x2X3Memory;
}

@GetMapping("/last")
public ResponseEntity<PduObject> getLast() {
if (x2X3Memory.getLast() == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(x2X3Memory.getLast());
}
}
21 changes: 21 additions & 0 deletions src/main/java/com/sipgate/li/simulator/x2x3/X2X3Memory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.sipgate.li.simulator.x2x3;

import com.sipgate.li.lib.x2x3.PduObject;
import com.sipgate.li.simulator.event.X2X3ReceivedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Service
public class X2X3Memory {

private PduObject lastMessage = null;

public PduObject getLast() {
return lastMessage;
}

@EventListener(X2X3ReceivedEvent.class)
public void onX2X3Received(final X2X3ReceivedEvent event) {
lastMessage = event.pduObject();
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/sipgate/li/simulator/x2x3/X2X3Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public X2X3Server(
this.x2X3Decoder = x2X3Decoder;
}

public int getPort() {
return port;
}

@EventListener(ApplicationStartedEvent.class)
public void run() throws Exception {
final EventLoopGroup bossGroup = new NioEventLoopGroup();
Expand Down
25 changes: 25 additions & 0 deletions src/test/java/com/sipgate/li/simulator/e2e/InterceptsX2Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.sipgate.li.simulator.e2e;

import static org.assertj.core.api.Assertions.assertThat;

import com.sipgate.li.lib.x2x3.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(SimulatorClientExtension.class)
class InterceptsX2Test {

@Test
void simulator_receives_x2(final SimulatorClient simulatorClient) throws Exception {
// GIVEN
final String body = "INVITE sip:[email protected]\n";

// WHEN
simulatorClient.post("/sip", body, Void.class);

// THEN
final PduObject result = simulatorClient.get("/x2/last", PduObject.class);
assertThat(result).isNotNull();
assertThat(result.payload()).isEqualTo(body.getBytes());
}
}
30 changes: 27 additions & 3 deletions src/test/java/com/sipgate/li/simulator/e2e/SimulatorClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,33 @@ public <T> T post(
final Map<String, String> arguments,
final Class<T> responseType,
final int expectedStatusCode
) throws IOException, InterruptedException {
return post(
path,
"application/x-www-form-urlencoded",
mapFormDataToString(arguments),
responseType,
expectedStatusCode
);
}

public <T> T post(final String path, final String body, final Class<T> responseType)
throws IOException, InterruptedException {
return post(path, "appliation/octet-stream", body, responseType, 200);
}

public <T> T post(
final String path,
final String contentType,
final String content,
final Class<T> responseType,
final int expectedStatusCode
) throws IOException, InterruptedException {
final var requestBuilder = HttpRequest.newBuilder().uri(baseUri.resolve(path)).POST(BodyPublishers.noBody());

if (!arguments.isEmpty()) {
requestBuilder.header("Content-Type", "application/x-www-form-urlencoded");
requestBuilder.POST(BodyPublishers.ofString(mapFormDataToString(arguments)));
if (!content.isEmpty()) {
requestBuilder.header("Content-Type", contentType);
requestBuilder.POST(BodyPublishers.ofString(content));
}

final var request = requestBuilder.build();
Expand All @@ -76,6 +97,9 @@ public <T> T post(
}

private static String mapFormDataToString(final Map<String, String> formData) {
if (formData.isEmpty()) {
return "";
}
final var formBodyBuilder = new StringBuilder();
for (final var singleEntry : formData.entrySet()) {
if (!formBodyBuilder.isEmpty()) {
Expand Down

0 comments on commit 02f06b7

Please sign in to comment.