• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package autotest.afe.create;
2 
3 import autotest.afe.AfeUtils;
4 import autotest.afe.CheckBoxPanel;
5 import autotest.afe.ControlTypeSelect;
6 import autotest.afe.HostSelector;
7 import autotest.afe.IButton;
8 import autotest.afe.ICheckBox;
9 import autotest.afe.ITextArea;
10 import autotest.afe.ITextBox;
11 import autotest.afe.RadioChooser;
12 import autotest.afe.TestSelector;
13 import autotest.afe.TestSelector.TestSelectorListener;
14 import autotest.common.JSONArrayList;
15 import autotest.common.JsonRpcCallback;
16 import autotest.common.JsonRpcProxy;
17 import autotest.common.SimpleCallback;
18 import autotest.common.StaticDataRepository;
19 import autotest.common.Utils;
20 import autotest.common.ui.NotifyManager;
21 import autotest.common.ui.SimplifiedList;
22 import autotest.common.ui.ExtendedListBox;
23 
24 import com.google.gwt.event.dom.client.BlurEvent;
25 import com.google.gwt.event.dom.client.BlurHandler;
26 import com.google.gwt.event.dom.client.ChangeEvent;
27 import com.google.gwt.event.dom.client.ChangeHandler;
28 import com.google.gwt.event.dom.client.ClickEvent;
29 import com.google.gwt.event.dom.client.ClickHandler;
30 import com.google.gwt.event.dom.client.HasClickHandlers;
31 import com.google.gwt.event.dom.client.KeyCodes;
32 import com.google.gwt.event.dom.client.KeyPressEvent;
33 import com.google.gwt.event.dom.client.KeyPressHandler;
34 import com.google.gwt.event.logical.shared.CloseEvent;
35 import com.google.gwt.event.logical.shared.CloseHandler;
36 import com.google.gwt.event.logical.shared.HasCloseHandlers;
37 import com.google.gwt.event.logical.shared.HasOpenHandlers;
38 import com.google.gwt.event.logical.shared.OpenEvent;
39 import com.google.gwt.event.logical.shared.OpenHandler;
40 import com.google.gwt.json.client.JSONArray;
41 import com.google.gwt.json.client.JSONBoolean;
42 import com.google.gwt.json.client.JSONNull;
43 import com.google.gwt.json.client.JSONNumber;
44 import com.google.gwt.json.client.JSONObject;
45 import com.google.gwt.json.client.JSONString;
46 import com.google.gwt.json.client.JSONValue;
47 import com.google.gwt.user.client.DOM;
48 import com.google.gwt.user.client.Window;
49 import com.google.gwt.user.client.ui.DisclosurePanel;
50 import com.google.gwt.user.client.ui.HasText;
51 import com.google.gwt.user.client.ui.HasValue;
52 
53 import java.util.ArrayList;
54 import java.util.HashMap;
55 import java.util.List;
56 import java.util.Map;
57 
58 import java.lang.Math;
59 
60 public class CreateJobViewPresenter implements TestSelectorListener {
61     public static interface Display {
getCheckBoxPanelDisplay()62         public CheckBoxPanel.Display getCheckBoxPanelDisplay();
getControlTypeSelectDisplay()63         public ControlTypeSelect.Display getControlTypeSelectDisplay();
getTestSelectorDisplay()64         public TestSelector.Display getTestSelectorDisplay();
getEditControlButton()65         public IButton getEditControlButton();
getJobName()66         public HasText getJobName();
getPriorityList()67         public ExtendedListBox getPriorityList();
getTimeout()68         public HasText getTimeout();
getMaxRuntime()69         public HasText getMaxRuntime();
getTestRetry()70         public HasText getTestRetry();
getEmailList()71         public HasText getEmailList();
getSkipVerify()72         public ICheckBox getSkipVerify();
getSkipReset()73         public ICheckBox getSkipReset();
getRebootBefore()74         public RadioChooser.Display getRebootBefore();
getRebootAfter()75         public RadioChooser.Display getRebootAfter();
getParseFailedRepair()76         public HasValue<Boolean> getParseFailedRepair();
getHostless()77         public ICheckBox getHostless();
getRequireSSP()78         public ICheckBox getRequireSSP();
getPool()79         public HasText getPool();
getArgs()80         public ITextBox getArgs();
getHostSelectorDisplay()81         public HostSelector.Display getHostSelectorDisplay();
getDroneSet()82         public SimplifiedList getDroneSet();
getSynchCountInput()83         public ITextBox getSynchCountInput();
getControlFile()84         public ITextArea getControlFile();
setControlFilePanelOpen(boolean isOpen)85         public void setControlFilePanelOpen(boolean isOpen);
getRunNonProfiledIteration()86         public ICheckBox getRunNonProfiledIteration();
getKernel()87         public ITextBox getKernel();
getKernelCmdline()88         public ITextBox getKernelCmdline();
getImageUrl()89         public ITextBox getImageUrl();
getViewLink()90         public HasText getViewLink();
getControlFilePanelClose()91         public HasCloseHandlers<DisclosurePanel> getControlFilePanelClose();
getControlFilePanelOpen()92         public HasOpenHandlers<DisclosurePanel> getControlFilePanelOpen();
getSubmitJobButton()93         public IButton getSubmitJobButton();
getCreateTemplateJobButton()94         public HasClickHandlers getCreateTemplateJobButton();
getResetButton()95         public HasClickHandlers getResetButton();
getFetchImageTestsButton()96         public HasClickHandlers getFetchImageTestsButton();
getFirmwareRWBuild()97         public ITextBox getFirmwareRWBuild();
getFirmwareROBuild()98         public ITextBox getFirmwareROBuild();
getTestSourceBuildList()99         public ExtendedListBox getTestSourceBuildList();
100     }
101 
102     private static final String EDIT_CONTROL_STRING = "Edit control file";
103     private static final String UNEDIT_CONTROL_STRING= "Revert changes";
104     private static final String VIEW_CONTROL_STRING = "View control file";
105     private static final String HIDE_CONTROL_STRING = "Hide control file";
106     private static final String FIRMWARE_RW_BUILD = "firmware_rw_build";
107     private static final String FIRMWARE_RO_BUILD = "firmware_ro_build";
108     private static final String TEST_SOURCE_BUILD = "test_source_build";
109 
110     public interface JobCreateListener {
onJobCreated(int jobId)111         public void onJobCreated(int jobId);
112     }
113 
114     private interface IPredicate<T> {
apply(T item)115         boolean apply(T item);
116     }
117 
118     private IPredicate<Integer> positiveIntegerPredicate = new IPredicate<Integer>() {
119         public boolean apply(Integer item) {
120             return item > 0;
121         }
122     };
123 
124     private IPredicate<Integer> nonnegativeIntegerPredicate = new IPredicate<Integer>() {
125         public boolean apply(Integer item) {
126             return item >= 0;
127         }
128     };
129 
130     private IPredicate<Integer> anyIntegerPredicate = new IPredicate<Integer>() {
131         public boolean apply(Integer item) {
132             return true;
133         }
134     };
135 
136     private JsonRpcProxy rpcProxy = JsonRpcProxy.getProxy();
137     private JobCreateListener listener;
138 
139     private StaticDataRepository staticData = StaticDataRepository.getRepository();
140 
141     private CheckBoxPanel profilersPanel = new CheckBoxPanel();
142     private ControlTypeSelect controlTypeSelect = new ControlTypeSelect();
143     protected TestSelector testSelector = new TestSelector();
144     private RadioChooser rebootBefore = new RadioChooser();
145     private RadioChooser rebootAfter = new RadioChooser();
146     private HostSelector hostSelector;
147 
148     private boolean controlEdited = false;
149     private boolean controlReadyForSubmit = false;
150     private JSONArray dependencies = new JSONArray();
151 
152     private Display display;
153 
bindDisplay(Display display)154     public void bindDisplay(Display display) {
155         this.display = display;
156     }
157 
CreateJobViewPresenter(JobCreateListener listener)158     public CreateJobViewPresenter(JobCreateListener listener) {
159         this.listener = listener;
160     }
161 
cloneJob(JSONValue cloneInfo)162     public void cloneJob(JSONValue cloneInfo) {
163         // reset() fires the TestSelectorListener, which will generate a new control file. We do
164         // no want this, so we'll stop listening to it for a bit.
165         testSelector.setListener(null);
166         reset();
167         testSelector.setListener(this);
168 
169         disableInputs();
170         openControlFileEditor();
171         JSONObject cloneObject = cloneInfo.isObject();
172         JSONObject jobObject = cloneObject.get("job").isObject();
173 
174         display.getJobName().setText(jobObject.get("name").isString().stringValue());
175 
176         ArrayList<String> builds = new ArrayList<String>();
177         if (jobObject.containsKey("image")) {
178             String image = jobObject.get("image").isString().stringValue();
179             builds.add(image);
180             display.getImageUrl().setText(image);
181             display.getFirmwareRWBuild().setEnabled(true);
182             display.getFirmwareROBuild().setEnabled(true);
183             display.getTestSourceBuildList().setEnabled(true);
184         }
185 
186         if (jobObject.containsKey(FIRMWARE_RW_BUILD)) {
187             String firmwareRWBuild = jobObject.get(FIRMWARE_RW_BUILD).isString().stringValue();
188             builds.add(firmwareRWBuild);
189             display.getFirmwareRWBuild().setText(firmwareRWBuild);
190         }
191 
192         if (jobObject.containsKey(FIRMWARE_RO_BUILD)) {
193             String firmwareROBuild = jobObject.get(FIRMWARE_RO_BUILD).isString().stringValue();
194             builds.add(firmwareROBuild);
195             display.getFirmwareROBuild().setText(firmwareROBuild);
196         }
197 
198         for (String build : builds) {
199             display.getTestSourceBuildList().addItem(build);
200         }
201 
202         if (jobObject.containsKey(TEST_SOURCE_BUILD)) {
203             String testSourceBuild = jobObject.get(TEST_SOURCE_BUILD).isString().stringValue();
204             if (builds.indexOf(testSourceBuild) >= 0) {
205                 display.getTestSourceBuildList().setSelectedIndex(builds.indexOf(testSourceBuild));
206             }
207         }
208 
209         Double priorityValue = jobObject.get("priority").isNumber().getValue();
210         Double maxPriority = staticData.getData("max_schedulable_priority").isNumber().getValue();
211         if (priorityValue > maxPriority) {
212             priorityValue = maxPriority;
213         }
214         String priorityName = staticData.getPriorityName(priorityValue);
215         display.getPriorityList().selectByName(priorityName);
216 
217         display.getTimeout().setText(Utils.jsonToString(jobObject.get("timeout_mins")));
218         display.getMaxRuntime().setText(Utils.jsonToString(jobObject.get("max_runtime_mins")));
219         display.getTestRetry().setText(Utils.jsonToString(jobObject.get("test_retry")));
220         display.getEmailList().setText(
221                 jobObject.get("email_list").isString().stringValue());
222 
223         display.getSkipVerify().setValue(!jobObject.get("run_verify").isBoolean().booleanValue());
224         display.getSkipReset().setValue(!jobObject.get("run_reset").isBoolean().booleanValue());
225         rebootBefore.setSelectedChoice(Utils.jsonToString(jobObject.get("reboot_before")));
226         rebootAfter.setSelectedChoice(Utils.jsonToString(jobObject.get("reboot_after")));
227         display.getParseFailedRepair().setValue(
228                 jobObject.get("parse_failed_repair").isBoolean().booleanValue());
229         display.getHostless().setValue(cloneObject.get("hostless").isBoolean().booleanValue());
230         if (display.getHostless().getValue()) {
231             hostSelector.setEnabled(false);
232         }
233         if (jobObject.get("require_ssp").isNull() != null)
234             display.getRequireSSP().setValue(false);
235         else
236             display.getRequireSSP().setValue(jobObject.get("require_ssp").isBoolean().booleanValue());
237         if (staticData.getData("drone_sets_enabled").isBoolean().booleanValue()) {
238             if (cloneObject.get("drone_set").isNull() == null) {
239                 display.getDroneSet().selectByName(Utils.jsonToString(cloneObject.get("drone_set")));
240             }
241         }
242 
243         controlTypeSelect.setControlType(
244                 jobObject.get("control_type").isString().stringValue());
245         display.getSynchCountInput().setText(Utils.jsonToString(jobObject.get("synch_count")));
246         setSelectedDependencies(jobObject.get("dependencies").isArray());
247         display.getControlFile().setText(
248                 jobObject.get("control_file").isString().stringValue());
249         controlReadyForSubmit = true;
250 
251         JSONArray hostInfo = cloneObject.get("hosts").isArray();
252         List<String> hostnames = new ArrayList<String>();
253         for (JSONObject host : new JSONArrayList<JSONObject>(hostInfo)) {
254             hostnames.add(Utils.jsonToString(host.get("hostname")));
255         }
256         hostSelector.setSelectedHostnames(hostnames, true);
257 
258         JSONObject metaHostCounts = cloneObject.get("meta_host_counts").isObject();
259 
260         for (String label : metaHostCounts.keySet()) {
261             String number = Integer.toString(
262                 (int) metaHostCounts.get(label).isNumber().doubleValue());
263             hostSelector.addMetaHosts(label, number);
264         }
265 
266         hostSelector.refresh();
267     }
268 
openControlFileEditor()269     private void openControlFileEditor() {
270         display.getControlFile().setReadOnly(false);
271         display.getEditControlButton().setText(UNEDIT_CONTROL_STRING);
272         display.setControlFilePanelOpen(true);
273         controlTypeSelect.setEnabled(true);
274         display.getSynchCountInput().setEnabled(true);
275         display.getEditControlButton().setEnabled(true);
276     }
277 
populatePriorities(JSONArray priorities)278     private void populatePriorities(JSONArray priorities) {
279         JSONValue maxSchedulableValue = staticData.getData("max_schedulable_priority");
280         double maxPriority = maxSchedulableValue.isNumber().getValue();
281         for(int i = 0; i < priorities.size(); i++) {
282             JSONArray priorityData = priorities.get(i).isArray();
283             String priority = priorityData.get(1).isString().stringValue();
284             double priorityValue = priorityData.get(0).isNumber().getValue();
285             String strPriorityValue = Double.toString(priorityValue);
286             if (priorityValue <= maxPriority) {
287                 display.getPriorityList().addItem(priority, strPriorityValue);
288             }
289         }
290 
291         resetPriorityToDefault();
292     }
293 
resetPriorityToDefault()294     private void resetPriorityToDefault() {
295         JSONValue defaultValue = staticData.getData("default_priority");
296         String defaultPriority = defaultValue.isString().stringValue();
297         display.getPriorityList().selectByName(defaultPriority);
298     }
299 
populateProfilers()300     private void populateProfilers() {
301         JSONArray tests = staticData.getData("profilers").isArray();
302 
303         for(JSONObject profiler : new JSONArrayList<JSONObject>(tests)) {
304             String name = profiler.get("name").isString().stringValue();
305             ICheckBox checkbox = profilersPanel.generateCheckBox();
306             checkbox.setText(name);
307             checkbox.addClickHandler(new ClickHandler() {
308                 public void onClick(ClickEvent event) {
309                     updateNonProfiledRunControl();
310                     generateControlFile(false);
311                     setInputsEnabled();
312                 }
313             });
314             profilersPanel.add(checkbox);
315         }
316 
317         display.getRunNonProfiledIteration().addClickHandler(new ClickHandler() {
318             @Override
319             public void onClick(ClickEvent event) {
320                 generateControlFile(false);
321             }
322         });
323         // default to checked -- run a non-profiled iteration by default
324         display.getRunNonProfiledIteration().setValue(true);
325     }
326 
updateNonProfiledRunControl()327     private void updateNonProfiledRunControl() {
328         boolean anyProfilersChecked = !profilersPanel.getChecked().isEmpty();
329         display.getRunNonProfiledIteration().setVisible(anyProfilersChecked);
330     }
331 
populateRebootChoices()332     private void populateRebootChoices() {
333         AfeUtils.populateRadioChooser(rebootBefore, "reboot_before");
334         AfeUtils.populateRadioChooser(rebootAfter, "reboot_after");
335     }
336 
337 
getKernelParams(String kernel_list, String cmdline)338     private JSONArray getKernelParams(String kernel_list, String cmdline) {
339         JSONArray result = new JSONArray();
340 
341         for(String version: kernel_list.split("[, ]+")) {
342             Map<String, String> item = new HashMap<String, String>();
343 
344             item.put("version", version);
345             // if there is a cmdline part, put it for all versions in the map
346             if (cmdline.length() > 0) {
347                 item.put("cmdline", cmdline);
348             }
349 
350             result.set(result.size(), Utils.mapToJsonObject(item));
351         }
352 
353         return result;
354     }
355     /**
356      * Get parameters to submit to the generate_control_file RPC.
357      * @param readyForSubmit are we getting a control file that's ready to submit for a job, or just
358      * an intermediate control file to be viewed by the user?
359      */
getControlFileParams(boolean readyForSubmit)360     protected JSONObject getControlFileParams(boolean readyForSubmit) {
361         JSONObject params = new JSONObject();
362 
363         String kernelString = display.getKernel().getText();
364         if (!kernelString.equals("")) {
365             params.put(
366                     "kernel", getKernelParams(kernelString, display.getKernelCmdline().getText()));
367         }
368 
369         boolean testsFromBuild = testSelector.usingTestsFromBuild();
370         params.put("db_tests", JSONBoolean.getInstance(!testsFromBuild));
371 
372         JSONArray tests = new JSONArray();
373         for (JSONObject test : testSelector.getSelectedTests()) {
374             if (testsFromBuild) {
375                 tests.set(tests.size(), test);
376             }
377             else {
378                 tests.set(tests.size(), test.get("id"));
379             }
380         }
381         params.put("tests", tests);
382 
383         JSONArray profilers = new JSONArray();
384         for (ICheckBox profiler : profilersPanel.getChecked()) {
385             profilers.set(profilers.size(), new JSONString(profiler.getText()));
386         }
387         params.put("profilers", profilers);
388 
389         if (display.getRunNonProfiledIteration().isVisible()) {
390             boolean profileOnly = !display.getRunNonProfiledIteration().getValue();
391             params.put("profile_only", JSONBoolean.getInstance(profileOnly));
392         }
393 
394         return params;
395     }
396 
generateControlFile(final boolean readyForSubmit, final SimpleCallback finishedCallback, final SimpleCallback errorCallback)397     private void generateControlFile(final boolean readyForSubmit,
398                                        final SimpleCallback finishedCallback,
399                                        final SimpleCallback errorCallback) {
400         JSONObject params = getControlFileParams(readyForSubmit);
401         rpcProxy.rpcCall("generate_control_file", params, new JsonRpcCallback() {
402             @Override
403             public void onSuccess(JSONValue result) {
404                 JSONObject controlInfo = result.isObject();
405                 String controlFileText = controlInfo.get("control_file").isString().stringValue();
406                 boolean isServer = controlInfo.get("is_server").isBoolean().booleanValue();
407                 String synchCount = Utils.jsonToString(controlInfo.get("synch_count"));
408                 setSelectedDependencies(controlInfo.get("dependencies").isArray());
409                 display.getControlFile().setText(controlFileText);
410                 controlTypeSelect.setControlType(isServer ? TestSelector.SERVER_TYPE :
411                                                             TestSelector.CLIENT_TYPE);
412                 display.getSynchCountInput().setText(synchCount);
413                 controlReadyForSubmit = readyForSubmit;
414                 if (finishedCallback != null) {
415                     finishedCallback.doCallback(this);
416                 }
417             }
418 
419             @Override
420             public void onError(JSONObject errorObject) {
421                 super.onError(errorObject);
422                 if (errorCallback != null) {
423                     errorCallback.doCallback(this);
424                 }
425             }
426         });
427     }
428 
generateControlFile(boolean readyForSubmit)429     protected void generateControlFile(boolean readyForSubmit) {
430         generateControlFile(readyForSubmit, null, null);
431     }
432 
handleSkipVerify()433     public void handleSkipVerify() {
434         boolean shouldSkipVerify = false;
435         for (JSONObject test : testSelector.getSelectedTests()) {
436             boolean runVerify = test.get("run_verify").isBoolean().booleanValue();
437             if (!runVerify) {
438                 shouldSkipVerify = true;
439                 break;
440             }
441         }
442 
443         if (shouldSkipVerify) {
444             display.getSkipVerify().setValue(true);
445             display.getSkipVerify().setEnabled(false);
446         } else {
447             display.getSkipVerify().setEnabled(true);
448         }
449     }
450 
handleSkipReset()451     public void handleSkipReset() {
452         boolean shouldSkipReset = false;
453         for (JSONObject test : testSelector.getSelectedTests()) {
454             boolean runReset = test.get("run_reset").isBoolean().booleanValue();
455             if (!runReset) {
456                 shouldSkipReset = true;
457                 break;
458             }
459         }
460 
461         if (shouldSkipReset) {
462             display.getSkipReset().setValue(true);
463             display.getSkipReset().setEnabled(false);
464         } else {
465             display.getSkipReset().setEnabled(true);
466         }
467     }
468 
getMaximumRetriesCount()469     protected int getMaximumRetriesCount() {
470         int maxRetries = 0;
471         for (JSONObject test : testSelector.getSelectedTests()) {
472             maxRetries = (int) Math.max(maxRetries, test.get("test_retry").isNumber().getValue());
473         }
474         return maxRetries;
475     }
476 
handleBuildChange()477     protected void handleBuildChange() {
478         ChangeHandler handler = new ChangeHandler() {
479             @Override
480             public void onChange(ChangeEvent event) {
481                 String image = display.getImageUrl().getText();
482                 if (image.isEmpty()) {
483                     display.getFirmwareRWBuild().setText("");
484                     display.getFirmwareROBuild().setText("");
485                     display.getTestSourceBuildList().clear();
486                     display.getFirmwareRWBuild().setEnabled(false);
487                     display.getFirmwareROBuild().setEnabled(false);
488                     display.getTestSourceBuildList().setEnabled(false);
489                 }
490                 else {
491                     display.getFirmwareRWBuild().setEnabled(true);
492                     display.getFirmwareROBuild().setEnabled(true);
493                     display.getTestSourceBuildList().setEnabled(true);
494                     ArrayList<String> builds = new ArrayList<String>();
495                     builds.add(image);
496                     if (!display.getFirmwareRWBuild().getText().isEmpty())
497                         builds.add(display.getFirmwareRWBuild().getText());
498                     if (!display.getFirmwareROBuild().getText().isEmpty())
499                         builds.add(display.getFirmwareROBuild().getText());
500                     String currentTestSourceBuild = display.getTestSourceBuildList().getSelectedValue();
501                     int testSourceBuildIndex = builds.indexOf(currentTestSourceBuild);
502                     display.getTestSourceBuildList().clear();
503                     for (String build : builds) {
504                         display.getTestSourceBuildList().addItem(build);
505                     }
506                     if (testSourceBuildIndex >= 0) {
507                         display.getTestSourceBuildList().setSelectedIndex(testSourceBuildIndex);
508                     }
509                 }
510             }
511         };
512 
513         display.getImageUrl().addChangeHandler(handler);
514         display.getFirmwareRWBuild().addChangeHandler(handler);
515         display.getFirmwareROBuild().addChangeHandler(handler);
516     }
517 
setInputsEnabled()518     protected void setInputsEnabled() {
519         testSelector.setEnabled(true);
520         profilersPanel.setEnabled(true);
521         handleSkipVerify();
522         handleSkipReset();
523         display.getKernel().setEnabled(true);
524         display.getKernelCmdline().setEnabled(true);
525         display.getImageUrl().setEnabled(true);
526     }
527 
disableInputs()528     protected void disableInputs() {
529         testSelector.setEnabled(false);
530         profilersPanel.setEnabled(false);
531         display.getKernel().setEnabled(false);
532         display.getKernelCmdline().setEnabled(false);
533         display.getImageUrl().setEnabled(false);
534     }
535 
initialize()536     public void initialize() {
537         profilersPanel.bindDisplay(display.getCheckBoxPanelDisplay());
538         controlTypeSelect.bindDisplay(display.getControlTypeSelectDisplay());
539         testSelector.bindDisplay(display.getTestSelectorDisplay());
540         rebootBefore.bindDisplay(display.getRebootBefore());
541         rebootAfter.bindDisplay(display.getRebootAfter());
542 
543         display.getEditControlButton().setText(EDIT_CONTROL_STRING);
544         display.getViewLink().setText(VIEW_CONTROL_STRING);
545 
546         hostSelector = new HostSelector();
547         hostSelector.initialize();
548         hostSelector.bindDisplay(display.getHostSelectorDisplay());
549 
550         populatePriorities(staticData.getData("priorities").isArray());
551 
552         BlurHandler kernelBlurHandler = new BlurHandler() {
553             public void onBlur(BlurEvent event) {
554                 generateControlFile(false);
555             }
556         };
557 
558         display.getKernel().addBlurHandler(kernelBlurHandler);
559         display.getKernelCmdline().addBlurHandler(kernelBlurHandler);
560 
561         KeyPressHandler kernelKeyPressHandler = new KeyPressHandler() {
562             public void onKeyPress(KeyPressEvent event) {
563                 if (event.getCharCode() == (char) KeyCodes.KEY_ENTER) {
564                     generateControlFile(false);
565                 }
566             }
567         };
568 
569         display.getKernel().addKeyPressHandler(kernelKeyPressHandler);
570         display.getKernelCmdline().addKeyPressHandler(kernelKeyPressHandler);
571 
572         populateProfilers();
573         updateNonProfiledRunControl();
574 
575         populateRebootChoices();
576         onPreferencesChanged();
577 
578         if (parameterizedJobsEnabled()) {
579             display.getEditControlButton().setEnabled(false);
580         }
581 
582         display.getEditControlButton().addClickHandler(new ClickHandler() {
583             public void onClick(ClickEvent event) {
584                 DOM.eventCancelBubble(DOM.eventGetCurrentEvent(), true);
585 
586                 if (display.getEditControlButton().getText().equals(EDIT_CONTROL_STRING)) {
587                     disableInputs();
588                     display.getEditControlButton().setEnabled(false);
589                     SimpleCallback onGotControlFile = new SimpleCallback() {
590                         public void doCallback(Object source) {
591                             openControlFileEditor();
592                         }
593                     };
594                     SimpleCallback onControlFileError = new SimpleCallback() {
595                         public void doCallback(Object source) {
596                             setInputsEnabled();
597                             display.getEditControlButton().setEnabled(true);
598                         }
599                     };
600                     generateControlFile(true, onGotControlFile, onControlFileError);
601                 }
602                 else {
603                     if (controlEdited &&
604                         !Window.confirm("Are you sure you want to revert your" +
605                                         " changes?")) {
606                         return;
607                     }
608                     generateControlFile(false);
609                     display.getControlFile().setReadOnly(true);
610                     setInputsEnabled();
611                     display.getEditControlButton().setText(EDIT_CONTROL_STRING);
612                     controlTypeSelect.setEnabled(false);
613                     display.getSynchCountInput().setEnabled(false);
614                     controlEdited = false;
615                 }
616             }
617         });
618 
619         display.getControlFile().addChangeHandler(new ChangeHandler() {
620             public void onChange(ChangeEvent event) {
621                 controlEdited = true;
622             }
623         });
624 
625         display.getControlFilePanelClose().addCloseHandler(new CloseHandler<DisclosurePanel>() {
626             public void onClose(CloseEvent<DisclosurePanel> event) {
627                 display.getViewLink().setText(VIEW_CONTROL_STRING);
628             }
629         });
630 
631         display.getControlFilePanelOpen().addOpenHandler(new OpenHandler<DisclosurePanel>() {
632             public void onOpen(OpenEvent<DisclosurePanel> event) {
633                 display.getViewLink().setText(HIDE_CONTROL_STRING);
634             }
635         });
636 
637         display.getSubmitJobButton().addClickHandler(new ClickHandler() {
638             public void onClick(ClickEvent event) {
639                 submitJob(false);
640             }
641         });
642 
643         display.getCreateTemplateJobButton().addClickHandler(new ClickHandler() {
644             public void onClick(ClickEvent event) {
645                 submitJob(true);
646             }
647         });
648 
649         display.getResetButton().addClickHandler(new ClickHandler() {
650             public void onClick(ClickEvent event) {
651                 reset();
652             }
653         });
654 
655         display.getHostless().addClickHandler(new ClickHandler() {
656             @Override
657             public void onClick(ClickEvent event) {
658                 hostSelector.setEnabled(!display.getHostless().getValue());
659             }
660         });
661 
662         display.getFetchImageTestsButton().addClickHandler(new ClickHandler() {
663             public void onClick(ClickEvent event) {
664                 String imageUrl = display.getImageUrl().getText();
665                 if (imageUrl == null || imageUrl.isEmpty()) {
666                     NotifyManager.getInstance().showMessage(
667                         "No build was specified for fetching tests.");
668                 }
669                 fetchImageTests();
670             }
671         });
672 
673         handleBuildChange();
674 
675         reset();
676 
677         if (staticData.getData("drone_sets_enabled").isBoolean().booleanValue()) {
678             AfeUtils.populateListBox(display.getDroneSet(), "drone_sets");
679         } else {
680             AfeUtils.removeElement("create_drone_set_wrapper");
681         }
682 
683         testSelector.setListener(this);
684     }
685 
reset()686     public void reset() {
687         StaticDataRepository repository = StaticDataRepository.getRepository();
688 
689         display.getJobName().setText("");
690         resetPriorityToDefault();
691         rebootBefore.reset();
692         rebootAfter.reset();
693         display.getParseFailedRepair().setValue(
694                 repository.getData("parse_failed_repair_default").isBoolean().booleanValue());
695         display.getHostless().setValue(false);
696         // Default require_ssp to False, since it's not applicable to client side test.
697         display.getRequireSSP().setValue(false);
698         display.getKernel().setText("");
699         display.getKernelCmdline().setText("");
700         display.getImageUrl().setText("");
701         display.getTimeout().setText(Utils.jsonToString(repository.getData("job_timeout_mins_default")));
702         display.getMaxRuntime().setText(
703                 Utils.jsonToString(repository.getData("job_max_runtime_mins_default")));
704         display.getTestRetry().setText("");
705         display.getEmailList().setText("");
706         testSelector.reset();
707         display.getSkipVerify().setValue(true);
708         display.getSkipReset().setValue(false);
709         profilersPanel.reset();
710         setInputsEnabled();
711         controlTypeSelect.setControlType(TestSelector.CLIENT_TYPE);
712         controlTypeSelect.setEnabled(false);
713         display.getSynchCountInput().setEnabled(false);
714         display.getSynchCountInput().setText("1");
715         display.getControlFile().setText("");
716         display.getControlFile().setReadOnly(true);
717         controlEdited = false;
718         display.setControlFilePanelOpen(false);
719         display.getEditControlButton().setText(EDIT_CONTROL_STRING);
720         hostSelector.reset();
721         dependencies = new JSONArray();
722         display.getPool().setText("");
723         display.getArgs().setText("");
724         display.getImageUrl().setText("");
725         fetchImageTests();
726     }
727 
submitJob(final boolean isTemplate)728     private void submitJob(final boolean isTemplate) {
729         final int timeoutValue, maxRuntimeValue, testRetryValue;
730         final JSONValue synchCount;
731         try {
732             timeoutValue = parsePositiveIntegerInput(display.getTimeout().getText(), "timeout");
733             maxRuntimeValue = parsePositiveIntegerInput(
734                     display.getMaxRuntime().getText(), "max runtime");
735             String testRetryText = display.getTestRetry().getText();
736             if (testRetryText == "")
737                 testRetryValue = getMaximumRetriesCount();
738             else
739                 testRetryValue = parseNonnegativeIntegerInput(testRetryText, "test retries");
740 
741             if (display.getHostless().getValue()) {
742                 synchCount = JSONNull.getInstance();
743             } else {
744                 synchCount = new JSONNumber(parsePositiveIntegerInput(
745                     display.getSynchCountInput().getText(),
746                     "number of machines used per execution"));
747             }
748         } catch (IllegalArgumentException exc) {
749             return;
750         }
751 
752         // disallow accidentally clicking submit twice
753         display.getSubmitJobButton().setEnabled(false);
754 
755         final SimpleCallback doSubmit = new SimpleCallback() {
756             public void doCallback(Object source) {
757                 JSONObject args = new JSONObject();
758                 args.put("name", new JSONString(display.getJobName().getText()));
759                 String priority = display.getPriorityList().getSelectedValue();
760                 args.put("priority", new JSONNumber(Double.parseDouble(priority)));
761                 args.put("control_file", new JSONString(display.getControlFile().getText()));
762                 args.put("control_type",
763                          new JSONString(controlTypeSelect.getControlType()));
764                 args.put("synch_count", synchCount);
765                 args.put("timeout_mins", new JSONNumber(timeoutValue));
766                 args.put("max_runtime_mins", new JSONNumber(maxRuntimeValue));
767                 args.put("test_retry", new JSONNumber(testRetryValue));
768                 args.put("email_list", new JSONString(display.getEmailList().getText()));
769                 args.put("run_verify", JSONBoolean.getInstance(
770                         !display.getSkipVerify().getValue()));
771                 args.put("run_reset", JSONBoolean.getInstance(
772                         !display.getSkipReset().getValue()));
773                 args.put("is_template", JSONBoolean.getInstance(isTemplate));
774                 args.put("dependencies", getSelectedDependencies());
775                 args.put("reboot_before", new JSONString(rebootBefore.getSelectedChoice()));
776                 args.put("reboot_after", new JSONString(rebootAfter.getSelectedChoice()));
777                 args.put("parse_failed_repair",
778                          JSONBoolean.getInstance(display.getParseFailedRepair().getValue()));
779                 args.put("hostless", JSONBoolean.getInstance(display.getHostless().getValue()));
780                 args.put("require_ssp", JSONBoolean.getInstance(display.getRequireSSP().getValue()));
781                 args.put("pool", new JSONString(display.getPool().getText()));
782 
783                 if (staticData.getData("drone_sets_enabled").isBoolean().booleanValue()) {
784                     args.put("drone_set", new JSONString(display.getDroneSet().getSelectedName()));
785                 }
786 
787                 HostSelector.HostSelection hosts = hostSelector.getSelectedHosts();
788                 args.put("hosts", Utils.stringsToJSON(hosts.hosts));
789                 args.put("meta_hosts", Utils.stringsToJSON(hosts.metaHosts));
790                 args.put("one_time_hosts",
791                     Utils.stringsToJSON(hosts.oneTimeHosts));
792 
793                 String imageUrlString = display.getImageUrl().getText();
794                 if (!imageUrlString.equals("")) {
795                     args.put("image", new JSONString(imageUrlString));
796                 }
797                 else if (display.getHostless().getValue() &&
798                          testSuiteSelected()) {
799                     display.getSubmitJobButton().setEnabled(true);
800                     NotifyManager.getInstance().showError("Please specify an image to use.");
801                     return;
802                 }
803 
804 
805                 String argsString = display.getArgs().getText().trim();
806                 if (!argsString.equals("")) {
807                     JSONArray argsArray = new JSONArray();
808                     for (String arg : argsString.split(",")) {
809                         argsArray.set(argsArray.size(), new JSONString(arg.trim()));
810                     }
811                     args.put("args", argsArray);
812                 }
813 
814                 // TODO(crbug.com/464962): Fall back to build in cros-version label if possible.
815                 // Validate server-side packaging requirements
816                 if (display.getRequireSSP().getValue()) {
817                     String error = "";
818                     if (controlTypeSelect.getControlType() == "Client") {
819                         error = "Client side test does not need server-side packaging.";
820                     }
821                     else if (imageUrlString.equals("")) {
822                       boolean has_cros_version_dependency = false;
823                       for (int i = 0; i < getSelectedDependencies().size(); i++) {
824                         String dep = getSelectedDependencies().get(i).toString();
825                         if (dep.startsWith("\"cros-version:")) {
826                           has_cros_version_dependency = true;
827                           break;
828                         }
829                       }
830                       if (!has_cros_version_dependency)
831                         error = "You must specify an image to run test with server-side packaging.";
832                     }
833 
834                     if (error != "") {
835                         display.getSubmitJobButton().setEnabled(true);
836                         NotifyManager.getInstance().showError(error);
837                         return;
838                     }
839                 }
840 
841                 String firmwareRWBuild = display.getFirmwareRWBuild().getText();
842                 String firmwareROBuild = display.getFirmwareROBuild().getText();
843                 String testSourceBuild = display.getTestSourceBuildList().getSelectedValue();
844                 if (!firmwareRWBuild.isEmpty() || !firmwareROBuild.isEmpty()) {
845                     String error = "";
846                     if (testSourceBuild.isEmpty())
847                         error = "You must specify which build should be used to retrieve test code.";
848 
849                     // TODO(crbug.com/502638): Enable create test job with updating firmware.
850                     if (!display.getHostless().getValue())
851                         error = "Only suite job supports updating both ChromeOS build and firmware build.";
852                     if (error != "") {
853                         display.getSubmitJobButton().setEnabled(true);
854                         NotifyManager.getInstance().showError(error);
855                         return;
856                     }
857                     if (!firmwareRWBuild.isEmpty())
858                         args.put(FIRMWARE_RW_BUILD, new JSONString(firmwareRWBuild));
859                     if (!firmwareROBuild.isEmpty())
860                         args.put(FIRMWARE_RO_BUILD, new JSONString(firmwareROBuild));
861                     args.put(TEST_SOURCE_BUILD, new JSONString(testSourceBuild));
862                 }
863 
864                 rpcProxy.rpcCall("create_job_page_handler", args, new JsonRpcCallback() {
865                     @Override
866                     public void onSuccess(JSONValue result) {
867                         int id = (int) result.isNumber().doubleValue();
868                         NotifyManager.getInstance().showMessage(
869                                     "Job " + Integer.toString(id) + " created");
870                         reset();
871                         if (listener != null) {
872                             listener.onJobCreated(id);
873                         }
874                         display.getSubmitJobButton().setEnabled(true);
875                     }
876 
877                     @Override
878                     public void onError(JSONObject errorObject) {
879                         super.onError(errorObject);
880                         display.getSubmitJobButton().setEnabled(true);
881                     }
882                 });
883             }
884         };
885 
886         // ensure control file is ready for submission
887         if (!controlReadyForSubmit) {
888             generateControlFile(true, doSubmit, new SimpleCallback() {
889                 public void doCallback(Object source) {
890                     display.getSubmitJobButton().setEnabled(true);
891                 }
892             });
893         } else {
894             doSubmit.doCallback(this);
895         }
896     }
897 
getSelectedDependencies()898     private JSONArray getSelectedDependencies() {
899         return dependencies;
900     }
901 
setSelectedDependencies(JSONArray dependencies)902     private void setSelectedDependencies(JSONArray dependencies) {
903         this.dependencies = dependencies;
904     }
905 
parseNonnegativeIntegerInput(String input, String fieldName)906     private int parseNonnegativeIntegerInput(String input, String fieldName) {
907         return parsePredicatedIntegerInput(input, fieldName,
908                                            nonnegativeIntegerPredicate,
909                                            "non-negative");
910     }
911 
parsePositiveIntegerInput(String input, String fieldName)912     private int parsePositiveIntegerInput(String input, String fieldName) {
913         return parsePredicatedIntegerInput(input, fieldName,
914                                            positiveIntegerPredicate,
915                                            "positive");
916     }
917 
parseAnyIntegerInput(String input, String fieldName)918     private int parseAnyIntegerInput(String input, String fieldName) {
919         return parsePredicatedIntegerInput(input, fieldName,
920                                            anyIntegerPredicate,
921                                            "integer");
922     }
923 
parsePredicatedIntegerInput(String input, String fieldName, IPredicate<Integer> predicate, String domain)924     private int parsePredicatedIntegerInput(String input, String fieldName,
925                                             IPredicate<Integer> predicate,
926                                             String domain) {
927         final int parsedInt;
928         try {
929             if (input.equals("") ||
930                 !predicate.apply(parsedInt = Integer.parseInt(input))) {
931                     String error = "Please enter a " + domain + " " + fieldName;
932                     NotifyManager.getInstance().showError(error);
933                     throw new IllegalArgumentException();
934             }
935         } catch (NumberFormatException e) {
936             String error = "Invalid " + fieldName + ": \"" + input + "\"";
937             NotifyManager.getInstance().showError(error);
938             throw new IllegalArgumentException();
939         }
940         return parsedInt;
941     }
942 
refresh()943     public void refresh() {
944         hostSelector.refresh();
945     }
946 
onTestSelectionChanged()947     public void onTestSelectionChanged() {
948         generateControlFile(false);
949         setInputsEnabled();
950 
951         // Set hostless selection to true if the test name contains test_suites
952         display.getHostless().setValue(false);
953         hostSelector.setEnabled(true);
954 
955         if (testSuiteSelected()) {
956             display.getHostless().setValue(true);
957             hostSelector.setEnabled(false);
958         }
959     }
960 
testSuiteSelected()961     private boolean testSuiteSelected() {
962         for (JSONObject test : testSelector.getSelectedTests()) {
963             if (Utils.jsonToString(test.get("name")).toLowerCase().contains("test_suites:"))
964             {
965                 return true;
966             }
967         }
968 
969         return false;
970     }
971 
setRebootSelectorDefault(RadioChooser chooser, String name)972     private void setRebootSelectorDefault(RadioChooser chooser, String name) {
973         JSONObject user = staticData.getData("current_user").isObject();
974         String defaultOption = Utils.jsonToString(user.get(name));
975         chooser.setDefaultChoice(defaultOption);
976     }
977 
selectPreferredDroneSet()978     private void selectPreferredDroneSet() {
979         JSONObject user = staticData.getData("current_user").isObject();
980         JSONValue droneSet = user.get("drone_set");
981         if (droneSet.isNull() == null) {
982             String preference = Utils.jsonToString(user.get("drone_set"));
983             display.getDroneSet().selectByName(preference);
984         }
985     }
986 
onPreferencesChanged()987     public void onPreferencesChanged() {
988         setRebootSelectorDefault(rebootBefore, "reboot_before");
989         setRebootSelectorDefault(rebootAfter, "reboot_after");
990         selectPreferredDroneSet();
991         testSelector.reset();
992     }
993 
parameterizedJobsEnabled()994     private boolean parameterizedJobsEnabled() {
995         return staticData.getData("parameterized_jobs").isBoolean().booleanValue();
996     }
997 
fetchImageTests()998     private void fetchImageTests() {
999         testSelector.setImageTests(new JSONArray());
1000 
1001         String imageUrl = display.getImageUrl().getText();
1002         if (imageUrl == null || imageUrl.isEmpty()) {
1003             testSelector.reset();
1004             return;
1005         }
1006 
1007         JSONObject params = new JSONObject();
1008         params.put("build", new JSONString(imageUrl));
1009 
1010         rpcProxy.rpcCall("get_tests_by_build", params, new JsonRpcCallback() {
1011             @Override
1012             public void onSuccess(JSONValue result) {
1013                 JSONArray tests = result.isArray();
1014                 testSelector.setImageTests(tests);
1015                 testSelector.reset();
1016             }
1017 
1018             @Override
1019             public void onError(JSONObject errorObject) {
1020                 super.onError(errorObject);
1021                 NotifyManager.getInstance().showError(
1022                     "Failed to update tests for given build.");
1023                 testSelector.reset();
1024             }
1025         });
1026     }
1027 }
1028