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

435 statements  

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

1import json 

2 

3from unittest.mock import patch, MagicMock 

4from rest_framework.test import APIRequestFactory, APITestCase 

5from django.conf import settings 

6from django.db import transaction 

7from django.test import TestCase 

8from django.http.response import Http404 

9from django.urls import reverse 

10 

11from CIResults.models import Build, Component, Test, Machine, RunConfigTag, TestResult, TestSuite, RunConfig 

12from CIResults.models import TextStatus, IssueFilter, MachineTag, Issue, Bug, BugTracker 

13from CIResults.rest_views import CustomPagination, IssueFilterViewSet, RunConfigViewSet, get_obj_by_id_or_name 

14from CIResults.rest_views import BuildViewSet 

15from CIResults.tests.test_views import create_user_and_log_in 

16 

17from shortener.models import Shortener 

18 

19 

20# HACK: Massively speed up the login primitive. We don't care about security in tests 

21settings.PASSWORD_HASHERS = ('django.contrib.auth.hashers.MD5PasswordHasher', ) 

22 

23 

24class UtilsTests(TestCase): 

25 def test_get_obj_by_id_or_name__id(self): 

26 rc = RunConfig.objects.create(name='valid', temporary=True) 

27 self.assertEqual(get_obj_by_id_or_name(RunConfig, 1), rc) 

28 

29 def test_get_obj_by_id_or_name__name(self): 

30 rc = RunConfig.objects.create(name='valid', temporary=True) 

31 self.assertEqual(get_obj_by_id_or_name(RunConfig, "valid"), rc) 

32 

33 def test_get_obj_by_id_or_name__not_exist(self): 

34 self.assertRaises(RunConfig.DoesNotExist, get_obj_by_id_or_name, RunConfig, 1) 

35 

36 

37class CustomPaginationTests(TestCase): 

38 def get_page_size(self, query_params, page_size_query_param='page_size', max_page_size=None): 

39 request = MagicMock(query_params=query_params) 

40 

41 pagination = CustomPagination() 

42 pagination.page_size_query_param = page_size_query_param 

43 pagination.max_page_size = max_page_size 

44 

45 return pagination.get_page_size(request) 

46 

47 def test_default_page_size(self): 

48 self.assertEqual(self.get_page_size({}), CustomPagination.page_size) 

49 

50 def test_default_page_size_without_page_size_field(self): 

51 self.assertEqual(self.get_page_size({}, page_size_query_param=None), CustomPagination.page_size) 

52 

53 def test_invalid_page_size(self): 

54 self.assertEqual(self.get_page_size({'page_size': 'toto'}), CustomPagination.page_size) 

55 

56 def test_negative_page_size(self): 

57 self.assertEqual(self.get_page_size({CustomPagination.page_size_query_param: -0}), None) 

58 

59 def test_page_size_too_big(self): 

60 self.assertEqual(self.get_page_size({'page_size': '1000'}, max_page_size=10), 10) 

61 

62 def test_page_size_big_but_no_limits(self): 

63 self.assertEqual(self.get_page_size({'page_size': '1000'}, max_page_size=None), 1000) 

64 

65 def test_acceptable_page_size(self): 

66 self.assertEqual(self.get_page_size({'page_size2': '42'}, page_size_query_param='page_size2'), 42) 

67 

68 

69class IssueFilterTests(APITestCase): 

70 maxDiff = None 

71 

72 def setUp(self): 

73 self.view = IssueFilterViewSet() 

74 self.user = None 

75 

76 def __post__(self, body_dict, logged_in=True, permissions=['add_issuefilter']): 

77 if logged_in: 

78 self.user = create_user_and_log_in(self.client, permissions=permissions) 

79 

80 return self.client.post(reverse('api:issuefilter-list'), body_dict, format='json') 

81 

82 def test__get_or_None__empty_field(self): 

83 errors = [] 

84 self.assertIsNone(self.view.__get_or_None__(Machine, 'field', {'field': ''}, errors)) 

85 self.assertEqual(errors, []) 

86 

87 def test__get_or_None__invalid_id(self): 

88 errors = [] 

89 self.assertIsNone(self.view.__get_or_None__(Machine, 'field', {'field': '12'}, errors)) 

90 self.assertEqual(errors, ["The object referenced by 'field' does not exist"]) 

91 

92 def test_get_filter_by_description(self): 

93 IssueFilter.objects.create(description="filter one") 

94 IssueFilter.objects.create(description="filter two") 

95 response = self.client.get(reverse('api:issuefilter-list'), {'description': 'one'}) 

