Commit beaa6353 authored by Małgorzata Ksionek's avatar Małgorzata Ksionek

Add class for group level analytics

Add specs for group level

Update entities

Update base classes

Add groups-centric changes

Update plan and review stage

Add summary classes

Add summary spec

Update specs files

Add to specs test cases for group

Add changelog entry

Add group serializer

Fix typo

Fix typo

Add fetching namespace in sql query

Update specs

Add rubocop fix

Add rubocop fix

Modify method to be in sync with code review

Add counting deploys from subgroup

To group summary stage

Add subgroups handling

In group stage summary

Add additional spec

Add additional specs

Add more precise inheritance

Add attr reader to group level

Fix rubocop offence

Fix problems with specs

Add cr remarks

Renaming median method and a lot of calls in specs

Move spec setup

Rename method in specs

Add code review remarks regarding module

Add proper module name
parent 0e8af252
# frozen_string_literal: true
module CycleAnalytics
class Base
module BaseMethods
STAGES = %i[issue plan code test review staging production].freeze
def all_medians_by_stage
STAGES.each_with_object({}) do |stage_name, medians_per_stage|
medians_per_stage[stage_name] = self[stage_name].median
medians_per_stage[stage_name] = self[stage_name].project_median
end
end
......@@ -21,7 +21,7 @@ module CycleAnalytics
end
def [](stage_name)
Gitlab::CycleAnalytics::Stage[stage_name].new(project: @project, options: @options)
Gitlab::CycleAnalytics::Stage[stage_name].new(options: options)
end
end
end
# frozen_string_literal: true
module CycleAnalytics
class GroupLevel
include BaseMethods
attr_reader :options
def initialize(options:)
@options = options
end
def summary
@summary ||= ::Gitlab::CycleAnalytics::GroupStageSummary.new(options[:group],
from: options[:from],
current_user: options[:current_user]).data
end
def permissions(user: nil)
STAGES.each_with_object({}) do |stage, obj|
obj[stage] = true
end
end
def stats
@stats ||= STAGES.map do |stage_name|
self[stage_name].as_json(serializer: GroupAnalyticsStageSerializer)
end
end
end
end
# frozen_string_literal: true
module CycleAnalytics
class ProjectLevel < Base
class ProjectLevel
include BaseMethods
attr_reader :project, :options
def initialize(project, options:)
@project = project
@options = options
@options = options.merge(project: project)
end
def summary
......
......@@ -20,12 +20,12 @@ class AnalyticsIssueEntity < Grape::Entity
end
expose :url do |object|
url_to(:namespace_project_issue, id: object[:iid].to_s)
url_to(:namespace_project_issue, object)
end
private
def url_to(route, id)
public_send("#{route}_url", request.project.namespace, request.project, id) # rubocop:disable GitlabSecurity/PublicSend
def url_to(route, object)
public_send("#{route}_url", object[:path], object[:name], object[:iid].to_s) # rubocop:disable GitlabSecurity/PublicSend
end
end
......@@ -4,6 +4,6 @@ class AnalyticsMergeRequestEntity < AnalyticsIssueEntity
expose :state
expose :url do |object|
url_to(:namespace_project_merge_request, id: object[:iid].to_s)
url_to(:namespace_project_merge_request, object)
end
end
......@@ -8,9 +8,9 @@ class AnalyticsStageEntity < Grape::Entity
expose :legend
expose :description
expose :median, as: :value do |stage|
expose :project_median, as: :value do |stage|
# median returns a BatchLoader instance which we first have to unwrap by using to_f
# we use to_f to make sure results below 1 are presented to the end-user
stage.median.to_f.nonzero? ? distance_of_time_in_words(stage.median) : nil
stage.project_median.to_f.nonzero? ? distance_of_time_in_words(stage.project_median) : nil
end
end
# frozen_string_literal: true
class GroupAnalyticsStageEntity < Grape::Entity
include EntityDateHelper
expose :title
expose :name
expose :legend
expose :description
expose :group_median, as: :value do |stage|
# median returns a BatchLoader instance which we first have to unwrap by using to_f
# we use to_f to make sure results below 1 are presented to the end-user
stage.group_median.to_f.nonzero? ? distance_of_time_in_words(stage.group_median) : nil
end
end
# frozen_string_literal: true
class GroupAnalyticsStageSerializer < BaseSerializer
entity GroupAnalyticsStageEntity
end
---
title: Adjust cycle analytics to group level
merge_request: 30391
author:
type: added
......@@ -5,12 +5,11 @@ module Gitlab
class BaseEventFetcher
include BaseQuery
attr_reader :projections, :query, :stage, :order, :project, :options
attr_reader :projections, :query, :stage, :order, :options
MAX_EVENTS = 50
def initialize(project: nil, stage:, options:)
@project = project
def initialize(stage:, options:)
@stage = stage
@options = options
end
......@@ -68,11 +67,23 @@ module Gitlab
end
def allowed_ids_source
{ project_id: project.id }
group ? { group_id: group.id, include_subgroups: true } : { project_id: project.id }
end
def serialization_context
{}
end
def projects
[project]
group ? Project.inside_path(group.full_path) : [project]
end
def group
@group ||= options.fetch(:group, nil)
end
def project
@project ||= options.fetch(:project, nil)
end
end
end
......
......@@ -16,17 +16,25 @@ module Gitlab
def stage_query(project_ids)
query = mr_closing_issues_table.join(issue_table).on(issue_table[:id].eq(mr_closing_issues_table[:issue_id]))
.join(issue_metrics_table).on(issue_table[:id].eq(issue_metrics_table[:issue_id]))
.join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
.join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
.where(issue_table[:project_id].in(project_ids))
.where(routes_table[:source_type].eq('Namespace'))
.where(issue_table[:created_at].gteq(options[:from]))
# Load merge_requests
query = query.join(mr_table, Arel::Nodes::OuterJoin)
query = load_merge_requests(query)
query
end
def load_merge_requests(query)
query.join(mr_table, Arel::Nodes::OuterJoin)
.on(mr_table[:id].eq(mr_closing_issues_table[:merge_request_id]))
.join(mr_metrics_table)
.on(mr_table[:id].eq(mr_metrics_table[:merge_request_id]))
query
end
end
end
......
......@@ -5,10 +5,9 @@ module Gitlab
class BaseStage
include BaseQuery
attr_reader :project, :options
attr_reader :options
def initialize(project: nil, options:)
@project = project
def initialize(options:)
@options = options
end
......@@ -24,7 +23,7 @@ module Gitlab
raise NotImplementedError.new("Expected #{self.name} to implement title")
end
def median
def project_median
return if project.nil?
BatchLoader.for(project.id).batch(key: name) do |project_ids, loader|
......@@ -42,6 +41,10 @@ module Gitlab
end
end
def group_median
median_query(projects.map(&:id))
end
def median_query(project_ids)
# Build a `SELECT` query. We find the first of the `end_time_attrs` that isn't `NULL` (call this end_time).
# Next, we find the first of the start_time_attrs that isn't `NULL` (call this start_time).
......@@ -67,8 +70,7 @@ module Gitlab
private
def event_fetcher
@event_fetcher ||= Gitlab::CycleAnalytics::EventFetcher[name].new(project: project,
stage: name,
@event_fetcher ||= Gitlab::CycleAnalytics::EventFetcher[name].new(stage: name,
options: event_options)
end
......@@ -77,7 +79,15 @@ module Gitlab
end
def projects
[project]
group ? Project.inside_path(group.full_path) : [project]
end
def group
@group ||= options.fetch(:group, nil)
end
def project
@project ||= options.fetch(:project, nil)
end
end
end
......
......@@ -11,7 +11,9 @@ module Gitlab
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
mr_table[:author_id]]
mr_table[:author_id],
projects_table[:name],
routes_table[:path]]
@order = mr_table[:created_at]
super(*args)
......@@ -20,7 +22,7 @@ module Gitlab
private
def serialize(event)
AnalyticsMergeRequestSerializer.new(project: project).represent(event)
AnalyticsMergeRequestSerializer.new(serialization_context).represent(event)
end
def allowed_ids_finder_class
......
# frozen_string_literal: true
module Gitlab
module CycleAnalytics
class GroupStageSummary
def initialize(group, from:, current_user:)
@group = group
@from = from
@current_user = current_user
end
def data
[serialize(Summary::Group::Issue.new(group: @group, from: @from, current_user: @current_user)),
serialize(Summary::Group::Deploy.new(group: @group, from: @from))]
end
private
def serialize(summary_object)
AnalyticsSummarySerializer.new.represent(summary_object)
end
end
end
end
......@@ -10,7 +10,9 @@ module Gitlab
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
issue_table[:author_id]]
issue_table[:author_id],
projects_table[:name],
routes_table[:path]]
super(*args)
end
......@@ -18,7 +20,7 @@ module Gitlab
private
def serialize(event)
AnalyticsIssueSerializer.new(project: project).represent(event)
AnalyticsIssueSerializer.new(serialization_context).represent(event)
end
def allowed_ids_finder_class
......
......@@ -5,8 +5,11 @@ module Gitlab
module IssueHelper
def stage_query(project_ids)
query = issue_table.join(issue_metrics_table).on(issue_table[:id].eq(issue_metrics_table[:issue_id]))
.join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
.join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
.where(issue_table[:project_id].in(project_ids))
.where(routes_table[:source_type].eq('Namespace'))
.where(issue_table[:created_at].gteq(options[:from]))
.where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
......
......@@ -35,6 +35,14 @@ module Gitlab
User.arel_table
end
def projects_table
Project.arel_table
end
def routes_table
Route.arel_table
end
def build_table
::CommitStatus.arel_table
end
......
......@@ -23,7 +23,7 @@ module Gitlab
end
def get
::CycleAnalytics::Base::STAGES.each do |stage|
::CycleAnalytics::BaseMethods::STAGES.each do |stage|
@stage_permission_hash[stage] = authorized_stage?(stage)
end
......
......@@ -10,7 +10,9 @@ module Gitlab
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
issue_table[:author_id]]
issue_table[:author_id],
projects_table[:name],
routes_table[:path]]
super(*args)
end
......@@ -18,7 +20,7 @@ module Gitlab
private
def serialize(event)
AnalyticsIssueSerializer.new(project: project).represent(event)
AnalyticsIssueSerializer.new(serialization_context).represent(event)
end
def allowed_ids_finder_class
......
......@@ -5,14 +5,21 @@ module Gitlab
module PlanHelper
def stage_query(project_ids)
query = issue_table.join(issue_metrics_table).on(issue_table[:id].eq(issue_metrics_table[:issue_id]))
.join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
.join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
.where(issue_table[:project_id].in(project_ids))
.where(issue_table[:created_at].gteq(options[:from]))
.where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
.where(issue_metrics_table[:first_mentioned_in_commit_at].not_eq(nil))
.where(routes_table[:source_type].eq('Namespace'))
query = add_conditions_to_query(query)
query
end
def add_conditions_to_query(query)
query.where(issue_table[:created_at].gteq(options[:from]))
.where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
.where(issue_metrics_table[:first_mentioned_in_commit_at].not_eq(nil))
end
end
end
end
......@@ -10,7 +10,9 @@ module Gitlab
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
issue_table[:author_id]]
issue_table[:author_id],
projects_table[:name],
routes_table[:path]]
super(*args)
end
......@@ -18,7 +20,7 @@ module Gitlab
private
def serialize(event)
AnalyticsIssueSerializer.new(project: project).represent(event)
AnalyticsIssueSerializer.new(serialization_context).represent(event)
end
def allowed_ids_finder_class
......
......@@ -11,7 +11,9 @@ module Gitlab
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
mr_table[:author_id]]
mr_table[:author_id],
projects_table[:name],
routes_table[:path]]
super(*args)
end
......@@ -19,7 +21,7 @@ module Gitlab
private
def serialize(event)
AnalyticsMergeRequestSerializer.new(project: project).represent(event)
AnalyticsMergeRequestSerializer.new(serialization_context).represent(event)
end
def allowed_ids_finder_class
......
# frozen_string_literal: true
module Gitlab
module CycleAnalytics
module Summary
module Group
class Base
def initialize(group:, from:)
@group = group
@from = from
end
def title
raise NotImplementedError.new("Expected #{self.name} to implement title")
end
def value
raise NotImplementedError.new("Expected #{self.name} to implement value")
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module CycleAnalytics
module Summary
module Group
class Deploy < Group::Base
def title
n_('Deploy', 'Deploys', value)
end
def value
@value ||= Deployment.joins(:project)
.where(projects: { id: projects })
.where("deployments.created_at > ?", @from)
.success
.count
end
private
def projects
Project.inside_path(@group.full_path).ids
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module CycleAnalytics
module Summary
module Group
class Issue < Group::Base
def initialize(group:, from:, current_user:)
@group = group
@from = from
@current_user = current_user
end
def title
n_('New Issue', 'New Issues', value)
end
def value
@value ||= IssuesFinder.new(@current_user, group_id: @group.id, include_subgroups: true).execute.created_after(@from).count
end
end
end
end
end
end
......@@ -9,12 +9,12 @@ describe Gitlab::CycleAnalytics::BaseEventFetcher do
let(:options) do
{ start_time_attrs: start_time_attrs,
end_time_attrs: end_time_attrs,
from: 30.days.ago }
from: 30.days.ago,
project: project }
end
subject do
described_class.new(project: project,
stage: :issue,
described_class.new(stage: :issue,
options: options).fetch
end
......
......@@ -5,31 +5,31 @@ describe Gitlab::CycleAnalytics::CodeStage do
let(:stage_name) { :code }
let(:project) { create(:project) }
let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
let!(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
let!(:mr_1) { create(:merge_request, source_project: project, created_at: 15.minutes.ago) }
let!(:mr_2) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'A') }
let!(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
let(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
let(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
let(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
let(:mr_1) { create(:merge_request, source_project: project, created_at: 15.minutes.ago) }
let(:mr_2) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'A') }
let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: project.creator, project: project }) }
before do
issue_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 45.minutes.ago)
issue_2.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
issue_3.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B')
create(:merge_requests_closing_issues, merge_request: mr_1, issue: issue_1)
create(:merge_requests_closing_issues, merge_request: mr_2, issue: issue_2)
end
it_behaves_like 'base stage'
describe '#median' do
describe '#project_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
expect(stage.median).to eq(ISSUES_MEDIAN)
expect(stage.project_median).to eq(ISSUES_MEDIAN)
end
end
......@@ -41,4 +41,80 @@ describe Gitlab::CycleAnalytics::CodeStage do
expect(result.map { |event| event[:title] }).to contain_exactly(mr_1.title, mr_2.title)
end
end
context 'when group is given' do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project_2) { create(:project, group: group) }
let(:project_3) { create(:project, group: group) }
let(:issue_2_1) { create(:issue, project: project_2, created_at: 90.minutes.ago) }
let(:issue_2_2) { create(:issue, project: project_3, created_at: 60.minutes.ago) }
let(:issue_2_3) { create(:issue, project: project_2, created_at: 60.minutes.ago) }
let(:mr_2_1) { create(:merge_request, source_project: project_2, created_at: 15.minutes.ago) }
let(:mr_2_2) { create(:merge_request, source_project: project_3, created_at: 10.minutes.ago, source_branch: 'A') }
let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: user, group: group }) }
before do
group.add_owner(user)
issue_2_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 45.minutes.ago)
issue_2_2.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
issue_2_3.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
create(:merge_requests_closing_issues, merge_request: mr_2_1, issue: issue_2_1)
create(:merge_requests_closing_issues, merge_request: mr_2_2, issue: issue_2_2)
end
describe '#group_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
expect(stage.group_median).to eq(ISSUES_MEDIAN)
end
end
describe '#events' do
it 'exposes merge requests that close issues' do
result = stage.events
expect(result.count).to eq(2)
expect(result.map { |event| event[:title] }).to contain_exactly(mr_2_1.title, mr_2_2.title)
end
end
context 'when subgroup is given' do
let(:subgroup) { create(:group, parent: group) }
let(:project_4) { create(:project, group: subgroup) }
let(:project_5) { create(:project, group: subgroup) }
let(:issue_3_1) { create(:issue, project: project_4, created_at: 90.minutes.ago) }
let(:issue_3_2) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
let(:issue_3_3) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
let(:mr_3_1) { create(:merge_request, source_project: project_4, created_at: 15.minutes.ago) }
let(:mr_3_2) { create(:merge_request, source_project: project_5, created_at: 10.minutes.ago, source_branch: 'A') }
before do
issue_3_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 45.minutes.ago)
issue_3_2.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
issue_3_3.metrics.update!(first_added_to_board_at: 60.minutes.ago, first_mentioned_in_commit_at: 40.minutes.ago)
create(:merge_requests_closing_issues, merge_request: mr_3_1, issue: issue_3_1)
create(:merge_requests_closing_issues, merge_request: mr_3_2, issue: issue_3_2)
end
describe '#events' do
it 'exposes merge requests that close issues' do
result = stage.events
expect(result.count).to eq(4)
expect(result.map { |event| event[:title] }).to contain_exactly(mr_2_1.title, mr_2_2.title, mr_3_1.title, mr_3_2.title)
end
it 'exposes merge requests that close issues with full path for subgroup' do
result = stage.events
expect(result.count).to eq(4)
expect(result.find { |event| event[:title] == mr_3_1.title }[:url]).to include("#{subgroup.full_path}")
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::CycleAnalytics::GroupStageSummary do
let(:group) { create(:group) }
let(:project) { create(:project, :repository, namespace: group) }
let(:project_2) { create(:project, :repository, namespace: group) }
let(:from) { 1.day.ago }
let(:user) { create(:user, :admin) }
subject { described_class.new(group, from: Time.now, current_user: user).data }
describe "#new_issues" do
it "finds the number of issues created after the 'from date'" do
Timecop.freeze(5.days.ago) { create(:issue, project: project) }
Timecop.freeze(5.days.ago) { create(:issue, project: project_2) }
Timecop.freeze(5.days.from_now) { create(:issue, project: project) }
Timecop.freeze(5.days.from_now) { create(:issue, project: project_2) }
expect(subject.first[:value]).to eq(2)
end
it "doesn't find issues from other projects" do
Timecop.freeze(5.days.from_now) { create(:issue, project: create(:project, namespace: create(:group))) }
Timecop.freeze(5.days.from_now) { create(:issue, project: project) }
Timecop.freeze(5.days.from_now) { create(:issue, project: project_2) }
expect(subject.first[:value]).to eq(2)
end
it "finds issues from subgroups" do
Timecop.freeze(5.days.from_now) { create(:issue, project: create(:project, namespace: create(:group, parent: group))) }
Timecop.freeze(5.days.from_now) { create(:issue, project: project) }
Timecop.freeze(5.days.from_now) { create(:issue, project: project_2) }
expect(subject.first[:value]).to eq(3)
end
end
describe "#deploys" do
it "finds the number of deploys made created after the 'from date'" do
Timecop.freeze(5.days.ago) { create(:deployment, :success, project: project) }
Timecop.freeze(5.days.from_now) { create(:deployment, :success, project: project) }
Timecop.freeze(5.days.ago) { create(:deployment, :success, project: project_2) }
Timecop.freeze(5.days.from_now) { create(:deployment, :success, project: project_2) }
expect(subject.second[:value]).to eq(2)
end
it "doesn't find deploys from other projects" do
Timecop.freeze(5.days.from_now) do
create(:deployment, :success, project: create(:project, :repository, namespace: create(:group)))
end
expect(subject.second[:value]).to eq(0)
end
it "finds deploys from subgroups" do
Timecop.freeze(5.days.from_now) do
create(:deployment, :success, project: create(:project, :repository, namespace: create(:group, parent: group)))
end
expect(subject.second[:value]).to eq(1)
end
end
end
......@@ -4,11 +4,11 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::IssueStage do
let(:stage_name) { :issue }
let(:project) { create(:project) }
let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
let!(:issue_3) { create(:issue, project: project, created_at: 30.minutes.ago) }
let(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
let(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
let(:issue_3) { create(:issue, project: project, created_at: 30.minutes.ago) }
let!(:issue_without_milestone) { create(:issue, project: project, created_at: 1.minute.ago) }
let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: project.creator, project: project }) }
before do
issue_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago )
......@@ -24,7 +24,7 @@ describe Gitlab::CycleAnalytics::IssueStage do
end
it 'counts median from issues with metrics' do
expect(stage.median).to eq(ISSUES_MEDIAN)
expect(stage.project_median).to eq(ISSUES_MEDIAN)
end
end
......@@ -36,4 +36,69 @@ describe Gitlab::CycleAnalytics::IssueStage do
expect(result.map { |event| event[:title] }).to contain_exactly(issue_1.title, issue_2.title, issue_3.title)
end
end
context 'when group is given' do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project_2) { create(:project, group: group) }
let(:project_3) { create(:project, group: group) }
let(:issue_2_1) { create(:issue, project: project_2, created_at: 90.minutes.ago) }
let(:issue_2_2) { create(:issue, project: project_3, created_at: 60.minutes.ago) }
let(:issue_2_3) { create(:issue, project: project_2, created_at: 60.minutes.ago) }
let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: user, group: group }) }
before do
group.add_owner(user)
issue_2_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago)
issue_2_2.metrics.update!(first_added_to_board_at: 30.minutes.ago)
end
describe '#group_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
expect(stage.group_median).to eq(ISSUES_MEDIAN)
end
end
describe '#events' do
it 'exposes merge requests that close issues' do
result = stage.events
expect(result.count).to eq(2)
expect(result.map { |event| event[:title] }).to contain_exactly(issue_2_1.title, issue_2_2.title)
end
end
context 'when subgroup is given' do
let(:subgroup) { create(:group, parent: group) }
let(:project_4) { create(:project, group: subgroup) }
let(:project_5) { create(:project, group: subgroup) }
let(:issue_3_1) { create(:issue, project: project_4, created_at: 90.minutes.ago) }
let(:issue_3_2) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
let(:issue_3_3) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
before do
issue_3_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago)
issue_3_2.metrics.update!(first_added_to_board_at: 30.minutes.ago)
end
describe '#events' do
it 'exposes merge requests that close issues' do
result = stage.events
expect(result.count).to eq(4)
expect(result.map { |event| event[:title] }).to contain_exactly(issue_2_1.title, issue_2_2.title, issue_3_1.title, issue_3_2.title)
end
it 'exposes merge requests that close issues with full path for subgroup' do
result = stage.events
expect(result.count).to eq(4)
expect(result.find { |event| event[:title] == issue_3_1.title }[:url]).to include("#{subgroup.full_path}")
end
end
end
end
end
......@@ -8,7 +8,7 @@ describe Gitlab::CycleAnalytics::PlanStage do
let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
let!(:issue_3) { create(:issue, project: project, created_at: 30.minutes.ago) }
let!(:issue_without_milestone) { create(:issue, project: project, created_at: 1.minute.ago) }
let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: project.creator, project: project }) }
before do
issue_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 10.minutes.ago)
......@@ -18,13 +18,13 @@ describe Gitlab::CycleAnalytics::PlanStage do
it_behaves_like 'base stage'
describe '#median' do
describe '#project_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
expect(stage.median).to eq(ISSUES_MEDIAN)
expect(stage.project_median).to eq(ISSUES_MEDIAN)
end
end
......@@ -36,4 +36,72 @@ describe Gitlab::CycleAnalytics::PlanStage do
expect(result.map { |event| event[:title] }).to contain_exactly(issue_1.title, issue_2.title)
end
end
context 'when group is given' do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project_2) { create(:project, group: group) }
let(:project_3) { create(:project, group: group) }
let(:issue_2_1) { create(:issue, project: project_2, created_at: 90.minutes.ago) }
let(:issue_2_2) { create(:issue, project: project_3, created_at: 60.minutes.ago) }
let(:issue_2_3) { create(:issue, project: project_2, created_at: 60.minutes.ago) }
let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: user, group: group }) }
before do
group.add_owner(user)
issue_2_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 10.minutes.ago)
issue_2_2.metrics.update!(first_added_to_board_at: 30.minutes.ago, first_mentioned_in_commit_at: 20.minutes.ago)
issue_2_3.metrics.update!(first_added_to_board_at: 15.minutes.ago)
end
describe '#group_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
expect(stage.group_median).to eq(ISSUES_MEDIAN)
end
end
describe '#events' do
it 'exposes merge requests that close issues' do
result = stage.events
expect(result.count).to eq(2)
expect(result.map { |event| event[:title] }).to contain_exactly(issue_2_1.title, issue_2_2.title)
end
end
context 'when subgroup is given' do
let(:subgroup) { create(:group, parent: group) }
let(:project_4) { create(:project, group: subgroup) }
let(:project_5) { create(:project, group: subgroup) }
let(:issue_3_1) { create(:issue, project: project_4, created_at: 90.minutes.ago) }
let(:issue_3_2) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
let(:issue_3_3) { create(:issue, project: project_5, created_at: 60.minutes.ago) }
before do
issue_3_1.metrics.update!(first_associated_with_milestone_at: 60.minutes.ago, first_mentioned_in_commit_at: 10.minutes.ago)
issue_3_2.metrics.update!(first_added_to_board_at: 30.minutes.ago, first_mentioned_in_commit_at: 20.minutes.ago)
issue_3_3.metrics.update!(first_added_to_board_at: 15.minutes.ago)
end
describe '#events' do
it 'exposes merge requests that close issues' do
result = stage.events
expect(result.count).to eq(4)
expect(result.map { |event| event[:title] }).to contain_exactly(issue_2_1.title, issue_2_2.title, issue_3_1.title, issue_3_2.title)
end
it 'exposes merge requests that close issues with full path for subgroup' do
result = stage.events
expect(result.count).to eq(4)
expect(result.find { |event| event[:title] == issue_3_1.title }[:url]).to include("#{subgroup.full_path}")
end
end
end
end
end
......@@ -4,14 +4,14 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::ReviewStage do
let(:stage_name) { :review }
let(:project) { create(:project) }
let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
let!(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
let!(:mr_1) { create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago) }
let!(:mr_2) { create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A') }
let!(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
let(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
let(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
let(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
let(:mr_1) { create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago) }
let(:mr_2) { create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A') }
let(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
let!(:mr_4) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'C') }
let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: project.creator, project: project }) }
before do
mr_1.metrics.update!(merged_at: 30.minutes.ago)
......@@ -24,13 +24,13 @@ describe Gitlab::CycleAnalytics::ReviewStage do
it_behaves_like 'base stage'
describe '#median' do
describe '#project_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
expect(stage.median).to eq(ISSUES_MEDIAN)
expect(stage.project_median).to eq(ISSUES_MEDIAN)
end
end
......@@ -42,4 +42,47 @@ describe Gitlab::CycleAnalytics::ReviewStage do
expect(result.map { |event| event[:title] }).to contain_exactly(mr_1.title, mr_2.title)
end
end
context 'when group is given' do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project_2) { create(:project, group: group) }
let(:project_3) { create(:project, group: group) }
let(:issue_2_1) { create(:issue, project: project_2, created_at: 90.minutes.ago) }
let(:issue_2_2) { create(:issue, project: project_3, created_at: 60.minutes.ago) }
let(:issue_2_3) { create(:issue, project: project_2, created_at: 60.minutes.ago) }
let(:mr_2_1) { create(:merge_request, :closed, source_project: project_2, created_at: 60.minutes.ago) }
let(:mr_2_2) { create(:merge_request, :closed, source_project: project_3, created_at: 40.minutes.ago, source_branch: 'A') }
let(:mr_2_3) { create(:merge_request, source_project: project_2, created_at: 10.minutes.ago, source_branch: 'B') }
let!(:mr_2_4) { create(:merge_request, source_project: project_3, created_at: 10.minutes.ago, source_branch: 'C') }
let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: user, group: group }) }
before do
group.add_owner(user)
mr_2_1.metrics.update!(merged_at: 30.minutes.ago)
mr_2_2.metrics.update!(merged_at: 10.minutes.ago)
create(:merge_requests_closing_issues, merge_request: mr_2_1, issue: issue_2_1)
create(:merge_requests_closing_issues, merge_request: mr_2_2, issue: issue_2_2)
create(:merge_requests_closing_issues, merge_request: mr_2_3, issue: issue_2_3)
end
describe '#group_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
expect(stage.group_median).to eq(ISSUES_MEDIAN)
end
end
describe '#events' do
it 'exposes merge requests that close issues' do
result = stage.events
expect(result.count).to eq(2)
expect(result.map { |event| event[:title] }).to contain_exactly(mr_2_1.title, mr_2_2.title)
end
end
end
end
......@@ -2,7 +2,7 @@ require 'spec_helper'
shared_examples 'default query config' do
let(:project) { create(:project) }
let(:event) { described_class.new(project: project, stage: stage_name, options: { from: 1.day.ago }) }
let(:event) { described_class.new(stage: stage_name, options: { from: 1.day.ago, project: project }) }
it 'has the stage attribute' do
expect(event.stage).not_to be_nil
......
......@@ -3,10 +3,10 @@ require 'spec_helper'
shared_examples 'base stage' do
ISSUES_MEDIAN = 30.minutes.to_i
let(:stage) { described_class.new(project: double, options: {}) }
let(:stage) { described_class.new(options: { project: double }) }
before do
allow(stage).to receive(:median).and_return(1.12)
allow(stage).to receive(:project_median).and_return(1.12)
allow_any_instance_of(Gitlab::CycleAnalytics::BaseEventFetcher).to receive(:event_result).and_return({})
end
......
......@@ -5,16 +5,16 @@ describe Gitlab::CycleAnalytics::StagingStage do
let(:stage_name) { :staging }
let(:project) { create(:project) }
let!(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
let!(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
let!(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
let!(:mr_1) { create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago) }
let!(:mr_2) { create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A') }
let!(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
let(:issue_1) { create(:issue, project: project, created_at: 90.minutes.ago) }
let(:issue_2) { create(:issue, project: project, created_at: 60.minutes.ago) }
let(:issue_3) { create(:issue, project: project, created_at: 60.minutes.ago) }
let(:mr_1) { create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago) }
let(:mr_2) { create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A') }
let(:mr_3) { create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B') }
let(:build_1) { create(:ci_build, project: project) }
let(:build_2) { create(:ci_build, project: project) }
let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: project.creator, project: project }) }
before do
mr_1.metrics.update!(merged_at: 80.minutes.ago, first_deployed_to_production_at: 50.minutes.ago, pipeline_id: build_1.commit_id)
......@@ -28,13 +28,13 @@ describe Gitlab::CycleAnalytics::StagingStage do
it_behaves_like 'base stage'
describe '#median' do
describe '#project_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
expect(stage.median).to eq(ISSUES_MEDIAN)
expect(stage.project_median).to eq(ISSUES_MEDIAN)
end
end
......@@ -46,4 +46,50 @@ describe Gitlab::CycleAnalytics::StagingStage do
expect(result.map { |event| event[:name] }).to contain_exactly(build_1.name, build_2.name)
end
end
context 'when group is given' do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project_2) { create(:project, group: group) }
let(:project_3) { create(:project, group: group) }
let(:issue_2_1) { create(:issue, project: project_2, created_at: 90.minutes.ago) }
let(:issue_2_2) { create(:issue, project: project_3, created_at: 60.minutes.ago) }
let(:issue_2_3) { create(:issue, project: project_2, created_at: 60.minutes.ago) }
let(:mr_1) { create(:merge_request, :closed, source_project: project_2, created_at: 60.minutes.ago) }
let(:mr_2) { create(:merge_request, :closed, source_project: project_3, created_at: 40.minutes.ago, source_branch: 'A') }
let(:mr_3) { create(:merge_request, source_project: project_2, created_at: 10.minutes.ago, source_branch: 'B') }
let(:build_1) { create(:ci_build, project: project_2) }
let(:build_2) { create(:ci_build, project: project_3) }
let(:stage) { described_class.new(options: { from: 2.days.ago, current_user: user, group: group }) }
before do
group.add_owner(user)
mr_1.metrics.update!(merged_at: 80.minutes.ago, first_deployed_to_production_at: 50.minutes.ago, pipeline_id: build_1.commit_id)
mr_2.metrics.update!(merged_at: 60.minutes.ago, first_deployed_to_production_at: 30.minutes.ago, pipeline_id: build_2.commit_id)
mr_3.metrics.update!(merged_at: 10.minutes.ago, first_deployed_to_production_at: 3.days.ago, pipeline_id: create(:ci_build, project: project_2).commit_id)
create(:merge_requests_closing_issues, merge_request: mr_1, issue: issue_2_1)
create(:merge_requests_closing_issues, merge_request: mr_2, issue: issue_2_2)
create(:merge_requests_closing_issues, merge_request: mr_3, issue: issue_2_3)
end
describe '#group_median' do
around do |example|
Timecop.freeze { example.run }
end
it 'counts median from issues with metrics' do
expect(stage.group_median).to eq(ISSUES_MEDIAN)
end
end
describe '#events' do
it 'exposes merge requests that close issues' do
result = stage.events
expect(result.count).to eq(2)
expect(result.map { |event| event[:name] }).to contain_exactly(build_1.name, build_2.name)
end
end
end
end
......@@ -34,7 +34,7 @@ describe Gitlab::CycleAnalytics::UsageData do
expect(result).to have_key(:avg_cycle_analytics)
CycleAnalytics::Base::STAGES.each do |stage|
CycleAnalytics::BaseMethods::STAGES.each do |stage|
expect(result[:avg_cycle_analytics]).to have_key(stage)
stage_values = result[:avg_cycle_analytics][stage]
......
......@@ -38,7 +38,7 @@ describe 'CycleAnalytics#code' do
merge_merge_requests_closing_issue(user, project, issue)
deploy_master(user, project)
expect(subject[:code].median).to be_nil
expect(subject[:code].project_median).to be_nil
end
end
end
......@@ -68,7 +68,7 @@ describe 'CycleAnalytics#code' do
merge_merge_requests_closing_issue(user, project, issue)
expect(subject[:code].median).to be_nil
expect(subject[:code].project_median).to be_nil
end
end
end
......
# frozen_string_literal: true
require 'spec_helper'
describe CycleAnalytics::GroupLevel do
let(:group) { create(:group)}
let(:project) { create(:project, :repository, namespace: group) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
let(:milestone) { create(:milestone, project: project) }
let(:mr) { create_merge_request_closing_issue(user, project, issue, commit_message: "References #{issue.to_reference}") }
let(:pipeline) { create(:ci_empty_pipeline, status: 'created', project: project, ref: mr.source_branch, sha: mr.source_branch_sha, head_pipeline_of: mr) }
subject { described_class.new(options: { from: from_date, group: group, current_user: user }) }
describe '#permissions' do
it 'returns permissions' do
expect(subject.permissions.values.uniq).to eq([true])
end
end
describe '#stats' do
before do
allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([issue])
create_cycle(user, project, issue, mr, milestone, pipeline)
deploy_master(user, project)
end
it 'returns medians for each stage for a specific group' do
expect(subject.no_stats?).to eq(false)
end
end
describe '#summary' do
before do
create_cycle(user, project, issue, mr, milestone, pipeline)
deploy_master(user, project)
end
it 'returns medians for each stage for a specific group' do
expect(subject.summary.map { |summary| summary[:value] }).to contain_exactly(1, 1)
end
end
end
......@@ -43,7 +43,7 @@ describe 'CycleAnalytics#issue' do
create_merge_request_closing_issue(user, project, issue)
merge_merge_requests_closing_issue(user, project, issue)
expect(subject[:issue].median).to be_nil
expect(subject[:issue].project_median).to be_nil
end
end
end
......@@ -47,7 +47,7 @@ describe 'CycleAnalytics#plan' do
create_merge_request_closing_issue(user, project, issue, source_branch: branch_name)
merge_merge_requests_closing_issue(user, project, issue)
expect(subject[:issue].median).to be_nil
expect(subject[:issue].project_median).to be_nil
end
end
end
......@@ -41,7 +41,7 @@ describe 'CycleAnalytics#production' do
MergeRequests::MergeService.new(project, user).execute(merge_request)
deploy_master(user, project)
expect(subject[:production].median).to be_nil
expect(subject[:production].project_median).to be_nil
end
end
......@@ -52,7 +52,7 @@ describe 'CycleAnalytics#production' do
MergeRequests::MergeService.new(project, user).execute(merge_request)
deploy_master(user, project, environment: 'staging')
expect(subject[:production].median).to be_nil
expect(subject[:production].project_median).to be_nil
end
end
end
......@@ -23,7 +23,7 @@ describe CycleAnalytics::ProjectLevel do
it 'returns every median for each stage for a specific project' do
values = described_class::STAGES.each_with_object({}) do |stage_name, hsh|
hsh[stage_name] = subject[stage_name].median.presence
hsh[stage_name] = subject[stage_name].project_median.presence
end
expect(subject.all_medians_by_stage).to eq(values)
......
......@@ -28,7 +28,7 @@ describe 'CycleAnalytics#review' do
it "returns nil" do
MergeRequests::MergeService.new(project, user).execute(create(:merge_request))
expect(subject[:review].median).to be_nil
expect(subject[:review].project_median).to be_nil
end
end
end
......@@ -45,7 +45,7 @@ describe 'CycleAnalytics#staging' do
MergeRequests::MergeService.new(project, user).execute(merge_request)
deploy_master(user, project)
expect(subject[:staging].median).to be_nil
expect(subject[:staging].project_median).to be_nil
end
end
......@@ -56,7 +56,7 @@ describe 'CycleAnalytics#staging' do
MergeRequests::MergeService.new(project, user).execute(merge_request)
deploy_master(user, project, environment: 'staging')
expect(subject[:staging].median).to be_nil
expect(subject[:staging].project_median).to be_nil
end
end
end
......@@ -36,7 +36,7 @@ describe 'CycleAnalytics#test' do
merge_merge_requests_closing_issue(user, project, issue)
expect(subject[:test].median).to be_nil
expect(subject[:test].project_median).to be_nil
end
end
......@@ -47,7 +47,7 @@ describe 'CycleAnalytics#test' do
pipeline.run!
pipeline.succeed!
expect(subject[:test].median).to be_nil
expect(subject[:test].project_median).to be_nil
end
end
......@@ -62,7 +62,7 @@ describe 'CycleAnalytics#test' do
merge_merge_requests_closing_issue(user, project, issue)
expect(subject[:test].median).to be_nil
expect(subject[:test].project_median).to be_nil
end
end
......@@ -77,7 +77,7 @@ describe 'CycleAnalytics#test' do
merge_merge_requests_closing_issue(user, project, issue)
expect(subject[:test].median).to be_nil
expect(subject[:test].project_median).to be_nil
end
end
end
......@@ -9,12 +9,14 @@ describe AnalyticsIssueEntity do
iid: "1",
id: "1",
created_at: "2016-11-12 15:04:02.948604",
author: user
author: user,
name: project.name,
path: project.namespace
}
end
let(:project) { create(:project) }
let(:request) { EntityRequest.new(project: project, entity: :merge_request) }
let(:request) { EntityRequest.new(entity: :merge_request) }
let(:entity) do
described_class.new(entity_hash, request: request, project: project)
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe AnalyticsIssueSerializer do
subject do
described_class
.new(project: project, entity: :merge_request)
.new(entity: :merge_request)
.represent(resource)
end
......@@ -16,7 +16,9 @@ describe AnalyticsIssueSerializer do
iid: "1",
id: "1",
created_at: "2016-11-12 15:04:02.948604",
author: user
author: user,
name: project.name,
path: project.namespace
}
end
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe AnalyticsMergeRequestSerializer do
subject do
described_class
.new(project: project, entity: :merge_request)
.new(entity: :merge_request)
.represent(resource)
end
......@@ -17,7 +17,9 @@ describe AnalyticsMergeRequestSerializer do
id: "1",
state: 'open',
created_at: "2016-11-12 15:04:02.948604",
author: user
author: user,
name: project.name,
path: project.namespace
}
end
......
......@@ -6,11 +6,11 @@ describe AnalyticsStageSerializer do
end
let(:resource) do
Gitlab::CycleAnalytics::CodeStage.new(project: double, options: {})
Gitlab::CycleAnalytics::CodeStage.new(options: { project: double })
end
before do
allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:median).and_return(1.12)
allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:project_median).and_return(1.12)
allow_any_instance_of(Gitlab::CycleAnalytics::BaseEventFetcher).to receive(:event_result).and_return({})
end
......@@ -24,7 +24,7 @@ describe AnalyticsStageSerializer do
context 'when median is equal 0' do
before do
allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:median).and_return(0)
allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:project_median).and_return(0)
end
it 'sets the value to nil' do
......@@ -34,7 +34,7 @@ describe AnalyticsStageSerializer do
context 'when median is below 1' do
before do
allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:median).and_return(0.12)
allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:project_median).and_return(0.12)
end
it 'sets the value to equal to median' do
......@@ -44,7 +44,7 @@ describe AnalyticsStageSerializer do
context 'when median is above 1' do
before do
allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:median).and_return(60.12)
allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:project_median).and_return(60.12)
end
it 'sets the value to equal to median' do
......
......@@ -50,7 +50,7 @@ module CycleAnalyticsHelpers
end
median_time_difference = time_differences.sort[2]
expect(subject[phase].median).to be_within(5).of(median_time_difference)
expect(subject[phase].project_median).to be_within(5).of(median_time_difference)
end
context "when the data belongs to another project" do
......@@ -80,7 +80,7 @@ module CycleAnalyticsHelpers
# Turn off the stub before checking assertions
allow(self).to receive(:project).and_call_original
expect(subject[phase].median).to be_nil
expect(subject[phase].project_median).to be_nil
end
end
......@@ -103,7 +103,7 @@ module CycleAnalyticsHelpers
Timecop.freeze(end_time + 1.day) { post_fn[self, data] } if post_fn
expect(subject[phase].median).to be_nil
expect(subject[phase].project_median).to be_nil
end
end
end
......@@ -121,7 +121,7 @@ module CycleAnalyticsHelpers
Timecop.freeze(end_time + 1.day) { post_fn[self, data] } if post_fn
expect(subject[phase].median).to be_nil
expect(subject[phase].project_median).to be_nil
end
end
end
......@@ -138,7 +138,7 @@ module CycleAnalyticsHelpers
post_fn[self, data] if post_fn
expect(subject[phase].median).to be_nil
expect(subject[phase].project_median).to be_nil
end
end
end
......@@ -146,7 +146,7 @@ module CycleAnalyticsHelpers
context "when none of the start / end conditions are matched" do
it "returns nil" do
expect(subject[phase].median).to be_nil
expect(subject[phase].project_median).to be_nil
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