]> source.dussan.org Git - sonarqube.git/blob
0d1184c2167ef71dd2ddd299d920ea967a1c210d
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.ce.task.projectanalysis.step;
21
22 import com.tngtech.java.junit.dataprovider.DataProvider;
23 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
24 import com.tngtech.java.junit.dataprovider.UseDataProvider;
25 import java.time.ZoneId;
26 import java.time.ZonedDateTime;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.List;
30 import java.util.Optional;
31 import java.util.Random;
32 import java.util.stream.Stream;
33 import javax.annotation.Nullable;
34 import org.junit.Before;
35 import org.junit.Rule;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 import org.slf4j.event.Level;
39 import org.sonar.api.testfixtures.log.LogTester;
40 import org.sonar.api.utils.MessageException;
41 import org.sonar.api.utils.System2;
42 import org.sonar.ce.task.log.CeTaskMessages;
43 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
44 import org.sonar.ce.task.projectanalysis.component.Component;
45 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
46 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
47 import org.sonar.ce.task.projectanalysis.period.NewCodePeriodResolver;
48 import org.sonar.ce.task.projectanalysis.period.Period;
49 import org.sonar.ce.task.projectanalysis.period.PeriodHolderImpl;
50 import org.sonar.ce.task.step.ComputationStep;
51 import org.sonar.ce.task.step.TestComputationStepContext;
52 import org.sonar.core.util.SequenceUuidFactory;
53 import org.sonar.db.DbTester;
54 import org.sonar.db.component.ComponentDto;
55 import org.sonar.db.component.SnapshotDto;
56 import org.sonar.db.event.EventTesting;
57 import org.sonar.db.newcodeperiod.NewCodePeriodDao;
58 import org.sonar.db.newcodeperiod.NewCodePeriodType;
59 import org.sonar.server.project.Project;
60
61 import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
62 import static org.assertj.core.api.Assertions.assertThat;
63 import static org.assertj.core.api.Assertions.assertThatThrownBy;
64 import static org.assertj.core.api.Assertions.fail;
65 import static org.mockito.ArgumentMatchers.any;
66 import static org.mockito.Mockito.mock;
67 import static org.mockito.Mockito.verify;
68 import static org.mockito.Mockito.verifyNoInteractions;
69 import static org.mockito.Mockito.verifyNoMoreInteractions;
70 import static org.mockito.Mockito.when;
71 import static org.sonar.db.component.SnapshotDto.STATUS_PROCESSED;
72 import static org.sonar.db.component.SnapshotDto.STATUS_UNPROCESSED;
73 import static org.sonar.db.event.EventDto.CATEGORY_VERSION;
74 import static org.sonar.db.event.EventTesting.newEvent;
75
76 @RunWith(DataProviderRunner.class)
77 public class LoadPeriodsStepIT extends BaseStepTest {
78   @Rule
79   public DbTester dbTester = DbTester.create(System2.INSTANCE);
80   @Rule
81   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
82   @Rule
83   public LogTester logTester = new LogTester();
84
85   private final AnalysisMetadataHolder analysisMetadataHolder = mock(AnalysisMetadataHolder.class);
86   private final PeriodHolderImpl periodsHolder = new PeriodHolderImpl();
87   private final System2 system2Mock = mock(System2.class);
88   private final NewCodePeriodDao dao = new NewCodePeriodDao(system2Mock, new SequenceUuidFactory());
89   private final NewCodePeriodResolver newCodePeriodResolver = new NewCodePeriodResolver(dbTester.getDbClient(), analysisMetadataHolder);
90   private final ZonedDateTime analysisDate = ZonedDateTime.of(2019, 3, 20, 5, 30, 40, 0, ZoneId.systemDefault());
91   private final CeTaskMessages ceTaskMessages = mock(CeTaskMessages.class);
92   private final LoadPeriodsStep underTest = new LoadPeriodsStep(analysisMetadataHolder, dao, treeRootHolder, periodsHolder, dbTester.getDbClient(), newCodePeriodResolver,
93     ceTaskMessages, system2Mock);
94
95   private ComponentDto project;
96
97   @Override
98   protected ComputationStep step() {
99     return underTest;
100   }
101
102   @Before
103   public void setUp() {
104     logTester.setLevel(Level.TRACE);
105     project = dbTester.components().insertPublicProject().getMainBranchComponent();
106
107     when(analysisMetadataHolder.isBranch()).thenReturn(true);
108     when(analysisMetadataHolder.isFirstAnalysis()).thenReturn(false);
109     when(analysisMetadataHolder.getAnalysisDate()).thenReturn(analysisDate.toInstant().toEpochMilli());
110   }
111
112   @Test
113   public void no_period_on_first_analysis() {
114     setupRoot(project);
115
116     when(analysisMetadataHolder.isFirstAnalysis()).thenReturn(true);
117     underTest.execute(new TestComputationStepContext());
118
119     verify(analysisMetadataHolder).isFirstAnalysis();
120     verify(analysisMetadataHolder).isBranch();
121     verify(analysisMetadataHolder).getProject();
122     verify(analysisMetadataHolder).getNewCodeReferenceBranch();
123     assertThat(periodsHolder.hasPeriod()).isFalse();
124     verifyNoMoreInteractions(analysisMetadataHolder);
125   }
126
127   @Test
128   public void no_period_date_if_not_branch() {
129     when(analysisMetadataHolder.isBranch()).thenReturn(false);
130     underTest.execute(new TestComputationStepContext());
131
132     verify(analysisMetadataHolder).isBranch();
133     assertThat(periodsHolder.hasPeriod()).isFalse();
134     verifyNoMoreInteractions(analysisMetadataHolder);
135   }
136
137   @Test
138   public void load_default_if_nothing_defined() {
139     setupRoot(project);
140
141     SnapshotDto analysis = dbTester.components().insertSnapshot(project,
142       snapshot -> snapshot.setCreatedAt(milisSinceEpoch(2019, 3, 15, 0)));
143
144     underTest.execute(new TestComputationStepContext());
145
146     assertPeriod(NewCodePeriodType.PREVIOUS_VERSION, null, analysis.getCreatedAt());
147     verifyDebugLogs("Resolving first analysis as new code period as there is only one existing version");
148   }
149
150   @Test
151   public void load_number_of_days_global() {
152     setGlobalPeriod(NewCodePeriodType.NUMBER_OF_DAYS, "10");
153
154     testNumberOfDays(project);
155   }
156
157   @Test
158   public void load_number_of_days_on_project() {
159     setGlobalPeriod(NewCodePeriodType.PREVIOUS_VERSION, null);
160     setProjectPeriod(project.uuid(), NewCodePeriodType.NUMBER_OF_DAYS, "10");
161
162     testNumberOfDays(project);
163   }
164
165   @Test
166   public void load_number_of_days_on_branch() {
167     ComponentDto branch = dbTester.components().insertProjectBranch(project);
168
169     setGlobalPeriod(NewCodePeriodType.PREVIOUS_VERSION, null);
170     setProjectPeriod(project.uuid(), NewCodePeriodType.PREVIOUS_VERSION, null);
171     setBranchPeriod(project.uuid(), branch.uuid(), NewCodePeriodType.NUMBER_OF_DAYS, "10");
172
173     testNumberOfDays(branch);
174     verifyNoInteractions(ceTaskMessages);
175   }
176
177   @Test
178   public void load_reference_branch() {
179     ComponentDto branch = dbTester.components().insertProjectBranch(project);
180     setupRoot(branch);
181
182     setProjectPeriod(project.uuid(), NewCodePeriodType.REFERENCE_BRANCH, "master");
183
184     underTest.execute(new TestComputationStepContext());
185     assertPeriod(NewCodePeriodType.REFERENCE_BRANCH, "master", null);
186     verifyNoInteractions(ceTaskMessages);
187   }
188
189   @Test
190   public void scanner_overrides_branch_new_code_reference_branch() {
191     ComponentDto branch = dbTester.components().insertProjectBranch(project);
192     setupRoot(branch);
193
194     setBranchPeriod(project.uuid(), branch.uuid(), NewCodePeriodType.REFERENCE_BRANCH, "master");
195
196     String newCodeReferenceBranch = "newCodeReferenceBranch";
197     when(analysisMetadataHolder.getNewCodeReferenceBranch()).thenReturn(Optional.of(newCodeReferenceBranch));
198
199     underTest.execute(new TestComputationStepContext());
200     assertPeriod(NewCodePeriodType.REFERENCE_BRANCH, newCodeReferenceBranch, null);
201     verify(ceTaskMessages).add(any(CeTaskMessages.Message.class));
202   }
203
204   @Test
205   public void scanner_defines_new_code_reference_branch() {
206     ComponentDto branch = dbTester.components().insertProjectBranch(project);
207     setupRoot(branch);
208
209     String newCodeReferenceBranch = "newCodeReferenceBranch";
210     when(analysisMetadataHolder.getNewCodeReferenceBranch()).thenReturn(Optional.of(newCodeReferenceBranch));
211
212     underTest.execute(new TestComputationStepContext());
213     assertPeriod(NewCodePeriodType.REFERENCE_BRANCH, newCodeReferenceBranch, null);
214     verifyNoInteractions(ceTaskMessages);
215   }
216
217   @Test
218   public void scanner_overrides_project_new_code_reference_branch() {
219     ComponentDto branch = dbTester.components().insertProjectBranch(project);
220     setupRoot(branch);
221
222     setProjectPeriod(project.uuid(), NewCodePeriodType.REFERENCE_BRANCH, "master");
223
224     String newCodeReferenceBranch = "newCodeReferenceBranch";
225     when(analysisMetadataHolder.getNewCodeReferenceBranch()).thenReturn(Optional.of(newCodeReferenceBranch));
226
227     underTest.execute(new TestComputationStepContext());
228     assertPeriod(NewCodePeriodType.REFERENCE_BRANCH, newCodeReferenceBranch, null);
229     verifyNoInteractions(ceTaskMessages);
230   }
231
232   @Test
233   public void load_reference_branch_without_fork_date_in_report() {
234     ComponentDto branch = dbTester.components().insertProjectBranch(project);
235     setupRoot(branch);
236
237     setProjectPeriod(project.uuid(), NewCodePeriodType.REFERENCE_BRANCH, "master");
238
239     underTest.execute(new TestComputationStepContext());
240     assertPeriod(NewCodePeriodType.REFERENCE_BRANCH, "master", null);
241     verifyNoInteractions(ceTaskMessages);
242   }
243
244   private void testNumberOfDays(ComponentDto projectOrBranch) {
245     setupRoot(projectOrBranch);
246
247     SnapshotDto analysis = dbTester.components().insertSnapshot(projectOrBranch,
248       snapshot -> snapshot.setCreatedAt(milisSinceEpoch(2019, 3, 15, 0)));
249
250     underTest.execute(new TestComputationStepContext());
251
252     assertPeriod(NewCodePeriodType.NUMBER_OF_DAYS, "10", analysis.getCreatedAt());
253     verifyDebugLogs("Resolving new code period by 10 days: 2019-03-10");
254   }
255
256   @Test
257   public void load_specific_analysis() {
258     ComponentDto branch = dbTester.components().insertProjectBranch(project);
259     SnapshotDto selectedAnalysis = dbTester.components().insertSnapshot(branch);
260     SnapshotDto aVersionAnalysis = dbTester.components().insertSnapshot(branch, snapshot -> snapshot.setCreatedAt(milisSinceEpoch(2019, 3, 12, 0)).setLast(false));
261     dbTester.events().insertEvent(EventTesting.newEvent(aVersionAnalysis).setName("a_version").setCategory(CATEGORY_VERSION));
262     dbTester.components().insertSnapshot(branch, snapshot -> snapshot.setCreatedAt(milisSinceEpoch(2019, 3, 15, 0)).setLast(true));
263
264     setBranchPeriod(project.uuid(), branch.uuid(), NewCodePeriodType.SPECIFIC_ANALYSIS, selectedAnalysis.getUuid());
265     setupRoot(branch);
266
267     underTest.execute(new TestComputationStepContext());
268
269     assertPeriod(NewCodePeriodType.SPECIFIC_ANALYSIS, selectedAnalysis.getUuid(), selectedAnalysis.getCreatedAt());
270     verifyDebugLogs("Resolving new code period with a specific analysis");
271     verifyNoInteractions(ceTaskMessages);
272   }
273
274   @Test
275   public void throw_ISE_if_no_analysis_found_for_number_of_days() {
276     setProjectPeriod(project.uuid(), NewCodePeriodType.NUMBER_OF_DAYS, "10");
277
278     setupRoot(project);
279
280     assertThatThrownBy(() -> underTest.execute(new TestComputationStepContext()))
281       .isInstanceOf(IllegalStateException.class)
282       .hasMessageContaining("Attempting to resolve period while no analysis exist");
283   }
284
285   @Test
286   public void throw_ISE_if_no_analysis_found_with_default() {
287     setupRoot(project);
288
289     assertThatThrownBy(() -> underTest.execute(new TestComputationStepContext()))
290       .isInstanceOf(IllegalStateException.class)
291       .hasMessageContaining("Attempting to resolve period while no analysis exist");
292   }
293
294   @Test
295   public void ignore_unprocessed_snapshots() {
296     SnapshotDto analysis1 = dbTester.components()
297       .insertSnapshot(project, snapshot -> snapshot.setStatus(STATUS_UNPROCESSED).setCreatedAt(milisSinceEpoch(2019, 3, 12, 0)).setLast(false));
298     SnapshotDto analysis2 = dbTester.components().insertSnapshot(project,
299       snapshot -> snapshot.setStatus(STATUS_PROCESSED).setProjectVersion("not provided").setCreatedAt(milisSinceEpoch(2019, 3, 15, 0)).setLast(false));
300     dbTester.events().insertEvent(newEvent(analysis1).setName("not provided").setCategory(CATEGORY_VERSION).setDate(analysis1.getCreatedAt()));
301     dbTester.events().insertEvent(newEvent(analysis2).setName("not provided").setCategory(CATEGORY_VERSION).setDate(analysis2.getCreatedAt()));
302     setupRoot(project);
303     setProjectPeriod(project.uuid(), NewCodePeriodType.NUMBER_OF_DAYS, "10");
304
305     underTest.execute(new TestComputationStepContext());
306
307     assertPeriod(NewCodePeriodType.NUMBER_OF_DAYS, "10", analysis2.getCreatedAt());
308     verifyDebugLogs("Resolving new code period by 10 days: 2019-03-10");
309   }
310
311   @Test
312   public void throw_ISE_when_specific_analysis_is_set_but_does_not_exist_in_DB() {
313     ComponentDto project = dbTester.components().insertPublicProject().getMainBranchComponent();
314     setProjectPeriod(project.uuid(), NewCodePeriodType.SPECIFIC_ANALYSIS, "nonexistent");
315     setupRoot(project, project.uuid(), "any-string");
316
317     assertThatThrownBy(() -> underTest.execute(new TestComputationStepContext()))
318       .isInstanceOf(IllegalStateException.class)
319       .hasMessage("Analysis 'nonexistent' of project '" + project.uuid() + "' defined as the baseline does not exist");
320   }
321
322   @Test
323   public void throw_ISE_when_specific_analysis_is_set_but_does_not_belong_to_current_project() {
324     ComponentDto otherProject = dbTester.components().insertPublicProject().getMainBranchComponent();
325     SnapshotDto otherProjectAnalysis = dbTester.components().insertSnapshot(otherProject);
326     setBranchPeriod(project.uuid(), project.uuid(), NewCodePeriodType.SPECIFIC_ANALYSIS, otherProjectAnalysis.getUuid());
327     setupRoot(project);
328
329     assertThatThrownBy(() -> underTest.execute(new TestComputationStepContext()))
330       .isInstanceOf(IllegalStateException.class)
331       .hasMessage("Analysis '" + otherProjectAnalysis.getUuid() + "' of project '" + project.uuid() + "' defined as the baseline does not exist");
332   }
333
334   @Test
335   public void throw_ISE_when_specific_analysis_is_set_but_does_not_belong_to_current_branch() {
336     ComponentDto otherBranch = dbTester.components().insertProjectBranch(project);
337     SnapshotDto otherBranchAnalysis = dbTester.components().insertSnapshot(otherBranch);
338     setBranchPeriod(project.uuid(), project.uuid(), NewCodePeriodType.SPECIFIC_ANALYSIS, otherBranchAnalysis.getUuid());
339     setupRoot(project);
340
341     assertThatThrownBy(() -> underTest.execute(new TestComputationStepContext()))
342       .isInstanceOf(IllegalStateException.class)
343       .hasMessage("Analysis '" + otherBranchAnalysis.getUuid() + "' of project '" + project.uuid() + "' defined as the baseline does not exist");
344   }
345
346   @Test
347   public void load_previous_version() {
348     SnapshotDto analysis1 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1226379600000L).setProjectVersion("0.9").setLast(false)); // 2008-11-11
349     SnapshotDto analysis2 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1226494680000L).setProjectVersion("1.0").setLast(false)); // 2008-11-12
350     SnapshotDto analysis3 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1227157200000L).setProjectVersion("1.1").setLast(false)); // 2008-11-20
351     SnapshotDto analysis4 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1227358680000L).setProjectVersion("1.1").setLast(false)); // 2008-11-22
352     SnapshotDto analysis5 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1227934800000L).setProjectVersion("1.1").setLast(true)); // 2008-11-29
353     dbTester.events().insertEvent(newEvent(analysis1).setName("0.9").setCategory(CATEGORY_VERSION).setDate(analysis1.getCreatedAt()));
354     dbTester.events().insertEvent(newEvent(analysis2).setName("1.0").setCategory(CATEGORY_VERSION).setDate(analysis2.getCreatedAt()));
355     dbTester.events().insertEvent(newEvent(analysis5).setName("1.1").setCategory(CATEGORY_VERSION).setDate(analysis5.getCreatedAt()));
356     setupRoot(project, "1.1");
357     setProjectPeriod(project.uuid(), NewCodePeriodType.PREVIOUS_VERSION, null);
358
359     underTest.execute(new TestComputationStepContext());
360
361     assertPeriod(NewCodePeriodType.PREVIOUS_VERSION, "1.0", analysis2.getCreatedAt());
362
363     verifyDebugLogs("Resolving new code period by previous version: 1.0");
364   }
365
366   @Test
367   public void load_previous_version_when_version_is_changing() {
368     SnapshotDto analysis1 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1226379600000L).setProjectVersion("0.9").setLast(false)); // 2008-11-11
369     SnapshotDto analysis2 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1226494680000L).setProjectVersion("0.9").setLast(true)); // 2008-11-12
370
371     dbTester.events().insertEvent(newEvent(analysis2).setName("0.9").setCategory(CATEGORY_VERSION).setDate(analysis2.getCreatedAt()));
372     setupRoot(project, "1.0");
373     setProjectPeriod(project.uuid(), NewCodePeriodType.PREVIOUS_VERSION, null);
374
375     underTest.execute(new TestComputationStepContext());
376
377     assertPeriod(NewCodePeriodType.PREVIOUS_VERSION, "0.9", analysis2.getCreatedAt());
378
379     verifyDebugLogs("Resolving new code period by previous version: 0.9");
380   }
381
382   @Test
383   @UseDataProvider("zeroOrLess")
384   public void fail_with_MessageException_if_period_is_0_or_less(int zeroOrLess) {
385     setupRoot(project);
386     setProjectPeriod(project.uuid(), NewCodePeriodType.NUMBER_OF_DAYS, String.valueOf(zeroOrLess));
387
388     verifyFailWithInvalidValueMessageException(String.valueOf(zeroOrLess),
389       "Invalid code period '" + zeroOrLess + "': number of days is <= 0");
390   }
391
392   @Test
393   public void load_previous_version_with_previous_version_deleted() {
394     SnapshotDto analysis1 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1226379600000L).setProjectVersion("0.9").setLast(false)); // 2008-11-11
395     SnapshotDto analysis2 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1226494680000L).setProjectVersion("1.0").setLast(false)); // 2008-11-12
396     SnapshotDto analysis3 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1227157200000L).setProjectVersion("1.1").setLast(true)); // 2008-11-20
397     dbTester.events().insertEvent(newEvent(analysis1).setName("0.9").setCategory(CATEGORY_VERSION));
398     // The "1.0" version was deleted from the history
399     setupRoot(project, "1.1");
400
401     underTest.execute(new TestComputationStepContext());
402
403     // Analysis form 2008-11-11
404     assertPeriod(NewCodePeriodType.PREVIOUS_VERSION, "0.9", analysis1.getCreatedAt());
405   }
406
407   @Test
408   public void load_previous_version_with_first_analysis_when_no_previous_version_found() {
409     SnapshotDto analysis1 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1226379600000L).setProjectVersion("1.1").setLast(false)); // 2008-11-11
410     SnapshotDto analysis2 = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1227934800000L).setProjectVersion("1.1").setLast(true)); // 2008-11-29
411     dbTester.events().insertEvent(newEvent(analysis2).setName("1.1").setCategory(CATEGORY_VERSION));
412     setupRoot(project, "1.1");
413
414     underTest.execute(new TestComputationStepContext());
415
416     assertPeriod(NewCodePeriodType.PREVIOUS_VERSION, null, analysis1.getCreatedAt());
417
418     verifyDebugLogs("Resolving first analysis as new code period as there is only one existing version");
419   }
420
421   @Test
422   public void load_previous_version_with_first_analysis_when_previous_snapshot_is_the_last_one() {
423     SnapshotDto analysis = dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1226379600000L).setProjectVersion("0.9").setLast(true)); // 2008-11-11
424     dbTester.events().insertEvent(newEvent(analysis).setName("0.9").setCategory(CATEGORY_VERSION));
425     setupRoot(project, "1.1");
426
427     dbTester.newCodePeriods().insert(NewCodePeriodType.PREVIOUS_VERSION, null);
428
429     underTest.execute(new TestComputationStepContext());
430
431     assertPeriod(NewCodePeriodType.PREVIOUS_VERSION, "0.9", analysis.getCreatedAt());
432     verifyDebugLogs("Resolving new code period by previous version: 0.9");
433   }
434
435   @Test
436   @UseDataProvider("anyValidLeakPeriodSettingValue")
437   public void leak_period_setting_is_ignored_for_PR(NewCodePeriodType type, @Nullable String value) {
438     when(analysisMetadataHolder.isBranch()).thenReturn(false);
439
440     dbTester.newCodePeriods().insert(type, value);
441
442     underTest.execute(new TestComputationStepContext());
443
444     assertThat(periodsHolder.hasPeriod()).isFalse();
445   }
446
447   private void verifyFailWithInvalidValueMessageException(String propertyValue, String debugLog, String... otherDebugLogs) {
448     try {
449       underTest.execute(new TestComputationStepContext());
450       fail("a Message Exception should have been thrown");
451     } catch (MessageException e) {
452       verifyInvalidValueMessage(e, propertyValue);
453       verifyDebugLogs(debugLog, otherDebugLogs);
454     }
455   }
456
457   @DataProvider
458   public static Object[][] zeroOrLess() {
459     return new Object[][] {
460       {0},
461       {-1 - new Random().nextInt(30)}
462     };
463   }
464
465   @DataProvider
466   public static Object[][] stringConsideredAsVersions() {
467     return new Object[][] {
468       {randomAlphabetic(5)},
469       {"1,3"},
470       {"1.3"},
471       {"0 1"},
472       {"1-SNAPSHOT"},
473       {"01-12-2018"}, // unsupported date format
474     };
475   }
476
477   @DataProvider
478   public static Object[][] projectVersionNullOrNot() {
479     return new Object[][] {
480       {null},
481       {randomAlphabetic(15)},
482     };
483   }
484
485   @DataProvider
486   public static Object[][] anyValidLeakPeriodSettingValue() {
487     return new Object[][] {
488       // days
489       {NewCodePeriodType.NUMBER_OF_DAYS, "100"},
490       // previous_version
491       {NewCodePeriodType.PREVIOUS_VERSION, null}
492     };
493   }
494
495   private List<SnapshotDto> createSnapshots(ComponentDto project) {
496     ArrayList<SnapshotDto> list = new ArrayList<>();
497     list.add(dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1226379600000L).setLast(false))); // 2008-11-11
498     list.add(dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1226494680000L).setLast(false))); // 2008-11-12
499     list.add(dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1227157200000L).setLast(false))); // 2008-11-20
500     list.add(dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1227358680000L).setLast(false))); // 2008-11-22
501     list.add(dbTester.components().insertSnapshot(project, snapshot -> snapshot.setCreatedAt(1227934800000L).setLast(true))); // 2008-11-29
502     return list;
503   }
504
505   private long milisSinceEpoch(int year, int month, int day, int hour) {
506     return ZonedDateTime.of(year, month, day, hour, 0, 0, 0, ZoneId.systemDefault())
507       .toInstant().toEpochMilli();
508   }
509
510   private void setProjectPeriod(String projectUuid, NewCodePeriodType type, @Nullable String value) {
511     dbTester.newCodePeriods().insert(projectUuid, type, value);
512   }
513
514   private void setBranchPeriod(String projectUuid, String branchUuid, NewCodePeriodType type, @Nullable String value) {
515     dbTester.newCodePeriods().insert(projectUuid, branchUuid, type, value);
516   }
517
518   private void setGlobalPeriod(NewCodePeriodType type, @Nullable String value) {
519     dbTester.newCodePeriods().insert(type, value);
520   }
521
522   private void assertPeriod(NewCodePeriodType type, @Nullable String value, @Nullable Long date) {
523     Period period = periodsHolder.getPeriod();
524     assertThat(period).isNotNull();
525     assertThat(period.getMode()).isEqualTo(type.name());
526     assertThat(period.getModeParameter()).isEqualTo(value);
527     assertThat(period.getDate()).isEqualTo(date);
528   }
529
530   private void verifyDebugLogs(String log, String... otherLogs) {
531     assertThat(logTester.logs(Level.DEBUG))
532       .contains(Stream.concat(Stream.of(log), Arrays.stream(otherLogs)).toArray(String[]::new));
533   }
534
535   private void setupRoot(ComponentDto branchComponent) {
536     setupRoot(branchComponent, "any-string");
537   }
538
539   private void setupRoot(ComponentDto branchComponent, String projectUuid, String version) {
540     treeRootHolder.setRoot(ReportComponent
541       .builder(Component.Type.PROJECT, 1)
542       .setUuid(branchComponent.uuid())
543       .setKey(branchComponent.getKey())
544       .setProjectVersion(version)
545       .build());
546
547     Project project = mock(Project.class);
548     when(project.getUuid()).thenReturn(projectUuid);
549     when(analysisMetadataHolder.getProject()).thenReturn(project);
550   }
551
552   private void setupRoot(ComponentDto branchComponent, String version) {
553     setupRoot(branchComponent, project.uuid(), version);
554   }
555
556   private static void verifyInvalidValueMessage(MessageException e, String propertyValue) {
557     assertThat(e).hasMessage("Invalid new code period. '" + propertyValue
558       + "' is not one of: integer > 0, date before current analysis j, \"previous_version\", or version string that exists in the project' \n" +
559       "Please contact a project administrator to correct this setting");
560   }
561
562 }