Coverage for CIResults/tests/test_runconfigdiff.py: 100%

282 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-23 13:11 +0000

1from unittest.mock import patch, Mock, MagicMock, PropertyMock 

2from django.test import TestCase 

3from django.utils import timezone 

4from datetime import timedelta 

5 

6from CIResults.models import Component, Build, Test, Machine, RunConfig, TestSuite 

7from CIResults.models import TextStatus, TestResult 

8from CIResults.runconfigdiff import RunConfigResultsForTest, RunConfigResultsForTestDiff 

9from CIResults.runconfigdiff import RunConfigResultsForNotRunTest, ExecutionTime 

10 

11 

12class ExecutionTimeTests(TestCase): 

13 def test_empty(self): 

14 empty = ExecutionTime() 

15 

16 self.assertEqual(empty.minimum, None) 

17 self.assertEqual(empty.maximum, None) 

18 self.assertEqual(empty.count, 0) 

19 

20 def test_add__normal_case(self): 

21 val = ExecutionTime(23) + ExecutionTime(24) 

22 

23 self.assertEqual(val.minimum, 23) 

24 self.assertEqual(val.maximum, 24) 

25 self.assertEqual(str(val), "[23, 24] s") 

26 

27 def test_add__with_empty(self): 

28 val = ExecutionTime() + ExecutionTime(23) + ExecutionTime() 

29 self.assertEqual(val, ExecutionTime(23)) 

30 self.assertEqual(str(val), "[23] s") 

31 

32 def test_equal(self): 

33 # Check that arriving at the same result twice leads to values being equal 

34 val1 = ExecutionTime(23) + ExecutionTime(24) 

35 val2 = ExecutionTime(23) + ExecutionTime(24) 

36 self.assertEqual(val1, val2) 

37 

38 # Check that re-adding a value indeed does not result in the results being equal 

39 val2 += ExecutionTime(23) 

40 self.assertNotEqual(val1, val2) 

41 

42 def test_str__with_timedelta(self): 

43 self.assertEqual(str(ExecutionTime(timedelta(seconds=0.987654321))), "[0.99] s") 

44 self.assertEqual(str(ExecutionTime(timedelta(seconds=12345.987654321))), "[12345.99] s") 

45 

46 

47class RunConfigResultsForTestTests(TestCase): 

48 def __create_testsuite(self, name, statuses, acceptable_statuses=['pass'], public=True): 

49 testsuite = TestSuite.objects.create(name=name, description="nothing", public=public) 

50 

51 db_statuses = dict() 

52 for status_name in statuses: 

53 status = TextStatus.objects.create(testsuite=testsuite, name=status_name, 

54 vetted_on=timezone.now()) 

55 db_statuses[status_name] = status 

56 

57 for status_name in acceptable_statuses: 

58 testsuite.acceptable_statuses.add(db_statuses[status_name]) 

59 

60 return testsuite, db_statuses 

61 

62 def test_RunConfigResultsForTests_check_no_results(self): 

63 self.assertRaisesMessage(ValueError, "No results provided", RunConfigResultsForTest, []) 

64 

65 def test_RunConfigResultsForTests_check_single_result(self): 

66 self.testsuite1, self.testsuite1_statuses = self.__create_testsuite("testsuite1", 

67 ['pass', 'fail'], 

68 ['pass'], 

69 public=True) 

70 self.testsuite1_statuses["fail"].suppress() 

71 

72 test = Test.objects.create(name="Test", testsuite=self.testsuite1, public=True) 

73 result_pass = TestResult(id=1, test=test, status=self.testsuite1_statuses['pass']) 

74 result_fail = TestResult(id=2, test=test, status=self.testsuite1_statuses['fail']) 

75 

76 r = RunConfigResultsForTest([result_pass]) 

77 self.assertTrue(r.was_run) 

78 self.assertEqual(str(r), "pass") 

79 self.assertEqual(r, RunConfigResultsForTest([result_pass])) 

80 self.assertNotEqual(r, RunConfigResultsForTest([result_fail])) 

81 

82 # Now try with a suppressed status 

83 result_fail = TestResult(test=test, status=self.testsuite1_statuses['fail']) 

84 r = RunConfigResultsForTest([result_fail]) 

85 self.assertEqual(str(r), "{fail}") 

