xref: /aosp_15_r20/external/pigweed/pw_transfer/integration_test/legacy_binaries_test.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2022 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""A variety of transfer tests that validate backwards compatibility.
15
16Usage:
17
18   bazel run pw_transfer/integration_test:legacy_binaries_test
19
20Command-line arguments must be provided after a double-dash:
21
22   bazel run pw_transfer/integration_test:legacy_binaries_test -- \
23       --server-port 3304
24
25Which tests to run can be specified as command-line arguments:
26
27  bazel run pw_transfer/integration_test:legacy_binaries_test -- \
28      LegacyClientTransferIntegrationTests.test_small_client_write_0_cpp
29
30"""
31
32from parameterized import parameterized
33import random
34
35from pw_transfer.integration_test import config_pb2
36from pw_transfer.integration_test import test_fixture
37from test_fixture import TransferIntegrationTestHarness
38from python.runfiles import runfiles
39
40# Each set of transfer tests uses a different client/server port pair to
41# allow tests to be run in parallel.
42_SERVER_PORT = 3314
43_CLIENT_PORT = 3315
44
45
46# NOTE: These backwards compatibility tests DO NOT include tests that verify
47# expected error cases (e.g. timeouts, unknown resource ID) because legacy
48# integration test clients did not support the ability to check those.
49# Additionally, there are deliberately NOT back-to-back read/write transfers
50# because of known issues with transfer cleanup in the legacy transfer protocol.
51class LegacyTransferIntegrationTest(test_fixture.TransferIntegrationTest):
52    """This base class defines the tests to run, but isn't run directly."""
53
54    # Explicitly use UNKNOWN_VERSION (the default value of
55    # TransferAction.protocol_version), as that will cause protocol_version to
56    # be omitted from the generated text proto, which is critical for the legacy
57    # client that doesn't support transfer version specifications (and will
58    # cause a proto parse error).
59    PROTOCOL_VERSION = config_pb2.TransferAction.ProtocolVersion.UNKNOWN_VERSION
60    LEGACY_SERVER = False
61    LEGACY_CLIENT = False
62
63    def default_config(self) -> test_fixture.TransferConfig:
64        # The legacy binaries aren't aware of the max_lifetime_retries field,
65        # which was added more recently. Clear it so it isn't encoded into the
66        # serialized message.
67        config = super().default_config()
68        config.client.max_lifetime_retries = 0
69        return config
70
71    @parameterized.expand(
72        [
73            ("cpp"),
74            ("java"),
75            ("python"),
76        ]
77    )
78    def test_single_byte_client_write(self, client_type):
79        if not (self.LEGACY_SERVER or self.LEGACY_CLIENT):
80            self.skipTest("No legacy binary in use, skipping")
81
82        if not self.LEGACY_SERVER and (
83            client_type == "java" or client_type == "python"
84        ):
85            self.skipTest("Java and Python legacy clients not yet set up")
86
87        payload = b"?"
88        config = self.default_config()
89        resource_id = 5
90        self.do_single_write(
91            "cpp", config, resource_id, payload, self.PROTOCOL_VERSION
92        )
93
94    @parameterized.expand(
95        [
96            ("cpp"),
97            ("java"),
98            ("python"),
99        ]
100    )
101    def test_small_client_write(self, client_type):
102        if not (self.LEGACY_SERVER or self.LEGACY_CLIENT):
103            self.skipTest("No legacy binary in use, skipping")
104
105        if not self.LEGACY_SERVER and (
106            client_type == "java" or client_type == "python"
107        ):
108            self.skipTest("Java and Python legacy clients not yet set up")
109
110        payload = b"some data"
111        config = self.default_config()
112        resource_id = 5
113        self.do_single_write(
114            "cpp", config, resource_id, payload, self.PROTOCOL_VERSION
115        )
116
117    @parameterized.expand(
118        [
119            ("cpp"),
120            ("java"),
121            ("python"),
122        ]
123    )
124    def test_medium_hdlc_escape_client_write(self, client_type):
125        if not (self.LEGACY_SERVER or self.LEGACY_CLIENT):
126            self.skipTest("No legacy binary in use, skipping")
127
128        if not self.LEGACY_SERVER and (
129            client_type == "java" or client_type == "python"
130        ):
131            self.skipTest("Java and Python legacy clients not yet set up")
132
133        payload = b"~" * 8731
134        config = self.default_config()
135        resource_id = 12345678
136        self.do_single_write(
137            "cpp", config, resource_id, payload, self.PROTOCOL_VERSION
138        )
139
140    @parameterized.expand(
141        [
142            ("cpp"),
143            ("java"),
144            ("python"),
145        ]
146    )
147    def test_medium_random_data_client_write(self, client_type):
148        if not (self.LEGACY_SERVER or self.LEGACY_CLIENT):
149            self.skipTest("No legacy binary in use, skipping")
150
151        if not self.LEGACY_SERVER and (
152            client_type == "java" or client_type == "python"
153        ):
154            self.skipTest("Java and Python legacy clients not yet set up")
155
156        rng = random.Random(1533659510898)
157        payload = rng.randbytes(13713)
158        config = self.default_config()
159        resource_id = 12345678
160        self.do_single_write(
161            "cpp", config, resource_id, payload, self.PROTOCOL_VERSION
162        )
163
164    @parameterized.expand(
165        [
166            ("cpp"),
167            ("java"),
168            ("python"),
169        ]
170    )
171    def test_single_byte_client_read(self, client_type):
172        if not (self.LEGACY_SERVER or self.LEGACY_CLIENT):
173            self.skipTest("No legacy binary in use, skipping")
174
175        if not self.LEGACY_SERVER and (
176            client_type == "java" or client_type == "python"
177        ):
178            self.skipTest("Java and Python legacy clients not yet set up")
179
180        payload = b"?"
181        config = self.default_config()
182        resource_id = 5
183        self.do_single_read(
184            "cpp", config, resource_id, payload, self.PROTOCOL_VERSION
185        )
186
187    @parameterized.expand(
188        [
189            ("cpp"),
190            ("java"),
191            ("python"),
192        ]
193    )
194    def test_small_client_read(self, client_type):
195        if not (self.LEGACY_SERVER or self.LEGACY_CLIENT):
196            self.skipTest("No legacy binary in use, skipping")
197
198        if not self.LEGACY_SERVER and (
199            client_type == "java" or client_type == "python"
200        ):
201            self.skipTest("Java and Python legacy clients not yet set up")
202
203        payload = b"some data"
204        config = self.default_config()
205        resource_id = 5
206        self.do_single_read(
207            "cpp", config, resource_id, payload, self.PROTOCOL_VERSION
208        )
209
210    @parameterized.expand(
211        [
212            ("cpp"),
213            ("java"),
214            ("python"),
215        ]
216    )
217    def test_medium_hdlc_escape_client_read(self, client_type):
218        if not (self.LEGACY_SERVER or self.LEGACY_CLIENT):
219            self.skipTest("No legacy binary in use, skipping")
220
221        if self.LEGACY_SERVER:
222            self.skipTest("Legacy server has HDLC buffer sizing issues")
223
224        payload = b"~" * 8731
225        config = self.default_config()
226        resource_id = 5
227        self.do_single_read(
228            "cpp", config, resource_id, payload, self.PROTOCOL_VERSION
229        )
230
231    @parameterized.expand(
232        [
233            ("cpp"),
234            ("java"),
235            ("python"),
236        ]
237    )
238    def test_medium_random_data_client_read(self, client_type):
239        if not (self.LEGACY_SERVER or self.LEGACY_CLIENT):
240            self.skipTest("No legacy binary in use, skipping")
241
242        if self.LEGACY_SERVER:
243            self.skipTest("Legacy server has HDLC buffer sizing issues")
244
245        rng = random.Random(1533659510898)
246        payload = rng.randbytes(13713)
247        config = self.default_config()
248        resource_id = 5
249        self.do_single_read(
250            "cpp", config, resource_id, payload, self.PROTOCOL_VERSION
251        )
252
253
254class LegacyClientTransferIntegrationTests(LegacyTransferIntegrationTest):
255    r = runfiles.Create()
256    client_binary = r.Rlocation(
257        "+_repo_rules+pw_transfer_test_binaries/cpp_client_528098d5",
258    )
259    HARNESS_CONFIG = TransferIntegrationTestHarness.Config(
260        cpp_client_binary=client_binary,
261        server_port=_SERVER_PORT,
262        client_port=_CLIENT_PORT,
263    )
264    LEGACY_CLIENT = True
265
266
267class LegacyServerTransferIntegrationTests(LegacyTransferIntegrationTest):
268    r = runfiles.Create()
269    server_binary = r.Rlocation(
270        "+_repo_rules+pw_transfer_test_binaries/server_528098d5",
271    )
272    HARNESS_CONFIG = TransferIntegrationTestHarness.Config(
273        server_binary=server_binary,
274        server_port=_SERVER_PORT,
275        client_port=_CLIENT_PORT,
276    )
277    LEGACY_SERVER = True
278
279
280if __name__ == '__main__':
281    test_fixture.run_tests_for(LegacyClientTransferIntegrationTests)
282    test_fixture.run_tests_for(LegacyServerTransferIntegrationTests)
283