96 self.assertEqual(response.status_code, 200) 

97 self.assertEqual(response.data["count"], 1) 

98 self.assertEqual(response.data["results"][0]["description"], "filter one") 

99 

100 def test_create_empty(self): 

101 response = self.__post__({}) 

102 self.assertEqual(response.status_code, 400) 

103 self.assertEqual(response.data, ["The field 'description' cannot be empty"]) 

104 

105 def test_invalid_regexps(self): 

106 response = self.__post__({"description": "Minimal IssueFilter", 

107 "stdout_regex": '(', "stderr_regex": '(', 

108 "dmesg_regex": '('}) 

109 self.assertEqual(response.status_code, 400) 

110 self.assertEqual(response.data, ["The field 'stdout_regex' does not contain a valid regular expression", 

111 "The field 'stderr_regex' does not contain a valid regular expression", 

112 "The field 'dmesg_regex' does not contain a valid regular expression"]) 

113 

114 def test_create_minimal__unauthenticated(self): 

115 response = self.__post__({"description": "Minimal IssueFilter"}, logged_in=False) 

116 self.assertEqual(response.status_code, 401) 

117 

118 # FIXME: This is not currently working 

119 # def test_create_minimal__invalid_permissions(self): 

120 # response = self.__post__({"description": "Minimal IssueFilter"}, logged_in=True, permissions=[]) 

121 # self.assertEqual(response.status_code, 403) 

122 

123 def test_create_minimal(self): 

124 response = self.__post__({"description": "Minimal IssueFilter"}) 

125 self.assertEqual(response.status_code, 201) 

126 self.assertEqual(response.data, 

127 {'id': response.data['id'], 'description': 'Minimal IssueFilter', 

128 'tags': [], 'machine_tags': [], 'machines': [], 'tests': [], 

129 'statuses': [], 'stdout_regex': '', 

130 'stderr_regex': '', 'dmesg_regex': '', 

131 'user_query': '', '__str__': 'Minimal IssueFilter'}) 

132 

133 def test_create_invalid(self): 

134 response = self.__post__({ 

135 "description": "Invalid tags, machines, tests, and statuses", 

136 'tags': [1], 'machines': [2], 'tests': [3], 'statuses': [4] 

137 }) 

138 self.assertEqual(response.status_code, 400, response.data) 

139 self.assertEqual(response.data, ['At least one tag does not exist', 

140 'At least one machine does not exist', 

141 'At least one test does not exist', 

142 'At least one status does not exist']) 

143 

144 def test_create_complete(self): 

145 # Create some objects before referencing them 

146 ts = TestSuite.objects.create(name="ts", description="", url="", public=True) 

147 for i in range(1, 6): 

148 RunConfigTag.objects.create(id=i, name="tag{}".format(i), description="", url="", public=True) 

149 Machine.objects.create(id=i, name="machine{}".format(i), public=True) 

150 Test.objects.create(id=i, name="test{}".format(i), testsuite=ts, public=True) 

151 TextStatus.objects.create(id=i, testsuite=ts, name="status{}".format(i)) 

152 MachineTag.objects.create(id=i, name="TAG{}".format(i), public=True) 

153 

154 # Make the request and check that we get the expected output 

155 with transaction.atomic(): 

156 response = self.__post__({ 

157 "description": "Minimal IssueFilter", 

158 'tags': [1, 2], 'machine_tags': [1, 5], 'machines': [2, 3], 'tests': [3, 4], 'statuses': [4, 5], 

159 'stdout_regex': 'stdout', 'stderr_regex': 'stderr', 'dmesg_regex': 'dmesg' 

160 }) 

161 

162 self.assertEqual(response.status_code, 201, response.data) 

