xref: /aosp_15_r20/external/autotest/frontend/client/src/autotest/tko/SpreadsheetDataProcessor.java (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1 package autotest.tko;
2 
3 import autotest.common.StatusSummary;
4 import autotest.common.spreadsheet.Spreadsheet;
5 import autotest.common.spreadsheet.Spreadsheet.CellInfo;
6 import autotest.common.spreadsheet.Spreadsheet.Header;
7 import autotest.common.spreadsheet.Spreadsheet.HeaderImpl;
8 import autotest.common.table.DataSource.DataCallback;
9 import autotest.common.table.DataSource.Query;
10 import autotest.common.ui.NotifyManager;
11 
12 import com.google.gwt.core.client.Duration;
13 import com.google.gwt.json.client.JSONArray;
14 import com.google.gwt.json.client.JSONObject;
15 import com.google.gwt.user.client.Command;
16 import com.google.gwt.user.client.DeferredCommand;
17 import com.google.gwt.user.client.IncrementalCommand;
18 
19 import java.util.ArrayList;
20 import java.util.List;
21 
22 public class SpreadsheetDataProcessor implements DataCallback {
23     private static final NotifyManager notifyManager = NotifyManager.getInstance();
24     private static final int MAX_CELL_COUNT = 500000;
25     private static final int ROWS_PROCESSED_PER_ITERATION = 1000;
26 
27     private Spreadsheet spreadsheet;
28     private TestGroupDataSource dataSource;
29     private int numTotalTests;
30     private CellInfo lastCellInfo;
31 
32     private Header rowFields, columnFields;
33     private Command onFinished;
34     private Duration timer;
35     private Query currentQuery;
36 
37     public static class TooManyCellsError extends Exception {
38         public int cellCount;
39 
TooManyCellsError(int cellCount)40         public TooManyCellsError(int cellCount) {
41             super();
42             this.cellCount = cellCount;
43         }
44     }
45 
46     private class ProcessDataCommand implements IncrementalCommand {
47         private int state = 0;
48         private List<JSONObject> counts;
49         private int currentRow = 0;
50 
ProcessDataCommand(List<JSONObject> counts)51         public ProcessDataCommand(List<JSONObject> counts) {
52             this.counts = counts;
53         }
54 
processSomeRows()55         public void processSomeRows() {
56             for (int i = 0; i < ROWS_PROCESSED_PER_ITERATION; i++, currentRow++) {
57                 if (currentRow == counts.size()) {
58                     state++;
59                     return;
60                 }
61                 processRow(counts.get(currentRow).isObject());
62             }
63         }
64 
execute()65         public boolean execute() {
66             switch (state) {
67                 case 0:
68                     notifyManager.setLoading(true);
69                     numTotalTests = 0;
70                     try {
71                         processHeaders();
72                     } catch (TooManyCellsError exc) {
73                         notifyManager.showError("Resulting spreadsheet contains " + exc.cellCount +
74                                                 " cells, " + "exceeding maximum " + MAX_CELL_COUNT);
75                         finalizeCommand();
76                         return false;
77                     }
78                     break;
79                 case 1:
80                     spreadsheet.prepareForData();
81                     break;
82                 case 2:
83                     processSomeRows();
84                     return true;
85                 case 3:
86                     // we must make the spreadsheet visible before rendering, or size computations
87                     // won't work correctly
88                     spreadsheet.setVisible(true);
89                     break;
90                 case 4:
91                     spreadsheet.render(this);
92                     state++;
93                     return false; // render will re-add us to the command queue
94                 case 5:
95                     logTimer("Rendering");
96                     finalizeCommand();
97                     return false;
98             }
99 
100             state++;
101             return true;
102         }
103 
finalizeCommand()104         private void finalizeCommand() {
105             notifyManager.setLoading(false);
106             onFinished.execute();
107         }
108     }
109 
SpreadsheetDataProcessor(Spreadsheet spreadsheet)110     public SpreadsheetDataProcessor(Spreadsheet spreadsheet) {
111         this.spreadsheet = spreadsheet;
112     }
113 
processHeaders()114     public void processHeaders() throws TooManyCellsError {
115         spreadsheet.setHeaderFields(rowFields, columnFields);
116         List<List<String>> rowHeaderValues = dataSource.getHeaderGroupValues(0);
117         List<List<String>> columnHeaderValues = dataSource.getHeaderGroupValues(1);
118         int totalCells = rowHeaderValues.size() * columnHeaderValues.size();
119         if (totalCells > MAX_CELL_COUNT) {
120             throw new TooManyCellsError(totalCells);
121         }
122         for (List<String> header : rowHeaderValues) {
123             spreadsheet.addRowHeader(header);
124         }
125         for (List<String> header : columnHeaderValues) {
126             spreadsheet.addColumnHeader(header);
127         }
128     }
129 
processRow(JSONObject group)130     private void processRow(JSONObject group) {
131         JSONArray headerIndices = group.get("header_indices").isArray();
132         int row = (int) headerIndices.get(0).isNumber().doubleValue();
133         int column = (int) headerIndices.get(1).isNumber().doubleValue();
134         CellInfo cellInfo = spreadsheet.getCellInfo(row, column);
135         StatusSummary statusSummary = StatusSummary.getStatusSummary(
136             group,
137             TestGroupDataSource.PASS_COUNT_FIELD,
138             TestGroupDataSource.COMPLETE_COUNT_FIELD,
139             TestGroupDataSource.INCOMPLETE_COUNT_FIELD,
140             TestGroupDataSource.GROUP_COUNT_FIELD);
141         numTotalTests += statusSummary.getTotal();
142         cellInfo.contents = statusSummary.formatContents();
143         cellInfo.cssClass = statusSummary.getCssClass();
144         cellInfo.testCount = statusSummary.getTotal();
145         cellInfo.testIndex = (int) group.get("test_idx").isNumber().doubleValue();
146         lastCellInfo = cellInfo;
147     }
148 
refresh(JSONObject condition, Command onFinished)149     public void refresh(JSONObject condition, Command onFinished) {
150         timer = new Duration();
151         this.onFinished = onFinished;
152         dataSource.query(condition, this);
153     }
154 
onQueryReady(Query query)155     public void onQueryReady(Query query) {
156         currentQuery = query;
157         query.getPage(null, null, null, this);
158     }
159 
handlePage(List<JSONObject> data)160     public void handlePage(List<JSONObject> data) {
161         logTimer("Server response");
162         if (data.size() == 0) {
163             notifyManager.showMessage("No results for query");
164             onFinished.execute();
165             return;
166         }
167 
168         DeferredCommand.addCommand(new ProcessDataCommand(data));
169     }
170 
handleTotalResultCount(int totalCount)171     public void handleTotalResultCount(int totalCount) {}
172 
logTimer(String message)173     private void logTimer(String message) {
174         notifyManager.log(message + ": " + timer.elapsedMillis() + " ms");
175         timer = new Duration();
176     }
177 
getNumTotalTests()178     public int getNumTotalTests() {
179         return numTotalTests;
180     }
181 
182     /**
183      * This is useful when there turns out to be only a single test return.
184      * @return the last CellInfo created.  Should only really be called when there was only a single
185      *         one.
186      */
getLastCellInfo()187     public CellInfo getLastCellInfo() {
188         assert numTotalTests == 1;
189         return lastCellInfo;
190     }
191 
onError(JSONObject errorObject)192     public void onError(JSONObject errorObject) {
193         onFinished.execute();
194     }
195 
setHeaders(List<HeaderField> rowFields, List<HeaderField> columnFields, JSONObject queryParameters)196     public void setHeaders(List<HeaderField> rowFields, List<HeaderField> columnFields,
197                            JSONObject queryParameters) {
198         this.rowFields = getHeaderSqlNames(rowFields);
199         this.columnFields = getHeaderSqlNames(columnFields);
200 
201         List<List<String>> headerGroups = new ArrayList<List<String>>();
202         headerGroups.add(this.rowFields);
203         headerGroups.add(this.columnFields);
204         dataSource.setHeaderGroups(headerGroups);
205         dataSource.setQueryParameters(queryParameters);
206     }
207 
getHeaderSqlNames(List<HeaderField> fields)208     private Header getHeaderSqlNames(List<HeaderField> fields) {
209         Header header = new HeaderImpl();
210         for (HeaderField field : fields) {
211             header.add(field.getSqlName());
212         }
213         return header;
214     }
215 
setDataSource(TestGroupDataSource dataSource)216     public void setDataSource(TestGroupDataSource dataSource) {
217         this.dataSource = dataSource;
218     }
219 
getDataSource()220     public TestGroupDataSource getDataSource() {
221         return dataSource;
222     }
223 
getCurrentQuery()224     public Query getCurrentQuery() {
225         return currentQuery;
226     }
227 }
228