• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

reactive-firewall-org / multicast / 16182645011

09 Jul 2025 11:45PM UTC coverage: 31.012% (-66.3%) from 97.352%
16182645011

push

github

reactive-firewall
[HOTFIX] Potential fix for GHI #455

Changes in file .github/actions/checkout-and-rebuild/action.yml:
 * attempt to convert windows python path

42 of 133 branches covered (31.58%)

Branch coverage included in aggregate %.

684 of 2208 relevant lines covered (30.98%)

1.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/tests/test_usage.py
1
#! /usr/bin/env python3
2
# -*- coding: utf-8 -*-
3

4
# Python Test Repo Template
5
# ..................................
6
# Copyright (c) 2017-2025, Mr. Walls
7
# ..................................
8
# Licensed under MIT (the "License");
9
# you may not use this file except in compliance with the License.
10
# You may obtain a copy of the License at
11
# ..........................................
12
# https://github.com/reactive-firewall/python-repo/blob/HEAD/LICENSE.md
13
# ..........................................
14
# Unless required by applicable law or agreed to in writing, software
15
# distributed under the License is distributed on an "AS IS" BASIS,
16
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
# See the License for the specific language governing permissions and
18
# limitations under the License.
19

20
"""
21
Tests of integration by usage.
22

23
        Caution: See details about Robust Imports documented in tests.context.
24

25
        Meta
26
        tests.test_usage.BasicIntegrationTestSuite
27

28
        Integration Tests - Fixtures:
29

30
                Test fixtures by importing test context.
31

32
                >>> import tests.test_usage as test_usage
33
                >>> import tests
34
                >>>
35

36
                >>> tests.test_usage.MulticastTestSuite #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
37
                <class...tests.test_usage.MulticastTestSuite...>
38
                >>>
39

40
                >>> tests.test_usage.BasicIntegrationTestSuite #doctest: -DONT_ACCEPT_BLANKLINE, +ELLIPSIS
41
                <class...tests.test_usage.BasicIntegrationTestSuite...>
42
                >>>
43

44
"""
45

46
__module__ = "tests"
×
47

48
try:
×
49
        try:
×
50
                import context
×
51
        except Exception as _root_cause:  # pragma: no branch
52
                del _root_cause  # skipcq - cleanup any error leaks early
53
                from . import context
54
        if not hasattr(context, '__name__') or not context.__name__:  # pragma: no branch
×
55
                raise ModuleNotFoundError("[CWE-758] Failed to import context") from None
56
        else:
57
                from collections import namedtuple
×
58
                from context import multicast  # pylint: disable=cyclic-import - skipcq: PYL-R0401
×
59
                from multicast import __main__  # pylint: disable=cyclic-import - skipcq: PYL-R0401
×
60
                from context import unittest
×
61
                import io
×
62
                from unittest.mock import patch
×
63
                from context import subprocess
×
64
                from context import Process
×
65
except Exception as _cause:
66
        raise ImportError("[CWE-758] Failed to import test context") from _cause
67

68

69
@context.markWithMetaTag("mat", "say", "hear")
×
70
class MulticastTestSuite(context.BasicUsageTestSuite):
×
71
        """
72
        A test suite for special Multicast usage scenarios.
73

74
        This test suite extends the BasicUsageTestSuite and focuses on testing various
75
        aspects of the multicast functionality, including error handling, command-line
76
        interface behavior, and basic send/receive operations.
77

78
        Methods:
79
        --------
80
        test_aborts_WHEN_calling_multicast_GIVEN_invalid_tools():
81
                Tests the behavior of the CLI tools when given invalid tool names.
82

83
        test_say_is_stable_WHEN_calling_multicast_GIVEN_say_tool():
84
                Verifies the stability of the 'SAY' command with various message arguments.
85

86
        test_recv_aborts_WHEN_calling_multicast_GIVEN_invalid_args():
87
                Checks if the 'RECV' command properly aborts when given invalid arguments.
88

89
        test_hear_aborts_WHEN_calling_multicast_GIVEN_invalid_args():
90
                Ensures the 'HEAR' command aborts correctly when provided with invalid arguments.
91

92
        test_hear_is_stable_WHEN_calling_multicast_GIVEN_invalid_tool():
93
                Tests the stability of the 'HEAR' command when given an invalid tool (--hex).
94

95
        test_noop_stable_WHEN_calling_multicast_GIVEN_noop_args():
96
                Verifies the stability of the 'NOOP' command.
97

98
        test_help_works_WHEN_calling_multicast_GIVEN_help_tool():
99
                Checks if the 'HELP' command functions correctly.
100

101
        test_hear_works_WHEN_say_works():
102
                Tests the basic send and receive functionality using 'SAY' and 'HEAR' commands.
103

104
        test_recv_Errors_WHEN_say_not_used():
105
                Verifies that 'RECV' command produces an error when 'SAY' is not used.
106

107
        Notes:
108
        ------
109
        - This test suite uses subprocess calls to test the multicast CLI interface.
110
        - Some tests involve multiprocessing to simulate concurrent operations.
111
        - Ensure proper network configuration for multicast tests to function correctly.
112

113
        Warnings:
114
        ---------
115
        - Some tests may require specific network conditions to pass successfully.
116
        - Failure in these tests may indicate issues with the multicast implementation
117
                or the testing environment rather than actual bugs in the code.
118
        """
