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