--- /dev/null
+/*
+ * 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<Component, Event> events = HashMultimap.create();
+
+ @Override
+ public void add(Component component, Event event) {
+ events.put(requireNonNull(component), requireNonNull(event));
+ }
+
+ @Override
+ public Iterable<Event> getEvents(Component component) {
+ Collection<Event> res = this.events.get(component);
+ if (res == null) {
+ return Collections.emptySet();
+ }
+ return res;
+ }
+}
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;
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
"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) {
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;
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;
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;
private MeasureRepository measureRepository = mock(MeasureRepository.class);
private LanguageRepository languageRepository = mock(LanguageRepository.class);
+ private EventRepository eventRepository = mock(EventRepository.class);
+ private ArgumentCaptor<Event> 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() {
underTest.execute(context);
- assertThat(context.getRoot().getEventRepository().getEvents()).isEmpty();
+ verifyNoMoreInteractions(eventRepository);
}
@Test(expected = IllegalStateException.class)
underTest.execute(context);
- assertThat(context.getRoot().getEventRepository().getEvents()).isEmpty();
+ verifyNoMoreInteractions(eventRepository);
}
@Test
underTest.execute(context);
- List<Event> 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
underTest.execute(context);
- List<Event> 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
underTest.execute(context);
- List<Event> 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
underTest.execute(context);
- List<Event> 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
underTest.execute(context);
- assertThat(context.getRoot().getEventRepository().getEvents()).isEmpty();
+ verify(eventRepository, never()).add(any(Component.class), any(Event.class));
}
@Test
underTest.execute(context);
- List<Event> 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")));
@Test
public void verify_detection_with_complex_mix_of_qps() {
ComputationContext context = newNoChildRootContext();
+ final Set<Event> 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(
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 + ")"
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");
}
});
}
builder, languageRepository);
}
- private class EvenRepoComponent extends DumbComponent {
- private final EventRepository eventRepository = new EventRepository() {
- private final Set<Event> events = new HashSet<>();
-
- @Override
- public void add(Event event) {
- events.add(event);
- }
-
- @Override
- public Iterable<Event> 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;
- }
- }
-
}