001/*
002 * SonarQube
003 * Copyright (C) 2009-2016 SonarSource SA
004 * mailto:contact 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.List;
026import javax.annotation.CheckForNull;
027import javax.annotation.Nullable;
028
029import static com.google.common.base.Preconditions.checkArgument;
030import static com.google.common.base.Preconditions.checkState;
031import static java.util.Objects.requireNonNull;
032
033/**
034 * This class can be used to test {@link PostProjectAnalysisTask} implementations, see example below:
035 * <pre>
036 * import static org.assertj.core.api.Assertions.assertThat;
037 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newCeTaskBuilder;
038 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newConditionBuilder;
039 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newProjectBuilder;
040 * import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newQualityGateBuilder;
041 *
042 * public class CaptorPostProjectAnalysisTaskTest {
043 *   private class CaptorPostProjectAnalysisTask implements PostProjectAnalysisTask {
044 *     private ProjectAnalysis projectAnalysis;
045 *
046 *    {@literal @}Override
047 *     public void finished(ProjectAnalysis analysis) {
048 *       this.projectAnalysis = analysis;
049 *     }
050 *   }
051 *
052 *  {@literal @}Test
053 *   public void execute_is_passed_a_non_null_ProjectAnalysis_object() {
054 *     CaptorPostProjectAnalysisTask postProjectAnalysisTask = new CaptorPostProjectAnalysisTask();
055 *
056 *     PostProjectAnalysisTaskTester.of(postProjectAnalysisTask)
057 *       .withCeTask(
058 *           newCeTaskBuilder()
059 *               .setId("id")
060 *               .setStatus(CeTask.Status.SUCCESS)
061 *               .build())
062 *       .withProject(
063 *         PostProjectAnalysisTaskTester.newProjectBuilder()
064 *           .setUuid("uuid")
065 *           .setKey("key")
066 *           .setName("name")
067 *           .build())
068 *       .at(new Date())
069 *       .withQualityGate(
070 *         newQualityGateBuilder()
071 *           .setId("id")
072 *           .setName("name")
073 *           .setStatus(QualityGate.Status.OK)
074 *           .add(
075 *             newConditionBuilder()
076 *               .setMetricKey("metric key")
077 *               .setOperator(QualityGate.Operator.GREATER_THAN)
078 *               .setErrorThreshold("12")
079 *               .setOnLeakPeriod(true)
080 *               .build(QualityGate.EvaluationStatus.OK, "value"))
081 *           .build())
082 *       .execute();
083 *
084 *     assertThat(postProjectAnalysisTask.projectAnalysis).isNotNull();
085 *   }
086 * }
087 * </pre>
088 *
089 * @since 5.5
090 */
091public class PostProjectAnalysisTaskTester {
092  private static final String DATE_CAN_NOT_BE_NULL = "date cannot be null";
093  private static final String PROJECT_CAN_NOT_BE_NULL = "project cannot be null";
094  private static final String CE_TASK_CAN_NOT_BE_NULL = "ceTask cannot be null";
095  private static final String STATUS_CAN_NOT_BE_NULL = "status cannot be null";
096
097  private final PostProjectAnalysisTask underTest;
098  @CheckForNull
099  private CeTask ceTask;
100  @CheckForNull
101  private Project project;
102  @CheckForNull
103  private Date date;
104  @CheckForNull
105  private QualityGate qualityGate;
106
107  private PostProjectAnalysisTaskTester(PostProjectAnalysisTask underTest) {
108    this.underTest = requireNonNull(underTest, "PostProjectAnalysisTask instance cannot be null");
109  }
110
111  public static PostProjectAnalysisTaskTester of(PostProjectAnalysisTask underTest) {
112    return new PostProjectAnalysisTaskTester(underTest);
113  }
114
115  public static CeTaskBuilder newCeTaskBuilder() {
116    return new CeTaskBuilder();
117  }
118
119  public static ProjectBuilder newProjectBuilder() {
120    return new ProjectBuilder();
121  }
122
123  public static QualityGateBuilder newQualityGateBuilder() {
124    return new QualityGateBuilder();
125  }
126
127  public static ConditionBuilder newConditionBuilder() {
128    return new ConditionBuilder();
129  }
130
131  public PostProjectAnalysisTaskTester withCeTask(CeTask ceTask) {
132    this.ceTask = requireNonNull(ceTask, CE_TASK_CAN_NOT_BE_NULL);
133    return this;
134  }
135
136  public PostProjectAnalysisTaskTester withProject(Project project) {
137    this.project = requireNonNull(project, PROJECT_CAN_NOT_BE_NULL);
138    return this;
139  }
140
141  public PostProjectAnalysisTaskTester at(Date date) {
142    this.date = requireNonNull(date, DATE_CAN_NOT_BE_NULL);
143    return this;
144  }
145
146  public PostProjectAnalysisTaskTester withQualityGate(@Nullable QualityGate qualityGate) {
147    this.qualityGate = qualityGate;
148    return this;
149  }
150
151  public void execute() {
152    this.ceTask = requireNonNull(ceTask, CE_TASK_CAN_NOT_BE_NULL);
153    this.project = requireNonNull(project, PROJECT_CAN_NOT_BE_NULL);
154    this.date = requireNonNull(date, DATE_CAN_NOT_BE_NULL);
155
156    this.underTest.finished(
157      new PostProjectAnalysisTask.ProjectAnalysis() {
158        @Override
159        public CeTask getCeTask() {
160          return ceTask;
161        }
162
163        @Override
164        public Project getProject() {
165          return project;
166        }
167
168        @Override
169        public QualityGate getQualityGate() {
170          return qualityGate;
171        }
172
173        @Override
174        public Date getDate() {
175          return date;
176        }
177
178        @Override
179        public String toString() {
180          return "ProjectAnalysis{" +
181            "ceTask=" + ceTask +
182            ", project=" + project +
183            ", date=" + date.getTime() +
184            ", qualityGate=" + qualityGate +
185            '}';
186        }
187      });
188
189  }
190
191  public static final class CeTaskBuilder {
192    private static final String ID_CAN_NOT_BE_NULL = "id cannot be null";
193
194    @CheckForNull
195    private String id;
196    @CheckForNull
197    private CeTask.Status status;
198
199    private CeTaskBuilder() {
200      // prevents instantiation outside PostProjectAnalysisTaskTester
201    }
202
203    public CeTaskBuilder setId(String id) {
204      this.id = requireNonNull(id, ID_CAN_NOT_BE_NULL);
205      return this;
206    }
207
208    public CeTaskBuilder setStatus(CeTask.Status status) {
209      this.status = requireNonNull(status, STATUS_CAN_NOT_BE_NULL);
210      return this;
211    }
212
213    public CeTask build() {
214      requireNonNull(id, ID_CAN_NOT_BE_NULL);
215      requireNonNull(status, STATUS_CAN_NOT_BE_NULL);
216      return new CeTask() {
217        @Override
218        public String getId() {
219          return id;
220        }
221
222        @Override
223        public Status getStatus() {
224          return status;
225        }
226
227        @Override
228        public String toString() {
229          return "CeTask{" +
230            "id='" + id + '\'' +
231            ", status=" + status +
232            '}';
233        }
234      };
235    }
236  }
237
238  public static final class ProjectBuilder {
239    private static final String UUID_CAN_NOT_BE_NULL = "uuid cannot be null";
240    private static final String KEY_CAN_NOT_BE_NULL = "key cannot be null";
241    private static final String NAME_CAN_NOT_BE_NULL = "name cannot be null";
242    private String uuid;
243    private String key;
244    private String name;
245
246    private ProjectBuilder() {
247      // prevents instantiation outside PostProjectAnalysisTaskTester
248    }
249
250    public ProjectBuilder setUuid(String uuid) {
251      this.uuid = requireNonNull(uuid, UUID_CAN_NOT_BE_NULL);
252      return this;
253    }
254
255    public ProjectBuilder setKey(String key) {
256      this.key = requireNonNull(key, KEY_CAN_NOT_BE_NULL);
257      return this;
258    }
259
260    public ProjectBuilder setName(String name) {
261      this.name = requireNonNull(name, NAME_CAN_NOT_BE_NULL);
262      return this;
263    }
264
265    public Project build() {
266      requireNonNull(uuid, UUID_CAN_NOT_BE_NULL);
267      requireNonNull(key, KEY_CAN_NOT_BE_NULL);
268      requireNonNull(name, NAME_CAN_NOT_BE_NULL);
269      return new Project() {
270        @Override
271        public String getUuid() {
272          return uuid;
273        }
274
275        @Override
276        public String getKey() {
277          return key;
278        }
279
280        @Override
281        public String getName() {
282          return name;
283        }
284
285        @Override
286        public String toString() {
287          return "Project{" +
288            "uuid='" + uuid + '\'' +
289            ", key='" + key + '\'' +
290            ", name='" + name + '\'' +
291            '}';
292        }
293
294      };
295    }
296  }
297
298  public static final class QualityGateBuilder {
299    private static final String ID_CAN_NOT_BE_NULL = "id cannot be null";
300    private static final String NAME_CAN_NOT_BE_NULL = "name cannot be null";
301
302    private String id;
303    private String name;
304    private QualityGate.Status status;
305    private final List<QualityGate.Condition> conditions = new ArrayList<>();
306
307    private QualityGateBuilder() {
308      // prevents instantiation outside PostProjectAnalysisTaskTester
309    }
310
311    public QualityGateBuilder setId(String id) {
312      this.id = requireNonNull(id, ID_CAN_NOT_BE_NULL);
313      return this;
314    }
315
316    public QualityGateBuilder setName(String name) {
317      this.name = requireNonNull(name, NAME_CAN_NOT_BE_NULL);
318      return this;
319    }
320
321    public QualityGateBuilder setStatus(QualityGate.Status status) {
322      this.status = requireNonNull(status, STATUS_CAN_NOT_BE_NULL);
323      return this;
324    }
325
326    public QualityGateBuilder add(QualityGate.Condition condition) {
327      conditions.add(requireNonNull(condition, "condition cannot be null"));
328      return this;
329    }
330
331    public QualityGateBuilder clearConditions() {
332      this.conditions.clear();
333      return this;
334    }
335
336    public QualityGate build() {
337      requireNonNull(id, ID_CAN_NOT_BE_NULL);
338      requireNonNull(name, NAME_CAN_NOT_BE_NULL);
339      requireNonNull(status, STATUS_CAN_NOT_BE_NULL);
340
341      return new QualityGate() {
342        @Override
343        public String getId() {
344          return id;
345        }
346
347        @Override
348        public String getName() {
349          return name;
350        }
351
352        @Override
353        public Status getStatus() {
354          return status;
355        }
356
357        @Override
358        public Collection<Condition> getConditions() {
359          return conditions;
360        }
361
362        @Override
363        public String toString() {
364          return "QualityGate{" +
365            "id='" + id + '\'' +
366            ", name='" + name + '\'' +
367            ", status=" + status +
368            ", conditions=" + conditions +
369            '}';
370        }
371      };
372    }
373  }
374
375  public static final class ConditionBuilder {
376    private static final String METRIC_KEY_CAN_NOT_BE_NULL = "metricKey cannot be null";
377    private static final String OPERATOR_CAN_NOT_BE_NULL = "operator cannot be null";
378
379    private String metricKey;
380    private QualityGate.Operator operator;
381    private String errorThreshold;
382    private String warningThreshold;
383    private boolean onLeakPeriod;
384
385    private ConditionBuilder() {
386      // prevents instantiation outside PostProjectAnalysisTaskTester
387    }
388
389    public ConditionBuilder setMetricKey(String metricKey) {
390      this.metricKey = requireNonNull(metricKey, METRIC_KEY_CAN_NOT_BE_NULL);
391      return this;
392    }
393
394    public ConditionBuilder setOperator(QualityGate.Operator operator) {
395      this.operator = requireNonNull(operator, OPERATOR_CAN_NOT_BE_NULL);
396      return this;
397    }
398
399    public ConditionBuilder setErrorThreshold(@Nullable String errorThreshold) {
400      this.errorThreshold = errorThreshold;
401      return this;
402    }
403
404    public ConditionBuilder setWarningThreshold(@Nullable String warningThreshold) {
405      this.warningThreshold = warningThreshold;
406      return this;
407    }
408
409    public ConditionBuilder setOnLeakPeriod(boolean onLeakPeriod) {
410      this.onLeakPeriod = onLeakPeriod;
411      return this;
412    }
413
414    public QualityGate.Condition buildNoValue() {
415      checkCommonProperties();
416      return new QualityGate.Condition() {
417        @Override
418        public QualityGate.EvaluationStatus getStatus() {
419          return QualityGate.EvaluationStatus.NO_VALUE;
420        }
421
422        @Override
423        public String getMetricKey() {
424          return metricKey;
425        }
426
427        @Override
428        public QualityGate.Operator getOperator() {
429          return operator;
430        }
431
432        @Override
433        public String getErrorThreshold() {
434          return errorThreshold;
435        }
436
437        @Override
438        public String getWarningThreshold() {
439          return warningThreshold;
440        }
441
442        @Override
443        public boolean isOnLeakPeriod() {
444          return onLeakPeriod;
445        }
446
447        @Override
448        public String getValue() {
449          throw new IllegalStateException("There is no value when status is NO_VALUE");
450        }
451
452        @Override
453        public String toString() {
454          return "Condition{" +
455            "status=" + QualityGate.EvaluationStatus.NO_VALUE +
456            ", metricKey='" + metricKey + '\'' +
457            ", operator=" + operator +
458            ", errorThreshold='" + errorThreshold + '\'' +
459            ", warningThreshold='" + warningThreshold + '\'' +
460            ", onLeakPeriod=" + onLeakPeriod +
461            '}';
462        }
463      };
464    }
465
466    public QualityGate.Condition build(final QualityGate.EvaluationStatus status, final String value) {
467      checkCommonProperties();
468      requireNonNull(status, STATUS_CAN_NOT_BE_NULL);
469      checkArgument(status != QualityGate.EvaluationStatus.NO_VALUE, "status cannot be NO_VALUE, use method buildNoValue() instead");
470      requireNonNull(value, "value cannot be null, use method buildNoValue() instead");
471      return new QualityGate.Condition() {
472        @Override
473        public QualityGate.EvaluationStatus getStatus() {
474          return status;
475        }
476
477        @Override
478        public String getMetricKey() {
479          return metricKey;
480        }
481
482        @Override
483        public QualityGate.Operator getOperator() {
484          return operator;
485        }
486
487        @Override
488        public String getErrorThreshold() {
489          return errorThreshold;
490        }
491
492        @Override
493        public String getWarningThreshold() {
494          return warningThreshold;
495        }
496
497        @Override
498        public boolean isOnLeakPeriod() {
499          return onLeakPeriod;
500        }
501
502        @Override
503        public String getValue() {
504          return value;
505        }
506
507        @Override
508        public String toString() {
509          return "Condition{" +
510            "status=" + status +
511            ", metricKey='" + metricKey + '\'' +
512            ", operator=" + operator +
513            ", errorThreshold='" + errorThreshold + '\'' +
514            ", warningThreshold='" + warningThreshold + '\'' +
515            ", onLeakPeriod=" + onLeakPeriod +
516            ", value='" + value + '\'' +
517            '}';
518        }
519      };
520    }
521
522    private void checkCommonProperties() {
523      requireNonNull(metricKey, METRIC_KEY_CAN_NOT_BE_NULL);
524      requireNonNull(operator, OPERATOR_CAN_NOT_BE_NULL);
525      checkState(errorThreshold != null || warningThreshold != null, "At least one of errorThreshold and warningThreshold must be non null");
526    }
527  }
528}