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