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

233 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-19 09:20 +0000

1import json 

2from unittest.mock import patch, MagicMock 

3from rest_framework.test import APIRequestFactory 

4from django.conf import settings 

5from django.contrib.auth import get_user_model 

6from django.contrib.auth.models import Permission 

7from django.core.exceptions import ValidationError 

8from django.test import TestCase 

9from django.urls import reverse 

10from django.utils import timezone 

11 

12from CIResults.models import Test, Machine, RunConfigTag, TestSuite, Build 

13from CIResults.models import TextStatus, IssueFilter, Issue 

14from CIResults.models import RunConfig, TestsuiteRun, TestResult, Component 

15from CIResults.views import IssueFilterView, ResultsCompareView 

16 

17from datetime import timedelta 

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 

24def create_user_and_log_in(client, admin=False, permissions=[]): 

25 user = get_user_model().objects.create_user('user', 'user@provider.com', 'pwd', 

26 first_name='First', last_name='Last', 

27 is_superuser=admin) 

28 perm_objs = [] 

29 for codename in permissions: 

30 perm_objs.append(Permission.objects.get(codename=codename)) 

31 user.user_permissions.add(*perm_objs) 

32 

33 client.login(username='user', password='pwd') 

34 return user 

35 

36 

37class ViewMixin: 

38 view_kwargs = {} 

39 

40 @property 

41 def url(self): 

42 return reverse(self.reverse_name, kwargs=self.view_kwargs) 

43 

44 def test_get__authorized(self): 

45 if hasattr(self, 'permissions_needed'): 

46 create_user_and_log_in(self.client, permissions=self.permissions_needed) 

47 

48 response = self.client.get(self.url) 

49 self.assertEqual(response.status_code, 200) 

50 

51 def test_get__unauthorized_access(self): 

52 if not hasattr(self, 'permissions_needed'): 

53 self.skipTest("No need for authorization for the class") # pragma: no cover 

54 

55 create_user_and_log_in(self.client, permissions=[]) 

56 

57 response = self.client.get(self.url) 

58 self.assertEqual(response.status_code, 403) 

59 

60 

61class UserFiltrableViewMixin(ViewMixin): 

62 def test_invalid_query(self): 

63 response = self.client.get(self.url + "?query=djzkhjkf") 

64 self.assertEqual(response.status_code, 200) 

65 self.assertContains(response, "Filtering error") 

66 

67 def test_valid_query(self): 

68 response = self.client.get(self.url + "?query=" + self.query) 

69 self.assertEqual(response.status_code, 200) 

70 self.assertNotContains(response, "Filtering error") 

71 

72 

73class IndexTests(ViewMixin, TestCase): 

74 reverse_name = "CIResults-index" 

75 

76 

77class IssueListTests(UserFiltrableViewMixin, TestCase): 

78 reverse_name = "CIResults-issues-list" 

79 query = "filter_description = 'desc'" 

80 

81 

82class IssueAddTests(ViewMixin, TestCase): 

83 reverse_name = "CIResults-issue" 

84 permissions_needed = ['add_issue'] 

85 view_kwargs = {'action': 'create'} 

86 

87 

88class IssueEditTests(ViewMixin, TestCase): 

89 reverse_name = "CIResults-issue" 

90 permissions_needed = ['change_issue'] 

91 

92 def setUp(self): 

93 issue = Issue.objects.create() 

94 self.view_kwargs = {'action': 'edit', 'pk': issue.pk} 

95 

96 

97class IssueMiscTests(TestCase): 

98 post_actions = ["archive", "restore", "hide", "show"] 

99 

100 def setUp(self): 

101 self.issue = Issue.objects.create() 

102 

103 def url(self, action): 

104 return reverse("CIResults-issue", kwargs={'action': action, 'pk': self.issue.pk}) 

105 

106 def test_post__unauthorized_access(self): 

107 create_user_and_log_in(self.client, permissions=[]) 

108 for action in self.post_actions: 

109 with self.subTest(action=action): 

110 response = self.client.post(self.url(action), {}) 

111 self.assertEqual(response.status_code, 403) 

112 

113 def test_post__authorized_access(self): 

114 for action in self.post_actions: 

115 with self.subTest(action=action): 

116 user = create_user_and_log_in(self.client, permissions=['{}_issue'.format(action)]) 

117 

118 response = self.client.post(self.url(action), {}) 

119 self.assertEqual(response.status_code, 302) 

120 self.assertEqual(response.url, reverse('CIResults-index')) 

121 

122 user.delete() 

123 

124 def test_get_on_post_action(self): 

125 for action in self.post_actions: 

126 with self.subTest(action=action): 

127 self.assertRaises(ValidationError, self.client.get, self.url(action)) 

128 

129 

130class TestTests(ViewMixin, TestCase): 

131 reverse_name = "CIResults-tests" 