119

120
        __module__ = "tests.test_usage"
×
121

122
        __name__ = "tests.test_usage.MulticastTestSuite"
×
123

124
        def test_aborts_WHEN_calling_multicast_GIVEN_invalid_tools(self):
×
125
                """Tests the impossible state for CLI tools given bad tools"""
126
                theResult = False
×
127
                fail_fixture = str("multicast.__main__.McastDispatch().useTool(JUNK) == error")
×
128
                tst_dispatch = multicast.__main__.McastDispatch()
×
129
                test_junk_values = ["", "NoSuchTool", None]
×
130
                try:
×
131
                        for tst_in in test_junk_values:
×
132
                                (test_code, test_fixture) = tst_dispatch.useTool(tst_in)
×
133
                                self.assertEqual(type(test_code), type(True))
×
134
                                self.assertIsNone(test_fixture)
×
135
                                self.assertTupleEqual(
×
136
                                        tst_dispatch.useTool(tst_in),
137
                                        (False, None),  # skipcq: PTC-W0020  - This is test-code.
138
                                        fail_fixture
139
                                )
140
                        theResult = True
×
141
                except Exception as _cause:
142
                        context.debugtestError(_cause)
143
                        self.fail(fail_fixture)
144
                        theResult = False
145
                self.assertTrue(theResult, fail_fixture)
×
146

147
        def test_say_is_stable_WHEN_calling_multicast_GIVEN_say_tool(self):
×
148
                """
149
                Tests the message argument for expected syntax given simple args.
150

151
                First check that the --message argument requires a message value, or exits(2) as per CEP-8.
152
                Second check that providing the message value "test" is sufficient to succeed with exit(0).
153

154
                Rational of these tests are simple enough, the mis-use of the SAY sub-command should result
155
                in an argument error value of 2, due to misuse of shell/CLI builtin as per CEP-8, while a
156
                value of 0 should indicate success.
157
                """
158
                theResult = False
×
159
                fail_fixture = str(
160
                        "multicast.__main__.McastDispatch().useTool(SAY, message) != valid exit(0..3)"
161
                )
162
                try:
×
163
                        with self.assertRaises(SystemExit) as rtn_val_a:
×
164
                                _ = multicast.__main__.McastDispatch().doStep(["SAY", "--message"])
×
165
                        (tst_err_rslt_b, rtn_val_b) = multicast.__main__.McastDispatch().doStep(
×
166
                                ["SAY", "--message", "test"]
167
                        )
168
                        tst_err_rslt_a = rtn_val_a.exception.code
×
169
                        self.assertIsNotNone(rtn_val_a)
×
170
                        self.assertIsNotNone(rtn_val_b)
×
171
                        self.assertIsNotNone(tst_err_rslt_a)
×
172
                        self.assertIsNotNone(tst_err_rslt_b)
×
173
                        self.assertNotEqual(int(tst_err_rslt_a), int(0), str(rtn_val_a))
×
174
                        self.assertNotEqual(int(tst_err_rslt_a), int(1), str(rtn_val_a))
×
175
                        self.assertNotEqual(int(tst_err_rslt_b), int(1), str(rtn_val_b))
×
176
                        self.assertNotEqual(int(tst_err_rslt_b), int(2), str(rtn_val_b))
×
177
                        self.assertNotEqual(rtn_val_a, rtn_val_b)
×
178
                        self.assertNotEqual(tst_err_rslt_a, tst_err_rslt_b)
×
179
                        self.assertNotEqual(int(tst_err_rslt_b), int(tst_err_rslt_a))
×
180
                        self.assertNotEqual(int(tst_err_rslt_a), int(tst_err_rslt_b))
×
181
                        self.assertNotEqual(int(tst_err_rslt_b), int(3))
×
182
                        self.assertNotEqual(int(tst_err_rslt_a), int(3))
×
183
                        self.assertEqual(int(tst_err_rslt_a), int(2), str(rtn_val_a))
×
184
                        self.assertEqual(int(tst_err_rslt_b), int(0), str(rtn_val_b))
×
185
                        theResult = (int(tst_err_rslt_b) < int(tst_err_rslt_a))
×
186
                except Exception as _cause:
187
                        context.debugtestError(_cause)
188
                        self.fail(fail_fixture)
189
                        theResult = False
190
                self.assertTrue(theResult, fail_fixture)
×
191

192
        def test_recv_aborts_WHEN_calling_multicast_GIVEN_invalid_args(self):
×
193
                """Tests the message argument for failure given invalid input"""
194
                theResult = False
×
195
                fail_fixture = str("multicast.__main__.McastDispatch().useTool(RECV, junk) != exit(1)")
196
                try:
×
197
                        with self.assertRaises(SystemExit) as rtn_val_c:
×
198
                                _ = multicast.__main__.McastDispatch().doStep(["RECV", "--port", "test"])
×
199
                        with self.assertRaises(SystemExit) as rtn_val_d:
×
200
                                _ = multicast.__main__.McastDispatch().doStep(
×
201
                                        ["RECV", "--port=test", "group=None"]
202
                                )
203
                        self.assertIsNotNone(rtn_val_c)
×
204
                        self.assertIsNotNone(rtn_val_d)
