Home | History | Annotate | Download | only in create
      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 {
     64         public CheckBoxPanel.Display getCheckBoxPanelDisplay();
     65         public ControlTypeSelect.Display getControlTypeSelectDisplay();
     66         public TestSelector.Display getTestSelectorDisplay();
     67         public IButton getEditControlButton();
     68         public HasText getJobName();
     69         public ExtendedListBox getPriorityList();
     70         public HasText getTimeout();
     71         public HasText getMaxRuntime();
     72         public HasText getTestRetry();
     73         public HasText getEmailList();
     74         public ICheckBox getSkipVerify();
     75         public ICheckBox getSkipReset();
     76         public RadioChooser.Display getRebootBefore();
     77         public RadioChooser.Display getRebootAfter();
     78         public HasValue<Boolean> getParseFailedRepair();
     79         public ICheckBox getHostless();
     80         public ICheckBox getRequireSSP();
     81         public HasText getPool();
     82         public ITextBox getArgs();
     83         public HostSelector.Display getHostSelectorDisplay();
     84         public SimplifiedList getDroneSet();
     85         public ITextBox getSynchCountInput();
     86         public ITextArea getControlFile();
     87         public void setControlFilePanelOpen(boolean isOpen);
     88         public ICheckBox getRunNonProfiledIteration();
     89         public ITextBox getImageUrl();
     90         public HasText getViewLink();
     91         public HasCloseHandlers<DisclosurePanel> getControlFilePanelClose();
     92         public HasOpenHandlers<DisclosurePanel> getControlFilePanelOpen();
     93         public IButton getSubmitJobButton();
     94         public HasClickHandlers getCreateTemplateJobButton();
     95         public HasClickHandlers getResetButton();
     96         public ICheckBox getFetchTestsFromBuildCheckBox();
     97         public ITextBox getFirmwareRWBuild();
     98         public ITextBox getFirmwareROBuild();
     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 {
    111         public void onJobCreated(int jobId);
    112     }
    113 
    114     private interface IPredicate<T> {
    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 
    155     public void bindDisplay(Display display) {
    156         this.display = display;
    157     }
    158 
    159     public CreateJobViewPresenter(JobCreateListener listener) {
    160         this.listener = listener;
    161     }
    162 
    163     public void setCloning(boolean cloning) {
    164       this.cloning = cloning;
    165     }
    166 
    167     public boolean isCloning() {
    168       return cloning;
    169     }
    170 
    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 
    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 
    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 
    304     private void resetPriorityToDefault() {
    305         JSONValue defaultValue = staticData.getData("default_priority");
    306         String defaultPriority = defaultValue.isString().stringValue();
    307         display.getPriorityList().selectByName(defaultPriority);
    308     }
    309 
    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 
    337     private void updateNonProfiledRunControl() {
    338         boolean anyProfilersChecked = !profilersPanel.getChecked().isEmpty();
    339         display.getRunNonProfiledIteration().setVisible(anyProfilersChecked);
    340     }
    341 
    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      */
    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 
    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 
    422     protected void generateControlFile(boolean readyForSubmit) {
    423         generateControlFile(readyForSubmit, null, null);
    424     }
    425 
    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 
    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 
    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 
    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 
    527     protected void setInputsEnabled() {
    528         testSelector.setEnabled(true);
    529         profilersPanel.setEnabled(true);
    530         handleSkipVerify();
    531         handleSkipReset();
    532         display.getImageUrl().setEnabled(true);
    533     }
    534 
    535     protected void disableInputs() {
    536         testSelector.setEnabled(false);
    537         profilersPanel.setEnabled(false);
    538         display.getImageUrl().setEnabled(false);
    539     }
    540 
    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 
    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 
    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 
    905     private JSONArray getSelectedDependencies() {
    906         return dependencies;
    907     }
    908 
    909     private void setSelectedDependencies(JSONArray dependencies) {
    910         this.dependencies = dependencies;
    911     }
    912 
    913     private int parseNonnegativeIntegerInput(String input, String fieldName) {
    914         return parsePredicatedIntegerInput(input, fieldName,
    915                                            nonnegativeIntegerPredicate,
    916                                            "non-negative");
    917     }
    918 
    919     private int parsePositiveIntegerInput(String input, String fieldName) {
    920         return parsePredicatedIntegerInput(input, fieldName,
    921                                            positiveIntegerPredicate,
    922                                            "positive");
    923     }
    924 
    925     private int parseAnyIntegerInput(String input, String fieldName) {
    926         return parsePredicatedIntegerInput(input, fieldName,
    927                                            anyIntegerPredicate,
    928                                            "integer");
    929     }
    930 
    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 
    950     public void refresh() {
    951         hostSelector.refresh();
    952     }
    953 
    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 
    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 
    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 
    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 
    994     public void onPreferencesChanged() {
    995         setRebootSelectorDefault(rebootBefore, "reboot_before");
    996         setRebootSelectorDefault(rebootAfter, "reboot_after");
    997         selectPreferredDroneSet();
    998         testSelector.reset();
    999     }
   1000 
   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