132 

133 

134class TestMassRenameTests(ViewMixin, TestCase): 

135 reverse_name = "CIResults-tests-massrename" 

136 permissions_needed = ['change_test'] 

137 

138 

139class TestRenameTests(ViewMixin, TestCase): 

140 reverse_name = "CIResults-test-rename" 

141 permissions_needed = ['change_test'] 

142 

143 def setUp(self): 

144 testsuite = TestSuite.objects.create(name='ts1', public=True) 

145 t = Test.objects.create(name='test', testsuite=testsuite, public=True) 

146 self.view_kwargs = {'pk': t.pk} 

147 

148 

149class MachineTests(ViewMixin, TestCase): 

150 reverse_name = "CIResults-machines" 

151 

152 

153class TestResultListViewTests(UserFiltrableViewMixin, TestCase): 

154 reverse_name = "CIResults-results" 

155 query = "test_name = 'test'" 

156 

157 

158class KnownFailureListViewTests(UserFiltrableViewMixin, TestCase): 

159 reverse_name = "CIResults-knownfailures" 

160 query = "test_name = 'test'" 

161 

162 

163class ResultsCompareTests(ViewMixin, TestCase): 

164 reverse_name = "CIResults-compare" 

165 

166 def test_urlify(self): 

167 view = ResultsCompareView() 

168 string = "Hello http://gitlab.freedesktop.org, https://x.org" 

169 self.assertEqual(view.urlify(string), 

170 "Hello <http://gitlab.freedesktop.org>, <https://x.org>") 

171 

172 def test_invalid_runconfig(self): 

173 response = self.client.get(self.url + "?from=RUNCONFIG1&to=RUNCONFIG2") 

174 self.assertEqual(response.status_code, 200) 

175 

176 @patch('CIResults.models.RunConfig.objects.filter') 

177 def test_valid_runconfig(self, filter_mocked): 

178 filter_mocked.return_value.first.return_value.compare.return_value.text = "Test" 

179 response = self.client.get(self.url + "?from=RUNCONFIG1&to=RUNCONFIG2") 

180 self.assertEqual(response.status_code, 200) 

181 

182 

183class MassVettingMixin: 

184 def test_get_request_should_fail(self): 

185 create_user_and_log_in(self.client, permissions=[self.needed_permission]) 

186 response = self.client.get(self.url) 

187 self.assertEqual(response.status_code, 405) 

188 

189 def test_normal_query__without_privileges(self): 

190 create_user_and_log_in(self.client) 

191 response = self.client.post(self.url, {}) 

192 self.assertEqual(response.status_code, 403) 

193 

194 def test_normal_query__with_privileges(self): 

195 create_user_and_log_in(self.client, permissions=[self.needed_permission]) 

196 

197 with patch('CIResults.models.{}.objects.filter'.format(self.klass), 

198 return_value=[MagicMock(name='object 1'), 

199 MagicMock(name='object 2'), 

200 MagicMock(name='object 3')]) as filter_mocked: 

201 response = self.client.post(self.url, {'1': 'on', '2': 'on', '3': 'on', 'gfdgdfg': 'invalid'}) 

202 self.assertEqual(response.status_code, 302) 

203 

204 # Check that all the machines were requested from the DB 

205 filter_mocked.assert_called_once_with(pk__in=set([1, 2, 3])) 

206 

207 # Check that all machine returned were vetted 

208 for obj in filter_mocked.return_value: 

209 obj.vet.assert_called_once_with() 

210 

211 

212class MachineMassVettingTests(MassVettingMixin, TestCase): 

213 def setUp(self): 

214 self.url = reverse('CIResults-machine-mass-vetting') 

215 self.klass = "Machine" 

216 self.needed_permission = 'vet_machine' 

217 

218 

219class TestMassVettingTests(MassVettingMixin, TestCase): 

220 def setUp(self): 

221 self.url = reverse('CIResults-test-mass-vetting') 

222 self.klass = "Test" 

223 self.needed_permission = 'vet_test' 

224 

225 

226class TextStatustMassVettingTests(MassVettingMixin, TestCase): 

227 def setUp(self): 

228 self.url = reverse('CIResults-textstatus-mass-vetting') 

229 self.klass = "TextStatus" 

230 self.needed_permission = 'vet_textstatus' 

231 

232 

233class IssueDetailTests(ViewMixin, TestCase): 

234 reverse_name = "CIResults-issue-detail" 

235 

236 def setUp(self): 

237 issue = Issue.objects.create(filer='me@me.org', expected=True) 

238 self.view_kwargs = {'pk': issue.pk} 

239 

240 

241class IFADetailTests(ViewMixin, TestCase): 

242 reverse_name = "CIResults-ifa-detail" 

243 

244 def setUp(self): 

245 issue = Issue.objects.create(filer='me@me.org', expected=True) 