×
205
                        tst_err_rslt_c = rtn_val_c.exception.code
×
206
                        tst_err_rslt_d = rtn_val_d.exception.code
×
207
                        self.assertIsNotNone(tst_err_rslt_c)
×
208
                        self.assertIsNotNone(tst_err_rslt_d)
×
209
                        self.assertNotEqual(int(tst_err_rslt_c), int(0))
×
210
                        self.assertNotEqual(int(tst_err_rslt_c), int(1))
×
211
                        self.assertNotEqual(int(tst_err_rslt_d), int(1))
×
212
                        self.assertEqual(int(tst_err_rslt_c), int(2))
×
213
                        self.assertEqual(int(tst_err_rslt_d), int(2))
×
214
                        self.assertEqual(int(tst_err_rslt_d), int(tst_err_rslt_c))
×
215
                        self.assertEqual(int(tst_err_rslt_c), int(tst_err_rslt_d))
×
216
                        self.assertNotEqual(int(tst_err_rslt_d), int(3))
×
217
                        theResult = (int(tst_err_rslt_d) == int(tst_err_rslt_c))
×
218
                except Exception as _cause:
219
                        context.debugtestError(_cause)
220
                        self.fail(fail_fixture)
221
                        theResult = False
222
                self.assertTrue(theResult, fail_fixture)
×
223

224
        def test_hear_aborts_WHEN_calling_multicast_GIVEN_invalid_args(self):
×
225
                """Tests the message argument for failure given invalid input"""
226
                theResult = False
×
227
                fail_fixture = str("multicast.__main__.McastDispatch().useTool(HEAR, junk) != exit(2)")
228
                try:
×
229
                        with self.assertRaises(SystemExit) as rtn_val_e:
×
230
                                _ = __main__.main(["HEAR", "--port", "test"])
×
231
                        with self.assertRaises(SystemExit) as rtn_val_f:
×
232
                                _ = __main__.main(["RECV", "--port", "test"])
×
233
                        self.assertIsNotNone(rtn_val_e)
×
234
                        self.assertIsNotNone(rtn_val_f)
×
235
                        tst_err_rslt_e = rtn_val_e.exception.code
×
236
                        tst_err_rslt_f = rtn_val_f.exception.code
×
237
                        self.assertIsNotNone(tst_err_rslt_e)
×
238
                        self.assertIsNotNone(tst_err_rslt_f)
×
239
                        self.assertNotEqual(int(tst_err_rslt_e), int(0))
×
240
                        self.assertNotEqual(int(tst_err_rslt_f), int(0))
×
241
                        self.assertNotEqual(int(tst_err_rslt_e), int(1))
×
242
                        self.assertNotEqual(int(tst_err_rslt_f), int(1))
×
243
                        self.assertEqual(int(tst_err_rslt_e), int(2), "CEP-8 Violation. REGRESSION in HEAR")
×
244
                        self.assertEqual(int(tst_err_rslt_f), int(2), "CEP-8 Violation. REGRESSION in RECV")
×
245
                        self.assertNotEqual(rtn_val_e, rtn_val_f)
×
246
                        self.assertNotEqual(int(tst_err_rslt_e), int(3), "Regression. 3 != 64")
×
247
                        self.assertNotEqual(int(tst_err_rslt_f), int(3), "Regression. 3 != 64")
×
248
                        self.assertEqual(int(tst_err_rslt_f), int(tst_err_rslt_e))
×
249
                        theResult = (int(tst_err_rslt_f) == int(tst_err_rslt_e))
×
250
                except Exception as _cause:
251
                        context.debugtestError(_cause)
252
                        self.fail(fail_fixture)
253
                        theResult = False
254
                self.assertTrue(theResult, fail_fixture)
×
255

256
        def test_hear_ignores_WHEN_calling_multicast_GIVEN_invalid_args(self):
×
257
                """Tests the group argument for new auto-default behavior given None."""
258
                theResult = False
×
259
                fail_fixture = str("multicast.__main__.main(HEAR, group=None) == ERROR")
×
260
                try:
×
261
                        (rtn_val_f, tst_err_rslt_f) = __main__.main(
×
262
                                ["HEAR", "--group", "None", "--iface=None"]
263
                        )
264
                        self.assertIsNotNone(rtn_val_f)
×
265
                        self.assertIsNotNone(tst_err_rslt_f)
×
266
                        self.assertNotEqual(int(tst_err_rslt_f[0]), int(1), "REGRESSION in JOIN")
×
267
                        self.assertNotEqual(int(tst_err_rslt_f[0]), int(70), "CEP-8 Violation.")
×
268
                        self.assertNotEqual(int(tst_err_rslt_f[0]), int(2), "CEP-8 Violation.")
×
269
                        self.assertNotEqual(int(tst_err_rslt_f[0]), int(3), "CEP-8 Violation.")
×
270
                        self.assertEqual(int(tst_err_rslt_f[0]), int(0), fail_fixture)
×
271
                        theResult = (int(tst_err_rslt_f[0]) == int(0))
×
272
                except Exception as _cause:
273
                        context.debugtestError(_cause)
274
                        self.fail(fail_fixture)
275
                        theResult = False
276
                self.assertTrue(theResult, fail_fixture)
×
277