163 self.assertEqual(dict(response.data), 

164 {'id': response.data['id'], 'description': 'Minimal IssueFilter', 

165 'tags': [ 

166 {'id': 1, 'description': '', 'url': '', 'public': True, '__str__': 'tag1'}, 

167 {'id': 2, 'description': '', 'url': '', 'public': True, '__str__': 'tag2'} 

168 ], 

169 'machine_tags': [ 

170 {'id': 1, 'name': 'TAG1', 'public': True}, 

171 {'id': 5, 'name': 'TAG5', 'public': True}, 

172 ], 

173 'machines': [ 

174 {'id': 2, 'vetted_on': None, 'public': True, '__str__': 'machine2'}, 

175 {'id': 3, 'vetted_on': None, 'public': True, '__str__': 'machine3'}, 

176 ], 

177 'tests': [ 

178 {'id': 3, 'testsuite': {'id': ts.id, '__str__': 'ts'}, 'public': True, 

179 'vetted_on': None, 'first_runconfig': None, 'name': 'test3', '__str__': 'ts: test3'}, 

180 {'id': 4, 'testsuite': {'id': ts.id, '__str__': 'ts'}, 'public': True, 

181 'vetted_on': None, 'first_runconfig': None, 'name': 'test4', '__str__': 'ts: test4'}, 

182 ], 

183 'statuses': [ 

184 {'id': 4, 'testsuite': {'id': ts.id, '__str__': 'ts'}, 'name': 'status4', 

185 '__str__': 'ts: status4'}, 

186 {'id': 5, 'testsuite': {'id': ts.id, '__str__': 'ts'}, 'name': 'status5', 

187 '__str__': 'ts: status5'}, 

188 ], 

189 'stdout_regex': 'stdout', 'stderr_regex': 'stderr', 

190 'dmesg_regex': 'dmesg', '__str__': 'Minimal IssueFilter', 

191 'user_query': ''}) 

192 

193 def test_edit_invalid(self): 

194 response = self.__post__({"description": "new filter", 

195 "edit_filter": "a", "edit_issue": "b"}) 

196 self.assertEqual(response.status_code, 400, response.data) 

197 self.assertEqual(response.data, ["The field 'edit_filter' needs to be an integer", 

198 "The field 'edit_issue' needs to be an integer"]) 

199 

200 @patch('CIResults.models.IssueFilter.replace') 

201 @patch('CIResults.models.Issue.replace_filter') 

202 def test_edit_all_issues(self, mock_replace_filter, mock_filter_replace): 

203 filter = IssueFilter.objects.create(description="old filter") 

204 

205 with transaction.atomic(): 

206 response = self.__post__({"description": "new filter", "edit_filter": filter.id}) 

207 self.assertEqual(response.status_code, 201, response.data) 

208 self.assertEqual(response.data, 

209 {'id': response.data['id'], 'description': 'new filter', 

210 'tags': [], 'machine_tags': [], 'machines': [], 'tests': [], 

211 'statuses': [], 'stdout_regex': '', 

212 'stderr_regex': '', 'dmesg_regex': '', 

213 'user_query': '', '__str__': 'new filter'}) 

214 

215 new_filter = IssueFilter.objects.get(pk=response.data['id']) 

216 mock_replace_filter.assert_not_called() 

217 mock_filter_replace.assert_called_once_with(new_filter, self.user) 

218 self.assertEqual(mock_filter_replace.call_args_list[0][0][0].id, response.data['id']) 

219 

220 @patch('CIResults.models.IssueFilter.replace') 

221 @patch('CIResults.models.Issue.replace_filter') 

222 def test_edit_one_issue(self, mock_replace_filter, mock_filter_replace): 

223 filter = IssueFilter.objects.create(description="desc") 

224 issue = Issue.objects.create(description="issue") 

225 

226 with transaction.atomic(): 

227 response = self.__post__({"description": "new filter", 

228 "edit_filter": "{}".format(filter.id), 

229 "edit_issue": issue.id}) 

230 

231 self.assertEqual(response.status_code, 201, response.data) 

232 self.assertEqual(response.data, 

233 {'id': response.data['id'], 'description': 'new filter', 

234 'tags': [], 'machine_tags': [], 'machines': [], 'tests': [], 

235 'statuses': [], 'stdout_regex': '', 

236 'stderr_regex': '', 'dmesg_regex': '', 

237 'user_query': '', '__str__': 'new filter'}) 

238 

239 new_filter = IssueFilter.objects.get(pk=response.data['id']) 

240 mock_filter_replace.assert_not_called() 

241 mock_replace_filter.assert_called_once_with(filter, new_filter, self.user) 

242 self.assertEqual(mock_replace_filter.call_args_list[0][0][0].id, filter.id) 

243 self.assertEqual(mock_replace_filter.call_args_list[0][0][1].id, response.data['id']) 

244 

245 

246class RunConfigTests(TestCase): 

247 def setUp(self): 

248 self.view = RunConfigViewSet() 

249 self.arf = APIRequestFactory() 

250 

251 @patch('CIResults.models.RunConfig.objects.get') 

252 def test_get_runcfg__by_id(self, runcfg_get_mocked): 

253 self.assertEqual(self.view._get_runcfg('1'), runcfg_get_mocked.return_value) 

