1package autotest.tko;
2
3import autotest.common.JsonRpcCallback;
4import autotest.common.JsonRpcProxy;
5import autotest.common.PaddedJsonRpcProxy;
6import autotest.common.Utils;
7import autotest.common.ui.DetailView;
8import autotest.common.ui.NotifyManager;
9import autotest.common.ui.RealHyperlink;
10
11import com.google.gwt.event.logical.shared.OpenEvent;
12import com.google.gwt.event.logical.shared.OpenHandler;
13import com.google.gwt.event.logical.shared.ResizeEvent;
14import com.google.gwt.event.logical.shared.ResizeHandler;
15import com.google.gwt.json.client.JSONNumber;
16import com.google.gwt.json.client.JSONObject;
17import com.google.gwt.json.client.JSONString;
18import com.google.gwt.json.client.JSONValue;
19import com.google.gwt.user.client.Window;
20import com.google.gwt.user.client.ui.Composite;
21import com.google.gwt.user.client.ui.DisclosurePanel;
22import com.google.gwt.user.client.ui.FlexTable;
23import com.google.gwt.user.client.ui.FlowPanel;
24import com.google.gwt.user.client.ui.HTML;
25import com.google.gwt.user.client.ui.Panel;
26import com.google.gwt.user.client.ui.ScrollPanel;
27import com.google.gwt.user.client.ui.SimplePanel;
28
29import java.util.ArrayList;
30import java.util.Arrays;
31import java.util.Collections;
32import java.util.List;
33
34class TestDetailView extends DetailView {
35    private static final int NO_TEST_ID = -1;
36
37    private static final JsonRpcProxy logLoadingProxy =
38        new PaddedJsonRpcProxy(Utils.RETRIEVE_LOGS_URL);
39
40    private int testId = NO_TEST_ID;
41    private String jobTag;
42    private List<LogFileViewer> logFileViewers = new ArrayList<LogFileViewer>();
43    private RealHyperlink logLink = new RealHyperlink("(view all logs)");
44    private RealHyperlink testLogLink = new RealHyperlink("(view test logs)");
45    private Panel logPanel;
46    private Panel attributePanel = new SimplePanel();
47
48    private class LogFileViewer extends Composite
49                                implements OpenHandler<DisclosurePanel>, ResizeHandler {
50        private DisclosurePanel panel;
51        private ScrollPanel scroller; // ScrollPanel wrapping log contents
52        private String logFilePath;
53
54        private JsonRpcCallback rpcCallback = new JsonRpcCallback() {
55            @Override
56            public void onError(JSONObject errorObject) {
57                super.onError(errorObject);
58                String errorString = getErrorString(errorObject);
59                if (errorString.equals("")) {
60                    errorString = "Failed to load log "+ logFilePath;
61                }
62                setStatusText(errorString);
63            }
64
65            @Override
66            public void onSuccess(JSONValue result) {
67                handle(result);
68            }
69        };
70
71        public LogFileViewer(String logFilePath, String logFileName) {
72            this.logFilePath = logFilePath;
73            panel = new DisclosurePanel(logFileName);
74            panel.addOpenHandler(this);
75            panel.addStyleName("log-file-panel");
76            initWidget(panel);
77
78            Window.addResizeHandler(this);
79        }
80
81        @Override
82        public void onOpen(OpenEvent<DisclosurePanel> event) {
83            JSONObject params = new JSONObject();
84            params.put("path", new JSONString(getLogUrl()));
85            logLoadingProxy.rpcCall("dummy", params, rpcCallback);
86
87            setStatusText("Loading...");
88        }
89
90        private String getLogUrl() {
91            return Utils.getLogsUrl(jobTag + "/" + logFilePath);
92        }
93
94        public void handle(JSONValue value) {
95            String logContents = value.isString().stringValue();
96            if (logContents.equals("")) {
97                setStatusText("Log file is empty");
98            } else {
99                setLogText(logContents);
100            }
101        }
102
103        private void setLogText(String text) {
104            panel.clear();
105            scroller = new ScrollPanel();
106            scroller.getElement().setInnerText(text);
107            panel.add(scroller);
108            setScrollerWidth();
109        }
110
111        /**
112         * Firefox fails to set relative widths correctly for elements with overflow: scroll (or
113         * auto, or hidden).  Instead, it just expands the element to fit the contents.  So we use
114         * this trick to dynamically implement width: 100%.
115         */
116        private void setScrollerWidth() {
117            assert panel.isOpen();
118            scroller.setWidth("0px"); // allow the parent to assume its natural size
119            int targetWidthPx = scroller.getParent().getOffsetWidth();
120            NotifyManager.getInstance().log(targetWidthPx + "px");
121            scroller.setWidth(targetWidthPx + "px");
122        }
123
124        @Override
125        public void onResize(ResizeEvent event) {
126            if (panel.isOpen()) {
127                setScrollerWidth();
128            }
129        }
130
131        private void setStatusText(String status) {
132            panel.clear();
133            panel.add(new HTML("<i>" + status + "</i>"));
134        }
135    }
136
137    private static class AttributeTable extends Composite {
138        private DisclosurePanel container = new DisclosurePanel("Test attributes");
139        private FlexTable table = new FlexTable();
140
141        public AttributeTable(JSONObject attributes) {
142            processAttributes(attributes);
143            setupTableStyle();
144            container.add(table);
145            initWidget(container);
146        }
147
148        private void processAttributes(JSONObject attributes) {
149            if (attributes.size() == 0) {
150                table.setText(0, 0, "No test attributes");
151                return;
152            }
153
154            List<String> sortedKeys = new ArrayList<String>(attributes.keySet());
155            Collections.sort(sortedKeys);
156            for (String key : sortedKeys) {
157                String value = Utils.jsonToString(attributes.get(key));
158                int row = table.getRowCount();
159                table.setText(row, 0, key);
160                table.setText(row, 1, value);
161            }
162        }
163
164        private void setupTableStyle() {
165            container.addStyleName("test-attributes");
166        }
167    }
168
169    @Override
170    public void initialize() {
171        super.initialize();
172
173        addWidget(attributePanel, "td_attributes");
174        logPanel = new FlowPanel();
175        addWidget(logPanel, "td_log_files");
176        testLogLink.setOpensNewWindow(true);
177        addWidget(testLogLink, "td_view_logs_link");
178        logLink.setOpensNewWindow(true);
179        addWidget(logLink, "td_view_logs_link");
180    }
181
182    private void addLogViewers(String testName) {
183        logPanel.clear();
184        addLogFileViewer(testName + "/debug/" + testName + ".DEBUG", "Test debug log");
185        addLogFileViewer(testName + "/debug/" + testName + ".ERROR", "Test error log");
186        addLogFileViewer("status.log", "Job status log");
187        addLogFileViewer("debug/autoserv.DEBUG", "Job debug log");
188        addLogFileViewer("debug/autoserv.ERROR", "Job error log");
189    }
190
191    private void addLogFileViewer(String logPath, String logName) {
192        LogFileViewer viewer = new LogFileViewer(logPath, logName);
193        logFileViewers.add(viewer);
194        logPanel.add(viewer);
195    }
196
197    @Override
198    protected void fetchData() {
199        JSONObject params = new JSONObject();
200        params.put("test_idx", new JSONNumber(testId));
201        rpcProxy.rpcCall("get_detailed_test_views", params, new JsonRpcCallback() {
202            @Override
203            public void onSuccess(JSONValue result) {
204                JSONObject test;
205                try {
206                    test = Utils.getSingleObjectFromArray(result.isArray());
207                }
208                catch (IllegalArgumentException exc) {
209                    NotifyManager.getInstance().showError("No such job found");
210                    resetPage();
211                    return;
212                }
213
214                showTest(test);
215            }
216
217            @Override
218            public void onError(JSONObject errorObject) {
219                super.onError(errorObject);
220                resetPage();
221            }
222        });
223    }
224
225    @Override
226    protected void setObjectId(String id) {
227        try {
228            testId = Integer.parseInt(id);
229        }
230        catch (NumberFormatException exc) {
231            throw new IllegalArgumentException();
232        }
233    }
234
235    @Override
236    protected String getObjectId() {
237        if (testId == NO_TEST_ID) {
238            return NO_OBJECT;
239        }
240        return Integer.toString(testId);
241    }
242
243    @Override
244    protected String getDataElementId() {
245        return "td_data";
246    }
247
248    @Override
249    protected String getFetchControlsElementId() {
250        return "td_fetch_controls";
251    }
252
253    @Override
254    protected String getNoObjectText() {
255        return "No test selected";
256    }
257
258    @Override
259    protected String getTitleElementId() {
260        return "td_title";
261    }
262
263    @Override
264    public String getElementId() {
265        return "test_detail_view";
266    }
267
268    @Override
269    public void display() {
270        super.display();
271        CommonPanel.getPanel().setConditionVisible(false);
272    }
273
274    protected void showTest(JSONObject test) {
275        String testName = test.get("test_name").isString().stringValue();
276        jobTag = test.get("job_tag").isString().stringValue();
277
278        showText(testName, "td_test");
279        showText(jobTag, "td_job_tag");
280        showField(test, "job_name", "td_job_name");
281        showField(test, "status", "td_status");
282        showField(test, "reason", "td_reason");
283        showField(test, "test_started_time", "td_test_started");
284        showField(test, "test_finished_time", "td_test_finished");
285        showField(test, "hostname", "td_hostname");
286        showField(test, "platform", "td_platform");
287        showField(test, "kernel", "td_kernel");
288
289        String[] labels = Utils.JSONtoStrings(test.get("labels").isArray());
290        String labelList = Utils.joinStrings(", ", Arrays.asList(labels));
291        if (labelList.equals("")) {
292            labelList = "none";
293        }
294        showText(labelList, "td_test_labels");
295
296        JSONObject attributes = test.get("attributes").isObject();
297        attributePanel.clear();
298        attributePanel.add(new AttributeTable(attributes));
299
300        logLink.setHref(Utils.getRetrieveLogsUrl(jobTag));
301        testLogLink.setHref(Utils.getRetrieveLogsUrl(jobTag) + "/" + testName);
302        addLogViewers(testName);
303
304        displayObjectData("Test " + testName + " (job " + jobTag + ")");
305    }
306    @Override
307    public void resetPage() {
308        super.resetPage();
309    }
310}
311