278
        def test_hear_is_stable_WHEN_calling_multicast_GIVEN_invalid_tool(self):
×
279
                """Tests the hexdump argument for failure given future tools"""
280
                theResult = False
×
281
                fail_fixture = str("multicast.__main__.McastDispatch().useTool(HEAR, hex) == error")
×
282
                try:
×
283
                        self.assertTupleEqual(
×
284
                                multicast.__main__.main(["HEAR", "--hex"]),
285
                                (70, (False, None))  # skipcq: PTC-W0020  - This is test-code.
286
                        )
287
                        theResult = True
×
288
                except Exception as _cause:
289
                        context.debugtestError(_cause)
290
                        self.fail(fail_fixture)
291
                        theResult = False
292
                self.assertTrue(theResult, fail_fixture)
×
293

294
        def test_noop_stable_WHEN_calling_multicast_GIVEN_noop_args(self):
×
295
                """Tests the NOOP state for multicast given bad input"""
296
                theResult = False
×
297
                fail_fixture = str("multicast.__main__.main(NOOP) == Error")
×
298
                try:
×
299
                        self.assertIsNotNone(multicast.__main__.main(["NOOP"]), fail_fixture)
×
300
                        self.assertIsNotNone(multicast.__main__.main(["NOOP"])[0])  # skipcq: PTC-W0020
×
301
                        self.assertTupleEqual(
×
302
                                multicast.__main__.main(["NOOP"]),
303
                                (0, (True, None)),  # skipcq: PTC-W0020  - This is test-code.
304
                        )
305
                        theResult = True
×
306
                except Exception as _cause:
307
                        context.debugtestError(_cause)
308
                        self.fail(fail_fixture)
309
                        theResult = False
310
                self.assertTrue(theResult, fail_fixture)
×
311

312
        def test_help_works_WHEN_calling_multicast_GIVEN_help_tool(self):
×
313
                """Tests the HELP argument for help usage"""
314
                theResult = False
×
315
                fail_fixture = str("multicast.__main__.McastDispatch().useTool(HELP, []) == Empty")
×
316
                try:
×
317
                        with self.assertRaises(SystemExit) as rtn_val_h:
×
318
                                multicast.__main__.McastDispatch().doStep(["HELP"])
×
319
                        self.assertIsNotNone(rtn_val_h)
×
320
                        theResult = True
×
321
                except Exception as _cause:
322
                        context.debugtestError(_cause)
323
                        self.fail(fail_fixture)
324
                        theResult = False
325
                self.assertTrue(theResult, fail_fixture)
×
326

327
        def test_hear_works_WHEN_say_works(self):
×
328
                """Tests the basic send and recv test"""
329
                theResult = False
×
330
                fail_fixture = str("SAY --> HEAR == error")
×
331
                sub_fail_fixture = str("SAY X-> HEAR == Error X-> HEAR :: (Error in SAY)")
×
332
                try:
×
333
                        _fixture_SAY_args = [
×
334
                                "--port",
335
                                "59991",
336
                                "--group",
337
                                "'224.0.0.1'",
338
                                "--message",
339
                                "'test message'"
340
                        ]
341
                        _fixture_HEAR_args = [
×
342
                                "--port",
343
                                "59991",
344
                                "--groups",
345
                                "'224.0.0.1'""",
346
                                "--group",
347
                                "'224.0.0.1'"
348
                        ]
349
                        p = Process(
×
350
                                target=multicast.__main__.McastDispatch().doStep,
351
                                name="HEAR",
352
                                args=(["HEAR", _fixture_HEAR_args])
353
                        )
354
                        p.start()
×
355
                        try:
×
356
                                tst_fixture_sendDispatch = multicast.__main__.McastDispatch()
×
357
                                self.assertIsNotNone(
×
358
                                        tst_fixture_sendDispatch.doStep(["SAY", _fixture_SAY_args])
359
                                )
360
                                self.assertIsNotNone(
×
361
                                        tst_fixture_sendDispatch.doStep(["SAY", _fixture_SAY_args])
362
                                )
363
                                self.assertIsNotNone(
×
364
                                        tst_fixture_sendDispatch.doStep(["SAY", _fixture_SAY_args])
365
                                )
366
                        except Exception as _root_cause:
367
                                p.join()
368
                                raise unittest.SkipTest(sub_fail_fixture) from _root_cause
369
                        p.join()
×
370
                        self.assertIsNotNone(p.exitcode)
371
                        self.assertEqual(int(p.exitcode), int(0), f"Unexpected Exit-Code: {p.exitcode}.")
372
                        theResult = (int(p.exitcode) <= int(0))
373
                except unittest.SkipTest as baton:
×
374
                        raise unittest.SkipTest(sub_fail_fixture) from baton
×
375
                except Exception as _cause:
376
                        context.debugtestError(_cause)
377
                        self.fail(fail_fixture)
378
                        theResult = False
379
                self.assertTrue(theResult, fail_fixture)
×
380

381
        def test_hear_works_WHEN_fuzzed_and_say_works(self):
×
382
                """Tests the basic send and recv test. Skips if fuzzing broke SAY fixture."""
383
                theResult = False
×
384
                fail_fixture = str("SAY --> HEAR == error")
×
385
                _fixture_port_num = self._the_test_port
×
386
                try:
