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.Optional; 029import javax.annotation.CheckForNull; 030import javax.annotation.Nullable; 031 032import static com.google.common.base.Preconditions.checkArgument; 033import static com.google.common.base.Preconditions.checkState; 034import static java.util.Objects.requireNonNull; 035 036/** 037 * This class can be used to test {@link PostProjectAnalysisTask} implementations, see example below: 038 * <pre> 039 * import static org.assertj.core.api.Assertions.assertThat; 040 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newCeTaskBuilder; 041 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newConditionBuilder; 042 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newProjectBuilder; 043 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newQualityGateBuilder; 044 * 045 * public class CaptorPostProjectAnalysisTaskTest { 046 * private class CaptorPostProjectAnalysisTask implements PostProjectAnalysisTask { 047 * private ProjectAnalysis projectAnalysis; 048 * 049 * {@literal @}Override 050 * public void finished(ProjectAnalysis analysis) { 051 * this.projectAnalysis = analysis; 052 * } 053 * } 054 * 055 * {@literal @}Test 056 * public void execute_is_passed_a_non_null_ProjectAnalysis_object() { 057 * CaptorPostProjectAnalysisTask postProjectAnalysisTask = new CaptorPostProjectAnalysisTask(); 058 * 059 * PostProjectAnalysisTaskTester.of(postProjectAnalysisTask) 060 * .withCeTask( 061 * newCeTaskBuilder() 062 * .setId("id") 063 * .setStatus(CeTask.Status.SUCCESS) 064 * .build()) 065 * .withProject( 066 * PostProjectAnalysisTaskTester.newProjectBuilder() 067 * .setUuid("uuid") 068 * .setKey("key") 069 * .setName("name") 070 * .build()) 071 * .at(new Date()) 072 * .withQualityGate( 073 * newQualityGateBuilder() 074 * .setId("id") 075 * .setName("name") 076 * .setStatus(QualityGate.Status.OK) 077 * .add( 078 * newConditionBuilder() 079 * .setMetricKey("metric key") 080 * .setOperator(QualityGate.Operator.GREATER_THAN) 081 * .setErrorThreshold("12") 082 * .setOnLeakPeriod(true) 083 * .build(QualityGate.EvaluationStatus.OK, "value")) 084 * .build()) 085 * .execute(); 086 * 087 * assertThat(postProjectAnalysisTask.projectAnalysis).isNotNull(); 088 * } 089 * } 090 * </pre> 091 * 092 * @since 5.5 093 */ 094public class PostProjectAnalysisTaskTester { 095 private static final String DATE_CAN_NOT_BE_NULL = "date cannot be null"; 096 private static final String PROJECT_CAN_NOT_BE_NULL = "project cannot be null"; 097 private static final String CE_TASK_CAN_NOT_BE_NULL = "ceTask cannot be null"; 098 private static final String STATUS_CAN_NOT_BE_NULL = "status cannot be null"; 099 private static final String SCANNER_CONTEXT_CAN_NOT_BE_NULL = "scannerContext cannot be null"; 100 101 private final PostProjectAnalysisTask underTest; 102 @CheckForNull 103 private CeTask ceTask; 104 @CheckForNull 105 private Project project; 106 @CheckForNull 107 private Date date; 108 @CheckForNull 109 private QualityGate qualityGate; 110 private ScannerContext scannerContext; 111 112 private PostProjectAnalysisTaskTester(PostProjectAnalysisTask underTest) { 113 this.underTest = requireNonNull(underTest, "PostProjectAnalysisTask instance cannot be null"); 114 } 115 116 public static PostProjectAnalysisTaskTester of(PostProjectAnalysisTask underTest) { 117 return new PostProjectAnalysisTaskTester(underTest); 118 } 119 120 public static CeTaskBuilder newCeTaskBuilder() { 121 return new CeTaskBuilder(); 122 } 123 124 public static ProjectBuilder newProjectBuilder() { 125 return new ProjectBuilder(); 126 } 127 128 public static QualityGateBuilder newQualityGateBuilder() { 129 return new QualityGateBuilder(); 130 } 131 132 public static ConditionBuilder newConditionBuilder() { 133 return new ConditionBuilder(); 134 } 135 136 public static ScannerContextBuilder newScannerContextBuilder() { 137 return new ScannerContextBuilder(); 138 } 139 140 public PostProjectAnalysisTaskTester withCeTask(CeTask ceTask) { 141 this.ceTask = requireNonNull(ceTask, CE_TASK_CAN_NOT_BE_NULL); 142 return this; 143 } 144 145 public PostProjectAnalysisTaskTester withProject(Project project) { 146 this.project = requireNonNull(project, PROJECT_CAN_NOT_BE_NULL); 147 return this; 148 } 149 150 /** 151 * @since 6.1 152 */ 153 public PostProjectAnalysisTaskTester withScannerContext(ScannerContext scannerContext) { 154 this.scannerContext = requireNonNull(scannerContext, SCANNER_CONTEXT_CAN_NOT_BE_NULL); 155 return this; 156 } 157 158 public PostProjectAnalysisTaskTester at(Date date) { 159 this.date = requireNonNull(date, DATE_CAN_NOT_BE_NULL); 160 return this; 161 } 162 163 public PostProjectAnalysisTaskTester withQualityGate(@Nullable QualityGate qualityGate) { 164 this.qualityGate = qualityGate; 165 return this; 166 } 167 168 public void execute() { 169 this.ceTask = requireNonNull(ceTask, CE_TASK_CAN_NOT_BE_NULL); 170 this.project = requireNonNull(project, PROJECT_CAN_NOT_BE_NULL); 171 this.date = requireNonNull(date, DATE_CAN_NOT_BE_NULL); 172 173 this.underTest.finished( 174 new PostProjectAnalysisTask.ProjectAnalysis() { 175 @Override 176 public ScannerContext getScannerContext() { 177 return scannerContext; 178 } 179 180 @Override 181 public CeTask getCeTask() { 182 return ceTask; 183 } 184 185 @Override 186 public Project getProject() { 187 return project; 188 } 189 190 @Override 191 public QualityGate getQualityGate() { 192 return qualityGate; 193 } 194 195 @Override 196 public Date getDate() { 197 return date; 198 } 199 200 @Override 201 public Optional<Date> getAnalysisDate() { 202 return Optional.of(date); 203 } 204 205 @Override 206 public String toString() { 207 return "ProjectAnalysis{" + 208 "ceTask=" + ceTask + 209 ", project=" + project + 210 ", date=" + date.getTime() + 211 ", analysisDate=" + date.getTime() + 212 ", qualityGate=" + qualityGate + 213 '}'; 214 } 215 }); 216 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 QualityGateBuilder { 327 private static final String ID_CAN_NOT_BE_NULL = "id cannot be null"; 328 private static final String NAME_CAN_NOT_BE_NULL = "name cannot be null"; 329 330 private String id; 331 private String name; 332 private QualityGate.Status status; 333 private final List<QualityGate.Condition> conditions = new ArrayList<>(); 334 335 private QualityGateBuilder() { 336 // prevents instantiation outside PostProjectAnalysisTaskTester 337 } 338 339 public QualityGateBuilder setId(String id) { 340 this.id = requireNonNull(id, ID_CAN_NOT_BE_NULL); 341 return this; 342 } 343 344 public QualityGateBuilder setName(String name) { 345 this.name = requireNonNull(name, NAME_CAN_NOT_BE_NULL); 346 return this; 347 } 348 349 public QualityGateBuilder setStatus(QualityGate.Status status) { 350 this.status = requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 351 return this; 352 } 353 354 public QualityGateBuilder add(QualityGate.Condition condition) { 355 conditions.add(requireNonNull(condition, "condition cannot be null")); 356 return this; 357 } 358 359 public QualityGateBuilder clearConditions() { 360 this.conditions.clear(); 361 return this; 362 } 363 364 public QualityGate build() { 365 requireNonNull(id, ID_CAN_NOT_BE_NULL); 366 requireNonNull(name, NAME_CAN_NOT_BE_NULL); 367 requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 368 369 return new QualityGate() { 370 @Override 371 public String getId() { 372 return id; 373 } 374 375 @Override 376 public String getName() { 377 return name; 378 } 379 380 @Override 381 public Status getStatus() { 382 return status; 383 } 384 385 @Override 386 public Collection<Condition> getConditions() { 387 return conditions; 388 } 389 390 @Override 391 public String toString() { 392 return "QualityGate{" + 393 "id='" + id + '\'' + 394 ", name='" + name + '\'' + 395 ", status=" + status + 396 ", conditions=" + conditions + 397 '}'; 398 } 399 }; 400 } 401 } 402 403 public static final class ConditionBuilder { 404 private static final String METRIC_KEY_CAN_NOT_BE_NULL = "metricKey cannot be null"; 405 private static final String OPERATOR_CAN_NOT_BE_NULL = "operator cannot be null"; 406 407 private String metricKey; 408 private QualityGate.Operator operator; 409 private String errorThreshold; 410 private String warningThreshold; 411 private boolean onLeakPeriod; 412 413 private ConditionBuilder() { 414 // prevents instantiation outside PostProjectAnalysisTaskTester 415 } 416 417 public ConditionBuilder setMetricKey(String metricKey) { 418 this.metricKey = requireNonNull(metricKey, METRIC_KEY_CAN_NOT_BE_NULL); 419 return this; 420 } 421 422 public ConditionBuilder setOperator(QualityGate.Operator operator) { 423 this.operator = requireNonNull(operator, OPERATOR_CAN_NOT_BE_NULL); 424 return this; 425 } 426 427 public ConditionBuilder setErrorThreshold(@Nullable String errorThreshold) { 428 this.errorThreshold = errorThreshold; 429 return this; 430 } 431 432 public ConditionBuilder setWarningThreshold(@Nullable String warningThreshold) { 433 this.warningThreshold = warningThreshold; 434 return this; 435 } 436 437 public ConditionBuilder setOnLeakPeriod(boolean onLeakPeriod) { 438 this.onLeakPeriod = onLeakPeriod; 439 return this; 440 } 441 442 public QualityGate.Condition buildNoValue() { 443 checkCommonProperties(); 444 return new QualityGate.Condition() { 445 @Override 446 public QualityGate.EvaluationStatus getStatus() { 447 return QualityGate.EvaluationStatus.NO_VALUE; 448 } 449 450 @Override 451 public String getMetricKey() { 452 return metricKey; 453 } 454 455 @Override 456 public QualityGate.Operator getOperator() { 457 return operator; 458 } 459 460 @Override 461 public String getErrorThreshold() { 462 return errorThreshold; 463 } 464 465 @Override 466 public String getWarningThreshold() { 467 return warningThreshold; 468 } 469 470 @Override 471 public boolean isOnLeakPeriod() { 472 return onLeakPeriod; 473 } 474 475 @Override 476 public String getValue() { 477 throw new IllegalStateException("There is no value when status is NO_VALUE"); 478 } 479 480 @Override 481 public String toString() { 482 return "Condition{" + 483 "status=" + QualityGate.EvaluationStatus.NO_VALUE + 484 ", metricKey='" + metricKey + '\'' + 485 ", operator=" + operator + 486 ", errorThreshold='" + errorThreshold + '\'' + 487 ", warningThreshold='" + warningThreshold + '\'' + 488 ", onLeakPeriod=" + onLeakPeriod + 489 '}'; 490 } 491 }; 492 } 493 494 public QualityGate.Condition build(final QualityGate.EvaluationStatus status, final String value) { 495 checkCommonProperties(); 496 requireNonNull(status, STATUS_CAN_NOT_BE_NULL); 497 checkArgument(status != QualityGate.EvaluationStatus.NO_VALUE, "status cannot be NO_VALUE, use method buildNoValue() instead"); 498 requireNonNull(value, "value cannot be null, use method buildNoValue() instead"); 499 return new QualityGate.Condition() { 500 @Override 501 public QualityGate.EvaluationStatus getStatus() { 502 return status; 503 } 504 505 @Override 506 public String getMetricKey() { 507 return metricKey; 508 } 509 510 @Override 511 public QualityGate.Operator getOperator() { 512 return operator; 513 } 514 515 @Override 516 public String getErrorThreshold() { 517 return errorThreshold; 518 } 519 520 @Override 521 public String getWarningThreshold() { 522 return warningThreshold; 523 } 524 525 @Override 526 public boolean isOnLeakPeriod() { 527 return onLeakPeriod; 528 } 529 530 @Override 531 public String getValue() { 532 return value; 533 } 534 535 @Override 536 public String toString() { 537 return "Condition{" + 538 "status=" + status + 539 ", metricKey='" + metricKey + '\'' + 540 ", operator=" + operator + 541 ", errorThreshold='" + errorThreshold + '\'' + 542 ", warningThreshold='" + warningThreshold + '\'' + 543 ", onLeakPeriod=" + onLeakPeriod + 544 ", value='" + value + '\'' + 545 '}'; 546 } 547 }; 548 } 549 550 private void checkCommonProperties() { 551 requireNonNull(metricKey, METRIC_KEY_CAN_NOT_BE_NULL); 552 requireNonNull(operator, OPERATOR_CAN_NOT_BE_NULL); 553 checkState(errorThreshold != null || warningThreshold != null, "At least one of errorThreshold and warningThreshold must be non null"); 554 } 555 } 556 557 public static final class ScannerContextBuilder { 558 private final Map<String, String> properties = new HashMap<>(); 559 560 private ScannerContextBuilder() { 561 // prevents instantiation outside PostProjectAnalysisTaskTester 562 } 563 564 public ScannerContextBuilder addProperties(Map<String, String> map) { 565 properties.putAll(map); 566 return this; 567 } 568 569 public ScannerContext build() { 570 return () -> properties; 571 } 572 } 573}