3 * Copyright (C) 2009-2021 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.ce.task.projectanalysis.step;
22 import java.text.SimpleDateFormat;
23 import java.util.Date;
24 import java.util.Random;
25 import java.util.stream.Stream;
26 import javax.annotation.Nullable;
27 import org.junit.Before;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.sonar.api.resources.Qualifiers;
31 import org.sonar.api.resources.Scopes;
32 import org.sonar.api.utils.System2;
33 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
34 import org.sonar.ce.task.projectanalysis.component.BranchPersister;
35 import org.sonar.ce.task.projectanalysis.component.Component;
36 import org.sonar.ce.task.projectanalysis.component.DefaultBranchImpl;
37 import org.sonar.ce.task.projectanalysis.component.MutableDisabledComponentsHolder;
38 import org.sonar.ce.task.projectanalysis.component.ProjectPersister;
39 import org.sonar.ce.task.projectanalysis.component.ProjectViewAttributes;
40 import org.sonar.ce.task.projectanalysis.component.SubViewAttributes;
41 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
42 import org.sonar.ce.task.projectanalysis.component.ViewAttributes;
43 import org.sonar.ce.task.projectanalysis.component.ViewsComponent;
44 import org.sonar.ce.task.step.ComputationStep;
45 import org.sonar.ce.task.step.TestComputationStepContext;
46 import org.sonar.db.DbClient;
47 import org.sonar.db.DbTester;
48 import org.sonar.db.component.ComponentDbTester;
49 import org.sonar.db.component.ComponentDto;
50 import org.sonar.db.component.ComponentTesting;
52 import static org.assertj.core.api.Assertions.assertThat;
53 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
54 import static org.mockito.Mockito.mock;
55 import static org.mockito.Mockito.when;
56 import static org.sonar.ce.task.projectanalysis.component.ViewAttributes.Type.APPLICATION;
57 import static org.sonar.ce.task.projectanalysis.component.ViewAttributes.Type.PORTFOLIO;
58 import static org.sonar.ce.task.projectanalysis.component.ViewsComponent.builder;
59 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
60 import static org.sonar.db.component.ComponentTesting.newProjectCopy;
61 import static org.sonar.db.component.ComponentTesting.newSubPortfolio;
63 public class ViewsPersistComponentsStepTest extends BaseStepTest {
65 private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
67 private static final String VIEW_KEY = "VIEW_KEY";
68 private static final String VIEW_NAME = "VIEW_NAME";
69 private static final String VIEW_DESCRIPTION = "view description";
70 private static final String VIEW_UUID = "VIEW_UUID";
71 private static final String SUBVIEW_1_KEY = "SUBVIEW_1_KEY";
72 private static final String SUBVIEW_1_NAME = "SUBVIEW_1_NAME";
73 private static final String SUBVIEW_1_DESCRIPTION = "subview 1 description";
74 private static final String SUBVIEW_1_UUID = "SUBVIEW_1_UUID";
75 private static final String PROJECT_VIEW_1_KEY = "PV1_KEY";
76 private static final String PROJECT_VIEW_1_NAME = "PV1_NAME";
77 private static final String PROJECT_VIEW_1_UUID = "PV1_UUID";
80 public DbTester dbTester = DbTester.create(System2.INSTANCE);
83 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
85 public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
87 private final System2 system2 = mock(System2.class);
88 private final DbClient dbClient = dbTester.getDbClient();
90 private final ComponentDbTester componentDbTester = new ComponentDbTester(dbTester);
91 private final MutableDisabledComponentsHolder disabledComponentsHolder = mock(MutableDisabledComponentsHolder.class, RETURNS_DEEP_STUBS);
92 private PersistComponentsStep underTest;
95 public void setup() throws Exception {
96 now = DATE_FORMAT.parse("2015-06-02");
97 when(system2.now()).thenReturn(now.getTime());
99 analysisMetadataHolder.setBranch(new DefaultBranchImpl());
100 BranchPersister branchPersister = mock(BranchPersister.class);
101 ProjectPersister projectPersister = mock(ProjectPersister.class);
102 underTest = new PersistComponentsStep(dbClient, treeRootHolder, system2, disabledComponentsHolder, analysisMetadataHolder, branchPersister, projectPersister);
106 protected ComputationStep step() {
111 public void persist_empty_view() {
112 treeRootHolder.setRoot(createViewBuilder(PORTFOLIO).build());
114 underTest.execute(new TestComputationStepContext());
116 assertRowsCountInTableProjects(1);
118 ComponentDto projectDto = getComponentFromDb(VIEW_KEY);
119 assertDtoIsView(projectDto);
123 public void persist_existing_empty_view() {
124 // most of the time view already exists since its supposed to be created when config is uploaded
125 persistComponents(newViewDto());
127 treeRootHolder.setRoot(createViewBuilder(PORTFOLIO).build());
129 underTest.execute(new TestComputationStepContext());
131 assertRowsCountInTableProjects(1);
133 assertDtoNotUpdated(VIEW_KEY);
137 public void persist_view_with_projectView() {
138 ComponentDto project = ComponentTesting.newPrivateProjectDto();
139 persistComponents(project);
141 treeRootHolder.setRoot(
142 createViewBuilder(PORTFOLIO)
143 .addChildren(createProjectView1Builder(project, null).build())
146 underTest.execute(new TestComputationStepContext());
148 assertRowsCountInTableProjects(3);
150 ComponentDto viewDto = getComponentFromDb(VIEW_KEY);
151 assertDtoIsView(viewDto);
153 ComponentDto pv1Dto = getComponentFromDb(PROJECT_VIEW_1_KEY);
154 assertDtoIsProjectView1(pv1Dto, viewDto, viewDto, project);
158 public void persist_application_with_projectView() {
159 ComponentDto project = ComponentTesting.newPrivateProjectDto();
160 persistComponents(project);
162 treeRootHolder.setRoot(
163 createViewBuilder(APPLICATION)
164 .addChildren(createProjectView1Builder(project, null).build())
167 underTest.execute(new TestComputationStepContext());
169 assertRowsCountInTableProjects(3);
171 ComponentDto applicationDto = getComponentFromDb(VIEW_KEY);
172 assertDtoIsApplication(applicationDto);
174 ComponentDto pv1Dto = getComponentFromDb(PROJECT_VIEW_1_KEY);
175 assertDtoIsProjectView1(pv1Dto, applicationDto, applicationDto, project);
179 public void persist_empty_subview() {
180 treeRootHolder.setRoot(
181 createViewBuilder(PORTFOLIO)
183 createSubView1Builder(null).build())
186 underTest.execute(new TestComputationStepContext());
188 assertRowsCountInTableProjects(2);
190 ComponentDto viewDto = getComponentFromDb(VIEW_KEY);
191 assertDtoIsView(viewDto);
193 ComponentDto sv1Dto = getComponentFromDb(SUBVIEW_1_KEY);
194 assertDtoIsSubView1(viewDto, sv1Dto);
198 public void persist_empty_subview_having_original_view_uuid() {
199 treeRootHolder.setRoot(
200 createViewBuilder(PORTFOLIO)
202 createSubView1Builder("ORIGINAL_UUID").build())
205 underTest.execute(new TestComputationStepContext());
207 assertRowsCountInTableProjects(2);
209 ComponentDto subView = getComponentFromDb(SUBVIEW_1_KEY);
210 assertThat(subView.getCopyResourceUuid()).isEqualTo("ORIGINAL_UUID");
214 public void persist_existing_empty_subview_under_existing_view() {
215 ComponentDto viewDto = newViewDto();
216 persistComponents(viewDto);
217 persistComponents(ComponentTesting.newSubPortfolio(viewDto, SUBVIEW_1_UUID, SUBVIEW_1_KEY).setName(SUBVIEW_1_NAME));
219 treeRootHolder.setRoot(
220 createViewBuilder(PORTFOLIO)
222 createSubView1Builder(null).build())
225 underTest.execute(new TestComputationStepContext());
227 assertRowsCountInTableProjects(2);
229 assertDtoNotUpdated(VIEW_KEY);
230 assertDtoNotUpdated(SUBVIEW_1_KEY);
234 public void persist_empty_subview_under_existing_view() {
235 persistComponents(newViewDto());
237 treeRootHolder.setRoot(
238 createViewBuilder(PORTFOLIO)
240 createSubView1Builder(null).build())
243 underTest.execute(new TestComputationStepContext());
245 assertRowsCountInTableProjects(2);
247 assertDtoNotUpdated(VIEW_KEY);
248 assertDtoIsSubView1(getComponentFromDb(VIEW_KEY), getComponentFromDb(SUBVIEW_1_KEY));
252 public void persist_project_view_under_subview() {
253 ComponentDto project = ComponentTesting.newPrivateProjectDto();
254 persistComponents(project);
256 treeRootHolder.setRoot(
257 createViewBuilder(PORTFOLIO)
259 createSubView1Builder(null)
261 createProjectView1Builder(project, null).build())
265 underTest.execute(new TestComputationStepContext());
267 assertRowsCountInTableProjects(4);
269 ComponentDto viewDto = getComponentFromDb(VIEW_KEY);
270 assertDtoIsView(viewDto);
271 ComponentDto subView1Dto = getComponentFromDb(SUBVIEW_1_KEY);
272 assertDtoIsSubView1(viewDto, subView1Dto);
273 ComponentDto pv1Dto = getComponentFromDb(PROJECT_VIEW_1_KEY);
274 assertDtoIsProjectView1(pv1Dto, viewDto, subView1Dto, project);
278 public void update_view_name_and_longName() {
279 ComponentDto viewDto = newViewDto().setLongName("another long name").setCreatedAt(now);
280 persistComponents(viewDto);
282 treeRootHolder.setRoot(createViewBuilder(PORTFOLIO).build());
284 underTest.execute(new TestComputationStepContext());
286 // commit functional transaction -> copies B-fields to A-fields
287 dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), viewDto.uuid());
290 assertRowsCountInTableProjects(1);
291 ComponentDto newViewDto = getComponentFromDb(VIEW_KEY);
292 assertDtoIsView(newViewDto);
296 public void update_project_view() {
297 ComponentDto view = newViewDto();
298 ComponentDto project = ComponentTesting.newPrivateProjectDto();
299 persistComponents(view, project);
300 ComponentDto projectView = ComponentTesting.newProjectCopy(PROJECT_VIEW_1_UUID, project, view)
301 .setDbKey(PROJECT_VIEW_1_KEY)
304 persistComponents(projectView);
306 treeRootHolder.setRoot(
307 createViewBuilder(PORTFOLIO)
308 .addChildren(createProjectView1Builder(project, null).build())
311 underTest.execute(new TestComputationStepContext());
313 // commit functional transaction -> copies B-fields to A-fields
314 dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), view.uuid());
317 assertRowsCountInTableProjects(3);
318 ComponentDto pv1Dto = getComponentFromDb(PROJECT_VIEW_1_KEY);
319 assertDtoIsProjectView1(pv1Dto, view, view, project);
323 public void update_copy_component_uuid_of_project_view() {
324 ComponentDto view = newViewDto();
325 ComponentDto project1 = newPrivateProjectDto("P1");
326 ComponentDto project2 = newPrivateProjectDto("P2");
327 persistComponents(view, project1, project2);
329 // Project view in DB is associated to project1
330 ComponentDto projectView = ComponentTesting.newProjectCopy(PROJECT_VIEW_1_UUID, project1, view)
331 .setDbKey(PROJECT_VIEW_1_KEY)
333 persistComponents(projectView);
335 treeRootHolder.setRoot(
336 createViewBuilder(PORTFOLIO)
337 // Project view in the View is linked to the first project2
338 .addChildren(createProjectView1Builder(project2, null).build())
341 underTest.execute(new TestComputationStepContext());
343 // commit functional transaction -> copies B-fields to A-fields
344 dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), view.uuid());
347 ComponentDto pv1Dto = getComponentFromDb(PROJECT_VIEW_1_KEY);
348 // Project view should now be linked to project2
349 assertDtoIsProjectView1(pv1Dto, view, view, project2);
353 public void update_copy_component_uuid_of_sub_view() {
354 ComponentDto view = newViewDto();
355 ComponentDto subView = newSubViewDto(view).setCopyComponentUuid("OLD_COPY");
356 persistComponents(view, subView);
358 treeRootHolder.setRoot(
359 createViewBuilder(PORTFOLIO)
361 createSubView1Builder("NEW_COPY").build())
364 underTest.execute(new TestComputationStepContext());
366 // commit functional transaction -> copies B-fields to A-fields
367 dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), view.uuid());
370 ComponentDto subViewReloaded = getComponentFromDb(SUBVIEW_1_KEY);
371 assertThat(subViewReloaded.getCopyResourceUuid()).isEqualTo("NEW_COPY");
375 public void persists_new_components_as_public_if_root_does_not_exist_yet_out_of_functional_transaction() {
376 ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto());
377 treeRootHolder.setRoot(
378 createViewBuilder(PORTFOLIO)
380 createSubView1Builder(null)
382 createProjectView1Builder(project, null).build())
386 underTest.execute(new TestComputationStepContext());
388 Stream.of(VIEW_UUID, SUBVIEW_1_UUID, PROJECT_VIEW_1_UUID)
389 .forEach(uuid -> assertThat(dbClient.componentDao().selectByUuid(dbTester.getSession(), uuid).get().isPrivate()).isFalse());
393 public void persists_new_components_with_visibility_of_root_in_db_out_of_functional_transaction() {
394 boolean isRootPrivate = new Random().nextBoolean();
395 ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto());
396 ComponentDto view = newViewDto().setUuid(VIEW_UUID).setDbKey(VIEW_KEY).setName("View").setPrivate(isRootPrivate);
397 dbTester.components().insertComponent(view);
398 treeRootHolder.setRoot(
399 createViewBuilder(PORTFOLIO)
401 createSubView1Builder(null)
403 createProjectView1Builder(project, null).build())
407 underTest.execute(new TestComputationStepContext());
409 Stream.of(VIEW_UUID, SUBVIEW_1_UUID, PROJECT_VIEW_1_UUID)
410 .forEach(uuid -> assertThat(dbClient.componentDao().selectByUuid(dbTester.getSession(), uuid).get().isPrivate())
411 .describedAs("for uuid " + uuid)
412 .isEqualTo(isRootPrivate));
416 public void persists_existing_components_with_visibility_of_root_in_db_out_of_functional_transaction() {
417 boolean isRootPrivate = new Random().nextBoolean();
418 ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto());
419 ComponentDto view = newViewDto().setUuid(VIEW_UUID).setDbKey(VIEW_KEY).setName("View").setPrivate(isRootPrivate);
420 dbTester.components().insertComponent(view);
421 ComponentDto subView = newSubPortfolio(view).setUuid("BCDE").setDbKey("MODULE").setPrivate(!isRootPrivate);
422 dbTester.components().insertComponent(subView);
423 dbTester.components().insertComponent(newProjectCopy("DEFG", project, view).setDbKey("DIR").setPrivate(isRootPrivate));
424 treeRootHolder.setRoot(
425 createViewBuilder(PORTFOLIO)
427 createSubView1Builder(null)
429 createProjectView1Builder(project, null).build())
433 underTest.execute(new TestComputationStepContext());
435 Stream.of(VIEW_UUID, SUBVIEW_1_UUID, PROJECT_VIEW_1_UUID, subView.uuid(), "DEFG")
436 .forEach(uuid -> assertThat(dbClient.componentDao().selectByUuid(dbTester.getSession(), uuid).get().isPrivate())
437 .describedAs("for uuid " + uuid)
438 .isEqualTo(isRootPrivate));
441 private static ViewsComponent.Builder createViewBuilder(ViewAttributes.Type viewType) {
442 return builder(Component.Type.VIEW, VIEW_KEY)
445 .setDescription(VIEW_DESCRIPTION)
446 .setViewAttributes(new ViewAttributes(viewType));
449 private ViewsComponent.Builder createSubView1Builder(@Nullable String originalViewUuid) {
450 return builder(Component.Type.SUBVIEW, SUBVIEW_1_KEY)
451 .setUuid(SUBVIEW_1_UUID)
452 .setName(SUBVIEW_1_NAME)
453 .setDescription(SUBVIEW_1_DESCRIPTION)
454 .setSubViewAttributes(new SubViewAttributes(originalViewUuid));
457 private static ViewsComponent.Builder createProjectView1Builder(ComponentDto project, Long analysisDate) {
458 return builder(Component.Type.PROJECT_VIEW, PROJECT_VIEW_1_KEY)
459 .setUuid(PROJECT_VIEW_1_UUID)
460 .setName(PROJECT_VIEW_1_NAME)
461 .setDescription("project view description is not persisted")
462 .setProjectViewAttributes(new ProjectViewAttributes(project.uuid(), project.getDbKey(), analysisDate, project.getBranch()));
465 private void persistComponents(ComponentDto... componentDtos) {
466 componentDbTester.insertComponents(componentDtos);
469 private ComponentDto getComponentFromDb(String componentKey) {
470 return dbClient.componentDao().selectByKey(dbTester.getSession(), componentKey).get();
473 private void assertRowsCountInTableProjects(int rowCount) {
474 assertThat(dbTester.countRowsOfTable("components")).isEqualTo(rowCount);
477 private void assertDtoNotUpdated(String componentKey) {
478 assertThat(getComponentFromDb(componentKey).getCreatedAt()).isNotEqualTo(now);
481 private ComponentDto newViewDto() {
482 return ComponentTesting.newPortfolio(VIEW_UUID)
487 private ComponentDto newSubViewDto(ComponentDto rootView) {
488 return ComponentTesting.newSubPortfolio(rootView, SUBVIEW_1_UUID, SUBVIEW_1_KEY)
489 .setName(SUBVIEW_1_NAME);
493 * Assertions to verify the DTO created from {@link #createViewBuilder(ViewAttributes.Type)} ()}
495 private void assertDtoIsView(ComponentDto dto) {
496 assertThat(dto.name()).isEqualTo(VIEW_NAME);
497 assertThat(dto.longName()).isEqualTo(VIEW_NAME);
498 assertThat(dto.description()).isEqualTo(VIEW_DESCRIPTION);
499 assertThat(dto.path()).isNull();
500 assertThat(dto.uuid()).isEqualTo(VIEW_UUID);
501 assertThat(dto.projectUuid()).isEqualTo(VIEW_UUID);
502 assertThat(dto.getRootUuid()).isEqualTo(VIEW_UUID);
503 assertThat(dto.moduleUuid()).isNull();
504 assertThat(dto.moduleUuidPath()).isEqualTo("." + dto.uuid() + ".");
505 assertThat(dto.qualifier()).isEqualTo(Qualifiers.VIEW);
506 assertThat(dto.scope()).isEqualTo(Scopes.PROJECT);
507 assertThat(dto.getCopyResourceUuid()).isNull();
508 assertThat(dto.getCreatedAt()).isEqualTo(now);
512 * Assertions to verify the DTO created from {@link #createViewBuilder(ViewAttributes.Type)} ()}
514 private void assertDtoIsApplication(ComponentDto dto) {
515 assertThat(dto.name()).isEqualTo(VIEW_NAME);
516 assertThat(dto.longName()).isEqualTo(VIEW_NAME);
517 assertThat(dto.description()).isEqualTo(VIEW_DESCRIPTION);
518 assertThat(dto.path()).isNull();
519 assertThat(dto.uuid()).isEqualTo(VIEW_UUID);
520 assertThat(dto.projectUuid()).isEqualTo(VIEW_UUID);
521 assertThat(dto.getRootUuid()).isEqualTo(VIEW_UUID);
522 assertThat(dto.moduleUuid()).isNull();
523 assertThat(dto.moduleUuidPath()).isEqualTo("." + dto.uuid() + ".");
524 assertThat(dto.qualifier()).isEqualTo(Qualifiers.APP);
525 assertThat(dto.scope()).isEqualTo(Scopes.PROJECT);
526 assertThat(dto.getCopyResourceUuid()).isNull();
527 assertThat(dto.getCreatedAt()).isEqualTo(now);
531 * Assertions to verify the DTO created from {@link #createProjectView1Builder(ComponentDto, Long)}
533 private void assertDtoIsSubView1(ComponentDto viewDto, ComponentDto sv1Dto) {
534 assertThat(sv1Dto.name()).isEqualTo(SUBVIEW_1_NAME);
535 assertThat(sv1Dto.longName()).isEqualTo(SUBVIEW_1_NAME);
536 assertThat(sv1Dto.description()).isEqualTo(SUBVIEW_1_DESCRIPTION);
537 assertThat(sv1Dto.path()).isNull();
538 assertThat(sv1Dto.uuid()).isEqualTo(SUBVIEW_1_UUID);
539 assertThat(sv1Dto.projectUuid()).isEqualTo(viewDto.uuid());
540 assertThat(sv1Dto.getRootUuid()).isEqualTo(viewDto.uuid());
541 assertThat(sv1Dto.moduleUuid()).isEqualTo(viewDto.uuid());
542 assertThat(sv1Dto.moduleUuidPath()).isEqualTo(viewDto.moduleUuidPath() + sv1Dto.uuid() + ".");
543 assertThat(sv1Dto.qualifier()).isEqualTo(Qualifiers.SUBVIEW);
544 assertThat(sv1Dto.scope()).isEqualTo(Scopes.PROJECT);
545 assertThat(sv1Dto.getCopyResourceUuid()).isNull();
546 assertThat(sv1Dto.getCreatedAt()).isEqualTo(now);
549 private void assertDtoIsProjectView1(ComponentDto pv1Dto, ComponentDto viewDto, ComponentDto parentViewDto, ComponentDto project) {
550 assertThat(pv1Dto.name()).isEqualTo(PROJECT_VIEW_1_NAME);
551 assertThat(pv1Dto.longName()).isEqualTo(PROJECT_VIEW_1_NAME);
552 assertThat(pv1Dto.description()).isNull();
553 assertThat(pv1Dto.path()).isNull();
554 assertThat(pv1Dto.uuid()).isEqualTo(PROJECT_VIEW_1_UUID);
555 assertThat(pv1Dto.projectUuid()).isEqualTo(viewDto.uuid());
556 assertThat(pv1Dto.getRootUuid()).isEqualTo(viewDto.uuid());
557 assertThat(pv1Dto.moduleUuid()).isEqualTo(parentViewDto.uuid());
558 assertThat(pv1Dto.moduleUuidPath()).isEqualTo(parentViewDto.moduleUuidPath() + pv1Dto.uuid() + ".");
559 assertThat(pv1Dto.qualifier()).isEqualTo(Qualifiers.PROJECT);
560 assertThat(pv1Dto.scope()).isEqualTo(Scopes.FILE);
561 assertThat(pv1Dto.getCopyResourceUuid()).isEqualTo(project.uuid());
562 assertThat(pv1Dto.getCreatedAt()).isEqualTo(now);