86 

87 def test_RunConfigResultsForTests_check_results_from_different_testsuites(self): 

88 self.testsuite1, self.testsuite1_statuses = self.__create_testsuite("testsuite1", 

89 ['pass'], [], 

90 public=True) 

91 self.testsuite2, self.testsuite2_statuses = self.__create_testsuite("testsuite2", 

92 ['pass'], [], 

93 public=True) 

94 

95 test1 = Test.objects.create(name="Test", testsuite=self.testsuite1, public=True) 

96 test2 = Test.objects.create(name="Test", testsuite=self.testsuite2, public=True) 

97 

98 result_pass_ts1 = TestResult(test=test1, status=self.testsuite1_statuses['pass']) 

99 result_pass_ts2 = TestResult(test=test2, status=self.testsuite2_statuses['pass']) 

100 

101 self.assertRaisesMessage(ValueError, "Results from multiple tests", 

102 RunConfigResultsForTest, [result_pass_ts1, result_pass_ts2]) 

103 

104 def test_RunConfigResultsForTests_check_two_results_same_status(self): 

105 self.testsuite1, self.testsuite1_statuses = self.__create_testsuite("testsuite1", 

106 ['pass', 'fail'], [], 

107 public=True) 

108 self.testsuite1_statuses["fail"].suppress() 

109 

110 test = Test.objects.create(name="Test", testsuite=self.testsuite1, public=True) 

111 result_pass1 = TestResult(id=1, test=test, status=self.testsuite1_statuses['pass']) 

112 result_pass2 = TestResult(id=2, test=test, status=self.testsuite1_statuses['pass']) 

113 result_fail = TestResult(id=3, test=test, status=self.testsuite1_statuses['fail']) 

114 

115 r = RunConfigResultsForTest([result_pass1, result_pass2]) 

116 self.assertEqual(str(r), "( 2 pass )") 

117 self.assertEqual(r, RunConfigResultsForTest([result_pass1, result_pass2])) 

118 self.assertNotEqual(r, RunConfigResultsForTest([result_pass1, result_fail])) 

119 

120 # Now try with a suppressed status 

121 result_fail1 = TestResult(test=test, status=self.testsuite1_statuses['fail']) 

122 result_fail2 = TestResult(test=test, status=self.testsuite1_statuses['fail']) 

123 r = RunConfigResultsForTest([result_fail1, result_fail2]) 

124 self.assertEqual(str(r), "( 2 {fail} )") 

125 

126 def test_RunConfigResultsForTests_check_same_statuses_but_different_bugs(self): 

127 self.testsuite1, self.testsuite1_statuses = self.__create_testsuite("testsuite1", 

128 ['pass', 'fail'], [], 

129 public=True) 

130 self.testsuite1_statuses["fail"].suppress() 

131 

132 test = Test.objects.create(name="Test", testsuite=self.testsuite1, public=True) 

133 result_pass = TestResult(test=test, status=self.testsuite1_statuses['pass']) 

134 result_fail = TestResult(test=test, status=self.testsuite1_statuses['fail']) 

135 

136 r1 = RunConfigResultsForTest([result_fail, result_pass]) 

137 r1.bugs_covering = set(['bug1', 'bug2']) 

138 

139 r2 = RunConfigResultsForTest([result_pass, result_fail]) 

140 r2.bugs_covering = set(['bug1', 'bug2']) 

141 

142 self.assertEqual(r1, r2) 

143 

144 r2.bugs_covering = set(['bug1', 'bug3']) 

145 self.assertNotEqual(r1, r2) 

146 

147 def test_RunConfigResultsForTests_check_two_results_different_status(self): 

148 self.testsuite1, self.testsuite1_statuses = self.__create_testsuite("testsuite1", 

149 ['pass', 'fail'], [], 

150 public=True) 

151 self.testsuite1_statuses["fail"].suppress() 

152 

153 test = Test.objects.create(name="Test", testsuite=self.testsuite1, public=True) 

154 result_pass1 = TestResult(id=1, test=test, status=self.testsuite1_statuses['pass']) 

155 result_pass2 = TestResult(id=2, test=test, status=self.testsuite1_statuses['pass']) 

156 result_fail = TestResult(id=3, test=test, status=self.testsuite1_statuses['fail']) 

157 

