Skip to content

Commit

Permalink
Improve Integration Tests for XML protocol.
Browse files Browse the repository at this point in the history
  • Loading branch information
TDF-PL-038 committed Nov 18, 2023
1 parent fd499f1 commit e1c8360
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 136 deletions.
29 changes: 19 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
# TakConn
## Założenia projektu

Projekt ma na celu stworzenie narzędzia integracji serwera TAK z dowolnym oprogramowaniem wykorzystującym kod Java lub C#, w zakresie wymiany komunikatów formatu CoT.
Oprogramowanie umożliwia wysyłanie wiadomości formatu CoT na serwer TAK przy wykorzystaniu zdefiniowanych sposobów komunikacji.
Projekt ma na celu stworzenie narzędzia integracji serwera TAK z dowolnym oprogramowaniem uruchamianym na maszynie
wirtualnej Java (Java Virtual Machine, JVM) lub kompilowanym z kodu bajtowego Javy do kodu maszynowego (np. przy użyciu
Graal VM). Integracja odbywa się w zakresie możliwości wymiany komunikatów protokołu COT (Cursor On Target), zarówno w
wersji klasycznej w formacie XML, jak i w wersji nowszej opartej na formacie Protocol Buffers.

## Stan projektu

Obecnie zaimplementowane funkcjonalności w języku Java:
- Połączenie TCP bez uwierzytelniania.
- Połączenie TCP przy uwierzytelnieniu certyfikatem.
- Połączenie UDP.
Obecnie zaimplementowane funkcjonalności:
- Połączenie TCP/SSL do serwera przy uwierzytelnieniu certyfikatem, z negocjacją formatu protokołu XML->Protobuff
- Połączenie TCP do serwera bez uwierzytelniania, z negocjacją formatu protokołu XML->Protobuff.

Obecnie zaimplementowane funkcjonalności w formie prototypu:
- Połączenie TCP do serwera.
- Połączenie UDP do serwera.

Lista funkcjonalności w trakcie implementacji:
- Połączenie TCP przy uwierzytelnieniu użytkownikiem i hasłem.
- Połączenie TCP przy uwierzytelnieniu certyfikatem, użytkownikiem i hasłem.
- Połączenie TCP do serwera przy uwierzytelnieniu użytkownikiem i hasłem.
- Połączenie TCP do serwera przy uwierzytelnieniu certyfikatem, użytkownikiem i hasłem.

Planowane funkcjonalności:
- Komunikacja Mesh UDP typu Multicast bezpośrednio z innymi urządzeniami.
- Komunikacja Mesh Point-Point TCP z konkretnym urzadzeniem, z negocjacją formatu protokołu XML->Protobuff.

Kod w języku C# jest w trakcie tworzenia.
## Przykład: Połączenie TCP/SSL do serwera przy uwierzytelnieniu certyfikatem, z negocjacją formatu protokołu XML->Protobuff

## Certifikaty
Potrzebne są pliki truststore.p12 i user.p12 w katalogach java/src/main/resources/cot/cert i c#/src/WOT.TAK.Client/cot/cert
Potrzebne są pliki `truststore.p12` i `user.p12` w katalogach `java/src/main/resources/cot/cert`

## Plik konfiguracyjny (Java)

Expand Down
2 changes: 1 addition & 1 deletion client/src/main/java/org/wot/tak/client/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ private void sendFilesFromDirectoryUsingConnector(TAKServerConnector connector,
for (File file : files) {
var xml = Files.readString(file.toPath());
var event = EventMarshalling.fromBytes(xml.getBytes());
connector.send(event);
// connector.send(event);
}
}
}
Expand Down
20 changes: 8 additions & 12 deletions connection/src/main/resources/protocol/xml/wot/Detail.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,7 @@
</xs:complexType>

<xs:complexType name="color">
<xs:sequence>
<xs:element name="argb" type="xs:integer"/>
</xs:sequence>
<xs:attribute name="argb" type="xs:integer"/>
</xs:complexType>