246 f = IssueFilter.objects.create(description='filter') 

247 

248 user = get_user_model().objects.create_user('user') 

249 issue.set_filters([f], user) 

250 pk = f.issuefilterassociated_set.first().pk 

251 self.view_kwargs = {'pk': pk} 

252 

253 

254class IssueFilterViewTests(TestCase): 

255 def setUp(self): 

256 self.issueFilterView = IssueFilterView() 

257 

258 def test_parse_filter_from_params(self): 

259 filter = self.issueFilterView.__parse_filter_from_params__( 

260 {"description": "Description", "stdout_regex": "stdout regex"} 

261 ) 

262 self.assertEqual(filter.description, "Description") 

263 self.assertEqual(filter.stdout_regex, "stdout regex") 

264 

265 def test_convert_to_user_query(self): 

266 arf = APIRequestFactory() 

267 request = arf.post("/", {"stderr_regex": "stderr regex"}, format="json") 

268 user_query = self.issueFilterView.__convert_to_user_query__(request) 

269 self.assertEqual(json.loads(user_query.content)["userQuery"], "stderr ~= 'stderr regex'") 

270 

271 

272class MachineDetailTests(ViewMixin, TestCase): 

273 reverse_name = "CIResults-machine-detail" 

274 

275 def setUp(self): 

276 machine = Machine.objects.create(name='Machine1', public=True) 

277 self.view_kwargs = {'pk': machine.pk} 

278 

279 

280class TestSuiteDetailTests(ViewMixin, TestCase): 

281 reverse_name = "CIResults-testsuite-detail" 

282 

283 def setUp(self): 

284 ts = TestSuite.objects.create(name='TestSuite', public=True) 

285 self.view_kwargs = {'pk': ts.pk} 

286 

287 

288class TestDetailTests(ViewMixin, TestCase): 

289 reverse_name = "CIResults-test-detail" 

290 

291 def setUp(self): 

292 ts = TestSuite.objects.create(name='TestSuite', public=True) 

293 test = Test.objects.create(name='test1', testsuite=ts, public=True) 

294 self.view_kwargs = {'pk': test.pk} 

295 

296 

297class TextStatusDetailTests(ViewMixin, TestCase): 

298 reverse_name = "CIResults-textstatus-detail" 

299 

300 def setUp(self): 

301 ts = TestSuite.objects.create(name='TestSuite', public=True) 

302 txt_stat = TextStatus.objects.create(name='status1', testsuite=ts) 

303 self.view_kwargs = {'pk': txt_stat.pk} 

304 

305 

306class TestResultDetailTests(ViewMixin, TestCase): 

307 reverse_name = "CIResults-testresult-detail" 

308 

309 def setUp(self): 

310 ts = TestSuite.objects.create(name='TestSuite', public=True) 

311 machine = Machine.objects.create(name='Machine1', public=True) 

312 runconfig = RunConfig.objects.create(name='runconfig', temporary=True) 

313 ts_run = TestsuiteRun.objects.create(testsuite=ts, machine=machine, runconfig=runconfig, 

314 run_id=0, start=timezone.now(), duration=timedelta(hours=3)) 

315 

316 test = Test.objects.create(name='test1', testsuite=ts, public=True) 

317 status = TextStatus.objects.create(name='status1', testsuite=ts) 

318 tr = TestResult.objects.create(test=test, status=status, ts_run=ts_run, 

319 start=timezone.now(), duration=timedelta(seconds=5)) 

320 self.view_kwargs = {'pk': tr.pk} 

321 

322 

323class RunConfigDetailTests(ViewMixin, TestCase): 

324 reverse_name = "CIResults-runcfg-detail" 

325 

326 def setUp(self): 

327 cfg = RunConfig.objects.create(name='runconfig', temporary=True) 

328 self.view_kwargs = {'pk': cfg.pk} 

329 

330 

331class RunConfigTagDetailTests(ViewMixin, TestCase): 

332 reverse_name = "CIResults-runcfgtag-detail" 

333 

334 def setUp(self): 

335 cfg = RunConfigTag.objects.create(name='tag', public=True) 

336 self.view_kwargs = {'pk': cfg.pk} 

337 

338 

339class BuildDetailTests(ViewMixin, TestCase): 

340 reverse_name = "CIResults-build-detail" 

341 

342 def setUp(self): 

343 component = Component.objects.create(name='component', public=True) 

344 build = Build.objects.create(name='build1', component=component) 

345 self.view_kwargs = {'pk': build.pk} 

346 

347 

348class ComponentDetailTests(ViewMixin, TestCase): 

349 reverse_name = "CIResults-component-detail" 

350 

351 def setUp(self): 

352 comp = Component.objects.create(name='runconfig', public=True) 

353 self.view_kwargs = {'pk': comp.pk}