teuthology 1.0.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 (172) hide show
  1. scripts/describe.py +1 -0
  2. scripts/dispatcher.py +62 -0
  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/run.py +4 -0
  9. scripts/schedule.py +4 -0
  10. scripts/suite.py +61 -16
  11. scripts/supervisor.py +44 -0
  12. scripts/update_inventory.py +10 -4
  13. scripts/wait.py +31 -0
  14. teuthology/__init__.py +24 -21
  15. teuthology/beanstalk.py +4 -3
  16. teuthology/config.py +17 -6
  17. teuthology/contextutil.py +18 -14
  18. teuthology/describe_tests.py +25 -18
  19. teuthology/dispatcher/__init__.py +365 -0
  20. teuthology/dispatcher/supervisor.py +374 -0
  21. teuthology/exceptions.py +54 -0
  22. teuthology/exporter.py +347 -0
  23. teuthology/kill.py +76 -75
  24. teuthology/lock/cli.py +16 -7
  25. teuthology/lock/ops.py +276 -70
  26. teuthology/lock/query.py +61 -44
  27. teuthology/ls.py +9 -18
  28. teuthology/misc.py +152 -137
  29. teuthology/nuke/__init__.py +12 -351
  30. teuthology/openstack/__init__.py +4 -3
  31. teuthology/openstack/openstack-centos-7.0-user-data.txt +1 -1
  32. teuthology/openstack/openstack-centos-7.1-user-data.txt +1 -1
  33. teuthology/openstack/openstack-centos-7.2-user-data.txt +1 -1
  34. teuthology/openstack/openstack-debian-8.0-user-data.txt +1 -1
  35. teuthology/openstack/openstack-opensuse-42.1-user-data.txt +1 -1
  36. teuthology/openstack/openstack-teuthology.cron +0 -1
  37. teuthology/orchestra/cluster.py +51 -9
  38. teuthology/orchestra/connection.py +23 -16
  39. teuthology/orchestra/console.py +111 -50
  40. teuthology/orchestra/daemon/cephadmunit.py +23 -5
  41. teuthology/orchestra/daemon/state.py +10 -3
  42. teuthology/orchestra/daemon/systemd.py +10 -8
  43. teuthology/orchestra/opsys.py +32 -11
  44. teuthology/orchestra/remote.py +369 -152
  45. teuthology/orchestra/run.py +21 -12
  46. teuthology/packaging.py +54 -15
  47. teuthology/provision/__init__.py +30 -10
  48. teuthology/provision/cloud/openstack.py +12 -6
  49. teuthology/provision/cloud/util.py +1 -2
  50. teuthology/provision/downburst.py +83 -29
  51. teuthology/provision/fog.py +68 -20
  52. teuthology/provision/openstack.py +5 -4
  53. teuthology/provision/pelagos.py +13 -5
  54. teuthology/repo_utils.py +91 -44
  55. teuthology/report.py +57 -35
  56. teuthology/results.py +5 -3
  57. teuthology/run.py +21 -15
  58. teuthology/run_tasks.py +114 -40
  59. teuthology/schedule.py +4 -3
  60. teuthology/scrape.py +28 -22
  61. teuthology/suite/__init__.py +75 -46
  62. teuthology/suite/build_matrix.py +34 -24
  63. teuthology/suite/fragment-merge.lua +105 -0
  64. teuthology/suite/matrix.py +31 -2
  65. teuthology/suite/merge.py +175 -0
  66. teuthology/suite/placeholder.py +8 -8
  67. teuthology/suite/run.py +204 -102
  68. teuthology/suite/util.py +67 -211
  69. teuthology/task/__init__.py +1 -1
  70. teuthology/task/ansible.py +101 -31
  71. teuthology/task/buildpackages.py +2 -2
  72. teuthology/task/ceph_ansible.py +13 -6
  73. teuthology/task/cephmetrics.py +2 -1
  74. teuthology/task/clock.py +33 -14
  75. teuthology/task/exec.py +18 -0
  76. teuthology/task/hadoop.py +2 -2
  77. teuthology/task/install/__init__.py +51 -22
  78. teuthology/task/install/bin/adjust-ulimits +16 -0
  79. teuthology/task/install/bin/daemon-helper +114 -0
  80. teuthology/task/install/bin/stdin-killer +263 -0
  81. teuthology/task/install/deb.py +24 -4
  82. teuthology/task/install/redhat.py +36 -32
  83. teuthology/task/install/rpm.py +41 -14
  84. teuthology/task/install/util.py +48 -22
  85. teuthology/task/internal/__init__.py +69 -11
  86. teuthology/task/internal/edit_sudoers.sh +10 -0
  87. teuthology/task/internal/lock_machines.py +3 -133
  88. teuthology/task/internal/redhat.py +48 -28
  89. teuthology/task/internal/syslog.py +31 -8
  90. teuthology/task/kernel.py +155 -147
  91. teuthology/task/lockfile.py +1 -1
  92. teuthology/task/mpi.py +10 -10
  93. teuthology/task/pcp.py +1 -1
  94. teuthology/task/selinux.py +17 -8
  95. teuthology/task/ssh_keys.py +6 -6
  96. teuthology/task/tests/__init__.py +137 -77
  97. teuthology/task/tests/test_fetch_coredumps.py +116 -0
  98. teuthology/task/tests/test_run.py +4 -4
  99. teuthology/timer.py +3 -3
  100. teuthology/util/loggerfile.py +19 -0
  101. teuthology/util/scanner.py +159 -0
  102. teuthology/util/sentry.py +52 -0
  103. teuthology/util/time.py +52 -0
  104. teuthology-1.2.0.data/scripts/adjust-ulimits +16 -0
  105. teuthology-1.2.0.data/scripts/daemon-helper +114 -0
  106. teuthology-1.2.0.data/scripts/stdin-killer +263 -0
  107. teuthology-1.2.0.dist-info/METADATA +89 -0
  108. teuthology-1.2.0.dist-info/RECORD +174 -0
  109. {teuthology-1.0.0.dist-info → teuthology-1.2.0.dist-info}/WHEEL +1 -1
  110. {teuthology-1.0.0.dist-info → teuthology-1.2.0.dist-info}/entry_points.txt +5 -2
  111. scripts/nuke.py +0 -45
  112. scripts/worker.py +0 -37
  113. teuthology/nuke/actions.py +0 -456
  114. teuthology/openstack/test/__init__.py +0 -0
  115. teuthology/openstack/test/openstack-integration.py +0 -286
  116. teuthology/openstack/test/test_config.py +0 -35
  117. teuthology/openstack/test/test_openstack.py +0 -1695
  118. teuthology/orchestra/test/__init__.py +0 -0
  119. teuthology/orchestra/test/integration/__init__.py +0 -0
  120. teuthology/orchestra/test/integration/test_integration.py +0 -94
  121. teuthology/orchestra/test/test_cluster.py +0 -240
  122. teuthology/orchestra/test/test_connection.py +0 -106
  123. teuthology/orchestra/test/test_console.py +0 -217
  124. teuthology/orchestra/test/test_opsys.py +0 -404
  125. teuthology/orchestra/test/test_remote.py +0 -185
  126. teuthology/orchestra/test/test_run.py +0 -286
  127. teuthology/orchestra/test/test_systemd.py +0 -54
  128. teuthology/orchestra/test/util.py +0 -12
  129. teuthology/sentry.py +0 -18
  130. teuthology/test/__init__.py +0 -0
  131. teuthology/test/fake_archive.py +0 -107
  132. teuthology/test/fake_fs.py +0 -92
  133. teuthology/test/integration/__init__.py +0 -0
  134. teuthology/test/integration/test_suite.py +0 -86
  135. teuthology/test/task/__init__.py +0 -205
  136. teuthology/test/task/test_ansible.py +0 -624
  137. teuthology/test/task/test_ceph_ansible.py +0 -176
  138. teuthology/test/task/test_console_log.py +0 -88
  139. teuthology/test/task/test_install.py +0 -337
  140. teuthology/test/task/test_internal.py +0 -57
  141. teuthology/test/task/test_kernel.py +0 -243
  142. teuthology/test/task/test_pcp.py +0 -379
  143. teuthology/test/task/test_selinux.py +0 -35
  144. teuthology/test/test_config.py +0 -189
  145. teuthology/test/test_contextutil.py +0 -68
  146. teuthology/test/test_describe_tests.py +0 -316
  147. teuthology/test/test_email_sleep_before_teardown.py +0 -81
  148. teuthology/test/test_exit.py +0 -97
  149. teuthology/test/test_get_distro.py +0 -47
  150. teuthology/test/test_get_distro_version.py +0 -47
  151. teuthology/test/test_get_multi_machine_types.py +0 -27
  152. teuthology/test/test_job_status.py +0 -60
  153. teuthology/test/test_ls.py +0 -48
  154. teuthology/test/test_misc.py +0 -368
  155. teuthology/test/test_nuke.py +0 -232
  156. teuthology/test/test_packaging.py +0 -763
  157. teuthology/test/test_parallel.py +0 -28
  158. teuthology/test/test_repo_utils.py +0 -204
  159. teuthology/test/test_report.py +0 -77
  160. teuthology/test/test_results.py +0 -155
  161. teuthology/test/test_run.py +0 -238
  162. teuthology/test/test_safepath.py +0 -55
  163. teuthology/test/test_schedule.py +0 -45
  164. teuthology/test/test_scrape.py +0 -167
  165. teuthology/test/test_timer.py +0 -80
  166. teuthology/test/test_vps_os_vers_parameter_checking.py +0 -84
  167. teuthology/test/test_worker.py +0 -303
  168. teuthology/worker.py +0 -339
  169. teuthology-1.0.0.dist-info/METADATA +0 -76
  170. teuthology-1.0.0.dist-info/RECORD +0 -210
  171. {teuthology-1.0.0.dist-info → teuthology-1.2.0.dist-info}/LICENSE +0 -0
  172. {teuthology-1.0.0.dist-info → teuthology-1.2.0.dist-info}/top_level.txt +0 -0