158 r = RunConfigResultsForTest([result_pass1, result_fail, result_pass2]) 

159 self.assertEqual(str(r), "( 1 {fail}, 2 pass )") 

160 self.assertEqual(r, RunConfigResultsForTest([result_pass1, result_pass2, result_fail])) 

161 self.assertEqual(r, RunConfigResultsForTest([result_pass1, result_fail])) 

162 

163 def test_RunConfigResultsForTests_check_not_runs_ignored(self): 

164 self.testsuite1, self.testsuite1_statuses = self.__create_testsuite("testsuite1", 

165 ['pass', 'fail', 'notrun'], 

166 [], public=True) 

167 self.testsuite1.notrun_status = self.testsuite1_statuses['notrun'] 

168 self.testsuite1.save() 

169 

170 test = Test.objects.create(name="Test", testsuite=self.testsuite1, public=True) 

171 result_pass = TestResult(id=1, test=test, status=self.testsuite1_statuses['pass']) 

172 result_notrun = TestResult(id=2, test=test, status=self.testsuite1_statuses['notrun']) 

173 result_fail = TestResult(id=3, test=test, status=self.testsuite1_statuses['fail']) 

174 

175 r = RunConfigResultsForTest([result_pass, result_notrun, result_fail]) 

176 self.assertEqual(str(r), "( 1 fail, 1 pass )") 

177 self.assertEqual(r, RunConfigResultsForTest([result_pass, result_fail])) 

178 

179 def test_RunConfigResultsForTests_check_only_not_runs(self): 

180 self.testsuite1, self.testsuite1_statuses = self.__create_testsuite("testsuite1", 

181 ['pass', 'fail', 'notrun'], 

182 [], public=True) 

183 self.testsuite1.notrun_status = self.testsuite1_statuses['notrun'] 

184 self.testsuite1.save() 

185 

186 test = Test.objects.create(name="Test", testsuite=self.testsuite1, public=True) 

187 result_notrun1 = TestResult(test=test, status=self.testsuite1_statuses['notrun']) 

188 result_notrun2 = TestResult(test=test, status=self.testsuite1_statuses['notrun']) 

189 result_notrun3 = TestResult(test=test, status=self.testsuite1_statuses['notrun']) 

190 

191 self.assertRaisesMessage(ValueError, "No results provided", 

192 RunConfigResultsForTest, [result_notrun1, result_notrun2, result_notrun3]) 

193 

194 def test_RunConfigResultsForTests_is_suppressed(self): 

195 self.testsuite1, self.testsuite1_statuses = self.__create_testsuite("testsuite1", 

196 ['pass', 'fail'], [], 

197 public=True) 

198 self.testsuite1.acceptable_statuses.add(self.testsuite1_statuses['pass']) 

199 

200 test = Test.objects.create(name="Test", testsuite=self.testsuite1, public=True) 

201 result_pass1 = TestResult(test=test, status=self.testsuite1_statuses['pass']) 

202 result_pass2 = TestResult(test=test, status=self.testsuite1_statuses['pass']) 

203 result_fail = TestResult(test=test, status=self.testsuite1_statuses['fail']) 

204 

205 # Try without suppressing fails 

206 r = RunConfigResultsForTest([result_pass1, result_fail, result_pass2]) 

207 self.assertFalse(r.is_suppressed) 

208 

209 # Try again, with fail suppressed 

210 self.testsuite1_statuses["fail"].suppress() 

211 r = RunConfigResultsForTest([result_pass1, result_fail, result_pass2]) 

212 self.assertTrue(r.is_suppressed) 

213 

214 

215class RunConfigResultsForTestDiffTests(TestCase): 

216 def setUp(self): 

217 first_runconfig = RunConfig.objects.create(name="Runconfig", temporary=False) 

218 

219 self.testsuite = TestSuite.objects.create(name="testsuite", public=True, 

220 vetted_on=timezone.now()) 

221 self.test = Test.objects.create(name="test1", testsuite=self.testsuite, public=True, 

222 vetted_on=timezone.now(), first_runconfig=first_runconfig) 

223 self.machine = Machine.objects.create(name="machine1", public=True, 

224 vetted_on=timezone.now()) 

225 

226 def test_is_fix(self): 

227 result_from = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="FAIL"), 