254 runcfg_get_mocked.assert_called_once_with(pk=1) 

255 

256 @patch('CIResults.models.RunConfig.objects.get') 

257 def test_get_runcfg__by_invalid_name(self, runcfg_get_mocked): 

258 self.assertRaises(Http404, self.view._get_runcfg, 'missing') 

259 runcfg_get_mocked.assert_not_called() 

260 

261 @patch('CIResults.models.RunConfig.objects.get') 

262 def test_get_runcfg__by_valid_name(self, runcfg_get_mocked): 

263 rc = RunConfig.objects.create(name='valid', temporary=True) 

264 self.assertEqual(self.view._get_runcfg('valid').pk, rc.id) 

265 runcfg_get_mocked.assert_not_called() 

266 

267 def test_retrieve__by_id(self): 

268 rc = RunConfig.objects.create(name='valid', temporary=True) 

269 data = self.view.retrieve(self.arf.get("/", {}, format="json"), pk="valid").data 

270 self.assertEqual(data["id"], rc.id) 

271 self.assertEqual(data["name"], "valid") 

272 self.assertEqual(data["tags"], []) 

273 self.assertIsNone(data["url"]) 

274 self.assertIsNotNone(data["added_on"]) 

275 

276 def test_known_failures(self): 

277 # TODO: Revisit the test whenever we start generating fixtures 

278 RunConfig.objects.create(name='valid', temporary=True) 

279 response = self.view.known_failures(self.arf.get('/', {}, format='json'), 

280 pk='valid') 

281 self.assertEqual(response.data, []) 

282 

283 @patch('CIResults.serializers.RunConfigDiffSerializer.data') 

284 @patch('CIResults.models.RunConfig.compare') 

285 def test_compare(self, compare_mocked, serializer_mocked): 

286 RunConfig.objects.create(name='runcfg1', temporary=True) 

287 runcfg2 = RunConfig.objects.create(name='runcfg2', temporary=True) 

288 response = self.view.compare(self.arf.get('/', {'to': 'runcfg2'}, format='json'), 

289 pk='runcfg1') 

290 compare_mocked.assert_called_once_with(runcfg2, no_compress=False) 

291 self.assertEqual(response.data, serializer_mocked) 

292 

293 @patch('CIResults.models.RunConfig.compare') 

294 def test_compare__no_compress(self, compare_mocked): 

295 RunConfig.objects.create(name='runcfg1', temporary=True) 

296 runcfg2 = RunConfig.objects.create(name='runcfg2', temporary=True) 

297 self.view.compare(self.arf.get('/', {'to': 'runcfg2', 'no_compress': '1'}, format='json'), 

298 pk='runcfg1') 

299 compare_mocked.assert_called_once_with(runcfg2, no_compress=True) 

300 

301 def test_compare__only_summary(self): 

302 RunConfig.objects.create(name='runcfg1', temporary=True) 

303 RunConfig.objects.create(name='runcfg2', temporary=True) 

304 response = self.view.compare(self.arf.get('/', {'to': 'runcfg2', 'summary': ''}, format='json'), 

305 pk='runcfg1') 

306 self.assertIn('CI Bug Log', response.content.decode()) 

307 

308 def test_create__no_permissions(self): 

309 response = self.client.post(reverse('api:runconfig-list'), 

310 data={"name": "runcfg", "tags": ["tag1"], "temporary": False}, 

311 content_type="application/json") 

312 self.assertEqual(response.status_code, 401) 

313 

314 def test_create(self): 

315 RunConfigTag.objects.create(id=1, name="tag1", public=True) 

316 create_user_and_log_in(self.client, admin=True) 

317 response = self.client.post(reverse('api:runconfig-list'), 

318 data={"name": "runcfg", "tags": ["tag1"], "builds": [], "temporary": False}, 

319 content_type="application/json") 

320 self.assertEqual(response.status_code, 201) 

321 self.assertEqual(response.data["name"], "runcfg") 

322 self.assertEqual(response.data["tags"], ["tag1"]) 

323 

324 def test_create__invalid_data(self): 

325 create_user_and_log_in(self.client, admin=True) 

326 response = self.client.post(reverse('api:runconfig-list'), data={"name": "runcfg"}, 

327 content_type="application/json") 

328 self.assertEqual(response.status_code, 400) 

329 

330 def test_create__invalid_data_missing_tag(self): 

331 create_user_and_log_in(self.client, admin=True) 

332 response = self.client.post(reverse('api:runconfig-list'), 

333 data={"name": "runcfg", "tags": ["tag1"], "temporary": False}, 

334 content_type="application/json") 

