]> source.dussan.org Git - sonarqube.git/blob
1b84b4591a9a698e2219257e56ff812a5389858e
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2016 SonarSource SA
4  * mailto:contact 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.server.computation.step;
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import org.junit.Before;
29 import org.junit.Rule;
30 import org.junit.Test;
31 import org.junit.rules.ExpectedException;
32 import org.mockito.ArgumentCaptor;
33 import org.sonar.api.utils.System2;
34 import org.sonar.db.DbClient;
35 import org.sonar.db.DbSession;
36 import org.sonar.db.DbTester;
37 import org.sonar.db.component.ComponentDto;
38 import org.sonar.db.component.ComponentTesting;
39 import org.sonar.db.component.SnapshotDto;
40 import org.sonar.db.component.SnapshotTesting;
41 import org.sonar.db.duplication.DuplicationUnitDto;
42 import org.sonar.duplications.block.Block;
43 import org.sonar.duplications.block.ByteArray;
44 import org.sonar.scanner.protocol.output.ScannerReport;
45 import org.sonar.server.computation.analysis.AnalysisMetadataHolderRule;
46 import org.sonar.server.computation.batch.BatchReportReaderRule;
47 import org.sonar.server.computation.batch.TreeRootHolderRule;
48 import org.sonar.server.computation.component.Component;
49 import org.sonar.server.computation.component.FileAttributes;
50 import org.sonar.server.computation.component.ReportComponent;
51 import org.sonar.server.computation.duplication.CrossProjectDuplicationStatusHolder;
52 import org.sonar.server.computation.duplication.IntegrateCrossProjectDuplications;
53 import org.sonar.server.computation.snapshot.Snapshot;
54
55 import static java.util.Arrays.asList;
56 import static org.assertj.core.api.Assertions.assertThat;
57 import static org.mockito.Mockito.eq;
58 import static org.mockito.Mockito.mock;
59 import static org.mockito.Mockito.verify;
60 import static org.mockito.Mockito.verifyZeroInteractions;
61 import static org.mockito.Mockito.when;
62 import static org.sonar.server.computation.component.Component.Type.FILE;
63 import static org.sonar.server.computation.component.Component.Type.PROJECT;
64
65 public class LoadCrossProjectDuplicationsRepositoryStepTest {
66
67   @Rule
68   public ExpectedException thrown = ExpectedException.none();
69
70   static final String XOO_LANGUAGE = "xoo";
71
72   static final int PROJECT_REF = 1;
73   static final int FILE_REF = 2;
74   static final String CURRENT_FILE_KEY = "FILE_KEY";
75
76   static final Component CURRENT_FILE = ReportComponent.builder(FILE, FILE_REF)
77     .setKey(CURRENT_FILE_KEY)
78     .setFileAttributes(new FileAttributes(false, XOO_LANGUAGE))
79     .build();
80
81   @Rule
82   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(
83     ReportComponent.builder(PROJECT, PROJECT_REF)
84       .addChildren(CURRENT_FILE).build());
85
86   @Rule
87   public BatchReportReaderRule batchReportReader = new BatchReportReaderRule();
88
89   @Rule
90   public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
91
92   CrossProjectDuplicationStatusHolder crossProjectDuplicationStatusHolder = mock(CrossProjectDuplicationStatusHolder.class);
93
94   @Rule
95   public DbTester dbTester = DbTester.create(System2.INSTANCE);
96
97   DbClient dbClient = dbTester.getDbClient();
98
99   DbSession dbSession = dbTester.getSession();
100
101   IntegrateCrossProjectDuplications integrateCrossProjectDuplications = mock(IntegrateCrossProjectDuplications.class);
102
103   Snapshot baseProjectSnapshot;
104
105   ComputationStep underTest = new LoadCrossProjectDuplicationsRepositoryStep(treeRootHolder, batchReportReader, analysisMetadataHolder, crossProjectDuplicationStatusHolder,
106     integrateCrossProjectDuplications, dbClient);
107
108   @Before
109   public void setUp() throws Exception {
110     ComponentDto project = ComponentTesting.newProjectDto();
111     dbClient.componentDao().insert(dbSession, project);
112     SnapshotDto projectSnapshot = SnapshotTesting.newSnapshotForProject(project);
113     dbClient.snapshotDao().insert(dbSession, projectSnapshot);
114     dbSession.commit();
115
116     baseProjectSnapshot = new Snapshot.Builder()
117       .setId(projectSnapshot.getId())
118       .setCreatedAt(projectSnapshot.getCreatedAt())
119       .build();
120   }
121
122   @Test
123   public void call_compute_cpd_on_one_duplication() throws Exception {
124     when(crossProjectDuplicationStatusHolder.isEnabled()).thenReturn(true);
125     analysisMetadataHolder.setBaseProjectSnapshot(baseProjectSnapshot);
126
127     ComponentDto otherProject = createProject("OTHER_PROJECT_KEY");
128     SnapshotDto otherProjectSnapshot = createProjectSnapshot(otherProject);
129
130     ComponentDto otherFIle = createFile("OTHER_FILE_KEY", otherProject);
131     SnapshotDto otherFileSnapshot = createFileSnapshot(otherFIle, otherProjectSnapshot);
132
133     String hash = "a8998353e96320ec";
134     DuplicationUnitDto duplicate = new DuplicationUnitDto()
135       .setHash(hash)
136       .setStartLine(40)
137       .setEndLine(55)
138       .setIndexInFile(0)
139       .setProjectSnapshotId(otherProjectSnapshot.getId())
140       .setSnapshotId(otherFileSnapshot.getId())
141       .setComponentUuid(otherFileSnapshot.getComponentUuid());
142     dbClient.duplicationDao().insert(dbSession, duplicate);
143     dbSession.commit();
144
145     ScannerReport.CpdTextBlock originBlock = ScannerReport.CpdTextBlock.newBuilder()
146       .setHash(hash)
147       .setStartLine(30)
148       .setEndLine(45)
149       .setStartTokenIndex(0)
150       .setEndTokenIndex(10)
151       .build();
152     batchReportReader.putDuplicationBlocks(FILE_REF, asList(originBlock));
153
154     underTest.execute();
155
156     verify(integrateCrossProjectDuplications).computeCpd(CURRENT_FILE,
157       Arrays.asList(
158         new Block.Builder()
159           .setResourceId(CURRENT_FILE_KEY)
160           .setBlockHash(new ByteArray(hash))
161           .setIndexInFile(0)
162           .setLines(originBlock.getStartLine(), originBlock.getEndLine())
163           .setUnit(originBlock.getStartTokenIndex(), originBlock.getEndTokenIndex())
164           .build()),
165       Arrays.asList(
166         new Block.Builder()
167           .setResourceId(otherFIle.getKey())
168           .setBlockHash(new ByteArray(hash))
169           .setIndexInFile(duplicate.getIndexInFile())
170           .setLines(duplicate.getStartLine(), duplicate.getEndLine())
171           .build()));
172   }
173
174   @Test
175   public void call_compute_cpd_on_many_duplication() throws Exception {
176     when(crossProjectDuplicationStatusHolder.isEnabled()).thenReturn(true);
177     analysisMetadataHolder.setBaseProjectSnapshot(baseProjectSnapshot);
178
179     ComponentDto otherProject = createProject("OTHER_PROJECT_KEY");
180     SnapshotDto otherProjectSnapshot = createProjectSnapshot(otherProject);
181
182     ComponentDto otherFIle = createFile("OTHER_FILE_KEY", otherProject);
183     SnapshotDto otherFileSnapshot = createFileSnapshot(otherFIle, otherProjectSnapshot);
184
185     ScannerReport.CpdTextBlock originBlock1 = ScannerReport.CpdTextBlock.newBuilder()
186       .setHash("a8998353e96320ec")
187       .setStartLine(30)
188       .setEndLine(45)
189       .setStartTokenIndex(0)
190       .setEndTokenIndex(10)
191       .build();
192     ScannerReport.CpdTextBlock originBlock2 = ScannerReport.CpdTextBlock.newBuilder()
193       .setHash("b1234353e96320ff")
194       .setStartLine(10)
195       .setEndLine(25)
196       .setStartTokenIndex(5)
197       .setEndTokenIndex(15)
198       .build();
199     batchReportReader.putDuplicationBlocks(FILE_REF, asList(originBlock1, originBlock2));
200
201     DuplicationUnitDto duplicate1 = new DuplicationUnitDto()
202       .setHash(originBlock1.getHash())
203       .setStartLine(40)
204       .setEndLine(55)
205       .setIndexInFile(0)
206       .setProjectSnapshotId(otherProjectSnapshot.getId())
207       .setSnapshotId(otherFileSnapshot.getId())
208       .setComponentUuid(otherFileSnapshot.getComponentUuid());
209
210     DuplicationUnitDto duplicate2 = new DuplicationUnitDto()
211       .setHash(originBlock2.getHash())
212       .setStartLine(20)
213       .setEndLine(35)
214       .setIndexInFile(1)
215       .setProjectSnapshotId(otherProjectSnapshot.getId())
216       .setSnapshotId(otherFileSnapshot.getId())
217       .setComponentUuid(otherFileSnapshot.getComponentUuid());
218     dbClient.duplicationDao().insert(dbSession, duplicate1);
219     dbClient.duplicationDao().insert(dbSession, duplicate2);
220     dbSession.commit();
221
222     underTest.execute();
223
224     Class<ArrayList<Block>> listClass = (Class<ArrayList<Block>>) (Class) ArrayList.class;
225     ArgumentCaptor<ArrayList<Block>> originBlocks = ArgumentCaptor.forClass(listClass);
226     ArgumentCaptor<ArrayList<Block>> duplicationBlocks = ArgumentCaptor.forClass(listClass);
227
228     verify(integrateCrossProjectDuplications).computeCpd(eq(CURRENT_FILE), originBlocks.capture(), duplicationBlocks.capture());
229
230     Map<Integer, Block> originBlocksByIndex = blocksByIndexInFile(originBlocks.getValue());
231     assertThat(originBlocksByIndex.get(0)).isEqualTo(
232       new Block.Builder()
233         .setResourceId(CURRENT_FILE_KEY)
234         .setBlockHash(new ByteArray(originBlock1.getHash()))
235         .setIndexInFile(0)
236         .setLines(originBlock1.getStartLine(), originBlock1.getEndLine())
237         .setUnit(originBlock1.getStartTokenIndex(), originBlock1.getEndTokenIndex())
238         .build());
239     assertThat(originBlocksByIndex.get(1)).isEqualTo(
240       new Block.Builder()
241         .setResourceId(CURRENT_FILE_KEY)
242         .setBlockHash(new ByteArray(originBlock2.getHash()))
243         .setIndexInFile(1)
244         .setLines(originBlock2.getStartLine(), originBlock2.getEndLine())
245         .setUnit(originBlock2.getStartTokenIndex(), originBlock2.getEndTokenIndex())
246         .build());
247
248     Map<Integer, Block> duplicationBlocksByIndex = blocksByIndexInFile(duplicationBlocks.getValue());
249     assertThat(duplicationBlocksByIndex.get(0)).isEqualTo(
250       new Block.Builder()
251         .setResourceId(otherFIle.getKey())
252         .setBlockHash(new ByteArray(originBlock1.getHash()))
253         .setIndexInFile(duplicate1.getIndexInFile())
254         .setLines(duplicate1.getStartLine(), duplicate1.getEndLine())
255         .build());
256     assertThat(duplicationBlocksByIndex.get(1)).isEqualTo(
257       new Block.Builder()
258         .setResourceId(otherFIle.getKey())
259         .setBlockHash(new ByteArray(originBlock2.getHash()))
260         .setIndexInFile(duplicate2.getIndexInFile())
261         .setLines(duplicate2.getStartLine(), duplicate2.getEndLine())
262         .build());
263   }
264
265   @Test
266   public void nothing_to_do_when_cross_project_duplication_is_disabled() throws Exception {
267     when(crossProjectDuplicationStatusHolder.isEnabled()).thenReturn(false);
268     analysisMetadataHolder.setBaseProjectSnapshot(baseProjectSnapshot);
269
270     ComponentDto otherProject = createProject("OTHER_PROJECT_KEY");
271     SnapshotDto otherProjectSnapshot = createProjectSnapshot(otherProject);
272
273     ComponentDto otherFIle = createFile("OTHER_FILE_KEY", otherProject);
274     SnapshotDto otherFileSnapshot = createFileSnapshot(otherFIle, otherProjectSnapshot);
275
276     String hash = "a8998353e96320ec";
277     DuplicationUnitDto duplicate = new DuplicationUnitDto()
278       .setHash(hash)
279       .setStartLine(40)
280       .setEndLine(55)
281       .setIndexInFile(0)
282       .setProjectSnapshotId(otherProjectSnapshot.getId())
283       .setSnapshotId(otherFileSnapshot.getId())
284       .setComponentUuid(otherFileSnapshot.getComponentUuid());
285     dbClient.duplicationDao().insert(dbSession, duplicate);
286     dbSession.commit();
287
288     ScannerReport.CpdTextBlock originBlock = ScannerReport.CpdTextBlock.newBuilder()
289       .setHash(hash)
290       .setStartLine(30)
291       .setEndLine(45)
292       .setStartTokenIndex(0)
293       .setEndTokenIndex(10)
294       .build();
295     batchReportReader.putDuplicationBlocks(FILE_REF, asList(originBlock));
296
297     underTest.execute();
298
299     verifyZeroInteractions(integrateCrossProjectDuplications);
300   }
301
302   @Test
303   public void nothing_to_do_when_no_cpd_text_blocks_found() throws Exception {
304     when(crossProjectDuplicationStatusHolder.isEnabled()).thenReturn(true);
305     analysisMetadataHolder.setBaseProjectSnapshot(baseProjectSnapshot);
306
307     batchReportReader.putDuplicationBlocks(FILE_REF, Collections.<ScannerReport.CpdTextBlock>emptyList());
308
309     underTest.execute();
310
311     verifyZeroInteractions(integrateCrossProjectDuplications);
312   }
313
314   @Test
315   public void nothing_to_do_when_cpd_text_blocks_exists_but_no_duplicated_found() throws Exception {
316     when(crossProjectDuplicationStatusHolder.isEnabled()).thenReturn(true);
317     analysisMetadataHolder.setBaseProjectSnapshot(baseProjectSnapshot);
318
319     ScannerReport.CpdTextBlock originBlock = ScannerReport.CpdTextBlock.newBuilder()
320       .setHash("a8998353e96320ec")
321       .setStartLine(30)
322       .setEndLine(45)
323       .setStartTokenIndex(0)
324       .setEndTokenIndex(10)
325       .build();
326     batchReportReader.putDuplicationBlocks(FILE_REF, asList(originBlock));
327
328     underTest.execute();
329
330     verifyZeroInteractions(integrateCrossProjectDuplications);
331   }
332
333   private ComponentDto createProject(String projectKey) {
334     ComponentDto project = ComponentTesting.newProjectDto().setKey(projectKey);
335     dbClient.componentDao().insert(dbSession, project);
336     dbSession.commit();
337     return project;
338   }
339
340   private SnapshotDto createProjectSnapshot(ComponentDto project) {
341     SnapshotDto projectSnapshot = SnapshotTesting.newSnapshotForProject(project);
342     dbClient.snapshotDao().insert(dbSession, projectSnapshot);
343     dbSession.commit();
344     return projectSnapshot;
345   }
346
347   private ComponentDto createFile(String fileKey, ComponentDto project) {
348     ComponentDto file = ComponentTesting.newFileDto(project)
349       .setKey(fileKey)
350       .setLanguage(XOO_LANGUAGE);
351     dbClient.componentDao().insert(dbSession, file);
352     dbSession.commit();
353     return file;
354   }
355
356   private SnapshotDto createFileSnapshot(ComponentDto file, SnapshotDto projectSnapshot) {
357     SnapshotDto fileSnapshot = SnapshotTesting.createForComponent(file, projectSnapshot);
358     dbClient.snapshotDao().insert(dbSession, fileSnapshot);
359     dbSession.commit();
360     return fileSnapshot;
361   }
362
363   private static Map<Integer, Block> blocksByIndexInFile(List<Block> blocks) {
364     Map<Integer, Block> blocksByIndexInFile = new HashMap<>();
365     for (Block block : blocks) {
366       blocksByIndexInFile.put(block.getIndexInFile(), block);
367     }
368     return blocksByIndexInFile;
369   }
370
371 }