228 is_failure=True, bugs_covering=[], all_failures_covered=False, is_suppressed=False) 

229 result_to = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="PASS"), 

230 is_failure=False, bugs_covering=[], all_failures_covered=True, is_suppressed=False) 

231 

232 r = RunConfigResultsForTestDiff(test=self.test, testsuite=self.testsuite, 

233 machine=self.machine, result_from=result_from, 

234 result_to=result_to) 

235 

236 self.assertTrue(r.is_fix and r.is_known_change) 

237 self.assertFalse(r.is_regression or r.is_warning or r.is_unknown_change or r.is_regression) 

238 self.assertEqual(str(r), "machine1: FAIL -> PASS") 

239 

240 def test_is_regression(self): 

241 result_from = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="PASS"), 

242 is_failure=False, bugs_covering=[], all_failures_covered=True, is_suppressed=False) 

243 result_to = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="FAIL"), 

244 is_failure=True, bugs_covering=[], all_failures_covered=False, is_suppressed=False) 

245 

246 r = RunConfigResultsForTestDiff(test=self.test, testsuite=self.testsuite, 

247 machine=self.machine, result_from=result_from, 

248 result_to=result_to) 

249 

250 self.assertTrue(r.is_regression and r.is_unknown_change) 

251 self.assertFalse(r.is_fix or r.is_warning or r.is_suppressed or r.is_known_change) 

252 self.assertEqual(str(r), "machine1: PASS -> FAIL") 

253 

254 def test_is_warning(self): 

255 result_from = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="FAIL"), 

256 is_failure=True, bugs_covering=[], all_failures_covered=False, is_suppressed=False) 

257 result_to = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="FAIL"), 

258 is_failure=True, bugs_covering=[], all_failures_covered=False, is_suppressed=False) 

259 

260 r = RunConfigResultsForTestDiff(test=self.test, testsuite=self.testsuite, 

261 machine=self.machine, result_from=result_from, 

262 result_to=result_to) 

263 

264 self.assertTrue(r.is_warning and r.is_unknown_change) 

265 self.assertFalse(r.is_fix or r.is_regression or r.is_regression or r.is_known_change) 

266 self.assertEqual(str(r), "machine1: FAIL -> FAIL") 

267 

268 def test_is_suppressed(self): 

269 result_from = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="PASS"), 

270 is_failure=True, bugs_covering=[], all_failures_covered=False, is_suppressed=False) 

271 result_to = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="{FAIL}"), 

272 is_failure=True, bugs_covering=[], all_failures_covered=False, is_suppressed=True) 

273 

274 r = RunConfigResultsForTestDiff(test=self.test, testsuite=self.testsuite, 

275 machine=self.machine, result_from=result_from, 

276 result_to=result_to) 

277 

278 self.assertTrue(r.is_suppressed and r.is_unknown_change) 

279 self.assertFalse(r.is_fix or r.is_regression or r.is_warning or r.is_known_change) 

280 self.assertEqual(str(r), "machine1: PASS -> {FAIL}") 

281 

282 def test_is_known_change(self): 

283 result_from = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="FAIL"), 

284 is_failure=True, all_failures_covered=True, is_suppressed=False, 

285 bugs_covering=[MagicMock(spec="Bug", short_name="fdo#1234"), 

286 MagicMock(spec="Bug", short_name="fdo#1235")]) 

287 result_to = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="FAIL"), 

288 is_failure=True, all_failures_covered=True, is_suppressed=False, 

289 bugs_covering=[MagicMock(spec="Bug", short_name="fdo#1236"), 

290 MagicMock(spec="Bug", short_name="fdo#1237")]) 

291 

292 r = RunConfigResultsForTestDiff(test=self.test, testsuite=self.testsuite, 

293 machine=self.machine, result_from=result_from, 

294 result_to=result_to) 

295 

296 self.assertTrue(r.is_warning and r.is_known_change) 

297 self.assertFalse(r.is_regression or r.is_fix or r.is_unknown_change) 

298 self.assertEqual(str(r), "machine1: FAIL ([fdo#1234] / [fdo#1235]) -> FAIL ([fdo#1236] / [fdo#1237])") 

299 

300 def test_is_new_test(self): 

301 result_from = RunConfigResultsForNotRunTest() 