×
387
                        self.assertIsNotNone(_fixture_port_num)
×
388
                        self.assertEqual(type(_fixture_port_num), type(int(0)))
×
389
                        _fixture_SAY_args = [
×
390
                                "--port",
391
                                str(_fixture_port_num),
392
                                "--group",
393
                                "'224.0.0.1'",
394
                                "--message",
395
                                "'test message'"
396
                        ]
397
                        _fixture_HEAR_args = [
×
398
                                "HEAR",
399
                                "--port",
400
                                str(_fixture_port_num),
401
                                "--groups",
402
                                "'224.0.0.1'",
403
                                "--group",
404
                                "'224.0.0.1'"
405
                        ]
406
                        p = Process(
×
407
                                target=multicast.__main__.McastDispatch().doStep,
408
                                name="HEAR",
409
                                args=(["HEAR", _fixture_HEAR_args])
410
                        )
411
                        p.start()
×
412
                        try:
×
413
                                self.assertIsNotNone(
×
414
                                        multicast.__main__.McastDispatch().doStep(["SAY", _fixture_SAY_args])
415
                                )
416
                                self.assertIsNotNone(
×
417
                                        multicast.__main__.McastDispatch().doStep(["SAY", _fixture_SAY_args])
418
                                )
419
                                self.assertIsNotNone(
×
420
                                        multicast.__main__.McastDispatch().doStep(["SAY", _fixture_SAY_args])
421
                                )
422
                        except Exception as _root_cause:
423
                                p.join()
424
                                raise unittest.SkipTest(fail_fixture) from _root_cause
425
                        p.join()
×
426
                        self.assertIsNotNone(p.exitcode)
427
                        self.assertEqual(int(p.exitcode), int(0))
428
                        theResult = (int(p.exitcode) <= int(0))
429
                except unittest.SkipTest as baton:
×
430
                        raise unittest.SkipTest("Fuzzing broke SAY fixture.") from baton
×
431
                except Exception as _cause:
432
                        context.debugtestError(_cause)
433
                        self.skipTest(fail_fixture)
434
                        theResult = False
435
                self.assertTrue(theResult, fail_fixture)
×
436

437
        def test_say_works_WHEN_using_stdin(self):
×
438
                """Tests the basic send with streamed input test case."""
439
                theResult = False
×
440
                fail_fixture = str("STDIN --> SAY == error")
×
441
                _fixture_port_num = self._the_test_port
×
442
                try:
×
443
                        say = multicast.send.McastSAY()
×
444
                        self.assertIsNotNone(say)
×
445
                        self.assertIsNotNone(_fixture_port_num)
×
446
                        test_cases = [
×
447
                                "",  # Empty input
448
                                "Test message from stdin",  # Basic case
449
                                "A" * 1024,  # Large input
450
                                "Special chars: !@#$%^&*()",  # Special characters
451
                                "Unicode: 你好世界",  # Unicode
452
                                "HEAR\x00"  # Null byte injection
453
                        ]
454
                        for test_input in test_cases:
×
455
                                self.assertIsNotNone(test_input)
×
456
                                with patch('sys.stdin', io.StringIO(test_input)):
×
457
                                        result = say.doStep(data=["-"], group="224.0.0.1", port=_fixture_port_num)
×
458
                                        self.assertIsNotNone(result)
×
459
                                        # Verify the message was actually sent
460
                                        theResult = result[0] or False
×
461
                                        self.assertTrue(theResult)  # Assuming there's a success indicator
×
462
                except Exception as _cause:
463
                        context.debugtestError(_cause)
464
                        self.fail(fail_fixture)
465
                        theResult = False
466
                self.assertTrue(theResult, fail_fixture)
×
467

468
        def test_recv_Errors_WHEN_say_not_used(self):
×
469
                """Tests the basic noop recv test"""
470
                theResult = False
×
471
                fail_fixture = str("NOOP --> RECV != error")
×
472
                sub_fail_fixture = str("NOOP X-> RECV == Error X-> RECV :: (Error in NOOP)")
×
473
                try:
×
474
                        _fixture_RECV_args = [
×
475
                                "--port",
476
                                "59992",
477
                                "--groups",
478
                                "'224.0.0.1'",
479
                                "--group",
480
                                "'224.0.0.1'"
481
                        ]
482
                        p = Process(
×
483
                                target=multicast.__main__.McastDispatch().doStep,
484
                                name="NOHEAR",
485
                                args=(["RECV", _fixture_RECV_args])
486
                        )
487
                        p.start()
×
488
                        try:
×
489
                                test_cls = multicast.__main__.McastDispatch()
×
490
                                self.assertTupleEqual(
×
491
                                        test_cls.doStep(["NOOP", []]),
492
                                        (int(0), (True, None)),  # skipcq: PTC-W0020  - This is test-code.
493
                                        sub_fail_fixture
494
                                )
495
                        except Exception as _root_cause:
496
                                p.join()
497
                                raise unittest.SkipTest(sub_fail_fixture) from _root_cause
498
                        p.join()
×
499
                        self.assertIsNotNone(p.exitcode, fail_fixture)
500
                        self.assertEqual(int(p.exitcode), int(0), f"Unexpected Exit-Code: {p.exitcode}.")
501
                        theResult = (int(p.exitcode) <= int(0))
502
                except unittest.SkipTest as baton:
×
503
                        raise unittest.SkipTest(sub_fail_fixture) from baton
×
504
                except Exception as _cause:
505
                        context.debugtestError(_cause)
506
                        self.fail(fail_fixture)
507
                        theResult = False
508
                self.assertTrue(theResult, fail_fixture)
×
509

510

511
@context.markWithMetaTag("mat", "usage")
×
512
class BasicIntegrationTestSuite(context.BasicUsageTestSuite):
×
513
        """
514
        A test suite for basic functional integration tests of the multicast module.
515

516
        This class inherits from context.BasicUsageTestSuite and provides a set of
517
        test cases to verify the functionality of the multicast module's command-line
518
        interface and core features.
519

520
        The suite includes tests for:
521
        - Printing usage information when called with the help argument
522
        - Verifying command-specific help output
523
        - Comparing responses between absolute and implicit module calls
524
        - Checking version information output
525
        - Validating error handling for invalid inputs
526
        - Profiling and stability checks for the NOOP command
527

528
        Attributes:
529
                _thepython (str): Path to the Python interpreter used for testing.
530

531
        Methods:
532
                setUp(): Prepares the test environment before each test method is run.
533
                test_prints_usage_WHEN_called_GIVEN_help_argument(): Verifies help output.
534
                test_prints_usage_WHEN_called_GIVEN_cmd_and_help_argument(): Checks command-specific help.
535
                test_equivilant_response_WHEN_absolute_vs_implicit(): Compares module call methods.
536
                test_prints_version_WHEN_called_GIVEN_version_argument(): Validates version output.
537
                test_Usage_Error_WHEN_the_help_command_is_called(): Ensures correct help output.
538
                test_profile_WHEN_the_noop_command_is_called(): Profiles the NOOP command.
539
                test_stable_WHEN_the_noop_command_is_called(): Checks NOOP command stability.
540
                test_invalid_Error_WHEN_cli_called_GIVEN_bad_input(): Verifies error handling.
541

542
        Note:
543
                This test suite relies on the context module for utility functions and
544
                the subprocess module for executing Python commands. It uses various
545
                assertion methods to validate the expected behavior of the multicast module.
546

547
        Example:
548
                To run this test suite, use the unittest module's test runner:
549

550
                ```
551
                python -m unittest tests.test_usage.BasicIntegrationTestSuite
552
                ```
553
        """
554

555
        __module__ = "tests.test_usage"
×
556

557
        __name__ = "tests.test_usage.BasicIntegrationTestSuite"
×
558

559
        def setUp(self):
×
560
                super(self.__class__, self).setUp()  # skipcq: PYL-E1003 - this is more polymorphic
×
561
                if (self._thepython is None):
×
562
                        self.skipTest(str("No python cmd to test with!"))
×
563

564
        def test_prints_usage_WHEN_called_GIVEN_help_argument(self):
×
565
                """Test case for multicast.__main__ help."""
566
                theResult = False
×
567
                fail_fixture = str("multicast.__main__(--help) == not helpful")
×
568
                try:
×
569
                        if (self._thepython is not None):
×
570
                                theOutputtxt = context.checkPythonCommand(
×
571
                                        [str(self._thepython), str("-m"), str("multicast"), str("--help")],
572
                                        stderr=subprocess.STDOUT
573
                                )
574
                                self.assertIn(str("usage:"), str(theOutputtxt))
×
575
                                if (str("usage:") in str(theOutputtxt)):
×
576
                                        theResult = True
×
577
                                else:
578
                                        theResult = False
×
579
                                        context.debugUnexpectedOutput(
×
580
                                                str("usage:"), str(theOutputtxt), self._thepython
581
                                        )
582
                except Exception as _cause:
583
                        context.debugtestError(_cause)
584
                        del _cause  # skipcq - cleanup any error leaks early
585
                        self.fail(fail_fixture)
586
                        theResult = False
587
                self.assertTrue(theResult, str("Could Not find usage from multicast --help"))
×
588

589
        def test_prints_usage_WHEN_called_GIVEN_cmd_and_help_argument(self):
×
590
                """Test case for multicast HEAR|RECV|SAY help."""
591
                theResult = None
×
592
                fail_fixture = str("multicast.__main__(--help) == not helpful")
×
593
                try:
×
594
                        if (self._thepython is not None):
×
595
                                for test_case in [".__main__", ""]:
×
596
                                        args = [
×
597
                                                str(self._thepython),
598
                                                str("-m"),
599
                                                str("multicast{}").format(str(test_case)),
600
                                                str("--help")
601
                                        ]
602
                                        theOutputtxt = context.checkPythonCommand(args, stderr=subprocess.STDOUT)
×
603
                                        self.assertIn(str("usage:"), str(theOutputtxt))
×
604
                                        if (str("usage:") in str(theOutputtxt)):
×
605
                                                theResult = ((theResult is None) or (theResult is True))
×
606
                                        else:
607
                                                theResult = False
×
608
                                                context.debugUnexpectedOutput(
×
609
                                                        str("usage:"), str(theOutputtxt), self._thepython
610
                                                )
611
                except Exception as _cause:
612
                        context.debugtestError(_cause)
613
                        del _cause  # skipcq - cleanup any error leaks early
