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