From c295398811dff0db54e3a6c140ab41d275780f73 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Thu, 28 May 2015 09:28:53 +0200 Subject: [PATCH] SONAR-6589 move EventRepository out of Component --- .../computation/component/Component.java | 6 -- .../computation/component/ComponentImpl.java | 25 ------ .../container/ComputeEngineContainerImpl.java | 2 + .../computation/event/EventRepository.java | 6 +- .../event/EventRepositoryImpl.java | 46 ++++++++++ .../step/QualityProfileEventsStep.java | 11 ++- .../computation/component/DumbComponent.java | 6 -- .../step/QualityProfileEventsStepTest.java | 89 +++++++++---------- 8 files changed, 99 insertions(+), 92 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/event/EventRepositoryImpl.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java index c379e1f72eb..2bbb79ef1fe 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java @@ -21,7 +21,6 @@ package org.sonar.server.computation.component; import java.util.List; import org.sonar.server.computation.context.ComputationContext; -import org.sonar.server.computation.event.EventRepository; import org.sonar.server.computation.step.PopulateComponentsUuidAndKeyStep; public interface Component { @@ -62,9 +61,4 @@ public interface Component { List getChildren(); - /** - * The event repository for the current component - */ - EventRepository getEventRepository(); - } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentImpl.java index f0ae5fd9512..f5952196b02 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentImpl.java @@ -20,27 +20,21 @@ package org.sonar.server.computation.component; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; import javax.annotation.Nullable; import org.sonar.batch.protocol.Constants; import org.sonar.batch.protocol.output.BatchReport; import org.sonar.server.computation.ComputationContext; -import org.sonar.server.computation.event.Event; -import org.sonar.server.computation.event.EventRepository; import static com.google.common.base.Predicates.notNull; import static com.google.common.collect.ImmutableList.copyOf; import static com.google.common.collect.Iterables.filter; -import static java.util.Objects.requireNonNull; public class ComponentImpl implements Component { private final ComputationContext context; private final Type type; private final BatchReport.Component component; private final List children; - private final EventRepository eventRepository = new SetEventRepository(); // Mutable values private String key; @@ -112,23 +106,4 @@ public class ComponentImpl implements Component { return context; } - @Override - public EventRepository getEventRepository() { - return eventRepository; - } - - private static class SetEventRepository implements EventRepository { - private final Set events = new HashSet<>(); - - @Override - public void add(Event event) { - events.add(requireNonNull(event)); - } - - @Override - public Iterable getEvents() { - return events; - } - } - } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java index f1040901595..a6a62dc8d2f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java @@ -37,6 +37,7 @@ import org.sonar.server.computation.activity.ActivityManager; import org.sonar.server.computation.batch.BatchReportReaderImpl; import org.sonar.server.computation.batch.ReportExtractor; import org.sonar.server.computation.component.DbComponentsRefCache; +import org.sonar.server.computation.event.EventRepositoryImpl; import org.sonar.server.computation.component.ProjectSettingsRepository; import org.sonar.server.computation.issue.IssueCache; import org.sonar.server.computation.issue.IssueComputation; @@ -115,6 +116,7 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co // repositories PlatformLanguageRepository.class, MeasureRepositoryImpl.class, + EventRepositoryImpl.class, ProjectSettingsRepository.class, // component caches diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/event/EventRepository.java b/server/sonar-server/src/main/java/org/sonar/server/computation/event/EventRepository.java index 1e55c0c18ad..5041e3f82b9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/event/EventRepository.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/event/EventRepository.java @@ -19,8 +19,10 @@ */ package org.sonar.server.computation.event; +import org.sonar.server.computation.component.Component; + public interface EventRepository { - void add(Event event); + void add(Component component, Event event); - Iterable getEvents(); + Iterable getEvents(Component component); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/event/EventRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/event/EventRepositoryImpl.java new file mode 100644 index 00000000000..b65f94e46f9 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/event/EventRepositoryImpl.java @@ -0,0 +1,46 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.computation.event; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import java.util.Collection; +import java.util.Collections; +import org.sonar.server.computation.component.Component; + +import static java.util.Objects.requireNonNull; + +public class EventRepositoryImpl implements EventRepository { + private final Multimap events = HashMultimap.create(); + + @Override + public void add(Component component, Event event) { + events.put(requireNonNull(component), requireNonNull(event)); + } + + @Override + public Iterable getEvents(Component component) { + Collection res = this.events.get(component); + if (res == null) { + return Collections.emptySet(); + } + return res; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java index 2e26992c1d2..511bb9b14f6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java @@ -32,6 +32,7 @@ import org.sonar.server.computation.ComputationContext; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor; import org.sonar.server.computation.event.Event; +import org.sonar.server.computation.event.EventRepository; import org.sonar.server.computation.measure.MeasureRepository; import org.sonar.server.computation.qualityprofile.QPMeasureData; import org.sonar.server.computation.qualityprofile.QualityProfile; @@ -45,9 +46,11 @@ import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisi public class QualityProfileEventsStep implements ComputationStep { private final MeasureRepository measureRepository; + private final EventRepository eventRepository; - public QualityProfileEventsStep(MeasureRepository measureRepository) { + public QualityProfileEventsStep(MeasureRepository measureRepository, EventRepository eventRepository) { this.measureRepository = measureRepository; + this.eventRepository = eventRepository; } @Override @@ -105,15 +108,15 @@ public class QualityProfileEventsStep implements ComputationStep { "key", profile.getQpKey(), "from", UtcDateUtils.formatDateTime(fixDate(from)), "to", UtcDateUtils.formatDateTime(fixDate(profile.getRulesUpdatedAt())))); - component.getEventRepository().add(createQProfileEvent(component, profile, "Changes in %s", data)); + eventRepository.add(component, createQProfileEvent(component, profile, "Changes in %s", data)); } private void markAsRemoved(Component component, QualityProfile profile) { - component.getEventRepository().add(createQProfileEvent(component, profile, "Stop using %s")); + eventRepository.add(component, createQProfileEvent(component, profile, "Stop using %s")); } private void markAsAdded(Component component, QualityProfile profile) { - component.getEventRepository().add(createQProfileEvent(component, profile, "Use %s")); + eventRepository.add(component, createQProfileEvent(component, profile, "Use %s")); } private static Event createQProfileEvent(Component component, QualityProfile profile, String namePattern) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/DumbComponent.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/DumbComponent.java index 8830ff340df..e2f7061f0b4 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/component/DumbComponent.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/component/DumbComponent.java @@ -26,7 +26,6 @@ import java.util.List; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.server.computation.context.ComputationContext; -import org.sonar.server.computation.event.EventRepository; public class DumbComponent implements Component { public static final Component DUMB_PROJECT = new DumbComponent(Type.PROJECT, 1, "PROJECT_KEY", "PROJECT_UUID"); @@ -87,9 +86,4 @@ public class DumbComponent implements Component { return context; } - @Override - public EventRepository getEventRepository() { - throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_ERROR); - } - } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/QualityProfileEventsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/QualityProfileEventsStepTest.java index 2759dec7c19..0f86e6d7c9d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/QualityProfileEventsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/QualityProfileEventsStepTest.java @@ -20,7 +20,6 @@ package org.sonar.server.computation.step; import com.google.common.base.Optional; -import com.google.common.collect.Lists; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -29,6 +28,9 @@ import java.util.List; import java.util.Set; import javax.annotation.Nullable; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.sonar.api.config.Settings; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.resources.AbstractLanguage; @@ -50,8 +52,14 @@ import org.sonar.server.computation.qualityprofile.QualityProfile; import org.sonar.server.db.DbClient; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.sonar.api.utils.DateUtils.parseDateTime; @@ -65,8 +73,10 @@ public class QualityProfileEventsStepTest { private MeasureRepository measureRepository = mock(MeasureRepository.class); private LanguageRepository languageRepository = mock(LanguageRepository.class); + private EventRepository eventRepository = mock(EventRepository.class); + private ArgumentCaptor eventArgumentCaptor = ArgumentCaptor.forClass(Event.class); - private QualityProfileEventsStep underTest = new QualityProfileEventsStep(measureRepository); + private QualityProfileEventsStep underTest = new QualityProfileEventsStep(measureRepository, eventRepository); @Test public void no_effect_if_no_previous_measure() { @@ -76,7 +86,7 @@ public class QualityProfileEventsStepTest { underTest.execute(context); - assertThat(context.getRoot().getEventRepository().getEvents()).isEmpty(); + verifyNoMoreInteractions(eventRepository); } @Test(expected = IllegalStateException.class) @@ -97,7 +107,7 @@ public class QualityProfileEventsStepTest { underTest.execute(context); - assertThat(context.getRoot().getEventRepository().getEvents()).isEmpty(); + verifyNoMoreInteractions(eventRepository); } @Test @@ -110,9 +120,9 @@ public class QualityProfileEventsStepTest { underTest.execute(context); - List events = Lists.newArrayList(context.getRoot().getEventRepository().getEvents()); - assertThat(events).hasSize(1); - verifyEvent(events.get(0), "Use '" + qp.getQpName() + "' (" + language.getName() + ")", null); + verify(eventRepository).add(eq(context.getRoot()), eventArgumentCaptor.capture()); + verifyNoMoreInteractions(eventRepository); + verifyEvent(eventArgumentCaptor.getValue(), "Use '" + qp.getQpName() + "' (" + language.getName() + ")", null); } @Test @@ -125,9 +135,9 @@ public class QualityProfileEventsStepTest { underTest.execute(context); - List events = Lists.newArrayList(context.getRoot().getEventRepository().getEvents()); - assertThat(events).hasSize(1); - verifyEvent(events.get(0), "Use '" + qp.getQpName() + "' (" + qp.getLanguageKey() + ")", null); + verify(eventRepository).add(eq(context.getRoot()), eventArgumentCaptor.capture()); + verifyNoMoreInteractions(eventRepository); + verifyEvent(eventArgumentCaptor.getValue(), "Use '" + qp.getQpName() + "' (" + qp.getLanguageKey() + ")", null); } @Test @@ -140,9 +150,9 @@ public class QualityProfileEventsStepTest { underTest.execute(context); - List events = Lists.newArrayList(context.getRoot().getEventRepository().getEvents()); - assertThat(events).hasSize(1); - verifyEvent(events.get(0), "Stop using '" + qp.getQpName() + "' (" + language.getName() + ")", null); + verify(eventRepository).add(eq(context.getRoot()), eventArgumentCaptor.capture()); + verifyNoMoreInteractions(eventRepository); + verifyEvent(eventArgumentCaptor.getValue(), "Stop using '" + qp.getQpName() + "' (" + language.getName() + ")", null); } @Test @@ -155,9 +165,9 @@ public class QualityProfileEventsStepTest { underTest.execute(context); - List events = Lists.newArrayList(context.getRoot().getEventRepository().getEvents()); - assertThat(events).hasSize(1); - verifyEvent(events.get(0), "Stop using '" + qp.getQpName() + "' (" + qp.getLanguageKey() + ")", null); + verify(eventRepository).add(eq(context.getRoot()), eventArgumentCaptor.capture()); + verifyNoMoreInteractions(eventRepository); + verifyEvent(eventArgumentCaptor.getValue(), "Stop using '" + qp.getQpName() + "' (" + qp.getLanguageKey() + ")", null); } @Test @@ -169,7 +179,7 @@ public class QualityProfileEventsStepTest { underTest.execute(context); - assertThat(context.getRoot().getEventRepository().getEvents()).isEmpty(); + verify(eventRepository, never()).add(any(Component.class), any(Event.class)); } @Test @@ -183,10 +193,9 @@ public class QualityProfileEventsStepTest { underTest.execute(context); - List events = Lists.newArrayList(context.getRoot().getEventRepository().getEvents()); - assertThat(events).hasSize(1); - verifyEvent( - events.get(0), + verify(eventRepository).add(eq(context.getRoot()), eventArgumentCaptor.capture()); + verifyNoMoreInteractions(eventRepository); + verifyEvent(eventArgumentCaptor.getValue(), "Changes in '" + qp2.getQpName() + "' (" + language.getName() + ")", "from=" + UtcDateUtils.formatDateTime(parseDateTime("2011-04-25T01:05:14+0100")) + ";key=" + qp1.getQpKey() + ";to=" + UtcDateUtils.formatDateTime(parseDateTime("2011-04-25T01:05:18+0100"))); @@ -195,6 +204,14 @@ public class QualityProfileEventsStepTest { @Test public void verify_detection_with_complex_mix_of_qps() { ComputationContext context = newNoChildRootContext(); + final Set events = new HashSet<>(); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + events.add((Event) invocationOnMock.getArguments()[1]); + return null; + } + }).when(eventRepository).add(eq(context.getRoot()), any(Event.class)); mockMeasures( context.getRoot(), arrayOf( @@ -211,7 +228,7 @@ public class QualityProfileEventsStepTest { underTest.execute(context); - assertThat(context.getRoot().getEventRepository().getEvents()).extracting("name").containsOnly( + assertThat(events).extracting("name").containsOnly( "Stop using '" + QP_NAME_2 + "' (" + LANGUAGE_KEY_1 + ")", "Use '" + QP_NAME_2 + "' (" + LANGUAGE_KEY_3 + ")", "Changes in '" + QP_NAME_1 + "' (" + LANGUAGE_KEY_1 + ")" @@ -282,7 +299,7 @@ public class QualityProfileEventsStepTest { return newContext(new ComponentTreeBuilder() { @Override public Component build(ComputationContext context) { - return new EvenRepoComponent(context, Component.Type.PROJECT, 1); + return new DumbComponent(context, Component.Type.PROJECT, 1, "uuid", "key"); } }); } @@ -292,30 +309,4 @@ public class QualityProfileEventsStepTest { builder, languageRepository); } - private class EvenRepoComponent extends DumbComponent { - private final EventRepository eventRepository = new EventRepository() { - private final Set events = new HashSet<>(); - - @Override - public void add(Event event) { - events.add(event); - } - - @Override - public Iterable getEvents() { - return events; - } - }; - - public EvenRepoComponent(@Nullable org.sonar.server.computation.context.ComputationContext context, - Type type, int ref, @Nullable Component... children) { - super(context, type, ref, null, null, children); - } - - @Override - public EventRepository getEventRepository() { - return eventRepository; - } - } - } -- 2.39.5