614
                        self.fail(fail_fixture)
615
                        theResult = False
616
                self.assertTrue(theResult, str("Could Not find usage from multicast CMD --help"))
×
617

618
        def test_equivilant_response_WHEN_absolute_vs_implicit(self):
×
619
                """Test case for multicast vs multicast.__main__"""
620
                theResult = False
×
621
                try:
×
622
                        theExpectedText = context.checkPythonCommand(
×
623
                                [str(self._thepython), str("-m"), str("multicast.__main__")],
624
                                stderr=subprocess.STDOUT
625
                        )
626
                        self.assertIsNotNone(theExpectedText)
×
627
                        theOutputtxt = context.checkPythonCommand(
×
628
                                [str(self._thepython), str("-m"), str("multicast")], stderr=subprocess.STDOUT
629
                        )
630
                        self.assertIn(str(theExpectedText), str(theOutputtxt))
×
631
                        if (str(theExpectedText) in str(theOutputtxt)):
×
632
                                theResult = True
×
633
                        else:
634
                                theResult = False
×
635
                                context.debugUnexpectedOutput(
×
636
                                        str(theExpectedText), str(theOutputtxt), self._thepython
637
                                )
638
                except BaseException as _cause:
639
                        context.debugtestError(_cause)
640
                        del _cause  # skipcq - cleanup any error leaks early
641
                        theResult = False
642
                self.assertTrue(theResult, str("Could Not swap multicast for multicast.__main__"))
×
643

644
        def test_prints_version_WHEN_called_GIVEN_version_argument(self):
×
645
                """Test for result from --version argument: python -m multicast.* --version """
646
                theResult = False
×
647
                if (self._thepython is not None):
×
648
                        try:
×
649
                                for test_case in [".__main__", ""]:
×
650
                                        args = [
×
651
                                                str(self._thepython),
652
                                                str("-m"),
653
                                                str("multicast{}").format(str(test_case)),
654
                                                str("--version")
655
                                        ]
656
                                        theOutputtxt = context.checkPythonCommand(args, stderr=subprocess.STDOUT)
×
657
                                        context.check_exec_command_has_output(self, args)
×
658
                                        theResult = (theOutputtxt is not None)
×
659
                        except Exception as _cause:
660
                                context.debugtestError(_cause)
661
                                del _cause  # skipcq - cleanup any error leaks early
662
                                theResult = False
663
                self.assertTrue(theResult, str("Could Not find version from multicast --version"))
×
664

665
        def _validate_help_output(self, args: list) -> bool:
×
666
                """
667
                Helper method to validate help command output.
668

669
                Args:
670
                        args (list) -- List of command arguments to execute
671

672
                Returns:
673
                        bool: True if validation passes, False otherwise
674
                """
675
                usageText = "usage:"
×
676
                theOutputtxt = context.checkPythonCommand(args, stderr=subprocess.STDOUT)
×
677
                subResult = False
×
678
                try:
×
679
                        if isinstance(theOutputtxt, bytes):
×
680
                                theOutputtxt = theOutputtxt.decode('utf8')
×
681
                except UnicodeDecodeError:
682
                        theOutputtxt = str(repr(bytes(theOutputtxt)))
683
                self.assertIsNotNone(theOutputtxt)
×
684
                self.assertIn(str(usageText), str(theOutputtxt))
×
685
                if str(usageText) in str(theOutputtxt):
×
686
                        subResult = True
×
687
                else:
688
                        context.debugUnexpectedOutput(
×
689
                                str(usageText), str(theOutputtxt), self._thepython
690
                        )
691
                return subResult
×
692

693
        def test_Usage_Error_WHEN_the_help_command_is_called(self):
×
694
                """Test case for multicast* --help."""
695
                theResult = False
×
696
                fail_fixture = str("multicast --help == not helpful")
×
697
                try:
×
698
                        if (self._thepython is not None):
×
699
                                for test_case in [".__main__", ""]:
×
700
                                        args = [
×
701
                                                str(self._thepython),
702
                                                str("-m"),
703
                                                str("multicast{}").format(str(test_case)),
704
                                                str("--help")
705
                                        ]
706
                                        with self.subTest(args=args):
×
707
                                                if self._validate_help_output(args):
×
708
                                                        theResult = True
×
709
                except Exception as _cause:
710
                        context.debugtestError(_cause)
711
                        del _cause  # skipcq - cleanup any error leaks early
712
                        self.fail(fail_fixture)
713
                        theResult = False
714
                self.assertTrue(theResult, str("Could Not find usage from multicast --help"))
×
715

716
        def test_Usage_Error_WHEN_the_help_sub_command_is_called(self):
×
717
                """
718
                Test case for validating help output of multicast sub-commands.
719

720
                This test ensures that the help output is correct for various sub-commands
721
                (HEAR, RECV, SAY) in both daemon and non-daemon modes. It validates that
722
                each command combination provides appropriate usage information.
723

724
                Test fixtures use named tuples to organize:
725
                - mode: daemon/non-daemon mode
726
                - command: the sub-command being tested
727
                """
728
                theResult = False
×
729
                fail_fixture = str("multicast [HEAR|RECV] --help == not helpful")
×
730
                try:
×
731
                        TestCase = namedtuple("TestCase", ["mode", "command"])