335 self.assertEqual(response.status_code, 400) 

336 

337 def test_import_testsuite_run(self): 

338 RunConfig.objects.create(name='runcfg1', temporary=False) 

339 component = TestSuite.objects.create(id=1, name='testsuite', public=True) 

340 Build.objects.create(name='testsuite-1', component=component) 

341 create_user_and_log_in(self.client, admin=True) 

342 response = self.client.post("/api/runconfig/runcfg1/testsuiterun/", content_type="application/json", data={ 

343 "test_suite": "testsuite-1", 

344 "test_results": { 

345 "machine-1": { 

346 "001": { 

347 "test1": { 

348 "status": "pass", 

349 "stdout": "output" 

350 } 

351 }, 

352 "002": { 

353 "test2": { 

354 "status": "pass", 

355 "stdout": "output" 

356 } 

357 } 

358 } 

359 } 

360 }) 

361 self.assertEqual(response.status_code, 200) 

362 self.assertIsNotNone(Machine.objects.get(name="machine-1")) 

363 self.assertIsNotNone(Test.objects.get(name="test1")) 

364 self.assertIsNotNone(TextStatus.objects.get(name="pass")) 

365 self.assertEqual(TestResult.objects.count(), 2) 

366 for test_name in ["test1", "test2"]: 

367 result = TestResult.objects.filter(test__name=test_name).first() 

368 self.assertEqual(result.status.name, "pass") 

369 self.assertEqual(result.stdout, "output") 

370 

371 def test_import_testsuite_run__no_permissions(self): 

372 response = self.client.post("/api/runconfig/runcfg1/testsuiterun/", content_type="application/json", data={}) 

373 self.assertEqual(response.status_code, 401) 

374 

375 def test_import_testsuite_run__invalid_data(self): 

376 RunConfig.objects.create(name='runcfg1', temporary=False) 

377 component = TestSuite.objects.create(id=1, name='testsuite', public=True) 

378 Build.objects.create(name='testsuite-1', component=component) 

379 create_user_and_log_in(self.client, admin=True) 

380 response = self.client.post("/api/runconfig/runcfg1/testsuiterun/", content_type="application/json", data={ 

381 "test_suite": "testsuite-1", 

382 "test_results": "invalid_data" 

383 }) 

384 self.assertEqual(response.status_code, 400) 

385 self.assertEqual(response.json()["message"]["test_results"], 

386 ['Expected a dictionary of items but got type "str".']) 

387 

388 def test_import_testsuite_run__invalid_data_no_testsuite(self): 

389 RunConfig.objects.create(name='runcfg1', temporary=False) 

390 create_user_and_log_in(self.client, admin=True) 

391 response = self.client.post("/api/runconfig/runcfg1/testsuiterun/", content_type="application/json", data={ 

392 "test_suite": "testsuite-1", 

393 "test_results": { 

394 "machine-1": { 

395 "001": { 

396 "test1": { 

397 "status": "pass", 

398 "stdout": "output" 

399 } 

400 } 

401 } 

402 } 

403 }) 

404 self.assertEqual(response.status_code, 400) 

405 self.assertEqual(response.json()["message"], 'Testsuite build testsuite-1 does not exist') 

406 

407 

408class BuildViewSetTests(APITestCase): 

409 def setUp(self) -> None: 

410 self.component = Component.objects.create(name="component", public=False) 

411 self.view = BuildViewSet() 

412 self.arf = APIRequestFactory() 

413 

414 def test_retrieve(self): 

415 rc = Build.objects.create(name='valid', component=self.component) 

416 data = self.view.retrieve(self.arf.get("/", {}, format="json"), pk="valid").data 

417 self.assertEqual(data["id"], rc.id) 

418 self.assertEqual(data["name"], "valid") 

419 self.assertIsNotNone(data["added_on"]) 

420 

421 def test_create_build_without_permissions(self): 

422 response = self.client.post(reverse('api:build-list'), 

423 data={"name": "test-build", "component": "component", "version": "1"}, 

424 format="json") 

425 self.assertEqual(response.status_code, 401) 

426 

427 def test_create_build(self): 

428 create_user_and_log_in(self.client, admin=True) 

429 response = self.client.post(reverse('api:build-list'), 

430 data={"name": "build1", "component": "component", "version": "1", "parents": []}, 

431 format="json") 

432 self.assertEqual(response.status_code, 201) 

433 self.assertEqual(response.data["name"], "build1") 

434 