<xs:complexType name="contact">
Expand Down Expand Up @@ -202,20 +200,18 @@
<xs:annotation>
<xs:documentation>some type of location?</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="altsrc" type="xs:string">
<xs:annotation>
<xs:documentation>TDB can be DTED0 or ???</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="geopointsrc" type="xs:integer"/>
</xs:sequence>
<xs:attribute name="altsrc" type="xs:string">
<xs:annotation>
<xs:documentation>TDB can be DTED0 or ???</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="geopointsrc" type="xs:string"/>
</xs:complexType>

<xs:complexType name="remarks" mixed="true">
<xs:annotation>
<xs:documentation>Provides a place to annotate CoT with free text information. e.g. comments from other
users about the current COT. Used also fro the geoChat.
users about the current COT. Used also from the geoChat.
</xs:documentation>
<xs:documentation>the xml body of this class is used to transport the chat message</xs:documentation>
</xs:annotation>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<xs:annotation>
<xs:documentation>
A system-specific flowtag identifier associated with the encapsulating CoT object.
The attribute value should be an xs:dateTime value.
The attribute value should be a xs:dateTime value.
</xs:documentation>
</xs:annotation>
</xs:anyAttribute>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import org.wot.tak.connection.messages.ClientXmlMessage;
import org.wot.tak.connection.protocol.ProtocolVersion;
import org.wot.tak.connection.protocol.protobuf.DetailMarshalling;
import org.wot.tak.connection.protocol.xml.EventMarshalling;
import org.wot.tak.connection.protocol.xml.Detail;
import org.wot.tak.connection.protocol.protobuf.Takmessage;
import org.wot.tak.connection.protocol.xml.Event;

