• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package software.amazon.awssdk.crt.test;
2 
3 import org.junit.Assume;
4 import org.junit.Test;
5 import static org.junit.Assert.assertNotNull;
6 import static org.junit.Assert.assertTrue;
7 import static org.junit.Assert.assertEquals;
8 import static org.junit.Assert.fail;
9 
10 import software.amazon.awssdk.crt.*;
11 import software.amazon.awssdk.crt.auth.credentials.CredentialsProvider;
12 import software.amazon.awssdk.crt.auth.credentials.CognitoCredentialsProvider.CognitoCredentialsProviderBuilder;
13 import software.amazon.awssdk.crt.auth.credentials.DefaultChainCredentialsProvider.DefaultChainCredentialsProviderBuilder;
14 import software.amazon.awssdk.crt.auth.credentials.StaticCredentialsProvider.StaticCredentialsProviderBuilder;
15 import software.amazon.awssdk.crt.auth.credentials.X509CredentialsProvider.X509CredentialsProviderBuilder;
16 import software.amazon.awssdk.crt.auth.signing.AwsSigningConfig;
17 import software.amazon.awssdk.crt.auth.signing.AwsSigningConfig.AwsSigningAlgorithm;
18 import software.amazon.awssdk.crt.http.HttpProxyOptions;
19 import software.amazon.awssdk.crt.http.HttpProxyOptions.HttpProxyConnectionType;
20 import software.amazon.awssdk.crt.io.ClientBootstrap;
21 import software.amazon.awssdk.crt.io.EventLoopGroup;
22 import software.amazon.awssdk.crt.io.HostResolver;
23 import software.amazon.awssdk.crt.io.Pkcs11Lib;
24 import software.amazon.awssdk.crt.io.SocketOptions;
25 import software.amazon.awssdk.crt.io.TlsContext;
26 import software.amazon.awssdk.crt.io.TlsContextOptions;
27 import software.amazon.awssdk.crt.io.TlsContextPkcs11Options;
28 import software.amazon.awssdk.crt.io.ExponentialBackoffRetryOptions.JitterMode;
29 import software.amazon.awssdk.crt.mqtt5.*;
30 import software.amazon.awssdk.crt.mqtt5.Mqtt5ClientOptions.ClientOfflineQueueBehavior;
31 import software.amazon.awssdk.crt.mqtt5.Mqtt5ClientOptions.ClientSessionBehavior;
32 import software.amazon.awssdk.crt.mqtt5.Mqtt5ClientOptions.ExtendedValidationAndFlowControlOptions;
33 import software.amazon.awssdk.crt.mqtt5.Mqtt5ClientOptions.LifecycleEvents;
34 import software.amazon.awssdk.crt.mqtt5.Mqtt5ClientOptions.Mqtt5ClientOptionsBuilder;
35 import software.amazon.awssdk.crt.mqtt5.Mqtt5ClientOptions.PublishEvents;
36 import software.amazon.awssdk.crt.mqtt5.packets.*;
37 import software.amazon.awssdk.crt.mqtt5.packets.ConnectPacket.ConnectPacketBuilder;
38 import software.amazon.awssdk.crt.mqtt5.packets.DisconnectPacket.DisconnectPacketBuilder;
39 import software.amazon.awssdk.crt.mqtt5.packets.DisconnectPacket.DisconnectReasonCode;
40 import software.amazon.awssdk.crt.mqtt5.packets.PublishPacket.PublishPacketBuilder;
41 import software.amazon.awssdk.crt.mqtt5.packets.SubscribePacket.SubscribePacketBuilder;
42 import software.amazon.awssdk.crt.mqtt5.packets.UnsubscribePacket.UnsubscribePacketBuilder;
43 import software.amazon.awssdk.crt.mqtt5.packets.SubscribePacket.RetainHandlingType;
44 
45 import java.util.ArrayList;
46 import java.util.Random;
47 import java.util.UUID;
48 import java.util.concurrent.CompletableFuture;
49 import java.util.concurrent.TimeUnit;
50 import java.util.function.Consumer;
51 
52 /* For environment variable setup, see SetupCrossCICrtEnvironment in the CRT builder */
53 public class Mqtt5ClientTest extends Mqtt5ClientTestFixture {
54 
Mqtt5ClientTest()55     public Mqtt5ClientTest() {
56     }
57 
58     /**
59      * ============================================================
60      * CREATION TEST CASES
61      * ============================================================
62      */
63 
64     /* Happy path. Minimal creation and cleanup */
65     @Test
New_UC1()66     public void New_UC1() {
67         skipIfNetworkUnavailable();
68         Assume.assumeNotNull(AWS_TEST_MQTT5_DIRECT_MQTT_HOST, AWS_TEST_MQTT5_DIRECT_MQTT_PORT);
69         try {
70             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
71                 AWS_TEST_MQTT5_DIRECT_MQTT_HOST,
72                 Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_PORT));
73             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
74                 assertNotNull(client);
75             }
76         } catch (Exception ex) {
77             fail(ex.getMessage());
78         }
79     }
80 
81     /* Maximum creation and cleanup */
82     @Test
New_UC2()83     public void New_UC2() {
84         skipIfNetworkUnavailable();
85         Assume.assumeNotNull(
86             AWS_TEST_MQTT5_DIRECT_MQTT_HOST, AWS_TEST_MQTT5_DIRECT_MQTT_PORT,
87             AWS_TEST_MQTT5_BASIC_AUTH_USERNAME, AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD,
88             AWS_TEST_MQTT5_PROXY_HOST, AWS_TEST_MQTT5_PROXY_PORT);
89         try {
90 
91             try (
92                 EventLoopGroup elg = new EventLoopGroup(1);
93                 HostResolver hr = new HostResolver(elg);
94                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
95                 SocketOptions socketOptions = new SocketOptions();
96             ) {
97 
98                 PublishPacketBuilder willPacketBuilder = new PublishPacketBuilder();
99                 willPacketBuilder.withQOS(QOS.AT_LEAST_ONCE).withPayload("Hello World".getBytes()).withTopic("test/topic");
100 
101                 ConnectPacketBuilder connectBuilder = new ConnectPacketBuilder();
102                 connectBuilder.withClientId("MQTT5 CRT")
103                 .withKeepAliveIntervalSeconds(1000L)
104                 .withMaximumPacketSizeBytes(1000L)
105                 .withPassword(AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD.getBytes())
106                 .withReceiveMaximum(1000L)
107                 .withRequestProblemInformation(true)
108                 .withRequestResponseInformation(true)
109                 .withSessionExpiryIntervalSeconds(1000L)
110                 .withUsername(AWS_TEST_MQTT5_BASIC_AUTH_USERNAME)
111                 .withWill(willPacketBuilder.build())
112                 .withWillDelayIntervalSeconds(1000L);
113 
114                 ArrayList<UserProperty> userProperties = new ArrayList<UserProperty>();
115                 userProperties.add(new UserProperty("Hello", "World"));
116                 connectBuilder.withUserProperties(userProperties);
117 
118                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
119                     AWS_TEST_MQTT5_DIRECT_MQTT_HOST,
120                     Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_PORT));
121                 builder.withBootstrap(bootstrap)
122                 .withConnackTimeoutMs(100L)
123                 .withConnectOptions(connectBuilder.build())
124                 .withExtendedValidationAndFlowControlOptions(ExtendedValidationAndFlowControlOptions.NONE)
125                 .withLifecycleEvents(new LifecycleEvents() {
126                     @Override
127                     public void onAttemptingConnect(Mqtt5Client client, OnAttemptingConnectReturn onAttemptingConnectReturn) {}
128 
129                     @Override
130                     public void onConnectionSuccess(Mqtt5Client client, OnConnectionSuccessReturn onConnectionSuccessReturn) {}
131 
132                     @Override
133                     public void onConnectionFailure(Mqtt5Client client, OnConnectionFailureReturn onConnectionFailureReturn) {}
134 
135                     @Override
136                     public void onDisconnection(Mqtt5Client client, OnDisconnectionReturn onDisconnectionReturn) {}
137 
138                     @Override
139                     public void onStopped(Mqtt5Client client, OnStoppedReturn onStoppedReturn) {}
140                 })
141                 .withMaxReconnectDelayMs(1000L)
142                 .withMinConnectedTimeToResetReconnectDelayMs(1000L)
143                 .withMinReconnectDelayMs(1000L)
144                 .withOfflineQueueBehavior(ClientOfflineQueueBehavior.FAIL_ALL_ON_DISCONNECT)
145                 .withAckTimeoutSeconds(1000L)
146                 .withPingTimeoutMs(1000L)
147                 .withPublishEvents(new PublishEvents() {
148                     @Override
149                     public void onMessageReceived(Mqtt5Client client, PublishReturn publishReturn) {}
150                 })
151                 .withRetryJitterMode(JitterMode.Default)
152                 .withSessionBehavior(ClientSessionBehavior.CLEAN)
153                 .withSocketOptions(socketOptions);
154                 // Skip websocket and TLS options - those are all different tests
155 
156                 HttpProxyOptions proxyOptions = new HttpProxyOptions();
157                 proxyOptions.setHost(AWS_TEST_MQTT5_PROXY_HOST);
158                 proxyOptions.setPort((Integer.parseInt(AWS_TEST_MQTT5_PROXY_PORT)));
159                 proxyOptions.setConnectionType(HttpProxyConnectionType.Tunneling);
160                 builder.withHttpProxyOptions(proxyOptions);
161 
162                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
163                     assertNotNull(client);
164                 }
165             }
166 
167         } catch (Exception ex) {
168             fail(ex.getMessage());
169         }
170     }
171 
172     /* Minimal memory check */
173     @Test
New_UC3()174     public void New_UC3() {
175         skipIfNetworkUnavailable();
176         Assume.assumeNotNull(AWS_TEST_MQTT5_DIRECT_MQTT_HOST, AWS_TEST_MQTT5_DIRECT_MQTT_PORT);
177         try {
178             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
179                 AWS_TEST_MQTT5_DIRECT_MQTT_HOST,
180                 Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_PORT));
181             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
182                 assertNotNull(client);
183             }
184         } catch (Exception ex) {
185             fail(ex.getMessage());
186         }
187         CrtResource.waitForNoResources();
188     }
189 
190     /* Maximum memory test */
191     @Test
New_UC4()192     public void New_UC4() {
193         skipIfNetworkUnavailable();
194         Assume.assumeNotNull(
195             AWS_TEST_MQTT5_DIRECT_MQTT_HOST, AWS_TEST_MQTT5_DIRECT_MQTT_PORT,
196             AWS_TEST_MQTT5_BASIC_AUTH_USERNAME, AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD,
197             AWS_TEST_MQTT5_PROXY_HOST, AWS_TEST_MQTT5_PROXY_PORT);
198         try {
199             try (
200                 EventLoopGroup elg = new EventLoopGroup(1);
201                 HostResolver hr = new HostResolver(elg);
202                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
203                 SocketOptions socketOptions = new SocketOptions();
204             ) {
205                 PublishPacketBuilder willPacketBuilder = new PublishPacketBuilder();
206                 willPacketBuilder.withQOS(QOS.AT_LEAST_ONCE).withPayload("Hello World".getBytes()).withTopic("test/topic");
207 
208                 ConnectPacketBuilder connectBuilder = new ConnectPacketBuilder();
209                 connectBuilder.withClientId("MQTT5 CRT");
210                 connectBuilder.withKeepAliveIntervalSeconds(1000L);
211                 connectBuilder.withMaximumPacketSizeBytes(1000L);
212                 connectBuilder.withPassword(AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD.getBytes());
213                 connectBuilder.withReceiveMaximum(1000L);
214                 connectBuilder.withRequestProblemInformation(true);
215                 connectBuilder.withRequestResponseInformation(true);
216                 connectBuilder.withSessionExpiryIntervalSeconds(1000L);
217                 connectBuilder.withUsername(AWS_TEST_MQTT5_BASIC_AUTH_USERNAME);
218                 connectBuilder.withWill(willPacketBuilder.build());
219                 connectBuilder.withWillDelayIntervalSeconds(1000L);
220 
221                 ArrayList<UserProperty> userProperties = new ArrayList<UserProperty>();
222                 userProperties.add(new UserProperty("Hello", "World"));
223                 connectBuilder.withUserProperties(userProperties);
224 
225                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
226                     AWS_TEST_MQTT5_DIRECT_MQTT_HOST,
227                     Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_PORT));
228                 builder.withBootstrap(bootstrap)
229                 .withConnackTimeoutMs(1000L)
230                 .withConnectOptions(connectBuilder.build())
231                 .withExtendedValidationAndFlowControlOptions(ExtendedValidationAndFlowControlOptions.NONE)
232                 .withLifecycleEvents(new LifecycleEvents() {
233                     @Override
234                     public void onAttemptingConnect(Mqtt5Client client, OnAttemptingConnectReturn onAttemptingConnectReturn) {}
235 
236                     @Override
237                     public void onConnectionSuccess(Mqtt5Client client, OnConnectionSuccessReturn onConnectionSuccessReturn) {}
238 
239                     @Override
240                     public void onConnectionFailure(Mqtt5Client client, OnConnectionFailureReturn onConnectionFailureReturn) {}
241 
242                     @Override
243                     public void onDisconnection(Mqtt5Client client, OnDisconnectionReturn onDisconnectionReturn) {}
244 
245                     @Override
246                     public void onStopped(Mqtt5Client client, OnStoppedReturn onStoppedReturn) {}
247                 })
248                 .withMaxReconnectDelayMs(1000L)
249                 .withMinConnectedTimeToResetReconnectDelayMs(1000L)
250                 .withMinReconnectDelayMs(1000L)
251                 .withOfflineQueueBehavior(ClientOfflineQueueBehavior.FAIL_ALL_ON_DISCONNECT)
252                 .withAckTimeoutSeconds(1000L)
253                 .withPingTimeoutMs(1000L)
254                 .withPublishEvents(new PublishEvents() {
255                     @Override
256                     public void onMessageReceived(Mqtt5Client client, PublishReturn publishReturn) {}
257                 })
258                 .withRetryJitterMode(JitterMode.Default)
259                 .withSessionBehavior(ClientSessionBehavior.CLEAN)
260                 .withSocketOptions(socketOptions);
261                 // Skip websocket and TLS options - those are all different tests
262 
263                 HttpProxyOptions proxyOptions = new HttpProxyOptions();
264                 proxyOptions.setHost(AWS_TEST_MQTT5_PROXY_HOST);
265                 proxyOptions.setPort((Integer.parseInt(AWS_TEST_MQTT5_PROXY_PORT)));
266                 proxyOptions.setConnectionType(HttpProxyConnectionType.Tunneling);
267                 builder.withHttpProxyOptions(proxyOptions);
268 
269                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
270                     assertNotNull(client);
271                 }
272             }
273 
274         } catch (Exception ex) {
275             fail(ex.getMessage());
276         }
277 
278         CrtResource.waitForNoResources();
279     }
280 
281     /**
282      * ============================================================
283      * DIRECT CONNECT TEST CASES
284      * ============================================================
285      */
286 
287     /* Happy path. Direct connection with minimal configuration */
288     @Test
ConnDC_UC1()289     public void ConnDC_UC1() {
290         skipIfNetworkUnavailable();
291         Assume.assumeNotNull(AWS_TEST_MQTT5_DIRECT_MQTT_HOST, AWS_TEST_MQTT5_DIRECT_MQTT_PORT);
292         try {
293             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
294 
295             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
296                 AWS_TEST_MQTT5_DIRECT_MQTT_HOST,
297                 Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_PORT));
298             builder.withLifecycleEvents(events);
299 
300             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
301                 client.start();
302                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
303                 client.stop();
304             }
305 
306         } catch (Exception ex) {
307             fail(ex.getMessage());
308         }
309     }
310 
311     /* Direct connection with basic authentication */
312     @Test
ConnDC_UC2()313     public void ConnDC_UC2() {
314         skipIfNetworkUnavailable();
315         Assume.assumeNotNull(
316             AWS_TEST_MQTT5_DIRECT_MQTT_BASIC_AUTH_HOST, AWS_TEST_MQTT5_DIRECT_MQTT_BASIC_AUTH_PORT,
317             AWS_TEST_MQTT5_BASIC_AUTH_USERNAME, AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD);
318         try {
319             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
320 
321             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
322                 AWS_TEST_MQTT5_DIRECT_MQTT_BASIC_AUTH_HOST,
323                 Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_BASIC_AUTH_PORT));
324             builder.withLifecycleEvents(events);
325 
326             ConnectPacketBuilder connectOptions = new ConnectPacketBuilder();
327             connectOptions.withUsername(AWS_TEST_MQTT5_BASIC_AUTH_USERNAME).withPassword(AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD.getBytes());
328             builder.withConnectOptions(connectOptions.build());
329 
330             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
331                 client.start();
332                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
333                 client.stop();
334             }
335         } catch (Exception ex) {
336             fail(ex.getMessage());
337         }
338     }
339 
340     /* Direct connection with TLS */
341     @Test
ConnDC_UC3()342     public void ConnDC_UC3() {
343         skipIfNetworkUnavailable();
344         Assume.assumeNotNull(AWS_TEST_MQTT5_DIRECT_MQTT_TLS_HOST, AWS_TEST_MQTT5_DIRECT_MQTT_TLS_PORT);
345         try {
346             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
347 
348             try (TlsContextOptions tlsOptions = TlsContextOptions.createDefaultClient()) {
349                 tlsOptions.withVerifyPeer(false);
350                 try (TlsContext tlsContext = new TlsContext(tlsOptions)) {
351                     Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
352                         AWS_TEST_MQTT5_DIRECT_MQTT_TLS_HOST, Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_TLS_PORT));
353                     builder.withLifecycleEvents(events);
354                     builder.withTlsContext(tlsContext);
355 
356                     try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
357                         client.start();
358                         events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
359                         client.stop();
360                     }
361                 }
362             }
363         } catch (Exception ex) {
364             fail(ex.getMessage());
365         }
366     }
367 
368     /* Direct connection with mTLS */
369     @Test
ConnDC_UC4()370     public void ConnDC_UC4() {
371         skipIfNetworkUnavailable();
372         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
373         try {
374             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
375 
376             try (
377                 TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
378                     AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
379                 TlsContext tlsContext = new TlsContext(tlsOptions);
380             ) {
381                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
382                 builder.withLifecycleEvents(events);
383                 builder.withTlsContext(tlsContext);
384 
385                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
386                     client.start();
387                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
388                     client.stop();
389                 }
390             }
391         } catch (Exception ex) {
392             fail(ex.getMessage());
393         }
394     }
395 
396     /* Direct connection with HttpProxyOptions */
397     @Test
ConnDC_UC5()398     public void ConnDC_UC5() {
399         skipIfNetworkUnavailable();
400         Assume.assumeNotNull(
401             AWS_TEST_MQTT5_DIRECT_MQTT_TLS_HOST, AWS_TEST_MQTT5_DIRECT_MQTT_TLS_PORT,
402             AWS_TEST_MQTT5_PROXY_HOST, AWS_TEST_MQTT5_PROXY_PORT);
403         try {
404 
405             try (
406                 EventLoopGroup elg = new EventLoopGroup(1);
407                 HostResolver hr = new HostResolver(elg);
408                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
409             ) {
410                 LifecycleEvents_Futured events = new LifecycleEvents_Futured();
411                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
412                     AWS_TEST_MQTT5_DIRECT_MQTT_TLS_HOST, Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_TLS_PORT));
413                 builder.withLifecycleEvents(events);
414                 builder.withBootstrap(bootstrap);
415 
416                 HttpProxyOptions proxyOptions = new HttpProxyOptions();
417                 proxyOptions.setHost(AWS_TEST_MQTT5_PROXY_HOST);
418                 proxyOptions.setPort(Integer.parseInt(AWS_TEST_MQTT5_PROXY_PORT));
419                 proxyOptions.setConnectionType(HttpProxyConnectionType.Tunneling);
420 
421                 try (TlsContextOptions tlsOptions = TlsContextOptions.createDefaultClient()) {
422                     tlsOptions.withVerifyPeer(false);
423                     try (TlsContext tlsContext = new TlsContext(tlsOptions)) {
424                         builder.withTlsContext(tlsContext);
425                         builder.withHttpProxyOptions(proxyOptions);
426 
427                         try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
428                             client.start();
429                             events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
430                             client.stop();
431                         }
432                     }
433                 }
434             }
435 
436         } catch (Exception ex) {
437             fail(ex.getMessage());
438         }
439     }
440 
441     /* Maximum options set connection test */
442     @Test
ConnDC_UC6()443     public void ConnDC_UC6() {
444         skipIfNetworkUnavailable();
445         Assume.assumeNotNull(
446             AWS_TEST_MQTT5_DIRECT_MQTT_BASIC_AUTH_HOST, AWS_TEST_MQTT5_DIRECT_MQTT_BASIC_AUTH_PORT,
447             AWS_TEST_MQTT5_BASIC_AUTH_USERNAME, AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD);
448         try {
449             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
450 
451             try (
452                 EventLoopGroup elg = new EventLoopGroup(1);
453                 HostResolver hr = new HostResolver(elg);
454                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
455                 SocketOptions socketOptions = new SocketOptions();
456             ) {
457                 PublishPacketBuilder willPacketBuilder = new PublishPacketBuilder();
458                 willPacketBuilder.withQOS(QOS.AT_LEAST_ONCE).withPayload("Hello World".getBytes()).withTopic("test/topic");
459 
460                 ConnectPacketBuilder connectBuilder = new ConnectPacketBuilder();
461                 connectBuilder.withClientId("MQTT5 CRT" + UUID.randomUUID().toString());
462                 connectBuilder.withKeepAliveIntervalSeconds(1000L);
463                 connectBuilder.withMaximumPacketSizeBytes(1000L);
464                 connectBuilder.withPassword(AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD.getBytes());
465                 connectBuilder.withReceiveMaximum(1000L);
466                 connectBuilder.withRequestProblemInformation(true);
467                 connectBuilder.withRequestResponseInformation(true);
468                 connectBuilder.withSessionExpiryIntervalSeconds(1000L);
469                 connectBuilder.withUsername(AWS_TEST_MQTT5_BASIC_AUTH_USERNAME);
470                 connectBuilder.withWill(willPacketBuilder.build());
471                 connectBuilder.withWillDelayIntervalSeconds(1000L);
472 
473                 ArrayList<UserProperty> userProperties = new ArrayList<UserProperty>();
474                 userProperties.add(new UserProperty("Hello", "World"));
475                 connectBuilder.withUserProperties(userProperties);
476 
477                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
478                     AWS_TEST_MQTT5_DIRECT_MQTT_BASIC_AUTH_HOST,
479                     Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_BASIC_AUTH_PORT));
480                 builder.withBootstrap(bootstrap)
481                 .withConnackTimeoutMs(1000L)
482                 .withConnectOptions(connectBuilder.build())
483                 .withExtendedValidationAndFlowControlOptions(ExtendedValidationAndFlowControlOptions.NONE)
484                 .withLifecycleEvents(events)
485                 .withMaxReconnectDelayMs(1000L)
486                 .withMinConnectedTimeToResetReconnectDelayMs(1000L)
487                 .withMinReconnectDelayMs(1000L)
488                 .withOfflineQueueBehavior(ClientOfflineQueueBehavior.FAIL_ALL_ON_DISCONNECT)
489                 .withAckTimeoutSeconds(1000L)
490                 .withPingTimeoutMs(1000L)
491                 .withPublishEvents(new PublishEvents() {
492                     @Override
493                     public void onMessageReceived(Mqtt5Client client, PublishReturn publishReturn) {}
494                 })
495                 .withRetryJitterMode(JitterMode.Default)
496                 .withSessionBehavior(ClientSessionBehavior.CLEAN)
497                 .withSocketOptions(socketOptions);
498                 // Skip websocket, proxy options, and TLS options - those are all different tests
499 
500                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
501                     client.start();
502                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
503                     DisconnectPacketBuilder disconnect = new DisconnectPacketBuilder();
504                     client.stop(disconnect.build());
505                 }
506             }
507 
508         } catch (Exception ex) {
509             fail(ex.getMessage());
510         }
511 
512         CrtResource.waitForNoResources();
513     }
514 
515     /**
516      * ============================================================
517      * WEBSOCKET CONNECT TEST CASES
518      * ============================================================
519      */
520 
521     /* Happy path. Websocket connection with minimal configuration */
522     @Test
ConnWS_UC1()523     public void ConnWS_UC1() {
524         skipIfNetworkUnavailable();
525         Assume.assumeNotNull(AWS_TEST_MQTT5_WS_MQTT_HOST, AWS_TEST_MQTT5_WS_MQTT_PORT);
526         try {
527 
528             try (
529                 EventLoopGroup elg = new EventLoopGroup(1);
530                 HostResolver hr = new HostResolver(elg);
531                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
532             ) {
533 
534                 LifecycleEvents_Futured events = new LifecycleEvents_Futured();
535 
536                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
537                     AWS_TEST_MQTT5_WS_MQTT_HOST, Long.parseLong(AWS_TEST_MQTT5_WS_MQTT_PORT));
538                 builder.withLifecycleEvents(events);
539                 builder.withBootstrap(bootstrap);
540 
541                 Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketTransform = new Consumer<Mqtt5WebsocketHandshakeTransformArgs>() {
542                     @Override
543                     public void accept(Mqtt5WebsocketHandshakeTransformArgs t) {
544                         t.complete(t.getHttpRequest());
545                     }
546                 };
547                 builder.withWebsocketHandshakeTransform(websocketTransform);
548 
549                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
550                     client.start();
551                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
552                     client.stop();
553                 }
554             }
555 
556         } catch (Exception ex) {
557             fail(ex.getMessage());
558         }
559     }
560 
561     /* Websocket connection with basic authentication */
562     @Test
ConnWS_UC2()563     public void ConnWS_UC2() {
564         skipIfNetworkUnavailable();
565         Assume.assumeNotNull(
566             AWS_TEST_MQTT5_WS_MQTT_BASIC_AUTH_HOST, AWS_TEST_MQTT5_WS_MQTT_BASIC_AUTH_PORT,
567             AWS_TEST_MQTT5_BASIC_AUTH_USERNAME, AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD);
568         try {
569             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
570 
571             try (
572                 EventLoopGroup elg = new EventLoopGroup(1);
573                 HostResolver hr = new HostResolver(elg);
574                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
575             ) {
576                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
577                     AWS_TEST_MQTT5_WS_MQTT_BASIC_AUTH_HOST, Long.parseLong(AWS_TEST_MQTT5_WS_MQTT_BASIC_AUTH_PORT));
578                 builder.withLifecycleEvents(events);
579                 builder.withBootstrap(bootstrap);
580 
581                 Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketTransform = new Consumer<Mqtt5WebsocketHandshakeTransformArgs>() {
582                     @Override
583                     public void accept(Mqtt5WebsocketHandshakeTransformArgs t) {
584                         t.complete(t.getHttpRequest());
585                     }
586                 };
587                 builder.withWebsocketHandshakeTransform(websocketTransform);
588 
589                 ConnectPacketBuilder connectOptions = new ConnectPacketBuilder();
590                 connectOptions.withUsername(AWS_TEST_MQTT5_BASIC_AUTH_USERNAME).withPassword(AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD.getBytes());
591                 builder.withConnectOptions(connectOptions.build());
592 
593                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
594                     client.start();
595                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
596                     client.stop();
597                 }
598             }
599         } catch (Exception ex) {
600             fail(ex.getMessage());
601         }
602     }
603 
604     /* Websocket connection with TLS */
605     @Test
ConnWS_UC3()606     public void ConnWS_UC3() {
607         skipIfNetworkUnavailable();
608         Assume.assumeNotNull(AWS_TEST_MQTT5_WS_MQTT_TLS_HOST, AWS_TEST_MQTT5_WS_MQTT_TLS_PORT);
609         try {
610             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
611 
612             try (
613                 EventLoopGroup elg = new EventLoopGroup(1);
614                 HostResolver hr = new HostResolver(elg);
615                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
616             ) {
617 
618                 try (TlsContextOptions tlsOptions = TlsContextOptions.createDefaultClient()) {
619                     tlsOptions.withVerifyPeer(false);
620                     try (TlsContext tlsContext = new TlsContext(tlsOptions)) {
621                         Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
622                             AWS_TEST_MQTT5_WS_MQTT_TLS_HOST, Long.parseLong(AWS_TEST_MQTT5_WS_MQTT_TLS_PORT));
623                         builder.withLifecycleEvents(events);
624                         builder.withBootstrap(bootstrap);
625 
626                         Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketTransform = new Consumer<Mqtt5WebsocketHandshakeTransformArgs>() {
627                             @Override
628                             public void accept(Mqtt5WebsocketHandshakeTransformArgs t) {
629                                 t.complete(t.getHttpRequest());
630                             }
631                         };
632                         builder.withWebsocketHandshakeTransform(websocketTransform);
633                         builder.withTlsContext(tlsContext);
634 
635                         try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
636                             client.start();
637                             events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
638                             client.stop();
639                         }
640                     }
641                 }
642             }
643 
644         } catch (Exception ex) {
645             fail(ex.getMessage());
646         }
647     }
648 
649     /* Websocket connection with HttpProxyOptions */
650     @Test
ConnWS_UC5()651     public void ConnWS_UC5() {
652         skipIfNetworkUnavailable();
653         Assume.assumeNotNull(
654             AWS_TEST_MQTT5_WS_MQTT_TLS_HOST, AWS_TEST_MQTT5_WS_MQTT_TLS_PORT,
655             AWS_TEST_MQTT5_PROXY_HOST, AWS_TEST_MQTT5_PROXY_PORT);
656         try {
657             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
658 
659             EventLoopGroup elg = new EventLoopGroup(1);
660             HostResolver hr = new HostResolver(elg);
661             ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
662 
663             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
664                 AWS_TEST_MQTT5_WS_MQTT_TLS_HOST, Long.parseLong(AWS_TEST_MQTT5_WS_MQTT_TLS_PORT));
665             builder.withLifecycleEvents(events);
666             builder.withBootstrap(bootstrap);
667 
668             TlsContextOptions tlsOptions = TlsContextOptions.createDefaultClient();
669             tlsOptions.withVerifyPeer(false);
670             TlsContext tlsContext = new TlsContext(tlsOptions);
671             builder.withTlsContext(tlsContext);
672 
673             Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketTransform = new Consumer<Mqtt5WebsocketHandshakeTransformArgs>() {
674                 @Override
675                 public void accept(Mqtt5WebsocketHandshakeTransformArgs t) {
676                     t.complete(t.getHttpRequest());
677                 }
678             };
679             builder.withWebsocketHandshakeTransform(websocketTransform);
680 
681             HttpProxyOptions proxyOptions = new HttpProxyOptions();
682             proxyOptions.setHost(AWS_TEST_MQTT5_PROXY_HOST);
683             proxyOptions.setPort(Integer.parseInt(AWS_TEST_MQTT5_PROXY_PORT));
684             proxyOptions.setConnectionType(HttpProxyConnectionType.Tunneling);
685             builder.withHttpProxyOptions(proxyOptions);
686 
687             Mqtt5Client client = new Mqtt5Client(builder.build());
688 
689             client.start();
690             events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
691             client.stop();
692 
693             client.close();
694             tlsContext.close();
695             tlsOptions.close();
696             elg.close();
697             hr.close();
698             bootstrap.close();
699 
700         } catch (Exception ex) {
701             fail(ex.getMessage());
702         }
703     }
704 
705     /* Websocket connection with all options set */
706     @Test
ConnWS_UC6()707     public void ConnWS_UC6() {
708         skipIfNetworkUnavailable();
709         Assume.assumeNotNull(
710             AWS_TEST_MQTT5_WS_MQTT_BASIC_AUTH_HOST, AWS_TEST_MQTT5_WS_MQTT_BASIC_AUTH_PORT,
711             AWS_TEST_MQTT5_BASIC_AUTH_USERNAME, AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD);
712         try {
713             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
714 
715             try (
716                 EventLoopGroup elg = new EventLoopGroup(1);
717                 HostResolver hr = new HostResolver(elg);
718                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
719                 SocketOptions socketOptions = new SocketOptions();
720             ) {
721                 PublishPacketBuilder willPacketBuilder = new PublishPacketBuilder();
722                 willPacketBuilder.withQOS(QOS.AT_LEAST_ONCE).withPayload("Hello World".getBytes()).withTopic("test/topic");
723 
724                 ConnectPacketBuilder connectBuilder = new ConnectPacketBuilder();
725                 connectBuilder.withClientId("MQTT5 CRT"+UUID.randomUUID().toString());
726                 connectBuilder.withKeepAliveIntervalSeconds(1000L);
727                 connectBuilder.withMaximumPacketSizeBytes(1000L);
728                 connectBuilder.withPassword(AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD.getBytes());
729                 connectBuilder.withReceiveMaximum(1000L);
730                 connectBuilder.withRequestProblemInformation(true);
731                 connectBuilder.withRequestResponseInformation(true);
732                 connectBuilder.withSessionExpiryIntervalSeconds(1000L);
733                 connectBuilder.withUsername(AWS_TEST_MQTT5_BASIC_AUTH_USERNAME);
734                 connectBuilder.withWill(willPacketBuilder.build());
735                 connectBuilder.withWillDelayIntervalSeconds(1000L);
736 
737                 ArrayList<UserProperty> userProperties = new ArrayList<UserProperty>();
738                 userProperties.add(new UserProperty("Hello", "World"));
739                 connectBuilder.withUserProperties(userProperties);
740 
741                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
742                     AWS_TEST_MQTT5_WS_MQTT_BASIC_AUTH_HOST, Long.parseLong(AWS_TEST_MQTT5_WS_MQTT_BASIC_AUTH_PORT));
743                 builder.withBootstrap(bootstrap)
744                 .withConnackTimeoutMs(1000L)
745                 .withConnectOptions(connectBuilder.build())
746                 .withExtendedValidationAndFlowControlOptions(ExtendedValidationAndFlowControlOptions.NONE)
747                 .withLifecycleEvents(events)
748                 .withMaxReconnectDelayMs(1000L)
749                 .withMinConnectedTimeToResetReconnectDelayMs(1000L)
750                 .withMinReconnectDelayMs(1000L)
751                 .withOfflineQueueBehavior(ClientOfflineQueueBehavior.FAIL_ALL_ON_DISCONNECT)
752                 .withAckTimeoutSeconds(1000L)
753                 .withPingTimeoutMs(1000L)
754                 .withPublishEvents(new PublishEvents() {
755                     @Override
756                     public void onMessageReceived(Mqtt5Client client, PublishReturn publishReturn) {}
757                 })
758                 .withRetryJitterMode(JitterMode.Default)
759                 .withSessionBehavior(ClientSessionBehavior.CLEAN)
760                 .withSocketOptions(socketOptions);
761 
762                 Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketTransform = new Consumer<Mqtt5WebsocketHandshakeTransformArgs>() {
763                     @Override
764                     public void accept(Mqtt5WebsocketHandshakeTransformArgs t) {
765                         t.complete(t.getHttpRequest());
766                     }
767                 };
768                 builder.withWebsocketHandshakeTransform(websocketTransform);
769 
770                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
771                     client.start();
772                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
773                     DisconnectPacketBuilder disconnect = new DisconnectPacketBuilder();
774                     client.stop(disconnect.build());
775                 }
776             }
777 
778         } catch (Exception ex) {
779             fail(ex.getMessage());
780         }
781         CrtResource.waitForNoResources();
782     }
783 
784     /**
785      * ============================================================
786      * Negative Connect Tests with Incorrect Data
787      * ============================================================
788      */
789 
790     /* Client connect with invalid host name */
791     @Test
ConnNegativeID_UC1()792     public void ConnNegativeID_UC1() {
793         skipIfNetworkUnavailable();
794         Assume.assumeNotNull(AWS_TEST_MQTT5_DIRECT_MQTT_PORT);
795         boolean foundExpectedError = false;
796         boolean exceptionOccurred = false;
797 
798         try {
799             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
800 
801             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
802                 "_test", Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_PORT));
803             builder.withLifecycleEvents(events);
804             builder.withMinReconnectDelayMs(1000L);
805 
806             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
807                 client.start();
808 
809                 try {
810                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
811                 } catch (Exception ex) {
812                     exceptionOccurred = true;
813                     if (events.connectFailureCode == 1059) {
814                         foundExpectedError = true;
815                     } else {
816                         System.out.println("EXCEPTION: " + ex);
817                         System.out.println(ex.getMessage() + " \n");
818                     }
819                 }
820 
821                 if (foundExpectedError == false) {
822                     System.out.println("Error code was not AWS_IO_DNS_INVALID_NAME like expected! There was an exception though");
823                 }
824                 if (exceptionOccurred == false) {
825                     fail("No exception occurred!");
826                 }
827             }
828         } catch (Exception ex) {
829             fail(ex.getMessage());
830         }
831     }
832 
833     /* Client connect with invalid, nonexistent port for direct connection */
834     @Test
ConnNegativeID_UC2()835     public void ConnNegativeID_UC2() {
836         skipIfNetworkUnavailable();
837         Assume.assumeNotNull(AWS_TEST_MQTT5_DIRECT_MQTT_HOST);
838         boolean foundExpectedError = false;
839         boolean exceptionOccurred = false;
840 
841         try {
842             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
843             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_DIRECT_MQTT_HOST, 65535L);
844             builder.withLifecycleEvents(events);
845             builder.withMinReconnectDelayMs(1000L);
846 
847             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
848                 client.start();
849 
850                 try {
851                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
852                 } catch (Exception ex) {
853                     exceptionOccurred = true;
854                     if (events.connectFailureCode == 1047) {
855                         foundExpectedError = true;
856                     }
857                 }
858 
859                 if (foundExpectedError == false) {
860                     System.out.println("Error code was not AWS_IO_SOCKET_CONNECTION_REFUSED like expected! There was an exception though");
861                 }
862                 if (exceptionOccurred == false) {
863                     fail("No exception occurred!");
864                 }
865             }
866 
867         } catch (Exception ex) {
868             fail(ex.getMessage());
869         }
870     }
871 
872     /* Client connect with invalid protocol port for direct connection */
873     @Test
ConnNegativeID_UC2_ALT()874     public void ConnNegativeID_UC2_ALT() {
875         skipIfNetworkUnavailable();
876         Assume.assumeNotNull(AWS_TEST_MQTT5_DIRECT_MQTT_HOST, AWS_TEST_MQTT5_WS_MQTT_PORT);
877         boolean foundExpectedError = false;
878         boolean exceptionOccurred = false;
879 
880         try {
881             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
882             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
883                 AWS_TEST_MQTT5_DIRECT_MQTT_HOST, Long.parseLong(AWS_TEST_MQTT5_WS_MQTT_PORT));
884             builder.withLifecycleEvents(events);
885 
886             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
887                 client.start();
888 
889                 try {
890                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
891                 } catch (Exception ex) {
892                     exceptionOccurred = true;
893                     if (events.connectFailureCode == 5149) {
894                         foundExpectedError = true;
895                     }
896                 }
897 
898                 if (foundExpectedError == false) {
899                     System.out.println("Error code was not AWS_ERROR_MQTT5_DECODE_PROTOCOL_ERROR like expected! There was an exception though");
900                 }
901                 if (exceptionOccurred == false) {
902                     fail("No exception occurred!");
903                 }
904             }
905 
906         } catch (Exception ex) {
907             fail(ex.getMessage());
908         }
909     }
910 
911     /* Client connect with invalid, nonexistent port for websocket connection */
912     @Test
ConnNegativeID_UC3()913     public void ConnNegativeID_UC3() {
914         skipIfNetworkUnavailable();
915         Assume.assumeNotNull(AWS_TEST_MQTT5_WS_MQTT_HOST);
916         boolean foundExpectedError = false;
917         boolean exceptionOccurred = false;
918 
919         try {
920             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
921 
922             try (
923                 EventLoopGroup elg = new EventLoopGroup(1);
924                 HostResolver hr = new HostResolver(elg);
925                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
926             ) {
927                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_WS_MQTT_HOST, 444L);
928                 builder.withLifecycleEvents(events);
929                 builder.withBootstrap(bootstrap);
930 
931                 Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketTransform = new Consumer<Mqtt5WebsocketHandshakeTransformArgs>() {
932                     @Override
933                     public void accept(Mqtt5WebsocketHandshakeTransformArgs t) {
934                         t.complete(t.getHttpRequest());
935                     }
936                 };
937                 builder.withWebsocketHandshakeTransform(websocketTransform);
938 
939                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
940                     client.start();
941 
942                     try {
943                         events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
944                     } catch (Exception ex) {
945                         exceptionOccurred = true;
946                         if (events.connectFailureCode == 1047) {
947                             foundExpectedError = true;
948                         }
949                     }
950 
951                     if (foundExpectedError == false) {
952                         System.out.println("Error code was not AWS_ERROR_MQTT5_DECODE_PROTOCOL_ERROR like expected! There was an exception though");
953                     }
954                     if (exceptionOccurred == false) {
955                         fail("No exception occurred!");
956                     }
957                 }
958             }
959         } catch (Exception ex) {
960             fail(ex.getMessage());
961         }
962     }
963 
964     /* Client connect with invalid protocol port for websocket connection */
965     @Test
ConnNegativeID_UC3_ALT()966     public void ConnNegativeID_UC3_ALT() {
967         skipIfNetworkUnavailable();
968         Assume.assumeNotNull(AWS_TEST_MQTT5_WS_MQTT_HOST, AWS_TEST_MQTT5_DIRECT_MQTT_PORT);
969         boolean foundExpectedError = false;
970         boolean exceptionOccurred = false;
971 
972         try {
973             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
974 
975             try (
976                 EventLoopGroup elg = new EventLoopGroup(1);
977                 HostResolver hr = new HostResolver(elg);
978                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
979             ) {
980 
981                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
982                     AWS_TEST_MQTT5_WS_MQTT_HOST, Long.parseLong(AWS_TEST_MQTT5_DIRECT_MQTT_PORT));
983                 builder.withLifecycleEvents(events);
984                 builder.withBootstrap(bootstrap);
985 
986                 Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketTransform = new Consumer<Mqtt5WebsocketHandshakeTransformArgs>() {
987                     @Override
988                     public void accept(Mqtt5WebsocketHandshakeTransformArgs t) {
989                         t.complete(t.getHttpRequest());
990                     }
991                 };
992                 builder.withWebsocketHandshakeTransform(websocketTransform);
993 
994                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
995                     client.start();
996                     try {
997                         events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
998                     } catch (Exception ex) {
999                         exceptionOccurred = true;
1000                         if (events.connectFailureCode == 46) {
1001                             foundExpectedError = true;
1002                         }
1003                     }
1004 
1005                     if (foundExpectedError == false) {
1006                         System.out.println("Error code was not AWS_ERROR_SYS_CALL_FAILURE (occurs right after AWS_ERROR_MQTT5_DECODE_PROTOCOL_ERROR for Websockets) like expected! There was an exception though");
1007                     }
1008                     if (exceptionOccurred == false) {
1009                         fail("No exception occurred!");
1010                     }
1011                 }
1012             }
1013         } catch (Exception ex) {
1014             fail(ex.getMessage());
1015         }
1016     }
1017 
1018     /* Client connect with socket timeout */
1019     @Test
ConnNegativeID_UC4()1020     public void ConnNegativeID_UC4() {
1021         skipIfNetworkUnavailable();
1022         boolean foundExpectedError = false;
1023         boolean exceptionOccurred = false;
1024 
1025         try {
1026             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1027 
1028             try (
1029                 EventLoopGroup elg = new EventLoopGroup(1);
1030                 HostResolver hr = new HostResolver(elg);
1031                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
1032                 SocketOptions options = new SocketOptions();
1033             ) {
1034                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder("www.example.com", 81L);
1035                 builder.withLifecycleEvents(events);
1036                 builder.withBootstrap(bootstrap);
1037 
1038                 options.connectTimeoutMs = 100;
1039                 builder.withSocketOptions(options);
1040 
1041                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1042                     client.start();
1043 
1044                     try {
1045                         events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1046                     } catch (Exception ex) {
1047                         exceptionOccurred = true;
1048                         if (events.connectFailureCode == 1048) {
1049                             foundExpectedError = true;
1050                         }
1051                     }
1052                     if (foundExpectedError == false) {
1053                         System.out.println("Error code was not AWS_IO_SOCKET_TIMEOUT like expected! There was an exception though");
1054                     }
1055                     if (exceptionOccurred == false) {
1056                         fail("No exception occurred!");
1057                     }
1058                 }
1059             }
1060 
1061         } catch (Exception ex) {
1062             fail(ex.getMessage());
1063         }
1064     }
1065 
1066     /* Websocket handshake failure test */
1067     @Test
ConnNegativeID_UC6()1068     public void ConnNegativeID_UC6() {
1069         skipIfNetworkUnavailable();
1070         Assume.assumeNotNull(AWS_TEST_MQTT5_WS_MQTT_HOST, AWS_TEST_MQTT5_WS_MQTT_PORT);
1071         boolean foundExpectedError = false;
1072         boolean exceptionOccurred = false;
1073 
1074         try {
1075             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1076 
1077             try (
1078                 EventLoopGroup elg = new EventLoopGroup(1);
1079                 HostResolver hr = new HostResolver(elg);
1080                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
1081             ) {
1082 
1083                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(
1084                     AWS_TEST_MQTT5_WS_MQTT_HOST, Long.parseLong(AWS_TEST_MQTT5_WS_MQTT_PORT));
1085                 builder.withLifecycleEvents(events);
1086                 builder.withBootstrap(bootstrap);
1087 
1088                 Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketTransform = new Consumer<Mqtt5WebsocketHandshakeTransformArgs>() {
1089                     @Override
1090                     public void accept(Mqtt5WebsocketHandshakeTransformArgs t) {
1091                         t.completeExceptionally(new Throwable("Intentional failure!"));
1092                     }
1093                 };
1094                 builder.withWebsocketHandshakeTransform(websocketTransform);
1095 
1096                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1097                     client.start();
1098 
1099                     try {
1100                         events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1101                     } catch (Exception ex) {
1102                         exceptionOccurred = true;
1103                         if (events.connectFailureCode == 3) {
1104                             foundExpectedError = true;
1105                         }
1106                     }
1107                     if (foundExpectedError == false) {
1108                         System.out.println("Error code was not AWS_ERROR_UNKNOWN like expected! There was an exception though");
1109                     }
1110                     if (exceptionOccurred == false) {
1111                         fail("No exception occurred!");
1112                     }
1113 
1114                     client.stop();
1115                 }
1116             }
1117         } catch (Exception ex) {
1118             fail(ex.getMessage());
1119         }
1120     }
1121 
1122     /* For the double client ID test */
1123     static final class LifecycleEvents_DoubleClientID implements Mqtt5ClientOptions.LifecycleEvents {
1124         CompletableFuture<Void> connectedFuture = new CompletableFuture<>();
1125         CompletableFuture<Void> disconnectedFuture = new CompletableFuture<>();
1126         CompletableFuture<Void> stoppedFuture = new CompletableFuture<>();
1127         String client_name = "";
1128 
1129         @Override
onAttemptingConnect(Mqtt5Client client, OnAttemptingConnectReturn onAttemptingConnectReturn)1130         public void onAttemptingConnect(Mqtt5Client client, OnAttemptingConnectReturn onAttemptingConnectReturn) {}
1131 
1132         @Override
onConnectionSuccess(Mqtt5Client client, OnConnectionSuccessReturn onConnectionSuccessReturn)1133         public void onConnectionSuccess(Mqtt5Client client, OnConnectionSuccessReturn onConnectionSuccessReturn) {
1134             connectedFuture.complete(null);
1135         }
1136 
1137         @Override
onConnectionFailure(Mqtt5Client client, OnConnectionFailureReturn onConnectionFailureReturn)1138         public void onConnectionFailure(Mqtt5Client client, OnConnectionFailureReturn onConnectionFailureReturn) {
1139             connectedFuture.completeExceptionally(new Exception(
1140                 "[" + client_name + "] Could not connect! Error code is: " + onConnectionFailureReturn.getErrorCode()
1141             ));
1142         }
1143 
1144         @Override
onDisconnection(Mqtt5Client client, OnDisconnectionReturn onDisconnectionReturn)1145         public void onDisconnection(Mqtt5Client client, OnDisconnectionReturn onDisconnectionReturn) {
1146             disconnectedFuture.complete(null);
1147         }
1148 
1149         @Override
onStopped(Mqtt5Client client, OnStoppedReturn onStoppedReturn)1150         public void onStopped(Mqtt5Client client, OnStoppedReturn onStoppedReturn) {
1151             stoppedFuture.complete(null);
1152         }
1153     }
1154 
1155     /* Double Client ID failure test */
1156     @Test
ConnNegativeID_UC7()1157     public void ConnNegativeID_UC7() {
1158         skipIfNetworkUnavailable();
1159         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1160         String testUUID = UUID.randomUUID().toString();
1161 
1162         try {
1163             LifecycleEvents_DoubleClientID eventsOne = new LifecycleEvents_DoubleClientID();
1164             LifecycleEvents_DoubleClientID eventsTwo = new LifecycleEvents_DoubleClientID();
1165             eventsOne.client_name = "client_one";
1166             eventsTwo.client_name = "client_two";
1167 
1168             ConnectPacketBuilder connectOptions = new ConnectPacketBuilder().withClientId("test/MQTT5_Java_Double_ClientIDFail_" + testUUID);
1169 
1170             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1171             builder.withLifecycleEvents(eventsOne);
1172             builder.withConnectOptions(connectOptions.build());
1173             builder.withConnackTimeoutMs(30000l); // 30 seconds
1174 
1175             Mqtt5ClientOptionsBuilder builderTwo = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1176             builderTwo.withLifecycleEvents(eventsTwo);
1177             builderTwo.withConnectOptions(connectOptions.build());
1178             builderTwo.withConnackTimeoutMs(30000l); // 30 seconds
1179 
1180             try (TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1181                     AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1182                 TlsContext tlsContext = new TlsContext(tlsOptions))
1183             {
1184                 builder.withTlsContext(tlsContext);
1185                 builderTwo.withTlsContext(tlsContext);
1186                 try (Mqtt5Client clientOne = new Mqtt5Client(builder.build());
1187                     Mqtt5Client clientTwo = new Mqtt5Client(builderTwo.build());) {
1188                     clientOne.start();
1189                     eventsOne.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1190 
1191                     Thread.sleep(2000); // Sleep for 2 seconds to not hit IoT Core limits
1192 
1193                     clientTwo.start();
1194                     eventsTwo.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1195 
1196                     // Make sure a disconnection for client 1 happened
1197                     eventsOne.disconnectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1198 
1199                     // Stop the clients from disconnecting each other. If we do not do this, then the clients will
1200                     // attempt to reconnect endlessly, making a never ending loop.
1201                     clientOne.stop();
1202                     clientTwo.stop();
1203                 }
1204             }
1205         } catch (Exception ex) {
1206             fail(ex.getMessage());
1207         }
1208     }
1209 
1210     /**
1211      * ============================================================
1212      * Negative Data Input Tests
1213      * ============================================================
1214      */
1215 
1216     /* Negative Connect Packet Properties */
1217     @Test
NewNegative_UC1()1218     public void NewNegative_UC1() {
1219         skipIfNetworkUnavailable();
1220         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1221         boolean clientCreationFailed = false;
1222 
1223         try {
1224             Mqtt5Client client = null;
1225             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1226             ConnectPacketBuilder connectOptions = new ConnectPacketBuilder();
1227 
1228             connectOptions.withKeepAliveIntervalSeconds(-100L);
1229             builder.withConnectOptions(connectOptions.build());
1230 
1231             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1232                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1233             TlsContext tlsContext = new TlsContext(tlsOptions);
1234             tlsOptions.close();
1235             builder.withTlsContext(tlsContext);
1236 
1237             clientCreationFailed = false;
1238             try {
1239                 client = new Mqtt5Client(builder.build());
1240             } catch (Exception ex) {
1241                 clientCreationFailed = true;
1242             }
1243             if (clientCreationFailed == false) {
1244                 fail("Client creation did not fail with negative KeepAliveIntervalSeconds");
1245             }
1246             connectOptions.withKeepAliveIntervalSeconds(100L);
1247 
1248             connectOptions.withSessionExpiryIntervalSeconds(-100L);
1249             builder.withConnectOptions(connectOptions.build());
1250             clientCreationFailed = false;
1251             try {
1252                 client = new Mqtt5Client(builder.build());
1253             } catch (Exception ex) {
1254                 clientCreationFailed = true;
1255             }
1256             if (clientCreationFailed == false) {
1257                 fail("Client creation did not fail with negative SessionExpiryIntervalSeconds");
1258             }
1259             connectOptions.withSessionExpiryIntervalSeconds(100L);
1260 
1261             connectOptions.withReceiveMaximum(-100L);
1262             builder.withConnectOptions(connectOptions.build());
1263             clientCreationFailed = false;
1264             try {
1265                 client = new Mqtt5Client(builder.build());
1266             } catch (Exception ex) {
1267                 clientCreationFailed = true;
1268             }
1269             if (clientCreationFailed == false) {
1270                 fail("Client creation did not fail negative ReceiveMaximum");
1271             }
1272             connectOptions.withReceiveMaximum(100L);
1273 
1274             connectOptions.withMaximumPacketSizeBytes(-100L);
1275             builder.withConnectOptions(connectOptions.build());
1276             clientCreationFailed = false;
1277             try {
1278                 client = new Mqtt5Client(builder.build());
1279             } catch (Exception ex) {
1280                 clientCreationFailed = true;
1281             }
1282             if (clientCreationFailed == false) {
1283                 fail("Client creation did not fail with negative MaximumPacketSizeBytes");
1284             }
1285             connectOptions.withMaximumPacketSizeBytes(100L);
1286 
1287             connectOptions.withWillDelayIntervalSeconds(-100L);
1288             builder.withConnectOptions(connectOptions.build());
1289             clientCreationFailed = false;
1290             try {
1291                 client = new Mqtt5Client(builder.build());
1292             } catch (Exception ex) {
1293                 clientCreationFailed = true;
1294             }
1295             if (clientCreationFailed == false) {
1296                 fail("Client creation did not fail with negative willDelayIntervalSeconds");
1297             }
1298             connectOptions.withWillDelayIntervalSeconds(100L);
1299 
1300             // Make sure everything is closed
1301             if (client != null) {
1302                 client.close();
1303             }
1304             if (tlsContext != null) {
1305                 tlsContext.close();
1306             }
1307 
1308         } catch (Exception ex) {
1309             fail(ex.getMessage());
1310         }
1311     }
1312 
1313     /* Overflow Connect Packet Properties */
1314     @Test
NewNegative_UC1_ALT()1315     public void NewNegative_UC1_ALT() {
1316         skipIfNetworkUnavailable();
1317         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1318         boolean clientCreationFailed = false;
1319 
1320         try {
1321             Mqtt5Client client = null;
1322             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1323             ConnectPacketBuilder connectOptions = new ConnectPacketBuilder();
1324 
1325             connectOptions.withKeepAliveIntervalSeconds(2147483647L);
1326             builder.withConnectOptions(connectOptions.build());
1327 
1328             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1329                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1330             TlsContext tlsContext = new TlsContext(tlsOptions);
1331             tlsOptions.close();
1332             builder.withTlsContext(tlsContext);
1333 
1334             clientCreationFailed = false;
1335             try {
1336                 client = new Mqtt5Client(builder.build());
1337             } catch (Exception ex) {
1338                 clientCreationFailed = true;
1339             }
1340             if (clientCreationFailed == false) {
1341                 fail("Client creation did not fail with overflow KeepAliveIntervalSeconds");
1342             }
1343             connectOptions.withKeepAliveIntervalSeconds(100L);
1344 
1345             connectOptions.withSessionExpiryIntervalSeconds(9223372036854775807L);
1346             builder.withConnectOptions(connectOptions.build());
1347             clientCreationFailed = false;
1348             try {
1349                 client = new Mqtt5Client(builder.build());
1350             } catch (Exception ex) {
1351                 clientCreationFailed = true;
1352             }
1353             if (clientCreationFailed == false) {
1354                 fail("Client creation did not fail with overflow SessionExpiryIntervalSeconds");
1355             }
1356             connectOptions.withSessionExpiryIntervalSeconds(100L);
1357 
1358             connectOptions.withReceiveMaximum(2147483647L);
1359             builder.withConnectOptions(connectOptions.build());
1360             clientCreationFailed = false;
1361             try {
1362                 client = new Mqtt5Client(builder.build());
1363             } catch (Exception ex) {
1364                 clientCreationFailed = true;
1365             }
1366             if (clientCreationFailed == false) {
1367                 fail("Client creation did not fail overflow ReceiveMaximum");
1368             }
1369             connectOptions.withReceiveMaximum(100L);
1370 
1371             connectOptions.withMaximumPacketSizeBytes(9223372036854775807L);
1372             builder.withConnectOptions(connectOptions.build());
1373             clientCreationFailed = false;
1374             try {
1375                 client = new Mqtt5Client(builder.build());
1376             } catch (Exception ex) {
1377                 clientCreationFailed = true;
1378             }
1379             if (clientCreationFailed == false) {
1380                 fail("Client creation did not fail with overflow MaximumPacketSizeBytes");
1381             }
1382             connectOptions.withMaximumPacketSizeBytes(100L);
1383 
1384             // WillDelayIntervalSeconds is an unsigned 64 bit Long, so it cannot overflow it from Java
1385 
1386             // Make sure everything is closed
1387             if (client != null) {
1388                 client.close();
1389             }
1390             if (tlsContext != null) {
1391                 tlsContext.close();
1392             }
1393 
1394         } catch (Exception ex) {
1395             fail(ex.getMessage());
1396         }
1397     }
1398 
1399     /* Negative Disconnect Packet Properties */
1400     @Test
NewNegative_UC2()1401     public void NewNegative_UC2() {
1402         skipIfNetworkUnavailable();
1403         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1404         boolean clientDisconnectFailed = false;
1405 
1406         try {
1407             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1408             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1409             builder.withLifecycleEvents(events);
1410 
1411             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1412                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1413             TlsContext tlsContext = new TlsContext(tlsOptions);
1414             tlsOptions.close();
1415             builder.withTlsContext(tlsContext);
1416 
1417             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1418                 client.start();
1419                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1420 
1421                 DisconnectPacketBuilder disconnectBuilder = new DisconnectPacketBuilder();
1422                 disconnectBuilder.withSessionExpiryIntervalSeconds(-100L);
1423                 try {
1424                     client.stop(disconnectBuilder.build());
1425                 } catch (Exception ex) {
1426                     clientDisconnectFailed = true;
1427                 }
1428 
1429                 if (clientDisconnectFailed == false) {
1430                     fail("Client disconnect packet creation did not fail!");
1431                 }
1432 
1433                 client.stop(new DisconnectPacketBuilder().build());
1434             }
1435 
1436             if (tlsContext != null) {
1437                 tlsContext.close();
1438             }
1439 
1440         } catch (Exception ex) {
1441             fail(ex.getMessage());
1442         }
1443     }
1444 
1445     /* Overflow Disconnect Packet Properties */
1446     @Test
NewNegative_UC2_ALT()1447     public void NewNegative_UC2_ALT() {
1448         skipIfNetworkUnavailable();
1449         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1450         boolean clientDisconnectFailed = false;
1451 
1452         try {
1453             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1454             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1455             builder.withLifecycleEvents(events);
1456 
1457             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1458                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1459             TlsContext tlsContext = new TlsContext(tlsOptions);
1460             tlsOptions.close();
1461             builder.withTlsContext(tlsContext);
1462 
1463             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1464                 client.start();
1465                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1466 
1467                 DisconnectPacketBuilder disconnectBuilder = new DisconnectPacketBuilder();
1468                 disconnectBuilder.withSessionExpiryIntervalSeconds(9223372036854775807L);
1469                 try {
1470                     client.stop(disconnectBuilder.build());
1471                 } catch (Exception ex) {
1472                     clientDisconnectFailed = true;
1473                 }
1474 
1475                 if (clientDisconnectFailed == false) {
1476                     fail("Client disconnect did not fail!");
1477                 }
1478 
1479                 client.stop(new DisconnectPacketBuilder().build());
1480             }
1481 
1482             if (tlsContext != null) {
1483                 tlsContext.close();
1484             }
1485 
1486         } catch (Exception ex) {
1487             fail(ex.getMessage());
1488         }
1489     }
1490 
1491     /* Negative Publish Packet Properties */
1492     @Test
NewNegative_UC3()1493     public void NewNegative_UC3() {
1494         skipIfNetworkUnavailable();
1495         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1496         boolean clientPublishFailed = false;
1497 
1498         try {
1499             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1500             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1501             builder.withLifecycleEvents(events);
1502 
1503             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1504                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1505             TlsContext tlsContext = new TlsContext(tlsOptions);
1506             tlsOptions.close();
1507             builder.withTlsContext(tlsContext);
1508 
1509             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1510                 client.start();
1511                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1512 
1513                 PublishPacketBuilder publishBuilder = new PublishPacketBuilder();
1514                 publishBuilder.withPayload("Hello World".getBytes()).withTopic("test/topic");
1515                 publishBuilder.withMessageExpiryIntervalSeconds(-100L);
1516                 try {
1517                     CompletableFuture<PublishResult> future = client.publish(publishBuilder.build());
1518                     future.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1519                 } catch (Exception ex) {
1520                     clientPublishFailed = true;
1521                 }
1522 
1523                 if (clientPublishFailed == false) {
1524                     fail("Client publish did not fail!");
1525                 }
1526 
1527                 client.stop();
1528             }
1529 
1530             if (tlsContext != null) {
1531                 tlsContext.close();
1532             }
1533 
1534         } catch (Exception ex) {
1535             fail(ex.getMessage());
1536         }
1537     }
1538 
1539     /* Overflow Publish Packet Properties */
1540     @Test
NewNegative_UC3_ALT()1541     public void NewNegative_UC3_ALT() {
1542         skipIfNetworkUnavailable();
1543         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1544         boolean clientPublishFailed = false;
1545 
1546         try {
1547             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1548             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1549             builder.withLifecycleEvents(events);
1550 
1551             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1552                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1553             TlsContext tlsContext = new TlsContext(tlsOptions);
1554             tlsOptions.close();
1555             builder.withTlsContext(tlsContext);
1556 
1557             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1558                 client.start();
1559                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1560 
1561                 PublishPacketBuilder publishBuilder = new PublishPacketBuilder();
1562                 publishBuilder.withPayload("Hello World".getBytes()).withTopic("test/topic").withQOS(QOS.AT_LEAST_ONCE);
1563                 publishBuilder.withMessageExpiryIntervalSeconds(9223372036854775807L);
1564                 try {
1565                     CompletableFuture<PublishResult> future = client.publish(publishBuilder.build());
1566                     future.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1567                 } catch (Exception ex) {
1568                     clientPublishFailed = true;
1569                 }
1570 
1571                 if (clientPublishFailed == false) {
1572                     fail("Client publish did not fail!");
1573                 }
1574 
1575                 client.stop();
1576             }
1577 
1578             if (tlsContext != null) {
1579                 tlsContext.close();
1580             }
1581 
1582         } catch (Exception ex) {
1583             fail(ex.getMessage());
1584         }
1585     }
1586 
1587     /* Negative Subscribe Packet Properties */
1588     @Test
NewNegative_UC4()1589     public void NewNegative_UC4() {
1590         skipIfNetworkUnavailable();
1591         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1592         boolean clientSubscribeFailed = false;
1593 
1594         try {
1595             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1596             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1597             builder.withLifecycleEvents(events);
1598 
1599             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1600                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1601             TlsContext tlsContext = new TlsContext(tlsOptions);
1602             tlsOptions.close();
1603             builder.withTlsContext(tlsContext);
1604 
1605             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1606                 client.start();
1607                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1608 
1609                 SubscribePacketBuilder subscribeBuilder = new SubscribePacketBuilder();
1610                 subscribeBuilder.withSubscription("test/topic", QOS.AT_LEAST_ONCE);
1611                 subscribeBuilder.withSubscriptionIdentifier(-100L);
1612                 try {
1613                     CompletableFuture<SubAckPacket> future = client.subscribe(subscribeBuilder.build());
1614                     future.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1615                 } catch (Exception ex) {
1616                     clientSubscribeFailed = true;
1617                 }
1618 
1619                 if (clientSubscribeFailed == false) {
1620                     fail("Client subscribe did not fail!");
1621                 }
1622 
1623                 client.stop();
1624             }
1625 
1626             if (tlsContext != null) {
1627                 tlsContext.close();
1628             }
1629 
1630         } catch (Exception ex) {
1631             fail(ex.getMessage());
1632         }
1633     }
1634 
1635     /* Overflow Subscribe Packet Properties */
1636     @Test
NewNegative_UC4_ALT()1637     public void NewNegative_UC4_ALT() {
1638         skipIfNetworkUnavailable();
1639         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1640         boolean clientSubscribeFailed = false;
1641 
1642         try {
1643             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1644             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1645             builder.withLifecycleEvents(events);
1646 
1647             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1648                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1649             TlsContext tlsContext = new TlsContext(tlsOptions);
1650             tlsOptions.close();
1651             builder.withTlsContext(tlsContext);
1652 
1653             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1654                 client.start();
1655                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1656 
1657                 SubscribePacketBuilder subscribeBuilder = new SubscribePacketBuilder();
1658                 subscribeBuilder.withSubscription("test/topic", QOS.AT_LEAST_ONCE);
1659                 subscribeBuilder.withSubscriptionIdentifier(9223372036854775807L);
1660                 try {
1661                     CompletableFuture<SubAckPacket> future = client.subscribe(subscribeBuilder.build());
1662                     future.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1663                 } catch (Exception ex) {
1664                     clientSubscribeFailed = true;
1665                 }
1666 
1667                 if (clientSubscribeFailed == false) {
1668                     fail("Client subscribe did not fail!");
1669                 }
1670 
1671                 client.stop();
1672             }
1673 
1674             if (tlsContext != null) {
1675                 tlsContext.close();
1676             }
1677 
1678         } catch (Exception ex) {
1679             fail(ex.getMessage());
1680         }
1681     }
1682 
1683     /**
1684      * ============================================================
1685      * Negotiated Settings Tests
1686      * ============================================================
1687      */
1688 
1689     /* Happy path, minimal success test */
1690     @Test
Negotiated_UC1()1691     public void Negotiated_UC1() {
1692         skipIfNetworkUnavailable();
1693         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1694         try {
1695             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1696             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1697             builder.withLifecycleEvents(events);
1698 
1699             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1700                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1701             TlsContext tlsContext = new TlsContext(tlsOptions);
1702             tlsOptions.close();
1703             builder.withTlsContext(tlsContext);
1704 
1705             ConnectPacketBuilder optionsBuilder = new ConnectPacketBuilder();
1706             optionsBuilder.withSessionExpiryIntervalSeconds(600000L);
1707             builder.withConnectOptions(optionsBuilder.build());
1708 
1709             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1710                 client.start();
1711                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1712 
1713                 // TODO: Add support for this in the future
1714                 // assertEquals(
1715                 //     "Negotiated Settings session expiry interval does not match sent session expiry interval",
1716                 //     events.connectSuccessSettings.getSessionExpiryIntervalSeconds(),
1717                 //     600000L);
1718 
1719                 client.stop();
1720             }
1721 
1722             if (tlsContext != null) {
1723                 tlsContext.close();
1724             }
1725 
1726         } catch (Exception ex) {
1727             fail(ex.getMessage());
1728         }
1729     }
1730 
1731     /* Maximum success test */
1732     @Test
Negotiated_UC2()1733     public void Negotiated_UC2() {
1734         skipIfNetworkUnavailable();
1735         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1736         String testUUID = UUID.randomUUID().toString();
1737         try {
1738             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1739             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1740             builder.withLifecycleEvents(events);
1741 
1742             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1743                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1744             TlsContext tlsContext = new TlsContext(tlsOptions);
1745             tlsOptions.close();
1746             builder.withTlsContext(tlsContext);
1747 
1748             ConnectPacketBuilder optionsBuilder = new ConnectPacketBuilder();
1749             optionsBuilder.withClientId("test/MQTT5_Binding_Java_" + testUUID);
1750             optionsBuilder.withSessionExpiryIntervalSeconds(0L);
1751             optionsBuilder.withKeepAliveIntervalSeconds(360L);
1752             builder.withConnectOptions(optionsBuilder.build());
1753 
1754             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1755                 client.start();
1756                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1757 
1758                 assertEquals(
1759                     "Negotiated Settings client ID does not match sent client ID",
1760                     events.connectSuccessSettings.getAssignedClientID(),
1761                     "test/MQTT5_Binding_Java_" + testUUID);
1762                 assertEquals(
1763                     "Negotiated Settings session expiry interval does not match sent session expiry interval",
1764                     events.connectSuccessSettings.getSessionExpiryIntervalSeconds(),
1765                     0L);
1766                 assertEquals(
1767                     "Negotiated Settings keep alive result does not match sent keep alive",
1768                     events.connectSuccessSettings.getServerKeepAliveSeconds(),
1769                     360);
1770                 assertEquals(
1771                         "Negotiated Settings rejoined session does not match expected value",
1772                         false,
1773                         events.connectSuccessSettings.getRejoinedSession());
1774 
1775                 client.stop();
1776             }
1777 
1778             if (tlsContext != null) {
1779                 tlsContext.close();
1780             }
1781 
1782         } catch (Exception ex) {
1783             fail(ex.getMessage());
1784         }
1785     }
1786 
1787     /* Rejoin always session resumption test */
1788     @Test
Negotiated_Rejoin_Always()1789     public void Negotiated_Rejoin_Always() {
1790         skipIfNetworkUnavailable();
1791         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1792         String testUUID = UUID.randomUUID().toString();
1793         try {
1794             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1795             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1796             builder.withLifecycleEvents(events);
1797 
1798             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1799                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1800             TlsContext tlsContext = new TlsContext(tlsOptions);
1801             tlsOptions.close();
1802             builder.withTlsContext(tlsContext);
1803 
1804             ConnectPacketBuilder optionsBuilder = new ConnectPacketBuilder();
1805             optionsBuilder.withClientId("test/MQTT5_Binding_Java_" + testUUID);
1806             optionsBuilder.withSessionExpiryIntervalSeconds(3600L);
1807             optionsBuilder.withKeepAliveIntervalSeconds(360L);
1808             builder.withConnectOptions(optionsBuilder.build());
1809 
1810             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1811                 client.start();
1812                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1813 
1814                 assertEquals(
1815                         "Negotiated Settings client ID does not match sent client ID",
1816                         events.connectSuccessSettings.getAssignedClientID(),
1817                         "test/MQTT5_Binding_Java_" + testUUID);
1818                 assertEquals(
1819                         "Negotiated Settings session expiry interval does not match sent session expiry interval",
1820                         events.connectSuccessSettings.getSessionExpiryIntervalSeconds(),
1821                         3600L);
1822                 assertEquals(
1823                         "Negotiated Settings keep alive result does not match sent keep alive",
1824                         events.connectSuccessSettings.getServerKeepAliveSeconds(),
1825                         360);
1826                 assertEquals(
1827                         "Negotiated Settings rejoined session does not match expected value",
1828                         false,
1829                         events.connectSuccessSettings.getRejoinedSession());
1830 
1831                 client.stop();
1832                 events.stopFuture.get();
1833             }
1834 
1835             builder.withSessionBehavior(ClientSessionBehavior.REJOIN_ALWAYS);
1836             LifecycleEvents_Futured rejoinEvents = new LifecycleEvents_Futured();
1837             builder.withLifecycleEvents(rejoinEvents);
1838 
1839             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1840                 client.start();
1841                 rejoinEvents.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1842 
1843                 assertEquals(
1844                         "Negotiated Settings rejoined session does not match expected value",
1845                         true,
1846                         rejoinEvents.connectSuccessSettings.getRejoinedSession());
1847 
1848                 client.stop();
1849             }
1850 
1851             if (tlsContext != null) {
1852                 tlsContext.close();
1853             }
1854 
1855         } catch (Exception ex) {
1856             fail(ex.getMessage());
1857         }
1858     }
1859 
1860     /**
1861      * ============================================================
1862      * Operation Tests
1863      * ============================================================
1864      */
1865 
1866     /* Sub-UnSub happy path */
1867     @Test
Op_UC1()1868     public void Op_UC1() {
1869         skipIfNetworkUnavailable();
1870         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1871         String testUUID = UUID.randomUUID().toString();
1872         String testTopic = "test/MQTT5_Binding_Java_" + testUUID;
1873         try {
1874             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1875             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1876             builder.withLifecycleEvents(events);
1877 
1878             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1879                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1880             TlsContext tlsContext = new TlsContext(tlsOptions);
1881             tlsOptions.close();
1882             builder.withTlsContext(tlsContext);
1883 
1884             PublishEvents_Futured publishEvents = new PublishEvents_Futured();
1885             builder.withPublishEvents(publishEvents);
1886 
1887             PublishPacketBuilder publishPacketBuilder = new PublishPacketBuilder();
1888             publishPacketBuilder.withTopic(testTopic);
1889             publishPacketBuilder.withPayload("Hello World".getBytes());
1890             publishPacketBuilder.withQOS(QOS.AT_LEAST_ONCE);
1891 
1892             SubscribePacketBuilder subscribePacketBuilder = new SubscribePacketBuilder();
1893             subscribePacketBuilder.withSubscription(testTopic, QOS.AT_LEAST_ONCE);
1894 
1895             UnsubscribePacketBuilder unsubscribePacketBuilder = new UnsubscribePacketBuilder();
1896             unsubscribePacketBuilder.withSubscription(testTopic);
1897 
1898             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
1899                 client.start();
1900                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1901 
1902                 client.subscribe(subscribePacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1903 
1904                 client.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1905                 publishEvents.publishReceivedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1906 
1907                 publishEvents.publishReceivedFuture = new CompletableFuture<>();
1908                 publishEvents.publishPacket = null;
1909                 client.unsubscribe(unsubscribePacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1910                 client.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1911 
1912                 assertEquals(
1913                     "Publish after unsubscribe still arrived!",
1914                     publishEvents.publishPacket,
1915                     null);
1916 
1917                 client.stop();
1918             }
1919 
1920             if (tlsContext != null) {
1921                 tlsContext.close();
1922             }
1923 
1924         } catch (Exception ex) {
1925             fail(ex.getMessage());
1926         }
1927     }
1928 
1929     /* Sub-UnSub happy path */
1930     @Test
Op_UC2()1931     public void Op_UC2() {
1932         skipIfNetworkUnavailable();
1933         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1934         String testUUID = UUID.randomUUID().toString();
1935         String testTopic = "test/MQTT5_Binding_Java_" + testUUID;
1936         try {
1937             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1938             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
1939             builder.withLifecycleEvents(events);
1940 
1941             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
1942                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1943             TlsContext tlsContext = new TlsContext(tlsOptions);
1944             tlsOptions.close();
1945             builder.withTlsContext(tlsContext);
1946 
1947             ConnectPacketBuilder connectOptions = new ConnectPacketBuilder();
1948             PublishPacketBuilder willPacket = new PublishPacketBuilder();
1949             willPacket.withTopic(testTopic);
1950             willPacket.withQOS(QOS.AT_LEAST_ONCE);
1951             willPacket.withPayload("Hello World".getBytes());
1952             connectOptions.withWill(willPacket.build());
1953             connectOptions.withWillDelayIntervalSeconds(0L);
1954             builder.withConnectOptions(connectOptions.build());
1955 
1956             Mqtt5ClientOptionsBuilder builderTwo = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
1957             LifecycleEvents_Futured eventsTwo = new LifecycleEvents_Futured();
1958             builderTwo.withLifecycleEvents(eventsTwo);
1959             PublishEvents_Futured publishEvents = new PublishEvents_Futured();
1960             builderTwo.withPublishEvents(publishEvents);
1961 
1962             TlsContextOptions tlsOptionsTwo = TlsContextOptions.createWithMtlsFromPath(
1963                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
1964             TlsContext tlsContextTwo = new TlsContext(tlsOptionsTwo);
1965             tlsOptionsTwo.close();
1966             builderTwo.withTlsContext(tlsContextTwo);
1967 
1968             SubscribePacketBuilder subscribeOptions = new SubscribePacketBuilder();
1969             subscribeOptions.withSubscription(testTopic, QOS.AT_LEAST_ONCE);
1970 
1971             try (
1972                 Mqtt5Client clientOne = new Mqtt5Client(builder.build());
1973                 Mqtt5Client clientTwo = new Mqtt5Client(builderTwo.build());
1974             ) {
1975                 clientOne.start();
1976                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1977                 clientTwo.start();
1978                 eventsTwo.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1979 
1980                 clientTwo.subscribe(subscribeOptions.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1981                 clientOne.stop();
1982 
1983                 // Did we get a publish message?
1984                 publishEvents.publishReceivedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
1985                 assertTrue(publishEvents.publishPacket != null);
1986 
1987                 clientTwo.stop(new DisconnectPacketBuilder().build());
1988             }
1989 
1990             if (tlsContext != null) {
1991                 tlsContext.close();
1992                 tlsContextTwo.close();
1993             }
1994 
1995         } catch (Exception ex) {
1996             fail(ex.getMessage());
1997         }
1998     }
1999 
2000     /* Binary Publish Test */
2001     @Test
Op_UC3()2002     public void Op_UC3() {
2003         skipIfNetworkUnavailable();
2004         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2005         String testUUID = UUID.randomUUID().toString();
2006         String testTopic = "test/MQTT5_Binding_Java_" + testUUID;
2007         try {
2008             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2009             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2010             builder.withLifecycleEvents(events);
2011 
2012             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2013                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2014             TlsContext tlsContext = new TlsContext(tlsOptions);
2015             tlsOptions.close();
2016             builder.withTlsContext(tlsContext);
2017 
2018             PublishEvents_Futured publishEvents = new PublishEvents_Futured();
2019             builder.withPublishEvents(publishEvents);
2020 
2021             // Make random binary
2022             byte[] randomBytes = new byte[256];
2023             Random random = new Random();
2024             random.nextBytes(randomBytes);
2025 
2026             PublishPacketBuilder publishPacketBuilder = new PublishPacketBuilder();
2027             publishPacketBuilder.withTopic(testTopic).withPayload(randomBytes).withQOS(QOS.AT_LEAST_ONCE);
2028 
2029             SubscribePacketBuilder subscribePacketBuilder = new SubscribePacketBuilder();
2030             subscribePacketBuilder.withSubscription(testTopic, QOS.AT_LEAST_ONCE);
2031 
2032             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2033                 client.start();
2034                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2035 
2036                 client.subscribe(subscribePacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2037 
2038                 client.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2039                 publishEvents.publishReceivedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2040 
2041                 assertTrue(java.util.Arrays.equals(publishEvents.publishPacket.getPayload(), randomBytes));
2042 
2043                 client.stop();
2044                 events.stopFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2045             }
2046 
2047             if (tlsContext != null) {
2048                 tlsContext.close();
2049             }
2050 
2051         } catch (Exception ex) {
2052             fail(ex.getMessage());
2053         }
2054     }
2055 
2056     /* Will test */
2057     @Test
Op_UC4()2058     public void Op_UC4() {
2059         skipIfNetworkUnavailable();
2060         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2061         String testUUID = UUID.randomUUID().toString();
2062         String testTopic = "test/MQTT5_Binding_Java_" + testUUID;
2063         try {
2064             // Publisher
2065             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2066             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2067             builder.withLifecycleEvents(events);
2068 
2069             // Subscriber
2070             Mqtt5ClientOptionsBuilder builderTwo = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2071             LifecycleEvents_Futured eventsTwo = new LifecycleEvents_Futured();
2072             builderTwo.withLifecycleEvents(eventsTwo);
2073 
2074             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2075                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2076             TlsContext tlsContext = new TlsContext(tlsOptions);
2077             tlsOptions.close();
2078             builder.withTlsContext(tlsContext);
2079             builderTwo.withTlsContext(tlsContext);
2080 
2081             PublishEvents_Futured publishEvents = new PublishEvents_Futured();
2082             builderTwo.withPublishEvents(publishEvents);
2083             SubscribePacketBuilder subscribePacketBuilder = new SubscribePacketBuilder();
2084             subscribePacketBuilder.withSubscription(testTopic, QOS.AT_LEAST_ONCE);
2085 
2086             ConnectPacketBuilder connectPacketBuilder = new ConnectPacketBuilder();
2087             PublishPacketBuilder publishPacketBuilder = new PublishPacketBuilder();
2088             publishPacketBuilder.withTopic(testTopic);
2089             publishPacketBuilder.withPayload("Hello World".getBytes());
2090             publishPacketBuilder.withQOS(QOS.AT_LEAST_ONCE);
2091             connectPacketBuilder.withWill(publishPacketBuilder.build());
2092             connectPacketBuilder.withKeepAliveIntervalSeconds(4l);
2093             builder.withConnectOptions(connectPacketBuilder.build());
2094             builder.withPingTimeoutMs(8l);
2095 
2096             DisconnectPacketBuilder disconnectPacketBuilder = new DisconnectPacketBuilder();
2097             disconnectPacketBuilder.withReasonCode(DisconnectReasonCode.DISCONNECT_WITH_WILL_MESSAGE);
2098 
2099             try (Mqtt5Client publisher = new Mqtt5Client(builder.build());
2100                 Mqtt5Client subscriber = new Mqtt5Client(builderTwo.build())) {
2101 
2102                 publisher.start();
2103                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2104 
2105                 subscriber.start();
2106                 eventsTwo.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2107                 subscriber.subscribe(subscribePacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2108 
2109                 publisher.stop(disconnectPacketBuilder.build());
2110 
2111                 publishEvents.publishReceivedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2112                 subscriber.stop(new DisconnectPacketBuilder().build());
2113             }
2114 
2115             if (tlsContext != null) {
2116                 tlsContext.close();
2117             }
2118 
2119         } catch (Exception ex) {
2120             fail(ex.getMessage());
2121         }
2122     }
2123 
2124     /* Shared subscriptions test */
2125     @Test
Op_SharedSubscription()2126     public void Op_SharedSubscription() {
2127         skipIfNetworkUnavailable();
2128         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2129         int messageCount = 10;
2130         String testUUID = UUID.randomUUID().toString();
2131         String testTopic = "test/MQTT5_Binding_Java_" + testUUID;
2132         String sharedTopicfilter = "$share/crttest/test/MQTT5_Binding_Java_" + testUUID;
2133 
2134         try {
2135             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2136                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2137             TlsContext tlsContext = new TlsContext(tlsOptions);
2138             tlsOptions.close();
2139 
2140             // Publisher builder
2141             Mqtt5ClientOptionsBuilder publisherBuilder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2142             LifecycleEvents_Futured publisherLCEvents = new LifecycleEvents_Futured();
2143             publisherBuilder.withLifecycleEvents(publisherLCEvents);
2144             publisherBuilder.withTlsContext(tlsContext);
2145 
2146             PublishEvents_Futured_Counted publishEvents = new PublishEvents_Futured_Counted();
2147             publishEvents.desiredPublishCount = messageCount;
2148 
2149             // SubscriberOne builder
2150             Mqtt5ClientOptionsBuilder subscriberOneBuilder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2151             LifecycleEvents_Futured subscriberOneLCEvents = new LifecycleEvents_Futured();
2152             subscriberOneBuilder.withLifecycleEvents(subscriberOneLCEvents);
2153             subscriberOneBuilder.withTlsContext(tlsContext);
2154             subscriberOneBuilder.withPublishEvents(publishEvents);
2155 
2156             // SubscriberTwo builder
2157             Mqtt5ClientOptionsBuilder subscriberTwoBuilder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2158             LifecycleEvents_Futured subscriberTwoLCEvents = new LifecycleEvents_Futured();
2159             subscriberTwoBuilder.withLifecycleEvents(subscriberTwoLCEvents);
2160             subscriberTwoBuilder.withTlsContext(tlsContext);
2161             subscriberTwoBuilder.withPublishEvents(publishEvents);
2162 
2163             // PublishPacketBuilder
2164             PublishPacketBuilder publishPacketBuilder = new PublishPacketBuilder();
2165             publishPacketBuilder.withTopic(testTopic);
2166             publishPacketBuilder.withQOS(QOS.AT_LEAST_ONCE);
2167 
2168             // SubscribePacketBuilder
2169             SubscribePacketBuilder subscribePacketBuilder = new SubscribePacketBuilder();
2170             subscribePacketBuilder.withSubscription(sharedTopicfilter, QOS.AT_LEAST_ONCE);
2171 
2172             try (
2173                 Mqtt5Client publisherClient = new Mqtt5Client(publisherBuilder.build());
2174                 Mqtt5Client subscriberOneClient = new Mqtt5Client(subscriberOneBuilder.build());
2175                 Mqtt5Client subscriberTwoClient = new Mqtt5Client(subscriberTwoBuilder.build())
2176             ) {
2177                 publisherClient.start();
2178                 subscriberOneClient.start();
2179                 subscriberTwoClient.start();
2180 
2181                 publisherLCEvents.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2182                 subscriberOneLCEvents.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2183                 subscriberTwoLCEvents.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2184 
2185                 subscriberOneClient.subscribe(subscribePacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2186                 subscriberTwoClient.subscribe(subscribePacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2187 
2188                 for (int i = 0; i < messageCount; ++i) {
2189                     publishPacketBuilder.withPayload(String.valueOf(i).getBytes());
2190                     publisherClient.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2191                 }
2192 
2193                 publishEvents.publishReceivedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2194 
2195                 // Wait a little longer just to ensure that no packets beyond expectations are arrived.
2196                 publishEvents.afterCompletionFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2197 
2198                 // Check that both clients received packets.
2199                 // PublishEvents_Futured_Counted also checks for duplicated packets, so this one assert is enough
2200                 // to ensure that AWS IoT Core sent different packets to different subscribers.
2201                 assertTrue(publishEvents.clientsReceived.size() == 2);
2202 
2203                 subscriberOneClient.stop();
2204                 subscriberTwoClient.stop();
2205                 publisherClient.stop();
2206             }
2207 
2208             if (tlsContext != null) {
2209                 tlsContext.close();
2210             }
2211         } catch (Exception ex) {
2212             fail(ex.getMessage());
2213         }
2214     }
2215 
2216     /**
2217      * ============================================================
2218      * Error Operation Tests
2219      * ============================================================
2220      */
2221 
2222     /* Null Publish Test */
2223     @Test
ErrorOp_UC1()2224     public void ErrorOp_UC1() {
2225         skipIfNetworkUnavailable();
2226         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2227         boolean didExceptionOccur = false;
2228         try {
2229             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2230             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2231             builder.withLifecycleEvents(events);
2232 
2233             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2234                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2235             TlsContext tlsContext = new TlsContext(tlsOptions);
2236             tlsOptions.close();
2237             builder.withTlsContext(tlsContext);
2238 
2239             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2240                 client.start();
2241                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2242 
2243                 try {
2244                     client.publish(null).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2245                 } catch (Exception ex) {
2246                     didExceptionOccur = true;
2247                 }
2248 
2249                 if (didExceptionOccur == false) {
2250                     fail("Null publish packet did not cause exception with error!");
2251                 }
2252                 client.stop(new DisconnectPacketBuilder().build());
2253             }
2254 
2255             if (tlsContext != null) {
2256                 tlsContext.close();
2257             }
2258 
2259         } catch (Exception ex) {
2260             fail(ex.getMessage());
2261         }
2262     }
2263 
2264     /* Publish with empty builder test */
2265     @Test
ErrorOp_UC1_ALT()2266     public void ErrorOp_UC1_ALT() {
2267         skipIfNetworkUnavailable();
2268         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2269         boolean didExceptionOccur = false;
2270         try {
2271             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2272             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2273             builder.withLifecycleEvents(events);
2274 
2275             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2276                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2277             TlsContext tlsContext = new TlsContext(tlsOptions);
2278             tlsOptions.close();
2279             builder.withTlsContext(tlsContext);
2280 
2281             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2282                 client.start();
2283                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2284 
2285                 try {
2286                     client.publish(new PublishPacketBuilder().build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2287                 } catch (Exception ex) {
2288                     didExceptionOccur = true;
2289                 }
2290 
2291                 if (didExceptionOccur == false) {
2292                     fail("Empty publish packet did not cause exception with error!");
2293                 }
2294                 client.stop(new DisconnectPacketBuilder().build());
2295             }
2296 
2297             if (tlsContext != null) {
2298                 tlsContext.close();
2299             }
2300 
2301         } catch (Exception ex) {
2302             fail(ex.getMessage());
2303         }
2304     }
2305 
2306     /* Null Subscribe Test */
2307     @Test
ErrorOp_UC2()2308     public void ErrorOp_UC2() {
2309         skipIfNetworkUnavailable();
2310         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2311         boolean didExceptionOccur = false;
2312         try {
2313             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2314             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2315             builder.withLifecycleEvents(events);
2316 
2317             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2318                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2319             TlsContext tlsContext = new TlsContext(tlsOptions);
2320             tlsOptions.close();
2321             builder.withTlsContext(tlsContext);
2322 
2323             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2324                 client.start();
2325                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2326 
2327                 try {
2328                     client.subscribe(null).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2329                 } catch (Exception ex) {
2330                     didExceptionOccur = true;
2331                 }
2332 
2333                 if (didExceptionOccur == false) {
2334                     fail("Null subscribe packet did not cause exception with error!");
2335                 }
2336                 client.stop();
2337             }
2338 
2339             if (tlsContext != null) {
2340                 tlsContext.close();
2341             }
2342 
2343         } catch (Exception ex) {
2344             fail(ex.getMessage());
2345         }
2346     }
2347 
2348     /* Empty Subscribe Test */
2349     @Test
ErrorOp_UC2_ALT()2350     public void ErrorOp_UC2_ALT() {
2351         skipIfNetworkUnavailable();
2352         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2353         boolean didExceptionOccur = false;
2354         try {
2355             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2356             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2357             builder.withLifecycleEvents(events);
2358 
2359             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2360                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2361             TlsContext tlsContext = new TlsContext(tlsOptions);
2362             tlsOptions.close();
2363             builder.withTlsContext(tlsContext);
2364 
2365             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2366                 client.start();
2367                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2368 
2369                 try {
2370                     client.subscribe(new SubscribePacketBuilder().build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2371                 } catch (Exception ex) {
2372                     didExceptionOccur = true;
2373                 }
2374 
2375                 if (didExceptionOccur == false) {
2376                     fail("Empty subscribe packet did not cause exception with error!");
2377                 }
2378                 client.stop();
2379             }
2380 
2381             if (tlsContext != null) {
2382                 tlsContext.close();
2383             }
2384 
2385         } catch (Exception ex) {
2386             fail(ex.getMessage());
2387         }
2388     }
2389 
2390     /* Null Unsubscribe Test */
2391     @Test
ErrorOp_UC3()2392     public void ErrorOp_UC3() {
2393         skipIfNetworkUnavailable();
2394         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2395         boolean didExceptionOccur = false;
2396         try {
2397             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2398             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2399             builder.withLifecycleEvents(events);
2400 
2401             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2402                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2403             TlsContext tlsContext = new TlsContext(tlsOptions);
2404             tlsOptions.close();
2405             builder.withTlsContext(tlsContext);
2406 
2407             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2408                 client.start();
2409                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2410 
2411                 try {
2412                     client.unsubscribe(null).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2413                 } catch (Exception ex) {
2414                     didExceptionOccur = true;
2415                 }
2416 
2417                 if (didExceptionOccur == false) {
2418                     fail("Null unsubscribe packet did not cause exception with error!");
2419                 }
2420                 client.stop();
2421             }
2422 
2423             if (tlsContext != null) {
2424                 tlsContext.close();
2425             }
2426 
2427         } catch (Exception ex) {
2428             fail(ex.getMessage());
2429         }
2430     }
2431 
2432     /* Empty Unsubscribe Test */
2433     @Test
ErrorOp_UC3_ALT()2434     public void ErrorOp_UC3_ALT() {
2435         skipIfNetworkUnavailable();
2436         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2437         boolean didExceptionOccur = false;
2438         try {
2439             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2440             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2441             builder.withLifecycleEvents(events);
2442 
2443             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2444                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2445             TlsContext tlsContext = new TlsContext(tlsOptions);
2446             tlsOptions.close();
2447             builder.withTlsContext(tlsContext);
2448 
2449             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2450                 client.start();
2451                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2452 
2453                 try {
2454                     client.unsubscribe(new UnsubscribePacketBuilder().build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2455                 } catch (Exception ex) {
2456                     didExceptionOccur = true;
2457                 }
2458 
2459                 if (didExceptionOccur == false) {
2460                     fail("Empty unsubscribe packet did not cause exception with error!");
2461                 }
2462                 client.stop();
2463             }
2464 
2465             if (tlsContext != null) {
2466                 tlsContext.close();
2467             }
2468 
2469         } catch (Exception ex) {
2470             fail(ex.getMessage());
2471         }
2472     }
2473 
2474     /* Unsupported Connect packet data sent (IoT Core only) */
2475     @Test
ErrorOp_UC4()2476     public void ErrorOp_UC4() {
2477         skipIfNetworkUnavailable();
2478         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2479         boolean didExceptionOccur = false;
2480         try {
2481             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2482             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2483             builder.withLifecycleEvents(events);
2484 
2485             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2486                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2487             TlsContext tlsContext = new TlsContext(tlsOptions);
2488             tlsOptions.close();
2489             builder.withTlsContext(tlsContext);
2490 
2491             ConnectPacketBuilder connectOptions = new ConnectPacketBuilder();
2492             String clientIDString = "";
2493             for (int i = 0; i < 256; i++) {
2494                 clientIDString += "a";
2495             }
2496             connectOptions.withClientId(clientIDString);
2497             builder.withConnectOptions(connectOptions.build());
2498 
2499             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2500                 try {
2501                     client.start();
2502                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2503                 } catch (Exception ex) {
2504                     didExceptionOccur = true;
2505                 }
2506 
2507                 if (didExceptionOccur == false) {
2508                     fail("Was able to connect with Client ID longer than 128 characters (AWS_IOT_CORE_MAXIMUM_CLIENT_ID_LENGTH)");
2509                 }
2510                 client.stop();
2511             }
2512 
2513             if (tlsContext != null) {
2514                 tlsContext.close();
2515             }
2516 
2517         } catch (Exception ex) {
2518             fail(ex.getMessage());
2519         }
2520     }
2521 
2522     /**
2523      * ============================================================
2524      * QoS1 Tests
2525      * ============================================================
2526      */
2527 
2528     /* Happy path. No drop in connection, no retry, no reconnect */
2529     @Test
QoS1_UC1()2530     public void QoS1_UC1() {
2531         skipIfNetworkUnavailable();
2532         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2533         int messageCount = 10;
2534         String testUUID = UUID.randomUUID().toString();
2535         String testTopic = "test/MQTT5_Binding_Java_" + testUUID;
2536         try {
2537             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2538             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2539             builder.withLifecycleEvents(events);
2540 
2541             Mqtt5ClientOptionsBuilder builderTwo = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2542             LifecycleEvents_Futured eventsTwo = new LifecycleEvents_Futured();
2543             builderTwo.withLifecycleEvents(eventsTwo);
2544             PublishEvents_Futured_Counted publishEvents = new PublishEvents_Futured_Counted();
2545             publishEvents.desiredPublishCount = messageCount;
2546             builderTwo.withPublishEvents(publishEvents);
2547 
2548             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2549                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2550             TlsContext tlsContext = new TlsContext(tlsOptions);
2551             tlsOptions.close();
2552             builder.withTlsContext(tlsContext);
2553             builderTwo.withTlsContext(tlsContext);
2554 
2555             try (
2556                 Mqtt5Client publisher = new Mqtt5Client(builder.build());
2557                 Mqtt5Client subscriber = new Mqtt5Client(builderTwo.build());
2558             ) {
2559                 publisher.start();
2560                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2561                 subscriber.start();
2562                 eventsTwo.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2563 
2564                 SubscribePacketBuilder subscribePacketBuilder = new SubscribePacketBuilder();
2565                 subscribePacketBuilder.withSubscription(testTopic, QOS.AT_LEAST_ONCE);
2566                 subscriber.subscribe(subscribePacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2567 
2568                 PublishPacketBuilder publishPacketBuilder = new PublishPacketBuilder();
2569                 publishPacketBuilder.withTopic(testTopic);
2570                 publishPacketBuilder.withPayload("Hello World".getBytes());
2571                 publishPacketBuilder.withQOS(QOS.AT_LEAST_ONCE);
2572 
2573                 for (int i = 0; i < messageCount; i++) {
2574                     publisher.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2575                 }
2576 
2577                 // Did we get all the messages?
2578                 publishEvents.publishReceivedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2579 
2580                 subscriber.stop();
2581                 publisher.stop();
2582             }
2583 
2584             if (tlsContext != null) {
2585                 tlsContext.close();
2586             }
2587 
2588         } catch (Exception ex) {
2589             fail(ex.getMessage());
2590         }
2591     }
2592 
2593     /**
2594      * ============================================================
2595      * Retain Tests
2596      * ============================================================
2597      */
2598 
2599     /* Happy path. No drop in connection, no retry, no reconnect */
2600     @Test
Retain_UC1()2601     public void Retain_UC1() {
2602         skipIfNetworkUnavailable();
2603         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2604         String testUUID = UUID.randomUUID().toString();
2605         String testTopic = "test/retained_topic/MQTT5_Binding_Java_" + testUUID;
2606         try {
2607             Mqtt5ClientOptionsBuilder publisherEventsBuilder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2608             LifecycleEvents_Futured publisherEvents = new LifecycleEvents_Futured();
2609             publisherEventsBuilder.withLifecycleEvents(publisherEvents);
2610 
2611             Mqtt5ClientOptionsBuilder successSubscriberBuilder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2612             LifecycleEvents_Futured successSubscriberEvents = new LifecycleEvents_Futured();
2613             PublishEvents_Futured successSubscriberPublishEvents = new PublishEvents_Futured();
2614             successSubscriberBuilder.withLifecycleEvents(successSubscriberEvents);
2615             successSubscriberBuilder.withPublishEvents(successSubscriberPublishEvents);
2616 
2617             Mqtt5ClientOptionsBuilder unsuccessSubscriberBuilder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2618             LifecycleEvents_Futured unsuccessfulSubscriberEvents = new LifecycleEvents_Futured();
2619             PublishEvents_Futured unsuccessfulSubscriberPublishEvents = new PublishEvents_Futured();
2620             unsuccessSubscriberBuilder.withLifecycleEvents(unsuccessfulSubscriberEvents);
2621             unsuccessSubscriberBuilder.withPublishEvents(unsuccessfulSubscriberPublishEvents);
2622 
2623             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2624                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2625             TlsContext tlsContext = new TlsContext(tlsOptions);
2626             tlsOptions.close();
2627             publisherEventsBuilder.withTlsContext(tlsContext);
2628             successSubscriberBuilder.withTlsContext(tlsContext);
2629             unsuccessSubscriberBuilder.withTlsContext(tlsContext);
2630 
2631             try (
2632                 Mqtt5Client publisher = new Mqtt5Client(publisherEventsBuilder.build());
2633                 Mqtt5Client successSubscriber = new Mqtt5Client(successSubscriberBuilder.build());
2634                 Mqtt5Client unsuccessfulSubscriber = new Mqtt5Client(unsuccessSubscriberBuilder.build());
2635             ) {
2636                 // Connect and publish a retained message
2637                 publisher.start();
2638                 publisherEvents.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2639                 PublishPacketBuilder publishPacketBuilder = new PublishPacketBuilder();
2640                 publishPacketBuilder.withTopic(testTopic)
2641                     .withPayload("Hello World".getBytes())
2642                     .withQOS(QOS.AT_LEAST_ONCE)
2643                     .withRetain(true);
2644                 publisher.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2645 
2646                 // Setup for clearing the retained message
2647                 publishPacketBuilder.withPayload(null);
2648 
2649                 // Connect the successful subscriber
2650                 successSubscriber.start();
2651                 try {
2652                     successSubscriberEvents.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2653                 } catch (Exception ex) {
2654                     // Clear the retained message
2655                     publisher.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2656                     fail("Success subscriber could not connect!");
2657                 }
2658 
2659                 // Subscribe and verify the retained message
2660                 SubscribePacketBuilder subscribePacketBuilder = new SubscribePacketBuilder();
2661                 subscribePacketBuilder.withSubscription(testTopic, QOS.AT_LEAST_ONCE, false, true, RetainHandlingType.SEND_ON_SUBSCRIBE);
2662                 try {
2663                     successSubscriber.subscribe(subscribePacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2664                 } catch (Exception ex) {
2665                     // Clear the retained message
2666                     publisher.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2667                     fail("Success subscriber could not subscribe!");
2668                 }
2669                 try {
2670                     successSubscriberPublishEvents.publishReceivedFuture.get(360, TimeUnit.SECONDS);
2671                 } catch (Exception ex) {
2672                     // Clear the retained message
2673                     publisher.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2674                     fail("Success subscriber did not get retained message!");
2675                 }
2676 
2677                 // Clear the retained message
2678                 publisher.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2679 
2680                 // Wait 15 seconds to give the server time to clear everything out
2681                 Thread.sleep(15000);
2682 
2683                 // Connect the unsuccessful subscriber
2684                 unsuccessfulSubscriber.start();
2685                 unsuccessfulSubscriberEvents.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2686                 unsuccessfulSubscriber.subscribe(subscribePacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2687                 // Make sure we do NOT get a publish
2688                 boolean didExceptionOccur = false;
2689                 try {
2690                     unsuccessfulSubscriberPublishEvents.publishReceivedFuture.get(30, TimeUnit.SECONDS);
2691                 } catch (Exception ex) {
2692                     didExceptionOccur = true;
2693                 }
2694 
2695                 if (didExceptionOccur == false) {
2696                     fail("Unsuccessful subscriber got retained message even though it should be cleared!");
2697                 }
2698 
2699                 // Disconnect all clients
2700                 publisher.stop();
2701                 publisherEvents.stopFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2702                 successSubscriber.stop();
2703                 successSubscriberEvents.stopFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2704                 unsuccessfulSubscriber.stop();
2705                 unsuccessfulSubscriberEvents.stopFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2706             }
2707 
2708             if (tlsContext != null) {
2709                 tlsContext.close();
2710             }
2711 
2712         } catch (Exception ex) {
2713             fail(ex.getMessage());
2714         }
2715     }
2716 
2717     /**
2718      * ============================================================
2719      * Operation Interrupt Tests
2720      * ============================================================
2721      */
2722 
2723     // Subscribe interrupt test
2724     @Test
Interrupt_Sub_UC1()2725     public void Interrupt_Sub_UC1() {
2726         skipIfNetworkUnavailable();
2727         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2728         String testUUID = UUID.randomUUID().toString();
2729         String testTopic = "test/MQTT5_Binding_Java_" + testUUID;
2730         try {
2731             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2732             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2733             builder.withLifecycleEvents(events);
2734 
2735             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2736                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2737             TlsContext tlsContext = new TlsContext(tlsOptions);
2738             tlsOptions.close();
2739             builder.withTlsContext(tlsContext);
2740 
2741             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2742                 client.start();
2743                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2744 
2745                 SubscribePacketBuilder subscribePacketBuilder = new SubscribePacketBuilder();
2746                 subscribePacketBuilder.withSubscription(testTopic, QOS.AT_LEAST_ONCE);
2747 
2748                 try {
2749                     CompletableFuture<SubAckPacket> subscribeResult = client.subscribe(subscribePacketBuilder.build());
2750                     client.stop();
2751                     SubAckPacket packet = subscribeResult.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2752                 } catch (Exception ex) {
2753                     if (ex.getCause().getClass() == CrtRuntimeException.class) {
2754                         CrtRuntimeException exCrt = (CrtRuntimeException)ex.getCause();
2755                         if (exCrt.errorCode != 5153) {
2756                             System.out.println("Exception ocurred when stopping subscribe" +
2757                                 "but it was not AWS_ERROR_MQTT5_USER_REQUESTED_STOP like expected");
2758                         }
2759                     }
2760                 }
2761             }
2762 
2763             if (tlsContext != null) {
2764                 tlsContext.close();
2765             }
2766 
2767         } catch (Exception ex) {
2768             fail(ex.getMessage());
2769         }
2770     }
2771 
2772     // Unsubscribe interrupt test
2773     @Test
Interrupt_Unsub_UC1()2774     public void Interrupt_Unsub_UC1() {
2775         skipIfNetworkUnavailable();
2776         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2777         String testUUID = UUID.randomUUID().toString();
2778         String testTopic = "test/MQTT5_Binding_Java_" + testUUID;
2779         try {
2780             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2781             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2782             builder.withLifecycleEvents(events);
2783 
2784             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2785                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2786             TlsContext tlsContext = new TlsContext(tlsOptions);
2787             tlsOptions.close();
2788             builder.withTlsContext(tlsContext);
2789 
2790             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2791                 client.start();
2792                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2793 
2794                 UnsubscribePacketBuilder unsubscribePacketBuilder = new UnsubscribePacketBuilder();
2795                 unsubscribePacketBuilder.withSubscription(testTopic);
2796 
2797                 try {
2798                     CompletableFuture<UnsubAckPacket> unsubscribeResult = client.unsubscribe(unsubscribePacketBuilder.build());
2799                     client.stop();
2800                     UnsubAckPacket packet = unsubscribeResult.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2801                 } catch (Exception ex) {
2802                     if (ex.getCause().getClass() == CrtRuntimeException.class) {
2803                         CrtRuntimeException exCrt = (CrtRuntimeException)ex.getCause();
2804                         if (exCrt.errorCode != 5153) {
2805                             System.out.println("Exception ocurred when stopping unsubscribe" +
2806                                 "but it was not AWS_ERROR_MQTT5_USER_REQUESTED_STOP like expected");
2807                         }
2808                     }
2809                 }
2810             }
2811 
2812             if (tlsContext != null) {
2813                 tlsContext.close();
2814             }
2815 
2816         } catch (Exception ex) {
2817             fail(ex.getMessage());
2818         }
2819     }
2820 
2821     // Publish interrupt test
2822     @Test
Interrupt_Publish_UC1()2823     public void Interrupt_Publish_UC1() {
2824         skipIfNetworkUnavailable();
2825         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2826         String testUUID = UUID.randomUUID().toString();
2827         String testTopic = "test/MQTT5_Binding_Java_" + testUUID;
2828         try {
2829             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2830             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2831             builder.withLifecycleEvents(events);
2832 
2833             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2834                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2835             TlsContext tlsContext = new TlsContext(tlsOptions);
2836             tlsOptions.close();
2837             builder.withTlsContext(tlsContext);
2838 
2839             try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2840                 client.start();
2841                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2842 
2843                 PublishPacketBuilder publishPacketBuilder = new PublishPacketBuilder();
2844                 publishPacketBuilder.withTopic(testTopic).withQOS(QOS.AT_LEAST_ONCE).withPayload("null".getBytes());
2845 
2846                 try {
2847                     CompletableFuture<PublishResult> publishResult = client.publish(publishPacketBuilder.build());
2848                     client.stop();
2849                     PublishResult publishData = publishResult.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2850                 } catch (Exception ex) {
2851                     if (ex.getCause().getClass() == CrtRuntimeException.class) {
2852                         CrtRuntimeException exCrt = (CrtRuntimeException)ex.getCause();
2853                         if (exCrt.errorCode != 5153) {
2854                             System.out.println("Exception ocurred when stopping publish" +
2855                                 "but it was not AWS_ERROR_MQTT5_USER_REQUESTED_STOP like expected");
2856                         }
2857                     }
2858                 }
2859             }
2860 
2861             if (tlsContext != null) {
2862                 tlsContext.close();
2863             }
2864 
2865         } catch (Exception ex) {
2866             fail(ex.getMessage());
2867         }
2868     }
2869 
2870     /**
2871      * ============================================================
2872      * Misc Tests
2873      * ============================================================
2874      */
2875 
2876     /* Happy path. Check statistics before, make some publishes, check it after */
2877     @Test
OperationStatistics_UC1()2878     public void OperationStatistics_UC1() {
2879         skipIfNetworkUnavailable();
2880         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2881         int messageCount = 10;
2882         String testUUID = UUID.randomUUID().toString();
2883         String testTopic = "test/MQTT5_Binding_Java_" + testUUID;
2884         try {
2885             Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2886             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2887             builder.withLifecycleEvents(events);
2888 
2889             TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsFromPath(
2890                 AWS_TEST_MQTT5_IOT_CORE_RSA_CERT, AWS_TEST_MQTT5_IOT_CORE_RSA_KEY);
2891             TlsContext tlsContext = new TlsContext(tlsOptions);
2892             tlsOptions.close();
2893             builder.withTlsContext(tlsContext);
2894 
2895             try (
2896                 Mqtt5Client publisher = new Mqtt5Client(builder.build());
2897             ) {
2898                 publisher.start();
2899                 events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2900 
2901                 Mqtt5ClientOperationStatistics statistics = publisher.getOperationStatistics();
2902                 // Make sure it is empty
2903                 if (statistics.getIncompleteOperationCount() != 0) {
2904                     fail("Incomplete operation count was not zero!");
2905                 }
2906                 if (statistics.getIncompleteOperationSize() != 0) {
2907                     fail("Incomplete operation size was not zero!");
2908                 }
2909                 if (statistics.getUnackedOperationCount() != 0) {
2910                     fail("Unacked operation count was not zero!");
2911                 }
2912                 if (statistics.getUnackedOperationSize() != 0) {
2913                     fail("Unacked operation size was not zero!");
2914                 }
2915 
2916                 PublishPacketBuilder publishPacketBuilder = new PublishPacketBuilder();
2917                 publishPacketBuilder.withTopic(testTopic);
2918                 publishPacketBuilder.withPayload("Hello World".getBytes());
2919                 publishPacketBuilder.withQOS(QOS.AT_LEAST_ONCE);
2920 
2921                 for (int i = 0; i < messageCount; i++) {
2922                     publisher.publish(publishPacketBuilder.build()).get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2923                 }
2924 
2925                 // Make sure it is empty
2926                 if (statistics.getIncompleteOperationCount() != 0) {
2927                     fail("Incomplete operation count was not zero!");
2928                 }
2929                 if (statistics.getIncompleteOperationSize() != 0) {
2930                     fail("Incomplete operation size was not zero!");
2931                 }
2932                 if (statistics.getUnackedOperationCount() != 0) {
2933                     fail("Unacked operation count was not zero!");
2934                 }
2935                 if (statistics.getUnackedOperationSize() != 0) {
2936                     fail("Unacked operation size was not zero!");
2937                 }
2938 
2939                 publisher.stop();
2940                 events.stopFuture.get(60, TimeUnit.SECONDS);
2941             }
2942 
2943             if (tlsContext != null) {
2944                 tlsContext.close();
2945             }
2946 
2947         } catch (Exception ex) {
2948             fail(ex.getMessage());
2949         }
2950     }
2951 
2952     /**
2953      * ============================================================
2954      * MQTT5 DIRECT IoT Core CONNECTION TEST CASES
2955      * ============================================================
2956      */
2957 
2958     /* MQTT5 ConnDC_Cred_UC1 - MQTT5 connect with Java Keystore */
2959     @Test
ConnDC_Cred_UC1()2960     public void ConnDC_Cred_UC1() {
2961         skipIfNetworkUnavailable();
2962         Assume.assumeNotNull(
2963             AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_KEYSTORE_FORMAT,
2964             AWS_TEST_MQTT5_IOT_CORE_KEYSTORE_FILE, AWS_TEST_MQTT5_IOT_CORE_KEYSTORE_PASSWORD,
2965             AWS_TEST_MQTT5_IOT_CORE_KEYSTORE_CERT_ALIAS, AWS_TEST_MQTT5_IOT_CORE_KEYSTORE_CERT_PASSWORD);
2966         try {
2967             java.security.KeyStore keyStore = java.security.KeyStore.getInstance(AWS_TEST_MQTT5_IOT_CORE_KEYSTORE_FORMAT);
2968             java.io.FileInputStream keyStoreStream = new java.io.FileInputStream(AWS_TEST_MQTT5_IOT_CORE_KEYSTORE_FILE);
2969             keyStore.load(keyStoreStream, AWS_TEST_MQTT5_IOT_CORE_KEYSTORE_PASSWORD.toCharArray());
2970             keyStoreStream.close();
2971 
2972             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
2973 
2974             try (
2975                 TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsJavaKeystore(
2976                     keyStore,
2977                     AWS_TEST_MQTT5_IOT_CORE_KEYSTORE_CERT_ALIAS,
2978                     AWS_TEST_MQTT5_IOT_CORE_KEYSTORE_CERT_PASSWORD);
2979                 TlsContext tlsContext = new TlsContext(tlsOptions);
2980             ) {
2981                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
2982                 builder.withLifecycleEvents(events);
2983                 builder.withTlsContext(tlsContext);
2984 
2985                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
2986                     client.start();
2987                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
2988                     client.stop();
2989                 }
2990             }
2991         } catch (Exception ex) {
2992             fail(ex.getMessage());
2993         }
2994     }
2995 
2996     /* MQTT5 ConnDC_Cred_UC2 - MQTT5 connect with PKCS12 Key */
2997     @Test
ConnDC_Cred_UC2()2998     public void ConnDC_Cred_UC2() {
2999         skipIfNetworkUnavailable();
3000         Assume.assumeNotNull(
3001             AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_PKCS12_KEY,
3002             AWS_TEST_MQTT5_IOT_CORE_PKCS12_KEY_PASSWORD);
3003         try {
3004             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
3005             try (
3006                 TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsPkcs12(
3007                     AWS_TEST_MQTT5_IOT_CORE_PKCS12_KEY,
3008                     AWS_TEST_MQTT5_IOT_CORE_PKCS12_KEY_PASSWORD);
3009                 TlsContext tlsContext = new TlsContext(tlsOptions);
3010             ) {
3011                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
3012                 builder.withLifecycleEvents(events);
3013                 builder.withTlsContext(tlsContext);
3014 
3015                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
3016                     client.start();
3017                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
3018                     client.stop();
3019                 }
3020             }
3021         } catch (Exception ex) {
3022             fail(ex.getMessage());
3023         }
3024     }
3025 
3026     /* MQTT5 ConnDC_Cred_UC3 - MQTT5 connect with Windows Cert Store */
3027     @Test
ConnDC_Cred_UC3()3028     public void ConnDC_Cred_UC3() {
3029         skipIfNetworkUnavailable();
3030         Assume.assumeNotNull(
3031             AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_WINDOWS_PFX_CERT_NO_PASS,
3032             AWS_TEST_MQTT5_IOT_CORE_WINDOWS_CERT_STORE);
3033         try {
3034             LifecycleEvents_Futured events = new LifecycleEvents_Futured();
3035             try (
3036                 TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsWindowsCertStorePath(
3037                     AWS_TEST_MQTT5_IOT_CORE_WINDOWS_CERT_STORE);
3038                 TlsContext tlsContext = new TlsContext(tlsOptions);
3039             ) {
3040                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
3041                 builder.withLifecycleEvents(events);
3042                 builder.withTlsContext(tlsContext);
3043 
3044                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
3045                     client.start();
3046                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
3047                     client.stop();
3048                 }
3049             }
3050         } catch (Exception ex) {
3051             fail(ex.getMessage());
3052         }
3053     }
3054 
3055     /* MQTT5 ConnDC_Cred_UC4 - MQTT5 connect with PKCS11 */
3056     @Test
ConnDC_Cred_UC4()3057     public void ConnDC_Cred_UC4() {
3058         skipIfNetworkUnavailable();
3059         Assume.assumeNotNull(
3060             AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_PKCS11_LIB,
3061             AWS_TEST_MQTT5_IOT_CORE_PKCS11_TOKEN_LABEL, AWS_TEST_MQTT5_IOT_CORE_PKCS11_PIN,
3062             AWS_TEST_MQTT5_IOT_CORE_PKCS11_PKEY_LABEL, AWS_TEST_MQTT5_IOT_CORE_PKCS11_CERT_FILE);
3063         // The published Softhsm package on muslc (Alpine) crashes if we don't call C_Finalize at the end.
3064         try (
3065             Pkcs11Lib pkcs11Lib = new Pkcs11Lib(AWS_TEST_MQTT5_IOT_CORE_PKCS11_LIB, Pkcs11Lib.InitializeFinalizeBehavior.STRICT);
3066             TlsContextPkcs11Options pkcs11Options = new TlsContextPkcs11Options(pkcs11Lib);) {
3067                 pkcs11Options.withTokenLabel(AWS_TEST_MQTT5_IOT_CORE_PKCS11_TOKEN_LABEL);
3068                 pkcs11Options.withUserPin(AWS_TEST_MQTT5_IOT_CORE_PKCS11_PIN);
3069                 pkcs11Options.withPrivateKeyObjectLabel(AWS_TEST_MQTT5_IOT_CORE_PKCS11_PKEY_LABEL);
3070                 pkcs11Options.withCertificateFilePath(AWS_TEST_MQTT5_IOT_CORE_PKCS11_CERT_FILE);
3071 
3072                 LifecycleEvents_Futured events = new LifecycleEvents_Futured();
3073                 try (
3074                     TlsContextOptions tlsOptions = TlsContextOptions.createWithMtlsPkcs11(pkcs11Options);
3075                     TlsContext tlsContext = new TlsContext(tlsOptions);
3076                 ) {
3077                     Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 8883l);
3078                     builder.withLifecycleEvents(events);
3079                     builder.withTlsContext(tlsContext);
3080 
3081                     try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
3082                         client.start();
3083                         events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
3084                         client.stop();
3085                     }
3086                 }
3087         } catch (Exception ex) {
3088             fail(ex.getMessage());
3089         }
3090     }
3091 
3092     /**
3093      * ============================================================
3094      * MQTT5 WEBSOCKET IoT Core CONNECTION TEST CASES
3095      * ============================================================
3096      */
3097 
3098     /* MQTT5 ConnWS_Cred_UC1 - static credentials connect */
3099     @Test
ConnWS_Cred_UC1()3100     public void ConnWS_Cred_UC1() {
3101         skipIfNetworkUnavailable();
3102         Assume.assumeNotNull(
3103             AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_REGION,
3104             AWS_TEST_MQTT5_ROLE_CREDENTIAL_ACCESS_KEY, AWS_TEST_MQTT5_ROLE_CREDENTIAL_SECRET_ACCESS_KEY,
3105             AWS_TEST_MQTT5_ROLE_CREDENTIAL_SESSION_TOKEN);
3106         CredentialsProvider provider = null;
3107         AwsSigningConfig signingConfig = new AwsSigningConfig();
3108         Mqtt5ClientTestSigv4HandshakeTransformer transformer = null;
3109 
3110         try {
3111             try (
3112                 EventLoopGroup elg = new EventLoopGroup(1);
3113                 HostResolver hr = new HostResolver(elg);
3114                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
3115                 TlsContextOptions tlsOptions = TlsContextOptions.createDefaultClient();
3116                 TlsContext tlsContext = new TlsContext(tlsOptions);
3117             ) {
3118                 LifecycleEvents_Futured events = new LifecycleEvents_Futured();
3119 
3120                 StaticCredentialsProviderBuilder credentialsBuilder = new StaticCredentialsProviderBuilder();
3121                 credentialsBuilder.withAccessKeyId(AWS_TEST_MQTT5_ROLE_CREDENTIAL_ACCESS_KEY.getBytes());
3122                 credentialsBuilder.withSecretAccessKey(AWS_TEST_MQTT5_ROLE_CREDENTIAL_SECRET_ACCESS_KEY.getBytes());
3123                 credentialsBuilder.withSessionToken(AWS_TEST_MQTT5_ROLE_CREDENTIAL_SESSION_TOKEN.getBytes());
3124 
3125                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 443L);
3126                 builder.withLifecycleEvents(events);
3127                 builder.withBootstrap(bootstrap);
3128                 builder.withTlsContext(tlsContext);
3129 
3130                 provider = credentialsBuilder.build();
3131                 signingConfig.setCredentialsProvider(provider);
3132                 signingConfig.setAlgorithm(AwsSigningAlgorithm.SIGV4);
3133                 signingConfig.setSignatureType(AwsSigningConfig.AwsSignatureType.HTTP_REQUEST_VIA_QUERY_PARAMS);
3134                 signingConfig.setRegion(AWS_TEST_MQTT5_IOT_CORE_REGION);
3135                 signingConfig.setService("iotdevicegateway");
3136                 signingConfig.setOmitSessionToken(true);
3137                 transformer = new Mqtt5ClientTestSigv4HandshakeTransformer(signingConfig);
3138 
3139                 builder.withWebsocketHandshakeTransform(transformer);
3140                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
3141                     client.start();
3142                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
3143                     client.stop();
3144                 }
3145             }
3146         } catch (Exception ex) {
3147             ex.printStackTrace();
3148             fail(ex.getMessage());
3149         } finally {
3150             if (provider != null) {
3151                 provider.close();
3152             }
3153             if (signingConfig != null) {
3154                 signingConfig.close();
3155             }
3156             if (transformer != null) {
3157                 transformer.close();
3158             }
3159         }
3160     }
3161 
3162     /* MQTT5 ConnWS_Cred_UC2 - default credentials connect */
3163     @Test
ConnWS_Cred_UC2()3164     public void ConnWS_Cred_UC2() {
3165         skipIfAndroid(); // Credential Provider support not yet added for Android
3166         skipIfNetworkUnavailable();
3167         Assume.assumeNotNull(AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_REGION);
3168         CredentialsProvider provider = null;
3169         AwsSigningConfig signingConfig = new AwsSigningConfig();
3170         Mqtt5ClientTestSigv4HandshakeTransformer transformer = null;
3171 
3172         try {
3173             try (
3174                 EventLoopGroup elg = new EventLoopGroup(1);
3175                 HostResolver hr = new HostResolver(elg);
3176                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
3177                 TlsContextOptions tlsOptions = TlsContextOptions.createDefaultClient();
3178                 TlsContext tlsContext = new TlsContext(tlsOptions);
3179             ) {
3180                 LifecycleEvents_Futured events = new LifecycleEvents_Futured();
3181 
3182                 DefaultChainCredentialsProviderBuilder credentialsBuilder = new DefaultChainCredentialsProviderBuilder();
3183                 credentialsBuilder.withClientBootstrap(bootstrap);
3184 
3185                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 443l);
3186                 builder.withLifecycleEvents(events);
3187                 builder.withBootstrap(bootstrap);
3188                 builder.withTlsContext(tlsContext);
3189 
3190                 provider = credentialsBuilder.build();
3191                 signingConfig.setCredentialsProvider(provider);
3192                 signingConfig.setAlgorithm(AwsSigningAlgorithm.SIGV4);
3193                 signingConfig.setSignatureType(AwsSigningConfig.AwsSignatureType.HTTP_REQUEST_VIA_QUERY_PARAMS);
3194                 signingConfig.setRegion(AWS_TEST_MQTT5_IOT_CORE_REGION);
3195                 signingConfig.setService("iotdevicegateway");
3196                 signingConfig.setOmitSessionToken(true);
3197                 transformer = new Mqtt5ClientTestSigv4HandshakeTransformer(signingConfig);
3198 
3199                 builder.withWebsocketHandshakeTransform(transformer);
3200                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
3201                     client.start();
3202                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
3203                     client.stop();
3204                 }
3205             }
3206         } catch (Exception ex) {
3207             fail(ex.getMessage());
3208         } finally {
3209             if (provider != null) {
3210                 provider.close();
3211             }
3212             if (signingConfig != null) {
3213                 signingConfig.close();
3214             }
3215             if (transformer != null) {
3216                 transformer.close();
3217             }
3218         }
3219     }
3220 
3221     /**
3222      * MQTT5 ConnWS_Cred_UC3 - Cognito Identity credentials connect
3223      */
3224     @Test
ConnWS_Cred_UC3()3225     public void ConnWS_Cred_UC3() {
3226         skipIfNetworkUnavailable();
3227         Assume.assumeNotNull(
3228             AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_REGION,
3229             AWS_TEST_MQTT5_COGNITO_ENDPOINT, AWS_TEST_MQTT5_COGNITO_IDENTITY);
3230         CredentialsProvider provider = null;
3231         AwsSigningConfig signingConfig = new AwsSigningConfig();
3232         Mqtt5ClientTestSigv4HandshakeTransformer transformer = null;
3233 
3234         try {
3235             try (
3236                 EventLoopGroup elg = new EventLoopGroup(1);
3237                 HostResolver hr = new HostResolver(elg);
3238                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
3239                 TlsContextOptions cognitoContextOptions = TlsContextOptions.createDefaultClient();
3240                 TlsContext cognitoContext = new TlsContext(cognitoContextOptions);
3241                 TlsContextOptions tlsOptions = TlsContextOptions.createDefaultClient();
3242                 TlsContext tlsContext = new TlsContext(tlsOptions);
3243             ) {
3244                 LifecycleEvents_Futured events = new LifecycleEvents_Futured();
3245 
3246                 CognitoCredentialsProviderBuilder credentialsBuilder = new CognitoCredentialsProviderBuilder();
3247                 credentialsBuilder.withClientBootstrap(bootstrap);
3248                 credentialsBuilder.withTlsContext(cognitoContext);
3249                 credentialsBuilder.withEndpoint(AWS_TEST_MQTT5_COGNITO_ENDPOINT);
3250                 credentialsBuilder.withIdentity(AWS_TEST_MQTT5_COGNITO_IDENTITY);
3251 
3252                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 443l);
3253                 builder.withLifecycleEvents(events);
3254                 builder.withBootstrap(bootstrap);
3255                 builder.withTlsContext(tlsContext);
3256 
3257                 provider = credentialsBuilder.build();
3258                 signingConfig.setCredentialsProvider(provider);
3259                 signingConfig.setAlgorithm(AwsSigningAlgorithm.SIGV4);
3260                 signingConfig.setSignatureType(AwsSigningConfig.AwsSignatureType.HTTP_REQUEST_VIA_QUERY_PARAMS);
3261                 signingConfig.setRegion(AWS_TEST_MQTT5_IOT_CORE_REGION);
3262                 signingConfig.setService("iotdevicegateway");
3263                 signingConfig.setOmitSessionToken(true);
3264                 transformer = new Mqtt5ClientTestSigv4HandshakeTransformer(signingConfig);
3265 
3266                 builder.withWebsocketHandshakeTransform(transformer);
3267                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
3268                     client.start();
3269                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
3270                     client.stop();
3271                 }
3272             }
3273         } catch (Exception ex) {
3274             fail(ex.getMessage());
3275         } finally {
3276             if (provider != null) {
3277                 provider.close();
3278             }
3279             if (signingConfig != null) {
3280                 signingConfig.close();
3281             }
3282             if (transformer != null) {
3283                 transformer.close();
3284             }
3285         }
3286     }
3287 
3288     /* MQTT5 ConnWS_Cred_UC4 - X509 credentials connect */
3289     @Test
ConnWS_Cred_UC4()3290     public void ConnWS_Cred_UC4() {
3291         skipIfNetworkUnavailable();
3292         Assume.assumeNotNull(
3293             AWS_TEST_MQTT5_IOT_CORE_HOST, AWS_TEST_MQTT5_IOT_CORE_REGION,
3294             AWS_TEST_MQTT5_IOT_CORE_X509_CERT, AWS_TEST_MQTT5_IOT_CORE_X509_KEY,
3295             AWS_TEST_MQTT5_IOT_CORE_X509_ENDPOINT, AWS_TEST_MQTT5_IOT_CORE_X509_ROLE_ALIAS,
3296             AWS_TEST_MQTT5_IOT_CORE_X509_THING_NAME);
3297         CredentialsProvider provider = null;
3298         AwsSigningConfig signingConfig = new AwsSigningConfig();
3299         Mqtt5ClientTestSigv4HandshakeTransformer transformer = null;
3300         try {
3301             try (
3302                 EventLoopGroup elg = new EventLoopGroup(1);
3303                 HostResolver hr = new HostResolver(elg);
3304                 ClientBootstrap bootstrap = new ClientBootstrap(elg, hr);
3305                 TlsContextOptions x509ContextOptions = TlsContextOptions.createWithMtlsFromPath(
3306                     AWS_TEST_MQTT5_IOT_CORE_X509_CERT, AWS_TEST_MQTT5_IOT_CORE_X509_KEY);
3307                 TlsContext x509Context = new TlsContext(x509ContextOptions);
3308                 TlsContextOptions tlsOptions = TlsContextOptions.createDefaultClient();
3309                 TlsContext tlsContext = new TlsContext(tlsOptions);
3310             ) {
3311                 LifecycleEvents_Futured events = new LifecycleEvents_Futured();
3312 
3313                 X509CredentialsProviderBuilder credentialsBuilder = new X509CredentialsProviderBuilder();
3314                 credentialsBuilder.withClientBootstrap(bootstrap);
3315                 credentialsBuilder.withTlsContext(x509Context);
3316                 credentialsBuilder.withEndpoint(AWS_TEST_MQTT5_IOT_CORE_X509_ENDPOINT);
3317                 credentialsBuilder.withRoleAlias(AWS_TEST_MQTT5_IOT_CORE_X509_ROLE_ALIAS);
3318                 credentialsBuilder.withThingName(AWS_TEST_MQTT5_IOT_CORE_X509_THING_NAME);
3319 
3320                 Mqtt5ClientOptionsBuilder builder = new Mqtt5ClientOptionsBuilder(AWS_TEST_MQTT5_IOT_CORE_HOST, 443l);
3321                 builder.withLifecycleEvents(events);
3322                 builder.withBootstrap(bootstrap);
3323                 builder.withTlsContext(tlsContext);
3324 
3325                 provider = credentialsBuilder.build();
3326                 signingConfig.setCredentialsProvider(provider);
3327                 signingConfig.setAlgorithm(AwsSigningAlgorithm.SIGV4);
3328                 signingConfig.setSignatureType(AwsSigningConfig.AwsSignatureType.HTTP_REQUEST_VIA_QUERY_PARAMS);
3329                 signingConfig.setRegion(AWS_TEST_MQTT5_IOT_CORE_REGION);
3330                 signingConfig.setService("iotdevicegateway");
3331                 signingConfig.setOmitSessionToken(true);
3332                 transformer = new Mqtt5ClientTestSigv4HandshakeTransformer(signingConfig);
3333 
3334                 builder.withWebsocketHandshakeTransform(transformer);
3335                 try (Mqtt5Client client = new Mqtt5Client(builder.build())) {
3336                     client.start();
3337                     events.connectedFuture.get(OPERATION_TIMEOUT_TIME, TimeUnit.SECONDS);
3338                     client.stop();
3339                 }
3340             }
3341         } catch (Exception ex) {
3342             fail(ex.getMessage());
3343         } finally {
3344             if (provider != null) {
3345                 provider.close();
3346             }
3347             if (signingConfig != null) {
3348                 signingConfig.close();
3349             }
3350             if (transformer != null) {
3351                 transformer.close();
3352             }
3353         }
3354     }
3355 }
3356