302 result_to = MagicMock(spec="RunConfigResultsForTest", __str__=MagicMock(return_value="FAIL"), 

303 is_failure=True, bugs_covering=[], all_failures_covered=False, is_suppressed=False) 

304 

305 new_test = Test.objects.create(name="new_test", testsuite=self.testsuite, public=True, 

306 vetted_on=timezone.now(), first_runconfig=None) 

307 r = RunConfigResultsForTestDiff(test=new_test, testsuite=self.testsuite, 

308 machine=self.machine, result_from=result_from, 

309 result_to=result_to) 

310 

311 self.assertTrue(r.is_new_test and r.is_regression and r.is_unknown_change) 

312 self.assertFalse(r.is_fix or r.is_warning or r.is_known_change) 

313 self.assertEqual(str(r), "machine1: NOTRUN -> FAIL") 

314 

315 

316class RunConfigDiffTests(TestCase): 

317 def setUp(self): 

318 self.runcfg_from = RunConfig.objects.create(name="runcfg_from", temporary=False) 

319 self.runcfg_to = RunConfig.objects.create(name="runcfg_to", temporary=False) 

320 

321 self.component1 = Component.objects.create(name="component1", description="", public=True) 

322 self.component2 = Component.objects.create(name="component2", description="", public=True) 

323 self.component3 = Component.objects.create(name="component3", description="", public=True) 

324 

325 self.build_c1_1 = Build.objects.create(name="build_c1_1", component=self.component1, version="1") 

326 self.build_c1_2 = Build.objects.create(name="build_c1_2", component=self.component1, version="2") 

327 self.build_c2_1 = Build.objects.create(name="build_c2_1", component=self.component2, version="1") 

328 self.build_c2_2 = Build.objects.create(name="build_c2_2", component=self.component2, version="2") 

329 self.build_c3_1 = Build.objects.create(name="build_c3_1", component=self.component3, version="1") 

330 

331 self.machines = [] 

332 for i in range(10): 

333 self.machines.append(Mock(spec=Machine, name='machine_{}'.format(i))) 

334 

335 def test_builds__simple(self): 

336 self.runcfg_from.builds.add(self.build_c1_1, self.build_c2_1, self.build_c3_1) 

337 self.runcfg_to.builds.add(self.build_c1_2, self.build_c2_2, self.build_c3_1) 

338 

339 diff = self.runcfg_from.compare(self.runcfg_to) 

340 diff_builds = diff.builds 

341 

342 self.assertEqual(len(diff_builds), 2) 

343 

344 self.assertEqual(diff_builds[self.component1].from_build, self.build_c1_1) 

345 self.assertEqual(diff_builds[self.component1].to_build, self.build_c1_2) 

346 

347 self.assertEqual(diff_builds[self.component2].from_build, self.build_c2_1) 

348 self.assertEqual(diff_builds[self.component2].to_build, self.build_c2_2) 

349 

350 self.assertIn("component1: build_c1_1 -> build_c1_2", diff.text) 

351 self.assertIn("component2: build_c2_1 -> build_c2_2", diff.text) 

352 self.assertNotIn("component3", diff.text) 

353 

354 def test_builds__asymmetric(self): 

355 self.runcfg_from.builds.add(self.build_c1_1) 

356 self.runcfg_to.builds.add(self.build_c2_2) 

357 

358 diff = self.runcfg_from.compare(self.runcfg_to) 

359 diff_builds = diff.builds 

360 

361 self.assertEqual(len(diff_builds), 2) 

362 

363 self.assertEqual(diff_builds[self.component1].from_build, self.build_c1_1) 

364 self.assertEqual(diff_builds[self.component1].to_build, None) 

365 

366 self.assertEqual(diff_builds[self.component2].from_build, None) 

367 self.assertEqual(diff_builds[self.component2].to_build, self.build_c2_2) 

368 

369 self.assertIn("component1: build_c1_1 -> None", diff.text) 

370 self.assertIn("component2: None -> build_c2_2", diff.text) 

371 self.assertNotIn("component3", diff.text) 

372 

373 def test_testsuites__no_results(self): 

374 diff = self.runcfg_from.compare(self.runcfg_to) 

375 

376 self.assertIn("No changes found", diff.text) 

377 

378 @patch('CIResults.runconfigdiff.RunConfigDiff.runcfg_from_results', new_callable=PropertyMock) 

379 @patch('CIResults.runconfigdiff.RunConfigDiff.runcfg_to_results', new_callable=PropertyMock) 

380 def test_testsuites__all_combinaisons(self, mock_runcfg_to_results, mock_runcfg_from_results): 

381 mock_runcfg_from_results.return_value = {"testsuite3": {}, "testsuite1": {}} 

382 mock_runcfg_to_results.return_value = {"testsuite2": {}, "testsuite1": {}} 

383 

384 diff = self.runcfg_from.compare(self.runcfg_to) 

385 

386 self.assertEqual(diff.testsuites.runcfg_from, set(mock_runcfg_from_results.return_value.keys())) 

387 self.assertEqual(diff.testsuites.runcfg_to, set(mock_runcfg_to_results.return_value.keys())) 

388 self.assertEqual(diff.testsuites.new, set(["testsuite2"])) 

389 self.assertEqual(diff.testsuites.removed, set(["testsuite3"])) 

390 self.assertEqual(diff.testsuites.all, ["testsuite1", "testsuite2", "testsuite3"]) 

391 

392 def test_has_sufficient_machines__no_machines(self): 

393 diff = self.runcfg_from.compare(self.runcfg_to) 

394 self.assertTrue(diff.has_sufficient_machines) 

395 self.assertEqual(diff.status, "SUCCESS") 

396 

397 def test_has_sufficient_machines__same_machines(self): 

398 m = self.machines 

399 with patch('CIResults.runconfigdiff.RunConfigDiff._get_machine_list', 

400 side_effect=[set([m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9]]), 

401 set([m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9]])]): 

402 diff = self.runcfg_from.compare(self.runcfg_to) 

403 self.assertEqual(len(diff.machines.runcfg_from), 10) 

404 self.assertEqual(len(diff.machines.removed), 0) 

405 self.assertTrue(diff.has_sufficient_machines) 

406 self.assertEqual(diff.status, "SUCCESS") 

407 

408 def test_has_sufficient_machines__at_threshold(self): 

409 m = self.machines 

410 

411 with patch('CIResults.runconfigdiff.RunConfigDiff._get_machine_list', 

412 side_effect=[set([m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9]]), 

413 set([m[0], m[3], m[4], m[5], m[6], m[9]])]): 

414 diff = self.runcfg_from.compare(self.runcfg_to, 0.4) 

415 self.assertEqual(len(diff.machines.runcfg_from), 10) 

416 self.assertEqual(len(diff.machines.removed), 4) 

417 self.assertTrue(diff.has_sufficient_machines) 

418 self.assertEqual(diff.status, "SUCCESS") 

419 self.assertNotIn("prevented too many machines from booting", diff.text) 

420 

421 def test_has_sufficient_machines__under_threshold(self): 

422 m = self.machines 

423 with patch('CIResults.runconfigdiff.RunConfigDiff._get_machine_list', 

424 side_effect=[set([m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9]]), 

425 set([m[0], m[3], m[4], m[5], m[8]])]): 

426 diff = self.runcfg_from.compare(self.runcfg_to, 0.4) 

427 self.assertEqual(len(diff.machines.runcfg_from), 10) 

428 self.assertEqual(len(diff.machines.removed), 5) 

429 self.assertFalse(diff.has_sufficient_machines) 

430 self.assertEqual(diff.status, "FAILURE") 

431 self.assertIn("prevented too many machines from booting", diff.text) 

432 

433 def test_has_suppressed_results(self): 

434 diff = self.runcfg_from.compare(self.runcfg_to, 0.4) 

435 diff.results = [MagicMock(), MagicMock(), MagicMock()] 

436 

437 # Mock the return values of the is_suppressed property 

438 p_true = PropertyMock(return_value=True) 

439 p_false = PropertyMock(return_value=False) 

440 type(diff.results[0]).is_suppressed = p_false 

441 type(diff.results[1]).is_suppressed = p_true 

442 type(diff.results[2]).is_suppressed = p_false 

443 

444 self.assertTrue(diff.has_suppressed_results) 

445 

446 p_true.assert_called_once_with() 

447 p_false.assert_called_once_with() 

448 

449 # TODO: Test machines, bugs, status (with suppressed results)