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