435 def test_create_build__invalid_data_schema(self): 

436 create_user_and_log_in(self.client, admin=True) 

437 response = self.client.post(reverse('api:build-list'), 

438 data={"name": "test-build", "component": "component"}, 

439 format="json") 

440 self.assertEqual(response.status_code, 400) 

441 self.assertEqual(json.loads(response.content)["version"], ["This field is required."]) 

442 

443 def test_create_build__invalid_data(self): 

444 create_user_and_log_in(self.client, admin=True) 

445 response = self.client.post(reverse('api:build-list'), 

446 data={"name": "test-build", "component": "no-component", "version": "1"}, 

447 format="json") 

448 self.assertEqual(response.status_code, 400) 

449 

450 

451class BugViewSetTests(TestCase): 

452 def setUp(self): 

453 self.arf = APIRequestFactory() 

454 

455 @classmethod 

456 def setUpTestData(cls): 

457 cls.bt1 = BugTracker.objects.create(name='Test Suite 1', short_name='ts1', public=True) 

458 cls.bt2 = BugTracker.objects.create(name='Test Suite 2', short_name='ts2', public=True) 

459 

460 cls.bugs = dict() 

461 for bt in (cls.bt1, cls.bt2): 

462 cls.bugs[bt] = [] 

463 for i in range(2): 

464 cls.bugs[bt].append(Bug.objects.create(tracker=bt, bug_id='b_'+str(i))) 

465 

466 def test_retrieving_by_tracker_id(self): 

467 tracker = self.bt2 

468 bug = self.bugs[self.bt2][1] 

469 response = self.client.get(reverse('api-bugtracker-get-bug', 

470 kwargs={'tracker': tracker.id, 'bug_id': bug.bug_id}), format='json') 

471 self.assertEqual(response.status_code, 200) 

472 self.assertEqual(response.data['bug_id'], bug.bug_id) 

473 self.assertEqual(response.data['tracker']['short_name'], tracker.short_name) 

474 

475 def test_retrieving_by_tracker_name(self): 

476 tracker = self.bt1 

477 bug = self.bugs[self.bt2][0] 

478 response = self.client.get(reverse('api-bugtracker-get-bug', 

479 kwargs={'tracker': tracker.name, 'bug_id': bug.bug_id}), format='json') 

480 self.assertEqual(response.status_code, 200) 

481 self.assertEqual(response.data['bug_id'], bug.bug_id) 

482 self.assertEqual(response.data['tracker']['short_name'], tracker.short_name) 

483 

484 def test_retrieving_by_tracker_short_name(self): 

485 tracker = self.bt2 

486 bug = self.bugs[self.bt2][0] 

487 response = self.client.get(reverse('api-bugtracker-get-bug', 

488 kwargs={'tracker': tracker.short_name, 'bug_id': bug.bug_id}), format='json') 

489 self.assertEqual(response.status_code, 200) 

490 self.assertEqual(response.data['bug_id'], bug.bug_id) 

491 self.assertEqual(response.data['tracker']['short_name'], tracker.short_name) 

492 

493 

494class ShortenerViewSetTests(TestCase): 

495 def setUp(self): 

496 self.arf = APIRequestFactory() 

497 

498 @classmethod 

499 def setUpTestData(cls): 

500 cls.short1 = Shortener.get_or_create("Some sort of long query!") 

501 

502 def test_create_invalid_request(self): 

503 with self.assertRaisesMessage(ValueError, "Only JSON POST requests are supported"): 

504 self.client.post(reverse('api:shortener-list'), data={}) 

505 

506 def test_create_empty(self): 

507 with self.assertRaisesMessage(ValueError, 

508 "Missing the field 'full' which should contain the full text to be shortened"): 

509 self.client.post(reverse('api:shortener-list'), data={}, content_type="application/json") 

510 

511 def test_create_single(self): 

512 full = 'Some sort of long query, but different!' 

513 

514 response = self.client.post(reverse('api:shortener-list'), data={'full': full}, content_type="application/json") 

515 self.assertEqual(response.status_code, 200) 

516 

517 data = response.json() 

518 self.assertNotEqual(data['id'], self.short1.id) 

519 self.assertEqual(data['full'], full) 

520 

521 def test_create_multiple(self): 

522 fulls = ["query1", "query2"] 

523 

524 response = self.client.post(reverse('api:shortener-list'), data={'full': fulls}, 

525 content_type="application/json") 

526 self.assertEqual(response.status_code, 200) 

527 

528 data = response.json() 

