diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-20 06:08:21 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-20 06:08:21 +0300 |
commit | 93c966ae2abeb481cfa894351b74f954e406582d (patch) | |
tree | 6e1b7619e3d5e7acac52e7de1135dd67d0cb53d5 /spec | |
parent | 48641d6d58d6d5d19b8b2ffc66646c7e94d552a1 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/frontend/boards/mock_data.js | 2 | ||||
-rw-r--r-- | spec/frontend/boards/stores/actions_spec.js | 13 | ||||
-rw-r--r-- | spec/helpers/analytics/unique_visits_helper_spec.rb | 34 | ||||
-rw-r--r-- | spec/lib/gitlab/analytics/unique_visits_spec.rb | 81 | ||||
-rw-r--r-- | spec/models/concerns/atomic_internal_id_spec.rb | 18 | ||||
-rw-r--r-- | spec/models/internal_id_spec.rb | 279 | ||||
-rw-r--r-- | spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb | 6 |
7 files changed, 163 insertions, 270 deletions
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js index 73372eafb89..6ac4db8cdaa 100644 --- a/spec/frontend/boards/mock_data.js +++ b/spec/frontend/boards/mock_data.js @@ -291,7 +291,7 @@ export const setMockEndpoints = (opts = {}) => { export const mockList = { id: 'gid://gitlab/List/1', - title: 'Backlog', + title: 'Open', position: -Infinity, listType: 'backlog', collapsed: false, diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js index ebed33e5b34..5e16e389ddc 100644 --- a/spec/frontend/boards/stores/actions_spec.js +++ b/spec/frontend/boards/stores/actions_spec.js @@ -715,6 +715,19 @@ describe('fetchItemsForList', () => { [listId]: pageInfo, }; + describe('when list id is undefined', () => { + it('does not call the query', async () => { + jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse); + + await actions.fetchItemsForList( + { state, getters: () => {}, commit: () => {} }, + { listId: undefined }, + ); + + expect(gqlClient.query).toHaveBeenCalledTimes(0); + }); + }); + it('should commit mutations REQUEST_ITEMS_FOR_LIST and RECEIVE_ITEMS_FOR_LIST_SUCCESS on success', (done) => { jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse); diff --git a/spec/helpers/analytics/unique_visits_helper_spec.rb b/spec/helpers/analytics/unique_visits_helper_spec.rb deleted file mode 100644 index b4b370c169d..00000000000 --- a/spec/helpers/analytics/unique_visits_helper_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -RSpec.describe Analytics::UniqueVisitsHelper do - include Devise::Test::ControllerHelpers - - describe '#track_visit' do - let(:target_id) { 'p_analytics_valuestream' } - let(:current_user) { create(:user) } - - it 'does not track visit if user is not logged in' do - expect_any_instance_of(Gitlab::Analytics::UniqueVisits).not_to receive(:track_visit) - - helper.track_visit(target_id) - end - - it 'tracks visit if user is logged in' do - sign_in(current_user) - - expect_any_instance_of(Gitlab::Analytics::UniqueVisits).to receive(:track_visit) - - helper.track_visit(target_id) - end - - it 'tracks visit if user is not logged in, but has the cookie already' do - helper.request.cookies[:visitor_id] = { value: SecureRandom.uuid, expires: 24.months } - - expect_any_instance_of(Gitlab::Analytics::UniqueVisits).to receive(:track_visit) - - helper.track_visit(target_id) - end - end -end diff --git a/spec/lib/gitlab/analytics/unique_visits_spec.rb b/spec/lib/gitlab/analytics/unique_visits_spec.rb deleted file mode 100644 index f4d5c0b1eca..00000000000 --- a/spec/lib/gitlab/analytics/unique_visits_spec.rb +++ /dev/null @@ -1,81 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::Analytics::UniqueVisits, :clean_gitlab_redis_shared_state do - let(:unique_visits) { Gitlab::Analytics::UniqueVisits.new } - let(:target1_id) { 'g_analytics_contribution' } - let(:target2_id) { 'g_analytics_insights' } - let(:target3_id) { 'g_analytics_issues' } - let(:target4_id) { 'g_compliance_dashboard' } - let(:target5_id) { 'i_compliance_credential_inventory' } - let(:visitor1_id) { 'dfb9d2d2-f56c-4c77-8aeb-6cddc4a1f857' } - let(:visitor2_id) { '1dd9afb2-a3ee-4de1-8ae3-a405579c8584' } - let(:visitor3_id) { '34rfjuuy-ce56-sa35-ds34-dfer567dfrf2' } - - around do |example| - # We need to freeze to a reference time - # because visits are grouped by the week number in the year - # Without freezing the time, the test may behave inconsistently - # depending on which day of the week test is run. - reference_time = Time.utc(2020, 6, 1) - travel_to(reference_time) { example.run } - end - - describe '#track_visit' do - it 'tracks the unique weekly visits for targets' do - unique_visits.track_visit(target1_id, values: visitor1_id, time: 7.days.ago) - unique_visits.track_visit(target1_id, values: visitor1_id, time: 7.days.ago) - unique_visits.track_visit(target1_id, values: visitor2_id, time: 7.days.ago) - - unique_visits.track_visit(target2_id, values: visitor2_id, time: 7.days.ago) - unique_visits.track_visit(target2_id, values: visitor1_id, time: 8.days.ago) - unique_visits.track_visit(target2_id, values: visitor1_id, time: 15.days.ago) - - unique_visits.track_visit(target4_id, values: visitor3_id, time: 7.days.ago) - - unique_visits.track_visit(target5_id, values: visitor3_id, time: 15.days.ago) - unique_visits.track_visit(target5_id, values: visitor2_id, time: 15.days.ago) - - expect(unique_visits.unique_visits_for(targets: target1_id)).to eq(2) - expect(unique_visits.unique_visits_for(targets: target2_id)).to eq(1) - expect(unique_visits.unique_visits_for(targets: target4_id)).to eq(1) - - expect(unique_visits.unique_visits_for(targets: target2_id, start_date: 15.days.ago)).to eq(1) - - expect(unique_visits.unique_visits_for(targets: target3_id)).to eq(0) - - expect(unique_visits.unique_visits_for(targets: target5_id, start_date: 15.days.ago)).to eq(2) - - expect(unique_visits.unique_visits_for(targets: :analytics)).to eq(2) - expect(unique_visits.unique_visits_for(targets: :analytics, start_date: 15.days.ago)).to eq(1) - expect(unique_visits.unique_visits_for(targets: :analytics, start_date: 30.days.ago)).to eq(0) - - expect(unique_visits.unique_visits_for(targets: :analytics, start_date: 4.weeks.ago, end_date: Date.current)).to eq(2) - - expect(unique_visits.unique_visits_for(targets: :compliance)).to eq(1) - expect(unique_visits.unique_visits_for(targets: :compliance, start_date: 15.days.ago)).to eq(2) - expect(unique_visits.unique_visits_for(targets: :compliance, start_date: 30.days.ago)).to eq(0) - - expect(unique_visits.unique_visits_for(targets: :compliance, start_date: 4.weeks.ago, end_date: Date.current)).to eq(2) - end - - it 'sets the keys in Redis to expire automatically after 12 weeks' do - unique_visits.track_visit(target1_id, values: visitor1_id) - - Gitlab::Redis::SharedState.with do |redis| - redis.scan_each(match: "{#{target1_id}}-*").each do |key| - expect(redis.ttl(key)).to be_within(5.seconds).of(12.weeks) - end - end - end - - it 'raises an error if an invalid target id is given' do - invalid_target_id = "x_invalid" - - expect do - unique_visits.track_visit(invalid_target_id, values: visitor1_id) - end.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent) - end - end -end diff --git a/spec/models/concerns/atomic_internal_id_spec.rb b/spec/models/concerns/atomic_internal_id_spec.rb index 35b0f107676..b803e699b25 100644 --- a/spec/models/concerns/atomic_internal_id_spec.rb +++ b/spec/models/concerns/atomic_internal_id_spec.rb @@ -240,18 +240,12 @@ RSpec.describe AtomicInternalId do end describe '.with_project_iid_supply' do - let(:iid) { 100 } - - it 'wraps generate and track_greatest in a concurrency-safe lock' do - expect_next_instance_of(InternalId::InternalIdGenerator) do |g| - expect(g).to receive(:with_lock).and_call_original - expect(g.record).to receive(:last_value).and_return(iid) - expect(g).to receive(:track_greatest).with(iid + 4) - end - - ::Milestone.with_project_iid_supply(milestone.project) do |supply| - 4.times { supply.next_value } - end + it 'supplies a stream of iid values' do + expect do + ::Milestone.with_project_iid_supply(milestone.project) do |supply| + 4.times { supply.next_value } + end + end.to change { InternalId.find_by(project: milestone.project, usage: :milestones)&.last_value.to_i }.by(4) end end end diff --git a/spec/models/internal_id_spec.rb b/spec/models/internal_id_spec.rb index 390d1552c16..696b5b48cbf 100644 --- a/spec/models/internal_id_spec.rb +++ b/spec/models/internal_id_spec.rb @@ -39,216 +39,217 @@ RSpec.describe InternalId do end end - describe '.generate_next' do - subject { described_class.generate_next(id_subject, scope, usage, init) } + shared_examples_for 'a monotonically increasing id generator' do + describe '.generate_next' do + subject { described_class.generate_next(id_subject, scope, usage, init) } - context 'in the absence of a record' do - it 'creates a record if not yet present' do - expect { subject }.to change { described_class.count }.from(0).to(1) - end + context 'in the absence of a record' do + it 'creates a record if not yet present' do + expect { subject }.to change { described_class.count }.from(0).to(1) + end - it 'stores record attributes' do - subject + it 'stores record attributes' do + subject - described_class.first.tap do |record| - expect(record.project).to eq(project) - expect(record.usage).to eq(usage.to_s) + described_class.first.tap do |record| + expect(record.project).to eq(project) + expect(record.usage).to eq(usage.to_s) + end end - end - context 'with existing issues' do - before do - create_list(:issue, 2, project: project) - described_class.delete_all - end + context 'with existing issues' do + before do + create_list(:issue, 2, project: project) + described_class.delete_all + end - it 'calculates last_value values automatically' do - expect(subject).to eq(project.issues.size + 1) + it 'calculates last_value values automatically' do + expect(subject).to eq(project.issues.size + 1) + end end end - context 'with concurrent inserts on table' do - it 'looks up the record if it was created concurrently' do - args = { **scope, usage: described_class.usages[usage.to_s] } - record = double - expect(described_class).to receive(:find_by).with(args).and_return(nil) # first call, record not present - expect(described_class).to receive(:find_by).with(args).and_return(record) # second call, record was created by another process - expect(described_class).to receive(:create!).and_raise(ActiveRecord::RecordNotUnique, 'record not unique') - expect(record).to receive(:increment_and_save!) - - subject + it 'generates a strictly monotone, gapless sequence' do + seq = Array.new(10).map do + described_class.generate_next(issue, scope, usage, init) end - end - end + normalized = seq.map { |i| i - seq.min } - it 'generates a strictly monotone, gapless sequence' do - seq = Array.new(10).map do - described_class.generate_next(issue, scope, usage, init) + expect(normalized).to eq((0..seq.size - 1).to_a) end - normalized = seq.map { |i| i - seq.min } - - expect(normalized).to eq((0..seq.size - 1).to_a) - end - context 'there are no instances to pass in' do - let(:id_subject) { Issue } + context 'there are no instances to pass in' do + let(:id_subject) { Issue } - it 'accepts classes instead' do - expect(subject).to eq(1) + it 'accepts classes instead' do + expect(subject).to eq(1) + end end - end - context 'when executed outside of transaction' do - it 'increments counter with in_transaction: "false"' do - allow(ActiveRecord::Base.connection).to receive(:transaction_open?) { false } + context 'when executed outside of transaction' do + it 'increments counter with in_transaction: "false"' do + allow(ActiveRecord::Base.connection).to receive(:transaction_open?) { false } - expect(InternalId::InternalIdGenerator.internal_id_transactions_total).to receive(:increment) - .with(operation: :generate, usage: 'issues', in_transaction: 'false').and_call_original + expect(InternalId.internal_id_transactions_total).to receive(:increment) + .with(operation: :generate, usage: 'issues', in_transaction: 'false').and_call_original - subject + subject + end end - end - context 'when executed within transaction' do - it 'increments counter with in_transaction: "true"' do - expect(InternalId::InternalIdGenerator.internal_id_transactions_total).to receive(:increment) - .with(operation: :generate, usage: 'issues', in_transaction: 'true').and_call_original + context 'when executed within transaction' do + it 'increments counter with in_transaction: "true"' do + expect(InternalId.internal_id_transactions_total).to receive(:increment) + .with(operation: :generate, usage: 'issues', in_transaction: 'true').and_call_original - InternalId.transaction { subject } + InternalId.transaction { subject } + end end end - end - describe '.reset' do - subject { described_class.reset(issue, scope, usage, value) } + describe '.reset' do + subject { described_class.reset(issue, scope, usage, value) } - context 'in the absence of a record' do - let(:value) { 2 } + context 'in the absence of a record' do + let(:value) { 2 } - it 'does not revert back the value' do - expect { subject }.not_to change { described_class.count } - expect(subject).to be_falsey + it 'does not revert back the value' do + expect { subject }.not_to change { described_class.count } + expect(subject).to be_falsey + end end - end - context 'when valid iid is used to reset' do - let!(:value) { generate_next } + context 'when valid iid is used to reset' do + let!(:value) { generate_next } - context 'and iid is a latest one' do - it 'does rewind and next generated value is the same' do - expect(subject).to be_truthy - expect(generate_next).to eq(value) + context 'and iid is a latest one' do + it 'does rewind and next generated value is the same' do + expect(subject).to be_truthy + expect(generate_next).to eq(value) + end end - end - context 'and iid is not a latest one' do - it 'does not rewind' do - generate_next + context 'and iid is not a latest one' do + it 'does not rewind' do + generate_next - expect(subject).to be_falsey - expect(generate_next).to be > value + expect(subject).to be_falsey + expect(generate_next).to be > value + end end - end - def generate_next - described_class.generate_next(issue, scope, usage, init) + def generate_next + described_class.generate_next(issue, scope, usage, init) + end end - end - context 'when executed outside of transaction' do - let(:value) { 2 } + context 'when executed outside of transaction' do + let(:value) { 2 } - it 'increments counter with in_transaction: "false"' do - allow(ActiveRecord::Base.connection).to receive(:transaction_open?) { false } + it 'increments counter with in_transaction: "false"' do + allow(ActiveRecord::Base.connection).to receive(:transaction_open?) { false } - expect(InternalId::InternalIdGenerator.internal_id_transactions_total).to receive(:increment) - .with(operation: :reset, usage: 'issues', in_transaction: 'false').and_call_original + expect(InternalId.internal_id_transactions_total).to receive(:increment) + .with(operation: :reset, usage: 'issues', in_transaction: 'false').and_call_original - subject + subject + end end - end - context 'when executed within transaction' do - let(:value) { 2 } + context 'when executed within transaction' do + let(:value) { 2 } - it 'increments counter with in_transaction: "true"' do - expect(InternalId::InternalIdGenerator.internal_id_transactions_total).to receive(:increment) - .with(operation: :reset, usage: 'issues', in_transaction: 'true').and_call_original + it 'increments counter with in_transaction: "true"' do + expect(InternalId.internal_id_transactions_total).to receive(:increment) + .with(operation: :reset, usage: 'issues', in_transaction: 'true').and_call_original - InternalId.transaction { subject } + InternalId.transaction { subject } + end end end - end - describe '.track_greatest' do - let(:value) { 9001 } + describe '.track_greatest' do + let(:value) { 9001 } - subject { described_class.track_greatest(id_subject, scope, usage, value, init) } + subject { described_class.track_greatest(id_subject, scope, usage, value, init) } - context 'in the absence of a record' do - it 'creates a record if not yet present' do - expect { subject }.to change { described_class.count }.from(0).to(1) + context 'in the absence of a record' do + it 'creates a record if not yet present' do + expect { subject }.to change { described_class.count }.from(0).to(1) + end end - end - it 'stores record attributes' do - subject + it 'stores record attributes' do + subject - described_class.first.tap do |record| - expect(record.project).to eq(project) - expect(record.usage).to eq(usage.to_s) - expect(record.last_value).to eq(value) + described_class.first.tap do |record| + expect(record.project).to eq(project) + expect(record.usage).to eq(usage.to_s) + expect(record.last_value).to eq(value) + end end - end - context 'with existing issues' do - before do - create(:issue, project: project) - described_class.delete_all - end + context 'with existing issues' do + before do + create(:issue, project: project) + described_class.delete_all + end - it 'still returns the last value to that of the given value' do - expect(subject).to eq(value) + it 'still returns the last value to that of the given value' do + expect(subject).to eq(value) + end end - end - context 'when value is less than the current last_value' do - it 'returns the current last_value' do - described_class.create!(**scope, usage: usage, last_value: 10_001) + context 'when value is less than the current last_value' do + it 'returns the current last_value' do + described_class.create!(**scope, usage: usage, last_value: 10_001) - expect(subject).to eq 10_001 + expect(subject).to eq 10_001 + end end - end - context 'there are no instances to pass in' do - let(:id_subject) { Issue } + context 'there are no instances to pass in' do + let(:id_subject) { Issue } - it 'accepts classes instead' do - expect(subject).to eq(value) + it 'accepts classes instead' do + expect(subject).to eq(value) + end end - end - context 'when executed outside of transaction' do - it 'increments counter with in_transaction: "false"' do - allow(ActiveRecord::Base.connection).to receive(:transaction_open?) { false } + context 'when executed outside of transaction' do + it 'increments counter with in_transaction: "false"' do + allow(ActiveRecord::Base.connection).to receive(:transaction_open?) { false } - expect(InternalId::InternalIdGenerator.internal_id_transactions_total).to receive(:increment) - .with(operation: :track_greatest, usage: 'issues', in_transaction: 'false').and_call_original + expect(InternalId.internal_id_transactions_total).to receive(:increment) + .with(operation: :track_greatest, usage: 'issues', in_transaction: 'false').and_call_original - subject + subject + end end - end - context 'when executed within transaction' do - it 'increments counter with in_transaction: "true"' do - expect(InternalId::InternalIdGenerator.internal_id_transactions_total).to receive(:increment) - .with(operation: :track_greatest, usage: 'issues', in_transaction: 'true').and_call_original + context 'when executed within transaction' do + it 'increments counter with in_transaction: "true"' do + expect(InternalId.internal_id_transactions_total).to receive(:increment) + .with(operation: :track_greatest, usage: 'issues', in_transaction: 'true').and_call_original - InternalId.transaction { subject } + InternalId.transaction { subject } + end end end end + context 'when the feature flag is disabled' do + stub_feature_flags(generate_iids_without_explicit_locking: false) + + it_behaves_like 'a monotonically increasing id generator' + end + + context 'when the feature flag is enabled' do + stub_feature_flags(generate_iids_without_explicit_locking: true) + + it_behaves_like 'a monotonically increasing id generator' + end + describe '#increment_and_save!' do let(:id) { create(:internal_id) } diff --git a/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb b/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb index 42f82987989..03f565e0aac 100644 --- a/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb +++ b/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb @@ -165,9 +165,9 @@ RSpec.shared_examples 'AtomicInternalId' do |validate_presence: true| 3.times { supply.next_value } end - current_value = described_class.public_send(method_name, scope_value, &:current_value) - - expect(current_value).to eq(iid + 3) + described_class.public_send(method_name, scope_value) do |supply| + expect(supply.next_value).to eq(iid + 4) + end end end |