@@ -1,238 +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
- m_fetch_qa_suite.return_value = "/some/other/suite/path"
115
- result = run.fetch_tasks_if_needed(config)
116
- m_fetch_qa_suite.assert_called_with("feature_branch")
117
- assert result == "/some/other/suite/path"
118
-
119
- @patch("teuthology.run.get_status")
120
- @patch("teuthology.run.nuke")
121
- @patch("yaml.safe_dump")
122
- @patch("teuthology.report.try_push_job_info")
123
- @patch("teuthology.run.email_results")
124
- @patch("teuthology.run.open")
125
- @patch("sys.exit")
126
- 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):
127
- m_get_status.return_value = "fail"
128
- fake_ctx = Mock()
129
- summary = {"failure_reason": "reasons"}
130
- summary_dump = "failure_reason: reasons\n"
131
- config = {"nuke-on-error": True, "email-on-error": True}
132
- config_dump = "nuke-on-error: true\nemail-on-error: true\n"
133
- m_safe_dump.side_effect = [None, summary_dump, config_dump]
134
- run.report_outcome(config, "the/archive/path", summary, fake_ctx)
135
- assert m_nuke.called
136
- m_try_push_job_info.assert_called_with(config, summary)
137
- m_open.assert_called_with("the/archive/path/summary.yaml", "w")
138
- assert m_email_results.called
139
- assert m_open.called
140
- assert m_sys_exit.called
141
-
142
- @patch("teuthology.run.set_up_logging")
143
- @patch("teuthology.run.setup_config")
144
- @patch("teuthology.run.get_user")
145
- @patch("teuthology.run.write_initial_metadata")
146
- @patch("teuthology.report.try_push_job_info")
147
- @patch("teuthology.run.get_machine_type")
148
- @patch("teuthology.run.get_summary")
149
- @patch("yaml.safe_dump")
150
- @patch("teuthology.run.validate_tasks")
151
- @patch("teuthology.run.get_initial_tasks")
152
- @patch("teuthology.run.fetch_tasks_if_needed")
153
- @patch("teuthology.run.run_tasks")
154
- @patch("teuthology.run.report_outcome")
155
- def test_main(self, m_report_outcome, m_run_tasks, m_fetch_tasks_if_needed, m_get_initial_tasks, m_validate_tasks,
156
- m_safe_dump, m_get_summary, m_get_machine_type, m_try_push_job_info, m_write_initial_metadata,
157
- m_get_user, m_setup_config, m_set_up_logging):
158
- """ This really should be an integration test of some sort. """
159
- config = {"job_id": 1}
160
- m_setup_config.return_value = config
161
- m_get_machine_type.return_value = "machine_type"
162
- doc = scripts_run.__doc__
163
- args = docopt.docopt(doc, [
164
- "--verbose",
165
- "--archive", "some/archive/dir",
166
- "--description", "the_description",
167
- "--lock",
168
- "--os-type", "os_type",
169
- "--os-version", "os_version",
170
- "--block",
171
- "--name", "the_name",
172
- "--suite-path", "some/suite/dir",
173
- "path/to/config.yml",
174
- ])
175
- m_get_user.return_value = "the_owner"
176
- m_get_summary.return_value = dict(success=True, owner="the_owner", description="the_description")
177
- m_validate_tasks.return_value = ['task3']
178
- m_get_initial_tasks.return_value = ['task1', 'task2']
179
- m_fetch_tasks_if_needed.return_value = "some/suite/dir"
180
- run.main(args)
181
- m_set_up_logging.assert_called_with(True, "some/archive/dir")
182
- m_setup_config.assert_called_with(["path/to/config.yml"])
183
- m_write_initial_metadata.assert_called_with(
184
- "some/archive/dir",
185
- config,
186
- "the_name",
187
- "the_description",
188
- "the_owner"
189
- )
190
- m_try_push_job_info.assert_called_with(config, dict(status='running'))
191
- m_get_machine_type.assert_called_with(None, config)
192
- m_get_summary.assert_called_with("the_owner", "the_description")
193
- m_get_initial_tasks.assert_called_with(True, config, "machine_type")
194
- m_fetch_tasks_if_needed.assert_called_with(config)
195
- assert m_report_outcome.called
196
- args, kwargs = m_run_tasks.call_args
197
- fake_ctx = kwargs["ctx"]._conf
198
- # fields that must be in ctx for the tasks to behave
199
- expected_ctx = ["verbose", "archive", "description", "owner", "lock", "machine_type", "os_type", "os_version",
200
- "block", "name", "suite_path", "config", "summary"]
201
- for key in expected_ctx:
202
- assert key in fake_ctx
203
- assert isinstance(fake_ctx["config"], dict)
204
- assert isinstance(fake_ctx["summary"], dict)
205
- assert "tasks" in fake_ctx["config"]
206
- # ensures that values missing in args are added with the correct value
207
- assert fake_ctx["owner"] == "the_owner"
208
- assert fake_ctx["machine_type"] == "machine_type"
209
- # ensures os_type and os_version are property overwritten
210
- assert fake_ctx["config"]["os_type"] == "os_type"
211
- assert fake_ctx["config"]["os_version"] == "os_version"
212
-
213
- def test_get_teuthology_command(self):
214
- doc = scripts_run.__doc__
215
- args = docopt.docopt(doc, [
216
- "--archive", "some/archive/dir",
217
- "--description", "the_description",
218
- "--lock",
219
- "--block",
220
- "--name", "the_name",
221
- "--suite-path", "some/suite/dir",
222
- "path/to/config.yml", "path/to/config2.yaml",
223
- ])
224
- result = run.get_teuthology_command(args)
225
- result = result.split()
226
- expected = [
227
- "teuthology",
228
- "path/to/config.yml", "path/to/config2.yaml",
229
- "--suite-path", "some/suite/dir",
230
- "--lock",
231
- "--description", "the_description",
232
- "--name", "the_name",
233
- "--block",
234
- "--archive", "some/archive/dir",
235
- ]
236
- assert len(result) == len(expected)
237
- for arg in expected:
238
- 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