blob: 9d365e8f16fbfe4f9f8875039bdc224803e00604 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2016 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file or at
4# https://developers.google.com/open-source/licenses/bsd
5
6"""Tests for the ast2sort module."""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
11import unittest
12
13from proto import tracker_pb2
14from search import ast2sort
15from search import query2ast
16
17
18BUILTIN_ISSUE_FIELDS = query2ast.BUILTIN_ISSUE_FIELDS
19ANY_FIELD = query2ast.BUILTIN_ISSUE_FIELDS['any_field']
20
21
22class AST2SortTest(unittest.TestCase):
23
24 def setUp(self):
25 self.harmonized_labels = [
26 (101, 0, 'Hot'), (102, 1, 'Cold'), (103, None, 'Odd')]
27 self.harmonized_statuses = [
28 (201, 0, 'New'), (202, 1, 'Assigned'), (203, None, 'OnHold')]
29 self.harmonized_fields = []
30 self.fmt = lambda string, **kwords: string
31
32 def testBuildSortClauses_EmptySortDirectives(self):
33 left_joins, order_by = ast2sort.BuildSortClauses(
34 [], self.harmonized_labels, self.harmonized_statuses,
35 self.harmonized_fields)
36 self.assertEqual([], left_joins)
37 self.assertEqual([], order_by)
38
39 def testBuildSortClauses_Normal(self):
40 left_joins, order_by = ast2sort.BuildSortClauses(
41 ['stars', 'status', 'pri', 'reporter', 'id'], self.harmonized_labels,
42 self.harmonized_statuses, self.harmonized_fields)
43 expected_left_joins = [
44 ('User AS Sort3 ON Issue.reporter_id = Sort3.user_id', [])]
45 expected_order_by = [
46 ('Issue.star_count ASC', []),
47 ('FIELD(IF(ISNULL(Issue.status_id), Issue.derived_status_id, '
48 'Issue.status_id), %s,%s) DESC', [201, 202]),
49 ('FIELD(IF(ISNULL(Issue.status_id), Issue.derived_status_id, '
50 'Issue.status_id), %s) DESC', [203]),
51 ('ISNULL(Sort3.email) ASC', []),
52 ('Sort3.email ASC', []),
53 ('Issue.local_id ASC', [])]
54 self.assertEqual(expected_left_joins, left_joins)
55 self.assertEqual(expected_order_by, order_by)
56
57 def testProcessProjectSD(self):
58 left_joins, order_by = ast2sort._ProcessProjectSD(self.fmt)
59 self.assertEqual([], left_joins)
60 self.assertEqual(
61 [('Issue.project_id {sort_dir}', [])],
62 order_by)
63
64 def testProcessReporterSD(self):
65 left_joins, order_by = ast2sort._ProcessReporterSD(self.fmt)
66 self.assertEqual(
67 [('User AS {alias} ON Issue.reporter_id = {alias}.user_id', [])],
68 left_joins)
69 self.assertEqual(
70 [('ISNULL({alias}.email) {sort_dir}', []),
71 ('{alias}.email {sort_dir}', [])],
72 order_by)
73
74 def testProcessOwnerSD(self):
75 left_joins, order_by = ast2sort._ProcessOwnerSD(self.fmt)
76 self.assertEqual(
77 [('User AS {alias}_exp ON Issue.owner_id = {alias}_exp.user_id', []),
78 ('User AS {alias}_der ON '
79 'Issue.derived_owner_id = {alias}_der.user_id', [])],
80 left_joins)
81 self.assertEqual(
82 [('(ISNULL({alias}_exp.email) AND ISNULL({alias}_der.email)) '
83 '{sort_dir}', []),
84 ('CONCAT({alias}_exp.email, {alias}_der.email) {sort_dir}', [])],
85 order_by)
86
87 def testProcessCcSD(self):
88 left_joins, order_by = ast2sort._ProcessCcSD(self.fmt)
89 self.assertEqual(
90 [('Issue2Cc AS {alias} ON Issue.id = {alias}.issue_id '
91 'LEFT JOIN User AS {alias}_user '
92 'ON {alias}.cc_id = {alias}_user.user_id', [])],
93 left_joins)
94 self.assertEqual(
95 [('ISNULL({alias}_user.email) {sort_dir}', []),
96 ('{alias}_user.email {sort_dir}', [])],
97 order_by)
98
99 def testProcessComponentSD(self):
100 left_joins, order_by = ast2sort._ProcessComponentSD(self.fmt)
101 self.assertEqual(
102 [('Issue2Component AS {alias} ON Issue.id = {alias}.issue_id '
103 'LEFT JOIN ComponentDef AS {alias}_component '
104 'ON {alias}.component_id = {alias}_component.id', [])],
105 left_joins)
106 self.assertEqual(
107 [('ISNULL({alias}_component.path) {sort_dir}', []),
108 ('{alias}_component.path {sort_dir}', [])],
109 order_by)
110
111 def testProcessSummarySD(self):
112 left_joins, order_by = ast2sort._ProcessSummarySD(self.fmt)
113 self.assertEqual(
114 [('IssueSummary AS {alias} ON Issue.id = {alias}.issue_id', [])],
115 left_joins)
116 self.assertEqual(
117 [('{alias}.summary {sort_dir}', [])],
118 order_by)
119
120 def testProcessStatusSD(self):
121 pass # TODO(jrobbins): fill in this test case
122
123 def testProcessBlockedSD(self):
124 left_joins, order_by = ast2sort._ProcessBlockedSD(self.fmt)
125 self.assertEqual(
126 [('IssueRelation AS {alias} ON Issue.id = {alias}.issue_id '
127 'AND {alias}.kind = %s', ['blockedon'])],
128 left_joins)
129 self.assertEqual(
130 [('ISNULL({alias}.dst_issue_id) {sort_dir}', [])],
131 order_by)
132
133 def testProcessBlockedOnSD(self):
134 left_joins, order_by = ast2sort._ProcessBlockedOnSD(self.fmt)
135 self.assertEqual(
136 [('IssueRelation AS {alias} ON Issue.id = {alias}.issue_id '
137 'AND {alias}.kind = %s', ['blockedon'])],
138 left_joins)
139 self.assertEqual(
140 [('ISNULL({alias}.dst_issue_id) {sort_dir}', []),
141 ('{alias}.dst_issue_id {sort_dir}', [])],
142 order_by)
143
144 def testProcessBlockingSD(self):
145 left_joins, order_by = ast2sort._ProcessBlockingSD(self.fmt)
146 self.assertEqual(
147 [('IssueRelation AS {alias} ON Issue.id = {alias}.dst_issue_id '
148 'AND {alias}.kind = %s', ['blockedon'])],
149 left_joins)
150 self.assertEqual(
151 [('ISNULL({alias}.issue_id) {sort_dir}', []),
152 ('{alias}.issue_id {sort_dir}', [])],
153 order_by)
154
155 def testProcessMergedIntoSD(self):
156 left_joins, order_by = ast2sort._ProcessMergedIntoSD(self.fmt)
157 self.assertEqual(
158 [('IssueRelation AS {alias} ON Issue.id = {alias}.issue_id '
159 'AND {alias}.kind = %s', ['mergedinto'])],
160 left_joins)
161 self.assertEqual(
162 [('ISNULL({alias}.dst_issue_id) {sort_dir}', []),
163 ('{alias}.dst_issue_id {sort_dir}', [])],
164 order_by)
165
166 def testProcessCustomAndLabelSD(self):
167 pass # TODO(jrobbins): fill in this test case
168
169 def testProcessCustomAndLabelSD_PhaseField(self):
170 harmonized_labels = []
171 bear_fd = tracker_pb2.FieldDef(
172 field_id=1, field_name='DropBear', project_id=789,
173 field_type=tracker_pb2.FieldTypes.INT_TYPE)
174 bear2_fd = tracker_pb2.FieldDef(
175 field_id=2, field_name='DropBear', project_id=788,
176 field_type=tracker_pb2.FieldTypes.STR_TYPE)
177 koala_fd = tracker_pb2.FieldDef(
178 field_id=3, field_name='koala', project_id=789,
179 field_type=tracker_pb2.FieldTypes.INT_TYPE)
180 bear_app_fd = tracker_pb2.FieldDef(
181 field_id=4, field_name='dropbear', project_id=789,
182 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
183 harmonized_fields = [bear_fd, bear2_fd, koala_fd, bear_app_fd]
184 phase_name = 'stable'
185 alias = 'Sort0'
186 sort_dir = 'DESC'
187 sd = 'stable.dropbear'
188 left_joins, order_by = ast2sort._ProcessCustomAndLabelSD(
189 sd, harmonized_labels, harmonized_fields, alias, sort_dir,
190 self.fmt)
191
192 expected_joins = []
193 expected_order = []
194 int_left_joins, int_order_by = ast2sort._CustomFieldSortClauses(
195 [bear_fd, bear2_fd], tracker_pb2.FieldTypes.INT_TYPE, 'int_value',
196 alias, sort_dir, phase_name=phase_name)
197 str_left_joins, str_order_by = ast2sort._CustomFieldSortClauses(
198 [bear_fd, bear2_fd], tracker_pb2.FieldTypes.STR_TYPE, 'str_value',
199 alias, sort_dir, phase_name=phase_name)
200 user_left_joins, user_order_by = ast2sort._CustomFieldSortClauses(
201 [bear_fd, bear2_fd], tracker_pb2.FieldTypes.USER_TYPE, 'user_id',
202 alias, sort_dir, phase_name=phase_name)
203 label_left_joinss, label_order_by = ast2sort._LabelSortClauses(
204 sd, harmonized_labels, self.fmt)
205 expected_joins.extend(
206 int_left_joins + str_left_joins + user_left_joins + label_left_joinss)
207 expected_order.extend(
208 int_order_by + str_order_by + user_order_by + label_order_by)
209 self.assertEqual(left_joins, expected_joins)
210 self.assertEqual(order_by, expected_order)
211
212 def testApprovalFieldSortClauses_Status(self):
213 approval_fd_list = [
214 tracker_pb2.FieldDef(field_id=2, project_id=789,
215 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE),
216 tracker_pb2.FieldDef(field_id=4, project_id=788,
217 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
218 ]
219 left_joins, order_by = ast2sort._ApprovalFieldSortClauses(
220 approval_fd_list, '-status', self.fmt)
221
222 self.assertEqual(
223 [('{tbl_name} AS {alias}_approval '
224 'ON Issue.id = {alias}_approval.issue_id '
225 'AND {alias}_approval.approval_id IN ({approval_ids_ph})', [2, 4])],
226 left_joins)
227
228 self.assertEqual(
229 [('FIELD({alias}_approval.status, {approval_status_ph}) {rev_sort_dir}',
230 ast2sort.APPROVAL_STATUS_SORT_ORDER)],
231 order_by)
232
233 def testApprovalFieldSortClauses_Approver(self):
234 approval_fd_list = [
235 tracker_pb2.FieldDef(field_id=2, project_id=789,
236 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE),
237 tracker_pb2.FieldDef(field_id=4, project_id=788,
238 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
239 ]
240 left_joins, order_by = ast2sort._ApprovalFieldSortClauses(
241 approval_fd_list, '-approver', self.fmt)
242
243 self.assertEqual(
244 [('{tbl_name} AS {alias}_approval '
245 'ON Issue.id = {alias}_approval.issue_id '
246 'AND {alias}_approval.approval_id IN ({approval_ids_ph})', [2, 4]),
247 ('User AS {alias}_approval_user '
248 'ON {alias}_approval.approver_id = {alias}_approval_user.user_id',
249 [])],
250 left_joins)
251
252 self.assertEqual(
253 [('ISNULL({alias}_approval_user.email) {sort_dir}', []),
254 ('{alias}_approval_user.email {sort_dir}', [])],
255 order_by)
256
257 def testLabelSortClauses_NoSuchLabels(self):
258 sd = 'somethingelse'
259 harmonized_labels = [
260 (101, 0, 'Type-Defect'),
261 (102, 1, 'Type-Enhancement'),
262 (103, 2, 'Type-Task'),
263 (104, 0, 'Priority-High'),
264 (199, None, 'Type-Laundry'),
265 ]
266 left_joins, order_by = ast2sort._LabelSortClauses(
267 sd, harmonized_labels, self.fmt)
268 self.assertEqual([], left_joins)
269 self.assertEqual([], order_by)
270
271 def testLabelSortClauses_Normal(self):
272 sd = 'type'
273 harmonized_labels = [
274 (101, 0, 'Type-Defect'),
275 (102, 1, 'Type-Enhancement'),
276 (103, 2, 'Type-Task'),
277 (104, 0, 'Priority-High'),
278 (199, None, 'Type-Laundry'),
279 ]
280 left_joins, order_by = ast2sort._LabelSortClauses(
281 sd, harmonized_labels, self.fmt)
282 self.assertEqual(1, len(left_joins))
283 self.assertEqual(
284 ('Issue2Label AS {alias} ON Issue.id = {alias}.issue_id AND '
285 '{alias}.label_id IN ({all_label_ph})',
286 [101, 102, 103, 199]),
287 left_joins[0])
288 self.assertEqual(2, len(order_by))
289 self.assertEqual(
290 ('FIELD({alias}.label_id, {wk_label_ph}) {rev_sort_dir}',
291 [101, 102, 103]),
292 order_by[0])
293 self.assertEqual(
294 ('FIELD({alias}.label_id, {odd_label_ph}) {rev_sort_dir}',
295 [199]),
296 order_by[1])
297
298 def testCustomFieldSortClauses_Normal(self):
299 fd_list = [
300 tracker_pb2.FieldDef(field_id=1, project_id=789,
301 field_type=tracker_pb2.FieldTypes.INT_TYPE),
302 tracker_pb2.FieldDef(field_id=2, project_id=788,
303 field_type=tracker_pb2.FieldTypes.STR_TYPE),
304 ]
305 left_joins, order_by = ast2sort._CustomFieldSortClauses(
306 fd_list, tracker_pb2.FieldTypes.INT_TYPE, 'int_value', 'Sort0', 'DESC')
307
308 self.assertEqual(
309 left_joins, [
310 ('Issue2FieldValue AS Sort0_int_value '
311 'ON Issue.id = Sort0_int_value.issue_id '
312 'AND Sort0_int_value.field_id IN (%s)', [1]),
313 ])
314 self.assertEqual(
315 order_by, [
316 ('ISNULL(Sort0_int_value.int_value) DESC', []),
317 ('Sort0_int_value.int_value DESC', []),
318 ])
319
320 def testCustomFieldSortClauses_PhaseUser(self):
321 fd_list = [
322 tracker_pb2.FieldDef(field_id=1, project_id=789,
323 field_type=tracker_pb2.FieldTypes.INT_TYPE),
324 tracker_pb2.FieldDef(field_id=2, project_id=788,
325 field_type=tracker_pb2.FieldTypes.STR_TYPE),
326 tracker_pb2.FieldDef(field_id=3, project_id=788,
327 field_type=tracker_pb2.FieldTypes.USER_TYPE),
328 ]
329 left_joins, order_by = ast2sort._CustomFieldSortClauses(
330 fd_list, tracker_pb2.FieldTypes.USER_TYPE, 'user_id', 'Sort0', 'DESC',
331 phase_name='Stable')
332
333 self.assertEqual(
334 left_joins, [
335 ('Issue2FieldValue AS Sort0_user_id '
336 'ON Issue.id = Sort0_user_id.issue_id '
337 'AND Sort0_user_id.field_id IN (%s)', [3]),
338 ('IssuePhaseDef AS Sort0_user_id_phase '
339 'ON Sort0_user_id.phase_id = Sort0_user_id_phase.id '
340 'AND LOWER(Sort0_user_id_phase.name) = LOWER(%s)', ['Stable']),
341 ('User AS Sort0_user_id_user '
342 'ON Sort0_user_id.user_id = Sort0_user_id_user.user_id', []),
343 ])
344 self.assertEqual(
345 order_by, [
346 ('ISNULL(Sort0_user_id_user.email) DESC', []),
347 ('Sort0_user_id_user.email DESC', []),
348 ])
349
350 def testOneSortDirective_NativeSortable(self):
351 left_joins, order_by = ast2sort._OneSortDirective(
352 1, 'opened', self.harmonized_labels, self.harmonized_statuses,
353 self.harmonized_fields)
354 self.assertEqual([], left_joins)
355 self.assertEqual([('Issue.opened ASC', [])], order_by)
356
357 left_joins, order_by = ast2sort._OneSortDirective(
358 1, 'stars', self.harmonized_labels, self.harmonized_statuses,
359 self.harmonized_fields)
360 self.assertEqual([], left_joins)
361 self.assertEqual([('Issue.star_count ASC', [])], order_by)
362
363 left_joins, order_by = ast2sort._OneSortDirective(
364 1, '-stars', self.harmonized_labels, self.harmonized_statuses,
365 self.harmonized_fields)
366 self.assertEqual([], left_joins)
367 self.assertEqual([('Issue.star_count DESC', [])], order_by)
368
369 left_joins, order_by = ast2sort._OneSortDirective(
370 1, 'componentmodified', self.harmonized_labels,
371 self.harmonized_statuses, self.harmonized_fields)
372 self.assertEqual([], left_joins)
373 self.assertEqual([('Issue.component_modified ASC', [])], order_by)