Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(613)

Side by Side Diff: appengine/findit/util_scripts/crash_queries/delta_test/delta_test.py

Issue 2400283003: [Findit] Add skeleton code for delta test script. (Closed)
Patch Set: Rebase. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import json
6 import logging
7 import os
8 import pickle
9 import subprocess
10
11 from crash_queries import crash_iterator
12 from crash_queries.delta_test import delta_util
13
14 AZALEA_RESULTS_DIRECTORY = os.path.join(os.path.dirname(__file__),
15 'azalea_results')
16 DELTA_TEST_DIRECTORY = os.path.dirname(__file__)
17
18
19 class Delta(object):
20 """Stands for delta between two results."""
21
22 def __init__(self, result1, result2, fields):
23 self._result1 = result1
24 self._result2 = result2
25 self._fields = fields
26 self._delta_dict = {}
27 self._delta_str_dict = {}
28
29 @property
30 def delta_dict(self):
31 """Dict representation of delta."""
lijeffrey 2016/10/20 15:52:14 is it possible to include an example of what the r
Sharu Jiang 2016/10/20 22:39:06 Done.
32 if self._delta_dict:
33 return self._delta_dict
34
35 for field in self._fields:
36 value1 = getattr(self._result1, field)
37 value2 = getattr(self._result2, field)
38 if value1 != value2:
39 if hasattr(value1, 'ToDict') and callable(value1.ToDict):
40 value1 = value1.ToDict()
41 value2 = value2.ToDict()
lijeffrey 2016/10/20 15:52:14 does value2 need to be checked if callable(value2.
Sharu Jiang 2016/10/20 22:39:06 The result1 and result2 should be the same kind, s
42 self._delta_dict[field] = (value1, value2)
43
44 return self._delta_dict
45
46 @property
47 def delta_str_dict(self):
48 """Converts delta of each field to a string."""
49 if self._delta_str_dict:
50 return self._delta_str_dict
51
52 for key, (value1, value2) in self.delta_dict.iteritems():
53 self._delta_str_dict[key] = '%s: %s, %s' % (key, value1, value2)
54
55 return self._delta_str_dict
56
57 def ToDict(self):
58 return self.delta_dict
59
60 def __str__(self):
61 return '\n'.join(self.delta_str_dict.values())
62
63 def __bool__(self):
64 return bool(self.delta_dict)
65
66 def __nonzero__(self):
67 return self.__bool__()
68
69
70 def GetDeltasFromTwoSetsOfResults(set1, set2):
71 """Gets delta from two sets of results.
72
lijeffrey 2016/10/20 15:52:14 nit: include in the docstring that set1 and set2 a
Sharu Jiang 2016/10/20 22:39:06 Done.
73 Results are a list of (message, matches, component_name, cr_label)
74 Returns a list of delta results (results1, results2).
75 """
76 deltas = {}
77 for crash_id, result1 in set1.iteritems():
78 # Even when the command are exactly the same, it's possible that one set is
79 # loaded from local result file, another is just queried from database,
80 # sometimes some crash results would get deleted.
81 if crash_id not in set2:
lijeffrey 2016/10/20 15:52:14 nit: set2.keys()?
Sharu Jiang 2016/10/20 22:39:06 This is valid usage for dict.
82 continue
83
84 result2 = set2[crash_id]
85 delta = Delta(result1, result2, result1.fields)
86 if delta:
87 deltas[crash_id] = delta
88
89 return deltas
90
91
92 def GetResults(crashes, client_id, git_hash, result_path, verbose=False):
93 """Returns an evaluator function to compute delta between 2 findit githashes.
94
95 Args:
96 crashes (list): A list of crash infos.
97 client_id (str): Possible values - fracas/cracas/clustefuzz.
98 git_hash (str): A git hash of findit repository.
99 result_path (str): file path for subprocess to write results on.
100 verbose (bool): If True, print all the findit results.
101
102 Return:
103 A dict mapping crash id to culprit for every crashes analyzed by
104 git_hash version.
105 """
106 if not crashes:
107 return {}
108
109 if verbose:
110 logging.info('\n\n***************************')
111 logging.info('Switch to git %s', git_hash)
lijeffrey 2016/10/20 15:52:14 nit: Switching?
Sharu Jiang 2016/10/20 22:39:06 Done.
112 logging.info('***************************\n\n')
113
114 dev_null_handle = open(os.devnull, 'w')
115 subprocess.check_call(
116 'cd %s; git checkout %s' % (DELTA_TEST_DIRECTORY, git_hash),
117 stdout=dev_null_handle,
118 stderr=dev_null_handle,
119 shell=True)
120
121 if not os.path.exists(result_path):
122 args = ['python', 'run-azalea.py', result_path, '--client', client_id]
123 if verbose:
124 args.append('--verbose')
125 p = subprocess.Popen(args, stdin=subprocess.PIPE)
126 p.communicate(input=json.dumps(crashes))
stgao 2016/10/20 01:40:20 Just a note: not sure if the passing a big chunk o
Sharu Jiang 2016/10/20 22:39:06 It works fine for the largest batch, and the crash
127 else:
128 logging.info('\nLoading results from %s', result_path)
129
130 if not os.path.exists(result_path):
131 logging.error('Fail to get results.')
lijeffrey 2016/10/20 15:52:14 nit: Failed
Sharu Jiang 2016/10/20 22:39:06 Done.
132 return {}
133
134 with open(result_path) as f:
stgao 2016/10/20 01:40:20 As the result_path is passed in, why this function
Sharu Jiang 2016/10/20 22:39:06 We can read the file outside this function however
stgao 2016/10/21 01:41:39 Then why we pass the result_path into this functio
Sharu Jiang 2016/10/21 18:45:53 The result path is needed so we can check whether
135 return pickle.load(f)
136
137 return {}
138
139
140 def DeltaEvaluator(git_hash1, git_hash2,
141 client_id, app_id,
142 start_date, end_date, batch_size,
143 property_values=None, verbose=False):
144 """Evaluates delta between git_hash1 and git_hash2 on a set of Testcases.
145
146 Args:
147 git_hash1 (str): A git hash of findit repository.
148 git_hash2 (str): A git hash of findit repository.
149 start_date (str): Run delta test on testcases after (including)
150 the start_date, format should be '%Y-%m-%d'.
151 end_date (str): Run delta test on testcases before (not including)
152 the end_date, format should be '%Y-%m-%d'.
153 client_id (CrashClient): Possible values are 'fracas', 'cracas',
154 'cluterfuzz'.
155 app_id (str): Appengine app id to query.
156 batch_size (int): Size of a batch that can be queried at one time.
157 property_values (dict): Property values to query.
158 batch_size (int): The size of crashes that can be queried at one time.
159 verbose (bool): If True, print all the findit results.
160 Return:
161 (deltas, crash_count).
162 deltas (dict): Mappings id to delta for each culprit value.
163 crash_count (int): Total count of all the crashes.
164 """
165 head_branch_name = subprocess.check_output(
166 ['git', 'rev-parse', '--abbrev-ref', 'HEAD']).replace('\n', '')
167 try:
168 deltas = {}
169 crash_count = 0
170 for index, crashes in enumerate(
171 crash_iterator.IterateCrashes(client_id, app_id,
172 property_values=property_values,
173 start_date=start_date,
174 end_date=end_date,
175 batch_size=batch_size,
176 batch_run=True)):
177
178 results = []
179 for git_hash in [git_hash1, git_hash2]:
180 result_path = os.path.join(
181 AZALEA_RESULTS_DIRECTORY, delta_util.GenerateFileName(
182 client_id, property_values, start_date, end_date,
183 batch_size, index, git_hash))
184 results.append(GetResults(crashes, client_id, git_hash, result_path,
185 verbose=verbose))
186
187 crash_count += len(crashes)
188 deltas.update(GetDeltasFromTwoSetsOfResults(*results))
189
190 return deltas, crash_count
191 finally:
192 dev_null_handle = open(os.devnull, 'w')
stgao 2016/10/20 01:40:20 Should we do a with clause here? Otherwise a file
Sharu Jiang 2016/10/20 22:39:06 Done.
193 subprocess.check_call(['git', 'checkout', head_branch_name],
194 stdout=dev_null_handle,
195 stderr=dev_null_handle)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698