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 * .withQualityGate( 074 * newQualityGateBuilder() 075 * .setId("id") 076 * .setName("name") 077 * .setStatus(QualityGate.Status.OK) 078 * .add( 079 * newConditionBuilder() 080 * .setMetricKey("metric key") 081 * .setOperator(QualityGate.Operator.GREATER_THAN) 082 * .setErrorThreshold("12") 083 * .setOnLeakPeriod(true) 084 * .build(QualityGate.EvaluationStatus.OK, "value")) 085 * .build()) 086 * .execute(); 087 * 088 * assertThat(postProjectAnalysisTask.projectAnalysis).isNotNull(); 089 * } 090 * } 091 * </pre> 092 * 093 * @since 5.5 094 */ 095public class PostProjectAnalysisTaskTester { 096 private static final String DATE_CAN_NOT_BE_NULL = "date cannot be null"; 097 private static final String PROJECT_CAN_NOT_BE_NULL = "project cannot be null"; 098 private static final String CE_TASK_CAN_NOT_BE_NULL = "ceTask cannot be null"; 099 private static final String STATUS_CAN_NOT_BE_NULL = "status cannot be null"; 100 private static final String SCANNER_CONTEXT_CAN_NOT_BE_NULL = "scannerContext cannot be null"; 101 102 private final PostProjectAnalysisTask underTest; 103 @CheckForNull 104 private CeTask ceTask; 105 @CheckForNull 106 private Project project; 107 @CheckForNull 108 private Date date; 109 @CheckForNull 110 private QualityGate qualityGate; 111 @CheckForNull 112 private Branch branch; 113 private ScannerContext scannerContext; 114 115 private PostProjectAnalysisTaskTester(PostProjectAnalysisTask underTest) { 116 this.underTest = requireNonNull(underTest, "PostProjectAnalysisTask instance cannot be null"); 117 } 118 119 public static PostProjectAnalysisTaskTester of(PostProjectAnalysisTask underTest) { 120 return new PostProjectAnalysisTaskTester(underTest); 121 } 122 123 public static CeTaskBuilder newCeTaskBuilder() { 124 return new CeTaskBuilder(); 125 } 126 127 public static ProjectBuilder newProjectBuilder() { 128 return new ProjectBuilder(); 129 } 130 131 public static BranchBuilder newBranchBuilder() { 132 return new BranchBuilder(); 133 } 134 135 public static QualityGateBuilder newQualityGateBuilder() { 136 return new QualityGateBuilder(); 137 } 138 139 public static ConditionBuilder newConditionBuilder() { 140 return new ConditionBuilder(); 141 } 142 143 public static ScannerContextBuilder newScannerContextBuilder() { 144 return new ScannerContextBuilder(); 145 } 146 147 public PostProjectAnalysisTaskTester withCeTask(CeTask ceTask) { 148 this.ceTask = requireNonNull(ceTask, CE_TASK_CAN_NOT_BE_NULL); 149 return this; 150 } 151 152 public PostProjectAnalysisTaskTester withProject(Project project) { 153 this.project = requireNonNull(project, PROJECT_CAN_NOT_BE_NULL); 154 return this; 155 } 156 157 /** 158 * @since 6.1 159 */ 160 public PostProjectAnalysisTaskTester withScannerContext(ScannerContext scannerContext) { 161 this.scannerContext = requireNonNull(scannerContext, SCANNER_CONTEXT_CAN_NOT_BE_NULL); 162 return this; 163 } 164 165 public PostProjectAnalysisTaskTester at(Date date) { 166 this.date = requireNonNull(date, DATE_CAN_NOT_BE_NULL); 167 return this; 168 } 169 170 public PostProjectAnalysisTaskTester withQualityGate(@Nullable QualityGate qualityGate) { 171 this.qualityGate = qualityGate; 172 return this; 173 } 174 175 public PostProjectAnalysisTaskTester withBranch(@Nullable Branch b) { 176 this.branch = b; 177 return this; 178 } 179 180 public void execute() { 181 requireNonNull(ceTask, CE_TASK_CAN_NOT_BE_NULL); 182 requireNonNull(project, PROJECT_CAN_NOT_BE_NULL); 183 requireNonNull(date, DATE_CAN_NOT_BE_NULL); 184 185 this.underTest.finished( 186 new PostProjectAnalysisTask.ProjectAnalysis() { 187 @Override 188 public ScannerContext getScannerContext() { 189 return scannerContext; 190 } 191 192 @Override 193 public CeTask getCeTask() { 194 return ceTask; 195 } 196 197 @Override 198 public Project getProject() { 199 return project; 200 } 201 202 @Override 203 public Optional<Branch> getBranch() { 204 return Optional.ofNullable(branch); 205 } 206 207 @Override 208 public QualityGate getQualityGate() { 209 return qualityGate; 210 } 211 212 @Override 213 public Date getDate() { 214 return date; 215 } 216 217 @Override 218 public Optional<Date> getAnalysisDate() { 219 return Optional.of(date); 220 } 221 222 @Override 223 public String toString() { 224 return "ProjectAnalysis{" + 225 "ceTask=" + ceTask + 226 ", project=" + project + 227 ", date=" + date.getTime() + 228 ", analysisDate=" + date.getTime() + 229 ", qualityGate=" + qualityGate + 230 '}'; 231 } 232 }); 233 234 } 235 236 public static final class CeTaskBuilder { 237 private static final String ID_CAN_NOT_BE_NULL = "id cannot be null"; 238 239 @CheckForNull 240 private String id; 241 @CheckForNull 242 private CeTask.Status status; 243 244 private CeTaskBuilder() { 245 // prevents instantiation outside PostProjectAnalysisTaskTester 246 } 247 248 public CeTaskBuilder setId(String id) { 249 this.id = requireNonNull(id, ID_CAN_NOT_BE_NULL); 250 return this; 251 } 252 253 public CeTaskBuilder setStatus(CeTask.Status status) { 254 this.status = requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 255 return this; 256 } 257 258 public CeTask build() { 259 requireNonNull(id, ID_CAN_NOT_BE_NULL); 260 requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 261 return new CeTask() { 262 @Override 263 public String getId() { 264 return id; 265 } 266 267 @Override 268 public Status getStatus() { 269 return status; 270 } 271 272 @Override 273 public String toString() { 274 return "CeTask{" + 275 "id='" + id + '\'' + 276 ", status=" + status + 277 '}'; 278 } 279 }; 280 } 281 } 282 283 public static final class ProjectBuilder { 284 private static final String UUID_CAN_NOT_BE_NULL = "uuid cannot be null"; 285 private static final String KEY_CAN_NOT_BE_NULL = "key cannot be null"; 286 private static final String NAME_CAN_NOT_BE_NULL = "name cannot be null"; 287 private String uuid; 288 private String key; 289 private String name; 290 291 private ProjectBuilder() { 292 // prevents instantiation outside PostProjectAnalysisTaskTester 293 } 294 295 public ProjectBuilder setUuid(String uuid) { 296 this.uuid = requireNonNull(uuid, UUID_CAN_NOT_BE_NULL); 297 return this; 298 } 299 300 public ProjectBuilder setKey(String key) { 301 this.key = requireNonNull(key, KEY_CAN_NOT_BE_NULL); 302 return this; 303 } 304 305 public ProjectBuilder setName(String name) { 306 this.name = requireNonNull(name, NAME_CAN_NOT_BE_NULL); 307 return this; 308 } 309 310 public Project build() { 311 requireNonNull(uuid, UUID_CAN_NOT_BE_NULL); 312 requireNonNull(key, KEY_CAN_NOT_BE_NULL); 313 requireNonNull(name, NAME_CAN_NOT_BE_NULL); 314 return new Project() { 315 @Override 316 public String getUuid() { 317 return uuid; 318 } 319 320 @Override 321 public String getKey() { 322 return key; 323 } 324 325 @Override 326 public String getName() { 327 return name; 328 } 329 330 @Override 331 public String toString() { 332 return "Project{" + 333 "uuid='" + uuid + '\'' + 334 ", key='" + key + '\'' + 335 ", name='" + name + '\'' + 336 '}'; 337 } 338 339 }; 340 } 341 } 342 343 public static final class BranchBuilder { 344 private boolean isMain = true; 345 private String name = null; 346 private Branch.Type type = Branch.Type.LONG; 347 348 private BranchBuilder() { 349 // prevents instantiation outside PostProjectAnalysisTaskTester 350 } 351 352 public BranchBuilder setName(@Nullable String s) { 353 this.name = s; 354 return this; 355 } 356 357 public BranchBuilder setType(Branch.Type t) { 358 this.type = Objects.requireNonNull(t); 359 return this; 360 } 361 362 public BranchBuilder setIsMain(boolean b) { 363 this.isMain = b; 364 return this; 365 } 366 367 public Branch build() { 368 return new Branch() { 369 370 371 @Override 372 public boolean isMain() { 373 return isMain; 374 } 375 376 @Override 377 public Optional<String> getName() { 378 return Optional.ofNullable(name); 379 } 380 381 @Override 382 public Type getType() { 383 return type; 384 } 385 }; 386 } 387 } 388 389 public static final class QualityGateBuilder { 390 private static final String ID_CAN_NOT_BE_NULL = "id cannot be null"; 391 private static final String NAME_CAN_NOT_BE_NULL = "name cannot be null"; 392 393 private String id; 394 private String name; 395 private QualityGate.Status status; 396 private final List<QualityGate.Condition> conditions = new ArrayList<>(); 397 398 private QualityGateBuilder() { 399 // prevents instantiation outside PostProjectAnalysisTaskTester 400 } 401 402 public QualityGateBuilder setId(String id) { 403 this.id = requireNonNull(id, ID_CAN_NOT_BE_NULL); 404 return this; 405 } 406 407 public QualityGateBuilder setName(String name) { 408 this.name = requireNonNull(name, NAME_CAN_NOT_BE_NULL); 409 return this; 410 } 411 412 public QualityGateBuilder setStatus(QualityGate.Status status) { 413 this.status = requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 414 return this; 415 } 416 417 public QualityGateBuilder add(QualityGate.Condition condition) { 418 conditions.add(requireNonNull(condition, "condition cannot be null")); 419 return this; 420 } 421 422 public QualityGateBuilder clearConditions() { 423 this.conditions.clear(); 424 return this; 425 } 426 427 public QualityGate build() { 428 requireNonNull(id, ID_CAN_NOT_BE_NULL); 429 requireNonNull(name, NAME_CAN_NOT_BE_NULL); 430 requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 431 432 return new QualityGate() { 433 @Override 434 public String getId() { 435 return id; 436 } 437 438 @Override 439 public String getName() { 440 return name; 441 } 442 443 @Override 444 public Status getStatus() { 445 return status; 446 } 447 448 @Override 449 public Collection<Condition> getConditions() { 450 return conditions; 451 } 452 453 @Override 454 public String toString() { 455 return "QualityGate{" + 456 "id='" + id + '\'' + 457 ", name='" + name + '\'' + 458 ", status=" + status + 459 ", conditions=" + conditions + 460 '}'; 461 } 462 }; 463 } 464 } 465 466 public static final class ConditionBuilder { 467 private static final String METRIC_KEY_CAN_NOT_BE_NULL = "metricKey cannot be null"; 468 private static final String OPERATOR_CAN_NOT_BE_NULL = "operator cannot be null"; 469 470 private String metricKey; 471 private QualityGate.Operator operator; 472 private String errorThreshold; 473 private String warningThreshold; 474 private boolean onLeakPeriod; 475 476 private ConditionBuilder() { 477 // prevents instantiation outside PostProjectAnalysisTaskTester 478 } 479 480 public ConditionBuilder setMetricKey(String metricKey) { 481 this.metricKey = requireNonNull(metricKey, METRIC_KEY_CAN_NOT_BE_NULL); 482 return this; 483 } 484 485 public ConditionBuilder setOperator(QualityGate.Operator operator) { 486 this.operator = requireNonNull(operator, OPERATOR_CAN_NOT_BE_NULL); 487 return this; 488 } 489 490 public ConditionBuilder setErrorThreshold(@Nullable String errorThreshold) { 491 this.errorThreshold = errorThreshold; 492 return this; 493 } 494 495 public ConditionBuilder setWarningThreshold(@Nullable String warningThreshold) { 496 this.warningThreshold = warningThreshold; 497 return this; 498 } 499 500 public ConditionBuilder setOnLeakPeriod(boolean onLeakPeriod) { 501 this.onLeakPeriod = onLeakPeriod; 502 return this; 503 } 504 505 public QualityGate.Condition buildNoValue() { 506 checkCommonProperties(); 507 return new QualityGate.Condition() { 508 @Override 509 public QualityGate.EvaluationStatus getStatus() { 510 return QualityGate.EvaluationStatus.NO_VALUE; 511 } 512 513 @Override 514 public String getMetricKey() { 515 return metricKey; 516 } 517 518 @Override 519 public QualityGate.Operator getOperator() { 520 return operator; 521 } 522 523 @Override 524 public String getErrorThreshold() { 525 return errorThreshold; 526 } 527 528 @Override 529 public String getWarningThreshold() { 530 return warningThreshold; 531 } 532 533 @Override 534 public boolean isOnLeakPeriod() { 535 return onLeakPeriod; 536 } 537 538 @Override 539 public String getValue() { 540 throw new IllegalStateException("There is no value when status is NO_VALUE"); 541 } 542 543 @Override 544 public String toString() { 545 return "Condition{" + 546 "status=" + QualityGate.EvaluationStatus.NO_VALUE + 547 ", metricKey='" + metricKey + '\'' + 548 ", operator=" + operator + 549 ", errorThreshold='" + errorThreshold + '\'' + 550 ", warningThreshold='" + warningThreshold + '\'' + 551 ", onLeakPeriod=" + onLeakPeriod + 552 '}'; 553 } 554 }; 555 } 556 557 public QualityGate.Condition build(final QualityGate.EvaluationStatus status, final String value) { 558 checkCommonProperties(); 559 requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 560 checkArgument(status != QualityGate.EvaluationStatus.NO_VALUE, "status cannot be NO_VALUE, use method buildNoValue() instead"); 561 requireNonNull(value, "value cannot be null, use method buildNoValue() instead"); 562 return new QualityGate.Condition() { 563 @Override 564 public QualityGate.EvaluationStatus getStatus() { 565 return status; 566 } 567 568 @Override 569 public String getMetricKey() { 570 return metricKey; 571 } 572 573 @Override 574 public QualityGate.Operator getOperator() { 575 return operator; 576 } 577 578 @Override 579 public String getErrorThreshold() { 580 return errorThreshold; 581 } 582 583 @Override 584 public String getWarningThreshold() { 585 return warningThreshold; 586 } 587 588 @Override 589 public boolean isOnLeakPeriod() { 590 return onLeakPeriod; 591 } 592 593 @Override 594 public String getValue() { 595 return value; 596 } 597 598 @Override 599 public String toString() { 600 return "Condition{" + 601 "status=" + status + 602 ", metricKey='" + metricKey + '\'' + 603 ", operator=" + operator + 604 ", errorThreshold='" + errorThreshold + '\'' + 605 ", warningThreshold='" + warningThreshold + '\'' + 606 ", onLeakPeriod=" + onLeakPeriod + 607 ", value='" + value + '\'' + 608 '}'; 609 } 610 }; 611 } 612 613 private void checkCommonProperties() { 614 requireNonNull(metricKey, METRIC_KEY_CAN_NOT_BE_NULL); 615 requireNonNull(operator, OPERATOR_CAN_NOT_BE_NULL); 616 checkState(errorThreshold != null || warningThreshold != null, "At least one of errorThreshold and warningThreshold must be non null"); 617 } 618 } 619 620 public static final class ScannerContextBuilder { 621 private final Map<String, String> properties = new HashMap<>(); 622 623 private ScannerContextBuilder() { 624 // prevents instantiation outside PostProjectAnalysisTaskTester 625 } 626 627 public ScannerContextBuilder addProperties(Map<String, String> map) { 628 properties.putAll(map); 629 return this; 630 } 631 632 public ScannerContext build() { 633 return () -> properties; 634 } 635 } 636}