Commit 0d1adc9f authored by Sean McGivern's avatar Sean McGivern

Merge branch 'adjust-cycle-analytics-to-group-level' into 'master'

Adjust cycle analytics to group level

See merge request gitlab-org/gitlab-ce!30391
parents f4ce99c5 196dfd12
# frozen_string_literal: true
module CycleAnalytics
class GroupLevel
include LevelBase
attr_reader :options, :group
def initialize(group:, options:)
@group = group
@options = options.merge(group: group)
end
def summary
@summary ||= ::Gitlab::CycleAnalytics::GroupStageSummary.new(group,
from: options[:from],
current_user: options[:current_user]).data
end
def permissions(*)
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 Base
module LevelBase
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 ProjectLevel < Base
class ProjectLevel
include LevelBase
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|
# group_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
......@@ -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::LevelBase::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, created_after: @from).execute.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,40 +5,114 @@ 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
describe '#events' do
subject { stage.events }
it 'exposes merge requests that closes issues' do
result = stage.events
expect(subject.count).to eq(2)
expect(subject.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
subject { stage.events }
it 'exposes merge requests that close issues' do
expect(subject.count).to eq(2)
expect(subject.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
subject { stage.events }
it 'exposes merge requests that close issues' do
expect(subject.count).to eq(4)
expect(subject.map { |event| event[:title] }).to contain_exactly(mr_2_1.title, mr_2_2.title, mr_3_1.title, mr_3_2.title)
end
expect(result.count).to eq(2)
expect(result.map { |event| event[:title] }).to contain_exactly(mr_1.title, mr_2.title)
it 'exposes merge requests that close issues with full path for subgroup' do
expect(subject.count).to eq(4)
expect(subject.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
context 'with from date' do
before 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) }
end
it "finds the number of issues created after it" do
expect(subject.first[:value]).to eq(2)
end
context 'with subgroups' do
before do
Timecop.freeze(5.days.from_now) { create(:issue, project: create(:project, namespace: create(:group, parent: group))) }
end
it "finds issues from them" do
expect(subject.first[:value]).to eq(3)
end
end
end
context 'with other projects' do
before 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) }
end
it "doesn't find issues from them" do
expect(subject.first[:value]).to eq(2)
end
end
end
describe "#deploys" do
context 'with from date' do
before 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) }
end
it "finds the number of deploys made created after it" do
expect(subject.second[:value]).to eq(2)
end
context 'with subgroups' do
before do
Timecop.freeze(5.days.from_now) do
create(:deployment, :success, project: create(:project, :repository, namespace: create(:group, parent: group)))
end
end
it "finds deploys from them" do
expect(subject.second[:value]).to eq(3)
end
end
end
context 'with other projects' do
before do
Timecop.freeze(5.days.from_now) do
create(:deployment, :success, project: create(:project, :repository, namespace: create(:group)))
end
end
it "doesn't find deploys from them" do
expect(subject.second[:value]).to eq(0)
end
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,67 @@ 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
subject { stage.events }
it 'exposes merge requests that close issues' do
expect(subject.count).to eq(2)
expect(subject.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
subject { stage.events }
it 'exposes merge requests that close issues' do
expect(subject.count).to eq(4)
expect(subject.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
expect(subject.count).to eq(4)
expect(subject.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,22 +18,88 @@ 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
describe '#events' do
subject { stage.events }
it 'exposes issues with metrics' do
result = stage.events
expect(subject.count).to eq(2)
expect(subject.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
subject { stage.events }
it 'exposes merge requests that close issues' do
expect(subject.count).to eq(2)
expect(subject.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
subject { stage.events }
it 'exposes merge requests that close issues' do
expect(subject.count).to eq(4)
expect(subject.map { |event| event[:title] }).to contain_exactly(issue_2_1.title, issue_2_2.title, issue_3_1.title, issue_3_2.title)
end
expect(result.count).to eq(2)
expect(result.map { |event| event[:title] }).to contain_exactly(issue_1.title, issue_2.title)
it 'exposes merge requests that close issues with full path for subgroup' do
expect(subject.count).to eq(4)
expect(subject.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,22 +24,66 @@ 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
describe '#events' do
subject { stage.events }
it 'exposes merge requests that close issues' do
result = stage.events
expect(subject.count).to eq(2)
expect(subject.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
subject { stage.events }
expect(result.count).to eq(2)
expect(result.map { |event| event[:title] }).to contain_exactly(mr_1.title, mr_2.title)
it 'exposes merge requests that close issues' do
expect(subject.count).to eq(2)
expect(subject.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,22 +28,68 @@ 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
describe '#events' do
subject { stage.events }
it 'exposes builds connected to merge request' do
result = stage.events
expect(subject.count).to eq(2)
expect(subject.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
subject { stage.events }
expect(result.count).to eq(2)
expect(result.map { |event| event[:name] }).to contain_exactly(build_1.name, build_2.name)
it 'exposes merge requests that close issues' do
expect(subject.count).to eq(2)
expect(subject.map { |event| event[:name] }).to contain_exactly(build_1.name, build_2.name)
end
end
end
end
......@@ -4,7 +4,7 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::TestStage do
let(:stage_name) { :test }
let(:project) { create(: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 }) }
it_behaves_like 'base stage'
......@@ -36,7 +36,7 @@ describe Gitlab::CycleAnalytics::TestStage 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
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::LevelBase::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(group: group, options: { from: from_date, current_user: user }) }
describe '#permissions' do
it 'returns true for all stages' 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