xref: /aosp_15_r20/external/pigweed/pw_transfer/integration_test/cross_language_medium_read_test.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1#!/usr/bin/env python3
2# Copyright 2022 The Pigweed Authors
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may not
5# use this file except in compliance with the License. You may obtain a copy of
6# the License at
7#
8#     https://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations under
14# the License.
15"""Cross-language pw_transfer tests that take several seconds each.
16
17Usage:
18
19   bazel run pw_transfer/integration_test:cross_language_medium_read_test
20
21Command-line arguments must be provided after a double-dash:
22
23   bazel run pw_transfer/integration_test:cross_language_medium_read_test -- \
24       --server-port 3304
25
26Which tests to run can be specified as command-line arguments:
27
28  bazel run pw_transfer/integration_test:cross_language_medium_read_test -- \
29      MediumTransferReadIntegrationTest.test_medium_client_read_1_java
30
31"""
32
33import itertools
34from parameterized import parameterized
35import random
36
37from google.protobuf import text_format
38
39from pw_transfer.integration_test import config_pb2
40from pw_transfer.integration_test import test_fixture
41from test_fixture import TransferIntegrationTestHarness, TransferConfig
42
43_ALL_LANGUAGES = ("cpp", "java", "python")
44_ALL_VERSIONS = (
45    config_pb2.TransferAction.ProtocolVersion.V1,
46    config_pb2.TransferAction.ProtocolVersion.V2,
47)
48_ALL_LANGUAGES_AND_VERSIONS = tuple(
49    itertools.product(_ALL_LANGUAGES, _ALL_VERSIONS)
50)
51
52_ALL_LANGUAGES_V2 = tuple(
53    itertools.product(
54        _ALL_LANGUAGES, [config_pb2.TransferAction.ProtocolVersion.V2]
55    )
56)
57
58
59class MediumTransferReadIntegrationTest(test_fixture.TransferIntegrationTest):
60    # Each set of transfer tests uses a different client/server port pair to
61    # allow tests to be run in parallel.
62    HARNESS_CONFIG = TransferIntegrationTestHarness.Config(
63        server_port=3304, client_port=3305
64    )
65
66    @parameterized.expand(_ALL_LANGUAGES_AND_VERSIONS)
67    def test_medium_client_read(self, client_type, protocol_version):
68        payload = random.Random(67336391945).randbytes(512)
69        config = self.default_config()
70        resource_id = 5
71        self.do_single_read(
72            client_type, config, resource_id, payload, protocol_version
73        )
74
75    @parameterized.expand(_ALL_LANGUAGES_AND_VERSIONS)
76    def test_large_hdlc_escape_client_read(self, client_type, protocol_version):
77        # Use bytes that will be escaped by HDLC to ensure transfer over a
78        # HDLC channel doesn't cause frame corruption due to insufficient
79        # buffer space. ~10KB is relatively arbitrary, but is to ensure that
80        # more than a small handful of packets are sent between the server
81        # and client.
82        payload = b"~" * 98731
83        config = self.default_config()
84        resource_id = 5
85        self.do_single_read(
86            client_type, config, resource_id, payload, protocol_version
87        )
88
89    @parameterized.expand(_ALL_LANGUAGES_AND_VERSIONS)
90    def test_pattern_drop_client_read(self, client_type, protocol_version):
91        """Drops packets with an alternating pattern."""
92        payload = random.Random(67336391945).randbytes(1234)
93        config = TransferConfig(
94            self.default_server_config(),
95            self.default_client_config(),
96            text_format.Parse(
97                """
98                client_filter_stack: [
99                    { hdlc_packetizer: {} },
100                    {
101                        keep_drop_queue: {
102                            keep_drop_queue: [5, 1],
103                            only_consider_transfer_chunks: true,
104                        }
105                    }
106                ]
107
108                server_filter_stack: [
109                    { hdlc_packetizer: {} },
110                    {
111                        keep_drop_queue: {
112                            keep_drop_queue: [5, 1],
113                            only_consider_transfer_chunks: true,
114                        }
115                    }
116            ]""",
117                config_pb2.ProxyConfig(),
118            ),
119        )
120        # Resource ID is arbitrary, but deliberately set to be >1 byte.
121        resource_id = 1337
122
123        # This test causes flakes during the opening handshake of a transfer, so
124        # allow the resource_id of this transfer to be reused multiple times.
125        self.do_single_read(
126            client_type,
127            config,
128            resource_id,
129            payload,
130            protocol_version,
131            permanent_resource_id=True,
132        )
133
134    @parameterized.expand(_ALL_LANGUAGES_AND_VERSIONS)
135    def test_parameter_drop_client_read(self, client_type, protocol_version):
136        """Drops the first few transfer initialization packets."""
137        payload = random.Random(67336391945).randbytes(1234)
138        config = TransferConfig(
139            self.default_server_config(),
140            self.default_client_config(),
141            text_format.Parse(
142                """
143                client_filter_stack: [
144                    { hdlc_packetizer: {} },
145                    {
146                        keep_drop_queue: {
147                            keep_drop_queue: [2, 1, -1],
148                            only_consider_transfer_chunks: true,
149                        }
150                    }
151                ]
152
153                server_filter_stack: [
154                    { hdlc_packetizer: {} },
155                    {
156                        keep_drop_queue: {
157                            keep_drop_queue: [1, 2, -1],
158                            only_consider_transfer_chunks: true,
159                        }
160                    }
161            ]""",
162                config_pb2.ProxyConfig(),
163            ),
164        )
165        # Resource ID is arbitrary, but deliberately set to be >2 bytes.
166        resource_id = 597419
167
168        # This test deliberately causes flakes during the opening handshake of
169        # a transfer, so allow the resource_id of this transfer to be reused
170        # multiple times.
171        self.do_single_read(
172            client_type,
173            config,
174            resource_id,
175            payload,
176            protocol_version,
177            permanent_resource_id=True,
178        )
179
180    @parameterized.expand(_ALL_LANGUAGES_V2)
181    def test_medium_client_read_offset(self, client_type, protocol_version):
182        payload = random.Random(67336391945).randbytes(512)
183        config = self.default_config()
184
185        resource_id = 6
186        self.do_single_read(
187            client_type,
188            config,
189            resource_id,
190            payload,
191            protocol_version,
192            initial_offset=100,
193            offsettable_resources=True,
194        )
195
196    @parameterized.expand(_ALL_LANGUAGES_V2)
197    def test_medium_client_read_offset_with_drops(
198        self, client_type, protocol_version
199    ):
200        payload = random.Random(67336391945).randbytes(1024)
201        config = TransferConfig(
202            self.default_server_config(),
203            self.default_client_config(),
204            text_format.Parse(
205                """
206                client_filter_stack: [
207                    { hdlc_packetizer: {} },
208                    {
209                        keep_drop_queue: {
210                            keep_drop_queue: [5, 1],
211                            only_consider_transfer_chunks: true,
212                        }
213                    }
214                ]
215
216                server_filter_stack: [
217                    { hdlc_packetizer: {} },
218                    {
219                        keep_drop_queue: {
220                            keep_drop_queue: [5, 1],
221                            only_consider_transfer_chunks: true,
222                        }
223                    }
224                ]""",
225                config_pb2.ProxyConfig(),
226            ),
227        )
228
229        resource_id = 7
230        self.do_single_read(
231            client_type,
232            config,
233            resource_id,
234            payload,
235            protocol_version,
236            initial_offset=100,
237            offsettable_resources=True,
238        )
239
240
241if __name__ == '__main__':
242    test_fixture.run_tests_for(MediumTransferReadIntegrationTest)
243