Commit cc51425c authored by Maxime Orefice's avatar Maxime Orefice Committed by Douglas Barbosa Alexandre

Add daily coverage data new finder

This commit introduces a new finder which will be used to
fetch our daily coverage data at the project and group level.
parent b382088c
...@@ -40,7 +40,25 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati ...@@ -40,7 +40,25 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati
end end
def report_results def report_results
Ci::DailyBuildGroupReportResultsFinder.new(**finder_params).execute if ::Gitlab::Ci::Features.use_coverage_data_new_finder?(project)
::Ci::Testing::DailyBuildGroupReportResultsFinder.new(
params: new_finder_params,
current_user: current_user
).execute
else
Ci::DailyBuildGroupReportResultsFinder.new(**finder_params).execute
end
end
def new_finder_params
{
project: project,
coverage: true,
start_date: start_date,
end_date: end_date,
ref_path: params[:ref_path],
sort: true
}
end end
def finder_params def finder_params
......
# frozen_string_literal: true
# DailyBuildGroupReportResultsFinder
#
# Used to filter DailyBuildGroupReportResults by set of params
#
# Arguments:
# current_user
# params:
# project: integer
# group: integer
# coverage: boolean
# ref_path: string
# start_date: date
# end_date: date
# sort: boolean
# limit: integer
module Ci
module Testing
class DailyBuildGroupReportResultsFinder
include Gitlab::Allowable
MAX_ITEMS = 1_000
attr_reader :params, :current_user
def initialize(params: {}, current_user: nil)
@params = params
@current_user = current_user
end
def execute
return Ci::DailyBuildGroupReportResult.none unless query_allowed?
collection = Ci::DailyBuildGroupReportResult.by_projects(params[:project])
collection = filter_report_results(collection)
collection
end
private
def query_allowed?
can?(current_user, :read_build_report_results, params[:project])
end
def filter_report_results(collection)
collection = by_coverage(collection)
collection = by_ref_path(collection)
collection = by_dates(collection)
collection = sort(collection)
collection = limit_by(collection)
collection
end
def by_coverage(items)
params[:coverage].present? ? items.with_coverage : items
end
def by_ref_path(items)
params[:ref_path].present? ? items.by_ref_path(params[:ref_path]) : items.with_default_branch
end
def by_dates(items)
params[:start_date].present? && params[:end_date].present? ? items.by_dates(params[:start_date], params[:end_date]) : items
end
def sort(items)
params[:sort].present? ? items.ordered_by_date_and_group_name : items
end
# rubocop: disable CodeReuse/ActiveRecord
def limit_by(items)
items.limit(limit)
end
# rubocop: enable CodeReuse/ActiveRecord
def limit
return MAX_ITEMS unless params[:limit].present?
[params[:limit].to_i, MAX_ITEMS].min
end
end
end
end
...@@ -13,10 +13,13 @@ module Ci ...@@ -13,10 +13,13 @@ module Ci
validates :data, json_schema: { filename: "daily_build_group_report_result_data" } validates :data, json_schema: { filename: "daily_build_group_report_result_data" }
scope :with_included_projects, -> { includes(:project) } scope :with_included_projects, -> { includes(:project) }
scope :by_ref_path, -> (ref_path) { where(ref_path: ref_path) }
scope :by_projects, -> (ids) { where(project_id: ids) } scope :by_projects, -> (ids) { where(project_id: ids) }
scope :with_coverage, -> { where("(data->'coverage') IS NOT NULL") } scope :with_coverage, -> { where("(data->'coverage') IS NOT NULL") }
scope :with_default_branch, -> { where(default_branch: true) } scope :with_default_branch, -> { where(default_branch: true) }
scope :by_date, -> (start_date) { where(date: report_window(start_date)..Date.current) } scope :by_date, -> (start_date) { where(date: report_window(start_date)..Date.current) }
scope :by_dates, -> (start_date, end_date) { where(date: start_date..end_date) }
scope :ordered_by_date_and_group_name, -> { order(date: :desc, group_name: :asc) }
store_accessor :data, :coverage store_accessor :data, :coverage
......
---
name: coverage_data_new_finder
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/53670
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/301093
milestone: '13.9'
type: development
group: group::testing
default_enabled: false
...@@ -75,6 +75,10 @@ module Gitlab ...@@ -75,6 +75,10 @@ module Gitlab
def self.display_codequality_backend_comparison?(project) def self.display_codequality_backend_comparison?(project)
::Feature.enabled?(:codequality_backend_comparison, project, default_enabled: :yaml) ::Feature.enabled?(:codequality_backend_comparison, project, default_enabled: :yaml)
end end
def self.use_coverage_data_new_finder?(record)
::Feature.enabled?(:coverage_data_new_finder, record, default_enabled: :yaml)
end
end end
end end
end end
...@@ -11,6 +11,7 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do ...@@ -11,6 +11,7 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do
let(:end_date) { '2020-03-09' } let(:end_date) { '2020-03-09' }
let(:allowed_to_read) { true } let(:allowed_to_read) { true }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:feature_enabled?) { true }
before do before do
create_daily_coverage('rspec', 79.0, '2020-03-09') create_daily_coverage('rspec', 79.0, '2020-03-09')
...@@ -24,6 +25,8 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do ...@@ -24,6 +25,8 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do
allow(Ability).to receive(:allowed?).and_call_original allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?).with(user, :read_build_report_results, project).and_return(allowed_to_read) allow(Ability).to receive(:allowed?).with(user, :read_build_report_results, project).and_return(allowed_to_read)
stub_feature_flags(coverage_data_new_finder: feature_enabled?)
get :index, params: { get :index, params: {
namespace_id: project.namespace, namespace_id: project.namespace,
project_id: project, project_id: project,
...@@ -55,9 +58,7 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do ...@@ -55,9 +58,7 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do
end end
end end
context 'when format is CSV' do shared_examples 'CSV results' do
let(:format) { :csv }
it 'serves the results in CSV' do it 'serves the results in CSV' do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Type']).to eq('text/csv; charset=utf-8') expect(response.headers['Content-Type']).to eq('text/csv; charset=utf-8')
...@@ -88,9 +89,7 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do ...@@ -88,9 +89,7 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do
it_behaves_like 'ensuring policy' it_behaves_like 'ensuring policy'
end end
context 'when format is JSON' do shared_examples 'JSON results' do
let(:format) { :json }
it 'serves the results in JSON' do it 'serves the results in JSON' do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
...@@ -137,6 +136,38 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do ...@@ -137,6 +136,38 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do
it_behaves_like 'validating param_type' it_behaves_like 'validating param_type'
it_behaves_like 'ensuring policy' it_behaves_like 'ensuring policy'
end end
context 'when format is JSON' do
let(:format) { :json }
context 'when coverage_data_new_finder flag is enabled' do
let(:feature_enabled?) { true }
it_behaves_like 'JSON results'
end
context 'when coverage_data_new_finder flag is disabled' do
let(:feature_enabled?) { false }
it_behaves_like 'JSON results'
end
end
context 'when format is CSV' do
let(:format) { :csv }
context 'when coverage_data_new_finder flag is enabled' do
let(:feature_enabled?) { true }
it_behaves_like 'CSV results'
end
context 'when coverage_data_new_finder flag is disabled' do
let(:feature_enabled?) { false }
it_behaves_like 'CSV results'
end
end
end end
def create_daily_coverage(group_name, coverage, date) def create_daily_coverage(group_name, coverage, date)
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::Testing::DailyBuildGroupReportResultsFinder do
describe '#execute' do
let_it_be(:project) { create(:project, :private) }
let(:user_without_permission) { create(:user) }
let_it_be(:user_with_permission) { project.owner }
let_it_be(:ref_path) { 'refs/heads/master' }
let(:limit) { nil }
let_it_be(:default_branch) { false }
let(:start_date) { '2020-03-09' }
let(:end_date) { '2020-03-10' }
let(:sort) { true }
let_it_be(:rspec_coverage_1) { create_daily_coverage('rspec', 79.0, '2020-03-09') }
let_it_be(:karma_coverage_1) { create_daily_coverage('karma', 89.0, '2020-03-09') }
let_it_be(:rspec_coverage_2) { create_daily_coverage('rspec', 95.0, '2020-03-10') }
let_it_be(:karma_coverage_2) { create_daily_coverage('karma', 92.0, '2020-03-10') }
let_it_be(:rspec_coverage_3) { create_daily_coverage('rspec', 97.0, '2020-03-11') }
let_it_be(:karma_coverage_3) { create_daily_coverage('karma', 99.0, '2020-03-11') }
let(:finder) { described_class.new(params: params, current_user: current_user) }
let(:params) do
{
project: project,
coverage: true,
ref_path: ref_path,
start_date: start_date,
end_date: end_date,
limit: limit,
sort: sort
}
end
subject(:coverages) { finder.execute }
context 'when params are provided' do
context 'when current user is not allowed to read data' do
let(:current_user) { user_without_permission }
it 'returns an empty collection' do
expect(coverages).to be_empty
end
end
context 'when current user is allowed to read data' do
let(:current_user) { user_with_permission }
it 'returns matching coverages within the given date range' do
expect(coverages).to match_array([
karma_coverage_2,
rspec_coverage_2,
karma_coverage_1,
rspec_coverage_1
])
end
context 'when ref_path is nil' do
let(:default_branch) { true }
let(:ref_path) { nil }
it 'returns coverages for the default branch' do
rspec_coverage_4 = create_daily_coverage('rspec', 66.0, '2020-03-10')
expect(coverages).to contain_exactly(rspec_coverage_4)
end
end
context 'when limit is specified' do
let(:limit) { 2 }
it 'returns limited number of matching coverages within the given date range' do
expect(coverages).to match_array([
karma_coverage_2,
rspec_coverage_2
])
end
end
end
end
end
private
def create_daily_coverage(group_name, coverage, date)
create(
:ci_daily_build_group_report_result,
project: project,
ref_path: ref_path || 'feature-branch',
group_name: group_name,
data: { 'coverage' => coverage },
date: date,
default_branch: default_branch
)
end
end
...@@ -97,6 +97,35 @@ RSpec.describe Ci::DailyBuildGroupReportResult do ...@@ -97,6 +97,35 @@ RSpec.describe Ci::DailyBuildGroupReportResult do
end end
end end
describe '.by_ref_path' do
subject(:coverages) { described_class.by_ref_path(recent_build_group_report_result.ref_path) }
it 'returns coverages by ref_path' do
expect(coverages).to contain_exactly(recent_build_group_report_result, old_build_group_report_result)
end
end
describe '.ordered_by_date_and_group_name' do
subject(:coverages) { described_class.ordered_by_date_and_group_name }
it 'returns coverages ordered by data and group name' do
expect(subject).to contain_exactly(recent_build_group_report_result, old_build_group_report_result)
end
end
describe '.by_dates' do
subject(:coverages) { described_class.by_dates(start_date, end_date) }
context 'when daily coverages exist during those dates' do
let(:start_date) { 1.day.ago.to_date.to_s }
let(:end_date) { Date.current.to_s }
it 'returns coverages' do
expect(coverages).to contain_exactly(recent_build_group_report_result)
end
end
end
describe '.with_coverage' do describe '.with_coverage' do
subject { described_class.with_coverage } subject { described_class.with_coverage }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment