001/* 002 * SonarQube 003 * Copyright (C) 2009-2017 SonarSource SA 004 * mailto:info AT sonarsource DOT com 005 * 006 * This program is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.ce.posttask; 021 022import java.util.ArrayList; 023import java.util.Collection; 024import java.util.Date; 025import java.util.HashMap; 026import java.util.List; 027import java.util.Map; 028import java.util.Objects; 029import java.util.Optional; 030import javax.annotation.CheckForNull; 031import javax.annotation.Nullable; 032 033import static com.google.common.base.Preconditions.checkArgument; 034import static com.google.common.base.Preconditions.checkState; 035import static java.util.Objects.requireNonNull; 036 037/** 038 * This class can be used to test {@link PostProjectAnalysisTask} implementations, see example below: 039 * <pre> 040 * import static org.assertj.core.api.Assertions.assertThat; 041 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newCeTaskBuilder; 042 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newConditionBuilder; 043 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newProjectBuilder; 044 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newQualityGateBuilder; 045 * 046 * public class CaptorPostProjectAnalysisTaskTest { 047 * private class CaptorPostProjectAnalysisTask implements PostProjectAnalysisTask { 048 * private ProjectAnalysis projectAnalysis; 049 * 050 * {@literal @}Override 051 * public void finished(ProjectAnalysis analysis) { 052 * this.projectAnalysis = analysis; 053 * } 054 * } 055 * 056 * {@literal @}Test 057 * public void execute_is_passed_a_non_null_ProjectAnalysis_object() { 058 * CaptorPostProjectAnalysisTask postProjectAnalysisTask = new CaptorPostProjectAnalysisTask(); 059 * 060 * PostProjectAnalysisTaskTester.of(postProjectAnalysisTask) 061 * .withCeTask( 062 * newCeTaskBuilder() 063 * .setId("id") 064 * .setStatus(CeTask.Status.SUCCESS) 065 * .build()) 066 * .withProject( 067 * PostProjectAnalysisTaskTester.newProjectBuilder() 068 * .setUuid("uuid") 069 * .setKey("key") 070 * .setName("name") 071 * .build()) 072 * .at(new Date()) 073 * .withAnalysisUuid("uuid") 074 * .withQualityGate( 075 * newQualityGateBuilder() 076 * .setId("id") 077 * .setName("name") 078 * .setStatus(QualityGate.Status.OK) 079 * .add( 080 * newConditionBuilder() 081 * .setMetricKey("metric key") 082 * .setOperator(QualityGate.Operator.GREATER_THAN) 083 * .setErrorThreshold("12") 084 * .setOnLeakPeriod(true) 085 * .build(QualityGate.EvaluationStatus.OK, "value")) 086 * .build()) 087 * .execute(); 088 * 089 * assertThat(postProjectAnalysisTask.projectAnalysis).isNotNull(); 090 * } 091 * } 092 * </pre> 093 * 094 * @since 5.5 095 */ 096public class PostProjectAnalysisTaskTester { 097 private static final String DATE_CAN_NOT_BE_NULL = "date cannot be null"; 098 private static final String PROJECT_CAN_NOT_BE_NULL = "project cannot be null"; 099 private static final String CE_TASK_CAN_NOT_BE_NULL = "ceTask cannot be null"; 100 private static final String STATUS_CAN_NOT_BE_NULL = "status cannot be null"; 101 private static final String SCANNER_CONTEXT_CAN_NOT_BE_NULL = "scannerContext cannot be null"; 102 103 private final PostProjectAnalysisTask underTest; 104 @CheckForNull 105 private CeTask ceTask; 106 @CheckForNull 107 private Project project; 108 @CheckForNull 109 private Date date; 110 @CheckForNull 111 private QualityGate qualityGate; 112 @CheckForNull 113 private Branch branch; 114 private ScannerContext scannerContext; 115 private String analysisUuid; 116 117 private PostProjectAnalysisTaskTester(PostProjectAnalysisTask underTest) { 118 this.underTest = requireNonNull(underTest, "PostProjectAnalysisTask instance cannot be null"); 119 } 120 121 public static PostProjectAnalysisTaskTester of(PostProjectAnalysisTask underTest) { 122 return new PostProjectAnalysisTaskTester(underTest); 123 } 124 125 public static CeTaskBuilder newCeTaskBuilder() { 126 return new CeTaskBuilder(); 127 } 128 129 public static ProjectBuilder newProjectBuilder() { 130 return new ProjectBuilder(); 131 } 132 133 public static BranchBuilder newBranchBuilder() { 134 return new BranchBuilder(); 135 } 136 137 public static QualityGateBuilder newQualityGateBuilder() { 138 return new QualityGateBuilder(); 139 } 140 141 public static ConditionBuilder newConditionBuilder() { 142 return new ConditionBuilder(); 143 } 144 145 public static ScannerContextBuilder newScannerContextBuilder() { 146 return new ScannerContextBuilder(); 147 } 148 149 public PostProjectAnalysisTaskTester withCeTask(CeTask ceTask) { 150 this.ceTask = requireNonNull(ceTask, CE_TASK_CAN_NOT_BE_NULL); 151 return this; 152 } 153 154 public PostProjectAnalysisTaskTester withProject(Project project) { 155 this.project = requireNonNull(project, PROJECT_CAN_NOT_BE_NULL); 156 return this; 157 } 158 159 /** 160 * @since 6.1 161 */ 162 public PostProjectAnalysisTaskTester withScannerContext(ScannerContext scannerContext) { 163 this.scannerContext = requireNonNull(scannerContext, SCANNER_CONTEXT_CAN_NOT_BE_NULL); 164 return this; 165 } 166 167 public PostProjectAnalysisTaskTester at(Date date) { 168 this.date = requireNonNull(date, DATE_CAN_NOT_BE_NULL); 169 return this; 170 } 171 172 public PostProjectAnalysisTaskTester withQualityGate(@Nullable QualityGate qualityGate) { 173 this.qualityGate = qualityGate; 174 return this; 175 } 176 177 public PostProjectAnalysisTaskTester withBranch(@Nullable Branch b) { 178 this.branch = b; 179 return this; 180 } 181 182 /** 183 * @since 6.6 184 */ 185 public PostProjectAnalysisTaskTester withAnalysisUuid(@Nullable String analysisUuid) { 186 this.analysisUuid = analysisUuid; 187 return this; 188 } 189 190 public PostProjectAnalysisTask.ProjectAnalysis execute() { 191 requireNonNull(ceTask, CE_TASK_CAN_NOT_BE_NULL); 192 requireNonNull(project, PROJECT_CAN_NOT_BE_NULL); 193 requireNonNull(date, DATE_CAN_NOT_BE_NULL); 194 195 Analysis analysis = null; 196 if (analysisUuid != null) { 197 analysis = new AnalysisBuilder() 198 .setDate(date) 199 .setAnalysisUuid(analysisUuid) 200 .build(); 201 } 202 203 PostProjectAnalysisTask.ProjectAnalysis projectAnalysis = new ProjectAnalysisBuilder() 204 .setCeTask(ceTask) 205 .setProject(project) 206 .setBranch(branch) 207 .setQualityGate(qualityGate) 208 .setAnalysis(analysis) 209 .setScannerContext(scannerContext) 210 .setDate(date) 211 .build(); 212 213 this.underTest. 214 finished(projectAnalysis); 215 216 return projectAnalysis; 217 } 218 219 public static final class CeTaskBuilder { 220 private static final String ID_CAN_NOT_BE_NULL = "id cannot be null"; 221 222 @CheckForNull 223 private String id; 224 @CheckForNull 225 private CeTask.Status status; 226 227 private CeTaskBuilder() { 228 // prevents instantiation outside PostProjectAnalysisTaskTester 229 } 230 231 public CeTaskBuilder setId(String id) { 232 this.id = requireNonNull(id, ID_CAN_NOT_BE_NULL); 233 return this; 234 } 235 236 public CeTaskBuilder setStatus(CeTask.Status status) { 237 this.status = requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 238 return this; 239 } 240 241 public CeTask build() { 242 requireNonNull(id, ID_CAN_NOT_BE_NULL); 243 requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 244 return new CeTask() { 245 @Override 246 public String getId() { 247 return id; 248 } 249 250 @Override 251 public Status getStatus() { 252 return status; 253 } 254 255 @Override 256 public String toString() { 257 return "CeTask{" + 258 "id='" + id + '\'' + 259 ", status=" + status + 260 '}'; 261 } 262 }; 263 } 264 } 265 266 public static final class ProjectBuilder { 267 private static final String UUID_CAN_NOT_BE_NULL = "uuid cannot be null"; 268 private static final String KEY_CAN_NOT_BE_NULL = "key cannot be null"; 269 private static final String NAME_CAN_NOT_BE_NULL = "name cannot be null"; 270 private String uuid; 271 private String key; 272 private String name; 273 274 private ProjectBuilder() { 275 // prevents instantiation outside PostProjectAnalysisTaskTester 276 } 277 278 public ProjectBuilder setUuid(String uuid) { 279 this.uuid = requireNonNull(uuid, UUID_CAN_NOT_BE_NULL); 280 return this; 281 } 282 283 public ProjectBuilder setKey(String key) { 284 this.key = requireNonNull(key, KEY_CAN_NOT_BE_NULL); 285 return this; 286 } 287 288 public ProjectBuilder setName(String name) { 289 this.name = requireNonNull(name, NAME_CAN_NOT_BE_NULL); 290 return this; 291 } 292 293 public Project build() { 294 requireNonNull(uuid, UUID_CAN_NOT_BE_NULL); 295 requireNonNull(key, KEY_CAN_NOT_BE_NULL); 296 requireNonNull(name, NAME_CAN_NOT_BE_NULL); 297 return new Project() { 298 @Override 299 public String getUuid() { 300 return uuid; 301 } 302 303 @Override 304 public String getKey() { 305 return key; 306 } 307 308 @Override 309 public String getName() { 310 return name; 311 } 312 313 @Override 314 public String toString() { 315 return "Project{" + 316 "uuid='" + uuid + '\'' + 317 ", key='" + key + '\'' + 318 ", name='" + name + '\'' + 319 '}'; 320 } 321 322 }; 323 } 324 } 325 326 public static final class BranchBuilder { 327 private boolean isMain = true; 328 private String name = null; 329 private Branch.Type type = Branch.Type.LONG; 330 331 private BranchBuilder() { 332 // prevents instantiation outside PostProjectAnalysisTaskTester 333 } 334 335 public BranchBuilder setName(@Nullable String s) { 336 this.name = s; 337 return this; 338 } 339 340 public BranchBuilder setType(Branch.Type t) { 341 this.type = Objects.requireNonNull(t); 342 return this; 343 } 344 345 public BranchBuilder setIsMain(boolean b) { 346 this.isMain = b; 347 return this; 348 } 349 350 public Branch build() { 351 return new Branch() { 352 353 354 @Override 355 public boolean isMain() { 356 return isMain; 357 } 358 359 @Override 360 public Optional<String> getName() { 361 return Optional.ofNullable(name); 362 } 363 364 @Override 365 public Type getType() { 366 return type; 367 } 368 }; 369 } 370 } 371 372 public static final class QualityGateBuilder { 373 private static final String ID_CAN_NOT_BE_NULL = "id cannot be null"; 374 private static final String NAME_CAN_NOT_BE_NULL = "name cannot be null"; 375 376 private String id; 377 private String name; 378 private QualityGate.Status status; 379 private final List<QualityGate.Condition> conditions = new ArrayList<>(); 380 381 private QualityGateBuilder() { 382 // prevents instantiation outside PostProjectAnalysisTaskTester 383 } 384 385 public QualityGateBuilder setId(String id) { 386 this.id = requireNonNull(id, ID_CAN_NOT_BE_NULL); 387 return this; 388 } 389 390 public QualityGateBuilder setName(String name) { 391 this.name = requireNonNull(name, NAME_CAN_NOT_BE_NULL); 392 return this; 393 } 394 395 public QualityGateBuilder setStatus(QualityGate.Status status) { 396 this.status = requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 397 return this; 398 } 399 400 public QualityGateBuilder add(QualityGate.Condition condition) { 401 conditions.add(requireNonNull(condition, "condition cannot be null")); 402 return this; 403 } 404 405 public QualityGateBuilder clearConditions() { 406 this.conditions.clear(); 407 return this; 408 } 409 410 public QualityGate build() { 411 requireNonNull(id, ID_CAN_NOT_BE_NULL); 412 requireNonNull(name, NAME_CAN_NOT_BE_NULL); 413 requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 414 415 return new QualityGate() { 416 @Override 417 public String getId() { 418 return id; 419 } 420 421 @Override 422 public String getName() { 423 return name; 424 } 425 426 @Override 427 public Status getStatus() { 428 return status; 429 } 430 431 @Override 432 public Collection<Condition> getConditions() { 433 return conditions; 434 } 435 436 @Override 437 public String toString() { 438 return "QualityGate{" + 439 "id='" + id + '\'' + 440 ", name='" + name + '\'' + 441 ", status=" + status + 442 ", conditions=" + conditions + 443 '}'; 444 } 445 }; 446 } 447 } 448 449 public static final class ConditionBuilder { 450 private static final String METRIC_KEY_CAN_NOT_BE_NULL = "metricKey cannot be null"; 451 private static final String OPERATOR_CAN_NOT_BE_NULL = "operator cannot be null"; 452 453 private String metricKey; 454 private QualityGate.Operator operator; 455 private String errorThreshold; 456 private String warningThreshold; 457 private boolean onLeakPeriod; 458 459 private ConditionBuilder() { 460 // prevents instantiation outside PostProjectAnalysisTaskTester 461 } 462 463 public ConditionBuilder setMetricKey(String metricKey) { 464 this.metricKey = requireNonNull(metricKey, METRIC_KEY_CAN_NOT_BE_NULL); 465 return this; 466 } 467 468 public ConditionBuilder setOperator(QualityGate.Operator operator) { 469 this.operator = requireNonNull(operator, OPERATOR_CAN_NOT_BE_NULL); 470 return this; 471 } 472 473 public ConditionBuilder setErrorThreshold(@Nullable String errorThreshold) { 474 this.errorThreshold = errorThreshold; 475 return this; 476 } 477 478 public ConditionBuilder setWarningThreshold(@Nullable String warningThreshold) { 479 this.warningThreshold = warningThreshold; 480 return this; 481 } 482 483 public ConditionBuilder setOnLeakPeriod(boolean onLeakPeriod) { 484 this.onLeakPeriod = onLeakPeriod; 485 return this; 486 } 487 488 public QualityGate.Condition buildNoValue() { 489 checkCommonProperties(); 490 return new QualityGate.Condition() { 491 @Override 492 public QualityGate.EvaluationStatus getStatus() { 493 return QualityGate.EvaluationStatus.NO_VALUE; 494 } 495 496 @Override 497 public String getMetricKey() { 498 return metricKey; 499 } 500 501 @Override 502 public QualityGate.Operator getOperator() { 503 return operator; 504 } 505 506 @Override 507 public String getErrorThreshold() { 508 return errorThreshold; 509 } 510 511 @Override 512 public String getWarningThreshold() { 513 return warningThreshold; 514 } 515 516 @Override 517 public boolean isOnLeakPeriod() { 518 return onLeakPeriod; 519 } 520 521 @Override 522 public String getValue() { 523 throw new IllegalStateException("There is no value when status is NO_VALUE"); 524 } 525 526 @Override 527 public String toString() { 528 return "Condition{" + 529 "status=" + QualityGate.EvaluationStatus.NO_VALUE + 530 ", metricKey='" + metricKey + '\'' + 531 ", operator=" + operator + 532 ", errorThreshold='" + errorThreshold + '\'' + 533 ", warningThreshold='" + warningThreshold + '\'' + 534 ", onLeakPeriod=" + onLeakPeriod + 535 '}'; 536 } 537 }; 538 } 539 540 public QualityGate.Condition build(final QualityGate.EvaluationStatus status, final String value) { 541 checkCommonProperties(); 542 requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 543 checkArgument(status != QualityGate.EvaluationStatus.NO_VALUE, "status cannot be NO_VALUE, use method buildNoValue() instead"); 544 requireNonNull(value, "value cannot be null, use method buildNoValue() instead"); 545 return new QualityGate.Condition() { 546 @Override 547 public QualityGate.EvaluationStatus getStatus() { 548 return status; 549 } 550 551 @Override 552 public String getMetricKey() { 553 return metricKey; 554 } 555 556 @Override 557 public QualityGate.Operator getOperator() { 558 return operator; 559 } 560 561 @Override 562 public String getErrorThreshold() { 563 return errorThreshold; 564 } 565 566 @Override 567 public String getWarningThreshold() { 568 return warningThreshold; 569 } 570 571 @Override 572 public boolean isOnLeakPeriod() { 573 return onLeakPeriod; 574 } 575 576 @Override 577 public String getValue() { 578 return value; 579 } 580 581 @Override 582 public String toString() { 583 return "Condition{" + 584 "status=" + status + 585 ", metricKey='" + metricKey + '\'' + 586 ", operator=" + operator + 587 ", errorThreshold='" + errorThreshold + '\'' + 588 ", warningThreshold='" + warningThreshold + '\'' + 589 ", onLeakPeriod=" + onLeakPeriod + 590 ", value='" + value + '\'' + 591 '}'; 592 } 593 }; 594 } 595 596 private void checkCommonProperties() { 597 requireNonNull(metricKey, METRIC_KEY_CAN_NOT_BE_NULL); 598 requireNonNull(operator, OPERATOR_CAN_NOT_BE_NULL); 599 checkState(errorThreshold != null || warningThreshold != null, "At least one of errorThreshold and warningThreshold must be non null"); 600 } 601 } 602 603 public static final class ScannerContextBuilder { 604 private final Map<String, String> properties = new HashMap<>(); 605 606 private ScannerContextBuilder() { 607 // prevents instantiation outside PostProjectAnalysisTaskTester 608 } 609 610 public ScannerContextBuilder addProperties(Map<String, String> map) { 611 properties.putAll(map); 612 return this; 613 } 614 615 public ScannerContext build() { 616 return () -> properties; 617 } 618 } 619 620 public static final class ProjectAnalysisBuilder { 621 private CeTask ceTask; 622 private Project project; 623 private Branch branch; 624 private QualityGate qualityGate; 625 private Analysis analysis; 626 private ScannerContext scannerContext; 627 private Date date; 628 629 private ProjectAnalysisBuilder() { 630 // prevents instantiation outside PostProjectAnalysisTaskTester 631 } 632 633 public ProjectAnalysisBuilder setCeTask(CeTask ceTask) { 634 this.ceTask = ceTask; 635 return this; 636 } 637 638 public ProjectAnalysisBuilder setProject(Project project) { 639 this.project = project; 640 return this; 641 } 642 643 public ProjectAnalysisBuilder setBranch(@Nullable Branch branch) { 644 this.branch = branch; 645 return this; 646 } 647 648 public ProjectAnalysisBuilder setQualityGate(QualityGate qualityGate) { 649 this.qualityGate = qualityGate; 650 return this; 651 } 652 653 public ProjectAnalysisBuilder setAnalysis(@Nullable Analysis analysis) { 654 this.analysis = analysis; 655 return this; 656 } 657 658 public ProjectAnalysisBuilder setScannerContext(ScannerContext scannerContext) { 659 this.scannerContext = scannerContext; 660 return this; 661 } 662 663 public ProjectAnalysisBuilder setDate(Date date) { 664 this.date = date; 665 return this; 666 } 667 668 public PostProjectAnalysisTask.ProjectAnalysis build() { 669 return new PostProjectAnalysisTask.ProjectAnalysis() { 670 @Override 671 public CeTask getCeTask() { 672 return ceTask; 673 } 674 675 @Override 676 public Project getProject() { 677 return project; 678 } 679 680 @Override 681 public Optional<Branch> getBranch() { 682 return Optional.ofNullable(branch); 683 } 684 685 @CheckForNull 686 @Override 687 public QualityGate getQualityGate() { 688 return qualityGate; 689 } 690 691 @Override 692 public Date getDate() { 693 return date; 694 } 695 696 @Override 697 public Optional<Date> getAnalysisDate() { 698 return getAnalysis().map(Analysis::getDate); 699 } 700 701 @Override 702 public Optional<Analysis> getAnalysis() { 703 return Optional.ofNullable(analysis); 704 } 705 706 @Override 707 public ScannerContext getScannerContext() { 708 return scannerContext; 709 } 710 711 @Override 712 public String toString() { 713 return "ProjectAnalysis{" + 714 "ceTask=" + ceTask + 715 ", project=" + project + 716 ", date=" + date.getTime() + 717 ", analysisDate=" + date.getTime() + 718 ", qualityGate=" + qualityGate + 719 '}'; 720 } 721 }; 722 } 723 } 724 725 public static final class AnalysisBuilder { 726 private String analysisUuid; 727 private Date date; 728 729 private AnalysisBuilder() { 730 // prevents instantiation outside PostProjectAnalysisTaskTester 731 } 732 733 public AnalysisBuilder setAnalysisUuid(String analysisUuid) { 734 this.analysisUuid = analysisUuid; 735 return this; 736 } 737 738 public AnalysisBuilder setDate(Date date) { 739 this.date = date; 740 return this; 741 } 742 743 public Analysis build() { 744 return new Analysis() { 745 746 @Override 747 public String getAnalysisUuid() { 748 return analysisUuid; 749 } 750 751 @Override 752 public Date getDate() { 753 return date; 754 } 755 }; 756 } 757 } 758}