Commit e4db1cf8 authored by Erick Bajao's avatar Erick Bajao

Implement endpoints for code coverage graph

Adds an endpoint that will be used by the daily code coverage graph.
parent ce45c835
...@@ -12,7 +12,8 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati ...@@ -12,7 +12,8 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati
def index def index
respond_to do |format| respond_to do |format|
format.csv { send_data(render_csv(results), type: 'text/csv; charset=utf-8') } format.csv { send_data(render_csv(report_results), type: 'text/csv; charset=utf-8') }
format.json { render json: render_json(report_results) }
end end
end end
...@@ -37,7 +38,11 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati ...@@ -37,7 +38,11 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati
).render ).render
end end
def results def render_json(collection)
Ci::DailyBuildGroupReportResultSerializer.new.represent(collection, param_type: param_type)
end
def report_results
Ci::DailyBuildGroupReportResultsFinder.new(finder_params).execute Ci::DailyBuildGroupReportResultsFinder.new(finder_params).execute
end end
......
...@@ -71,6 +71,11 @@ class Projects::GraphsController < Projects::ApplicationController ...@@ -71,6 +71,11 @@ class Projects::GraphsController < Projects::ApplicationController
namespace_id: @project.namespace, namespace_id: @project.namespace,
project_id: @project, project_id: @project,
format: :csv format: :csv
),
graph_api_path: namespace_project_ci_daily_build_group_report_results_path(
namespace_id: @project.namespace,
project_id: @project,
format: :json
) )
} }
end end
......
...@@ -17,18 +17,22 @@ module Ci ...@@ -17,18 +17,22 @@ module Ci
return none unless can?(current_user, :read_build_report_results, project) return none unless can?(current_user, :read_build_report_results, project)
Ci::DailyBuildGroupReportResult.recent_results( Ci::DailyBuildGroupReportResult.recent_results(
{ query_params,
project_id: project, limit: limit
ref_path: ref_path,
date: start_date..end_date
},
limit: @limit
) )
end end
private private
attr_reader :current_user, :project, :ref_path, :start_date, :end_date attr_reader :current_user, :project, :ref_path, :start_date, :end_date, :limit
def query_params
{
project_id: project,
ref_path: ref_path,
date: start_date..end_date
}
end
def none def none
Ci::DailyBuildGroupReportResult.none Ci::DailyBuildGroupReportResult.none
......
# frozen_string_literal: true
module Ci
class DailyBuildGroupReportResultEntity < Grape::Entity
expose :date
::Ci::DailyBuildGroupReportResult::PARAM_TYPES.each do |type|
expose type, if: lambda { |report_result, options| options[:param_type] == type } do |report_result, options|
report_result.data[options[:param_type]]
end
end
end
end
# frozen_string_literal: true
module Ci
class DailyBuildGroupReportResultSerializer < BaseSerializer
entity ::Ci::DailyBuildGroupReportResultEntity
def represent(resource, opts = {})
group(resource).map do |group_name, data|
{
group_name: group_name,
data: super(data, opts)
}
end
end
private
def group(resource)
collect(resource).group_by(&:group_name)
end
def collect(resource)
return resource if resource.respond_to?(:group_by)
[resource]
end
end
end
...@@ -67,7 +67,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -67,7 +67,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
namespace :ci do namespace :ci do
resource :lint, only: [:show, :create] resource :lint, only: [:show, :create]
resources :daily_build_group_report_results, only: [:index], constraints: { format: 'csv' } resources :daily_build_group_report_results, only: [:index], constraints: { format: /(csv|json)/ }
end end
namespace :settings do namespace :settings do
......
...@@ -14,9 +14,10 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do ...@@ -14,9 +14,10 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do
before do before do
create_daily_coverage('rspec', 79.0, '2020-03-09') create_daily_coverage('rspec', 79.0, '2020-03-09')
create_daily_coverage('rspec', 77.0, '2020-03-08')
create_daily_coverage('karma', 81.0, '2019-12-10') create_daily_coverage('karma', 81.0, '2019-12-10')
create_daily_coverage('rspec', 67.0, '2019-12-09') create_daily_coverage('minitest', 67.0, '2019-12-09')
create_daily_coverage('karma', 71.0, '2019-12-09') create_daily_coverage('mocha', 71.0, '2019-12-09')
sign_in(user) sign_in(user)
...@@ -30,10 +31,33 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do ...@@ -30,10 +31,33 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do
param_type: param_type, param_type: param_type,
start_date: start_date, start_date: start_date,
end_date: end_date, end_date: end_date,
format: :csv format: format
} }
end end
shared_examples_for 'validating param_type' do
context 'when given param_type is invalid' do
let(:param_type) { 'something_else' }
it 'responds with 422 error' do
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
end
shared_examples_for 'ensuring policy' do
context 'when user is not allowed to read build report results' do
let(:allowed_to_read) { false }
it 'responds with 404 error' do
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
context 'when format is CSV' 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')
...@@ -41,6 +65,7 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do ...@@ -41,6 +65,7 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do
expect(csv_response).to eq([ expect(csv_response).to eq([
%w[date group_name coverage], %w[date group_name coverage],
['2020-03-09', 'rspec', '79.0'], ['2020-03-09', 'rspec', '79.0'],
['2020-03-08', 'rspec', '77.0'],
['2019-12-10', 'karma', '81.0'] ['2019-12-10', 'karma', '81.0']
]) ])
end end
...@@ -50,32 +75,68 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do ...@@ -50,32 +75,68 @@ RSpec.describe Projects::Ci::DailyBuildGroupReportResultsController do
let(:end_date) { '2020-03-09' } let(:end_date) { '2020-03-09' }
it 'limits the result to 90 days from the given start_date' do it 'limits the result to 90 days from the given start_date' do
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Type']).to eq('text/csv; charset=utf-8')
expect(csv_response).to eq([ expect(csv_response).to eq([
%w[date group_name coverage], %w[date group_name coverage],
['2020-03-09', 'rspec', '79.0'], ['2020-03-09', 'rspec', '79.0'],
['2020-03-08', 'rspec', '77.0'],
['2019-12-10', 'karma', '81.0'] ['2019-12-10', 'karma', '81.0']
]) ])
end end
end end
context 'when given param_type is invalid' do it_behaves_like 'validating param_type'
let(:param_type) { 'something_else' } it_behaves_like 'ensuring policy'
it 'responds with 422 error' do
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end end
context 'when format is JSON' do
let(:format) { :json }
it 'serves the results in JSON' do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq([
{
'group_name' => 'rspec',
'data' => [
{ 'date' => '2020-03-09', 'coverage' => 79.0 },
{ 'date' => '2020-03-08', 'coverage' => 77.0 }
]
},
{
'group_name' => 'karma',
'data' => [
{ 'date' => '2019-12-10', 'coverage' => 81.0 }
]
}
])
end end
context 'when user is not allowed to read build report results' do context 'when given date range spans more than 90 days' do
let(:allowed_to_read) { false } let(:start_date) { '2019-12-09' }
let(:end_date) { '2020-03-09' }
it 'responds with 404 error' do it 'limits the result to 90 days from the given start_date' do
expect(response).to have_gitlab_http_status(:not_found) expect(json_response).to eq([
{
'group_name' => 'rspec',
'data' => [
{ 'date' => '2020-03-09', 'coverage' => 79.0 },
{ 'date' => '2020-03-08', 'coverage' => 77.0 }
]
},
{
'group_name' => 'karma',
'data' => [
{ 'date' => '2019-12-10', 'coverage' => 81.0 }
]
}
])
end end
end end
it_behaves_like 'validating param_type'
it_behaves_like 'ensuring policy'
end
end end
def create_daily_coverage(group_name, coverage, date) def create_daily_coverage(group_name, coverage, date)
......
...@@ -49,8 +49,8 @@ RSpec.describe Projects::GraphsController do ...@@ -49,8 +49,8 @@ RSpec.describe Projects::GraphsController do
expect(assigns[:daily_coverage_options]).to eq( expect(assigns[:daily_coverage_options]).to eq(
base_params: { base_params: {
start_date: Time.current.to_date - 90.days, start_date: Date.current - 90.days,
end_date: Time.current.to_date, end_date: Date.current,
ref_path: project.repository.expand_ref('master'), ref_path: project.repository.expand_ref('master'),
param_type: 'coverage' param_type: 'coverage'
}, },
...@@ -58,6 +58,11 @@ RSpec.describe Projects::GraphsController do ...@@ -58,6 +58,11 @@ RSpec.describe Projects::GraphsController do
namespace_id: project.namespace, namespace_id: project.namespace,
project_id: project, project_id: project,
format: :csv format: :csv
),
graph_api_path: namespace_project_ci_daily_build_group_report_results_path(
namespace_id: project.namespace,
project_id: project,
format: :json
) )
) )
end end
......
# frozen_string_literal: true
require 'spec_helper'
describe Ci::DailyBuildGroupReportResultEntity do
let(:report_result) { double(date: '2020-05-20', group_name: 'rspec', data: { 'coverage' => 79.1 }) }
let(:entity) { described_class.new(report_result, param_type: param_type) }
let(:param_type) { 'coverage' }
describe '#as_json' do
subject { entity.as_json }
it { is_expected.to include(:date) }
it { is_expected.not_to include(:group_name) }
it { is_expected.to include(:coverage) }
context 'when given param_type is not allowed' do
let(:param_type) { 'something_else' }
it { is_expected.not_to include(:coverage) }
it { is_expected.not_to include(:something_else) }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Ci::DailyBuildGroupReportResultSerializer do
let(:report_result) do
[
double(date: '2020-05-20', group_name: 'rspec', data: { 'coverage' => 79.1 }),
double(date: '2020-05-20', group_name: 'karma', data: { 'coverage' => 90.1 }),
double(date: '2020-05-19', group_name: 'rspec', data: { 'coverage' => 77.1 }),
double(date: '2020-05-19', group_name: 'karma', data: { 'coverage' => 89.1 })
]
end
let(:serializer) { described_class.new.represent(report_result, param_type: 'coverage') }
describe '#to_json' do
let(:json) { Gitlab::Json.parse(serializer.to_json) }
it 'returns an array of group results' do
expect(json).to eq([
{
'group_name' => 'rspec',
'data' => [
{ 'date' => '2020-05-20', 'coverage' => 79.1 },
{ 'date' => '2020-05-19', 'coverage' => 77.1 }
]
},
{
'group_name' => 'karma',
'data' => [
{ 'date' => '2020-05-20', 'coverage' => 90.1 },
{ 'date' => '2020-05-19', 'coverage' => 89.1 }
]
}
])
end
end
end
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