| ... | @@ -94,9 +94,9 @@ class ReleaseTest(unittest.TestCase): | ... | @@ -94,9 +94,9 @@ class ReleaseTest(unittest.TestCase): |
| 94 | self.assertEqual(error.stderr, b'diagnostic') | 94 | self.assertEqual(error.stderr, b'diagnostic') |
| 95 | self.assertIn('codesign --verify Snowbound.app', printed.getvalue()) | 95 | self.assertIn('codesign --verify Snowbound.app', printed.getvalue()) |
| 96 | | 96 | |
| 97 | def test_staple_retries_only_a_lost_connection_and_propagates_second_failure(self): | 97 | def test_staple_retries_only_a_lost_connection_and_propagates_last_failure(self): |
| 98 | network = 'error is Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."\n' | 98 | network = 'error is Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."\n' |
| 99 | for failures in ([(68, network)], [(68, network), (68, network)], | 99 | for failures in ([(68, network)], [(68, network)] * 4, [(68, network)] * 5, |
| 100 | [(68, 'The bundle has not been notarized.\n')], | 100 | [(68, 'The bundle has not been notarized.\n')], |
| 101 | [(77, network)], [(68, network.replace('-1005', '-10050'))]): | 101 | [(77, network)], [(68, network.replace('-1005', '-10050'))]): |
| 102 | with self.subTest(failures=failures), tempfile.TemporaryDirectory() as folder: | 102 | with self.subTest(failures=failures), tempfile.TemporaryDirectory() as folder: |
| ... | @@ -114,15 +114,18 @@ class ReleaseTest(unittest.TestCase): | ... | @@ -114,15 +114,18 @@ class ReleaseTest(unittest.TestCase): |
| 114 | kwargs['stdout'].write('The staple and validate action worked!\n') | 114 | kwargs['stdout'].write('The staple and validate action worked!\n') |
| 115 | | 115 | |
| 116 | printed = io.StringIO() | 116 | printed = io.StringIO() |
| 117 | with patch.dict(release['staple'].__globals__, {'run': failing_tool}), redirect_stdout(printed): | 117 | sleep = Mock() |
| 118 | if len(failures) == 1 and failures[0] == (68, network): | 118 | with patch.dict(release['staple'].__globals__, {'run': failing_tool}), \ |
| | 119 | patch.object(release['time'], 'sleep', sleep), redirect_stdout(printed): |
| | 120 | if failures[0] == (68, network) and len(failures) < 5: |
| 119 | self.assertIsNone(release['staple'](Path(folder) / 'Snowbound.app')) | 121 | self.assertIsNone(release['staple'](Path(folder) / 'Snowbound.app')) |
| 120 | else: | 122 | else: |
| 121 | with self.assertRaises(subprocess.CalledProcessError) as raised: | 123 | with self.assertRaises(subprocess.CalledProcessError) as raised: |
| 122 | release['staple'](Path(folder) / 'Snowbound.app') | 124 | release['staple'](Path(folder) / 'Snowbound.app') |
| 123 | self.assertIs(raised.exception, errors[-1]) | 125 | self.assertIs(raised.exception, errors[-1]) |
| 124 | expected = 2 if failures[0] == (68, network) else 1 | 126 | retried = failures[0] == (68, network) |
| 125 | self.assertEqual(len(calls), expected) | 127 | self.assertEqual(len(calls), min(len(failures) + 1, 5) if retried else 1) |
| | 128 | self.assertEqual([wait for (wait,), _ in sleep.call_args_list], [10, 20, 40, 80][:len(calls) - 1]) |
| 126 | self.assertEqual(printed.getvalue(), ''.join(text for _, text in failures) + | 129 | self.assertEqual(printed.getvalue(), ''.join(text for _, text in failures) + |
| 127 | ('The staple and validate action worked!\n' if len(errors) < len(calls) else '')) | 130 | ('The staple and validate action worked!\n' if len(errors) < len(calls) else '')) |
| 128 | for command, kwargs in calls: | 131 | for command, kwargs in calls: |