529 self.assertEqual(data[0]['full'], fulls[0]) 

530 self.assertEqual(data[1]['full'], fulls[1]) 

531 

532 def test_retrieving_existing(self): 

533 response = self.client.post(reverse('api:shortener-list'), data={'full': self.short1.full}, 

534 content_type="application/json") 

535 self.assertEqual(response.status_code, 200) 

536 

537 data = response.json() 

538 self.assertEqual(data['id'], self.short1.id) 

539 

540 

541class MachineViewSetTests(TestCase): 

542 def setUp(self): 

543 self.arf = APIRequestFactory() 

544 

545 def test_list_machines(self): 

546 Machine.objects.create(name="machine_1", public=True) 

547 response = self.client.get(reverse('api:machine-list'), content_type="application/json") 

548 self.assertEqual(response.status_code, 200) 

549 self.assertEqual(json.loads(response.content)["results"], 

550 [{'id': 1, 

551 'name': 'machine_1', 

552 'description': None, 

553 'public': True, 

554 'vetted_on': None, 

555 'aliases': None, 

556 'tags': []}]) 

557 

558 def test_create_machine_without_permission(self): 

559 response = self.client.post(reverse('api:machine-list'), data={'name': 'machine_1', 'tags': ['tag1']}, 

560 content_type="application/json") 

561 self.assertEqual(response.status_code, 401) 

562 

563 def test_create_machine(self): 

564 self.user = create_user_and_log_in(self.client, admin=True) 

565 response = self.client.post(reverse('api:machine-list'), data={'name': 'machine_1', 'tags': ['tag1']}, 

566 content_type="application/json") 

567 self.assertEqual(response.status_code, 201) 

568 self.assertEqual(json.loads(response.content), { 

569 "data": { 

570 "id": 1, 

571 "name": "machine_1", 

572 "description": None, 

573 "public": False, 

574 "vetted_on": None, 

575 "aliases": None, 

576 "tags": ["tag1"] 

577 

578 }, 

579 "status": "success" 

580 }) 

581 

582 def test_create_machine_invalid_data(self): 

583 self.user = create_user_and_log_in(self.client, admin=True) 

584 response = self.client.post(reverse('api:machine-list'), data={'name': True}, 

585 content_type="application/json") 

586 self.assertEqual(response.status_code, 400) 

587 self.assertEqual(json.loads(response.content), { 

588 "message": {"name": ["Not a valid string."]}, 

589 "status": "error" 

590 }) 

591 

592 def test_create_machine_import_error(self): 

593 self.user = create_user_and_log_in(self.client, admin=True) 

594 response = self.client.post(reverse('api:machine-list'), data={'name': 'machine_1', 'alias': 'machine_2'}, 

595 content_type="application/json") 

596 self.assertEqual(response.status_code, 400) 

597 self.assertEqual(json.loads(response.content), { 

598 "message": "The machine this machine is supposed to alias does not exist. " 

599 "Create it first...", 

600 "status": "error" 

601 }) 

602 

603 

604class IssueViewSetTests(TestCase): 

605 def setUp(self): 

606 self.arf = APIRequestFactory() 

607 

608 def test_archive_issue_without_permission(self): 

609 response = self.client.get(reverse('api:issue-archive', kwargs={"pk": 1})) 

610 self.assertEqual(response.status_code, 401) 

611 self.assertEqual(response.json(), {"message": "User AnonymousUser doesn't have sufficient permissions"}) 

612 

613 def test_archive_issue(self): 

614 Issue.objects.create() 

615 self.user = create_user_and_log_in(self.client, admin=True) 

616 response = self.client.get(reverse('api:issue-archive', kwargs={"pk": 1})) 

617 self.assertEqual(response.status_code, 200) 

618 

619 def test_archive_archived_issue(self): 

620 self.user = create_user_and_log_in(self.client, admin=True) 

621 Issue.objects.create().archive(self.user) 

622 response = self.client.get(reverse('api:issue-archive', kwargs={"pk": 1})) 

623 self.assertEqual(response.status_code, 400) 

624 self.assertEqual(response.json(), {"message": "The issue is already archived"}) 

625 

626 def test_restore_issue_without_permission(self): 

627 response = self.client.get(reverse('api:issue-restore', kwargs={"pk": 1})) 

628 self.assertEqual(response.status_code, 401) 

629 self.assertEqual(response.json(), {"message": "User AnonymousUser doesn't have sufficient permissions"}) 

630 

631 def test_restore_issue(self): 

632 self.user = create_user_and_log_in(self.client, admin=True) 

