diff options
Diffstat (limited to 'spec')
50 files changed, 1015 insertions, 187 deletions
diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb index 63f33633a3c..609e7e20187 100644 --- a/spec/factories/clusters/clusters.rb +++ b/spec/factories/clusters/clusters.rb @@ -93,5 +93,25 @@ FactoryBot.define do trait :not_managed do managed { false } end + + trait :cleanup_not_started do + cleanup_status { 1 } + end + + trait :cleanup_uninstalling_applications do + cleanup_status { 2 } + end + + trait :cleanup_removing_project_namespaces do + cleanup_status { 3 } + end + + trait :cleanup_removing_service_account do + cleanup_status { 4 } + end + + trait :cleanup_errored do + cleanup_status { 5 } + end end end diff --git a/spec/graphql/features/authorization_spec.rb b/spec/graphql/features/authorization_spec.rb index 9a60ff3b78c..7ad6a622b4b 100644 --- a/spec/graphql/features/authorization_spec.rb +++ b/spec/graphql/features/authorization_spec.rb @@ -259,7 +259,8 @@ describe 'Gitlab::Graphql::Authorization' do let(:project_type) do |type| type_factory do |type| type.graphql_name 'FakeProjectType' - type.field :test_issues, issue_type.connection_type, null: false, resolve: -> (_, _, _) { Issue.where(project: [visible_project, other_project]) } + type.field :test_issues, issue_type.connection_type, null: false, + resolve: -> (_, _, _) { Issue.where(project: [visible_project, other_project]).order(id: :asc) } end end let(:query_type) do diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb index 0a27bbecfef..dcf3c989047 100644 --- a/spec/graphql/gitlab_schema_spec.rb +++ b/spec/graphql/gitlab_schema_spec.rb @@ -36,7 +36,7 @@ describe GitlabSchema do it 'paginates active record relations using `Gitlab::Graphql::Connections::KeysetConnection`' do connection = GraphQL::Relay::BaseConnection::CONNECTION_IMPLEMENTATIONS[ActiveRecord::Relation.name] - expect(connection).to eq(Gitlab::Graphql::Connections::KeysetConnection) + expect(connection).to eq(Gitlab::Graphql::Connections::Keyset::Connection) end describe '.execute' do diff --git a/spec/helpers/gitlab_routing_helper_spec.rb b/spec/helpers/gitlab_routing_helper_spec.rb index bf043f3f013..38699108b06 100644 --- a/spec/helpers/gitlab_routing_helper_spec.rb +++ b/spec/helpers/gitlab_routing_helper_spec.rb @@ -75,6 +75,12 @@ describe GitlabRoutingHelper do expect(preview_markdown_path(group)).to eq("/groups/#{group.path}/preview_markdown") end + it 'returns group preview markdown path for a group parent with args' do + group = create(:group) + + expect(preview_markdown_path(group, { type_id: 5 })).to eq("/groups/#{group.path}/preview_markdown?type_id=5") + end + it 'returns project preview markdown path for a project parent' do expect(preview_markdown_path(project)).to eq("/#{project.full_path}/preview_markdown") end diff --git a/spec/lib/gitlab/graphql/connections/keyset/conditions/not_null_condition_spec.rb b/spec/lib/gitlab/graphql/connections/keyset/conditions/not_null_condition_spec.rb new file mode 100644 index 00000000000..d943540fe1f --- /dev/null +++ b/spec/lib/gitlab/graphql/connections/keyset/conditions/not_null_condition_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Graphql::Connections::Keyset::Conditions::NotNullCondition do + describe '#build' do + let(:condition) { described_class.new(Issue.arel_table, %w(relative_position id), [1500, 500], ['>', '>'], before_or_after) } + + context 'when there is only one ordering field' do + let(:condition) { described_class.new(Issue.arel_table, ['id'], [500], ['>'], :after) } + + it 'generates a single condition sql' do + expected_sql = <<~SQL + ("issues"."id" > 500) + SQL + + expect(condition.build.squish).to eq expected_sql.squish + end + end + + context 'when :after' do + let(:before_or_after) { :after } + + it 'generates :after sql' do + expected_sql = <<~SQL + ("issues"."relative_position" > 1500) + OR ( + "issues"."relative_position" = 1500 + AND + "issues"."id" > 500 + ) + OR ("issues"."relative_position" IS NULL) + SQL + + expect(condition.build.squish).to eq expected_sql.squish + end + end + + context 'when :before' do + let(:before_or_after) { :before } + + it 'generates :before sql' do + expected_sql = <<~SQL + ("issues"."relative_position" > 1500) + OR ( + "issues"."relative_position" = 1500 + AND + "issues"."id" > 500 + ) + SQL + + expect(condition.build.squish).to eq expected_sql.squish + end + end + end +end diff --git a/spec/lib/gitlab/graphql/connections/keyset/conditions/null_condition_spec.rb b/spec/lib/gitlab/graphql/connections/keyset/conditions/null_condition_spec.rb new file mode 100644 index 00000000000..7fce94adb81 --- /dev/null +++ b/spec/lib/gitlab/graphql/connections/keyset/conditions/null_condition_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Graphql::Connections::Keyset::Conditions::NullCondition do + describe '#build' do + let(:condition) { described_class.new(Issue.arel_table, %w(relative_position id), [nil, 500], [nil, '>'], before_or_after) } + + context 'when :after' do + let(:before_or_after) { :after } + + it 'generates sql' do + expected_sql = <<~SQL + ( + "issues"."relative_position" IS NULL + AND + "issues"."id" > 500 + ) + SQL + + expect(condition.build.squish).to eq expected_sql.squish + end + end + + context 'when :before' do + let(:before_or_after) { :before } + + it 'generates :before sql' do + expected_sql = <<~SQL + ( + "issues"."relative_position" IS NULL + AND + "issues"."id" > 500 + ) + OR ("issues"."relative_position" IS NOT NULL) + SQL + + expect(condition.build.squish).to eq expected_sql.squish + end + end + end +end diff --git a/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb b/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb new file mode 100644 index 00000000000..ba1addadb5a --- /dev/null +++ b/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb @@ -0,0 +1,303 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Graphql::Connections::Keyset::Connection do + let(:nodes) { Project.all.order(id: :asc) } + let(:arguments) { {} } + subject(:connection) do + described_class.new(nodes, arguments, max_page_size: 3) + end + + def encoded_cursor(node) + described_class.new(nodes, {}).cursor_from_node(node) + end + + def decoded_cursor(cursor) + JSON.parse(Base64Bp.urlsafe_decode64(cursor)) + end + + describe '#cursor_from_nodes' do + let(:project) { create(:project) } + let(:cursor) { connection.cursor_from_node(project) } + + it 'returns an encoded ID' do + expect(decoded_cursor(cursor)).to eq('id' => project.id.to_s) + end + + context 'when an order is specified' do + let(:nodes) { Project.order(:updated_at) } + + it 'returns the encoded value of the order' do + expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.to_s) + end + + it 'includes the :id even when not specified in the order' do + expect(decoded_cursor(cursor)).to include('id' => project.id.to_s) + end + end + + context 'when multiple orders are specified' do + let(:nodes) { Project.order(:updated_at).order(:created_at) } + + it 'returns the encoded value of the order' do + expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.to_s) + end + end + + context 'when multiple orders with SQL are specified' do + let(:nodes) { Project.order(Arel.sql('projects.updated_at IS NULL')).order(:updated_at).order(:id) } + + it 'returns the encoded value of the order' do + expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.to_s) + end + end + end + + describe '#sliced_nodes' do + let(:projects) { create_list(:project, 4) } + + context 'when before is passed' do + let(:arguments) { { before: encoded_cursor(projects[1]) } } + + it 'only returns the project before the selected one' do + expect(subject.sliced_nodes).to contain_exactly(projects.first) + end + + context 'when the sort order is descending' do + let(:nodes) { Project.all.order(id: :desc) } + + it 'returns the correct nodes' do + expect(subject.sliced_nodes).to contain_exactly(*projects[2..-1]) + end + end + end + + context 'when after is passed' do + let(:arguments) { { after: encoded_cursor(projects[1]) } } + + it 'only returns the project before the selected one' do + expect(subject.sliced_nodes).to contain_exactly(*projects[2..-1]) + end + + context 'when the sort order is descending' do + let(:nodes) { Project.all.order(id: :desc) } + + it 'returns the correct nodes' do + expect(subject.sliced_nodes).to contain_exactly(projects.first) + end + end + end + + context 'when both before and after are passed' do + let(:arguments) do + { + after: encoded_cursor(projects[1]), + before: encoded_cursor(projects[3]) + } + end + + it 'returns the expected set' do + expect(subject.sliced_nodes).to contain_exactly(projects[2]) + end + end + + context 'when multiple orders are defined' do + let!(:project1) { create(:project, last_repository_check_at: 10.days.ago) } # Asc: project5 Desc: project3 + let!(:project2) { create(:project, last_repository_check_at: nil) } # Asc: project1 Desc: project1 + let!(:project3) { create(:project, last_repository_check_at: 5.days.ago) } # Asc: project3 Desc: project5 + let!(:project4) { create(:project, last_repository_check_at: nil) } # Asc: project2 Desc: project2 + let!(:project5) { create(:project, last_repository_check_at: 20.days.ago) } # Asc: project4 Desc: project4 + + context 'when ascending' do + let(:nodes) do + Project.order(Arel.sql('projects.last_repository_check_at IS NULL')).order(last_repository_check_at: :asc).order(id: :asc) + end + + context 'when no cursor is passed' do + let(:arguments) { {} } + + it 'returns projects in ascending order' do + expect(subject.sliced_nodes).to eq([project5, project1, project3, project2, project4]) + end + end + + context 'when before cursor value is NULL' do + let(:arguments) { { before: encoded_cursor(project4) } } + + it 'returns all projects before the cursor' do + expect(subject.sliced_nodes).to eq([project5, project1, project3, project2]) + end + end + + context 'when before cursor value is not NULL' do + let(:arguments) { { before: encoded_cursor(project3) } } + + it 'returns all projects before the cursor' do + expect(subject.sliced_nodes).to eq([project5, project1]) + end + end + + context 'when after cursor value is NULL' do + let(:arguments) { { after: encoded_cursor(project2) } } + + it 'returns all projects after the cursor' do + expect(subject.sliced_nodes).to eq([project4]) + end + end + + context 'when after cursor value is not NULL' do + let(:arguments) { { after: encoded_cursor(project1) } } + + it 'returns all projects after the cursor' do + expect(subject.sliced_nodes).to eq([project3, project2, project4]) + end + end + + context 'when before and after cursor' do + let(:arguments) { { before: encoded_cursor(project4), after: encoded_cursor(project5) } } + + it 'returns all projects after the cursor' do + expect(subject.sliced_nodes).to eq([project1, project3, project2]) + end + end + end + + context 'when descending' do + let(:nodes) do + Project.order(Arel.sql('projects.last_repository_check_at IS NULL')).order(last_repository_check_at: :desc).order(id: :asc) + end + + context 'when no cursor is passed' do + let(:arguments) { {} } + + it 'only returns projects in descending order' do + expect(subject.sliced_nodes).to eq([project3, project1, project5, project2, project4]) + end + end + + context 'when before cursor value is NULL' do + let(:arguments) { { before: encoded_cursor(project4) } } + + it 'returns all projects before the cursor' do + expect(subject.sliced_nodes).to eq([project3, project1, project5, project2]) + end + end + + context 'when before cursor value is not NULL' do + let(:arguments) { { before: encoded_cursor(project5) } } + + it 'returns all projects before the cursor' do + expect(subject.sliced_nodes).to eq([project3, project1]) + end + end + + context 'when after cursor value is NULL' do + let(:arguments) { { after: encoded_cursor(project2) } } + + it 'returns all projects after the cursor' do + expect(subject.sliced_nodes).to eq([project4]) + end + end + + context 'when after cursor value is not NULL' do + let(:arguments) { { after: encoded_cursor(project1) } } + + it 'returns all projects after the cursor' do + expect(subject.sliced_nodes).to eq([project5, project2, project4]) + end + end + + context 'when before and after cursor' do + let(:arguments) { { before: encoded_cursor(project4), after: encoded_cursor(project3) } } + + it 'returns all projects after the cursor' do + expect(subject.sliced_nodes).to eq([project1, project5, project2]) + end + end + end + end + + # TODO Enable this as part of below issue + # https://gitlab.com/gitlab-org/gitlab/issues/32933 + # context 'when an invalid cursor is provided' do + # let(:arguments) { { before: 'invalidcursor' } } + # + # it 'raises an error' do + # expect { expect(subject.sliced_nodes) }.to raise_error(Gitlab::Graphql::Errors::ArgumentError) + # end + # end + + # TODO Remove this as part of below issue + # https://gitlab.com/gitlab-org/gitlab/issues/32933 + context 'when an old style cursor is provided' do + let(:arguments) { { before: Base64Bp.urlsafe_encode64(projects[1].id.to_s, padding: false) } } + + it 'only returns the project before the selected one' do + expect(subject.sliced_nodes).to contain_exactly(projects.first) + end + end + end + + describe '#paged_nodes' do + let!(:projects) { create_list(:project, 5) } + + it 'returns the collection limited to max page size' do + expect(subject.paged_nodes.size).to eq(3) + end + + it 'is a loaded memoized array' do + expect(subject.paged_nodes).to be_an(Array) + expect(subject.paged_nodes.object_id).to eq(subject.paged_nodes.object_id) + end + + context 'when `first` is passed' do + let(:arguments) { { first: 2 } } + + it 'returns only the first elements' do + expect(subject.paged_nodes).to contain_exactly(projects.first, projects.second) + end + end + + context 'when `last` is passed' do + let(:arguments) { { last: 2 } } + + it 'returns only the last elements' do + expect(subject.paged_nodes).to contain_exactly(projects[3], projects[4]) + end + end + + context 'when both are passed' do + let(:arguments) { { first: 2, last: 2 } } + + it 'raises an error' do + expect { subject.paged_nodes }.to raise_error(Gitlab::Graphql::Errors::ArgumentError) + end + end + + context 'when primary key is not in original order' do + let(:nodes) { Project.order(last_repository_check_at: :desc) } + + it 'is added to end' do + sliced = subject.sliced_nodes + last_order_name = sliced.order_values.last.expr.name + + expect(last_order_name).to eq sliced.primary_key + end + end + + context 'when there is no primary key' do + let(:nodes) { NoPrimaryKey.all } + + it 'raises an error' do + expect(NoPrimaryKey.primary_key).to be_nil + expect { subject.sliced_nodes }.to raise_error(ArgumentError, 'Relation must have a primary key') + end + end + end + + class NoPrimaryKey < ActiveRecord::Base + self.table_name = 'no_primary_key' + self.primary_key = nil + end +end diff --git a/spec/lib/gitlab/graphql/connections/keyset/legacy_keyset_connection_spec.rb b/spec/lib/gitlab/graphql/connections/keyset/legacy_keyset_connection_spec.rb new file mode 100644 index 00000000000..aaf28fed684 --- /dev/null +++ b/spec/lib/gitlab/graphql/connections/keyset/legacy_keyset_connection_spec.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +# TODO https://gitlab.com/gitlab-org/gitlab/issues/35104 +require 'spec_helper' + +describe Gitlab::Graphql::Connections::Keyset::LegacyKeysetConnection do + describe 'old keyset_connection' do + let(:described_class) { Gitlab::Graphql::Connections::Keyset::Connection } + let(:nodes) { Project.all.order(id: :asc) } + let(:arguments) { {} } + subject(:connection) do + described_class.new(nodes, arguments, max_page_size: 3) + end + + before do + stub_feature_flags(graphql_keyset_pagination: false) + end + + def encoded_property(value) + Base64Bp.urlsafe_encode64(value.to_s, padding: false) + end + + describe '#cursor_from_nodes' do + let(:project) { create(:project) } + + it 'returns an encoded ID' do + expect(connection.cursor_from_node(project)) + .to eq(encoded_property(project.id)) + end + + context 'when an order was specified' do + let(:nodes) { Project.order(:updated_at) } + + it 'returns the encoded value of the order' do + expect(connection.cursor_from_node(project)) + .to eq(encoded_property(project.updated_at)) + end + end + end + + describe '#sliced_nodes' do + let(:projects) { create_list(:project, 4) } + + context 'when before is passed' do + let(:arguments) { { before: encoded_property(projects[1].id) } } + + it 'only returns the project before the selected one' do + expect(subject.sliced_nodes).to contain_exactly(projects.first) + end + + context 'when the sort order is descending' do + let(:nodes) { Project.all.order(id: :desc) } + + it 'returns the correct nodes' do + expect(subject.sliced_nodes).to contain_exactly(*projects[2..-1]) + end + end + end + + context 'when after is passed' do + let(:arguments) { { after: encoded_property(projects[1].id) } } + + it 'only returns the project before the selected one' do + expect(subject.sliced_nodes).to contain_exactly(*projects[2..-1]) + end + + context 'when the sort order is descending' do + let(:nodes) { Project.all.order(id: :desc) } + + it 'returns the correct nodes' do + expect(subject.sliced_nodes).to contain_exactly(projects.first) + end + end + end + + context 'when both before and after are passed' do + let(:arguments) do + { + after: encoded_property(projects[1].id), + before: encoded_property(projects[3].id) + } + end + + it 'returns the expected set' do + expect(subject.sliced_nodes).to contain_exactly(projects[2]) + end + end + end + + describe '#paged_nodes' do + let!(:projects) { create_list(:project, 5) } + + it 'returns the collection limited to max page size' do + expect(subject.paged_nodes.size).to eq(3) + end + + it 'is a loaded memoized array' do + expect(subject.paged_nodes).to be_an(Array) + expect(subject.paged_nodes.object_id).to eq(subject.paged_nodes.object_id) + end + + context 'when `first` is passed' do + let(:arguments) { { first: 2 } } + + it 'returns only the first elements' do + expect(subject.paged_nodes).to contain_exactly(projects.first, projects.second) + end + end + + context 'when `last` is passed' do + let(:arguments) { { last: 2 } } + + it 'returns only the last elements' do + expect(subject.paged_nodes).to contain_exactly(projects[3], projects[4]) + end + end + + context 'when both are passed' do + let(:arguments) { { first: 2, last: 2 } } + + it 'raises an error' do + expect { subject.paged_nodes }.to raise_error(Gitlab::Graphql::Errors::ArgumentError) + end + end + end + end +end diff --git a/spec/lib/gitlab/graphql/connections/keyset/order_info_spec.rb b/spec/lib/gitlab/graphql/connections/keyset/order_info_spec.rb new file mode 100644 index 00000000000..608a9ed1d85 --- /dev/null +++ b/spec/lib/gitlab/graphql/connections/keyset/order_info_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Graphql::Connections::Keyset::OrderInfo do + describe '#build_order_list' do + let(:order_list) { described_class.build_order_list(relation) } + + context 'when multiple orders with SQL is specified' do + let(:relation) { Project.order(Arel.sql('projects.updated_at IS NULL')).order(:updated_at).order(:id) } + + it 'ignores the SQL order' do + expect(order_list.count).to eq 2 + expect(order_list.first.attribute_name).to eq 'updated_at' + expect(order_list.first.operator_for(:after)).to eq '>' + expect(order_list.last.attribute_name).to eq 'id' + expect(order_list.last.operator_for(:after)).to eq '>' + end + end + end + + describe '#validate_ordering' do + let(:order_list) { described_class.build_order_list(relation) } + + context 'when number of ordering fields is 0' do + let(:relation) { Project.all } + + it 'raises an error' do + expect { described_class.validate_ordering(relation, order_list) } + .to raise_error(ArgumentError, 'A minimum of 1 ordering field is required') + end + end + + context 'when number of ordering fields is over 2' do + let(:relation) { Project.order(last_repository_check_at: :desc).order(updated_at: :desc).order(:id) } + + it 'raises an error' do + expect { described_class.validate_ordering(relation, order_list) } + .to raise_error(ArgumentError, 'A maximum of 2 ordering fields are allowed') + end + end + + context 'when the second (or first) column is nullable' do + let(:relation) { Project.order(last_repository_check_at: :desc).order(updated_at: :desc) } + + it 'raises an error' do + expect { described_class.validate_ordering(relation, order_list) } + .to raise_error(ArgumentError, "Column `updated_at` must not allow NULL") + end + end + + context 'for last ordering field' do + let(:relation) { Project.order(namespace_id: :desc) } + + it 'raises error if primary key is not last field' do + expect { described_class.validate_ordering(relation, order_list) } + .to raise_error(ArgumentError, "Last ordering field must be the primary key, `#{relation.primary_key}`") + end + end + end +end diff --git a/spec/lib/gitlab/graphql/connections/keyset/query_builder_spec.rb b/spec/lib/gitlab/graphql/connections/keyset/query_builder_spec.rb new file mode 100644 index 00000000000..59e153d9e07 --- /dev/null +++ b/spec/lib/gitlab/graphql/connections/keyset/query_builder_spec.rb @@ -0,0 +1,108 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Graphql::Connections::Keyset::QueryBuilder do + context 'when number of ordering fields is 0' do + it 'raises an error' do + expect { described_class.new(Issue.arel_table, [], {}, :after) } + .to raise_error(ArgumentError, 'No ordering scopes have been supplied') + end + end + + describe '#conditions' do + let(:relation) { Issue.order(relative_position: :desc).order(:id) } + let(:order_list) { Gitlab::Graphql::Connections::Keyset::OrderInfo.build_order_list(relation) } + let(:builder) { described_class.new(arel_table, order_list, decoded_cursor, before_or_after) } + let(:before_or_after) { :after } + + context 'when only a single ordering' do + let(:relation) { Issue.order(id: :desc) } + + context 'when the value is nil' do + let(:decoded_cursor) { { 'id' => nil } } + + it 'raises an error' do + expect { builder.conditions } + .to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'Before/after cursor invalid: `nil` was provided as only sortable value') + end + end + + context 'when value is not nil' do + let(:decoded_cursor) { { 'id' => 100 } } + let(:conditions) { builder.conditions } + + context 'when :after' do + it 'generates the correct condition' do + expect(conditions.strip).to eq '("issues"."id" < 100)' + end + end + + context 'when :before' do + let(:before_or_after) { :before } + + it 'generates the correct condition' do + expect(conditions.strip).to eq '("issues"."id" > 100)' + end + end + end + end + + context 'when two orderings' do + let(:decoded_cursor) { { 'relative_position' => 1500, 'id' => 100 } } + + context 'when no values are nil' do + context 'when :after' do + it 'generates the correct condition' do + conditions = builder.conditions + + expect(conditions).to include '"issues"."relative_position" < 1500' + expect(conditions).to include '"issues"."id" > 100' + expect(conditions).to include 'OR ("issues"."relative_position" IS NULL)' + end + end + + context 'when :before' do + let(:before_or_after) { :before } + + it 'generates the correct condition' do + conditions = builder.conditions + + expect(conditions).to include '("issues"."relative_position" > 1500)' + expect(conditions).to include '"issues"."id" < 100' + expect(conditions).to include '"issues"."relative_position" = 1500' + end + end + end + + context 'when first value is nil' do + let(:decoded_cursor) { { 'relative_position' => nil, 'id' => 100 } } + + context 'when :after' do + it 'generates the correct condition' do + conditions = builder.conditions + + expect(conditions).to include '"issues"."relative_position" IS NULL' + expect(conditions).to include '"issues"."id" > 100' + end + end + + context 'when :before' do + let(:before_or_after) { :before } + + it 'generates the correct condition' do + conditions = builder.conditions + + expect(conditions).to include '"issues"."relative_position" IS NULL' + expect(conditions).to include '"issues"."id" < 100' + expect(conditions).to include 'OR ("issues"."relative_position" IS NOT NULL)' + end + end + end + end + end + + def arel_table + Issue.arel_table + end +end diff --git a/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb b/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb deleted file mode 100644 index 4eb121794e1..00000000000 --- a/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb +++ /dev/null @@ -1,117 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Graphql::Connections::KeysetConnection do - let(:nodes) { Project.all.order(id: :asc) } - let(:arguments) { {} } - subject(:connection) do - described_class.new(nodes, arguments, max_page_size: 3) - end - - def encoded_property(value) - Base64Bp.urlsafe_encode64(value.to_s, padding: false) - end - - describe '#cursor_from_nodes' do - let(:project) { create(:project) } - - it 'returns an encoded ID' do - expect(connection.cursor_from_node(project)) - .to eq(encoded_property(project.id)) - end - - context 'when an order was specified' do - let(:nodes) { Project.order(:updated_at) } - - it 'returns the encoded value of the order' do - expect(connection.cursor_from_node(project)) - .to eq(encoded_property(project.updated_at)) - end - end - end - - describe '#sliced_nodes' do - let(:projects) { create_list(:project, 4) } - - context 'when before is passed' do - let(:arguments) { { before: encoded_property(projects[1].id) } } - - it 'only returns the project before the selected one' do - expect(subject.sliced_nodes).to contain_exactly(projects.first) - end - - context 'when the sort order is descending' do - let(:nodes) { Project.all.order(id: :desc) } - - it 'returns the correct nodes' do - expect(subject.sliced_nodes).to contain_exactly(*projects[2..-1]) - end - end - end - - context 'when after is passed' do - let(:arguments) { { after: encoded_property(projects[1].id) } } - - it 'only returns the project before the selected one' do - expect(subject.sliced_nodes).to contain_exactly(*projects[2..-1]) - end - - context 'when the sort order is descending' do - let(:nodes) { Project.all.order(id: :desc) } - - it 'returns the correct nodes' do - expect(subject.sliced_nodes).to contain_exactly(projects.first) - end - end - end - - context 'when both before and after are passed' do - let(:arguments) do - { - after: encoded_property(projects[1].id), - before: encoded_property(projects[3].id) - } - end - - it 'returns the expected set' do - expect(subject.sliced_nodes).to contain_exactly(projects[2]) - end - end - end - - describe '#paged_nodes' do - let!(:projects) { create_list(:project, 5) } - - it 'returns the collection limited to max page size' do - expect(subject.paged_nodes.size).to eq(3) - end - - it 'is a loaded memoized array' do - expect(subject.paged_nodes).to be_an(Array) - expect(subject.paged_nodes.object_id).to eq(subject.paged_nodes.object_id) - end - - context 'when `first` is passed' do - let(:arguments) { { first: 2 } } - - it 'returns only the first elements' do - expect(subject.paged_nodes).to contain_exactly(projects.first, projects.second) - end - end - - context 'when `last` is passed' do - let(:arguments) { { last: 2 } } - - it 'returns only the last elements' do - expect(subject.paged_nodes).to contain_exactly(projects[3], projects[4]) - end - end - - context 'when both are passed' do - let(:arguments) { { first: 2, last: 2 } } - - it 'raises an error' do - expect { subject.paged_nodes }.to raise_error(Gitlab::Graphql::Errors::ArgumentError) - end - end - end -end diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 8a3a7eee25d..47530025620 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -686,12 +686,36 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do context 'the cluster has a provider' do let(:cluster) { create(:cluster, :provided_by_gcp) } + let(:provider_status) { :errored } before do cluster.provider.make_errored! end - it { is_expected.to eq :errored } + it { is_expected.to eq provider_status } + + context 'when cluster cleanup is ongoing' do + using RSpec::Parameterized::TableSyntax + + where(:status_name, :cleanup_status) do + provider_status | :cleanup_not_started + :cleanup_ongoing | :cleanup_uninstalling_applications + :cleanup_ongoing | :cleanup_removing_project_namespaces + :cleanup_ongoing | :cleanup_removing_service_account + :cleanup_errored | :cleanup_errored + end + + with_them do + it 'returns cleanup_ongoing when uninstalling applications' do + cluster.cleanup_status = described_class + .state_machines[:cleanup_status] + .states[cleanup_status] + .value + + is_expected.to eq status_name + end + end + end end context 'there is a cached connection status' do @@ -715,6 +739,83 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do end end + describe 'cleanup_status state_machine' do + shared_examples 'cleanup_status transition' do + let(:cluster) { create(:cluster, from_state) } + + it 'transitions cleanup_status correctly' do + expect { subject }.to change { cluster.cleanup_status_name } + .from(from_state).to(to_state) + end + + it 'schedules a Clusters::Cleanup::*Worker' do + expect(expected_worker_class).to receive(:perform_async).with(cluster.id) + subject + end + end + + describe '#start_cleanup!' do + let(:expected_worker_class) { Clusters::Cleanup::AppWorker } + let(:to_state) { :cleanup_uninstalling_applications } + + subject { cluster.start_cleanup! } + + context 'when cleanup_status is cleanup_not_started' do + let(:from_state) { :cleanup_not_started } + + it_behaves_like 'cleanup_status transition' + end + + context 'when cleanup_status is errored' do + let(:from_state) { :cleanup_errored } + + it_behaves_like 'cleanup_status transition' + end + end + + describe '#make_cleanup_errored!' do + NON_ERRORED_STATES = Clusters::Cluster.state_machines[:cleanup_status].states.keys - [:cleanup_errored] + + NON_ERRORED_STATES.each do |state| + it "transitions cleanup_status from #{state} to cleanup_errored" do + cluster = create(:cluster, state) + + expect { cluster.make_cleanup_errored! }.to change { cluster.cleanup_status_name } + .from(state).to(:cleanup_errored) + end + + it "sets error message" do + cluster = create(:cluster, state) + + expect { cluster.make_cleanup_errored!("Error Message") }.to change { cluster.cleanup_status_reason } + .from(nil).to("Error Message") + end + end + end + + describe '#continue_cleanup!' do + context 'when cleanup_status is cleanup_uninstalling_applications' do + let(:expected_worker_class) { Clusters::Cleanup::ProjectNamespaceWorker } + let(:from_state) { :cleanup_uninstalling_applications } + let(:to_state) { :cleanup_removing_project_namespaces } + + subject { cluster.continue_cleanup! } + + it_behaves_like 'cleanup_status transition' + end + + context 'when cleanup_status is cleanup_removing_project_namespaces' do + let(:expected_worker_class) { Clusters::Cleanup::ServiceAccountWorker } + let(:from_state) { :cleanup_removing_project_namespaces } + let(:to_state) { :cleanup_removing_service_account } + + subject { cluster.continue_cleanup! } + + it_behaves_like 'cleanup_status transition' + end + end + end + describe '#connection_status' do let(:cluster) { create(:cluster) } let(:status) { :connected } diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 91a743c4377..62f73c3867b 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -3368,7 +3368,7 @@ describe MergeRequest do end end - describe '.with_open_merge_when_pipeline_succeeds' do + describe '.with_auto_merge_enabled' do let!(:project) { create(:project) } let!(:fork) { fork_project(project) } let!(:merge_request1) do @@ -3380,15 +3380,6 @@ describe MergeRequest do source_branch: 'feature-1') end - let!(:merge_request2) do - create(:merge_request, - :merge_when_pipeline_succeeds, - target_project: project, - target_branch: 'master', - source_project: fork, - source_branch: 'fork-feature-1') - end - let!(:merge_request4) do create(:merge_request, target_project: project, @@ -3397,9 +3388,9 @@ describe MergeRequest do source_branch: 'fork-feature-2') end - let(:query) { described_class.with_open_merge_when_pipeline_succeeds } + let(:query) { described_class.with_auto_merge_enabled } - it { expect(query).to contain_exactly(merge_request1, merge_request2) } + it { expect(query).to contain_exactly(merge_request1) } end it_behaves_like 'versioned description' diff --git a/spec/requests/api/graphql/current_user/todos_query_spec.rb b/spec/requests/api/graphql/current_user/todos_query_spec.rb new file mode 100644 index 00000000000..6817e37e64b --- /dev/null +++ b/spec/requests/api/graphql/current_user/todos_query_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Query current user todos' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:commit_todo) { create(:on_commit_todo, user: current_user, project: create(:project, :repository)) } + let_it_be(:issue_todo) { create(:todo, user: current_user, target: create(:issue)) } + let_it_be(:merge_request_todo) { create(:todo, user: current_user, target: create(:merge_request)) } + + let(:fields) do + <<~QUERY + nodes { + id + } + QUERY + end + + let(:query) do + graphql_query_for('currentUser', {}, query_graphql_field('todos', {}, fields)) + end + + subject { graphql_data.dig('currentUser', 'todos', 'nodes') } + + before do + post_graphql(query, current_user: current_user) + end + + it 'contains the expected ids' do + is_expected.to include( + a_hash_including('id' => commit_todo.to_global_id.to_s), + a_hash_including('id' => issue_todo.to_global_id.to_s), + a_hash_including('id' => merge_request_todo.to_global_id.to_s) + ) + end +end diff --git a/spec/rubocop/cop/avoid_break_from_strong_memoize_spec.rb b/spec/rubocop/cop/avoid_break_from_strong_memoize_spec.rb index ac7b1575ec0..62f6c7a3414 100644 --- a/spec/rubocop/cop/avoid_break_from_strong_memoize_spec.rb +++ b/spec/rubocop/cop/avoid_break_from_strong_memoize_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' require 'rubocop/rspec/support' diff --git a/spec/rubocop/cop/avoid_return_from_blocks_spec.rb b/spec/rubocop/cop/avoid_return_from_blocks_spec.rb index a5c280a7adc..133d286ccd2 100644 --- a/spec/rubocop/cop/avoid_return_from_blocks_spec.rb +++ b/spec/rubocop/cop/avoid_return_from_blocks_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' require 'rubocop/rspec/support' diff --git a/spec/rubocop/cop/destroy_all_spec.rb b/spec/rubocop/cop/destroy_all_spec.rb index b0bc40552b3..ac8aa56e040 100644 --- a/spec/rubocop/cop/destroy_all_spec.rb +++ b/spec/rubocop/cop/destroy_all_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' require 'rubocop/rspec/support' diff --git a/spec/rubocop/cop/gitlab/finder_with_find_by_spec.rb b/spec/rubocop/cop/gitlab/finder_with_find_by_spec.rb index 7f689b196c5..7af98b66218 100644 --- a/spec/rubocop/cop/gitlab/finder_with_find_by_spec.rb +++ b/spec/rubocop/cop/gitlab/finder_with_find_by_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/gitlab/httparty_spec.rb b/spec/rubocop/cop/gitlab/httparty_spec.rb index 510839a21d7..42da97679ec 100644 --- a/spec/rubocop/cop/gitlab/httparty_spec.rb +++ b/spec/rubocop/cop/gitlab/httparty_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' require 'rubocop/rspec/support' diff --git a/spec/rubocop/cop/gitlab/module_with_instance_variables_spec.rb b/spec/rubocop/cop/gitlab/module_with_instance_variables_spec.rb index 8e2d5f70353..9cb55ced1fa 100644 --- a/spec/rubocop/cop/gitlab/module_with_instance_variables_spec.rb +++ b/spec/rubocop/cop/gitlab/module_with_instance_variables_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' require 'rubocop/rspec/support' diff --git a/spec/rubocop/cop/gitlab/predicate_memoization_spec.rb b/spec/rubocop/cop/gitlab/predicate_memoization_spec.rb index 21fc4584654..ae9466368d2 100644 --- a/spec/rubocop/cop/gitlab/predicate_memoization_spec.rb +++ b/spec/rubocop/cop/gitlab/predicate_memoization_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' require 'rubocop/rspec/support' diff --git a/spec/rubocop/cop/group_public_or_visible_to_user_spec.rb b/spec/rubocop/cop/group_public_or_visible_to_user_spec.rb index 7b5235a3da7..8e027ad59f7 100644 --- a/spec/rubocop/cop/group_public_or_visible_to_user_spec.rb +++ b/spec/rubocop/cop/group_public_or_visible_to_user_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' require 'rubocop/rspec/support' diff --git a/spec/rubocop/cop/include_sidekiq_worker_spec.rb b/spec/rubocop/cop/include_sidekiq_worker_spec.rb index f5109287876..39965646aff 100644 --- a/spec/rubocop/cop/include_sidekiq_worker_spec.rb +++ b/spec/rubocop/cop/include_sidekiq_worker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/line_break_around_conditional_block_spec.rb b/spec/rubocop/cop/line_break_around_conditional_block_spec.rb index cc933ce12c8..d09de4c6614 100644 --- a/spec/rubocop/cop/line_break_around_conditional_block_spec.rb +++ b/spec/rubocop/cop/line_break_around_conditional_block_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' require 'rubocop/rspec/support' diff --git a/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb b/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb index 1df1fffb94e..419d74c298a 100644 --- a/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb +++ b/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/add_concurrent_index_spec.rb b/spec/rubocop/cop/migration/add_concurrent_index_spec.rb index 9c1ebcc0ced..9812e64216f 100644 --- a/spec/rubocop/cop/migration/add_concurrent_index_spec.rb +++ b/spec/rubocop/cop/migration/add_concurrent_index_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/add_reference_spec.rb b/spec/rubocop/cop/migration/add_reference_spec.rb index 0b56fe8ed83..03348ecc744 100644 --- a/spec/rubocop/cop/migration/add_reference_spec.rb +++ b/spec/rubocop/cop/migration/add_reference_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/add_timestamps_spec.rb b/spec/rubocop/cop/migration/add_timestamps_spec.rb index 33f1bb85af8..a3314d878e5 100644 --- a/spec/rubocop/cop/migration/add_timestamps_spec.rb +++ b/spec/rubocop/cop/migration/add_timestamps_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/datetime_spec.rb b/spec/rubocop/cop/migration/datetime_spec.rb index f2d9483d8d3..0a771003100 100644 --- a/spec/rubocop/cop/migration/datetime_spec.rb +++ b/spec/rubocop/cop/migration/datetime_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/hash_index_spec.rb b/spec/rubocop/cop/migration/hash_index_spec.rb index 5d53dde9a79..e8b05a94653 100644 --- a/spec/rubocop/cop/migration/hash_index_spec.rb +++ b/spec/rubocop/cop/migration/hash_index_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/remove_column_spec.rb b/spec/rubocop/cop/migration/remove_column_spec.rb index f1a64f431bd..bc2fa04ce64 100644 --- a/spec/rubocop/cop/migration/remove_column_spec.rb +++ b/spec/rubocop/cop/migration/remove_column_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/remove_concurrent_index_spec.rb b/spec/rubocop/cop/migration/remove_concurrent_index_spec.rb index a23d5d022e3..9de4c756f12 100644 --- a/spec/rubocop/cop/migration/remove_concurrent_index_spec.rb +++ b/spec/rubocop/cop/migration/remove_concurrent_index_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/remove_index_spec.rb b/spec/rubocop/cop/migration/remove_index_spec.rb index bbf2227e512..d343d27484a 100644 --- a/spec/rubocop/cop/migration/remove_index_spec.rb +++ b/spec/rubocop/cop/migration/remove_index_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb b/spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb index ba8cd2c6c4a..b3c5b855004 100644 --- a/spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb +++ b/spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/safer_boolean_column_spec.rb b/spec/rubocop/cop/migration/safer_boolean_column_spec.rb index 1c4f18fbcc3..915b73ed5a7 100644 --- a/spec/rubocop/cop/migration/safer_boolean_column_spec.rb +++ b/spec/rubocop/cop/migration/safer_boolean_column_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/timestamps_spec.rb b/spec/rubocop/cop/migration/timestamps_spec.rb index cafe255dc9a..d03c75e7cfc 100644 --- a/spec/rubocop/cop/migration/timestamps_spec.rb +++ b/spec/rubocop/cop/migration/timestamps_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/update_column_in_batches_spec.rb b/spec/rubocop/cop/migration/update_column_in_batches_spec.rb index cba01400d85..f72efaf2eb2 100644 --- a/spec/rubocop/cop/migration/update_column_in_batches_spec.rb +++ b/spec/rubocop/cop/migration/update_column_in_batches_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/migration/update_large_table_spec.rb b/spec/rubocop/cop/migration/update_large_table_spec.rb index 5e08eb4f772..0463b6550a8 100644 --- a/spec/rubocop/cop/migration/update_large_table_spec.rb +++ b/spec/rubocop/cop/migration/update_large_table_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/project_path_helper_spec.rb b/spec/rubocop/cop/project_path_helper_spec.rb index 84e6eb7d87f..1b69030c798 100644 --- a/spec/rubocop/cop/project_path_helper_spec.rb +++ b/spec/rubocop/cop/project_path_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/rspec/env_assignment_spec.rb b/spec/rubocop/cop/rspec/env_assignment_spec.rb index 621afbad3ba..2a2bd1434d6 100644 --- a/spec/rubocop/cop/rspec/env_assignment_spec.rb +++ b/spec/rubocop/cop/rspec/env_assignment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/rspec/factories_in_migration_specs_spec.rb b/spec/rubocop/cop/rspec/factories_in_migration_specs_spec.rb index 94324bc615d..20013519db4 100644 --- a/spec/rubocop/cop/rspec/factories_in_migration_specs_spec.rb +++ b/spec/rubocop/cop/rspec/factories_in_migration_specs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/rubocop/cop/sidekiq_options_queue_spec.rb b/spec/rubocop/cop/sidekiq_options_queue_spec.rb index 7f237d5ffbb..c10fd7bd32b 100644 --- a/spec/rubocop/cop/sidekiq_options_queue_spec.rb +++ b/spec/rubocop/cop/sidekiq_options_queue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'rubocop' diff --git a/spec/serializers/blob_entity_spec.rb b/spec/serializers/blob_entity_spec.rb index c0687d0232e..7e3a0a87bd5 100644 --- a/spec/serializers/blob_entity_spec.rb +++ b/spec/serializers/blob_entity_spec.rb @@ -15,8 +15,16 @@ describe BlobEntity do context 'as json' do subject { entity.as_json } - it 'exposes needed attributes' do - expect(subject).to include(:readable_text, :url) + it 'contains needed attributes' do + expect(subject).to include({ + id: blob.id, + path: blob.path, + name: blob.name, + mode: "100644", + readable_text: true, + icon: "file-text-o", + url: "/#{project.full_path}/blob/master/bar/branch-test.txt" + }) end end end diff --git a/spec/serializers/diff_file_base_entity_spec.rb b/spec/serializers/diff_file_base_entity_spec.rb index 68c5c665ed6..80f5bc8f159 100644 --- a/spec/serializers/diff_file_base_entity_spec.rb +++ b/spec/serializers/diff_file_base_entity_spec.rb @@ -5,15 +5,15 @@ require 'spec_helper' describe DiffFileBaseEntity do let(:project) { create(:project, :repository) } let(:repository) { project.repository } + let(:entity) { described_class.new(diff_file, options).as_json } context 'diff for a changed submodule' do let(:commit_sha_with_changed_submodule) do "cfe32cf61b73a0d5e9f13e774abde7ff789b1660" end let(:commit) { project.commit(commit_sha_with_changed_submodule) } - let(:diff_file) { commit.diffs.diff_files.to_a.last } let(:options) { { request: {}, submodule_links: Gitlab::SubmoduleLinks.new(repository) } } - let(:entity) { described_class.new(diff_file, options).as_json } + let(:diff_file) { commit.diffs.diff_files.to_a.last } it do expect(entity[:submodule]).to eq(true) @@ -23,4 +23,15 @@ describe DiffFileBaseEntity do ) end end + + context 'contains raw sizes for the blob' do + let(:commit) { project.commit('png-lfs') } + let(:options) { { request: {} } } + let(:diff_file) { commit.diffs.diff_files.to_a.second } + + it do + expect(entity[:old_size]).to eq(1219696) + expect(entity[:new_size]).to eq(132) + end + end end diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 58302ce14ba..9d0ad60a624 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -769,7 +769,7 @@ describe MergeRequests::RefreshService do fork_project(target_project, author, repository: true) end - let_it_be(:merge_request) do + let_it_be(:merge_request, refind: true) do create(:merge_request, author: author, source_project: source_project, @@ -795,88 +795,58 @@ describe MergeRequests::RefreshService do .parent_id end + let(:auto_merge_strategy) { AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS } let(:refresh_service) { service.new(project, user) } before do target_project.merge_method = merge_method target_project.save! + merge_request.auto_merge_strategy = auto_merge_strategy + merge_request.save! refresh_service.execute(oldrev, newrev, 'refs/heads/master') merge_request.reload end - let(:aborted_message) do - /aborted the automatic merge because target branch was updated/ - end - - shared_examples 'aborted MWPS' do - it 'aborts auto_merge' do - expect(merge_request.auto_merge_enabled?).to be_falsey - expect(merge_request.notes.last.note).to match(aborted_message) - end - - it 'removes merge_user' do - expect(merge_request.merge_user).to be_nil - end - - it 'does not add todos for merge user' do - expect(user.todos.for_target(merge_request)).to be_empty - end - - it 'adds todos for merge author' do - expect(author.todos.for_target(merge_request)).to be_present.and be_all(&:pending?) - end - end - context 'when Project#merge_method is set to FF' do let(:merge_method) { :ff } - it_behaves_like 'aborted MWPS' + it_behaves_like 'aborted merge requests for MWPS' context 'with forked project' do let(:source_project) { forked_project } - it_behaves_like 'aborted MWPS' + it_behaves_like 'aborted merge requests for MWPS' + end + + context 'with bogus auto merge strategy' do + let(:auto_merge_strategy) { 'bogus' } + + it_behaves_like 'maintained merge requests for MWPS' end end context 'when Project#merge_method is set to rebase_merge' do let(:merge_method) { :rebase_merge } - it_behaves_like 'aborted MWPS' + it_behaves_like 'aborted merge requests for MWPS' context 'with forked project' do let(:source_project) { forked_project } - it_behaves_like 'aborted MWPS' + it_behaves_like 'aborted merge requests for MWPS' end end context 'when Project#merge_method is set to merge' do let(:merge_method) { :merge } - shared_examples 'maintained MWPS' do - it 'does not cancel auto merge' do - expect(merge_request.auto_merge_enabled?).to be_truthy - expect(merge_request.notes).to be_empty - end - - it 'does not change merge_user' do - expect(merge_request.merge_user).to eq(user) - end - - it 'does not add todos' do - expect(author.todos.for_target(merge_request)).to be_empty - expect(user.todos.for_target(merge_request)).to be_empty - end - end - - it_behaves_like 'maintained MWPS' + it_behaves_like 'maintained merge requests for MWPS' context 'with forked project' do let(:source_project) { forked_project } - it_behaves_like 'maintained MWPS' + it_behaves_like 'maintained merge requests for MWPS' end end end diff --git a/spec/support/generate-seed-repo-rb b/spec/support/generate-seed-repo-rb index bee9d419376..b63ff7147ec 100755 --- a/spec/support/generate-seed-repo-rb +++ b/spec/support/generate-seed-repo-rb @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true # # # generate-seed-repo-rb # @@ -15,9 +16,9 @@ require 'erb' require 'tempfile' -SOURCE = File.expand_path('gitlab-git-test.git', __dir__).freeze -SCRIPT_NAME = 'generate-seed-repo-rb'.freeze -REPO_NAME = 'gitlab-git-test.git'.freeze +SOURCE = File.expand_path('gitlab-git-test.git', __dir__) +SCRIPT_NAME = 'generate-seed-repo-rb' +REPO_NAME = 'gitlab-git-test.git' def main Dir.mktmpdir do |dir| diff --git a/spec/support/prepare-gitlab-git-test-for-commit b/spec/support/prepare-gitlab-git-test-for-commit index d08e3ba5481..77c7f309312 100755 --- a/spec/support/prepare-gitlab-git-test-for-commit +++ b/spec/support/prepare-gitlab-git-test-for-commit @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true abort unless [ system('spec/support/generate-seed-repo-rb', out: 'spec/support/helpers/seed_repo.rb'), diff --git a/spec/support/shared_examples/ci/auto_merge_merge_requests_examples.rb b/spec/support/shared_examples/ci/auto_merge_merge_requests_examples.rb new file mode 100644 index 00000000000..c11448ffe0f --- /dev/null +++ b/spec/support/shared_examples/ci/auto_merge_merge_requests_examples.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +shared_examples 'aborted merge requests for MWPS' do + let(:aborted_message) do + /aborted the automatic merge because target branch was updated/ + end + + it 'aborts auto_merge' do + expect(merge_request.auto_merge_enabled?).to be_falsey + expect(merge_request.notes.last.note).to match(aborted_message) + end + + it 'removes merge_user' do + expect(merge_request.merge_user).to be_nil + end + + it 'does not add todos for merge user' do + expect(user.todos.for_target(merge_request)).to be_empty + end + + it 'adds todos for merge author' do + expect(author.todos.for_target(merge_request)).to be_present.and be_all(&:pending?) + end +end + +shared_examples 'maintained merge requests for MWPS' do + it 'does not cancel auto merge' do + expect(merge_request.auto_merge_enabled?).to be_truthy + expect(merge_request.notes).to be_empty + end + + it 'does not change merge_user' do + expect(merge_request.merge_user).to eq(user) + end + + it 'does not add todos' do + expect(author.todos.for_target(merge_request)).to be_empty + expect(user.todos.for_target(merge_request)).to be_empty + end +end diff --git a/spec/support/unpack-gitlab-git-test b/spec/support/unpack-gitlab-git-test index d5b4912457d..5d5f1b7d082 100755 --- a/spec/support/unpack-gitlab-git-test +++ b/spec/support/unpack-gitlab-git-test @@ -1,10 +1,12 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + require 'fileutils' -REPO = 'spec/support/gitlab-git-test.git'.freeze +REPO = 'spec/support/gitlab-git-test.git' PACK_DIR = REPO + '/objects/pack' GIT = %W[git --git-dir=#{REPO}].freeze -BASE_PACK = 'pack-691247af2a6acb0b63b73ac0cb90540e93614043'.freeze +BASE_PACK = 'pack-691247af2a6acb0b63b73ac0cb90540e93614043' def main unpack diff --git a/spec/views/projects/tree/_tree_header.html.haml_spec.rb b/spec/views/projects/tree/_tree_header.html.haml_spec.rb index 4b71ea9ffe3..caf8c4d1969 100644 --- a/spec/views/projects/tree/_tree_header.html.haml_spec.rb +++ b/spec/views/projects/tree/_tree_header.html.haml_spec.rb @@ -8,6 +8,8 @@ describe 'projects/tree/_tree_header' do let(:repository) { project.repository } before do + stub_feature_flags(vue_file_list: false) + assign(:project, project) assign(:repository, repository) assign(:id, File.join('master', '')) |