Commit cbe21937 authored by Maxime Orefice's avatar Maxime Orefice Committed by Shinya Maeda

Expose show tests endpoint

This endpoint will be used to fetch individual test suite
data. This is part of the work to improve the performance
of our junit feature.
parent 54828d89
......@@ -2,35 +2,58 @@
module Projects
module Pipelines
class TestsController < Projects::ApplicationController
before_action :pipeline
before_action :authorize_read_pipeline!
before_action :authorize_read_build!
class TestsController < Projects::Pipelines::ApplicationController
before_action :validate_feature_flag!
before_action :authorize_read_build!
before_action :builds, only: [:show]
def summary
respond_to do |format|
format.json do
render json: TestReportSerializer
render json: TestReportSummarySerializer
.new(project: project, current_user: @current_user)
.represent(pipeline.test_report_summary)
end
end
end
def show
respond_to do |format|
format.json do
render json: TestSuiteSerializer
.new(project: project, current_user: @current_user)
.represent(test_suite, details: true)
end
end
end
private
def validate_feature_flag!
render_404 unless Feature.enabled?(:build_report_summary, project)
end
def pipeline
project.all_pipelines.find(tests_params[:id])
# rubocop: disable CodeReuse/ActiveRecord
def builds
pipeline.latest_builds.where(id: build_params)
end
def build_params
return [] unless params[:build_ids]
params[:build_ids].split(",")
end
def tests_params
params.permit(:id)
def test_suite
if builds.present?
builds.map do |build|
build.collect_test_reports!(Gitlab::Ci::Reports::TestReports.new)
end.sum
else
render_404
end
end
# rubocop: enable CodeReuse/ActiveRecord
end
end
end
# frozen_string_literal: true
class TestReportSummaryEntity < TestReportEntity
expose :test_suites, using: TestSuiteSummaryEntity do |summary|
summary.test_suites.values
end
end
# frozen_string_literal: true
class TestReportSummarySerializer < BaseSerializer
entity TestReportSummaryEntity
end
# frozen_string_literal: true
class TestSuiteSerializer < BaseSerializer
entity TestSuiteEntity
end
# frozen_string_literal: true
class TestSuiteSummaryEntity < TestSuiteEntity
expose :build_ids do |summary|
summary.build_ids
end
end
......@@ -26,11 +26,11 @@ resources :pipelines, only: [:index, :new, :create, :show, :destroy] do
resources :stages, only: [], param: :name do
post :play_manual
end
end
resources :tests, only: [], controller: 'pipelines/tests' do
collection do
get :summary
end
resources :tests, only: [:show], param: :suite_name, controller: 'pipelines/tests' do
collection do
get :summary
end
end
end
......
......@@ -4,9 +4,9 @@ module Gitlab
module Ci
module Reports
class TestSuite
attr_reader :name
attr_reader :test_cases
attr_reader :total_time
attr_accessor :name
attr_accessor :test_cases
attr_accessor :total_time
attr_reader :suite_error
def initialize(name = nil)
......@@ -70,6 +70,14 @@ module Gitlab
@suite_error = msg
end
def +(other)
self.class.new.tap do |test_suite|
test_suite.name = self.name
test_suite.test_cases = self.test_cases.deep_merge(other.test_cases)
test_suite.total_time = self.total_time + other.total_time
end
end
private
def existing_key?(test_case)
......
......@@ -15,6 +15,10 @@ module Gitlab
end
# rubocop: disable CodeReuse/ActiveRecord
def build_ids
results.pluck(:build_id)
end
def total_time
@total_time ||= results.sum(&:tests_duration)
end
......
......@@ -46,12 +46,66 @@ RSpec.describe Projects::Pipelines::TestsController do
end
end
describe 'GET #show.json' do
context 'when pipeline has build report results' do
let(:pipeline) { create(:ci_pipeline, :with_report_results, project: project) }
let(:suite_name) { 'test' }
let(:build_ids) { pipeline.latest_builds.pluck(:id) }
it 'renders test suite data' do
get_tests_show_json(build_ids)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['name']).to eq('test')
end
end
context 'when pipeline does not have build report results' do
let(:pipeline) { create(:ci_empty_pipeline) }
let(:suite_name) { 'test' }
it 'renders 404' do
get_tests_show_json([])
expect(response).to have_gitlab_http_status(:not_found)
expect(response.body).to be_empty
end
end
context 'when feature is disabled' do
let(:suite_name) { 'test' }
before do
stub_feature_flags(build_report_summary: false)
end
it 'returns 404' do
get_tests_show_json([])
expect(response).to have_gitlab_http_status(:not_found)
expect(response.body).to be_empty
end
end
end
def get_tests_summary_json
get :summary,
params: {
namespace_id: project.namespace,
project_id: project,
id: pipeline.id
pipeline_id: pipeline.id
},
format: :json
end
def get_tests_show_json(build_ids)
get :show,
params: {
namespace_id: project.namespace,
project_id: project,
pipeline_id: pipeline.id,
suite_name: suite_name,
build_ids: build_ids
},
format: :json
end
......
......@@ -139,6 +139,41 @@ RSpec.describe Gitlab::Ci::Reports::TestSuite do
end
end
describe '#+' do
let(:test_suite_2) { described_class.new('Rspec') }
subject { test_suite + test_suite_2 }
context 'when adding multiple suites together' do
before do
test_suite.add_test_case(test_case_success)
test_suite.add_test_case(test_case_failed)
end
it 'returns a new test suite' do
expect(subject).to be_an_instance_of(described_class)
end
it 'returns the suite name' do
expect(subject.name).to eq('Rspec')
end
it 'returns the sum for total_time' do
expect(subject.total_time).to eq(3.33)
end
it 'merges tests cases hash', :aggregate_failures do
test_suite_2.add_test_case(create_test_case_java_success)
failed_keys = test_suite.test_cases['failed'].keys
success_keys = test_suite.test_cases['success'].keys + test_suite_2.test_cases['success'].keys
expect(subject.test_cases['failed'].keys).to contain_exactly(*failed_keys)
expect(subject.test_cases['success'].keys).to contain_exactly(*success_keys)
end
end
end
Gitlab::Ci::Reports::TestCase::STATUS_TYPES.each do |status_type|
describe "##{status_type}" do
subject { test_suite.public_send("#{status_type}") }
......
......@@ -17,6 +17,16 @@ RSpec.describe Gitlab::Ci::Reports::TestSuiteSummary do
end
end
describe '#build_ids' do
subject { test_suite_summary.build_ids }
context 'when test suite summary has several build report results' do
it 'returns the build ids' do
expect(subject).to contain_exactly(build_report_result_1.build_id, build_report_result_2.build_id)
end
end
end
describe '#total_time' do
subject { test_suite_summary.total_time }
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe TestReportSummaryEntity do
let(:pipeline) { create(:ci_pipeline, :with_report_results) }
let(:entity) { described_class.new(pipeline.test_report_summary) }
describe '#as_json' do
subject(:as_json) { entity.as_json }
it 'contains the total time' do
expect(as_json).to include(:total_time)
end
it 'contains the counts' do
expect(as_json).to include(:total_count, :success_count, :failed_count, :skipped_count, :error_count)
end
context 'when summary has test suites' do
it 'contains the test suites' do
expect(as_json).to include(:test_suites)
expect(as_json[:test_suites].count).to eq(1)
end
it 'contains build_ids' do
expect(as_json[:test_suites].first).to include(:build_ids)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe TestSuiteSummaryEntity do
let(:pipeline) { create(:ci_pipeline, :with_report_results) }
let(:entity) { described_class.new(pipeline.test_report_summary.total) }
describe '#as_json' do
subject(:as_json) { entity.as_json }
it 'contains the total time' do
expect(as_json).to include(:total_time)
end
it 'contains the counts' do
expect(as_json).to include(:total_count, :success_count, :failed_count, :skipped_count, :error_count)
end
it 'contains the build_ids' do
expect(as_json).to include(:build_ids)
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