Commit 39373637 authored by Scott Hampton's avatar Scott Hampton Committed by Douglas Barbosa Alexandre

Add test report summary to graphql

parent 1be0fefa
# frozen_string_literal: true
module Resolvers
module Ci
class TestReportSummaryResolver < BaseResolver
type ::Types::Ci::TestReportSummaryType, null: true
alias_method :pipeline, :object
def resolve(**args)
TestReportSummarySerializer
.new(project: pipeline.project, current_user: @current_user)
.represent(pipeline.test_report_summary)
end
end
end
end
...@@ -122,6 +122,12 @@ module Types ...@@ -122,6 +122,12 @@ module Types
method: :uses_needs?, method: :uses_needs?,
description: 'Indicates if the pipeline has jobs with `needs` dependencies.' description: 'Indicates if the pipeline has jobs with `needs` dependencies.'
field :test_report_summary,
Types::Ci::TestReportSummaryType,
null: false,
description: 'Summary of the test report generated by the pipeline.',
resolver: Resolvers::Ci::TestReportSummaryResolver
def detailed_status def detailed_status
object.detailed_status(current_user) object.detailed_status(current_user)
end end
......
# frozen_string_literal: true
module Types
module Ci
# rubocop: disable Graphql/AuthorizeTypes
# This is presented through `PipelineType` that has its own authorization
class TestReportSummaryType < BaseObject
graphql_name 'TestReportSummary'
description 'Test report for a pipeline'
field :total, Types::Ci::TestReportTotalType, null: false,
description: 'Total report statistics for a pipeline test report.'
field :test_suites, Types::Ci::TestSuiteSummaryType.connection_type, null: false,
description: 'Test suites belonging to a pipeline test report.'
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
# frozen_string_literal: true
module Types
module Ci
# rubocop: disable Graphql/AuthorizeTypes
class TestReportTotalType < BaseObject
graphql_name 'TestReportTotal'
description 'Total test report statistics.'
field :time, GraphQL::FLOAT_TYPE, null: true,
description: 'Total duration of the tests.'
field :count, GraphQL::INT_TYPE, null: true,
description: 'Total number of the test cases.'
field :success, GraphQL::INT_TYPE, null: true,
description: 'Total number of test cases that succeeded.'
field :failed, GraphQL::INT_TYPE, null: true,
description: 'Total number of test cases that failed.'
field :skipped, GraphQL::INT_TYPE, null: true,
description: 'Total number of test cases that were skipped.'
field :error, GraphQL::INT_TYPE, null: true,
description: 'Total number of test cases that had an error.'
field :suite_error, GraphQL::STRING_TYPE, null: true,
description: 'Test suite error message.'
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
# frozen_string_literal: true
module Types
module Ci
# rubocop: disable Graphql/AuthorizeTypes
class TestSuiteSummaryType < BaseObject
graphql_name 'TestSuiteSummary'
description 'Test suite summary in a pipeline test report.'
connection_type_class(Types::CountableConnectionType)
field :name, GraphQL::STRING_TYPE, null: true,
description: 'Name of the test suite.'
field :total_time, GraphQL::FLOAT_TYPE, null: true,
description: 'Total duration of the tests in the test suite.'
field :total_count, GraphQL::INT_TYPE, null: true,
description: 'Total number of the test cases in the test suite.'
field :success_count, GraphQL::INT_TYPE, null: true,
description: 'Total number of test cases that succeeded in the test suite.'
field :failed_count, GraphQL::INT_TYPE, null: true,
description: 'Total number of test cases that failed in the test suite.'
field :skipped_count, GraphQL::INT_TYPE, null: true,
description: 'Total number of test cases that were skipped in the test suite.'
field :error_count, GraphQL::INT_TYPE, null: true,
description: 'Total number of test cases that had an error.'
field :suite_error, GraphQL::STRING_TYPE, null: true,
description: 'Test suite error message.'
field :build_ids, [GraphQL::ID_TYPE], null: true,
description: 'IDs of the builds used to run the test suite.'
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
---
title: Add GraphQL endpoint for test report summary for pipelines
merge_request: 58596
author:
type: added
...@@ -4691,6 +4691,7 @@ Information about pagination in a connection. ...@@ -4691,6 +4691,7 @@ Information about pagination in a connection.
| `stages` | [`CiStageConnection`](#cistageconnection) | Stages of the pipeline. | | `stages` | [`CiStageConnection`](#cistageconnection) | Stages of the pipeline. |
| `startedAt` | [`Time`](#time) | Timestamp when the pipeline was started. | | `startedAt` | [`Time`](#time) | Timestamp when the pipeline was started. |
| `status` | [`PipelineStatusEnum!`](#pipelinestatusenum) | Status of the pipeline (CREATED, WAITING_FOR_RESOURCE, PREPARING, PENDING, RUNNING, FAILED, SUCCESS, CANCELED, SKIPPED, MANUAL, SCHEDULED). | | `status` | [`PipelineStatusEnum!`](#pipelinestatusenum) | Status of the pipeline (CREATED, WAITING_FOR_RESOURCE, PREPARING, PENDING, RUNNING, FAILED, SUCCESS, CANCELED, SKIPPED, MANUAL, SCHEDULED). |
| `testReportSummary` | [`TestReportSummary!`](#testreportsummary) | Summary of the test report generated by the pipeline. |
| `updatedAt` | [`Time!`](#time) | Timestamp of the pipeline's last activity. | | `updatedAt` | [`Time!`](#time) | Timestamp of the pipeline's last activity. |
| `upstream` | [`Pipeline`](#pipeline) | Pipeline that triggered the pipeline. | | `upstream` | [`Pipeline`](#pipeline) | Pipeline that triggered the pipeline. |
| `user` | [`User`](#user) | Pipeline user. | | `user` | [`User`](#user) | Pipeline user. |
...@@ -6225,6 +6226,65 @@ An edge in a connection. ...@@ -6225,6 +6226,65 @@ An edge in a connection.
| `cursor` | [`String!`](#string) | A cursor for use in pagination. | | `cursor` | [`String!`](#string) | A cursor for use in pagination. |
| `node` | [`TestReport`](#testreport) | The item at the end of the edge. | | `node` | [`TestReport`](#testreport) | The item at the end of the edge. |
### `TestReportSummary`
Test report for a pipeline.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `testSuites` | [`TestSuiteSummaryConnection!`](#testsuitesummaryconnection) | Test suites belonging to a pipeline test report. |
| `total` | [`TestReportTotal!`](#testreporttotal) | Total report statistics for a pipeline test report. |
### `TestReportTotal`
Total test report statistics.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `count` | [`Int`](#int) | Total number of the test cases. |
| `error` | [`Int`](#int) | Total number of test cases that had an error. |
| `failed` | [`Int`](#int) | Total number of test cases that failed. |
| `skipped` | [`Int`](#int) | Total number of test cases that were skipped. |
| `success` | [`Int`](#int) | Total number of test cases that succeeded. |
| `suiteError` | [`String`](#string) | Test suite error message. |
| `time` | [`Float`](#float) | Total duration of the tests. |
### `TestSuiteSummary`
Test suite summary in a pipeline test report.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `buildIds` | [`[ID!]`](#id) | IDs of the builds used to run the test suite. |
| `errorCount` | [`Int`](#int) | Total number of test cases that had an error. |
| `failedCount` | [`Int`](#int) | Total number of test cases that failed in the test suite. |
| `name` | [`String`](#string) | Name of the test suite. |
| `skippedCount` | [`Int`](#int) | Total number of test cases that were skipped in the test suite. |
| `successCount` | [`Int`](#int) | Total number of test cases that succeeded in the test suite. |
| `suiteError` | [`String`](#string) | Test suite error message. |
| `totalCount` | [`Int`](#int) | Total number of the test cases in the test suite. |
| `totalTime` | [`Float`](#float) | Total duration of the tests in the test suite. |
### `TestSuiteSummaryConnection`
The connection type for TestSuiteSummary.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `count` | [`Int!`](#int) | Total count of collection. |
| `edges` | [`[TestSuiteSummaryEdge]`](#testsuitesummaryedge) | A list of edges. |
| `nodes` | [`[TestSuiteSummary]`](#testsuitesummary) | A list of nodes. |
| `pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
### `TestSuiteSummaryEdge`
An edge in a connection.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `cursor` | [`String!`](#string) | A cursor for use in pagination. |
| `node` | [`TestSuiteSummary`](#testsuitesummary) | The item at the end of the edge. |
### `TimeReportStats` ### `TimeReportStats`
Represents the time report stats for timeboxes. Represents the time report stats for timeboxes.
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Resolvers::Ci::TestReportSummaryResolver do
include GraphqlHelpers
describe '#resolve' do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
subject(:resolve_subject) { resolve(described_class, obj: pipeline) }
context 'when pipeline has build report results' do
let(:pipeline) { create(:ci_pipeline, :with_report_results, project: project) }
it 'returns test report summary data' do
expect(resolve_subject.keys).to contain_exactly(:total, :test_suites)
expect(resolve_subject[:test_suites][0].keys).to contain_exactly(:build_ids, :name, :total_time, :total_count, :success_count, :failed_count, :skipped_count, :error_count, :suite_error)
expect(resolve_subject[:total][:time]).to eq(0.42)
expect(resolve_subject[:total][:count]).to eq(2)
expect(resolve_subject[:total][:success]).to eq(0)
expect(resolve_subject[:total][:failed]).to eq(0)
expect(resolve_subject[:total][:skipped]).to eq(0)
expect(resolve_subject[:total][:error]).to eq(2)
expect(resolve_subject[:total][:suite_error]).to eq(nil)
end
end
context 'when pipeline does not have build report results' do
let(:pipeline) { create(:ci_pipeline, project: project) }
it 'renders test report summary data' do
expect(resolve_subject.keys).to contain_exactly(:total, :test_suites)
expect(resolve_subject[:test_suites]).to eq([])
expect(resolve_subject[:total][:time]).to eq(0)
expect(resolve_subject[:total][:count]).to eq(0)
expect(resolve_subject[:total][:success]).to eq(0)
expect(resolve_subject[:total][:failed]).to eq(0)
expect(resolve_subject[:total][:skipped]).to eq(0)
expect(resolve_subject[:total][:error]).to eq(0)
expect(resolve_subject[:total][:suite_error]).to eq(nil)
end
end
end
end
...@@ -13,6 +13,7 @@ RSpec.describe Types::Ci::PipelineType do ...@@ -13,6 +13,7 @@ RSpec.describe Types::Ci::PipelineType do
coverage created_at updated_at started_at finished_at committed_at coverage created_at updated_at started_at finished_at committed_at
stages user retryable cancelable jobs source_job job downstream stages user retryable cancelable jobs source_job job downstream
upstream path project active user_permissions warnings commit_path uses_needs upstream path project active user_permissions warnings commit_path uses_needs
test_report_summary
] ]
if Gitlab.ee? if Gitlab.ee?
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Types::Ci::TestReportSummaryType do
specify { expect(described_class.graphql_name).to eq('TestReportSummary') }
it 'contains attributes related to a pipeline test report summary' do
expected_fields = %w[
total test_suites
]
expect(described_class).to have_graphql_fields(*expected_fields)
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Types::Ci::TestReportTotalType do
specify { expect(described_class.graphql_name).to eq('TestReportTotal') }
it 'contains attributes related to a pipeline test report summary' do
expected_fields = %w[
time count success failed skipped error suite_error
]
expect(described_class).to have_graphql_fields(*expected_fields)
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Types::Ci::TestSuiteSummaryType do
specify { expect(described_class.graphql_name).to eq('TestSuiteSummary') }
it 'contains attributes related to a pipeline test report summary' do
expected_fields = %w[
name total_time total_count success_count failed_count skipped_count error_count suite_error build_ids
]
expect(described_class).to have_graphql_fields(*expected_fields)
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