teuthology 1.1.0__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. scripts/describe.py +1 -0
  2. scripts/dispatcher.py +55 -26
  3. scripts/exporter.py +18 -0
  4. scripts/lock.py +1 -1
  5. scripts/node_cleanup.py +58 -0
  6. scripts/openstack.py +9 -9
  7. scripts/results.py +12 -11
  8. scripts/schedule.py +4 -0
  9. scripts/suite.py +57 -16
  10. scripts/supervisor.py +44 -0
  11. scripts/update_inventory.py +10 -4
  12. teuthology/__init__.py +24 -26
  13. teuthology/beanstalk.py +4 -3
  14. teuthology/config.py +16 -6
  15. teuthology/contextutil.py +18 -14
  16. teuthology/describe_tests.py +25 -18
  17. teuthology/dispatcher/__init__.py +210 -35
  18. teuthology/dispatcher/supervisor.py +140 -58
  19. teuthology/exceptions.py +43 -0
  20. teuthology/exporter.py +347 -0
  21. teuthology/kill.py +76 -81
  22. teuthology/lock/cli.py +3 -3
  23. teuthology/lock/ops.py +135 -61
  24. teuthology/lock/query.py +61 -44
  25. teuthology/ls.py +1 -1
  26. teuthology/misc.py +61 -75
  27. teuthology/nuke/__init__.py +12 -353
  28. teuthology/openstack/__init__.py +4 -3
  29. teuthology/openstack/openstack-centos-7.0-user-data.txt +1 -1
  30. teuthology/openstack/openstack-centos-7.1-user-data.txt +1 -1
  31. teuthology/openstack/openstack-centos-7.2-user-data.txt +1 -1
  32. teuthology/openstack/openstack-debian-8.0-user-data.txt +1 -1
  33. teuthology/openstack/openstack-opensuse-42.1-user-data.txt +1 -1
  34. teuthology/openstack/openstack-teuthology.cron +0 -1
  35. teuthology/orchestra/cluster.py +49 -7
  36. teuthology/orchestra/connection.py +16 -5
  37. teuthology/orchestra/console.py +111 -50
  38. teuthology/orchestra/daemon/cephadmunit.py +17 -4
  39. teuthology/orchestra/daemon/state.py +8 -1
  40. teuthology/orchestra/daemon/systemd.py +4 -4
  41. teuthology/orchestra/opsys.py +30 -11
  42. teuthology/orchestra/remote.py +405 -338
  43. teuthology/orchestra/run.py +3 -3
  44. teuthology/packaging.py +19 -16
  45. teuthology/provision/__init__.py +30 -10
  46. teuthology/provision/cloud/openstack.py +12 -6
  47. teuthology/provision/cloud/util.py +1 -2
  48. teuthology/provision/downburst.py +4 -3
  49. teuthology/provision/fog.py +68 -20
  50. teuthology/provision/openstack.py +5 -4
  51. teuthology/provision/pelagos.py +1 -1
  52. teuthology/repo_utils.py +43 -13
  53. teuthology/report.py +57 -35
  54. teuthology/results.py +5 -3
  55. teuthology/run.py +13 -14
  56. teuthology/run_tasks.py +27 -43
  57. teuthology/schedule.py +4 -3
  58. teuthology/scrape.py +28 -22
  59. teuthology/suite/__init__.py +74 -45
  60. teuthology/suite/build_matrix.py +34 -24
  61. teuthology/suite/fragment-merge.lua +105 -0
  62. teuthology/suite/matrix.py +31 -2
  63. teuthology/suite/merge.py +175 -0
  64. teuthology/suite/placeholder.py +6 -9
  65. teuthology/suite/run.py +175 -100
  66. teuthology/suite/util.py +64 -218
  67. teuthology/task/__init__.py +1 -1
  68. teuthology/task/ansible.py +101 -32
  69. teuthology/task/buildpackages.py +2 -2
  70. teuthology/task/ceph_ansible.py +13 -6
  71. teuthology/task/cephmetrics.py +2 -1
  72. teuthology/task/clock.py +33 -14
  73. teuthology/task/exec.py +18 -0
  74. teuthology/task/hadoop.py +2 -2
  75. teuthology/task/install/__init__.py +29 -7
  76. teuthology/task/install/bin/adjust-ulimits +16 -0
  77. teuthology/task/install/bin/daemon-helper +114 -0
  78. teuthology/task/install/bin/stdin-killer +263 -0
  79. teuthology/task/install/deb.py +1 -1
  80. teuthology/task/install/rpm.py +17 -5
  81. teuthology/task/install/util.py +3 -3
  82. teuthology/task/internal/__init__.py +41 -10
  83. teuthology/task/internal/edit_sudoers.sh +10 -0
  84. teuthology/task/internal/lock_machines.py +2 -9
  85. teuthology/task/internal/redhat.py +31 -1
  86. teuthology/task/internal/syslog.py +31 -8
  87. teuthology/task/kernel.py +152 -145
  88. teuthology/task/lockfile.py +1 -1
  89. teuthology/task/mpi.py +10 -10
  90. teuthology/task/pcp.py +1 -1
  91. teuthology/task/selinux.py +16 -8
  92. teuthology/task/ssh_keys.py +4 -4
  93. teuthology/task/tests/__init__.py +137 -77
  94. teuthology/task/tests/test_fetch_coredumps.py +116 -0
  95. teuthology/task/tests/test_run.py +4 -4
  96. teuthology/timer.py +3 -3
  97. teuthology/util/loggerfile.py +19 -0
  98. teuthology/util/scanner.py +159 -0
  99. teuthology/util/sentry.py +52 -0
  100. teuthology/util/time.py +52 -0
  101. teuthology-1.2.0.data/scripts/adjust-ulimits +16 -0
  102. teuthology-1.2.0.data/scripts/daemon-helper +114 -0
  103. teuthology-1.2.0.data/scripts/stdin-killer +263 -0
  104. teuthology-1.2.0.dist-info/METADATA +89 -0
  105. teuthology-1.2.0.dist-info/RECORD +174 -0
  106. {teuthology-1.1.0.dist-info → teuthology-1.2.0.dist-info}/WHEEL +1 -1
  107. {teuthology-1.1.0.dist-info → teuthology-1.2.0.dist-info}/entry_points.txt +3 -2
  108. scripts/nuke.py +0 -47
  109. scripts/worker.py +0 -37
  110. teuthology/nuke/actions.py +0 -456
  111. teuthology/openstack/test/__init__.py +0 -0
  112. teuthology/openstack/test/openstack-integration.py +0 -286
  113. teuthology/openstack/test/test_config.py +0 -35
  114. teuthology/openstack/test/test_openstack.py +0 -1695
  115. teuthology/orchestra/test/__init__.py +0 -0
  116. teuthology/orchestra/test/integration/__init__.py +0 -0
  117. teuthology/orchestra/test/integration/test_integration.py +0 -94
  118. teuthology/orchestra/test/test_cluster.py +0 -240
  119. teuthology/orchestra/test/test_connection.py +0 -106
  120. teuthology/orchestra/test/test_console.py +0 -217
  121. teuthology/orchestra/test/test_opsys.py +0 -404
  122. teuthology/orchestra/test/test_remote.py +0 -185
  123. teuthology/orchestra/test/test_run.py +0 -286
  124. teuthology/orchestra/test/test_systemd.py +0 -54
  125. teuthology/orchestra/test/util.py +0 -12
  126. teuthology/test/__init__.py +0 -0
  127. teuthology/test/fake_archive.py +0 -107
  128. teuthology/test/fake_fs.py +0 -92
  129. teuthology/test/integration/__init__.py +0 -0
  130. teuthology/test/integration/test_suite.py +0 -86
  131. teuthology/test/task/__init__.py +0 -205
  132. teuthology/test/task/test_ansible.py +0 -624
  133. teuthology/test/task/test_ceph_ansible.py +0 -176
  134. teuthology/test/task/test_console_log.py +0 -88
  135. teuthology/test/task/test_install.py +0 -337
  136. teuthology/test/task/test_internal.py +0 -57
  137. teuthology/test/task/test_kernel.py +0 -243
  138. teuthology/test/task/test_pcp.py +0 -379
  139. teuthology/test/task/test_selinux.py +0 -35
  140. teuthology/test/test_config.py +0 -189
  141. teuthology/test/test_contextutil.py +0 -68
  142. teuthology/test/test_describe_tests.py +0 -316
  143. teuthology/test/test_email_sleep_before_teardown.py +0 -81
  144. teuthology/test/test_exit.py +0 -97
  145. teuthology/test/test_get_distro.py +0 -47
  146. teuthology/test/test_get_distro_version.py +0 -47
  147. teuthology/test/test_get_multi_machine_types.py +0 -27
  148. teuthology/test/test_job_status.py +0 -60
  149. teuthology/test/test_ls.py +0 -48
  150. teuthology/test/test_misc.py +0 -391
  151. teuthology/test/test_nuke.py +0 -290
  152. teuthology/test/test_packaging.py +0 -763
  153. teuthology/test/test_parallel.py +0 -28
  154. teuthology/test/test_repo_utils.py +0 -225
  155. teuthology/test/test_report.py +0 -77
  156. teuthology/test/test_results.py +0 -155
  157. teuthology/test/test_run.py +0 -239
  158. teuthology/test/test_safepath.py +0 -55
  159. teuthology/test/test_schedule.py +0 -45
  160. teuthology/test/test_scrape.py +0 -167
  161. teuthology/test/test_timer.py +0 -80
  162. teuthology/test/test_vps_os_vers_parameter_checking.py +0 -84
  163. teuthology/test/test_worker.py +0 -303
  164. teuthology/worker.py +0 -354
  165. teuthology-1.1.0.dist-info/METADATA +0 -76
  166. teuthology-1.1.0.dist-info/RECORD +0 -213
  167. {teuthology-1.1.0.dist-info → teuthology-1.2.0.dist-info}/LICENSE +0 -0
  168. {teuthology-1.1.0.dist-info → teuthology-1.2.0.dist-info}/top_level.txt +0 -0
@@ -1,239 +0,0 @@
1
- import pytest
2
- import docopt
3
-
4
- from unittest.mock import patch, call, Mock
5
-
6
- from teuthology import run
7
- from scripts import run as scripts_run
8
-
9
-
10
- class TestRun(object):
11
- """ Tests for teuthology.run """
12
-
13
- @patch("teuthology.log.setLevel")
14
- @patch("teuthology.setup_log_file")
15
- @patch("os.mkdir")
16
- def test_set_up_logging(self, m_mkdir, m_setup_log_file, m_setLevel):
17
- run.set_up_logging(True, "path/to/archive")
18
- m_mkdir.assert_called_with("path/to/archive")
19
- m_setup_log_file.assert_called_with("path/to/archive/teuthology.log")
20
- assert m_setLevel.called
21
-
22
- # because of how we import things, mock merge_configs from run - where it's used
23
- # see: http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch
24
- @patch("teuthology.run.merge_configs")
25
- def test_setup_config(self, m_merge_configs):
26
- config = {"job_id": 1, "foo": "bar"}
27
- m_merge_configs.return_value = config
28
- result = run.setup_config(["some/config.yaml"])
29
- assert m_merge_configs.called
30
- assert result["job_id"] == "1"
31
- assert result["foo"] == "bar"
32
-
33
- @patch("teuthology.run.merge_configs")
34
- def test_setup_config_targets_ok(self, m_merge_configs):
35
- config = {"targets": list(range(4)), "roles": list(range(2))}
36
- m_merge_configs.return_value = config
37
- result = run.setup_config(["some/config.yaml"])
38
- assert result["targets"] == [0, 1, 2, 3]
39
- assert result["roles"] == [0, 1]
40
-
41
- @patch("teuthology.run.merge_configs")
42
- def test_setup_config_targets_invalid(self, m_merge_configs):
43
- config = {"targets": range(2), "roles": range(4)}
44
- m_merge_configs.return_value = config
45
- with pytest.raises(AssertionError):
46
- run.setup_config(["some/config.yaml"])
47
-
48
- @patch("teuthology.run.open")
49
- def test_write_initial_metadata(self, m_open):
50
- config = {"job_id": "123", "foo": "bar"}
51
- run.write_initial_metadata(
52
- "some/archive/dir",
53
- config,
54
- "the_name",
55
- "the_description",
56
- "the_owner",
57
- )
58
- expected = [
59
- call('some/archive/dir/pid', 'w'),
60
- call('some/archive/dir/owner', 'w'),
61
- call('some/archive/dir/orig.config.yaml', 'w'),
62
- call('some/archive/dir/info.yaml', 'w')
63
- ]
64
- assert m_open.call_args_list == expected
65
-
66
- def test_get_machine_type(self):
67
- result = run.get_machine_type(None, {"machine-type": "the_machine_type"})
68
- assert result == "the_machine_type"
69
-
70
- def test_get_summary(self):
71
- result = run.get_summary("the_owner", "the_description")
72
- assert result == {"owner": "the_owner", "description": "the_description", "success": True}
73
- result = run.get_summary("the_owner", None)
74
- assert result == {"owner": "the_owner", "success": True}
75
-
76
- def test_validate_tasks_invalid(self):
77
- config = {"tasks": [{"kernel": "can't be here"}]}
78
- with pytest.raises(AssertionError) as excinfo:
79
- run.validate_tasks(config)
80
- assert excinfo.value.args[0].startswith("kernel installation")
81
-
82
- def test_validate_task_no_tasks(self):
83
- result = run.validate_tasks({})
84
- assert result == []
85
-
86
- def test_validate_tasks_valid(self):
87
- expected = [{"foo": "bar"}, {"bar": "foo"}]
88
- result = run.validate_tasks({"tasks": expected})
89
- assert result == expected
90
-
91
- def test_validate_tasks_is_list(self):
92
- with pytest.raises(AssertionError) as excinfo:
93
- run.validate_tasks({"tasks": {"foo": "bar"}})
94
- assert excinfo.value.args[0].startswith("Expected list")
95
-
96
- def test_get_initial_tasks_invalid(self):
97
- with pytest.raises(AssertionError) as excinfo:
98
- run.get_initial_tasks(True, {"targets": "can't be here",
99
- "roles": "roles" }, "machine_type")
100
- assert excinfo.value.args[0].startswith("You cannot")
101
-
102
- def test_get_inital_tasks(self):
103
- config = {"roles": range(2), "kernel": "the_kernel", "use_existing_cluster": False}
104
- result = run.get_initial_tasks(True, config, "machine_type")
105
- assert {"internal.lock_machines": (2, "machine_type")} in result
106
- assert {"kernel": "the_kernel"} in result
107
- # added because use_existing_cluster == False
108
- assert {'internal.vm_setup': None} in result
109
- assert {'internal.buildpackages_prep': None} in result
110
-
111
- @patch("teuthology.run.fetch_qa_suite")
112
- def test_fetch_tasks_if_needed(self, m_fetch_qa_suite):
113
- config = {"suite_path": "/some/suite/path", "suite_branch": "feature_branch",
114
- "suite_sha1": "commit"}
115
- m_fetch_qa_suite.return_value = "/some/other/suite/path"
116
- result = run.fetch_tasks_if_needed(config)
117
- m_fetch_qa_suite.assert_called_with("feature_branch", commit="commit")
118
- assert result == "/some/other/suite/path"
119
-
120
- @patch("teuthology.run.get_status")
121
- @patch("teuthology.run.nuke")
122
- @patch("yaml.safe_dump")
123
- @patch("teuthology.report.try_push_job_info")
124
- @patch("teuthology.run.email_results")
125
- @patch("teuthology.run.open")
126
- @patch("sys.exit")
127
- def test_report_outcome(self, m_sys_exit, m_open, m_email_results, m_try_push_job_info, m_safe_dump, m_nuke, m_get_status):
128
- m_get_status.return_value = "fail"
129
- fake_ctx = Mock()
130
- summary = {"failure_reason": "reasons"}
131
- summary_dump = "failure_reason: reasons\n"
132
- config = {"nuke-on-error": True, "email-on-error": True}
133
- config_dump = "nuke-on-error: true\nemail-on-error: true\n"
134
- m_safe_dump.side_effect = [None, summary_dump, config_dump]
135
- run.report_outcome(config, "the/archive/path", summary, fake_ctx)
136
- assert m_nuke.called
137
- m_try_push_job_info.assert_called_with(config, summary)
138
- m_open.assert_called_with("the/archive/path/summary.yaml", "w")
139
- assert m_email_results.called
140
- assert m_open.called
141
- assert m_sys_exit.called
142
-
143
- @patch("teuthology.run.set_up_logging")
144
- @patch("teuthology.run.setup_config")
145
- @patch("teuthology.run.get_user")
146
- @patch("teuthology.run.write_initial_metadata")
147
- @patch("teuthology.report.try_push_job_info")
148
- @patch("teuthology.run.get_machine_type")
149
- @patch("teuthology.run.get_summary")
150
- @patch("yaml.safe_dump")
151
- @patch("teuthology.run.validate_tasks")
152
- @patch("teuthology.run.get_initial_tasks")
153
- @patch("teuthology.run.fetch_tasks_if_needed")
154
- @patch("teuthology.run.run_tasks")
155
- @patch("teuthology.run.report_outcome")
156
- def test_main(self, m_report_outcome, m_run_tasks, m_fetch_tasks_if_needed, m_get_initial_tasks, m_validate_tasks,
157
- m_safe_dump, m_get_summary, m_get_machine_type, m_try_push_job_info, m_write_initial_metadata,
158
- m_get_user, m_setup_config, m_set_up_logging):
159
- """ This really should be an integration test of some sort. """
160
- config = {"job_id": 1}
161
- m_setup_config.return_value = config
162
- m_get_machine_type.return_value = "machine_type"
163
- doc = scripts_run.__doc__
164
- args = docopt.docopt(doc, [
165
- "--verbose",
166
- "--archive", "some/archive/dir",
167
- "--description", "the_description",
168
- "--lock",
169
- "--os-type", "os_type",
170
- "--os-version", "os_version",
171
- "--block",
172
- "--name", "the_name",
173
- "--suite-path", "some/suite/dir",
174
- "path/to/config.yml",
175
- ])
176
- m_get_user.return_value = "the_owner"
177
- m_get_summary.return_value = dict(success=True, owner="the_owner", description="the_description")
178
- m_validate_tasks.return_value = ['task3']
179
- m_get_initial_tasks.return_value = ['task1', 'task2']
180
- m_fetch_tasks_if_needed.return_value = "some/suite/dir"
181
- run.main(args)
182
- m_set_up_logging.assert_called_with(True, "some/archive/dir")
183
- m_setup_config.assert_called_with(["path/to/config.yml"])
184
- m_write_initial_metadata.assert_called_with(
185
- "some/archive/dir",
186
- config,
187
- "the_name",
188
- "the_description",
189
- "the_owner"
190
- )
191
- m_try_push_job_info.assert_called_with(config, dict(status='running'))
192
- m_get_machine_type.assert_called_with(None, config)
193
- m_get_summary.assert_called_with("the_owner", "the_description")
194
- m_get_initial_tasks.assert_called_with(True, config, "machine_type")
195
- m_fetch_tasks_if_needed.assert_called_with(config)
196
- assert m_report_outcome.called
197
- args, kwargs = m_run_tasks.call_args
198
- fake_ctx = kwargs["ctx"]._conf
199
- # fields that must be in ctx for the tasks to behave
200
- expected_ctx = ["verbose", "archive", "description", "owner", "lock", "machine_type", "os_type", "os_version",
201
- "block", "name", "suite_path", "config", "summary"]
202
- for key in expected_ctx:
203
- assert key in fake_ctx
204
- assert isinstance(fake_ctx["config"], dict)
205
- assert isinstance(fake_ctx["summary"], dict)
206
- assert "tasks" in fake_ctx["config"]
207
- # ensures that values missing in args are added with the correct value
208
- assert fake_ctx["owner"] == "the_owner"
209
- assert fake_ctx["machine_type"] == "machine_type"
210
- # ensures os_type and os_version are property overwritten
211
- assert fake_ctx["config"]["os_type"] == "os_type"
212
- assert fake_ctx["config"]["os_version"] == "os_version"
213
-
214
- def test_get_teuthology_command(self):
215
- doc = scripts_run.__doc__
216
- args = docopt.docopt(doc, [
217
- "--archive", "some/archive/dir",
218
- "--description", "the_description",
219
- "--lock",
220
- "--block",
221
- "--name", "the_name",
222
- "--suite-path", "some/suite/dir",
223
- "path/to/config.yml", "path/to/config2.yaml",
224
- ])
225
- result = run.get_teuthology_command(args)
226
- result = result.split()
227
- expected = [
228
- "teuthology",
229
- "path/to/config.yml", "path/to/config2.yaml",
230
- "--suite-path", "some/suite/dir",
231
- "--lock",
232
- "--description", "the_description",
233
- "--name", "the_name",
234
- "--block",
235
- "--archive", "some/archive/dir",
236
- ]
237
- assert len(result) == len(expected)
238
- for arg in expected:
239
- assert arg in result
@@ -1,55 +0,0 @@
1
- from teuthology import safepath
2
-
3
- class TestSafepath(object):
4
- def test_simple(self):
5
- got = safepath.munge('foo')
6
- assert got == 'foo'
7
-
8
- def test_empty(self):
9
- # really odd corner case
10
- got = safepath.munge('')
11
- assert got == '_'
12
-
13
- def test_slash(self):
14
- got = safepath.munge('/')
15
- assert got == '_'
16
-
17
- def test_slashslash(self):
18
- got = safepath.munge('//')
19
- assert got == '_'
20
-
21
- def test_absolute(self):
22
- got = safepath.munge('/evil')
23
- assert got == 'evil'
24
-
25
- def test_absolute_subdir(self):
26
- got = safepath.munge('/evil/here')
27
- assert got == 'evil/here'
28
-
29
- def test_dot_leading(self):
30
- got = safepath.munge('./foo')
31
- assert got == 'foo'
32
-
33
- def test_dot_middle(self):
34
- got = safepath.munge('evil/./foo')
35
- assert got == 'evil/foo'
36
-
37
- def test_dot_trailing(self):
38
- got = safepath.munge('evil/foo/.')
39
- assert got == 'evil/foo'
40
-
41
- def test_dotdot(self):
42
- got = safepath.munge('../evil/foo')
43
- assert got == '_./evil/foo'
44
-
45
- def test_dotdot_subdir(self):
46
- got = safepath.munge('evil/../foo')
47
- assert got == 'evil/_./foo'
48
-
49
- def test_hidden(self):
50
- got = safepath.munge('.evil')
51
- assert got == '_evil'
52
-
53
- def test_hidden_subdir(self):
54
- got = safepath.munge('foo/.evil')
55
- assert got == 'foo/_evil'
@@ -1,45 +0,0 @@
1
- from teuthology.schedule import build_config
2
- from teuthology.misc import get_user
3
-
4
-
5
- class TestSchedule(object):
6
- basic_args = {
7
- '--verbose': False,
8
- '--owner': 'OWNER',
9
- '--description': 'DESC',
10
- '--email': 'EMAIL',
11
- '--first-in-suite': False,
12
- '--last-in-suite': True,
13
- '--name': 'NAME',
14
- '--worker': 'tala',
15
- '--timeout': '6',
16
- '--priority': '99',
17
- # TODO: make this work regardless of $PWD
18
- #'<conf_file>': ['../../examples/3node_ceph.yaml',
19
- # '../../examples/3node_rgw.yaml'],
20
- }
21
-
22
- def test_basic(self):
23
- expected = {
24
- 'description': 'DESC',
25
- 'email': 'EMAIL',
26
- 'first_in_suite': False,
27
- 'last_in_suite': True,
28
- 'machine_type': 'tala',
29
- 'name': 'NAME',
30
- 'owner': 'OWNER',
31
- 'priority': 99,
32
- 'results_timeout': '6',
33
- 'verbose': False,
34
- 'tube': 'tala',
35
- }
36
-
37
- job_dict = build_config(self.basic_args)
38
- assert job_dict == expected
39
-
40
- def test_owner(self):
41
- args = self.basic_args
42
- args['--owner'] = None
43
- job_dict = build_config(self.basic_args)
44
- assert job_dict['owner'] == 'scheduled_%s' % get_user()
45
-
@@ -1,167 +0,0 @@
1
- from __future__ import with_statement
2
-
3
- import os
4
- import shutil
5
- import tempfile
6
- import yaml
7
- from teuthology import scrape
8
-
9
- class FakeResultDir(object):
10
- """Mocks a Result Directory"""
11
-
12
- def __init__(self,
13
- failure_reason="Dummy reason",
14
- assertion="FAILED assert 1 == 2\n",
15
- blank_backtrace=False
16
- ):
17
- self.failure_reason = failure_reason
18
- self.assertion = assertion
19
- self.blank_backtrace = blank_backtrace
20
- self.path = tempfile.mkdtemp()
21
-
22
- with open(os.path.join(self.path, "config.yaml"), "w") as f:
23
- yaml.dump({"description": "Dummy test"}, f)
24
-
25
- with open(os.path.join(self.path, "summary.yaml"), "w") as f:
26
- yaml.dump({
27
- "success": "false",
28
- "failure_reason": self.failure_reason
29
- }, f)
30
-
31
- with open(os.path.join(self.path, "teuthology.log"), "w") as f:
32
- if not self.blank_backtrace:
33
- f.write(" ceph version 1000\n")
34
- f.write(".stderr: Dummy error\n")
35
- f.write(self.assertion)
36
- f.write(" NOTE: a copy of the executable dummy text\n")
37
-
38
- def __enter__(self):
39
- return self
40
-
41
- def __exit__(self, exc_typ, exc_val, exc_tb):
42
- shutil.rmtree(self.path)
43
-
44
- class TestScrape(object):
45
- """Tests for teuthology.scrape"""
46
-
47
- def test_grep(self):
48
- with FakeResultDir() as d:
49
- filepath = os.path.join(d.path, "scrapetest.txt")
50
- with open(filepath, 'w') as f:
51
- f.write("Ceph is an open-source software storage platform\n\
52
- Teuthology is used for testing.")
53
-
54
- #System level grep is called
55
- value1 = scrape.grep(filepath, "software")
56
- value2 = scrape.grep(filepath, "device")
57
-
58
- assert value1 ==\
59
- ['Ceph is an open-source software storage platform', '']
60
- assert value2 == []
61
-
62
- def test_job(self):
63
- with FakeResultDir() as d:
64
- job = scrape.Job(d.path, 1)
65
- assert job.get_success() == "false"
66
- assert job.get_assertion() == "FAILED assert 1 == 2"
67
- assert job.get_last_tlog_line() ==\
68
- b"NOTE: a copy of the executable dummy text"
69
- assert job.get_failure_reason() == "Dummy reason"
70
-
71
- def test_timeoutreason(self):
72
- with FakeResultDir(failure_reason=\
73
- "status 124: timeout '123 /home/ubuntu/cephtest/workunit.client.0/cephtool/test.sh'") as d:
74
- job = scrape.Job(d.path, 1)
75
- assert scrape.TimeoutReason.could_be(job)
76
- assert scrape.TimeoutReason(job).match(job)
77
-
78
- def test_deadreason(self):
79
- with FakeResultDir() as d:
80
- job = scrape.Job(d.path, 1)
81
- #Summary is present
82
- #So this cannot be a DeadReason
83
- assert not scrape.DeadReason.could_be(job)
84
-
85
- def test_lockdepreason(self):
86
- lkReason = None
87
- with FakeResultDir(assertion=\
88
- "FAILED assert common/lockdep reason\n") as d:
89
- job = scrape.Job(d.path, 1)
90
- assert scrape.LockdepReason.could_be(job)
91
-
92
- lkReason = scrape.LockdepReason(job)
93
- #Backtraces of same jobs must match 100%
94
- assert lkReason.match(job)
95
- with FakeResultDir(blank_backtrace=True) as d:
96
- #Corresponding to 0% match
97
- assert not lkReason.match(scrape.Job(d.path, 2))
98
-
99
- def test_assertionreason(self):
100
- with FakeResultDir() as d:
101
- job = scrape.Job(d.path, 1)
102
- assert scrape.AssertionReason.could_be(job)
103
-
104
- def test_genericreason(self):
105
- d1 = FakeResultDir(blank_backtrace=True)
106
- d2 = FakeResultDir(failure_reason="Dummy dummy")
107
- d3 = FakeResultDir()
108
-
109
- job1 = scrape.Job(d1.path, 1)
110
- job2 = scrape.Job(d2.path, 2)
111
- job3 = scrape.Job(d3.path, 3)
112
-
113
- reason = scrape.GenericReason(job3)
114
-
115
- assert reason.match(job2)
116
- assert not reason.match(job1)
117
-
118
- shutil.rmtree(d1.path)
119
- shutil.rmtree(d2.path)
120
- shutil.rmtree(d3.path)
121
-
122
- def test_valgrindreason(self):
123
- vreason = None
124
- with FakeResultDir(
125
- failure_reason="saw valgrind issues",
126
- assertion="2014-08-22T20:07:18.668 ERROR:tasks.ceph:saw valgrind issue <kind>Leak_DefinitelyLost</kind> in /var/log/ceph/valgrind/osd.3.log.gz\n"
127
- ) as d:
128
- job = scrape.Job(d.path, 1)
129
- assert scrape.ValgrindReason.could_be(job)
130
-
131
- vreason = scrape.ValgrindReason(job)
132
- assert vreason.match(job)
133
-
134
- def test_give_me_a_reason(self):
135
- with FakeResultDir() as d:
136
- job = scrape.Job(d.path, 1)
137
-
138
- assert type(scrape.give_me_a_reason(job)) == scrape.AssertionReason
139
-
140
- #Test the lockdep ordering
141
- with FakeResultDir(assertion=\
142
- "FAILED assert common/lockdep reason\n") as d:
143
- job = scrape.Job(d.path, 1)
144
- assert type(scrape.give_me_a_reason(job)) == scrape.LockdepReason
145
-
146
- def test_scraper(self):
147
- d = FakeResultDir()
148
- os.mkdir(os.path.join(d.path, "test"))
149
- shutil.move(
150
- os.path.join(d.path, "config.yaml"),
151
- os.path.join(d.path, "test", "config.yaml")
152
- )
153
- shutil.move(
154
- os.path.join(d.path, "summary.yaml"),
155
- os.path.join(d.path, "test", "summary.yaml")
156
- )
157
- shutil.move(
158
- os.path.join(d.path, "teuthology.log"),
159
- os.path.join(d.path, "test", "teuthology.log")
160
- )
161
-
162
- scrape.Scraper(d.path).analyze()
163
-
164
- #scrape.log should be created
165
- assert os.path.exists(os.path.join(d.path, "scrape.log"))
166
-
167
- shutil.rmtree(d.path)
@@ -1,80 +0,0 @@
1
- from teuthology import timer
2
-
3
- from unittest.mock import MagicMock, patch, mock_open
4
- from time import time
5
-
6
-
7
- class TestTimer(object):
8
- def test_data_empty(self):
9
- self.timer = timer.Timer()
10
- assert self.timer.data == dict()
11
-
12
- def test_data_one_mark(self):
13
- self.timer = timer.Timer()
14
- # Avoid failing if ~1ms elapses between these two calls
15
- self.timer.precision = 2
16
- self.timer.mark()
17
- assert len(self.timer.data['marks']) == 1
18
- assert self.timer.data['marks'][0]['interval'] == 0
19
- assert self.timer.data['marks'][0]['message'] == ''
20
-
21
- def test_data_five_marks(self):
22
- self.timer = timer.Timer()
23
- for i in range(5):
24
- self.timer.mark(str(i))
25
- assert len(self.timer.data['marks']) == 5
26
- assert [m['message'] for m in self.timer.data['marks']] == \
27
- ['0', '1', '2', '3', '4']
28
-
29
- def test_intervals(self):
30
- fake_time = MagicMock()
31
- with patch('teuthology.timer.time.time', fake_time):
32
- self.timer = timer.Timer()
33
- now = start_time = fake_time.return_value = time()
34
- intervals = [0, 1, 1, 2, 3, 5, 8]
35
- for i in intervals:
36
- now += i
37
- fake_time.return_value = now
38
- self.timer.mark(str(i))
39
-
40
- summed_intervals = [sum(intervals[:x + 1]) for x in range(len(intervals))]
41
- result_intervals = [m['interval'] for m in self.timer.data['marks']]
42
- assert result_intervals == summed_intervals
43
- assert self.timer.data['start'] == \
44
- self.timer.get_datetime_string(start_time)
45
- assert self.timer.data['end'] == \
46
- self.timer.get_datetime_string(start_time + summed_intervals[-1])
47
- assert [m['message'] for m in self.timer.data['marks']] == \
48
- [str(i) for i in intervals]
49
- assert self.timer.data['elapsed'] == summed_intervals[-1]
50
-
51
- def test_write(self):
52
- _path = '/path'
53
- _safe_dump = MagicMock(name='safe_dump')
54
- with patch('teuthology.timer.yaml.safe_dump', _safe_dump):
55
- with patch('teuthology.timer.open', mock_open(), create=True) as _open:
56
- self.timer = timer.Timer(path=_path)
57
- assert self.timer.path == _path
58
- self.timer.write()
59
- _open.assert_called_once_with(_path, 'w')
60
- _safe_dump.assert_called_once_with(
61
- dict(),
62
- _open.return_value.__enter__.return_value,
63
- default_flow_style=False,
64
- )
65
-
66
- def test_sync(self):
67
- _path = '/path'
68
- _safe_dump = MagicMock(name='safe_dump')
69
- with patch('teuthology.timer.yaml.safe_dump', _safe_dump):
70
- with patch('teuthology.timer.open', mock_open(), create=True) as _open:
71
- self.timer = timer.Timer(path=_path, sync=True)
72
- assert self.timer.path == _path
73
- assert self.timer.sync is True
74
- self.timer.mark()
75
- _open.assert_called_once_with(_path, 'w')
76
- _safe_dump.assert_called_once_with(
77
- self.timer.data,
78
- _open.return_value.__enter__.return_value,
79
- default_flow_style=False,
80
- )
@@ -1,84 +0,0 @@
1
- from unittest.mock import patch, Mock
2
-
3
- import teuthology.lock.util
4
- from teuthology import provision
5
-
6
-
7
- class TestVpsOsVersionParamCheck(object):
8
-
9
- def setup(self):
10
- self.fake_ctx = Mock()
11
- self.fake_ctx.machine_type = 'vps'
12
- self.fake_ctx.num_to_lock = 1
13
- self.fake_ctx.lock = False
14
-
15
- def fake_downburst_executable():
16
- return ''
17
-
18
- self.fake_downburst_executable = fake_downburst_executable
19
-
20
- def test_ubuntu_precise(self):
21
- self.fake_ctx.os_type = 'ubuntu'
22
- self.fake_ctx.os_version = 'precise'
23
- with patch.multiple(
24
- provision.downburst,
25
- downburst_executable=self.fake_downburst_executable,
26
- ):
27
- check_value = teuthology.lock.util.vps_version_or_type_valid(
28
- self.fake_ctx.machine_type,
29
- self.fake_ctx.os_type,
30
- self.fake_ctx.os_version)
31
-
32
- assert check_value
33
-
34
- def test_ubuntu_number(self):
35
- self.fake_ctx.os_type = 'ubuntu'
36
- self.fake_ctx.os_version = '12.04'
37
- with patch.multiple(
38
- provision.downburst,
39
- downburst_executable=self.fake_downburst_executable,
40
- ):
41
- check_value = teuthology.lock.util.vps_version_or_type_valid(
42
- self.fake_ctx.machine_type,
43
- self.fake_ctx.os_type,
44
- self.fake_ctx.os_version)
45
- assert check_value
46
-
47
- def test_mixup(self):
48
- self.fake_ctx.os_type = '6.5'
49
- self.fake_ctx.os_version = 'rhel'
50
- with patch.multiple(
51
- provision.downburst,
52
- downburst_executable=self.fake_downburst_executable,
53
- ):
54
- check_value = teuthology.lock.util.vps_version_or_type_valid(
55
- self.fake_ctx.machine_type,
56
- self.fake_ctx.os_type,
57
- self.fake_ctx.os_version)
58
- assert not check_value
59
-
60
- def test_bad_type(self):
61
- self.fake_ctx.os_type = 'aardvark'
62
- self.fake_ctx.os_version = '6.5'
63
- with patch.multiple(
64
- provision.downburst,
65
- downburst_executable=self.fake_downburst_executable,
66
- ):
67
- check_value = teuthology.lock.util.vps_version_or_type_valid(
68
- self.fake_ctx.machine_type,
69
- self.fake_ctx.os_type,
70
- self.fake_ctx.os_version)
71
- assert not check_value
72
-
73
- def test_bad_version(self):
74
- self.fake_ctx.os_type = 'rhel'
75
- self.fake_ctx.os_version = 'vampire_bat'
76
- with patch.multiple(
77
- provision.downburst,
78
- downburst_executable=self.fake_downburst_executable,
79
- ):
80
- check_value = teuthology.lock.util.vps_version_or_type_valid(
81
- self.fake_ctx.machine_type,
82
- self.fake_ctx.os_type,
83
- self.fake_ctx.os_version)
84
- assert not check_value