--- /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.activity;
+
+import javax.annotation.Nullable;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class Activity {
+
+ public static enum Type {
+ QPROFILE, SERVER, ANALYSIS_REPORT
+ }
+
+ private Type type;
+ private String action;
+ private String message;
+ private final Map<String,Object> data = new LinkedHashMap<>();
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(@Nullable String message) {
+ this.message = message;
+ }
+
+ public Map<String, Object> getData() {
+ return data;
+ }
+
+ public Activity setData(String key, Object val) {
+ this.data.put(key, val);
+ return this;
+ }
+}
*/
package org.sonar.server.activity;
-import org.sonar.core.activity.Activity;
-import org.sonar.core.activity.ActivityLog;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.api.utils.internal.Uuids;
import org.sonar.core.activity.db.ActivityDto;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.server.activity.index.ActivityIndex;
-import org.sonar.server.activity.index.ActivityQuery;
+import org.sonar.server.activity.index.ActivityIndexer;
import org.sonar.server.db.DbClient;
-import org.sonar.server.search.IndexClient;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
import org.sonar.server.user.UserSession;
-import javax.annotation.Nullable;
-
-/**
- * Log service is used to log Activity classes which represents an event to DB and Index.
- *
- * @see org.sonar.core.activity.ActivityLog
- */
-public class ActivityService {
+public class ActivityService implements ServerComponent {
private final DbClient dbClient;
- private final IndexClient indexClient;
+ private final ActivityIndexer indexer;
- public ActivityService(DbClient dbClient, IndexClient indexClient) {
+ public ActivityService(DbClient dbClient, ActivityIndexer indexer) {
this.dbClient = dbClient;
- this.indexClient = indexClient;
- }
-
- @Nullable
- private String getAuthor() {
- return (UserSession.get().login() != null) ? UserSession.get().login() : null;
- }
-
- private void save(DbSession session, ActivityDto log) {
- dbClient.activityDao().insert(session,
- log.setAuthor(getAuthor()));
- }
-
- public void write(DbSession session, Activity.Type type, String message) {
- save(session, ActivityDto.createFor(message).setType(type));
- }
-
- public <L extends ActivityLog> void write(DbSession session, Activity.Type type, L log) {
- this.save(session, ActivityDto.createFor(log)
- .setType(type));
- }
-
- public ActivityQuery newActivityQuery() {
- return new ActivityQuery();
+ this.indexer = indexer;
}
- public Result<Activity> search(ActivityQuery query, QueryContext options) {
- ActivityIndex index = indexClient.get(ActivityIndex.class);
- return new Result<Activity>(index, index.search(query, options));
+ public void save(Activity activity) {
+ ActivityDto dto = new ActivityDto()
+ .setKey(Uuids.create())
+ .setAuthor(UserSession.get().login())
+ .setAction(activity.getAction())
+ .setMessage(activity.getMessage())
+ .setData(KeyValueFormat.format(activity.getData()))
+ .setType(activity.getType().name());
+ dbClient.activityDao().insert(dto);
+ indexer.index();
}
}
import org.picocontainer.Startable;
import org.sonar.api.ServerComponent;
import org.sonar.api.utils.Paging;
+import org.sonar.server.es.SearchOptions;
import org.sonar.server.qualityprofile.QProfileActivity;
import org.sonar.server.qualityprofile.QProfileActivityQuery;
import org.sonar.server.qualityprofile.QProfileService;
-import org.sonar.server.search.QueryContext;
import org.sonar.server.search.Result;
import org.sonar.server.util.RubyUtils;
*/
public QProfileActivityResult search(Map<String, Object> params) {
QProfileActivityQuery query = new QProfileActivityQuery();
- QueryContext queryContext = new QueryContext().setMaxLimit();
- List<String> profileKeys = RubyUtils.toStrings(params.get("profileKeys"));
- if (profileKeys != null) {
- query.setQprofileKeys(profileKeys);
- }
+
+ query.setQprofileKey((String)params.get("profileKey"));
Date since = RubyUtils.toDate(params.get("since"));
if (since != null) {
query.setSince(since);
if (to != null) {
query.setTo(to);
}
+
+ SearchOptions options = new SearchOptions();
Integer page = RubyUtils.toInteger(params.get("p"));
int pageIndex = page != null ? page : 1;
- queryContext.setPage(pageIndex, 50);
+ options.setPage(pageIndex, 50);
- Result<QProfileActivity> result = service.searchActivities(query, queryContext);
- return new QProfileActivityResult(result.getHits(), Paging.create(queryContext.getLimit(), pageIndex, (int) result.getTotal()));
+ Result<QProfileActivity> result = service.searchActivities(query, options);
+ return new QProfileActivityResult(result.getHits(), Paging.create(options.getLimit(), pageIndex, (int) result.getTotal()));
}
@Override
*/
package org.sonar.server.activity.db;
+import org.sonar.api.ServerComponent;
import org.sonar.api.utils.System2;
import org.sonar.core.activity.db.ActivityDto;
import org.sonar.core.activity.db.ActivityMapper;
+import org.sonar.core.persistence.DaoComponent;
import org.sonar.core.persistence.DbSession;
-import org.sonar.server.db.BaseDao;
-import org.sonar.server.search.IndexDefinition;
+import org.sonar.core.persistence.MyBatis;
-import java.util.List;
+import java.util.Date;
-/**
- * @since 4.4
- */
-public class ActivityDao extends BaseDao<ActivityMapper, ActivityDto, String> {
+public class ActivityDao implements DaoComponent, ServerComponent {
- public ActivityDao(System2 system) {
- super(IndexDefinition.LOG, ActivityMapper.class, system);
- }
+ private final MyBatis mybatis;
+ private final System2 system;
- @Override
- protected ActivityDto doGetNullableByKey(DbSession session, String key) {
- throw new IllegalStateException("Cannot execute getByKey on Activities in DB");
+ public ActivityDao(MyBatis mybatis, System2 system) {
+ this.mybatis = mybatis;
+ this.system = system;
}
- @Override
- protected ActivityDto doInsert(DbSession session, ActivityDto item) {
- mapper(session).insert(item);
- return item;
+ public void insert(ActivityDto dto) {
+ DbSession session = mybatis.openSession(false);
+ try {
+ insert(session, dto);
+ session.commit();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
}
- @Override
- protected ActivityDto doUpdate(DbSession session, ActivityDto item) {
- throw new IllegalStateException("Cannot update Log!");
+ public void insert(DbSession session, ActivityDto dto) {
+ dto.setCreatedAt(new Date(system.now()));
+ session.getMapper(ActivityMapper.class).insert(dto);
}
- @Override
- protected void doDeleteByKey(DbSession session, String key) {
- throw new IllegalStateException("Cannot delete Log!");
- }
-
- public List<ActivityDto> findAll(DbSession session) {
- return mapper(session).selectAll();
- }
}
*/
package org.sonar.server.activity.index;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
-import org.sonar.core.activity.Activity;
import org.sonar.server.search.BaseDoc;
-import org.sonar.server.search.IndexUtils;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import java.util.Date;
+import java.util.HashMap;
import java.util.Map;
-/**
- * @since 4.4
- */
-public class ActivityDoc extends BaseDoc implements Activity {
+public class ActivityDoc extends BaseDoc {
- protected ActivityDoc(Map<String, Object> fields) {
+ public ActivityDoc(Map<String, Object> fields) {
super(fields);
}
- @Override
- public Date time() {
- return IndexUtils.parseDateTime((String) getField(ActivityNormalizer.LogFields.CREATED_AT.field()));
+ @VisibleForTesting
+ ActivityDoc() {
+ super(new HashMap<String, Object>());
+ }
+
+ public void setCreatedAt(Date date) {
+ setField(ActivityIndexDefinition.FIELD_CREATED_AT, date);
+ }
+
+ public Date getCreatedAt() {
+ return getFieldAsDate(ActivityIndexDefinition.FIELD_CREATED_AT);
+ }
+
+ public String getKey() {
+ return this.getField(ActivityIndexDefinition.FIELD_KEY);
+ }
+
+ public void setKey(String s) {
+ setField(ActivityIndexDefinition.FIELD_KEY, s);
+ }
+
+ @CheckForNull
+ public String getLogin() {
+ return this.getNullableField(ActivityIndexDefinition.FIELD_LOGIN);
+ }
+
+ public void setLogin(@Nullable String s) {
+ setField(ActivityIndexDefinition.FIELD_LOGIN, s);
+ }
+
+ public String getType() {
+ return ((String) getField(ActivityIndexDefinition.FIELD_TYPE));
+ }
+
+ public void setType(String s) {
+ setField(ActivityIndexDefinition.FIELD_TYPE, s);
+ }
+
+ @CheckForNull
+ public String getAction() {
+ return this.getNullableField(ActivityIndexDefinition.FIELD_ACTION);
}
- @Override
- public String login() {
- return this.getNullableField(ActivityNormalizer.LogFields.LOGIN.field());
+ public void setAction(@Nullable String s) {
+ setField(ActivityIndexDefinition.FIELD_ACTION, s);
}
- @Override
- public Type type() {
- return Type.valueOf((String) getField(ActivityNormalizer.LogFields.TYPE.field()));
+ @CheckForNull
+ public Map<String, String> getDetails() {
+ return this.getNullableField(ActivityIndexDefinition.FIELD_DETAILS);
}
- @Override
- public String action() {
- return this.getNullableField(ActivityNormalizer.LogFields.ACTION.field());
+ public void setDetails(Map<String, String> details) {
+ setField(ActivityIndexDefinition.FIELD_DETAILS, details);
}
- @Override
- public Map<String, String> details() {
- return this.getNullableField(ActivityNormalizer.LogFields.DETAILS.field());
+ @CheckForNull
+ public String getMessage() {
+ return this.getNullableField(ActivityIndexDefinition.FIELD_MESSAGE);
}
- @Override
- public String message() {
- return this.getNullableField(ActivityNormalizer.LogFields.MESSAGE.field());
+ public void setMessage(@Nullable String s) {
+ setField(ActivityIndexDefinition.FIELD_MESSAGE, s);
}
- @Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
*/
package org.sonar.server.activity.index;
+import com.google.common.base.Function;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.action.search.SearchType;
-import org.elasticsearch.common.settings.ImmutableSettings;
-import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.index.query.*;
+import org.elasticsearch.index.query.AndFilterBuilder;
+import org.elasticsearch.index.query.FilterBuilders;
+import org.elasticsearch.index.query.OrFilterBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortOrder;
-import org.sonar.core.activity.Activity;
-import org.sonar.core.activity.db.ActivityDto;
-import org.sonar.server.search.*;
+import org.sonar.core.util.NonNullInputFunction;
+import org.sonar.server.es.BaseIndex;
+import org.sonar.server.es.EsClient;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
-import javax.annotation.Nullable;
-
-import java.util.HashMap;
+import java.util.Date;
import java.util.Map;
-/**
- * @since 4.4
- */
-public class ActivityIndex extends BaseIndex<Activity, ActivityDto, String> {
-
- public ActivityIndex(ActivityNormalizer normalizer, SearchClient node) {
- super(IndexDefinition.LOG, normalizer, node);
- }
-
- @Override
- protected String getKeyValue(String key) {
- return key;
- }
-
- @Override
- protected Map mapKey() {
- Map<String, Object> mapping = new HashMap<String, Object>();
- mapping.put("path", ActivityNormalizer.LogFields.KEY.field());
- return mapping;
- }
-
- @Override
- protected ImmutableSettings.Builder addCustomIndexSettings(ImmutableSettings.Builder settings) {
- return settings
- .put("analysis.analyzer.default.type", "keyword");
- }
+public class ActivityIndex extends BaseIndex {
- @Override
- protected Map mapProperties() {
- Map<String, Object> mapping = new HashMap<String, Object>();
- for (IndexField field : ActivityNormalizer.LogFields.ALL_FIELDS) {
- mapping.put(field.field(), mapField(field));
+ /**
+ * Convert an Elasticsearch result (a map) to an {@link org.sonar.server.activity.index.ActivityDoc}. It's
+ * used for {@link org.sonar.server.es.SearchResult}.
+ */
+ private static final Function<Map<String, Object>, ActivityDoc> DOC_CONVERTER = new NonNullInputFunction<Map<String, Object>, ActivityDoc>() {
+ @Override
+ protected ActivityDoc doApply(Map<String, Object> input) {
+ return new ActivityDoc(input);
}
- return mapping;
- }
-
- @Override
- protected Activity toDoc(final Map<String, Object> fields) {
- return new ActivityDoc(fields);
- }
+ };
- public Result<Activity> findAll() {
- SearchRequestBuilder request = getClient().prepareSearch(this.getIndexName())
- .setQuery(QueryBuilders.matchAllQuery())
- .setTypes(this.getIndexType())
- .setSize(Integer.MAX_VALUE);
- SearchResponse response = request.get();
- return new Result<Activity>(this, response);
+ public ActivityIndex(EsClient esClient) {
+ super(esClient);
}
- public SearchResponse search(ActivityQuery query, QueryContext options) {
- return search(query, options, null);
+ public SearchResult<ActivityDoc> search(ActivityQuery query, SearchOptions options) {
+ SearchResponse response = doSearch(query, options);
+ return new SearchResult<>(response, DOC_CONVERTER);
}
- public SearchResponse search(ActivityQuery query, QueryContext options,
- @Nullable FilterBuilder domainFilter) {
-
- // Prepare query
- SearchRequestBuilder esSearch = getClient()
- .prepareSearch(this.getIndexName())
- .setTypes(this.getIndexType())
- .setIndices(this.getIndexName());
-
- // Integrate Pagination
- esSearch.setFrom(options.getOffset());
- esSearch.setSize(options.getLimit());
+ public SearchResponse doSearch(ActivityQuery query, SearchOptions options) {
+ SearchRequestBuilder requestBuilder = getClient()
+ .prepareSearch(ActivityIndexDefinition.INDEX)
+ .setTypes(ActivityIndexDefinition.TYPE);
- // Sort Date Desc
- esSearch.addSort(ActivityNormalizer.LogFields.CREATED_AT.field(), SortOrder.DESC);
+ requestBuilder.setFrom(options.getOffset());
+ requestBuilder.setSize(options.getLimit());
+ requestBuilder.addSort(ActivityIndexDefinition.FIELD_CREATED_AT, SortOrder.DESC);
AndFilterBuilder filter = FilterBuilders.andFilter();
-
- // implement Type Filtering
- OrFilterBuilder typeFilter = FilterBuilders.orFilter();
- for (Activity.Type type : query.getTypes()) {
- typeFilter.add(FilterBuilders.termFilter(ActivityNormalizer.LogFields.TYPE.field(), type));
+ if (!query.getTypes().isEmpty()) {
+ OrFilterBuilder typeFilter = FilterBuilders.orFilter();
+ for (String type : query.getTypes()) {
+ typeFilter.add(FilterBuilders.termFilter(ActivityIndexDefinition.FIELD_TYPE, type));
+ }
+ filter.add(typeFilter);
}
- filter.add(typeFilter);
-
- // Implement date Filter
- filter.add(FilterBuilders.rangeFilter(ActivityNormalizer.LogFields.CREATED_AT.field())
- .from(query.getSince())
- .to(query.getTo()));
- // Add any additional domain filter
- if (domainFilter != null) {
- filter.add(domainFilter);
+ if (!query.getDataOrFilters().isEmpty()) {
+ for (Map.Entry<String, Object> entry : query.getDataOrFilters().entrySet()) {
+ OrFilterBuilder orFilter = FilterBuilders.orFilter();
+ orFilter.add(FilterBuilders.nestedFilter(ActivityIndexDefinition.FIELD_DETAILS,
+ FilterBuilders.termFilter(ActivityIndexDefinition.FIELD_DETAILS + "." + entry.getKey(), entry.getValue())));
+ filter.add(orFilter);
+ }
}
- esSearch.setQuery(QueryBuilders.filteredQuery(
- QueryBuilders.matchAllQuery(), filter));
-
- if (options.isScroll()) {
- esSearch.setSearchType(SearchType.SCAN);
- esSearch.setScroll(TimeValue.timeValueMinutes(3));
+ Date since = query.getSince();
+ if (since != null) {
+ filter.add(FilterBuilders.rangeFilter(ActivityIndexDefinition.FIELD_CREATED_AT)
+ .gt(since)
+ .cache(false));
+ }
+ Date to = query.getTo();
+ if (to != null) {
+ filter.add(FilterBuilders.rangeFilter(ActivityIndexDefinition.FIELD_CREATED_AT)
+ .lt(to)
+ .cache(false));
}
- return esSearch.get();
+ requestBuilder.setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), filter));
+ return requestBuilder.get();
}
}
--- /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.activity.index;
+
+import com.google.common.collect.ImmutableMap;
+import org.elasticsearch.cluster.metadata.IndexMetaData;
+import org.sonar.api.config.Settings;
+import org.sonar.process.ProcessConstants;
+import org.sonar.server.es.IndexDefinition;
+import org.sonar.server.es.NewIndex;
+
+/**
+ * Definition of ES index "activities", including settings and fields.
+ */
+public class ActivityIndexDefinition implements IndexDefinition {
+
+ public static final String INDEX = "activities";
+ public static final String TYPE = "activity";
+ public static final String FIELD_KEY = "key";
+ public static final String FIELD_TYPE = "type";
+ public static final String FIELD_ACTION = "action";
+ public static final String FIELD_CREATED_AT = "createdAt";
+ public static final String FIELD_LOGIN = "login";
+ public static final String FIELD_DETAILS = "details";
+ public static final String FIELD_MESSAGE = "message";
+
+ private final Settings settings;
+
+ public ActivityIndexDefinition(Settings settings) {
+ this.settings = settings;
+ }
+
+ @Override
+ public void define(IndexDefinitionContext context) {
+ NewIndex index = context.create(INDEX);
+ // refresh is always handled by ActivityIndexer
+ index.getSettings().put("index.refresh_interval", "-1");
+ index.getSettings().put("analysis.analyzer.default.type", "keyword");
+
+ // shards
+ boolean clusterMode = settings.getBoolean(ProcessConstants.CLUSTER_ACTIVATE);
+ if (clusterMode) {
+ index.getSettings().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 4);
+ index.getSettings().put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 1);
+ // else keep defaults (one shard)
+ }
+
+ // type "activity"
+ NewIndex.NewIndexType mapping = index.createType(TYPE);
+ mapping.setAttribute("_id", ImmutableMap.of("path", FIELD_KEY));
+ mapping.stringFieldBuilder(FIELD_KEY).build();
+ mapping.stringFieldBuilder(FIELD_TYPE).build();
+ mapping.stringFieldBuilder(FIELD_ACTION).build();
+ mapping.stringFieldBuilder(FIELD_LOGIN).build();
+ mapping.createDynamicNestedField(FIELD_DETAILS);
+ mapping.stringFieldBuilder(FIELD_MESSAGE).build();
+ mapping.createDateTimeField(FIELD_CREATED_AT);
+ }
+}
--- /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.activity.index;
+
+import org.elasticsearch.action.update.UpdateRequest;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.es.BaseIndexer;
+import org.sonar.server.es.BulkIndexer;
+import org.sonar.server.es.EsClient;
+
+import java.sql.Connection;
+import java.util.Iterator;
+
+/**
+ * Add to Elasticsearch index {@link org.sonar.server.activity.index.ActivityIndexDefinition} the rows of
+ * db table ACTIVITIES that are not indexed yet
+ * <p/>
+ * TODO idea of improvement - index asynchronously with UpdateRequest#replicationType(ReplicationType.ASYNC)
+ */
+public class ActivityIndexer extends BaseIndexer {
+
+ private final DbClient dbClient;
+
+ public ActivityIndexer(DbClient dbClient, EsClient esClient) {
+ super(esClient, 0L, ActivityIndexDefinition.INDEX, ActivityIndexDefinition.TYPE);
+ this.dbClient = dbClient;
+ }
+
+ @Override
+ protected long doIndex(long lastUpdatedAt) {
+ final BulkIndexer bulk = new BulkIndexer(esClient, ActivityIndexDefinition.INDEX);
+ bulk.setLarge(lastUpdatedAt == 0L);
+
+ DbSession dbSession = dbClient.openSession(false);
+ Connection dbConnection = dbSession.getConnection();
+ try {
+ ActivityResultSetIterator rowIt = ActivityResultSetIterator.create(dbClient, dbConnection, lastUpdatedAt);
+ long maxUpdatedAt = doIndex(bulk, rowIt);
+ rowIt.close();
+ return maxUpdatedAt;
+
+ } finally {
+ dbSession.close();
+ }
+ }
+
+ public long index(Iterator<ActivityDoc> activities) {
+ final BulkIndexer bulk = new BulkIndexer(esClient, ActivityIndexDefinition.INDEX);
+ return doIndex(bulk, activities);
+ }
+
+ private long doIndex(BulkIndexer bulk, Iterator<ActivityDoc> activities) {
+ long maxUpdatedAt = 0L;
+ bulk.start();
+ while (activities.hasNext()) {
+ ActivityDoc activity = activities.next();
+ bulk.add(newUpsertRequest(activity));
+
+ // it's more efficient to sort programmatically than in SQL on some databases (MySQL for instance)
+ maxUpdatedAt = Math.max(maxUpdatedAt, activity.getCreatedAt().getTime());
+ }
+ bulk.stop();
+ return maxUpdatedAt;
+ }
+
+ private UpdateRequest newUpsertRequest(ActivityDoc doc) {
+ return new UpdateRequest(ActivityIndexDefinition.INDEX, ActivityIndexDefinition.TYPE, doc.getKey())
+ .doc(doc.getFields())
+ .upsert(doc.getFields());
+ }
+}
+++ /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.activity.index;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import org.elasticsearch.action.support.replication.ReplicationType;
-import org.elasticsearch.action.update.UpdateRequest;
-import org.sonar.api.utils.KeyValueFormat;
-import org.sonar.core.activity.db.ActivityDto;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.search.BaseNormalizer;
-import org.sonar.server.search.IndexField;
-import org.sonar.server.search.Indexable;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @since 4.4
- */
-public class ActivityNormalizer extends BaseNormalizer<ActivityDto, String> {
-
- public static final class LogFields extends Indexable {
-
- public static final IndexField KEY = add(IndexField.Type.STRING, "key");
- public static final IndexField TYPE = addSortable(IndexField.Type.STRING, "type");
- public static final IndexField ACTION = addSortable(IndexField.Type.STRING, "action");
- public static final IndexField CREATED_AT = addSortable(IndexField.Type.DATE, "createdAt");
- public static final IndexField UPDATED_AT = addSortable(IndexField.Type.DATE, BaseNormalizer.UPDATED_AT_FIELD);
- public static final IndexField LOGIN = addSearchable(IndexField.Type.STRING, "login");
- public static final IndexField DETAILS = addSearchable(IndexField.Type.OBJECT, "details");
- public static final IndexField MESSAGE = addSearchable(IndexField.Type.STRING, "message");
- public static final Set<IndexField> ALL_FIELDS = ImmutableSet.of(KEY, TYPE, ACTION, CREATED_AT, UPDATED_AT, LOGIN, DETAILS, MESSAGE);
- }
-
- public ActivityNormalizer(DbClient db) {
- super(db);
- }
-
- @Override
- public List<UpdateRequest> normalize(ActivityDto dto) {
-
- Map<String, Object> logDoc = new HashMap<String, Object>();
- logDoc.put(LogFields.KEY.field(), dto.getKey());
- logDoc.put(LogFields.TYPE.field(), dto.getType());
- logDoc.put(LogFields.ACTION.field(), dto.getAction());
- logDoc.put(LogFields.LOGIN.field(), dto.getAuthor());
- logDoc.put(LogFields.MESSAGE.field(), dto.getMessage());
- logDoc.put(LogFields.CREATED_AT.field(), dto.getCreatedAt());
- logDoc.put(LogFields.UPDATED_AT.field(), dto.getUpdatedAt());
-
- logDoc.put(LogFields.DETAILS.field(), KeyValueFormat.parse(dto.getData()));
-
- /* Creating updateRequest */
- return ImmutableList.of(new UpdateRequest()
- .id(dto.getKey())
- .replicationType(ReplicationType.ASYNC)
- .doc(logDoc)
- .upsert(logDoc));
- }
-}
*/
package org.sonar.server.activity.index;
-import com.google.common.collect.Lists;
-import org.sonar.core.activity.Activity;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Map;
-/**
- * @since 4.4
- */
public class ActivityQuery {
private Date since;
private Date to;
- private Collection<Activity.Type> types;
-
- public ActivityQuery() {
- types = Lists.newArrayList();
- }
+ private final Collection<String> types = new ArrayList<>();
+ private final Map<String, Object> dataOrFilters = new LinkedHashMap<>();
+ @CheckForNull
public Date getSince() {
return since;
}
- public ActivityQuery setSince(Date since) {
+ public ActivityQuery setSince(@Nullable Date since) {
this.since = since;
return this;
}
+ @CheckForNull
public Date getTo() {
return to;
}
- public ActivityQuery setTo(Date to) {
+ public ActivityQuery setTo(@Nullable Date to) {
this.to = to;
return this;
}
- public Collection<Activity.Type> getTypes() {
+ public Collection<String> getTypes() {
return types;
}
- public ActivityQuery setTypes(Collection<Activity.Type> types) {
- this.types = types;
+ public ActivityQuery setTypes(@Nullable Collection<String> types) {
+ this.types.clear();
+ if (types != null) {
+ this.types.addAll(types);
+ }
+ return this;
+ }
+
+ public Map<String, Object> getDataOrFilters() {
+ return dataOrFilters;
+ }
+
+ public ActivityQuery addDataOrFilter(String dataKey, Object dataValue) {
+ dataOrFilters.put(dataKey, dataValue);
return this;
}
}
--- /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.activity.index;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.db.ResultSetIterator;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.HashMap;
+
+/**
+ * Scrolls over table ACTIVITIES and reads documents to populate
+ * the index "activities/activity"
+ */
+class ActivityResultSetIterator extends ResultSetIterator<ActivityDoc> {
+
+ private static final String[] FIELDS = {
+ // column 1
+ "log_key",
+ "log_action",
+ "log_message",
+ "data_field",
+ "user_login",
+ "log_type",
+ "created_at"
+ };
+
+ private static final String SQL_ALL = "select " + StringUtils.join(FIELDS, ",") + " from activities ";
+
+ private static final String SQL_AFTER_DATE = SQL_ALL + " where created_at>=?";
+
+ private ActivityResultSetIterator(PreparedStatement stmt) throws SQLException {
+ super(stmt);
+ }
+
+ static ActivityResultSetIterator create(DbClient dbClient, Connection connection, long afterDate) {
+ try {
+ String sql = afterDate > 0L ? SQL_AFTER_DATE : SQL_ALL;
+ PreparedStatement stmt = dbClient.newScrollingSelectStatement(connection, sql);
+ if (afterDate > 0L) {
+ stmt.setTimestamp(1, new Timestamp(afterDate));
+ }
+ return new ActivityResultSetIterator(stmt);
+ } catch (SQLException e) {
+ throw new IllegalStateException("Fail to prepare SQL request to select activities", e);
+ }
+ }
+
+ @Override
+ protected ActivityDoc read(ResultSet rs) throws SQLException {
+ ActivityDoc doc = new ActivityDoc(new HashMap<String, Object>(10));
+
+ // all the fields must be present, even if value is null
+ doc.setKey(rs.getString(1));
+ doc.setAction(rs.getString(2));
+ doc.setMessage(rs.getString(3));
+ doc.setDetails(KeyValueFormat.parse(rs.getString(4)));
+ doc.setLogin(rs.getString(5));
+ doc.setType(rs.getString(6));
+ doc.setCreatedAt(rs.getTimestamp(7));
+ return doc;
+ }
+}
package org.sonar.server.activity.ws;
import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.core.activity.Activity;
import org.sonar.server.activity.index.ActivityDoc;
-import org.sonar.server.activity.index.ActivityNormalizer;
+import org.sonar.server.activity.index.ActivityIndexDefinition;
import org.sonar.server.search.QueryContext;
import org.sonar.server.search.ws.BaseMapping;
public class ActivityMapping extends BaseMapping<ActivityDoc, Object> {
public ActivityMapping() {
- map("type", ActivityNormalizer.LogFields.TYPE.field());
- map("action", ActivityNormalizer.LogFields.ACTION.field());
- mapDateTime("createdAt", ActivityNormalizer.LogFields.CREATED_AT.field());
- map("login", ActivityNormalizer.LogFields.LOGIN.field());
- map("message", ActivityNormalizer.LogFields.MESSAGE.field());
- map("details", new IndexMapper<ActivityDoc, Object>(ActivityNormalizer.LogFields.DETAILS.field()) {
+ map("type", ActivityIndexDefinition.FIELD_TYPE);
+ map("action", ActivityIndexDefinition.FIELD_ACTION);
+ mapDateTime("createdAt", ActivityIndexDefinition.FIELD_CREATED_AT);
+ map("login", ActivityIndexDefinition.FIELD_LOGIN);
+ map("message", ActivityIndexDefinition.FIELD_MESSAGE);
+ map("details", new IndexMapper<ActivityDoc, Object>(ActivityIndexDefinition.FIELD_DETAILS) {
@Override
public void write(JsonWriter json, ActivityDoc activity, Object context) {
json.name("details").beginObject();
- for (Map.Entry<String, String> detail : activity.details().entrySet()) {
+ for (Map.Entry<String, String> detail : activity.getDetails().entrySet()) {
json.prop(detail.getKey(), detail.getValue());
}
json.endObject();
});
}
- public void write(Activity activity, JsonWriter writer, QueryContext context) {
- doWrite((ActivityDoc) activity, null, writer, context);
+ public void write(ActivityDoc activity, JsonWriter writer, QueryContext context) {
+ doWrite(activity, null, writer, context);
}
}
*/
package org.sonar.server.activity.ws;
-import org.apache.commons.lang.StringUtils;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.RequestHandler;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.core.activity.Activity;
-import org.sonar.server.activity.ActivityService;
+import org.sonar.server.activity.Activity;
+import org.sonar.server.activity.index.ActivityDoc;
+import org.sonar.server.activity.index.ActivityIndex;
import org.sonar.server.activity.index.ActivityQuery;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
-import org.sonar.server.search.ws.SearchOptions;
-/**
- * @since 4.4
- */
public class SearchAction implements RequestHandler {
public static final String PARAM_TYPE = "type";
-
public static final String SEARCH_ACTION = "search";
- private final ActivityService logService;
- private final ActivityMapping mapping;
+ private final ActivityIndex activityIndex;
+ private final ActivityMapping docToJsonMapping;
- public SearchAction(ActivityService logService, ActivityMapping mapping) {
- this.logService = logService;
- this.mapping = mapping;
+ public SearchAction(ActivityIndex activityIndex, ActivityMapping docToJsonMapping) {
+ this.activityIndex = activityIndex;
+ this.docToJsonMapping = docToJsonMapping;
}
void define(WebService.NewController controller) {
.setInternal(true)
.setHandler(this);
- // Other parameters
action.createParam(PARAM_TYPE)
- .setDescription("Types of activities to search")
- .setPossibleValues(Activity.Type.values())
- .setDefaultValue(StringUtils.join(Activity.Type.values(), ","));
+ .setDescription("Activity type")
+ .setPossibleValues(Activity.Type.values());
- // Generic search parameters
- SearchOptions.defineFieldsParam(action, mapping.supportedFields());
-
- SearchOptions.definePageParams(action);
+ action.addPagingParams(10);
+ action.addFieldsParam(docToJsonMapping.supportedFields());
}
@Override
public void handle(Request request, Response response) {
- ActivityQuery query = logService.newActivityQuery();
- SearchOptions searchOptions = SearchOptions.create(request);
- QueryContext queryContext = mapping.newQueryOptions(searchOptions);
+ ActivityQuery query = new ActivityQuery();
+ query.setTypes(request.paramAsStrings(PARAM_TYPE));
+
+ SearchOptions options = new SearchOptions();
+ options.setPage(request.mandatoryParamAsInt(WebService.Param.PAGE), request.mandatoryParamAsInt(WebService.Param.PAGE_SIZE));
- Result<Activity> results = logService.search(query, queryContext);
+ SearchResult<ActivityDoc> results = activityIndex.search(query, options);
JsonWriter json = response.newJsonWriter().beginObject();
- searchOptions.writeStatistics(json, results);
- writeLogs(results, json, queryContext);
+ options.writeJson(json, results.getTotal());
+ writeActivities(results, json, new QueryContext().setFieldsToReturn(request.paramAsStrings(WebService.Param.FIELDS)));
json.endObject().close();
}
- private void writeLogs(Result<Activity> result, JsonWriter json, QueryContext context) {
+ private void writeActivities(SearchResult<ActivityDoc> docs, JsonWriter json, QueryContext context) {
json.name("logs").beginArray();
- for (Activity log : result.getHits()) {
- mapping.write(log, json, context);
+ for (ActivityDoc doc : docs.getDocs()) {
+ docToJsonMapping.write(doc, json, context);
}
json.endArray();
}
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.batch.protocol.output.BatchReportReader;
-import org.sonar.core.activity.Activity;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.computation.db.AnalysisReportDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.activity.Activity;
import org.sonar.server.activity.ActivityService;
import org.sonar.server.computation.step.ComputationStep;
import org.sonar.server.computation.step.ComputationSteps;
import java.io.File;
import java.io.IOException;
+import static org.sonar.api.utils.DateUtils.formatDateTimeNullSafe;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
public class ComputationService implements ServerComponent {
private static final Logger LOG = Loggers.get(ComputationService.class);
} finally {
item.dto.setFinishedAt(system.now());
- logActivity(item.dto, project);
+ saveActivity(item.dto, project);
profiler.stopInfo();
}
}
}
}
- private void logActivity(AnalysisReportDto report, ComponentDto project) {
- DbSession session = dbClient.openSession(false);
- try {
- report.setFinishedAt(System2.INSTANCE.now());
- activityService.write(session, Activity.Type.ANALYSIS_REPORT, new ReportActivity(report, project));
- session.commit();
- } finally {
- MyBatis.closeQuietly(session);
- }
+ private void saveActivity(AnalysisReportDto report, ComponentDto project) {
+ Activity activity = new Activity();
+ activity.setType(Activity.Type.ANALYSIS_REPORT);
+ activity.setAction("LOG_ANALYSIS_REPORT");
+ activity
+ .setData("key", String.valueOf(report.getId()))
+ .setData("projectKey", project.key())
+ .setData("projectName", project.name())
+ .setData("projectUuid", project.uuid())
+ .setData("status", String.valueOf(report.getStatus()))
+ .setData("submittedAt", formatDateTimeNullSafe(longToDate(report.getCreatedAt())))
+ .setData("startedAt", formatDateTimeNullSafe(longToDate(report.getStartedAt())))
+ .setData("finishedAt", formatDateTimeNullSafe(longToDate(report.getFinishedAt())));
+ activityService.save(activity);
}
}
+++ /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;
-
-import com.google.common.collect.ImmutableMap;
-import org.sonar.core.activity.ActivityLog;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.computation.db.AnalysisReportDto;
-
-import java.util.Map;
-
-import static org.sonar.api.utils.DateUtils.formatDateTimeNullSafe;
-import static org.sonar.api.utils.DateUtils.longToDate;
-
-public class ReportActivity implements ActivityLog {
-
- private static final String ACTION = "LOG_ANALYSIS_REPORT";
-
- private final AnalysisReportDto report;
- private final ComponentDto project;
-
- public ReportActivity(AnalysisReportDto report, ComponentDto project) {
- this.report = report;
- this.project = project;
- }
-
- @Override
- public Map<String, String> getDetails() {
- return ImmutableMap.<String, String>builder()
- .put("key", String.valueOf(report.getId()))
- .put("projectKey", project.key())
- .put("projectName", project.name())
- .put("projectUuid", project.uuid())
- .put("status", String.valueOf(report.getStatus()))
- .put("submittedAt", formatDateTimeNullSafe(longToDate(report.getCreatedAt())))
- .put("startedAt", formatDateTimeNullSafe(longToDate(report.getStartedAt())))
- .put("finishedAt", formatDateTimeNullSafe(longToDate(report.getFinishedAt())))
- .build();
- }
-
- @Override
- public String getAction() {
- return ACTION;
- }
-}
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.core.activity.Activity;
import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.server.activity.ActivityService;
+import org.sonar.server.activity.Activity;
+import org.sonar.server.activity.index.ActivityDoc;
+import org.sonar.server.activity.index.ActivityIndex;
import org.sonar.server.activity.index.ActivityQuery;
-import org.sonar.server.activity.ws.ActivityMapping;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
-import org.sonar.server.search.ws.SearchOptions;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
+import org.sonar.server.issue.ws.IssuesWs;
import org.sonar.server.user.UserSession;
import java.util.Arrays;
import java.util.Map;
+// FIXME replace by api/activities/search
public class HistoryWsAction implements ComputationWsAction, RequestHandler {
public static final String PARAM_TYPE = "type";
- private final ActivityService activityService;
- private final ActivityMapping mapping;
+ private final ActivityIndex activityIndex;
- public HistoryWsAction(ActivityService activityService, ActivityMapping mapping) {
- this.activityService = activityService;
- this.mapping = mapping;
+ public HistoryWsAction(ActivityIndex activityIndex) {
+ this.activityIndex = activityIndex;
}
@Override
.setInternal(true)
.setHandler(this);
- // Generic search parameters
- SearchOptions.defineFieldsParam(action, mapping.supportedFields());
- SearchOptions.definePageParams(action);
+ action.addPagingParams(10);
}
@Override
public void handle(Request request, Response response) {
- checkUserRights();
-
- ActivityQuery query = activityService.newActivityQuery();
- query.setTypes(Arrays.asList(Activity.Type.ANALYSIS_REPORT));
+ UserSession.get().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
- SearchOptions searchOptions = SearchOptions.create(request);
- QueryContext queryContext = mapping.newQueryOptions(searchOptions);
+ ActivityQuery query = new ActivityQuery();
+ query.setTypes(Arrays.asList(Activity.Type.ANALYSIS_REPORT.name()));
- Result<Activity> results = activityService.search(query, queryContext);
+ SearchOptions options = new SearchOptions();
+ options.setPage(request.mandatoryParamAsInt(IssuesWs.Param.PAGE), request.mandatoryParamAsInt(IssuesWs.Param.PAGE_SIZE));
+ SearchResult<ActivityDoc> results = activityIndex.search(query, options);
JsonWriter json = response.newJsonWriter().beginObject();
- searchOptions.writeStatistics(json, results);
+ options.writeJson(json, results.getTotal());
writeReports(results, json);
json.endObject().close();
}
- private void checkUserRights() {
- UserSession.get().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
- }
-
- private void writeReports(Result<Activity> result, JsonWriter json) {
+ private void writeReports(SearchResult<ActivityDoc> result, JsonWriter json) {
json.name("reports").beginArray();
- for (Activity reportActivity : result.getHits()) {
+ for (ActivityDoc doc : result.getDocs()) {
json.beginObject();
- for (Map.Entry<String, String> detail : reportActivity.details().entrySet()) {
+ for (Map.Entry<String, String> detail : doc.getDetails().entrySet()) {
json.prop(detail.getKey(), detail.getValue());
}
json.endObject();
import org.apache.commons.lang.StringUtils;
import org.sonar.api.rule.RuleKey;
-import org.sonar.core.activity.Activity;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.api.utils.internal.Uuids;
import org.sonar.core.activity.db.ActivityDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.migration.v44.ChangeLog;
import org.sonar.core.persistence.migration.v44.Migration44Mapper;
import org.sonar.core.qualityprofile.db.ActiveRuleKey;
import org.sonar.core.rule.SeverityUtil;
+import org.sonar.server.activity.Activity;
import org.sonar.server.activity.db.ActivityDao;
import org.sonar.server.db.DbClient;
import org.sonar.server.db.migrations.DatabaseMigration;
}
private void saveActiveRuleChange(DbSession session, ActiveRuleChange ruleChange, String author, Date currentTimeStamp) {
- ActivityDto activity = ActivityDto.createFor(ruleChange);
- activity.setType(Activity.Type.QPROFILE);
- activity.setAuthor(author);
- activity.setCreatedAt(currentTimeStamp);
- dao.insert(session, activity);
+ Activity activity = ruleChange.toActivity();
+ ActivityDto dto = new ActivityDto();
+ dto.setKey(Uuids.create());
+ dto.setType(Activity.Type.QPROFILE.name());
+ dto.setAction(activity.getAction());
+ dto.setMessage(activity.getMessage());
+ dto.setAuthor(author);
+ dto.setData(KeyValueFormat.format(activity.getData()));
+ dto.setCreatedAt(currentTimeStamp);
+ dao.insert(session, dto);
}
private void processRuleChange(ActiveRuleChange ruleChange, ChangeLog change) {
return setProperty(fieldName, ImmutableMap.of("type", "long"));
}
+ public NewIndexType createDynamicNestedField(String fieldName) {
+ return setProperty(fieldName, ImmutableMap.of("type", "nested", "dynamic", "true"));
+ }
+
public NewIndexType createShortField(String fieldName) {
return setProperty(fieldName, ImmutableMap.of("type", "short"));
}
String key = rs.getString(1);
String projectUuid = rs.getString(2);
- // all the keys must be present, even if value is null
+ // all the fields must be present, even if value is null
doc.setKey(key);
doc.setProjectUuid(projectUuid);
doc.setTechnicalUpdateDate(new Date(rs.getLong(3)));
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import java.util.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
@Override
public final void handle(Request request, Response response) throws Exception {
SearchOptions options = new SearchOptions();
- options.setPage(request.mandatoryParamAsInt(IssuesWs.Param.PAGE), request.mandatoryParamAsInt(IssuesWs.Param.PAGE_SIZE));
+ options.setPage(request.mandatoryParamAsInt(WebService.Param.PAGE), request.mandatoryParamAsInt(WebService.Param.PAGE_SIZE));
options.addFacets(request.paramAsStrings(WebService.Param.FACETS));
IssueQuery query = issueQueryService.createFromRequest(request);
import org.sonar.server.activity.RubyQProfileActivityService;
import org.sonar.server.activity.db.ActivityDao;
import org.sonar.server.activity.index.ActivityIndex;
-import org.sonar.server.activity.index.ActivityNormalizer;
+import org.sonar.server.activity.index.ActivityIndexDefinition;
+import org.sonar.server.activity.index.ActivityIndexer;
import org.sonar.server.activity.ws.ActivitiesWebService;
import org.sonar.server.activity.ws.ActivityMapping;
import org.sonar.server.authentication.ws.AuthenticationWs;
IssueIndex.class,
IssueDao.class,
- // Activity
- ActivityService.class,
- ActivityNormalizer.class,
- ActivityIndex.class,
ActivityDao.class
));
components.addAll(CorePropertyDefinitions.all());
pico.addSingleton(IndexRegistry.class);
pico.addSingleton(IndexCreator.class);
+ // Activity
+ pico.addSingleton(ActivityService.class);
+ pico.addSingleton(ActivityIndexDefinition.class);
+ pico.addSingleton(ActivityIndexer.class);
+ pico.addSingleton(ActivityIndex.class);
+
// batch
pico.addSingleton(BatchIndex.class);
pico.addSingleton(GlobalRepositoryAction.class);
import com.google.common.base.Objects;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
-import org.sonar.core.activity.ActivityLog;
import org.sonar.core.qualityprofile.db.ActiveRuleKey;
+import org.sonar.server.activity.Activity;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import java.util.HashMap;
import java.util.Map;
-public class ActiveRuleChange implements ActivityLog {
+public class ActiveRuleChange {
public static enum Type {
ACTIVATED, DEACTIVATED, UPDATED
return this;
}
- @Override
- public Map<String, String> getDetails() {
- HashMap<String, String> details = new HashMap<String, String>();
-
- details.put("key", getKey().toString());
- details.put("ruleKey", getKey().ruleKey().toString());
- details.put("profileKey", getKey().qProfile().toString());
+ public Activity toActivity() {
+ Activity activity = new Activity();
+ activity.setType(Activity.Type.QPROFILE);
+ activity.setAction(type.name());
+ activity.setData("key", getKey().toString());
+ activity.setData("ruleKey", getKey().ruleKey().toString());
+ activity.setData("profileKey", getKey().qProfile().toString());
for (Map.Entry<String, String> param : parameters.entrySet()) {
if (!param.getKey().isEmpty()) {
- details.put("param_" + param.getKey(), param.getValue());
+ activity.setData("param_" + param.getKey(), param.getValue());
}
}
if (StringUtils.isNotEmpty(severity)) {
- details.put("severity", severity);
+ activity.setData("severity", severity);
}
if (inheritance != null) {
- details.put("inheritance", inheritance.name());
+ activity.setData("inheritance", inheritance.name());
}
- return details;
+ return activity;
}
public static ActiveRuleChange createFor(Type type, ActiveRuleKey key) {
.add("parameters", parameters)
.toString();
}
-
- @Override
- public String getAction() {
- return type.name();
- }
}
import com.google.common.collect.Maps;
import org.sonar.api.rule.RuleKey;
-import org.sonar.core.activity.Activity;
import org.sonar.server.activity.index.ActivityDoc;
-import org.sonar.server.activity.index.ActivityNormalizer;
+import org.sonar.server.activity.index.ActivityIndexDefinition;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-
import java.util.Map;
/**
* @since 4.4
*/
-public class QProfileActivity extends ActivityDoc implements Activity {
+public class QProfileActivity extends ActivityDoc {
private String ruleName = null;
private String authorName = null;
@Override
@CheckForNull
- public String login() {
- return getNullableField(ActivityNormalizer.LogFields.LOGIN.field());
+ public String getLogin() {
+ return getNullableField(ActivityIndexDefinition.FIELD_LOGIN);
}
@CheckForNull
*/
package org.sonar.server.qualityprofile;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import org.sonar.core.activity.Activity;
+import org.sonar.server.activity.Activity;
import org.sonar.server.activity.index.ActivityQuery;
-import java.util.Collection;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import java.util.Arrays;
/**
* @since 4.4
*/
public class QProfileActivityQuery extends ActivityQuery {
- Collection<String> qprofileKeys;
-
public QProfileActivityQuery() {
super();
- this.setTypes(ImmutableSet.of(Activity.Type.QPROFILE));
- qprofileKeys = Lists.newArrayList();
+ setTypes(Arrays.asList(Activity.Type.QPROFILE.name()));
}
- public Collection<String> getQprofileKeys() {
- return qprofileKeys;
+ @CheckForNull
+ public String getQprofileKey() {
+ return (String)getDataOrFilters().get("profileKey");
}
- public QProfileActivityQuery setQprofileKeys(Collection<String> qprofileKeys) {
- this.qprofileKeys = qprofileKeys;
+ public QProfileActivityQuery setQprofileKey(@Nullable String qprofileKey) {
+ addDataOrFilter("profileKey", qprofileKey);
return this;
}
}
package org.sonar.server.qualityprofile;
import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.index.query.FilterBuilders;
-import org.elasticsearch.index.query.OrFilterBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.sonar.api.ServerComponent;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.user.UserDto;
import org.sonar.server.activity.index.ActivityIndex;
import org.sonar.server.db.DbClient;
+import org.sonar.server.es.SearchOptions;
import org.sonar.server.rule.index.RuleQuery;
-import org.sonar.server.search.IndexClient;
-import org.sonar.server.search.QueryContext;
import org.sonar.server.search.Result;
import org.sonar.server.user.UserSession;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
public class QProfileService implements ServerComponent {
private final DbClient db;
- private final IndexClient index;
+ private final ActivityIndex activityIndex;
private final RuleActivator ruleActivator;
private final QProfileFactory factory;
private final QProfileBackuper backuper;
private final QProfileReset reset;
private final QProfileExporters exporters;
- public QProfileService(DbClient db, IndexClient index, RuleActivator ruleActivator, QProfileFactory factory,
+ public QProfileService(DbClient db, ActivityIndex activityIndex, RuleActivator ruleActivator, QProfileFactory factory,
QProfileBackuper backuper, QProfileCopier copier, QProfileReset reset, QProfileExporters exporters) {
this.db = db;
- this.index = index;
+ this.activityIndex = activityIndex;
this.ruleActivator = ruleActivator;
this.factory = factory;
this.backuper = backuper;
UserSession.get().checkGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN);
}
- public Result<QProfileActivity> searchActivities(QProfileActivityQuery query, QueryContext options) {
+ public Result<QProfileActivity> searchActivities(QProfileActivityQuery query, SearchOptions options) {
DbSession session = db.openSession(false);
try {
- OrFilterBuilder activityFilter = FilterBuilders.orFilter();
- for (String profileKey : query.getQprofileKeys()) {
- activityFilter.add(FilterBuilders.nestedFilter("details",
- QueryBuilders.matchQuery("details.profileKey", profileKey)));
- }
-
- SearchResponse response = index.get(ActivityIndex.class).search(query, options, activityFilter);
+ SearchResponse response = activityIndex.doSearch(query, options);
Result<QProfileActivity> result = new Result<QProfileActivity>(response);
for (SearchHit hit : response.getHits().getHits()) {
QProfileActivity profileActivity = new QProfileActivity(hit.getSource());
RuleDto ruleDto = db.ruleDao().getNullableByKey(session, profileActivity.ruleKey());
profileActivity.ruleName(ruleDto != null ? ruleDto.getName() : null);
- String login = profileActivity.login();
+ String login = profileActivity.getLogin();
if (login != null) {
UserDto user = db.userDao().selectActiveUserByLogin(login, session);
profileActivity.authorName(user != null ? user.getName() : null);
import com.google.common.collect.Lists;
import org.sonar.api.ServerComponent;
import org.sonar.api.server.rule.RuleParamType;
-import org.sonar.core.activity.Activity;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.qualityprofile.db.ActiveRuleDto;
import org.sonar.core.qualityprofile.db.ActiveRuleKey;
private final TypeValidations typeValidations;
private final RuleActivatorContextFactory contextFactory;
private final IndexClient index;
- private final ActivityService log;
+ private final ActivityService activityService;
public RuleActivator(DbClient db, IndexClient index,
RuleActivatorContextFactory contextFactory, TypeValidations typeValidations,
- ActivityService log) {
+ ActivityService activityService) {
this.db = db;
this.index = index;
this.contextFactory = contextFactory;
this.typeValidations = typeValidations;
- this.log = log;
+ this.activityService = activityService;
}
public List<ActiveRuleChange> activate(DbSession dbSession, RuleActivation activation, String profileKey) {
} else if (change.getType() == ActiveRuleChange.Type.UPDATED) {
activeRule = doUpdate(change, context, dbSession);
}
- log.write(dbSession, Activity.Type.QPROFILE, change);
+ activityService.save(change.toActivity());
return activeRule;
}
import java.io.Serializable;
import java.util.*;
+/**
+ * @deprecated replaced by {@link org.sonar.server.es.BaseIndex}
+ */
+@Deprecated
public abstract class BaseIndex<DOMAIN, DTO extends Dto<KEY>, KEY extends Serializable>
implements Index<DOMAIN, DTO, KEY> {
protected abstract String getKeyValue(KEY key);
public final Settings getIndexSettings() {
- ImmutableSettings.Builder settings = this.addCustomIndexSettings(this.getBaseIndexSettings());
+ ImmutableSettings.Builder settings = this.getBaseIndexSettings();
// In case there is a replication factor set by the index,
// it is removed since we're using global cluster state
return settings.build();
}
- protected ImmutableSettings.Builder addCustomIndexSettings(ImmutableSettings.Builder baseIndexSettings) {
- return baseIndexSettings;
- }
-
protected abstract Map mapProperties();
protected abstract Map mapKey();
public static final IndexDefinition RULE = new IndexDefinition("rules", "rule");
public static final IndexDefinition ACTIVE_RULE = new IndexDefinition("rules", "activeRule");
public static final IndexDefinition ISSUES = new IndexDefinition("issues", "issue");
- public static final IndexDefinition LOG = new IndexDefinition("logs", "sonarLog");
// Only used for test
static final IndexDefinition TEST = new IndexDefinition("test", "test");
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.persistence.DbSession;
-import org.sonar.server.activity.index.ActivityIndex;
+import org.sonar.server.activity.index.ActivityIndexer;
import org.sonar.server.db.Dao;
import org.sonar.server.db.DbClient;
import org.sonar.server.issue.index.IssueAuthorizationIndexer;
private final IssueIndexer issueIndexer;
private final UserIndexer userIndexer;
private final ViewIndexer viewIndexer;
+ private final ActivityIndexer activityIndexer;
public IndexSynchronizer(DbClient db, IndexClient index, SourceLineIndexer sourceLineIndexer,
- IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer, UserIndexer userIndexer, ViewIndexer viewIndexer) {
+ IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer,
+ UserIndexer userIndexer, ViewIndexer viewIndexer, ActivityIndexer activityIndexer) {
this.db = db;
this.index = index;
this.sourceLineIndexer = sourceLineIndexer;
this.issueIndexer = issueIndexer;
this.userIndexer = userIndexer;
this.viewIndexer = viewIndexer;
+ this.activityIndexer = activityIndexer;
}
public void execute() {
try {
synchronize(session, db.ruleDao(), index.get(RuleIndex.class));
synchronize(session, db.activeRuleDao(), index.get(ActiveRuleIndex.class));
- synchronize(session, db.activityDao(), index.get(ActivityIndex.class));
session.commit();
} finally {
session.close();
}
+ LOG.info("Index activities");
+ activityIndexer.index();
+
LOG.info("Index issues");
issueAuthorizationIndexer.index();
issueIndexer.index();
+++ /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.activity;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import org.elasticsearch.action.search.SearchResponse;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.core.activity.Activity;
-import org.sonar.core.activity.ActivityLog;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.server.activity.db.ActivityDao;
-import org.sonar.server.activity.index.ActivityIndex;
-import org.sonar.server.activity.index.ActivityQuery;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.platform.Platform;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
-import org.sonar.server.tester.ServerTester;
-
-import java.util.Iterator;
-import java.util.Map;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ActivityBackendMediumTest {
-
- @ClassRule
- public static ServerTester tester = new ServerTester();
-
- ActivityService service = tester.get(ActivityService.class);
- ActivityDao dao = tester.get(ActivityDao.class);
- ActivityIndex index = tester.get(ActivityIndex.class);
- DbSession dbSession;
-
- @Before
- public void before() {
- tester.clearDbAndIndexes();
- dbSession = tester.get(DbClient.class).openSession(false);
- }
-
- @After
- public void after() {
- dbSession.close();
- }
-
- @Test
- public void insert_find_text_log() throws InterruptedException {
- final String testValue = "hello world";
- service.write(dbSession, Activity.Type.QPROFILE, testValue);
- dbSession.commit();
- assertThat(index.findAll().getTotal()).isEqualTo(1);
-
- Activity activity = Iterables.getFirst(index.findAll().getHits(), null);
- assertThat(activity).isNotNull();
- assertThat(activity.message()).isEqualTo(testValue);
- }
-
- @Test
- public void insert_find_loggable_log() {
- final String testKey = "message";
- final String testValue = "hello world";
- service.write(dbSession, Activity.Type.QPROFILE, new ActivityLog() {
-
- @Override
- public Map<String, String> getDetails() {
- return ImmutableMap.of(testKey, testValue);
- }
-
- @Override
- public String getAction() {
- return "myAction";
- }
- });
- dbSession.commit();
-
- assertThat(index.findAll().getTotal()).isEqualTo(1);
-
- Activity activity = Iterables.getFirst(index.findAll().getHits(), null);
- assertThat(activity).isNotNull();
- assertThat(activity.details().get(testKey)).isEqualTo(testValue);
- }
-
- @Test
- public void current_time_zone() {
- service.write(dbSession, Activity.Type.QPROFILE, "now");
- dbSession.commit();
-
- Activity activity = service.search(new ActivityQuery(), new QueryContext()).getHits().get(0);
- assertThat(System.currentTimeMillis() - activity.time().getTime()).isLessThan(1000L);
- }
-
- @Test
- public void massive_insert() {
-
- // 0 Assert no logs in DB
- assertThat(dao.findAll(dbSession)).hasSize(0);
- int max = 35;
- final String testValue = "hello world";
- for (int i = 0; i < max; i++) {
-
- service.write(dbSession, Activity.Type.QPROFILE, testValue + "_" + i);
- }
- dbSession.commit();
-
- // 1. assert both backends have all logs
- assertThat(dao.findAll(dbSession)).hasSize(max);
- assertThat(index.findAll().getHits()).hasSize(max);
-
- // 2. assert scrollable
- int count = 0;
- SearchResponse result = index.search(new ActivityQuery(), new QueryContext().setScroll(true));
- Iterator<Activity> logs = new Result<Activity>(index, result).scroll();
- while (logs.hasNext()) {
- logs.next();
- count++;
- }
- assertThat(count).isEqualTo(max);
-
- // 3 assert synchronize above IndexQueue threshold
- tester.clearIndexes();
- tester.get(Platform.class).executeStartupTasks();
- result = index.search(new ActivityQuery(), new QueryContext().setScroll(true));
- logs = new Result<Activity>(index, result).scroll();
- count = 0;
- while (logs.hasNext()) {
- logs.next();
- count++;
- }
- assertThat(count).isEqualTo(max);
-
- }
-
- @Test
- public void massive_log_insert() {
-
- // 0 Assert no logs in DB
- assertThat(dao.findAll(dbSession)).hasSize(0);
- int max = 40;
- final String testValue = "hello world";
- for (int i = 0; i < max; i++) {
- TestActivityLog log = new TestActivityLog(testValue + "_" + i, Activity.Type.QPROFILE.toString());
- service.write(dbSession, Activity.Type.QPROFILE, log);
- }
- dbSession.commit();
-
- // 1. assert both backends have all logs
- assertThat(dao.findAll(dbSession)).hasSize(max);
- assertThat(index.findAll().getHits()).hasSize(max);
-
- // 2. assert scrollable
- int count = 0;
- SearchResponse result = index.search(new ActivityQuery(), new QueryContext().setScroll(true));
- Iterator<Activity> logs = new Result<Activity>(index, result).scroll();
- while (logs.hasNext()) {
- logs.next();
- count++;
- }
- assertThat(count).isEqualTo(max);
-
- // 3 assert synchronize above IndexQueue threshold
- tester.clearIndexes();
- tester.get(Platform.class).executeStartupTasks();
- result = index.search(new ActivityQuery(), new QueryContext().setScroll(true));
- logs = new Result<Activity>(index, result).scroll();
- count = 0;
- while (logs.hasNext()) {
- logs.next();
- count++;
- }
- assertThat(count).isEqualTo(max);
-
- }
-
- class TestActivityLog implements ActivityLog {
-
- private final String name;
- private final String action;
-
- TestActivityLog(String name, String action) {
- this.name = name;
- this.action = action;
- }
-
- @Override
- public Map<String, String> getDetails() {
- return ImmutableMap.<String, String>of("name", name);
- }
-
- @Override
- public String getAction() {
- return action;
- }
- }
-}
+++ /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.activity;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import org.elasticsearch.action.search.SearchResponse;
-import org.joda.time.DateTime;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.core.activity.Activity;
-import org.sonar.core.activity.ActivityLog;
-import org.sonar.core.activity.db.ActivityDto;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.server.activity.db.ActivityDao;
-import org.sonar.server.activity.index.ActivityIndex;
-import org.sonar.server.activity.index.ActivityQuery;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
-import org.sonar.server.tester.ServerTester;
-
-import java.util.Iterator;
-import java.util.Map;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ActivityServiceMediumTest {
-
- @ClassRule
- public static ServerTester tester = new ServerTester();
-
- ActivityService service = tester.get(ActivityService.class);
- ActivityDao dao = tester.get(ActivityDao.class);
- ActivityIndex index = tester.get(ActivityIndex.class);
- DbSession dbSession;
-
- @Before
- public void before() {
- tester.clearDbAndIndexes();
- dbSession = tester.get(DbClient.class).openSession(false);
- }
-
- @After
- public void after() {
- dbSession.close();
- }
-
- @Test
- public void find_all() throws InterruptedException {
- service.write(dbSession, Activity.Type.QPROFILE, testValue);
- dbSession.commit();
- assertThat(index.findAll().getTotal()).isEqualTo(1);
-
- Activity activity = Iterables.getFirst(index.findAll().getHits(), null);
- assertThat(activity).isNotNull();
- assertThat(activity.message()).isEqualTo(testValue);
- }
-
- @Test
- public void search_message_log() throws InterruptedException {
- service.write(dbSession, Activity.Type.QPROFILE, testValue);
- dbSession.commit();
- assertThat(index.findAll().getTotal()).isEqualTo(1);
-
- SearchResponse result = index.search(service.newActivityQuery(), new QueryContext());
- assertThat(result.getHits().getTotalHits()).isEqualTo(1L);
- Result<Activity> activityResult = new Result<Activity>(index, result);
- assertThat(activityResult.getHits().get(0).message()).isEqualTo(testValue);
- }
-
- @Test
- public void search_activity_log() throws InterruptedException {
-
- service.write(dbSession, Activity.Type.QPROFILE, getActivity());
- dbSession.commit();
- assertThat(index.findAll().getTotal()).isEqualTo(1);
-
- SearchResponse result = index.search(service.newActivityQuery(), new QueryContext());
- assertThat(result.getHits().getTotalHits()).isEqualTo(1L);
- Result<Activity> activityResult = new Result<Activity>(index, result);
- assertThat(activityResult.getHits().get(0).details().get(test_key)).isEqualTo(test_value);
- }
-
- @Test
- public void filter_by_type() {
- service.write(dbSession, Activity.Type.NONE, getActivity());
- service.write(dbSession, Activity.Type.SERVER, getActivity());
- service.write(dbSession, Activity.Type.SERVER, testValue);
- service.write(dbSession, Activity.Type.QPROFILE, getActivity());
- dbSession.commit();
-
- assertThat(service.search(new ActivityQuery(),
- new QueryContext()).getHits()).hasSize(4);
-
- assertThat(service.search(new ActivityQuery()
- .setTypes(ImmutableSet.of(Activity.Type.SERVER)),
- new QueryContext()).getHits()).hasSize(2);
-
- assertThat(service.search(new ActivityQuery()
- .setTypes(ImmutableSet.of(Activity.Type.QPROFILE)),
- new QueryContext()).getHits()).hasSize(1);
- }
-
- @Test
- public void filter_by_date() throws InterruptedException {
-
- DateTime t0 = new DateTime().minusHours(1);
- ActivityDto activity = getActivityDto();
- activity.setCreatedAt(t0.toDate());
- dao.insert(dbSession, activity);
- activity = getActivityDto();
- activity.setCreatedAt(t0.toDate());
- dao.insert(dbSession, activity);
- dbSession.commit();
- DateTime t1 = new DateTime();
- activity = getActivityDto();
- activity.setCreatedAt(t1.toDate());
- dao.insert(dbSession, activity);
- dbSession.commit();
- DateTime t2 = new DateTime().plusHours(1);
-
- assertThat(service.search(new ActivityQuery(),
- new QueryContext()).getHits()).hasSize(3);
-
- assertThat(service.search(new ActivityQuery()
- .setSince(t0.minusSeconds(5).toDate()),
- new QueryContext()).getHits()).hasSize(3);
-
- assertThat(service.search(new ActivityQuery()
- .setSince(t1.minusSeconds(5).toDate()),
- new QueryContext()).getHits()).hasSize(1);
-
- assertThat(service.search(new ActivityQuery()
- .setSince(t2.minusSeconds(5).toDate()),
- new QueryContext()).getHits()).hasSize(0);
-
- assertThat(service.search(new ActivityQuery()
- .setTo(t1.minusSeconds(5).toDate()),
- new QueryContext()).getHits()).hasSize(2);
-
- assertThat(service.search(new ActivityQuery()
- .setSince(t1.minusSeconds(5).toDate())
- .setTo(t2.plusSeconds(5).toDate()),
- new QueryContext()).getHits()).hasSize(1);
- }
-
- private ActivityDto getActivityDto() {
- return ActivityDto.createFor(testValue)
- .setType(Activity.Type.NONE).setAuthor("testing");
- }
-
- @Test
- public void iterate_all() throws InterruptedException {
- int max = QueryContext.DEFAULT_LIMIT + 3;
- final String testValue = "hello world";
- for (int i = 0; i < max; i++) {
- service.write(dbSession, Activity.Type.QPROFILE, testValue + "_" + i);
- }
- dbSession.commit();
-
- // 0. assert Base case
- assertThat(dao.findAll(dbSession)).hasSize(max);
-
- SearchResponse result = index.search(service.newActivityQuery(), new QueryContext().setScroll(true));
- assertThat(result.getHits().getTotalHits()).isEqualTo(max);
- Result<Activity> activityResult = new Result<Activity>(index, result);
-
- assertThat(activityResult.getTotal()).isEqualTo(max);
- assertThat(activityResult.getHits()).hasSize(0);
- int count = 0;
- Iterator<Activity> logIterator = activityResult.scroll();
- while (logIterator.hasNext()) {
- count++;
- logIterator.next();
- }
- assertThat(count).isEqualTo(max);
- }
-
- final String test_key = "hello";
- final String test_value = "world";
- final String testValue = "hello world";
-
- private ActivityLog getActivity() {
- return new ActivityLog() {
- @Override
- public Map<String, String> getDetails() {
- return ImmutableMap.of(test_key, test_value);
- }
-
- @Override
- public String getAction() {
- return "myAction";
- }
- };
- }
-}
--- /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.activity;
+
+import org.apache.commons.io.IOUtils;
+import org.assertj.core.data.MapEntry;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.activity.db.ActivityDao;
+import org.sonar.server.activity.index.ActivityDoc;
+import org.sonar.server.activity.index.ActivityIndexDefinition;
+import org.sonar.server.activity.index.ActivityIndexer;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.issue.db.IssueDao;
+
+import java.sql.Clob;
+import java.util.List;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ActivityServiceTest {
+
+ @ClassRule
+ public static DbTester db = new DbTester();
+
+ @ClassRule
+ public static EsTester es = new EsTester().addDefinitions(new ActivityIndexDefinition(new Settings()));
+
+ System2 system = mock(System2.class);
+ ActivityService service;
+
+ @Before
+ public void before() {
+ ActivityDao activityDao = new ActivityDao(db.myBatis(), system);
+ IssueDao issueDao = new IssueDao(db.myBatis());
+ DbClient dbClient = new DbClient(db.database(), db.myBatis(), issueDao, activityDao);
+ service = new ActivityService(dbClient, new ActivityIndexer(dbClient, es.client()));
+ }
+
+ @Test
+ public void insert_and_index() throws Exception {
+ when(system.now()).thenReturn(1_500_000_000_000L);
+
+ Activity activity = new Activity();
+ activity.setType(Activity.Type.ANALYSIS_REPORT);
+ activity.setAction("THE_ACTION");
+ activity.setMessage("THE_MSG");
+ activity.setData("foo", "bar");
+ service.save(activity);
+
+ Map<String, Object> dbMap = db.selectFirst("select log_type as \"type\", log_action as \"action\", log_message as \"msg\", data_field as \"data\" from activities");
+ assertThat(dbMap).containsEntry("type", "ANALYSIS_REPORT");
+ assertThat(dbMap).containsEntry("action", "THE_ACTION");
+ assertThat(dbMap).containsEntry("msg", "THE_MSG");
+ Clob data = (Clob) dbMap.get("data");
+ assertThat(IOUtils.toString(data.getAsciiStream())).isEqualTo("foo=bar");
+
+ List<ActivityDoc> docs = es.getDocuments("activities", "activity", ActivityDoc.class);
+ assertThat(docs).hasSize(1);
+ assertThat(docs.get(0).getKey()).isNotEmpty();
+ assertThat(docs.get(0).getAction()).isEqualTo("THE_ACTION");
+ assertThat(docs.get(0).getMessage()).isEqualTo("THE_MSG");
+ assertThat(docs.get(0).getDetails()).containsOnly(MapEntry.entry("foo", "bar"));
+ }
+
+}
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.utils.DateUtils;
-import org.sonar.core.activity.Activity;
+import org.sonar.server.es.SearchOptions;
import org.sonar.server.qualityprofile.QProfileActivity;
import org.sonar.server.qualityprofile.QProfileActivityQuery;
import org.sonar.server.qualityprofile.QProfileService;
-import org.sonar.server.search.QueryContext;
import org.sonar.server.search.Result;
import java.util.Date;
ArgumentCaptor<QProfileActivityQuery> activityArgumentCaptor;
@Captor
- ArgumentCaptor<QueryContext> queryOptionsArgumentCaptor;
+ ArgumentCaptor<SearchOptions> queryOptionsArgumentCaptor;
RubyQProfileActivityService rubyQProfileActivityService;
Result<QProfileActivity> result = mock(Result.class);
when(result.getHits()).thenReturn(Lists.<QProfileActivity>newArrayList());
when(result.getTotal()).thenReturn(10L);
- when(service.searchActivities(any(QProfileActivityQuery.class), any(QueryContext.class))).thenReturn(result);
+ when(service.searchActivities(any(QProfileActivityQuery.class), any(SearchOptions.class))).thenReturn(result);
- rubyQProfileActivityService.search(ImmutableMap.<String, Object>of("profileKeys", "PROFILE_KEY", "since", since, "to", to));
+ rubyQProfileActivityService.search(ImmutableMap.<String, Object>of("profileKey", "PROFILE_KEY", "since", since, "to", to));
verify(service).searchActivities(activityArgumentCaptor.capture(), queryOptionsArgumentCaptor.capture());
assertThat(queryOptionsArgumentCaptor.getValue().getLimit()).isEqualTo(50);
- assertThat(activityArgumentCaptor.getValue().getQprofileKeys()).containsOnly("PROFILE_KEY");
- assertThat(activityArgumentCaptor.getValue().getTypes()).containsOnly(Activity.Type.QPROFILE);
+ assertThat(activityArgumentCaptor.getValue().getQprofileKey()).isEqualTo("PROFILE_KEY");
+ assertThat(activityArgumentCaptor.getValue().getTypes()).containsOnly(Activity.Type.QPROFILE.name());
assertThat(activityArgumentCaptor.getValue().getSince()).isEqualTo(since);
assertThat(activityArgumentCaptor.getValue().getTo()).isEqualTo(to);
}
Result<QProfileActivity> result = mock(Result.class);
when(result.getHits()).thenReturn(Lists.<QProfileActivity>newArrayList());
when(result.getTotal()).thenReturn(10L);
- when(service.searchActivities(any(QProfileActivityQuery.class), any(QueryContext.class))).thenReturn(result);
+ when(service.searchActivities(any(QProfileActivityQuery.class), any(SearchOptions.class))).thenReturn(result);
rubyQProfileActivityService.search(ImmutableMap.<String, Object>of());
assertThat(queryOptionsArgumentCaptor.getValue().getLimit()).isEqualTo(50);
- assertThat(activityArgumentCaptor.getValue().getQprofileKeys()).isEmpty();
+ assertThat(activityArgumentCaptor.getValue().getQprofileKey()).isNull();
assertThat(activityArgumentCaptor.getValue().getSince()).isNull();
assertThat(activityArgumentCaptor.getValue().getTo()).isNull();
}
*/
package org.sonar.server.activity.db;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import org.junit.After;
+import org.apache.commons.io.IOUtils;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.utils.KeyValueFormat;
+import org.junit.experimental.categories.Category;
import org.sonar.api.utils.System2;
-import org.sonar.core.activity.Activity;
-import org.sonar.core.activity.ActivityLog;
import org.sonar.core.activity.db.ActivityDto;
-import org.sonar.core.persistence.AbstractDaoTestCase;
-import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.test.DbTests;
+import java.sql.Clob;
+import java.sql.Timestamp;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@Category(DbTests.class)
+public class ActivityDaoTest {
-public class ActivityDaoTest extends AbstractDaoTestCase {
+ @Rule
+ public DbTester dbTester = new DbTester();
- private ActivityDao dao;
- private DbSession session;
+ System2 system = mock(System2.class);
+ ActivityDao sut;
@Before
public void before() throws Exception {
- this.session = getMyBatis().openSession(false);
- this.dao = new ActivityDao(mock(System2.class));
- }
-
- @After
- public void after() {
- session.close();
- }
-
- @Test
- public void fail_insert_missing_type() {
- String testValue = "hello world";
- ActivityDto log = ActivityDto.createFor(testValue);
- try {
- dao.insert(session, log);
- } catch (IllegalArgumentException e) {
- assertThat(e.getMessage()).isEqualTo("Type must be set");
- }
- }
-
-
- @Test
- public void fail_get_by_key() {
- try {
- dao.getByKey(session, "hello world");
- } catch (IllegalStateException e) {
- assertThat(e.getMessage()).isEqualTo("Cannot execute getByKey on Activities in DB");
- }
- }
-
-
- @Test
- public void fail_insert_missing_author() {
- String testValue = "hello world";
- ActivityDto log = ActivityDto.createFor(testValue)
- .setType(Activity.Type.QPROFILE);
- try {
- dao.insert(session, log);
- } catch (IllegalArgumentException e) {
- assertThat(e.getMessage()).isEqualTo("Type must be set");
- }
- }
-
- @Test
- public void insert_text_log() {
- String testValue = "hello world";
- ActivityDto log = ActivityDto.createFor(testValue)
- .setType(Activity.Type.QPROFILE)
- .setAuthor("jUnit");
- dao.insert(session, log);
-
- ActivityDto newDto = Iterables.getFirst(dao.findAll(session), null);
- assertThat(newDto).isNotNull();
- assertThat(newDto.getAuthor()).isEqualTo(log.getAuthor());
- assertThat(newDto.getMessage()).isEqualTo(testValue);
+ sut = new ActivityDao(dbTester.myBatis(), system);
}
@Test
- public void insert_loggable_log() {
- final String testKey = "message";
- final String testValue = "hello world";
- ActivityDto log = ActivityDto.createFor(new ActivityLog() {
-
- @Override
- public Map<String, String> getDetails() {
- return ImmutableMap.of(testKey, testValue);
- }
-
- @Override
- public String getAction() {
- return "myAction";
- }
- })
- .setAuthor("jUnit")
- .setType(Activity.Type.QPROFILE);
-
- dao.insert(session, log);
-
- ActivityDto newDto = Iterables.getFirst(dao.findAll(session), null);
- assertThat(newDto).isNotNull();
- assertThat(newDto.getAuthor()).isEqualTo(log.getAuthor());
- assertThat(newDto.getData()).isNotNull();
- Map<String, String> details = KeyValueFormat.parse(newDto.getData());
- assertThat(details.get(testKey)).isEqualTo(testValue);
+ public void insert() throws Exception {
+ when(system.now()).thenReturn(1_500_000_000_000L);
+ ActivityDto dto = new ActivityDto()
+ .setKey("UUID_1").setAction("THE_ACTION").setType("THE_TYPE")
+ .setAuthor("THE_AUTHOR").setData("THE_DATA");
+ sut.insert(dto);
+
+ Map<String, Object> map = dbTester.selectFirst("select created_at as \"createdAt\", log_action as \"action\", data_field as \"data\" from activities where log_key='UUID_1'");
+ assertThat(map.get("action")).isEqualTo("THE_ACTION");
+ assertThat(((Timestamp)map.get("createdAt")).getTime()).isEqualTo(1_500_000_000_000L);
+ Clob data = (Clob) map.get("data");
+ assertThat(IOUtils.toString(data.getAsciiStream())).isEqualTo("THE_DATA");
}
-
}
--- /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.activity.index;
+
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.process.ProcessConstants;
+import org.sonar.server.es.IndexDefinition;
+import org.sonar.server.es.NewIndex;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ActivityIndexDefinitionTest {
+
+ IndexDefinition.IndexDefinitionContext context = new IndexDefinition.IndexDefinitionContext();
+
+ @Test
+ public void define() throws Exception {
+ ActivityIndexDefinition def = new ActivityIndexDefinition(new Settings());
+ def.define(context);
+
+ assertThat(context.getIndices()).hasSize(1);
+ NewIndex index = context.getIndices().get("activities");
+ assertThat(index).isNotNull();
+ assertThat(index.getTypes().keySet()).containsOnly("activity");
+
+ // no cluster by default
+ assertThat(index.getSettings().get("index.number_of_shards")).isEqualTo("1");
+ assertThat(index.getSettings().get("index.number_of_replicas")).isEqualTo("0");
+ }
+
+ @Test
+ public void enable_cluster() throws Exception {
+ Settings settings = new Settings();
+ settings.setProperty(ProcessConstants.CLUSTER_ACTIVATE, true);
+ ActivityIndexDefinition def = new ActivityIndexDefinition(settings);
+ def.define(context);
+
+ NewIndex index = context.getIndices().get("activities");
+ assertThat(index.getSettings().get("index.number_of_shards")).isEqualTo("4");
+ assertThat(index.getSettings().get("index.number_of_replicas")).isEqualTo("1");
+ }
+}
--- /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.activity.index;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.server.activity.Activity;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
+
+import java.util.Arrays;
+import java.util.Date;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ActivityIndexTest {
+
+ @ClassRule
+ public static EsTester es = new EsTester().addDefinitions(new ActivityIndexDefinition(new Settings()));
+
+ ActivityIndex sut;
+
+ @Before
+ public void before() {
+ sut = new ActivityIndex(es.client());
+ }
+
+ @Test
+ public void search_all() throws Exception {
+ es.putDocuments("activities", "activity", newDoc(1, 1_500_000_000_000L), newDoc(2, 1_600_000_000_000L));
+
+ SearchResult<ActivityDoc> results = sut.search(new ActivityQuery(), new SearchOptions());
+ assertThat(results.getTotal()).isEqualTo(2L);
+ assertThat(results.getDocs()).hasSize(2);
+ assertThat(results.getDocs()).extracting("message").containsOnly("THE_MSG 1", "THE_MSG 2");
+ }
+
+ @Test
+ public void search_by_type() throws Exception {
+ es.putDocuments("activities", "activity", newDoc(1, 1_500_000_000_000L), newDoc(2, 1_600_000_000_000L));
+
+ ActivityQuery query = new ActivityQuery();
+ query.setTypes(Arrays.asList("ANALYSIS_REPORT"));
+ assertThat(sut.search(query, new SearchOptions()).getTotal()).isEqualTo(2L);
+
+ query = new ActivityQuery();
+ query.setTypes(Arrays.asList("OTHER", "TYPES"));
+ assertThat(sut.search(query, new SearchOptions()).getTotal()).isEqualTo(0L);
+ }
+
+ @Test
+ public void search_by_data() throws Exception {
+ es.putDocuments("activities", "activity", newDoc(1, 1_500_000_000_000L), newDoc(2, 1_600_000_000_000L));
+
+ ActivityQuery query = new ActivityQuery();
+ query.addDataOrFilter("foo", "bar2");
+ SearchResult<ActivityDoc> results = sut.search(query, new SearchOptions());
+ assertThat(results.getDocs()).hasSize(1);
+ assertThat(results.getDocs().get(0).getKey()).isEqualTo("UUID2");
+ }
+
+ @Test
+ public void search_by_date() throws Exception {
+ es.putDocuments("activities", "activity", newDoc(1, 1_500_000_000_000L), newDoc(2, 1_600_000_000_000L));
+
+ ActivityQuery query = new ActivityQuery();
+ query.setSince(new Date(1_550_000_000_000L));
+ SearchResult<ActivityDoc> results = sut.search(query, new SearchOptions());
+ assertThat(results.getDocs()).hasSize(1);
+ assertThat(results.getDocs().get(0).getKey()).isEqualTo("UUID2");
+
+ query = new ActivityQuery();
+ query.setTo(new Date(1_550_000_000_000L));
+ results = sut.search(query, new SearchOptions());
+ assertThat(results.getDocs()).hasSize(1);
+ assertThat(results.getDocs().get(0).getKey()).isEqualTo("UUID1");
+ }
+
+ ActivityDoc newDoc(int id, long date) {
+ ActivityDoc doc = new ActivityDoc();
+ doc.setKey("UUID" + id);
+ doc.setType(Activity.Type.ANALYSIS_REPORT.name());
+ doc.setAction("THE_ACTION " + id);
+ doc.setMessage("THE_MSG " + id);
+ doc.setDetails(ImmutableMap.of("foo", "bar" + id));
+ doc.setLogin("THE_GUY " + id);
+ doc.setCreatedAt(new Date(date));
+ return doc;
+ }
+}
--- /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.activity.index;
+
+import org.apache.commons.dbutils.DbUtils;
+import org.assertj.core.data.MapEntry;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.db.DbClient;
+import org.sonar.test.DbTests;
+
+import java.sql.Connection;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Category(DbTests.class)
+public class ActivityResultSetIteratorTest {
+
+ @ClassRule
+ public static DbTester dbTester = new DbTester();
+
+ DbClient client;
+ Connection connection;
+
+ @Before
+ public void setUp() throws Exception {
+ dbTester.truncateTables();
+ client = new DbClient(dbTester.database(), dbTester.myBatis());
+ connection = dbTester.openConnection();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ DbUtils.closeQuietly(connection);
+ }
+
+ @Test
+ public void traverse() throws Exception {
+ dbTester.prepareDbUnit(getClass(), "traverse.xml");
+ ActivityResultSetIterator it = ActivityResultSetIterator.create(client, connection, 0L);
+ assertThat(it.hasNext()).isTrue();
+ ActivityDoc doc = it.next();
+ assertThat(doc).isNotNull();
+ assertThat(doc.getKey()).isEqualTo("UUID1");
+ assertThat(doc.getAction()).isEqualTo("THE_ACTION");
+ assertThat(doc.getMessage()).isEqualTo("THE_MSG");
+ assertThat(doc.getDetails()).containsOnly(MapEntry.entry("foo", "bar"));
+ assertThat(doc.getLogin()).isEqualTo("THE_AUTHOR");
+
+ assertThat(it.hasNext()).isTrue();
+ assertThat(it.next()).isNotNull();
+ assertThat(it.hasNext()).isFalse();
+ it.close();
+ }
+
+ @Test
+ public void traverse_after_date() throws Exception {
+ dbTester.prepareDbUnit(getClass(), "traverse.xml");
+ ActivityResultSetIterator it = ActivityResultSetIterator.create(client, connection, DateUtils.parseDate("2014-12-01").getTime());
+
+ assertThat(it.hasNext()).isTrue();
+ ActivityDoc doc = it.next();
+ assertThat(doc).isNotNull();
+ assertThat(doc.getKey()).isEqualTo("UUID2");
+
+ assertThat(it.hasNext()).isFalse();
+ it.close();
+ }
+}
*/
package org.sonar.server.activity.ws;
-import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.sonar.api.server.ws.WebService;
-import org.sonar.core.activity.Activity;
-import org.sonar.core.persistence.DbSession;
+import org.sonar.server.activity.Activity;
import org.sonar.server.activity.ActivityService;
-import org.sonar.server.db.DbClient;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.ws.WsTester;
@ClassRule
public static ServerTester tester = new ServerTester();
- private ActivitiesWebService ws;
- private ActivityService service;
- private DbSession session;
-
+ ActivitiesWebService ws;
+ ActivityService service;
@Before
public void setUp() throws Exception {
tester.clearDbAndIndexes();
ws = tester.get(ActivitiesWebService.class);
service = tester.get(ActivityService.class);
- session = tester.get(DbClient.class).openSession(false);
- }
-
- @After
- public void after() {
- session.close();
}
@Test
}
@Test
- public void search_logs() throws Exception {
- service.write(session, Activity.Type.QPROFILE, "Hello World");
- session.commit();
+ public void search() throws Exception {
+ Activity activity = new Activity();
+ activity.setType(Activity.Type.ANALYSIS_REPORT);
+ activity.setAction("THE_ACTION");
+ activity.setMessage("THE_MSG");
+ activity.setData("foo", "bar");
+ service.save(activity);
MockUserSession.set();
- // 1. List single Text log
- WsTester.TestRequest request = tester.wsTester().newGetRequest(ActivitiesWebService.API_ENDPOINT, SearchAction.SEARCH_ACTION);
+ WsTester.TestRequest request = tester.wsTester().newGetRequest("api/activities", "search");
WsTester.Result result = request.execute();
+ assertThat(result.outputAsString()).contains("\"total\":1");
+ assertThat(result.outputAsString()).contains("\"type\":\"ANALYSIS_REPORT\"");
+ assertThat(result.outputAsString()).contains("\"details\":{\"foo\":\"bar\"}");
}
}
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.batch.protocol.output.BatchOutputWriter;
import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.activity.Activity;
import org.sonar.core.computation.db.AnalysisReportDto;
-import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
+import org.sonar.server.activity.Activity;
import org.sonar.server.activity.ActivityService;
import org.sonar.server.component.db.ComponentDao;
import org.sonar.server.computation.step.ComputationStep;
verify(projectStep1).execute(any(ComputationContext.class));
verify(projectStep2).execute(any(ComputationContext.class));
verify(viewStep, never()).execute(any(ComputationContext.class));
- verify(activityService).write(any(DbSession.class), eq(Activity.Type.ANALYSIS_REPORT), any(ReportActivity.class));
+ verify(activityService).save(any(Activity.class));
}
@Test
+++ /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;
-
-import org.junit.Test;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.computation.db.AnalysisReportDto;
-import org.sonar.server.component.ComponentTesting;
-
-import java.util.Map;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.computation.db.AnalysisReportDto.Status.FAILED;
-
-public class ReportActivityTest {
-
- @Test
- public void insert_find_analysis_report_log() {
- AnalysisReportDto report = AnalysisReportDto.newForTests(1L)
- .setProjectKey("projectKey")
- .setStatus(FAILED)
- .setCreatedAt(DateUtils.parseDate("2014-10-15").getTime())
- .setUpdatedAt(DateUtils.parseDate("2014-10-16").getTime())
- .setStartedAt(DateUtils.parseDate("2014-10-17").getTime())
- .setFinishedAt(DateUtils.parseDate("2014-10-18").getTime());
- ComponentDto project = ComponentTesting.newProjectDto();
-
- ReportActivity activity = new ReportActivity(report, project);
-
- Map<String, String> details = activity.getDetails();
- assertThat(details.get("key")).isEqualTo(String.valueOf(report.getId()));
- assertThat(details.get("projectKey")).isEqualTo(project.key());
- assertThat(details.get("projectName")).isEqualTo(project.name());
- assertThat(details.get("projectUuid")).isEqualTo(project.uuid());
- assertThat(details.get("status")).isEqualTo("FAILED");
- assertThat(details.get("submittedAt")).isEqualTo("2014-10-15T00:00:00+0200");
- assertThat(details.get("startedAt")).isEqualTo("2014-10-17T00:00:00+0200");
- assertThat(details.get("finishedAt")).isEqualTo("2014-10-18T00:00:00+0200");
- }
-
-}
package org.sonar.server.computation.ws;
-import org.apache.commons.io.IOUtils;
-import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
-import org.sonar.api.security.DefaultGroups;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.activity.Activity;
-import org.sonar.core.component.ComponentDto;
import org.sonar.core.computation.db.AnalysisReportDto;
import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.permission.PermissionFacade;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.user.UserDto;
+import org.sonar.server.activity.Activity;
import org.sonar.server.activity.ActivityService;
-import org.sonar.server.component.ComponentTesting;
-import org.sonar.server.computation.ReportActivity;
-import org.sonar.server.computation.ReportQueue;
-import org.sonar.server.db.DbClient;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.ws.WsTester;
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
+import java.util.Date;
/**
-* TODO replace this medium test by a small test
-*/
+ * TODO replace this medium test by a small test
+ */
public class HistoryWsActionMediumTest {
- private static final String DEFAULT_PROJECT_KEY = "DefaultProjectKey";
- private static final String DEFAULT_PROJECT_NAME = "DefaultProjectName";
- private static final String DEFAULT_REPORT_DATA = "default-project";
@ClassRule
public static ServerTester tester = new ServerTester();
- private DbClient dbClient;
- private DbSession session;
- private WsTester wsTester;
- private ReportQueue queue;
- private MockUserSession userSession;
- private ActivityService activityService;
+ HistoryWsAction sut;
+ ActivityService activityService;
@Before
- public void before() {
+ public void setUp() throws Exception {
tester.clearDbAndIndexes();
- dbClient = tester.get(DbClient.class);
- wsTester = tester.get(WsTester.class);
- session = dbClient.openSession(false);
- queue = tester.get(ReportQueue.class);
+ sut = tester.get(HistoryWsAction.class);
activityService = tester.get(ActivityService.class);
-
- UserDto connectedUser = new UserDto().setLogin("gandalf").setName("Gandalf");
- dbClient.userDao().insert(session, connectedUser);
-
- userSession = MockUserSession.set()
- .setLogin(connectedUser.getLogin())
- .setUserId(connectedUser.getId().intValue())
- .setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
- }
-
- @After
- public void after() {
- MyBatis.closeQuietly(session);
}
@Test
- public void add_and_try_to_retrieve_activities() throws Exception {
- insertPermissionsForProject(DEFAULT_PROJECT_KEY);
- queue.add(DEFAULT_PROJECT_KEY, IOUtils.toInputStream(DEFAULT_REPORT_DATA));
- queue.add(DEFAULT_PROJECT_KEY, IOUtils.toInputStream(DEFAULT_REPORT_DATA));
- queue.add(DEFAULT_PROJECT_KEY, IOUtils.toInputStream(DEFAULT_REPORT_DATA));
-
- List<AnalysisReportDto> reports = queue.all();
- ComponentDto project = ComponentTesting.newProjectDto()
- .setName(DEFAULT_PROJECT_NAME)
- .setKey(DEFAULT_PROJECT_KEY);
- for (AnalysisReportDto report : reports) {
- report.succeed();
- activityService.write(session, Activity.Type.ANALYSIS_REPORT, new ReportActivity(report, project));
- }
-
- session.commit();
- userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-
- WsTester.TestRequest request = wsTester.newGetRequest(ComputationWebService.API_ENDPOINT, "history");
- WsTester.Result result = request.execute();
-
- assertThat(result).isNotNull();
- result.assertJson(getClass(), "list_history_reports.json", false);
- }
-
- private ComponentDto insertPermissionsForProject(String projectKey) {
- ComponentDto project = new ComponentDto().setKey(projectKey).setId(1L);
- dbClient.componentDao().insert(session, project);
-
- tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session);
- userSession.addProjectPermissions(UserRole.ADMIN, project.key());
- userSession.addProjectPermissions(UserRole.USER, project.key());
-
- session.commit();
-
- return project;
+ public void search() throws Exception {
+ Activity activity1 = new Activity();
+ activity1.setType(Activity.Type.ANALYSIS_REPORT);
+ activity1.setAction("LOG_ANALYSIS_REPORT");
+ activity1.setData("projectKey", "P1");
+ activity1.setData("projectName", "POne");
+ activity1.setData("projectUuid", "U1");
+ activity1.setData("status", AnalysisReportDto.Status.SUCCESS);
+ activity1.setData("submittedAt", new Date());
+ activityService.save(activity1);
+
+ Activity activity2 = new Activity();
+ activity2.setType(Activity.Type.ANALYSIS_REPORT);
+ activity2.setAction("LOG_ANALYSIS_REPORT");
+ activity2.setData("projectKey", "P2");
+ activity2.setData("projectName", "PTwo");
+ activity2.setData("projectUuid", "U2");
+ activity2.setData("status", AnalysisReportDto.Status.FAILED);
+ activity2.setData("submittedAt", new Date());
+ activityService.save(activity2);
+
+ MockUserSession.set().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+
+ WsTester.TestRequest request = tester.wsTester().newGetRequest("api/computation", "history");
+ request.execute().assertJson(getClass(), "list_history_reports.json", false);
}
@Test(expected = ForbiddenException.class)
- public void user_rights_is_not_enough_throw_ForbiddenException() throws Exception {
- insertPermissionsForProject(DEFAULT_PROJECT_KEY);
- queue.add(DEFAULT_PROJECT_KEY, IOUtils.toInputStream(DEFAULT_REPORT_DATA));
-
- AnalysisReportDto report = queue.all().get(0);
- report.succeed();
- // queue.remove(report);
- userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+ public void requires_admin_right() throws Exception {
+ MockUserSession.set();
- WsTester.TestRequest sut = wsTester.newGetRequest(ComputationWebService.API_ENDPOINT, "history");
- sut.execute();
+ WsTester.TestRequest request = tester.wsTester().newGetRequest("api/computation", "history");
+ request.execute();
}
}
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
-import org.sonar.core.activity.db.ActivityDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
import org.sonar.server.activity.db.ActivityDao;
import org.sonar.server.db.DbClient;
-import java.util.List;
-
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-@RunWith(MockitoJUnitRunner.class)
public class ChangeLogMigrationTest {
@ClassRule
public static DbTester db = new DbTester().schema(ChangeLogMigrationTest.class, "schema.sql");
- @Mock
- System2 system2;
-
+ System2 system2 = mock(System2.class);
DbClient dbClient;
ActivityDao dao;
ChangeLogMigration migration;
@Before
public void setUp() throws Exception {
when(system2.now()).thenReturn(DateUtils.parseDate("2014-03-13").getTime());
- dao = new ActivityDao(system2);
+ dao = new ActivityDao(db.myBatis(), system2);
dbClient = new DbClient(db.database(), db.myBatis(), dao);
migration = new ChangeLogMigration(dao, dbClient);
session = dbClient.openSession(false);
public void migrate() throws Exception {
db.prepareDbUnit(getClass(), "active_rules_changes.xml");
migration.execute();
- assertThat(dao.findAll(session)).hasSize(5);
+ assertThat(db.countRowsOfTable("activities")).isEqualTo(5);
- List<ActivityDto> changes = dao.findAll(session);
- assertThat(changes.get(1).getData()).contains("param_PARAM1=TODO");
+ int count = db.countSql("select count(*) from activities where data_field like '%param_PARAM1=TODO%'");
+ assertThat(count).isGreaterThan(0);
}
@Test
db.prepareDbUnit(getClass(), "migrate_when_no_changelog.xml");
migration.execute();
- assertThat(dao.findAll(session)).isEmpty();
+ assertThat(db.countRowsOfTable("activities")).isEqualTo(0);
}
}
+++ /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.qualityprofile;
-
-import com.google.common.collect.Iterables;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.core.activity.Activity;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.qualityprofile.db.ActiveRuleKey;
-import org.sonar.server.activity.ActivityService;
-import org.sonar.server.activity.index.ActivityIndex;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.tester.ServerTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ActiveRuleChangeMediumTest {
-
- @ClassRule
- public static ServerTester tester = new ServerTester();
-
- ActivityService service = tester.get(ActivityService.class);
- ActivityIndex index = tester.get(ActivityIndex.class);
- DbSession dbSession;
-
- @Before
- public void before() {
- tester.clearDbAndIndexes();
- dbSession = tester.get(DbClient.class).openSession(false);
- }
-
- @After
- public void after() {
- dbSession.close();
- }
-
- @Test
- public void insert_find_active_rule_change() {
- ActiveRuleKey key = ActiveRuleKey.of("XOO_P1", RuleKey.of("xoo", "X1"));
- ActiveRuleChange change = ActiveRuleChange
- .createFor(ActiveRuleChange.Type.ACTIVATED, key)
- .setInheritance(ActiveRule.Inheritance.INHERITED)
- .setSeverity("BLOCKER")
- .setParameter("param1", "value1");
-
- service.write(dbSession, Activity.Type.QPROFILE, change);
- dbSession.commit();
-
- // 0. AssertBase case
- assertThat(index.findAll().getHits()).hasSize(1);
-
- Activity activity = Iterables.getFirst(index.findAll().getHits(), null);
- assertThat(activity).isNotNull();
- assertThat(activity.details().get("key")).isEqualTo(key.toString());
- }
-}
package org.sonar.server.qualityprofile;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import org.junit.After;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.activity.Activity;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.qualityprofile.db.ActiveRuleKey;
import org.sonar.core.qualityprofile.db.QualityProfileDto;
import org.sonar.core.rule.RuleDto;
import org.sonar.core.user.UserDto;
+import org.sonar.server.activity.Activity;
import org.sonar.server.activity.ActivityService;
import org.sonar.server.db.DbClient;
+import org.sonar.server.es.SearchOptions;
import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer;
import org.sonar.server.rule.RuleTesting;
import org.sonar.server.search.FacetValue;
-import org.sonar.server.search.QueryContext;
import org.sonar.server.search.Result;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.user.MockUserSession;
// We need an actual rule in DB to test RuleName in Activity
RuleDto rule = db.ruleDao().getByKey(dbSession, RuleTesting.XOO_X1);
- tester.get(ActivityService.class).write(dbSession, Activity.Type.QPROFILE,
- ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(XOO_P1_KEY, RuleTesting.XOO_X1))
- .setSeverity(Severity.MAJOR)
- .setParameter("max", "10")
- );
dbSession.commit();
- Result<QProfileActivity> activities = service.searchActivities(new QProfileActivityQuery(), new QueryContext());
+ tester.get(ActivityService.class).save(ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(XOO_P1_KEY, RuleTesting.XOO_X1))
+ .setSeverity(Severity.MAJOR)
+ .setParameter("max", "10").toActivity());
+
+ Result<QProfileActivity> activities = service.searchActivities(new QProfileActivityQuery(), new SearchOptions());
assertThat(activities.getHits()).hasSize(1);
QProfileActivity activity = activities.getHits().get(0);
- assertThat(activity.type()).isEqualTo(Activity.Type.QPROFILE);
- assertThat(activity.action()).isEqualTo(ActiveRuleChange.Type.ACTIVATED.name());
+ assertThat(activity.getType()).isEqualTo(Activity.Type.QPROFILE.name());
+ assertThat(activity.getAction()).isEqualTo(ActiveRuleChange.Type.ACTIVATED.name());
assertThat(activity.ruleKey()).isEqualTo(RuleTesting.XOO_X1);
assertThat(activity.profileKey()).isEqualTo(XOO_P1_KEY);
assertThat(activity.severity()).isEqualTo(Severity.MAJOR);
assertThat(activity.ruleName()).isEqualTo(rule.getName());
- assertThat(activity.login()).isEqualTo("david");
+ assertThat(activity.getLogin()).isEqualTo("david");
assertThat(activity.authorName()).isEqualTo("David");
assertThat(activity.parameters()).hasSize(1);
RuleKey ruleKey = RuleKey.of("xoo", "deleted_rule");
- tester.get(ActivityService.class).write(dbSession, Activity.Type.QPROFILE,
- ActiveRuleChange.createFor(ActiveRuleChange.Type.UPDATED, ActiveRuleKey.of(XOO_P1_KEY, ruleKey))
- .setParameter("max", "10")
+ tester.get(ActivityService.class).save(ActiveRuleChange.createFor(ActiveRuleChange.Type.UPDATED, ActiveRuleKey.of(XOO_P1_KEY, ruleKey))
+ .setParameter("max", "10").toActivity()
);
- dbSession.commit();
- Result<QProfileActivity> activities = service.searchActivities(new QProfileActivityQuery(), new QueryContext());
+ Result<QProfileActivity> activities = service.searchActivities(new QProfileActivityQuery(), new SearchOptions());
assertThat(activities.getHits()).hasSize(1);
QProfileActivity activity = activities.getHits().get(0);
// We need an actual rule in DB to test RuleName in Activity
db.ruleDao().getByKey(dbSession, RuleTesting.XOO_X1);
+ dbSession.commit();
- tester.get(ActivityService.class).write(dbSession, Activity.Type.QPROFILE,
+ tester.get(ActivityService.class).save(
ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(XOO_P1_KEY, RuleTesting.XOO_X1))
.setSeverity(Severity.MAJOR)
.setParameter("max", "10")
+ .toActivity()
);
- dbSession.commit();
- Result<QProfileActivity> activities = service.searchActivities(new QProfileActivityQuery(), new QueryContext());
+ Result<QProfileActivity> activities = service.searchActivities(new QProfileActivityQuery(), new SearchOptions());
assertThat(activities.getHits()).hasSize(1);
QProfileActivity activity = activities.getHits().get(0);
- assertThat(activity.login()).isEqualTo("david");
+ assertThat(activity.getLogin()).isEqualTo("david");
assertThat(activity.authorName()).isNull();
}
RuleKey ruleKey = RuleKey.of("xoo", "deleted_rule");
- tester.get(ActivityService.class).write(dbSession, Activity.Type.QPROFILE,
- ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(XOO_P1_KEY, ruleKey))
- .setSeverity(Severity.MAJOR)
- .setParameter("max", "10")
+ tester.get(ActivityService.class).save(ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(XOO_P1_KEY, ruleKey))
+ .setSeverity(Severity.MAJOR)
+ .setParameter("max", "10")
+ .toActivity()
);
dbSession.commit();
- Result<QProfileActivity> activities = service.searchActivities(new QProfileActivityQuery(), new QueryContext());
+ Result<QProfileActivity> activities = service.searchActivities(new QProfileActivityQuery(), new SearchOptions());
assertThat(activities.getHits()).hasSize(1);
QProfileActivity activity = activities.getHits().get(0);
@Test
public void search_activity_by_qprofile() throws InterruptedException {
- tester.get(ActivityService.class).write(dbSession, Activity.Type.QPROFILE,
- ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(XOO_P1_KEY, RuleTesting.XOO_X1)));
- tester.get(ActivityService.class).write(dbSession, Activity.Type.QPROFILE,
- ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(XOO_P2_KEY, RuleTesting.XOO_X1)));
- dbSession.commit();
+ tester.get(ActivityService.class).save(
+ ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(XOO_P1_KEY, RuleTesting.XOO_X1)).toActivity());
+ tester.get(ActivityService.class).save(
+ ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(XOO_P2_KEY, RuleTesting.XOO_X1)).toActivity());
// 0. Base case verify 2 activities in index
- assertThat(service.searchActivities(new QProfileActivityQuery(), new QueryContext()).getHits())
+ assertThat(service.searchActivities(new QProfileActivityQuery(), new SearchOptions()).getHits())
.hasSize(2);
// 1. filter by QProfile
List<QProfileActivity> result = service.searchActivities(new QProfileActivityQuery()
- .setQprofileKeys(ImmutableSet.of(XOO_P1_KEY)), new QueryContext()).getHits();
+ .setQprofileKey(XOO_P1_KEY), new SearchOptions()).getHits();
assertThat(result).hasSize(1);
-
- // 1. filter by QProfiles
- assertThat(service.searchActivities(new QProfileActivityQuery()
- .setQprofileKeys(ImmutableSet.of(XOO_P1_KEY, XOO_P2_KEY))
- , new QueryContext()).getHits()).hasSize(2);
}
@Test
public void search_activity_by_qprofile_having_dashes_in_keys() throws InterruptedException {
- tester.get(ActivityService.class).write(dbSession, Activity.Type.QPROFILE,
- ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of("java-default", RuleTesting.XOO_X1)));
- tester.get(ActivityService.class).write(dbSession, Activity.Type.QPROFILE,
- ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of("java-toto", RuleTesting.XOO_X1)));
- dbSession.commit();
+ tester.get(ActivityService.class).save(
+ ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of("java-default", RuleTesting.XOO_X1)).toActivity());
+ tester.get(ActivityService.class).save(
+ ActiveRuleChange.createFor(ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of("java-toto", RuleTesting.XOO_X1)).toActivity());
// 0. Base case verify 2 activities in index
- assertThat(service.searchActivities(new QProfileActivityQuery(), new QueryContext()).getHits())
+ assertThat(service.searchActivities(new QProfileActivityQuery(), new SearchOptions()).getHits())
.hasSize(2);
// 1. filter by QProfile
List<QProfileActivity> result = service.searchActivities(new QProfileActivityQuery()
- .setQprofileKeys(ImmutableSet.of("java-default")), new QueryContext()).getHits();
+ .setQprofileKey("java-default"), new SearchOptions()).getHits();
assertThat(result).hasSize(1);
-
- // 1. filter by QProfiles
- assertThat(service.searchActivities(new QProfileActivityQuery()
- .setQprofileKeys(ImmutableSet.of("java-default", "java-toto"))
- , new QueryContext()).getHits()).hasSize(2);
}
@Test
import org.sonar.core.rule.RuleDto;
import org.sonar.core.rule.RuleDto.Format;
import org.sonar.core.rule.RuleParamDto;
-import org.sonar.server.rule.RuleTesting;
-import java.util.Date;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
checkTables("update_parameter", "rules_parameters");
}
-
- @Test
- public void findAfterDate() throws Exception {
- long t0 = DateUtils.parseDate("2014-01-01").getTime();
- when(system2.now()).thenReturn(t0);
- dao.insert(session, RuleTesting.newXooX1());
- session.commit();
- assertThat(dao.getByKey(session, RuleTesting.XOO_X1).getCreatedAt().after(new Date(t0)));
-
-
- long t1 = DateUtils.parseDate("2014-02-01").getTime();
- when(system2.now()).thenReturn(t1);
- dao.insert(session, RuleTesting.newXooX2());
- session.commit();
- assertThat(dao.getByKey(session, RuleTesting.XOO_X2).getCreatedAt().after(new Date(t1)));
-
- long t2 = DateUtils.parseDate("2014-03-01").getTime();
- when(system2.now()).thenReturn(t2);
- session.flushStatements();
-
-
- assertThat(dao.findAll(session)).hasSize(2);
- assertThat(dao.findAfterDate(session, new Date(0))).hasSize(2);
- assertThat(dao.findAfterDate(session, new Date(t0))).hasSize(2);
- assertThat(dao.findAfterDate(session, new Date(t1))).hasSize(1);
- assertThat(dao.findAfterDate(session, new Date(t2))).hasSize(0);
- }
}
package org.sonar.server.search;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
-import org.elasticsearch.common.settings.ImmutableSettings;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
IndexDefinition.TEST,
null, searchClient) {
- @Override
- protected ImmutableSettings.Builder addCustomIndexSettings(ImmutableSettings.Builder baseIndexSettings) {
- return baseIndexSettings.put("index.number_of_replicas", 22);
- }
-
@Override
protected String getKeyValue(Serializable key) {
return null;
--- /dev/null
+<dataset>
+ <activities id="1" log_key="UUID1" log_type="ANALYSIS_REPORT" log_action="THE_ACTION" log_message="THE_MSG"
+ created_at="2014-01-01" data_field="foo=bar" user_login="THE_AUTHOR"/>
+
+ <activities id="2" log_key="UUID2" log_type="ANALYSIS_REPORT" log_action="THE_ACTION" log_message="THE_MSG"
+ created_at="2015-01-01" data_field="foo=bar" user_login="THE_AUTHOR"/>
+</dataset>
"reports": [
{
"status": "SUCCESS",
- "projectName": "DefaultProjectName",
- "projectKey": "DefaultProjectKey"
+ "projectName": "POne",
+ "projectKey": "P1",
+ "projectUuid": "U1"
},
{
- "status": "SUCCESS",
- "projectName": "DefaultProjectName",
- "projectKey": "DefaultProjectKey"
- },
- {
- "status": "SUCCESS",
- "projectName": "DefaultProjectName",
- "projectKey": "DefaultProjectKey"
+ "status": "FAILED",
+ "projectName": "PTwo",
+ "projectKey": "P2",
+ "projectUuid": "U2"
}
]
-}
\ No newline at end of file
+}
require_parameters 'key'
@profile = Internal.qprofile_loader.getByKey(params[:key])
- search = {'profileKeys' => @profile.key().to_s, 'since' => params[:since], 'to' => params[:to], 'p' => params[:p]}
+ search = {'profileKey' => @profile.key().to_s, 'since' => params[:since], 'to' => params[:to], 'p' => params[:p]}
result = Internal.component(Java::OrgSonarServerActivity::RubyQProfileActivityService.java_class).search(search)
@changes = result.activities
@paging = result.paging
+++ /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.core.activity;
-
-import java.util.Date;
-import java.util.Map;
-
-/**
- * @since 4.4
- */
-public interface Activity {
-
- Type type();
-
- String action();
-
- Date time();
-
- String login();
-
- Map<String, String> details();
-
- String message();
-
- public static enum Type {
- NONE, QPROFILE, SERVER, ANALYSIS_REPORT
- }
-
-}
+++ /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.core.activity;
-
-import java.util.Map;
-
-/**
- * @since 4.4
- */
-public interface ActivityLog {
-
- Map<String, String> getDetails();
-
- public String getAction();
-
-}
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.api.utils.KeyValueFormat;
-import org.sonar.api.utils.internal.Uuids;
-import org.sonar.core.activity.Activity;
-import org.sonar.core.activity.ActivityLog;
-import org.sonar.core.persistence.Dto;
-
-/**
- * @since 4.4
- */
-public final class ActivityDto extends Dto<String> {
+
+import java.util.Date;
+
+public class ActivityDto {
private String key;
private String message;
- private Activity.Type type;
+ private String type;
private String action;
private String author;
-
private String data;
+ private Date createdAt;
- protected ActivityDto() {
- this.key = Uuids.create();
+ public ActivityDto setKey(String key) {
+ this.key = key;
+ return this;
}
- @Override
public String getKey() {
return key;
}
- @Override
- public String toString() {
- return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public ActivityDto setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ return this;
}
- public Activity.Type getType() {
+ public String getType() {
return type;
}
- public ActivityDto setType(Activity.Type type) {
+ public ActivityDto setType(String type) {
this.type = type;
return this;
}
return this;
}
- public static ActivityDto createFor(String message) {
- return new ActivityDto()
- .setMessage(message);
- }
-
- public static ActivityDto createFor(String action, String message) {
- return new ActivityDto()
- .setAction(action)
- .setMessage(message);
- }
-
- public static ActivityDto createFor(ActivityLog activityLog) {
- return new ActivityDto()
- .setAction(activityLog.getAction())
- .setData(KeyValueFormat.format(activityLog.getDetails()));
-
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}
*/
package org.sonar.core.activity.db;
-import org.apache.ibatis.annotations.Param;
-
-import javax.annotation.Nullable;
-
-import java.sql.Timestamp;
-import java.util.List;
-
-/**
- * @since 4.4
- */
public interface ActivityMapper {
- void insert(ActivityDto rule);
-
- List<ActivityDto> selectAll();
+ void insert(ActivityDto dto);
- List<ActivityDto> selectAfterDate(@Nullable @Param("date") Timestamp timestamp);
}
+++ /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.
- */
-
-@ParametersAreNonnullByDefault
-package org.sonar.core.activity;
-
-import javax.annotation.ParametersAreNonnullByDefault;
<mapper namespace="org.sonar.core.activity.db.ActivityMapper">
- <insert id="insert" parameterType="Activity" useGeneratedKeys="false" >
+ <insert id="insert" parameterType="Activity" useGeneratedKeys="false">
insert into activities
(created_at, log_key, log_type, log_action, user_login, data_field, log_message)
- values (#{createdAt}, #{key}, #{type}, #{action}, #{author}, #{data}, #{message})
+ values (#{createdAt,jdbcType=TIMESTAMP}, #{key,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
+ #{action,jdbcType=VARCHAR},
+ #{author,jdbcType=VARCHAR}, #{data,jdbcType=VARCHAR}, #{message,jdbcType=VARCHAR})
</insert>
- <select id="selectAll" parameterType="map" resultType="Activity" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
- SELECT
- created_at as "createdAt",
- log_type as "type",
- user_login as "author",
- data_field as "data",
- log_message as "message",
- log_key as "key",
- log_action as "action"
- FROM activities
- </select>
-
-
- <select id="selectAfterDate" parameterType="map" resultType="Activity" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
- SELECT
- created_at as "createdAt",
- log_type as "type",
- user_login as "author",
- data_field as "data",
- log_message as "message",
- log_key as "key",
- log_action as "action"
- FROM activities
- <where>
- <if test="date != null">
- created_at >= #{date}
- </if>
- </where>
- </select>
</mapper>