633 Issue.objects.create().archive(self.user) 

634 response = self.client.get(reverse('api:issue-restore', kwargs={"pk": 1})) 

635 self.assertEqual(response.status_code, 200) 

636 

637 def test_restore_not_archived_issue(self): 

638 Issue.objects.create() 

639 self.user = create_user_and_log_in(self.client, admin=True) 

640 response = self.client.get(reverse('api:issue-restore', kwargs={"pk": 1})) 

641 self.assertEqual(response.status_code, 400) 

642 self.assertEqual(response.json(), {"message": "The issue is not currently archived"}) 

643 

644 def test_update_to_expected(self): 

645 Issue.objects.create(expected=False) 

646 self.user = create_user_and_log_in(self.client, admin=True) 

647 response = self.client.patch(reverse('api:issue-detail', kwargs={"pk": 1}), data={"id": 1, "expected": True}, 

648 content_type="application/json") 

649 self.assertEqual(response.status_code, 200) 

650 self.assertEqual(response.json()["expected"], True) 

651 self.assertEqual(Issue.objects.get(pk=1).expected, True) 

652 

653 def test_update_to_expected_wrong_value(self): 

654 Issue.objects.create(expected=False) 

655 self.user = create_user_and_log_in(self.client, admin=True) 

656 response = self.client.patch(reverse('api:issue-detail', kwargs={"pk": 1}), data={"id": 1, "expected": "Str"}, 

657 content_type="application/json") 

658 self.assertEqual(response.status_code, 400) 

659 self.assertEqual(response.json()["expected"], ["Must be a valid boolean."]) 

660 

661 def test_try_to_update_read_only_field(self): 

662 Issue.objects.create(runconfigs_covered_count=100) 

663 self.user = create_user_and_log_in(self.client, admin=True) 

664 response = self.client.patch(reverse('api:issue-detail', kwargs={"pk": 1}), 

665 data={"id": 1, "runconfigs_covered_count": 99}, content_type="application/json") 

666 self.assertEqual(response.status_code, 200) 

667 self.assertEqual(response.json()["runconfigs_covered_count"], 100) 

668 

669 

670class TestSetTests(TestCase): 

671 def setUp(self): 

672 self.arf = APIRequestFactory() 

673 ts = TestSuite.objects.create(name="ts", description="", url="", public=True) 

674 Test.objects.create(id=1, name="test1", testsuite=ts, public=True) 

675 

676 def test_vet_test_without_permission(self): 

677 response = self.client.get(reverse('api:test-vet', kwargs={"pk": 1})) 

678 self.assertEqual(response.status_code, 403) 

679 

680 def test_vet_test(self): 

681 self.user = create_user_and_log_in(self.client, admin=True) 

682 response = self.client.get(reverse('api:test-vet', kwargs={"pk": 1})) 

683 self.assertEqual(response.status_code, 200) 

684 

685 def test_vet_already_vetted(self): 

686 self.user = create_user_and_log_in(self.client, admin=True) 

687 Test.objects.get(pk=1).vet() 

688 response = self.client.get(reverse('api:test-vet', kwargs={"pk": 1})) 

689 self.assertEqual(response.status_code, 200) 

690 

691 def test_suppress_test_without_permission(self): 

692 response = self.client.get(reverse('api:test-suppress', kwargs={"pk": 1})) 

693 self.assertEqual(response.status_code, 403) 

694 

695 def test_suppress_test(self): 

696 Test.objects.get(pk=1).vet() 

697 self.user = create_user_and_log_in(self.client, admin=True) 

698 response = self.client.get(reverse('api:test-suppress', kwargs={"pk": 1})) 

699 self.assertEqual(response.status_code, 200) 

700 

701 

702class metrics_passrate_trend_viewTests(TestCase): 

703 def setUp(self): 

704 self.arf = APIRequestFactory() 

705 

706 def test_basic(self): 

707 # TODO: Add a fixture that would return useful data here 

708 response = self.client.get(reverse('api-metrics-passrate-per-runconfig'), 

709 {'query': ""}, format='json') 

710 self.assertEqual(response.status_code, 200) 

711 

712 

713class metrics_passrate_viewTests(TestCase): 

714 def setUp(self): 

715 self.arf = APIRequestFactory() 

716 

717 def test_basic(self): 

718 # TODO: Add a fixture that would return useful data here 

719 response = self.client.get(reverse('api-metrics-passrate-per-test'), 

720 {'query': ""}, format='json') 

721 self.assertEqual(response.status_code, 200)