Expand Down Expand Up @@ -48,80 +48,88 @@ class SSLConnectorTest {
void Connector_can_send_and_and_receive_messages_using_XML_protocol() throws Exception {
var socketFactory = new SocketFactory(config);

var callsignPattern = "[{0}][{1}] Automated Integration Tests";
var callsignPattern = "[{0}],[{1}],[XML] Automated Integration Tests";
var alphaCallsign = MessageFormat.format(callsignPattern, SSLConnector.class.getSimpleName(), "Alpha");
var bravoCallsign = MessageFormat.format(callsignPattern, SSLConnector.class.getSimpleName(), "Bravo");

var alphaChatMessage = MessageFormat.format("Test message {0}", UUID.randomUUID());
var bravoChatMessage = MessageFormat.format("Test message {0}", UUID.randomUUID());
var alphaChatText = MessageFormat.format("Test message {0}", UUID.randomUUID());
var bravoChatText = MessageFormat.format("Test message {0}", UUID.randomUUID());

var alphaMessage = ClientXmlMessage.announcement(alphaUid, alphaCallsign, alphaChatMessage);
var bravoMessage = ClientXmlMessage.chat(bravoUid, alphaCallsign, bravoChatMessage);
var alphaAnnouncementMessage = ClientXmlMessage.announcement(alphaUid, alphaCallsign);
var alphaChatMessage = ClientXmlMessage.chat(alphaUid, alphaCallsign, alphaChatText);

var bravoAnnouncementMessage = ClientXmlMessage.announcement(bravoUid, bravoCallsign);
var bravoChatMessage = ClientXmlMessage.chat(bravoUid, bravoCallsign, bravoChatText);

var alphaReceivedMessages = new CopyOnWriteArrayList<Event>();
var alphaHandler = createXmlMessageReceiver(alphaReceivedMessages);
var alphaMessageHandler = createXmlMessageReceiver(alphaReceivedMessages);

var bravoReceivedMessages = new CopyOnWriteArrayList<Event>();
var bravoHandler = createXmlMessageReceiver(bravoReceivedMessages);
var bravoMessageHandler = createXmlMessageReceiver(bravoReceivedMessages);

var negotiateProtocolVersion = false;
try (var alphaClient = new SSLConnector(
serverUrl.getHost(), port.toString(), socketFactory, negotiateProtocolVersion);
var bravoClient = new SSLConnector(
serverUrl.getHost(), port.toString(), socketFactory, negotiateProtocolVersion)) {

alphaClient.connect(alphaHandler);
bravoClient.connect(bravoHandler);
alphaClient.connect(alphaMessageHandler);
bravoClient.connect(bravoMessageHandler);

alphaClient.send(alphaAnnouncementMessage);
bravoClient.send(bravoAnnouncementMessage);

alphaClient.send(alphaMessage);
bravoClient.send(bravoMessage);
alphaClient.send(alphaChatMessage);
bravoClient.send(bravoChatMessage);

Awaitility.await()
.atMost(2, TimeUnit.SECONDS)
.atMost(10, TimeUnit.SECONDS)
.untilAsserted(
() -> {
assertThat(alphaReceivedMessages)
.anyMatch(message -> EventMarshalling.toString(message)
.contains(bravoChatMessage));
.anyMatch(message -> hasChatMessage(message, bravoCallsign, bravoChatText));

assertThat(bravoReceivedMessages)
.anyMatch(message -> EventMarshalling.toString(message)
.contains(alphaChatMessage));
.anyMatch(message -> hasChatMessage(message, alphaCallsign, alphaChatText));
});


assertThat(alphaClient.getProtocolVersion()).isEqualTo(ProtocolVersion.XML);
assertThat(bravoClient.getProtocolVersion()).isEqualTo(ProtocolVersion.XML);
}
}

@Test
void Connector_can_send_and_and_receive_messages_using_Protobuf_protocol() throws Exception {
var socketFactory = new SocketFactory(config);

var callsignPattern = "[{0}][{1}] Automated Integration Tests";
var callsignPattern = "[{0}][{1}][Protobuf] Automated Integration Tests";
var alphaCallsign = MessageFormat.format(callsignPattern, SSLConnector.class.getSimpleName(), "Alpha");
var bravoCallsign = MessageFormat.format(callsignPattern, SSLConnector.class.getSimpleName(), "Bravo");

var alphaChat = MessageFormat.format("Test message {0}", UUID.randomUUID());
var bravoChat = MessageFormat.format("Test message {0}", UUID.randomUUID());
var alphaChatText = MessageFormat.format("Test message {0}", UUID.randomUUID());
var bravoChatText = MessageFormat.format("Test message {0}", UUID.randomUUID());

var alphaAnnouncementMessage = ClientProtobufMessage.announcement(alphaUid, alphaCallsign);
var alphaChatMessage = ClientProtobufMessage.chat(alphaUid, alphaCallsign, alphaChat);
var alphaChatMessage = ClientProtobufMessage.chat(alphaUid, alphaCallsign, alphaChatText);

var bravoAnnouncementMessage = ClientProtobufMessage.announcement(bravoUid, bravoCallsign);
var bravoChatMessage = ClientProtobufMessage.chat(bravoUid, bravoCallsign, bravoChat);
var bravoChatMessage = ClientProtobufMessage.chat(bravoUid, bravoCallsign, bravoChatText);

var alphaClientMessages = new CopyOnWriteArrayList<Takmessage.TakMessage>();
var alphaClientHandler = createProtobufMessageReceiver(alphaClientMessages);
var alphaReceivedMessages = new CopyOnWriteArrayList<Takmessage.TakMessage>();
var alphaMessageHandler = createProtobufMessageReceiver(alphaReceivedMessages);

var bravoClientMessages = new CopyOnWriteArrayList<Takmessage.TakMessage>();
var bravoClientHandler = createProtobufMessageReceiver(bravoClientMessages);
var bravoReceivedMessages = new CopyOnWriteArrayList<Takmessage.TakMessage>();
var bravoMessageHandler = createProtobufMessageReceiver(bravoReceivedMessages);

var negotiateProtocolVersion = true;
try (var alphaClient = new SSLConnector(
serverUrl.getHost(), port.toString(), socketFactory, negotiateProtocolVersion);
var bravoClient = new SSLConnector(
serverUrl.getHost(), port.toString(), socketFactory, negotiateProtocolVersion)) {

alphaClient.connect(alphaClientHandler);
bravoClient.connect(bravoClientHandler);
alphaClient.connect(alphaMessageHandler);
bravoClient.connect(bravoMessageHandler);

Awaitility.await()
.atMost(10, TimeUnit.SECONDS)
Expand All @@ -135,19 +143,19 @@ void Connector_can_send_and_and_receive_messages_using_Protobuf_protocol() throw
});

alphaClient.send(alphaAnnouncementMessage);
alphaClient.send(alphaChatMessage);
bravoClient.send(bravoAnnouncementMessage);
alphaClient.send(alphaChatMessage);
bravoClient.send(bravoChatMessage);

Awaitility.await()
.atMost(10, TimeUnit.SECONDS)
.untilAsserted(
() -> {
assertThat(alphaClientMessages)
.anyMatch(message -> hasChatMessage(message, bravoCallsign, bravoChat));
assertThat(alphaReceivedMessages)
.anyMatch(message -> hasChatMessage(message, bravoCallsign, bravoChatText));

assertThat(bravoClientMessages)
.anyMatch(message -> hasChatMessage(message, alphaCallsign, alphaChat));
assertThat(bravoReceivedMessages)
.anyMatch(message -> hasChatMessage(message, alphaCallsign, alphaChatText));
});
}
}
Expand Down Expand Up @@ -200,4 +208,21 @@ private boolean hasChatMessage(Takmessage.TakMessage message, String senderCalls

return senderCallSignMatched && chatMessageMatched;
}

@SneakyThrows
private boolean hasChatMessage(Event message, String senderCallsign, String chatMessage) {
var detail = Optional.ofNullable(message.getDetail());

var senderCallSignMatched = detail
.map(Detail::getChat)
.map(chat -> senderCallsign.equals(chat.getSenderCallsign()))
.orElse(false);

var chatMessageMatched = detail
.map(Detail::getRemarks)
.map(remarks -> chatMessage.equals(remarks.getContent()))
.orElse(false);

return senderCallSignMatched && chatMessageMatched;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.GregorianCalendar;
import java.util.Random;
import java.util.TimeZone;
import java.util.UUID;

public final class ClientProtobufMessage {

private static final double LATITUDE = 27.85009;
private static final double LONGITUDE = -81.063847;

private ClientProtobufMessage() {
}

Expand All @@ -51,8 +53,8 @@ public static Takmessage.TakMessage announcement(UUID uid, String callsign)
.setStartTime(now)
.setStaleTime(now + 5 * 60 * 1000)
.setHow("h-g-i-g-o")
.setLat(27.85009)
.setLon(-81.063847)
.setLat(LATITUDE)
.setLon(LONGITUDE)
.setHae(9999999.0)
.setCe(9999999.0)
.setLe(9999999.0)
Expand Down Expand Up @@ -107,8 +109,6 @@ public static Takmessage.TakMessage chat(UUID uid, String callsign, String chatM
throws DatatypeConfigurationException, XMLStreamException, JAXBException {

var now = System.currentTimeMillis();
var latitude = 52.2312 + (0.5 - new Random().nextFloat()) / 10;
var longitude = 21.016 + (0.5 - new Random().nextFloat()) / 10;

var message = Takmessage.TakMessage.newBuilder()
.setCotEvent(Cotevent.CotEvent.newBuilder()
Expand All @@ -119,8 +119,8 @@ public static Takmessage.TakMessage chat(UUID uid, String callsign, String chatM
.setStartTime(now)
.setStaleTime(now + 5 * 60 * 1000)
.setHow("h-g-i-g-o")
.setLat(latitude)
.setLon(longitude)
.setLat(LATITUDE)
.setLon(LONGITUDE)
.setHae(9999999.0)
.setCe(9999999.0)
.setLe(9999999.0)
Expand Down
Loading

0 comments on commit e1c8360

Please sign in to comment.