44import static org .junit .jupiter .api .Assertions .assertFalse ;
55import static org .junit .jupiter .api .Assertions .assertTrue ;
66
7+ import java .io .ByteArrayOutputStream ;
78import java .net .DatagramPacket ;
89import java .net .DatagramSocket ;
910import java .net .InetAddress ;
1011import java .net .SocketTimeoutException ;
1112import java .nio .ByteBuffer ;
1213import java .nio .charset .StandardCharsets ;
14+ import java .util .Arrays ;
1315import java .util .concurrent .atomic .AtomicBoolean ;
16+ import java .util .zip .DeflaterOutputStream ;
1417
1518import org .eclipse .jdt .annotation .NonNullByDefault ;
1619import org .junit .jupiter .api .Test ;
@@ -102,6 +105,86 @@ public void sendShouldIgnoreAckAndProcessSubsequentData() throws Exception {
102105 assertTrue (ackAfterLead .get ());
103106 }
104107
108+ @ Test
109+ public void sendShouldHandleUncompressedMultiBlockResponse () throws Exception {
110+ final DatagramSocket server = new DatagramSocket (0 );
111+ final int port = server .getLocalPort ();
112+ final String responseXml = "<Response>OK</Response>" ;
113+ byte [] xmlBytes = (responseXml + '\0' ).getBytes (StandardCharsets .UTF_8 );
114+ int mid = xmlBytes .length / 2 ;
115+ byte [] part1 = Arrays .copyOfRange (xmlBytes , 0 , mid );
116+ byte [] part2 = Arrays .copyOfRange (xmlBytes , mid , xmlBytes .length );
117+
118+ Thread serverThread = new Thread (() -> {
119+ try {
120+ byte [] buf = new byte [4096 ];
121+ DatagramPacket requestPacket = new DatagramPacket (buf , buf .length );
122+ server .receive (requestPacket );
123+ int msgId = ByteBuffer .wrap (requestPacket .getData (), 0 , requestPacket .getLength ()).getInt ();
124+ InetAddress clientAddress = requestPacket .getAddress ();
125+ int clientPort = requestPacket .getPort ();
126+ byte [] lead = createLeadPacket (msgId , 2 , false );
127+ server .send (new DatagramPacket (lead , lead .length , clientAddress , clientPort ));
128+ byte [] block1 = createBlockPacket (msgId , part1 , false );
129+ server .send (new DatagramPacket (block1 , block1 .length , clientAddress , clientPort ));
130+ byte [] block2 = createBlockPacket (msgId , part2 , false );
131+ server .send (new DatagramPacket (block2 , block2 .length , clientAddress , clientPort ));
132+ } catch (Exception e ) {
133+ // ignore for test
134+ }
135+ });
136+ serverThread .start ();
137+
138+ UdpClient client = new UdpClient ("127.0.0.1" , port );
139+ UdpRequest request = new UdpRequest (HaywardMessageType .GET_TELEMETRY .getMsgInt (), "<Request/>" );
140+ UdpResponse response = client .send (request );
141+
142+ serverThread .join ();
143+ server .close ();
144+
145+ assertEquals (responseXml , response .getXml ());
146+ }
147+
148+ @ Test
149+ public void sendShouldDecompressMultiBlockResponseWhenFlagSet () throws Exception {
150+ final DatagramSocket server = new DatagramSocket (0 );
151+ final int port = server .getLocalPort ();
152+ final String responseXml = "<Response>OK</Response>" ;
153+ byte [] compressed = compress (responseXml );
154+ int mid = compressed .length / 2 ;
155+ byte [] part1 = Arrays .copyOfRange (compressed , 0 , mid );
156+ byte [] part2 = Arrays .copyOfRange (compressed , mid , compressed .length );
157+
158+ Thread serverThread = new Thread (() -> {
159+ try {
160+ byte [] buf = new byte [4096 ];
161+ DatagramPacket requestPacket = new DatagramPacket (buf , buf .length );
162+ server .receive (requestPacket );
163+ int msgId = ByteBuffer .wrap (requestPacket .getData (), 0 , requestPacket .getLength ()).getInt ();
164+ InetAddress clientAddress = requestPacket .getAddress ();
165+ int clientPort = requestPacket .getPort ();
166+ byte [] lead = createLeadPacket (msgId , 2 , true );
167+ server .send (new DatagramPacket (lead , lead .length , clientAddress , clientPort ));
168+ byte [] block1 = createBlockPacket (msgId , part1 , true );
169+ server .send (new DatagramPacket (block1 , block1 .length , clientAddress , clientPort ));
170+ byte [] block2 = createBlockPacket (msgId , part2 , true );
171+ server .send (new DatagramPacket (block2 , block2 .length , clientAddress , clientPort ));
172+ } catch (Exception e ) {
173+ // ignore for test
174+ }
175+ });
176+ serverThread .start ();
177+
178+ UdpClient client = new UdpClient ("127.0.0.1" , port );
179+ UdpRequest request = new UdpRequest (HaywardMessageType .GET_TELEMETRY .getMsgInt (), "<Request/>" );
180+ UdpResponse response = client .send (request );
181+
182+ serverThread .join ();
183+ server .close ();
184+
185+ assertEquals (responseXml , response .getXml ());
186+ }
187+
105188 private static byte [] createAckPacket (int messageId ) throws Exception {
106189 UdpRequest ack = new UdpRequest (HaywardMessageType .ACK .getMsgInt (), "ACK" , messageId );
107190 return ack .toBytes ();
@@ -121,20 +204,31 @@ private static byte[] createLeadPacket(int messageId, int blocks, boolean compre
121204 }
122205
123206 private static byte [] createBlockPacket (int messageId , String xml ) {
124- byte [] xmlBytes = (xml + '\0' ).getBytes (StandardCharsets .UTF_8 );
207+ return createBlockPacket (messageId , (xml + '\0' ).getBytes (StandardCharsets .UTF_8 ), false );
208+ }
209+
210+ private static byte [] createBlockPacket (int messageId , byte [] data , boolean compressed ) {
125211 ByteBuffer header = ByteBuffer .allocate (24 );
126212 header .putInt (messageId );
127213 header .putLong (System .currentTimeMillis ());
128214 header .put ("1.22" .getBytes (StandardCharsets .US_ASCII ));
129215 header .putInt (HaywardMessageType .MSP_BLOCKMESSAGE .getMsgInt ());
130216 header .put ((byte ) 1 );
131217 header .put ((byte ) 0 );
218+ header .put ((byte ) (compressed ? 1 : 0 ));
132219 header .put ((byte ) 0 );
133- header .put ((byte ) 0 );
134- byte [] packet = new byte [24 + xmlBytes .length ];
220+ byte [] packet = new byte [24 + data .length ];
135221 System .arraycopy (header .array (), 0 , packet , 0 , 24 );
136- System .arraycopy (xmlBytes , 0 , packet , 24 , xmlBytes .length );
222+ System .arraycopy (data , 0 , packet , 24 , data .length );
137223 return packet ;
138224 }
225+
226+ private static byte [] compress (String xml ) throws Exception {
227+ ByteArrayOutputStream baos = new ByteArrayOutputStream ();
228+ try (DeflaterOutputStream dos = new DeflaterOutputStream (baos )) {
229+ dos .write (xml .getBytes (StandardCharsets .UTF_8 ));
230+ }
231+ return baos .toByteArray ();
232+ }
139233}
140234
0 commit comments