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