×
732
                        inner_fixtures = [
×
733
                                TestCase(mode="--daemon {}", command="HEAR"),
734
                                TestCase(mode="{}", command="HEAR"),
735
                                TestCase(mode="--daemon {}", command="RECV"),
736
                                TestCase(mode="{}", command="RECV"),
737
                                TestCase(mode="{}", command="SAY"),
738
                                TestCase(mode="{}", command="NOOP")
739
                        ]
740
                        if (self._thepython is not None):
×
741
                                theResult = True
×
742
                                for test_case_o in [".__main__", ""]:
×
743
                                        for test_case_i in inner_fixtures:
×
744
                                                self.assertIsInstance(test_case_i, TestCase)
×
745
                                                args = [
×
746
                                                        str(self._thepython),
747
                                                        str("-m"),
748
                                                        str("multicast{}").format(str(test_case_o)),
749
                                                        str(test_case_i.mode).format(str(test_case_i.command)),
750
                                                        str("--help")
751
                                                ]
752
                                                with self.subTest(args=args):
×
753
                                                        if not self._validate_help_output(args):
×
754
                                                                theResult = False
×
755
                except Exception as _cause:
756
                        context.debugtestError(_cause)
757
                        del _cause  # skipcq - cleanup any error leaks early
758
                        self.fail(fail_fixture)
759
                        theResult = False
760
                self.assertTrue(theResult, str("Could Not find usage from multicast --help"))
×
761

762
        def test_profile_WHEN_the_noop_command_is_called(self):
×
763
                """Test case template for profiling"""
764
                theResult = False
×
765
                if (self._thepython is not None):
×
766
                        try:
×
767
                                for test_case in ["NOOP"]:
×
768
                                        args = [
×
769
                                                str(self._thepython),
770
                                                str("-m"),
771
                                                str("multicast"),
772
                                                str("{}").format(str(test_case))
773
                                        ]
774
                                        theOutputtxt = context.timePythonCommand(args, stderr=subprocess.STDOUT)
×
775
                                        # now test it
776
                                        try:
×
777
                                                if isinstance(theOutputtxt, bytes):
×
778
                                                        theOutputtxt = theOutputtxt.decode('utf8')
×
779
                                        except UnicodeDecodeError:
780
                                                theOutputtxt = str(repr(bytes(theOutputtxt)))
781
                                        # or simply:
782
                                        self.assertIsNotNone(theOutputtxt)
×
783
                                        theResult = True
×
784
                        except Exception as _cause:
785
                                context.debugtestError(_cause)
786
                                del _cause  # skipcq - cleanup any error leaks early
787
                                theResult = False
788
                assert theResult
×
789

790
        def test_stable_WHEN_the_noop_command_is_called(self):
×
791
                """Test case template for profiling"""
792
                theResult = False
×
793
                if (self._thepython is not None):
×
794
                        try:
×
795
                                for test_case in ["NOOP"]:
×
796
                                        args = [
×
797
                                                str(self._thepython),
798
                                                str("-m"),
799
                                                str("multicast"),
800
                                                str("{}").format(str(test_case))
801
                                        ]
802
                                        context.checkPythonFuzzing(args, stderr=None)
×
803
                                        # now test it
804
                                        theResult = True
×
805
                        except Exception as _cause:
806
                                context.debugtestError(_cause)
807
                                del _cause  # skipcq - cleanup any error leaks early
808
                                theResult = False
809
                self.assertTrue(theResult, str("Could Not handle multicast NOOP"))
×
810

811
        def test_invalid_Error_WHEN_cli_called_GIVEN_bad_input(self):
×
812
                """Test case template for invalid input to multicast CLI."""
813
                theResult = False
×
814
                if (self._thepython is not None):
×
815
                        try:
×
816
                                test_cases = [
817
                                        "BAdInPut",  # Basic invalid input
818
                                        int(1),  # Non-string input
819
                                        "exit",  # Reserved word
820
                                        "",  # Empty string
821
                                        " ",  # Whitespace
822
                                        "\t",  # Tab character
823
                                        "你好",  # Unicode
824
                                        "HEAR\x00",  # Null byte injection
825
                                        "SAY;ls"  # Command injection attempt
826
                                ]
827
                                for test_case in test_cases:
×
828
                                        args = [
×
829
                                                str(self._thepython),
830
                                                str("-m"),
831
                                                str("multicast"),
832
                                                str("{}").format(str(test_case))
833
                                        ]
834
                                        theOutputtxt = context.checkPythonCommand(args, stderr=subprocess.STDOUT)
×
835
                                        # or simply:
836
                                        if theOutputtxt:
×
837
                                                self.assertIsNotNone(theOutputtxt, f"Error with {str(test_case)}")
×
838
                                                self.assertIn(str("invalid choice:"), str(theOutputtxt))
×
839
                                                self.assertIn(repr(str(test_case)), str(theOutputtxt))
×
840
                                                theResult = True
×
841
                        except Exception as _cause:
842
                                context.debugtestError(_cause)
843
                                del _cause  # skipcq - cleanup any error leaks early
844
                                theResult = False
845
                self.assertTrue(theResult, str("Could Not handle negative inputs"))
×
846

847

848
if __name__ == '__main__':
849
        unittest.main()
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc