def test_connect_disconnect_with_default_singletons(self): connection = self._create_connection(use_static_singletons=True) connection.connect().result(TIMEOUT) connection.disconnect().result(TIMEOUT) # free singletons ClientBootstrap.release_static_default() EventLoopGroup.release_static_default() DefaultHostResolver.release_static_default()
def test_closes_on_zero_refcount(self): self.skipTest("Skipping until we have permanent echo server") elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) handler = SimpleHandler() future = EventStreamRpcClientConnection.connect( handler=handler, host_name="127.0.0.1", port=8033, bootstrap=bootstrap) # connection should succeed self.assertIsNone(future.exception(TIMEOUT)) # grab pointers to stuff that will tell us about how shutdown went, record = handler.record shutdown_future = handler.connection.shutdown_future # connection should shut itself down when all references are released. # the shutdown_future should complete, but the handler's shutdown # callback should not fire in this test because the handler has been deleted. del handler self.assertIsNone(shutdown_future.exception(TIMEOUT)) self.assertIsNone( record.shutdown_call, "on_connection_shutdown shouldn't fire if handler is garbage collected before connection finishes shutdown") self.assertIsNone(record.failure)
def test_mtls_from_path(self): config = Config.get() elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) # test "from path" builder by writing secrets to tempfiles tmp_dirpath = tempfile.mkdtemp() try: cert_filepath = os.path.join(tmp_dirpath, 'cert') with open(cert_filepath, 'wb') as cert_file: cert_file.write(config.cert) key_filepath = os.path.join(tmp_dirpath, 'key') with open(key_filepath, 'wb') as key_file: key_file.write(config.key) connection = awsiot_mqtt_connection_builder.mtls_from_path( cert_filepath=cert_filepath, pri_key_filepath=key_filepath, endpoint=config.endpoint, client_id=create_client_id(), client_bootstrap=bootstrap) finally: shutil.rmtree(tmp_dirpath) self._test_connection(connection)
def _initialize_default_loop(self): event_loop_group = EventLoopGroup(1) host_resolver = DefaultHostResolver(event_loop_group) return ClientBootstrap( event_loop_group, host_resolver, )
def test_connect_success(self): elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) handler = ConnectionHandler(self._fail_test_from_callback) future = ClientConnection.connect(handler=handler, host_name="127.0.0.1", port=8033, bootstrap=bootstrap) self.assertIsNone(future.exception(TIMEOUT)) self.assertIsNotNone(handler.record.setup_call) self.assertTrue( isinstance(handler.record.setup_call['connection'], ClientConnection)) self.assertIsNone(handler.record.setup_call['error']) self.assertTrue(handler.connection.is_open()) self.assertIsNone(handler.record.shutdown_call) # close shutdown_future = handler.connection.close() self.assertIsNone(shutdown_future.exception(TIMEOUT)) self.assertIsNotNone(handler.record.shutdown_call) self.assertIsNone(handler.record.shutdown_call['reason']) self._assertNoFailuresFromCallbacks()
def _connect_fully(self): # connect, send CONNECT message, receive CONNECT_ACK elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) handler = ConnectionHandler(self._fail_test_from_callback) connect_future = ClientConnection.connect(handler=handler, host_name="127.0.0.1", port=8033, bootstrap=bootstrap) self.assertIsNone(connect_future.exception(TIMEOUT)) # send CONNECT msg msg_future = handler.connection.send_protocol_message( message_type=MessageType.CONNECT, headers=[ Header.from_string(':version', '0.1.0'), Header.from_string('client-name', 'accepted.testy_mc_testerson') ]) self.assertIsNone(msg_future.exception(TIMEOUT)) # wait to receive CONNECT_ACK msg = handler.record.message_calls.get(timeout=TIMEOUT) self.assertIs(MessageType.CONNECT_ACK, msg['message_type']) self.assertTrue(MessageFlag.CONNECTION_ACCEPTED & msg['flags']) return handler
def test_echo(self): self.skipTest("Skipping until we have permanent echo server") elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) handler = SimpleHandler() connect_future = EventStreamRpcClientConnection.connect( handler=handler, host_name="127.0.0.1", port=8033, bootstrap=bootstrap) self.assertIsNone(connect_future.exception(TIMEOUT)) # send CONNECT msg msg_future = handler.connection.send_protocol_message( message_type=EventStreamRpcMessageType.CONNECT, headers=[EventStreamHeader.from_string(':version', '0.1.0'), EventStreamHeader.from_string('client-name', 'accepted.testy_mc_testerson')]) self.assertIsNone(msg_future.exception(TIMEOUT)) # wait to receive CONNECT_ACK msg = handler.record.message_calls.get(timeout=TIMEOUT) self.assertIs(EventStreamRpcMessageType.CONNECT_ACK, msg['message_type']) self.assertTrue(EventStreamRpcMessageFlag.CONNECTION_ACCEPTED & msg['flags']) # send PING msg, server will echo back its headers and payload in the PING_RESPONSE. # test every single header type echo_headers = [ EventStreamHeader.from_bool('echo-true', True), EventStreamHeader.from_bool('echo-false', False), EventStreamHeader.from_byte('echo-byte', 127), EventStreamHeader.from_int16('echo-int16', 32000), EventStreamHeader.from_int32('echo-int32', 2000000000), EventStreamHeader.from_int64('echo-int64', 999999999999), EventStreamHeader.from_byte_buf('echo-byte-buf', b'\x00\xff\x0f\xf0'), EventStreamHeader.from_string('echo-string', 'noodles'), EventStreamHeader.from_timestamp('echo-timestamp', time.time()), EventStreamHeader.from_uuid('echo-uuid', UUID('01234567-89ab-cdef-0123-456789abcdef')), ] echo_payload = b'\x00\xDE\xAD\xBE\xEF' msg_future = handler.connection.send_protocol_message( message_type=EventStreamRpcMessageType.PING, headers=echo_headers, payload=echo_payload) self.assertIsNone(msg_future.exception(TIMEOUT)) # wait to receive PING_RESPONSE, which should echo what we sent msg = handler.record.message_calls.get(timeout=TIMEOUT) self.assertIs(EventStreamRpcMessageType.PING_RESPONSE, msg['message_type']) for sent_header in echo_headers: recv_header = next(x for x in msg['headers'] if x.name.lower() == sent_header.name.lower()) self.assertEqual(sent_header.type, recv_header.type) self.assertEqual(sent_header.value, recv_header.value) self.assertEqual(echo_payload, msg['payload']) self.assertIsNone(handler.record.failure)
def test_create_destroy(self): event_loop_group = EventLoopGroup() host_resolver = DefaultHostResolver(event_loop_group) bootstrap = ClientBootstrap(event_loop_group, host_resolver) # ensure shutdown_event fires bootstrap_shutdown_event = bootstrap.shutdown_event del bootstrap self.assertTrue(bootstrap_shutdown_event.wait(TIMEOUT))
def test_on_message_old_fn_signature(self): # ensure that message-received callbacks with the old function signature still work config = Config.get() elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) tls_opts = TlsContextOptions.create_client_with_mtls( config.cert, config.key) tls = ClientTlsContext(tls_opts) client = Client(bootstrap, tls) connection = Connection(client=client, client_id=create_client_id(), host_name=config.endpoint, port=8883) any_received = Future() sub_received = Future() # Note: Testing degenerate callback signature that failed to take # forward-compatibility **kwargs. def on_any_message(topic, payload): any_received.set_result({'topic': topic, 'payload': payload}) def on_sub_message(topic, payload): sub_received.set_result({'topic': topic, 'payload': payload}) # on_message for connection has to be set before connect, or possible race will happen connection.on_message(on_any_message) connection.connect().result(TIMEOUT) # subscribe without callback subscribed, packet_id = connection.subscribe(self.TEST_TOPIC, QoS.AT_LEAST_ONCE, on_sub_message) subscribed.result(TIMEOUT) # publish published, packet_id = connection.publish(self.TEST_TOPIC, self.TEST_MSG, QoS.AT_LEAST_ONCE) puback = published.result(TIMEOUT) # receive message rcv = any_received.result(TIMEOUT) self.assertEqual(self.TEST_TOPIC, rcv['topic']) self.assertEqual(self.TEST_MSG, rcv['payload']) rcv = sub_received.result(TIMEOUT) self.assertEqual(self.TEST_TOPIC, rcv['topic']) self.assertEqual(self.TEST_MSG, rcv['payload']) # disconnect connection.disconnect().result(TIMEOUT)
def test_mtls_from_bytes(self): config = Config.get() elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) connection = awsiot_mqtt_connection_builder.mtls_from_bytes( cert_bytes=config.cert, pri_key_bytes=config.key, endpoint=config.endpoint, client_id=create_client_id(), client_bootstrap=bootstrap) self._test_connection(connection)
def test_websockets_default(self): config = Config.get() elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) cred_provider = AwsCredentialsProvider.new_default_chain(bootstrap) connection = awsiot_mqtt_connection_builder.websockets_with_default_aws_signing( region=config.region, credentials_provider=cred_provider, endpoint=config.endpoint, client_id=create_client_id(), client_bootstrap=bootstrap) self._test_connection(connection)
def _establish_http_connection(self, test_type, uri, proxy_options): event_loop_group = EventLoopGroup() host_resolver = DefaultHostResolver(event_loop_group) bootstrap = ClientBootstrap(event_loop_group, host_resolver) connection_future = HttpClientConnection.new( host_name=uri, port=ProxyTestConfiguration.get_port_from_test_type(test_type), bootstrap=bootstrap, tls_connection_options=ProxyTestConfiguration. get_tls_connection_options_for_test(test_type, uri), proxy_options=proxy_options) return connection_future.result(TIMEOUT)
def _connect_and_return_weakref(self): elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) handler = ConnectionHandler(self._fail_test_from_callback) future = ClientConnection.connect(handler=handler, host_name="127.0.0.1", port=8033, bootstrap=bootstrap) # connection should succeed self.assertIsNone(future.exception(TIMEOUT)) return weakref.ref(handler.connection)
def test_websockets_proxy(self): config = Config.get() elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) cred_provider = AwsCredentialsProvider.new_default_chain(bootstrap) connection = mqtt_connection_builder.websockets_with_default_aws_signing( credentials_provider=cred_provider, websocket_proxy_options=HttpProxyOptions(PROXY_HOST, PROXY_PORT), endpoint=config.endpoint, region=config.region, client_id=create_client_id(), client_bootstrap=bootstrap) self._test_connection(connection)
def connect(*, ipc_socket: str = None, authtoken: str = None, lifecycle_handler: Optional[LifecycleHandler] = None, timeout=10.0) -> GreengrassCoreIPCClient: """ Creates an IPC client and connects to the GreengrassCoreIPC service. Args: ipc_socket: Path to the Unix domain socket of Greengrass Nucleus, defaults to environment variable AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT authtoken: Authentication token, defaults to environment variable SVCUID lifecycle_handler: Handler for events over the course of this network connection. See :class:`LifecycleHandler` for more info. Handler methods will only be invoked if the connect attempt succeeds. timeout: The number of seconds to wait for establishing the connection. Returns: Client for the GreengrassCoreIPC service. """ if not ipc_socket: ipc_socket = os.environ[ "AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT"] if not authtoken: authtoken = os.environ["SVCUID"] if not lifecycle_handler: lifecycle_handler = LifecycleHandler() elg = EventLoopGroup(num_threads=1) resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) socket_options = SocketOptions() socket_options.domain = SocketDomain.Local amender = MessageAmendment.create_static_authtoken_amender(authtoken) connection = Connection( host_name=ipc_socket, port=0, # dummy port number, not needed for Unix domain sockets bootstrap=bootstrap, socket_options=socket_options, connect_message_amender=amender, ) connect_future = connection.connect(lifecycle_handler) connect_future.result(timeout) return GreengrassCoreIPCClient(connection)
def test_connect_failure(self): elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) handler = SimpleHandler() future = EventStreamRpcClientConnection.connect( handler=handler, host_name="fake", port=99, bootstrap=bootstrap) failure = future.exception(TIMEOUT) self.assertTrue(isinstance(failure, Exception)) self.assertIsNone(handler.record.setup_call) self.assertIsNone(handler.record.shutdown_call) self.assertIsNone(handler.record.failure)
def _test_connection(self): config = Config.get() elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) tls_opts = TlsContextOptions.create_client_with_mtls( config.cert, config.key) tls = ClientTlsContext(tls_opts) client = Client(bootstrap, tls) connection = Connection(client=client, client_id=create_client_id(), host_name=config.endpoint, port=8883) connection.connect().result(TIMEOUT) return connection
def test_websockets_sts(self): """Websocket connection with X-Amz-Security-Token query param""" config = Config.get() elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) cred_provider = AwsCredentialsProvider.new_static( access_key_id=config.cognito_creds['AccessKeyId'], secret_access_key=config.cognito_creds['SecretKey'], session_token=config.cognito_creds['SessionToken']) connection = awsiot_mqtt_connection_builder.websockets_with_default_aws_signing( region=config.region, credentials_provider=cred_provider, endpoint=config.endpoint, client_id=create_client_id(), client_bootstrap=bootstrap) self._test_connection(connection)
def test_on_message(self): config = Config.get() elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) tls_opts = TlsContextOptions.create_client_with_mtls( config.cert, config.key) tls = ClientTlsContext(tls_opts) client = Client(bootstrap, tls) connection = Connection(client=client, client_id=create_client_id(), host_name=config.endpoint, port=8883) received = Future() def on_message(**kwargs): received.set_result(kwargs) # on_message for connection has to be set before connect, or possible race will happen connection.on_message(on_message) connection.connect().result(TIMEOUT) # subscribe without callback subscribed, packet_id = connection.subscribe(self.TEST_TOPIC, QoS.AT_LEAST_ONCE) subscribed.result(TIMEOUT) # publish published, packet_id = connection.publish(self.TEST_TOPIC, self.TEST_MSG, QoS.AT_LEAST_ONCE) puback = published.result(TIMEOUT) # receive message rcv = received.result(TIMEOUT) self.assertEqual(self.TEST_TOPIC, rcv['topic']) self.assertEqual(self.TEST_MSG, rcv['payload']) self.assertFalse(rcv['dup']) self.assertEqual(QoS.AT_LEAST_ONCE, rcv['qos']) self.assertFalse(rcv['retain']) # disconnect connection.disconnect().result(TIMEOUT)
def test_connect_failure(self): elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) handler = ConnectionHandler(self._fail_test_from_callback) future = ClientConnection.connect(handler=handler, host_name="fake", port=99, bootstrap=bootstrap) failure = future.exception(TIMEOUT) self.assertTrue(isinstance(failure, Exception)) self.assertIsNotNone(handler.record.setup_call) self.assertIsNone(handler.record.setup_call['connection']) self.assertTrue( isinstance(handler.record.setup_call['error'], Exception)) self.assertIsNone(handler.record.shutdown_call) self._assertNoFailuresFromCallbacks()
def _new_h2_client_connection(self, url): event_loop_group = EventLoopGroup() host_resolver = DefaultHostResolver(event_loop_group) bootstrap = ClientBootstrap(event_loop_group, host_resolver) port = 443 scheme = 'https' tls_ctx_options = TlsContextOptions() tls_ctx = ClientTlsContext(tls_ctx_options) tls_conn_opt = tls_ctx.new_connection_options() tls_conn_opt.set_server_name(url.hostname) tls_conn_opt.set_alpn_list(["h2"]) connection_future = HttpClientConnection.new(host_name=url.hostname, port=port, bootstrap=bootstrap, tls_connection_options=tls_conn_opt) return connection_future.result(self.timeout)
def s3_client_new(secure, region, part_size=0): event_loop_group = EventLoopGroup() host_resolver = DefaultHostResolver(event_loop_group) bootstrap = ClientBootstrap(event_loop_group, host_resolver) credential_provider = AwsCredentialsProvider.new_default_chain(bootstrap) tls_option = None if secure: opt = TlsContextOptions() ctx = ClientTlsContext(opt) tls_option = TlsConnectionOptions(ctx) s3_client = S3Client(bootstrap=bootstrap, region=region, credential_provider=credential_provider, tls_connection_options=tls_option, part_size=part_size) return s3_client
def _create_connection(self, auth_type=AuthType.CERT_AND_KEY, use_static_singletons=False): config = Config(auth_type) if auth_type == AuthType.CERT_AND_KEY: tls_opts = TlsContextOptions.create_client_with_mtls_from_path(config.cert_path, config.key_path) tls = ClientTlsContext(tls_opts) elif auth_type == AuthType.PKCS11: try: pkcs11_lib = Pkcs11Lib( file=config.pkcs11_lib_path, behavior=Pkcs11Lib.InitializeFinalizeBehavior.STRICT) tls_opts = TlsContextOptions.create_client_with_mtls_pkcs11( pkcs11_lib=pkcs11_lib, user_pin=config.pkcs11_pin, token_label=config.pkcs11_token_label, private_key_label=config.pkcs11_key_label, cert_file_path=config.cert_path) tls = ClientTlsContext(tls_opts) except Exception as e: if 'AWS_ERROR_UNIMPLEMENTED' in str(e): raise unittest.SkipTest(f'TLS with PKCS#11 not supported on this platform ({sys.platform})') else: # re-raise exception raise if use_static_singletons: client = Client(tls_ctx=tls) else: elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) client = Client(bootstrap, tls) connection = Connection( client=client, client_id=create_client_id(), host_name=config.endpoint, port=8883) return connection
def connect(self): elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) socket_options = SocketOptions() socket_options.domain = SocketDomain.Local amender = MessageAmendment.create_static_authtoken_amender(getenv("SVCUID")) hostname = getenv("AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT") connection = Connection( host_name=hostname, port=8033, bootstrap=bootstrap, socket_options=socket_options, connect_message_amender=amender, ) self.lifecycle_handler = LifecycleHandler() connect_future = connection.connect(self.lifecycle_handler) connect_future.result(config_utils.TIMEOUT) return connection
def _new_client_connection(self, secure, proxy_options=None): if secure: tls_ctx_opt = TlsContextOptions() tls_ctx_opt.override_default_trust_store_from_path(None, 'test/resources/ca.crt') tls_ctx = ClientTlsContext(tls_ctx_opt) tls_conn_opt = tls_ctx.new_connection_options() tls_conn_opt.set_server_name(self.hostname) else: tls_conn_opt = None event_loop_group = EventLoopGroup() host_resolver = DefaultHostResolver(event_loop_group) bootstrap = ClientBootstrap(event_loop_group, host_resolver) connection_future = HttpClientConnection.new(host_name=self.hostname, port=self.port, bootstrap=bootstrap, tls_connection_options=tls_conn_opt, proxy_options=proxy_options) return connection_future.result(self.timeout)
def _new_client_connection(self, secure, proxy_options=None): if secure: tls_ctx_opt = TlsContextOptions() tls_ctx_opt.verify_peer = False tls_ctx = ClientTlsContext(tls_ctx_opt) tls_conn_opt = tls_ctx.new_connection_options() tls_conn_opt.set_server_name(self.hostname) else: tls_conn_opt = None event_loop_group = EventLoopGroup() host_resolver = DefaultHostResolver(event_loop_group) bootstrap = ClientBootstrap(event_loop_group, host_resolver) connection_future = HttpClientConnection.new( host_name=self.hostname, port=self.port, bootstrap=bootstrap, tls_connection_options=tls_conn_opt, proxy_options=proxy_options) return connection_future.result(self.timeout)
def _establish_mqtt_connection(self, proxy_options): event_loop_group = EventLoopGroup() host_resolver = DefaultHostResolver(event_loop_group) bootstrap = ClientBootstrap(event_loop_group, host_resolver) tls_opts = TlsContextOptions.create_client_with_mtls_from_path( ProxyTestConfiguration.HTTP_PROXY_TLS_CERT_PATH, ProxyTestConfiguration.HTTP_PROXY_TLS_KEY_PATH) tls_opts.override_default_trust_store_from_path( ca_filepath=ProxyTestConfiguration.HTTP_PROXY_TLS_ROOT_CA_PATH) tls = ClientTlsContext(tls_opts) client = Client(bootstrap, tls) connection = Connection( client=client, client_id=create_client_id(), host_name=ProxyTestConfiguration.HTTP_PROXY_MQTT_ENDPOINT, port=8883, proxy_options=proxy_options) connection.connect().result(TIMEOUT) return connection
def test_setup_callback_exception_closes_connection(self): elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) handler = ConnectionHandler(self._fail_test_from_callback) # tell handler to explode during setup callback handler.raise_during_setup = True connect_future = ClientConnection.connect(handler=handler, host_name="127.0.0.1", port=8033, bootstrap=bootstrap) # the connect future does actually succeed, since the user's setup # callback got a chance to run. connect_future.exception(TIMEOUT) # but the unhandled exception should cause the connection to die shutdown_reason = handler.connection.shutdown_future.exception(TIMEOUT) self.assertTrue("CALLBACK_EXCEPTION" in shutdown_reason.name) self.assertTrue("CALLBACK_EXCEPTION" in handler.record.shutdown_call['reason'].name)
def test_connect_success(self): self.skipTest("Skipping until we have permanent echo server") elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) handler = SimpleHandler() future = EventStreamRpcClientConnection.connect( handler=handler, host_name="127.0.0.1", port=8033, bootstrap=bootstrap) self.assertIsNone(future.exception(TIMEOUT)) self.assertIsNotNone(handler.record.setup_call) self.assertTrue(handler.connection.is_open()) self.assertIsNone(handler.record.shutdown_call) # close shutdown_future = handler.connection.close() self.assertIsNone(shutdown_future.exception(TIMEOUT)) self.assertIsNotNone(handler.record.shutdown_call) self.assertIsNone(handler.record.shutdown_call['reason']) self.assertIsNone(handler.record.failure)
def test_init(self): event_loop_group = EventLoopGroup() host_resolver = DefaultHostResolver(event_loop_group)