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,28 +0,0 @@
1
- from teuthology.parallel import parallel
2
-
3
-
4
- def identity(item, input_set=None, remove=False):
5
- if input_set is not None:
6
- assert item in input_set
7
- if remove:
8
- input_set.remove(item)
9
- return item
10
-
11
-
12
- class TestParallel(object):
13
- def test_basic(self):
14
- in_set = set(range(10))
15
- with parallel() as para:
16
- for i in in_set:
17
- para.spawn(identity, i, in_set, remove=True)
18
- assert para.any_spawned is True
19
- assert para.count == len(in_set)
20
-
21
- def test_result(self):
22
- in_set = set(range(10))
23
- with parallel() as para:
24
- for i in in_set:
25
- para.spawn(identity, i, in_set)
26
- for result in para:
27
- in_set.remove(result)
28
-
@@ -1,225 +0,0 @@
1
- import logging
2
- import unittest.mock as mock
3
- import os
4
- import os.path
5
- from pytest import raises, mark
6
- import shutil
7
- import subprocess
8
- import tempfile
9
-
10
- from teuthology.exceptions import BranchNotFoundError, CommitNotFoundError
11
- from teuthology import repo_utils
12
- from teuthology import parallel
13
- repo_utils.log.setLevel(logging.WARNING)
14
-
15
-
16
- class TestRepoUtils(object):
17
-
18
- @classmethod
19
- def setup_class(cls):
20
- cls.temp_path = tempfile.mkdtemp(prefix='test_repo-')
21
- cls.dest_path = cls.temp_path + '/empty_dest'
22
- cls.src_path = cls.temp_path + '/empty_src'
23
-
24
- if 'TEST_ONLINE' in os.environ:
25
- cls.repo_url = 'https://github.com/ceph/empty.git'
26
- cls.commit = '71245d8e454a06a38a00bff09d8f19607c72e8bf'
27
- else:
28
- cls.repo_url = 'file://' + cls.src_path
29
- cls.commit = None
30
-
31
- @classmethod
32
- def teardown_class(cls):
33
- shutil.rmtree(cls.temp_path)
34
-
35
- def setup_method(self, method):
36
- assert not os.path.exists(self.dest_path)
37
- proc = subprocess.Popen(
38
- ('git', 'init', self.src_path),
39
- stdout=subprocess.PIPE,
40
- )
41
- assert proc.wait() == 0
42
- proc = subprocess.Popen(
43
- ('git', 'config', 'user.email', 'test@ceph.com'),
44
- cwd=self.src_path,
45
- stdout=subprocess.PIPE,
46
- )
47
- assert proc.wait() == 0
48
- proc = subprocess.Popen(
49
- ('git', 'config', 'user.name', 'Test User'),
50
- cwd=self.src_path,
51
- stdout=subprocess.PIPE,
52
- )
53
- assert proc.wait() == 0
54
- proc = subprocess.Popen(
55
- ('git', 'commit', '--allow-empty', '--allow-empty-message',
56
- '--no-edit'),
57
- cwd=self.src_path,
58
- stdout=subprocess.PIPE,
59
- )
60
- assert proc.wait() == 0
61
- if not self.commit:
62
- result = subprocess.check_output(
63
- 'git rev-parse HEAD',
64
- shell=True,
65
- cwd=self.src_path,
66
- ).split()
67
- assert result
68
- self.commit = result[0].decode()
69
-
70
- def teardown_method(self, method):
71
- shutil.rmtree(self.dest_path, ignore_errors=True)
72
-
73
- def test_clone_repo_existing_branch(self):
74
- repo_utils.clone_repo(self.repo_url, self.dest_path, 'master', self.commit)
75
- assert os.path.exists(self.dest_path)
76
-
77
- def test_clone_repo_non_existing_branch(self):
78
- with raises(BranchNotFoundError):
79
- repo_utils.clone_repo(self.repo_url, self.dest_path, 'nobranch', self.commit)
80
- assert not os.path.exists(self.dest_path)
81
-
82
- def test_fetch_no_repo(self):
83
- fake_dest_path = self.temp_path + '/not_a_repo'
84
- assert not os.path.exists(fake_dest_path)
85
- with raises(OSError):
86
- repo_utils.fetch(fake_dest_path)
87
- assert not os.path.exists(fake_dest_path)
88
-
89
- def test_fetch_noop(self):
90
- repo_utils.clone_repo(self.repo_url, self.dest_path, 'master', self.commit)
91
- repo_utils.fetch(self.dest_path)
92
- assert os.path.exists(self.dest_path)
93
-
94
- def test_fetch_branch_no_repo(self):
95
- fake_dest_path = self.temp_path + '/not_a_repo'
96
- assert not os.path.exists(fake_dest_path)
97
- with raises(OSError):
98
- repo_utils.fetch_branch(fake_dest_path, 'master')
99
- assert not os.path.exists(fake_dest_path)
100
-
101
- def test_fetch_branch_fake_branch(self):
102
- repo_utils.clone_repo(self.repo_url, self.dest_path, 'master', self.commit)
103
- with raises(BranchNotFoundError):
104
- repo_utils.fetch_branch(self.dest_path, 'nobranch')
105
-
106
- @mark.parametrize('git_str',
107
- ["fatal: couldn't find remote ref",
108
- "fatal: Couldn't find remote ref"])
109
- @mock.patch('subprocess.Popen')
110
- def test_fetch_branch_different_git_versions(self, mock_popen, git_str):
111
- """
112
- Newer git versions return a lower case string
113
- See: https://github.com/git/git/commit/0b9c3afdbfb629363
114
- """
115
- branch_name = 'nobranch'
116
- process_mock = mock.Mock()
117
- attrs = {
118
- 'wait.return_value': 1,
119
- 'stdout.read.return_value': f"{git_str} {branch_name}".encode(),
120
- }
121
- process_mock.configure_mock(**attrs)
122
- mock_popen.return_value = process_mock
123
- with raises(BranchNotFoundError):
124
- repo_utils.fetch_branch('', branch_name)
125
-
126
- def test_enforce_existing_branch(self):
127
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
128
- 'master')
129
- assert os.path.exists(self.dest_path)
130
-
131
- def test_enforce_existing_commit(self):
132
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
133
- 'master', self.commit)
134
- assert os.path.exists(self.dest_path)
135
-
136
- def test_enforce_non_existing_branch(self):
137
- with raises(BranchNotFoundError):
138
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
139
- 'blah', self.commit)
140
- assert not os.path.exists(self.dest_path)
141
-
142
- def test_enforce_non_existing_commit(self):
143
- with raises(CommitNotFoundError):
144
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
145
- 'master', 'c69e90807d222c1719c45c8c758bf6fac3d985f1')
146
- assert not os.path.exists(self.dest_path)
147
-
148
- def test_enforce_multiple_calls_same_branch(self):
149
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
150
- 'master', self.commit)
151
- assert os.path.exists(self.dest_path)
152
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
153
- 'master', self.commit)
154
- assert os.path.exists(self.dest_path)
155
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
156
- 'master', self.commit)
157
- assert os.path.exists(self.dest_path)
158
-
159
- def test_enforce_multiple_calls_different_branches(self):
160
- with raises(BranchNotFoundError):
161
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
162
- 'blah1')
163
- assert not os.path.exists(self.dest_path)
164
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
165
- 'master', self.commit)
166
- assert os.path.exists(self.dest_path)
167
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
168
- 'master', self.commit)
169
- assert os.path.exists(self.dest_path)
170
- with raises(BranchNotFoundError):
171
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
172
- 'blah2')
173
- assert not os.path.exists(self.dest_path)
174
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path,
175
- 'master', self.commit)
176
- assert os.path.exists(self.dest_path)
177
-
178
- def test_enforce_invalid_branch(self):
179
- with raises(ValueError):
180
- repo_utils.enforce_repo_state(self.repo_url, self.dest_path, 'a b', self.commit)
181
-
182
- def test_simultaneous_access(self):
183
- count = 5
184
- with parallel.parallel() as p:
185
- for i in range(count):
186
- p.spawn(repo_utils.enforce_repo_state, self.repo_url,
187
- self.dest_path, 'master', self.commit)
188
- for result in p:
189
- assert result is None
190
-
191
- def test_simultaneous_access_different_branches(self):
192
- branches = [('master', self.commit), ('master', self.commit), ('nobranch', 'nocommit'),
193
- ('nobranch', 'nocommit'), ('master', self.commit), ('nobranch', 'nocommit')]
194
-
195
- with parallel.parallel() as p:
196
- for branch, commit in branches:
197
- if branch == 'master':
198
- p.spawn(repo_utils.enforce_repo_state, self.repo_url,
199
- self.dest_path, branch, commit)
200
- else:
201
- dest_path = self.dest_path + '_' + branch
202
-
203
- def func():
204
- repo_utils.enforce_repo_state(
205
- self.repo_url, dest_path,
206
- branch, commit)
207
- p.spawn(
208
- raises,
209
- BranchNotFoundError,
210
- func,
211
- )
212
- for result in p:
213
- pass
214
-
215
- URLS_AND_DIRNAMES = [
216
- ('git@git.ceph.com/ceph-qa-suite.git', 'git.ceph.com_ceph-qa-suite'),
217
- ('git://git.ceph.com/ceph-qa-suite.git', 'git.ceph.com_ceph-qa-suite'),
218
- ('https://github.com/ceph/ceph', 'github.com_ceph_ceph'),
219
- ('https://github.com/liewegas/ceph.git', 'github.com_liewegas_ceph'),
220
- ('file:///my/dir/has/ceph.git', 'my_dir_has_ceph'),
221
- ]
222
-
223
- @mark.parametrize("input_, expected", URLS_AND_DIRNAMES)
224
- def test_url_to_dirname(self, input_, expected):
225
- assert repo_utils.url_to_dirname(input_) == expected
@@ -1,77 +0,0 @@
1
- import yaml
2
- import json
3
- from teuthology.test import fake_archive
4
- from teuthology import report
5
-
6
-
7
- class TestSerializer(object):
8
- def setup(self):
9
- self.archive = fake_archive.FakeArchive()
10
- self.archive.setup()
11
- self.archive_base = self.archive.archive_base
12
- self.reporter = report.ResultsReporter(archive_base=self.archive_base)
13
-
14
- def teardown(self):
15
- self.archive.teardown()
16
-
17
- def test_all_runs_one_run(self):
18
- run_name = "test_all_runs"
19
- yaml_path = "examples/3node_ceph.yaml"
20
- job_count = 3
21
- self.archive.create_fake_run(run_name, job_count, yaml_path)
22
- assert [run_name] == self.reporter.serializer.all_runs
23
-
24
- def test_all_runs_three_runs(self):
25
- run_count = 3
26
- runs = {}
27
- for i in range(run_count):
28
- run_name = "run #%s" % i
29
- yaml_path = "examples/3node_ceph.yaml"
30
- job_count = 3
31
- job_ids = self.archive.create_fake_run(
32
- run_name,
33
- job_count,
34
- yaml_path)
35
- runs[run_name] = job_ids
36
- assert sorted(runs.keys()) == sorted(self.reporter.serializer.all_runs)
37
-
38
- def test_jobs_for_run(self):
39
- run_name = "test_jobs_for_run"
40
- yaml_path = "examples/3node_ceph.yaml"
41
- job_count = 3
42
- jobs = self.archive.create_fake_run(run_name, job_count, yaml_path)
43
- job_ids = [str(job['job_id']) for job in jobs]
44
-
45
- got_jobs = self.reporter.serializer.jobs_for_run(run_name)
46
- assert sorted(job_ids) == sorted(got_jobs.keys())
47
-
48
- def test_running_jobs_for_run(self):
49
- run_name = "test_jobs_for_run"
50
- yaml_path = "examples/3node_ceph.yaml"
51
- job_count = 10
52
- num_hung = 3
53
- self.archive.create_fake_run(run_name, job_count, yaml_path,
54
- num_hung=num_hung)
55
-
56
- got_jobs = self.reporter.serializer.running_jobs_for_run(run_name)
57
- assert len(got_jobs) == num_hung
58
-
59
- def test_json_for_job(self):
60
- run_name = "test_json_for_job"
61
- yaml_path = "examples/3node_ceph.yaml"
62
- job_count = 1
63
- jobs = self.archive.create_fake_run(run_name, job_count, yaml_path)
64
- job = jobs[0]
65
-
66
- with open(yaml_path) as yaml_file:
67
- obj_from_yaml = yaml.safe_load(yaml_file)
68
- full_obj = obj_from_yaml.copy()
69
- full_obj.update(job['info'])
70
- full_obj.update(job['summary'])
71
-
72
- out_json = self.reporter.serializer.json_for_job(
73
- run_name, str(job['job_id']))
74
- out_obj = json.loads(out_json)
75
- assert full_obj == out_obj
76
-
77
-
@@ -1,155 +0,0 @@
1
- import textwrap
2
- from teuthology.config import config
3
- from teuthology import results
4
- from teuthology import report
5
-
6
- from unittest.mock import patch, DEFAULT
7
-
8
-
9
- class TestResultsEmail(object):
10
- reference = {
11
- 'run_name': 'test_name',
12
- 'jobs': [
13
- # Running
14
- {'description': 'description for job with name test_name',
15
- 'job_id': 30481,
16
- 'name': 'test_name',
17
- 'log_href': 'http://qa-proxy.ceph.com/teuthology/test_name/30481/teuthology.log', # noqa
18
- 'owner': 'job@owner',
19
- 'duration': None,
20
- 'status': 'running',
21
- },
22
- # Waiting
23
- {'description': 'description for job with name test_name',
24
- 'job_id': 62965,
25
- 'name': 'test_name',
26
- 'log_href': 'http://qa-proxy.ceph.com/teuthology/test_name/30481/teuthology.log', # noqa
27
- 'owner': 'job@owner',
28
- 'duration': None,
29
- 'status': 'waiting',
30
- },
31
- # Queued
32
- {'description': 'description for job with name test_name',
33
- 'job_id': 79063,
34
- 'name': 'test_name',
35
- 'log_href': 'http://qa-proxy.ceph.com/teuthology/test_name/30481/teuthology.log', # noqa
36
- 'owner': 'job@owner',
37
- 'duration': None,
38
- 'status': 'queued',
39
- },
40
- # Failed
41
- {'description': 'description for job with name test_name',
42
- 'job_id': 88979,
43
- 'name': 'test_name',
44
- 'log_href': 'http://qa-proxy.ceph.com/teuthology/test_name/88979/teuthology.log', # noqa
45
- 'owner': 'job@owner',
46
- 'duration': 35190,
47
- 'success': False,
48
- 'status': 'fail',
49
- 'failure_reason': 'Failure reason!',
50
- },
51
- # Dead
52
- {'description': 'description for job with name test_name',
53
- 'job_id': 69152,
54
- 'name': 'test_name',
55
- 'log_href': 'http://qa-proxy.ceph.com/teuthology/test_name/69152/teuthology.log', # noqa
56
- 'owner': 'job@owner',
57
- 'duration': 5225,
58
- 'success': False,
59
- 'status': 'dead',
60
- 'failure_reason': 'Dead reason!',
61
- },
62
- # Passed
63
- {'description': 'description for job with name test_name',
64
- 'job_id': 68369,
65
- 'name': 'test_name',
66
- 'log_href': 'http://qa-proxy.ceph.com/teuthology/test_name/68369/teuthology.log', # noqa
67
- 'owner': 'job@owner',
68
- 'duration': 33771,
69
- 'success': True,
70
- 'status': 'pass',
71
- },
72
- ],
73
- 'subject': '1 fail, 1 dead, 1 running, 1 waiting, 1 queued, 1 pass in test_name', # noqa
74
- 'body': textwrap.dedent("""
75
- Test Run: test_name
76
- =================================================================
77
- info: http://example.com/test_name/
78
- logs: http://qa-proxy.ceph.com/teuthology/test_name/
79
- failed: 1
80
- dead: 1
81
- running: 1
82
- waiting: 1
83
- queued: 1
84
- passed: 1
85
-
86
-
87
- Fail
88
- =================================================================
89
- [88979] description for job with name test_name
90
- -----------------------------------------------------------------
91
- time: 09:46:30
92
- info: http://example.com/test_name/88979/
93
- log: http://qa-proxy.ceph.com/teuthology/test_name/88979/
94
-
95
- Failure reason!
96
-
97
-
98
-
99
- Dead
100
- =================================================================
101
- [69152] description for job with name test_name
102
- -----------------------------------------------------------------
103
- time: 01:27:05
104
- info: http://example.com/test_name/69152/
105
- log: http://qa-proxy.ceph.com/teuthology/test_name/69152/
106
-
107
- Dead reason!
108
-
109
-
110
-
111
- Running
112
- =================================================================
113
- [30481] description for job with name test_name
114
- info: http://example.com/test_name/30481/
115
-
116
-
117
-
118
- Waiting
119
- =================================================================
120
- [62965] description for job with name test_name
121
- info: http://example.com/test_name/62965/
122
-
123
-
124
-
125
- Queued
126
- =================================================================
127
- [79063] description for job with name test_name
128
- info: http://example.com/test_name/79063/
129
-
130
-
131
-
132
- Pass
133
- =================================================================
134
- [68369] description for job with name test_name
135
- time: 09:22:51
136
- info: http://example.com/test_name/68369/
137
- """).strip(),
138
- }
139
-
140
- def setup(self):
141
- config.results_ui_server = "http://example.com/"
142
- config.archive_server = "http://qa-proxy.ceph.com/teuthology/"
143
-
144
- def test_build_email_body(self):
145
- run_name = self.reference['run_name']
146
- with patch.multiple(
147
- report,
148
- ResultsReporter=DEFAULT,
149
- ):
150
- reporter = report.ResultsReporter()
151
- reporter.get_jobs.return_value = self.reference['jobs']
152
- (subject, body) = results.build_email_body(
153
- run_name, _reporter=reporter)
154
- assert subject == self.reference['subject']
155
- assert body == self.reference['body']