From 96554ae01d8c5b21dd7f703584ffc6dcbdf75852 Mon Sep 17 00:00:00 2001 From: Jacob Jo <47648260+johubertj@users.noreply.github.com> Date: Mon, 24 Feb 2025 11:28:13 -0800 Subject: [PATCH] test(integv2): fixes to allow test_record_padding to partially run (#5099) Co-authored-by: James Mayclin --- .../spec/buildspec_ubuntu_integrationv2.yml | 2 +- tests/integrationv2/processes.py | 44 +++++++++++++------ tests/integrationv2/test_record_padding.py | 5 ++- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/codebuild/spec/buildspec_ubuntu_integrationv2.yml b/codebuild/spec/buildspec_ubuntu_integrationv2.yml index 881e9439758..8b4870f1f38 100644 --- a/codebuild/spec/buildspec_ubuntu_integrationv2.yml +++ b/codebuild/spec/buildspec_ubuntu_integrationv2.yml @@ -42,7 +42,7 @@ batch: - "test_early_data test_hello_retry_requests test_sni_match test_pq_handshake test_fragmentation test_key_update" - "test_session_resumption test_renegotiate_apache test_buffered_send" - "test_npn test_signature_algorithms" - - "test_version_negotiation test_external_psk test_ocsp test_renegotiate test_serialization" + - "test_version_negotiation test_external_psk test_ocsp test_renegotiate test_serialization test_record_padding" env: variables: diff --git a/tests/integrationv2/processes.py b/tests/integrationv2/processes.py index 76dd7a00326..f8162ef060e 100644 --- a/tests/integrationv2/processes.py +++ b/tests/integrationv2/processes.py @@ -90,6 +90,16 @@ def communicate(self, input_data=None, send_marker_list=None, close_marker=None, return (stdout, stderr) + # Helper function to print out debugging statements + def get_fd_name(self, proc, fileobj): + if fileobj == proc.stdout: + return "stdout" + elif fileobj == proc.stderr: + return "stderr" + elif fileobj == proc.stdin: + return "stdin" + return "unknown fd" + def _communicate(self, input_data=None, send_marker_list=None, close_marker=None, kill_marker=None, send_with_newline=False, timeout=None): """ @@ -158,7 +168,7 @@ def _communicate(self, input_data=None, send_marker_list=None, close_marker=None self._check_timeout(endtime, orig_timeout, stdout, stderr) # (Key, events) tuple represents a single I/O operation - for key, events in ready: + for key, num_events in ready: # STDIN is only registered to receive events after the send_marker is found. if key.fileobj is self.proc.stdin: print(f'{self.name}: stdin available') @@ -168,21 +178,27 @@ def _communicate(self, input_data=None, send_marker_list=None, close_marker=None input_data_offset += os.write(key.fd, chunk) print(f'{self.name}: sent') except BrokenPipeError: - selector.unregister(key.fileobj) + print(f"{self.name}: Unregistering (stdin) BrokenPipeError") + selector.unregister(self.proc.stdin) else: if input_data_offset >= input_data_len: - selector.unregister(key.fileobj) + print(f"{self.name}: Unregistering (stdin) Input_data_offset >= input_data_len") + selector.unregister(self.proc.stdin) input_data_sent = True input_data_offset = 0 if send_marker_list: send_marker = send_marker_list.pop(0) print(f'{self.name}: next send_marker is {send_marker}') elif key.fileobj in (self.proc.stdout, self.proc.stderr): - print(f'{self.name}: stdout available') + fd_name = self.get_fd_name(self.proc, key.fileobj) + print(f'{self.name}: {fd_name} available') + # 32 KB (32 × 1024 = 32,768 bytes), read 32KB from the file descriptor data = os.read(key.fd, 32768) if not data: selector.unregister(key.fileobj) + print(f"{self.name}: Unregistering: {fd_name} No Data") + data_str = str(data) # Prepends n - 1 bytes of previously-seen stdout to the chunk we'll be searching @@ -228,6 +244,7 @@ def _communicate(self, input_data=None, send_marker_list=None, close_marker=None if self.wait_for_marker: print(f'{self.name}: looking for wait_for_marker {self.wait_for_marker} in {data_debug}') if self.wait_for_marker is not None and self.wait_for_marker in data_str: + print(f"{self.name}: Unregistering (stdout + stderr), found wait_for_marker") selector.unregister(self.proc.stdout) selector.unregister(self.proc.stderr) return None, None @@ -235,20 +252,19 @@ def _communicate(self, input_data=None, send_marker_list=None, close_marker=None if kill_marker: print(f'{self.name}: looking for kill_marker {kill_marker} in {data}') if kill_marker is not None and kill_marker in data: + print(f"{self.name}: Unregistering (stdout + stderr), found kill_marker") selector.unregister(self.proc.stdout) selector.unregister(self.proc.stderr) self.proc.kill() - # If we have finished sending all our input, and have received the - # ready-to-send marker, we can close out stdin. - if self.proc.stdin and input_data_sent and not input_data: - print(f'{self.name}: finished sending') - if close_marker: - print(f'{self.name}: looking for close_marker {close_marker} in {data_debug}') - if close_marker is None or (close_marker and close_marker in data_str): - print(f'{self.name}: closing stdin') - input_data_sent = None - self.proc.stdin.close() + if self.proc.stdin and input_data_sent and not input_data: + print(f'{self.name}: finished sending') + if close_marker: + print(f'{self.name}: looking for close_marker {close_marker} in {data_debug}') + if close_marker is None or (close_marker and close_marker in data_str): + print(f'{self.name} Found close marker: closing stdin') + input_data_sent = None + self.proc.stdin.close() self.proc.wait(timeout=self._remaining_time(endtime)) diff --git a/tests/integrationv2/test_record_padding.py b/tests/integrationv2/test_record_padding.py index 05e4162137a..5b4546027e6 100644 --- a/tests/integrationv2/test_record_padding.py +++ b/tests/integrationv2/test_record_padding.py @@ -166,10 +166,13 @@ def test_s2n_client_handles_padded_records(managed_process, cipher, provider, cu # s2nc will wait until it has received the server's response before closing s2nc = managed_process(S2N, client_options, timeout=5, - close_marker=strip_string_of_bytes(str(server_random_bytes))) + close_marker=strip_string_of_bytes(str(server_random_bytes)), expect_stderr=True) expected_version = get_expected_s2n_version(protocol, provider) for client_results in s2nc.get_results(): + # Aware of I/O issues causing this testcase to sometimes fail with a non zero exit status + # https://github.com/aws/s2n-tls/issues/5130 + client_results.expect_nonzero_exit = True client_results.assert_success() # assert that the client has received server's application payload assert server_random_bytes in client_results.stdout