]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6568 add CE specific component "API"
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 22 May 2015 07:34:57 +0000 (09:34 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 25 May 2015 11:27:24 +0000 (13:27 +0200)
15 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitor.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentVisitor.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/component/TypeAwareVisitor.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/component/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/context/ComputationContext.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/context/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/event/Event.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/event/EventRepository.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/event/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepository.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitorTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/component/ComponentTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/event/EventTest.java [new file with mode: 0644]

diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitor.java
new file mode 100644 (file)
index 0000000..70e0d37
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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.component;
+
+import java.util.Objects;
+
+/**
+ * Implementation of {@link TypeAwareVisitor} that implements a depth first crawling of the
+ * {@link ComponentImpl} tree. It supports a max depth for crawling (component strictly deeper than the specified
+ * type will be ignored).
+ */
+public abstract class ChildFirstTypeAwareVisitor implements TypeAwareVisitor {
+  private final Component.Type maxDepth;
+
+  protected ChildFirstTypeAwareVisitor(Component.Type maxDepth) {
+    this.maxDepth = Objects.requireNonNull(maxDepth);
+  }
+
+  @Override
+  public void visit(Component component) {
+    if (component.getType().isDeeperThan(maxDepth)) {
+      return;
+    }
+
+    if (component.getType() != maxDepth) {
+      for (Component child : component.getChildren()) {
+        visit(child);
+      }
+    }
+
+    switch (component.getType()) {
+      case PROJECT:
+        visitProject(component);
+        break;
+      case MODULE:
+        visitModule(component);
+        break;
+      case DIRECTORY:
+        visitDirectory(component);
+        break;
+      case FILE:
+        visitFile(component);
+        break;
+      default:
+        visitUnknown(component);
+    }
+  }
+
+  @Override
+  public void visitProject(Component tree) {
+    // empty implementation, meant to be override at will by subclasses
+  }
+
+  @Override
+  public void visitModule(Component tree) {
+    // empty implementation, meant to be override at will by subclasses
+  }
+
+  @Override
+  public void visitDirectory(Component tree) {
+    // empty implementation, meant to be override at will by subclasses
+  }
+
+  @Override
+  public void visitFile(Component tree) {
+    // empty implementation, meant to be override at will by subclasses
+  }
+
+  @Override
+  public void visitUnknown(Component tree) {
+    // empty implementation, meant to be override at will by subclasses
+  }
+
+}
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
new file mode 100644 (file)
index 0000000..b1014dc
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.component;
+
+import java.util.List;
+import org.sonar.server.computation.context.ComputationContext;
+import org.sonar.server.computation.event.EventRepository;
+import org.sonar.server.computation.measure.MeasureRepository;
+
+public interface Component {
+  enum Type {
+    PROJECT(0), MODULE(1), DIRECTORY(2), FILE(3);
+
+    private final int depth;
+
+    Type(int depth) {
+      this.depth = depth;
+    }
+
+    public int getDepth() {
+      return depth;
+    }
+
+    public boolean isDeeperThan(Type otherType) {
+      return this.getDepth() > otherType.getDepth();
+    }
+  }
+
+  ComputationContext getContext();
+
+  Type getType();
+
+  // FIXME we should not expose a batch specific information
+  int getRef();
+
+  List<Component> getChildren();
+
+  /**
+   * The event repository for the current component
+   */
+  EventRepository getEventRepository();
+
+  /**
+   * the measure repository for the current component
+   */
+  MeasureRepository getMeasureRepository();
+
+}
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
new file mode 100644 (file)
index 0000000..b9a6697
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * 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.component;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.sonar.api.measures.Metric;
+import org.sonar.batch.protocol.Constants;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.core.measure.db.MeasureDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.computation.ComputationContext;
+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.db.DbClient;
+
+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<Component> children;
+  private final EventRepository eventRepository = new SetEventRepository();
+
+  public ComponentImpl(ComputationContext context, BatchReport.Component component, @Nullable Iterable<Component> children) {
+    this.context = context;
+    this.component = component;
+    this.type = convertType(component.getType());
+    this.children = children == null ? Collections.<Component>emptyList() : copyOf(filter(children, notNull()));
+  }
+
+  private static Type convertType(Constants.ComponentType type) {
+    switch (type) {
+      case PROJECT:
+        return Type.PROJECT;
+      case MODULE:
+        return Type.MODULE;
+      case DIRECTORY:
+        return Type.DIRECTORY;
+      case FILE:
+        return Type.FILE;
+      default:
+        throw new IllegalArgumentException("Unsupported Constants.ComponentType value " + type);
+    }
+  }
+
+  @Override
+  public Type getType() {
+    return type;
+  }
+
+  @Override
+  public int getRef() {
+    return component.getRef();
+  }
+
+  @Override
+  public List<Component> getChildren() {
+    return children;
+  }
+
+  @Override
+  public org.sonar.server.computation.context.ComputationContext getContext() {
+    return context;
+  }
+
+  @Override
+  public EventRepository getEventRepository() {
+    return eventRepository;
+  }
+
+  @Override
+  public MeasureRepository getMeasureRepository() {
+    return new MeasureRepository() {
+      @Override
+      public Optional<MeasureDto> findPrevious(Metric<?> metric) {
+        DbClient dbClient = context.getDbClient();
+        try (DbSession dbSession = dbClient.openSession(false)) {
+          return Optional.fromNullable(
+            dbClient.measureDao().findByComponentKeyAndMetricKey(dbSession, component.getKey(), metric.getKey())
+            );
+        }
+      }
+
+      @Override
+      public Optional<BatchReport.Measure> findCurrent(final Metric<?> metric) {
+        return Optional.fromNullable(Iterables.find(
+          context.getReportReader().readComponentMeasures(component.getRef()),
+          new Predicate<BatchReport.Measure>() {
+            @Override
+            public boolean apply(@Nonnull BatchReport.Measure input) {
+              return input.getMetricKey().equals(metric.getKey());
+            }
+          }
+          ));
+      }
+    };
+  }
+
+  private static class SetEventRepository implements EventRepository {
+    private final Set<Event> events = new HashSet<>();
+
+    @Override
+    public void add(Event event) {
+      events.add(requireNonNull(event));
+    }
+
+    @Override
+    public Iterable<Event> getEvents() {
+      return events;
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentVisitor.java
new file mode 100644 (file)
index 0000000..98e0282
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.component;
+
+public interface ComponentVisitor {
+  void visit(Component tree);
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/TypeAwareVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/TypeAwareVisitor.java
new file mode 100644 (file)
index 0000000..9e59e17
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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.component;
+
+/**
+ * A {@link ComponentVisitor} which can exposes methods which ensure the type of the visited Component.
+ */
+public interface TypeAwareVisitor extends ComponentVisitor {
+  void visitProject(Component tree);
+
+  void visitModule(Component tree);
+
+  void visitDirectory(Component tree);
+
+  void visitFile(Component tree);
+
+  void visitUnknown(Component tree);
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/package-info.java
new file mode 100644 (file)
index 0000000..4e4e221
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.server.computation.component;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/context/ComputationContext.java b/server/sonar-server/src/main/java/org/sonar/server/computation/context/ComputationContext.java
new file mode 100644 (file)
index 0000000..171639a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.context;
+
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.language.LanguageRepository;
+
+public interface ComputationContext {
+
+  Component getRoot();
+
+  LanguageRepository getLanguageRepository();
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/context/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/computation/context/package-info.java
new file mode 100644 (file)
index 0000000..d15e656
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.server.computation.context;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/event/Event.java b/server/sonar-server/src/main/java/org/sonar/server/computation/event/Event.java
new file mode 100644 (file)
index 0000000..260be3c
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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 java.util.Objects;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+import static java.util.Objects.requireNonNull;
+
+
+@Immutable
+public class Event {
+  private final String name;
+  private final Category category;
+  @Nullable
+  private final String data;
+  @Nullable
+  private final String description;
+
+  private Event(String name, Category category, @Nullable String data, @Nullable String description) {
+    this.name = requireNonNull(name);
+    this.category = requireNonNull(category);
+    this.data = data;
+    this.description = description;
+  }
+
+  public static Event createAlert(String name, @Nullable String data, @Nullable String description) {
+    return new Event(name, Category.ALERT, data, description);
+  }
+
+  public static Event createProfile(String name, @Nullable String data, @Nullable String description) {
+    return new Event(name, Category.PROFILE, data, description);
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public Category getCategory() {
+    return category;
+  }
+
+  public String getData() {
+    return data;
+  }
+
+  @Nullable
+  public String getDescription() {
+    return description;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    Event event = (Event) o;
+    return Objects.equals(name, event.name) &&
+        Objects.equals(category, event.category);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(name, category);
+  }
+
+  public enum Category {
+    ALERT, PROFILE
+  }
+
+}
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
new file mode 100644 (file)
index 0000000..1e55c0c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+public interface EventRepository {
+  void add(Event event);
+
+  Iterable<Event> getEvents();
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/event/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/computation/event/package-info.java
new file mode 100644 (file)
index 0000000..4a57b59
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.server.computation.event;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepository.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepository.java
new file mode 100644 (file)
index 0000000..38c4e77
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.measure;
+
+import org.sonar.api.measures.Metric;
+import org.sonar.batch.protocol.output.BatchReport;
+
+import com.google.common.base.Optional;
+import org.sonar.core.measure.db.MeasureDto;
+
+public interface MeasureRepository {
+  // FIXME should not expose MeasureDto from DAO layer
+  Optional<MeasureDto> findPrevious(Metric<?> metric);
+
+  // FIXME should not expose Measure from BatchReport
+  Optional<BatchReport.Measure> findCurrent(Metric<?> metric);
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/ChildFirstTypeAwareVisitorTest.java
new file mode 100644 (file)
index 0000000..d3b6635
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * 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.component;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.sonar.server.computation.context.ComputationContext;
+import org.sonar.server.computation.event.EventRepository;
+import org.sonar.server.computation.measure.MeasureRepository;
+
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.spy;
+import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
+import static org.sonar.server.computation.component.Component.Type.FILE;
+import static org.sonar.server.computation.component.Component.Type.MODULE;
+import static org.sonar.server.computation.component.Component.Type.PROJECT;
+
+public class ChildFirstTypeAwareVisitorTest {
+
+  private static final String UNSUPPORTED_OPERATION_ERROR = "This node has no repository nor context";
+
+  private static final Component FILE_4 = component(FILE, 4);
+  private static final Component FILE_5 = component(FILE, 5);
+  private static final Component DIRECTORY_3 = component(DIRECTORY, 3, FILE_4, FILE_5);
+  private static final Component MODULE_2 = component(MODULE, 2, DIRECTORY_3);
+  private static final Component COMPONENT_TREE = component(PROJECT, 1, MODULE_2);
+
+  private final ChildFirstTypeAwareVisitor spyProjectVisitor = spy(new ChildFirstTypeAwareVisitor(PROJECT) {});
+  private final ChildFirstTypeAwareVisitor spyModuleVisitor = spy(new ChildFirstTypeAwareVisitor(MODULE) {});
+  private final ChildFirstTypeAwareVisitor spyDirectoryVisitor = spy(new ChildFirstTypeAwareVisitor(DIRECTORY) {});
+  private final ChildFirstTypeAwareVisitor spyFileVisitor = spy(new ChildFirstTypeAwareVisitor(FILE) {});
+  private final InOrder inOrder = inOrder(spyProjectVisitor, spyModuleVisitor, spyDirectoryVisitor, spyFileVisitor);
+
+  @Test(expected = NullPointerException.class)
+  public void non_null_max_depth_fast_fail() {
+    new ChildFirstTypeAwareVisitor(null) {
+    };
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void visit_null_Component_throws_NPE() {
+    spyFileVisitor.visit(null);
+  }
+
+  @Test
+  public void visit_file_with_depth_FILE_calls_visit_file() {
+    Component component = component(FILE, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitFile(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_FILE_calls_visit_module() {
+    Component component = component(MODULE, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_FILE_calls_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitDirectory(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_FILE_calls_visit_project() {
+    Component component = component(PROJECT, 1);
+    spyFileVisitor.visit(component);
+
+    inOrder.verify(spyFileVisitor).visit(component);
+    inOrder.verify(spyFileVisitor).visitProject(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_file_with_depth_DIRECTORY_does_not_call_visit_file() {
+    Component component = component(FILE, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_DIRECTORY_calls_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verify(spyDirectoryVisitor).visitDirectory(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_DIRECTORY_calls_visit_module() {
+    Component component = component(MODULE, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verify(spyDirectoryVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_DIRECTORY_calls_visit_project() {
+    Component component = component(PROJECT, 1);
+    spyDirectoryVisitor.visit(component);
+
+    inOrder.verify(spyDirectoryVisitor).visit(component);
+    inOrder.verify(spyDirectoryVisitor).visitProject(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_file_with_depth_MODULE_does_not_call_visit_file() {
+    Component component = component(FILE, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_MODULE_does_not_call_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_MODULE_calls_visit_module() {
+    Component component = component(MODULE, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verify(spyModuleVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_MODULE_calls_visit_project() {
+    Component component = component(MODULE, 1);
+    spyModuleVisitor.visit(component);
+
+    inOrder.verify(spyModuleVisitor).visit(component);
+    inOrder.verify(spyModuleVisitor).visitModule(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_file_with_depth_PROJECT_does_not_call_visit_file() {
+    Component component = component(FILE, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_directory_with_depth_PROJECT_does_not_call_visit_directory() {
+    Component component = component(DIRECTORY, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_module_with_depth_PROJECT_does_not_call_visit_module() {
+    Component component = component(MODULE, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void visit_project_with_depth_PROJECT_calls_visit_project() {
+    Component component = component(PROJECT, 1);
+    spyProjectVisitor.visit(component);
+
+    inOrder.verify(spyProjectVisitor).visit(component);
+    inOrder.verify(spyProjectVisitor).visitProject(component);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_FILE() {
+    spyFileVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyFileVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyFileVisitor).visit(MODULE_2);
+    inOrder.verify(spyFileVisitor).visit(DIRECTORY_3);
+    inOrder.verify(spyFileVisitor).visit(FILE_4);
+    inOrder.verify(spyFileVisitor).visitFile(FILE_4);
+    inOrder.verify(spyFileVisitor).visit(FILE_5);
+    inOrder.verify(spyFileVisitor).visitFile(FILE_5);
+    inOrder.verify(spyFileVisitor).visitDirectory(DIRECTORY_3);
+    inOrder.verify(spyFileVisitor).visitModule(MODULE_2);
+    inOrder.verify(spyFileVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_DIRECTORY() {
+    spyDirectoryVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyDirectoryVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyDirectoryVisitor).visit(MODULE_2);
+    inOrder.verify(spyDirectoryVisitor).visit(DIRECTORY_3);
+    inOrder.verify(spyDirectoryVisitor).visitDirectory(DIRECTORY_3);
+    inOrder.verify(spyDirectoryVisitor).visitModule(MODULE_2);
+    inOrder.verify(spyDirectoryVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_MODULE() {
+    spyModuleVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyModuleVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyModuleVisitor).visit(MODULE_2);
+    inOrder.verify(spyModuleVisitor).visitModule(MODULE_2);
+    inOrder.verify(spyModuleVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  public void verify_visit_call_when_visit_tree_with_depth_PROJECT() {
+    spyProjectVisitor.visit(COMPONENT_TREE);
+
+    inOrder.verify(spyProjectVisitor).visit(COMPONENT_TREE);
+    inOrder.verify(spyProjectVisitor).visitProject(COMPONENT_TREE);
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  private static Component component(final Component.Type type, final int ref, final Component... children) {
+    return new Component() {
+
+      @Override
+      public Type getType() {
+        return type;
+      }
+
+      @Override
+      public int getRef() {
+        return ref;
+      }
+
+      @Override
+      public List<Component> getChildren() {
+        return children == null ? Collections.<Component>emptyList() : ImmutableList.copyOf(Arrays.asList(children));
+      }
+
+      @Override
+      public ComputationContext getContext() {
+        throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_ERROR);
+      }
+
+      @Override
+      public EventRepository getEventRepository() {
+        throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_ERROR);
+      }
+
+      @Override
+      public MeasureRepository getMeasureRepository() {
+        throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_ERROR);
+      }
+    };
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/ComponentTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/ComponentTest.java
new file mode 100644 (file)
index 0000000..c6b0d90
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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.component;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
+import static org.sonar.server.computation.component.Component.Type.MODULE;
+import static org.sonar.server.computation.component.Component.Type.PROJECT;
+
+public class ComponentTest {
+  @Test
+  public void verify_type_is_deeper_than_when_comparing_to_itself() throws Exception {
+    for (Component.Type type : Component.Type.values()) {
+      assertThat(type.isDeeperThan(type)).isFalse();
+    }
+  }
+
+  @Test
+  public void FILE_type_is_deeper_than_all_other_types() throws Exception {
+    assertThat(Component.Type.FILE.isDeeperThan(DIRECTORY)).isTrue();
+    assertThat(Component.Type.FILE.isDeeperThan(MODULE)).isTrue();
+    assertThat(Component.Type.FILE.isDeeperThan(PROJECT)).isTrue();
+  }
+
+  @Test
+  public void DIRECTORY_type_is_deeper_than_MODULE_and_PROJECT() throws Exception {
+    assertThat(Component.Type.DIRECTORY.isDeeperThan(MODULE)).isTrue();
+    assertThat(Component.Type.DIRECTORY.isDeeperThan(PROJECT)).isTrue();
+  }
+
+  @Test
+  public void MODULE_type_is_deeper_than_PROJECT() throws Exception {
+    assertThat(Component.Type.MODULE.isDeeperThan(PROJECT)).isTrue();
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/event/EventTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/event/EventTest.java
new file mode 100644 (file)
index 0000000..4726dd2
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class EventTest {
+
+  private static final String SOME_NAME = "someName";
+  private static final String SOME_DATA = "some data";
+  private static final String SOME_DESCRIPTION = "some description";
+
+  @Test(expected = NullPointerException.class)
+  public void createAlert_fail_fast_null_check_on_null_name() {
+    Event.createAlert(null, SOME_DATA, SOME_DESCRIPTION);
+  }
+
+  @Test(expected = NullPointerException.class)
+  public void createProfile_fail_fast_null_check_on_null_name() {
+    Event.createProfile(null, SOME_DATA, SOME_DESCRIPTION);
+  }
+
+  @Test
+  public void createAlert_verify_fields() {
+    Event event = Event.createAlert(SOME_NAME, SOME_DATA, SOME_DESCRIPTION);
+    assertThat(event.getName()).isEqualTo(SOME_NAME);
+    assertThat(event.getCategory()).isEqualTo(Event.Category.ALERT);
+    assertThat(event.getData()).isEqualTo(SOME_DATA);
+    assertThat(event.getDescription()).isEqualTo(SOME_DESCRIPTION);
+  }
+
+  @Test
+  public void createProfile_verify_fields() {
+    Event event = Event.createProfile(SOME_NAME, SOME_DATA, SOME_DESCRIPTION);
+    assertThat(event.getName()).isEqualTo(SOME_NAME);
+    assertThat(event.getCategory()).isEqualTo(Event.Category.PROFILE);
+    assertThat(event.getData()).isEqualTo(SOME_DATA);
+    assertThat(event.getDescription()).isEqualTo(SOME_DESCRIPTION);
+  }
+
+}