diff options
Diffstat (limited to 'spec/lib/gitlab')
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/job_spec.rb | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/extendable/entry_spec.rb | 46 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/status/build/factory_spec.rb | 8 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/yaml_processor_spec.rb | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/git/repository_spec.rb | 12 | ||||
-rw-r--r-- | spec/lib/gitlab/gitaly_client/repository_service_spec.rb | 11 | ||||
-rw-r--r-- | spec/lib/gitlab/graphql/representation/tree_entry_spec.rb | 20 | ||||
-rw-r--r-- | spec/lib/gitlab/kubernetes/helm/api_spec.rb | 24 | ||||
-rw-r--r-- | spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb | 179 | ||||
-rw-r--r-- | spec/lib/gitlab/markdown_cache/field_data_spec.rb | 15 | ||||
-rw-r--r-- | spec/lib/gitlab/markdown_cache/redis/extension_spec.rb | 76 | ||||
-rw-r--r-- | spec/lib/gitlab/markdown_cache/redis/store_spec.rb | 68 |
12 files changed, 448 insertions, 15 deletions
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index 0560eb42e4d..e0552ae8c57 100644 --- a/spec/lib/gitlab/ci/config/entry/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -94,7 +94,7 @@ describe Gitlab::Ci::Config::Entry::Job do it 'returns error about wrong value type' do expect(entry).not_to be_valid - expect(entry.errors).to include "job extends should be a string" + expect(entry.errors).to include "job extends should be an array of strings or a string" end end diff --git a/spec/lib/gitlab/ci/config/extendable/entry_spec.rb b/spec/lib/gitlab/ci/config/extendable/entry_spec.rb index 0a148375d11..d63612053b6 100644 --- a/spec/lib/gitlab/ci/config/extendable/entry_spec.rb +++ b/spec/lib/gitlab/ci/config/extendable/entry_spec.rb @@ -44,12 +44,12 @@ describe Gitlab::Ci::Config::Extendable::Entry do end end - describe '#extends_key' do + describe '#extends_keys' do context 'when entry is extensible' do it 'returns symbolized extends key value' do entry = described_class.new(:test, test: { extends: 'something' }) - expect(entry.extends_key).to eq :something + expect(entry.extends_keys).to eq [:something] end end @@ -57,7 +57,7 @@ describe Gitlab::Ci::Config::Extendable::Entry do it 'returns nil' do entry = described_class.new(:test, test: 'something') - expect(entry.extends_key).to be_nil + expect(entry.extends_keys).to be_nil end end end @@ -76,7 +76,7 @@ describe Gitlab::Ci::Config::Extendable::Entry do end end - describe '#base_hash!' do + describe '#base_hashes!' do subject { described_class.new(:test, hash) } context 'when base hash is not extensible' do @@ -87,8 +87,8 @@ describe Gitlab::Ci::Config::Extendable::Entry do } end - it 'returns unchanged base hash' do - expect(subject.base_hash!).to eq(script: 'rspec') + it 'returns unchanged base hashes' do + expect(subject.base_hashes!).to eq([{ script: 'rspec' }]) end end @@ -101,12 +101,12 @@ describe Gitlab::Ci::Config::Extendable::Entry do } end - it 'extends the base hash first' do - expect(subject.base_hash!).to eq(extends: 'first', script: 'rspec') + it 'extends the base hashes first' do + expect(subject.base_hashes!).to eq([{ extends: 'first', script: 'rspec' }]) end it 'mutates original context' do - subject.base_hash! + subject.base_hashes! expect(hash.fetch(:second)).to eq(extends: 'first', script: 'rspec') end @@ -171,6 +171,34 @@ describe Gitlab::Ci::Config::Extendable::Entry do end end + context 'when extending multiple hashes correctly' do + let(:hash) do + { + first: { script: 'my value', image: 'ubuntu' }, + second: { image: 'alpine' }, + test: { extends: %w(first second) } + } + end + + let(:result) do + { + first: { script: 'my value', image: 'ubuntu' }, + second: { image: 'alpine' }, + test: { extends: %w(first second), script: 'my value', image: 'alpine' } + } + end + + it 'returns extended part of the hash' do + expect(subject.extend!).to eq result[:test] + end + + it 'mutates original context' do + subject.extend! + + expect(hash).to eq result + end + end + context 'when hash is not extensible' do let(:hash) do { diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb index 025439f1b6e..b6231510b91 100644 --- a/spec/lib/gitlab/ci/status/build/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb @@ -163,11 +163,11 @@ describe Gitlab::Ci::Status::Build::Factory do it 'matches correct extended statuses' do expect(factory.extended_statuses) - .to eq [Gitlab::Ci::Status::Build::Canceled] + .to eq [Gitlab::Ci::Status::Build::Canceled, Gitlab::Ci::Status::Build::Retryable] end - it 'does not fabricate a retryable build status' do - expect(status).not_to be_a Gitlab::Ci::Status::Build::Retryable + it 'fabricates a retryable build status' do + expect(status).to be_a Gitlab::Ci::Status::Build::Retryable end it 'fabricates status with correct details' do @@ -177,7 +177,7 @@ describe Gitlab::Ci::Status::Build::Factory do expect(status.illustration).to include(:image, :size, :title) expect(status.label).to eq 'canceled' expect(status).to have_details - expect(status).not_to have_action + expect(status).to have_action end end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 29276d5b686..635b4e556e8 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -1470,7 +1470,7 @@ module Gitlab expect { Gitlab::Ci::YamlProcessor.new(config) } .to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, - 'rspec: unknown key in `extends`') + 'rspec: unknown keys in `extends` (something)') end end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index cb4701e8edc..e72fb9c6fbc 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -186,6 +186,18 @@ describe Gitlab::Git::Repository, :seed_helper do it { is_expected.to be < 2 } end + describe '#object_directory_size' do + before do + allow(repository.gitaly_repository_client) + .to receive(:get_object_directory_size) + .and_return(2) + end + + subject { repository.object_directory_size } + + it { is_expected.to eq 2048 } + end + describe '#empty?' do it { expect(repository).not_to be_empty } end diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb index 09de7ca6afd..a3808adb376 100644 --- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb @@ -73,6 +73,17 @@ describe Gitlab::GitalyClient::RepositoryService do end end + describe '#get_object_directory_size' do + it 'sends a get_object_directory_size message' do + expect_any_instance_of(Gitaly::RepositoryService::Stub) + .to receive(:get_object_directory_size) + .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash)) + .and_return(size: 0) + + client.get_object_directory_size + end + end + describe '#apply_gitattributes' do let(:revision) { 'master' } diff --git a/spec/lib/gitlab/graphql/representation/tree_entry_spec.rb b/spec/lib/gitlab/graphql/representation/tree_entry_spec.rb new file mode 100644 index 00000000000..d45e690160c --- /dev/null +++ b/spec/lib/gitlab/graphql/representation/tree_entry_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Graphql::Representation::TreeEntry do + let(:project) { create(:project, :repository) } + let(:repository) { project.repository } + + describe '.decorate' do + it 'returns NilClass when given nil' do + expect(described_class.decorate(nil, repository)).to be_nil + end + + it 'returns array of TreeEntry' do + entries = described_class.decorate(repository.tree.blobs, repository) + + expect(entries.first).to be_a(described_class) + end + end +end diff --git a/spec/lib/gitlab/kubernetes/helm/api_spec.rb b/spec/lib/gitlab/kubernetes/helm/api_spec.rb index 24ce397ec3d..0de809833e6 100644 --- a/spec/lib/gitlab/kubernetes/helm/api_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/api_spec.rb @@ -36,6 +36,8 @@ describe Gitlab::Kubernetes::Helm::Api do describe '#uninstall' do before do allow(client).to receive(:create_pod).and_return(nil) + allow(client).to receive(:get_config_map).and_return(nil) + allow(client).to receive(:create_config_map).and_return(nil) allow(client).to receive(:delete_pod).and_return(nil) allow(namespace).to receive(:ensure_exists!).once end @@ -53,6 +55,28 @@ describe Gitlab::Kubernetes::Helm::Api do subject.uninstall(command) end + + context 'with a ConfigMap' do + let(:resource) { Gitlab::Kubernetes::ConfigMap.new(application_name, files).generate } + + it 'creates a ConfigMap on kubeclient' do + expect(client).to receive(:create_config_map).with(resource).once + + subject.install(command) + end + + context 'config map already exists' do + before do + expect(client).to receive(:get_config_map).with("values-content-configuration-#{application_name}", gitlab_namespace).and_return(resource) + end + + it 'updates the config map' do + expect(client).to receive(:update_config_map).with(resource).once + + subject.install(command) + end + end + end end describe '#install' do diff --git a/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb b/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb new file mode 100644 index 00000000000..18052b1991c --- /dev/null +++ b/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb @@ -0,0 +1,179 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Gitlab::MarkdownCache::ActiveRecord::Extension do + let(:klass) do + Class.new(ActiveRecord::Base) do + self.table_name = 'issues' + include CacheMarkdownField + cache_markdown_field :title, whitelisted: true + cache_markdown_field :description, pipeline: :single_line + + attr_accessor :author, :project + end + end + + let(:cache_version) { Gitlab::MarkdownCache::CACHE_COMMONMARK_VERSION << 16 } + let(:thing) { klass.new(title: markdown, title_html: html, cached_markdown_version: cache_version) } + + let(:markdown) { '`Foo`' } + let(:html) { '<p data-sourcepos="1:1-1:5" dir="auto"><code>Foo</code></p>' } + + let(:updated_markdown) { '`Bar`' } + let(:updated_html) { '<p data-sourcepos="1:1-1:5" dir="auto"><code>Bar</code></p>' } + + context 'an unchanged markdown field' do + let(:thing) { klass.new(title: markdown) } + + before do + thing.title = thing.title + thing.save + end + + it { expect(thing.title).to eq(markdown) } + it { expect(thing.title_html).to eq(html) } + it { expect(thing.title_html_changed?).not_to be_truthy } + it { expect(thing.cached_markdown_version).to eq(cache_version) } + end + + context 'a changed markdown field' do + let(:thing) { klass.new(title: markdown, title_html: html, cached_markdown_version: cache_version) } + + before do + thing.title = updated_markdown + thing.save + end + + it { expect(thing.title_html).to eq(updated_html) } + it { expect(thing.cached_markdown_version).to eq(cache_version) } + end + + context 'when a markdown field is set repeatedly to an empty string' do + it do + expect(thing).to receive(:refresh_markdown_cache).once + thing.title = '' + thing.save + thing.title = '' + thing.save + end + end + + context 'when a markdown field is set repeatedly to a string which renders as empty html' do + it do + expect(thing).to receive(:refresh_markdown_cache).once + thing.title = '[//]: # (This is also a comment.)' + thing.save + thing.title = '[//]: # (This is also a comment.)' + thing.save + end + end + + context 'a non-markdown field changed' do + let(:thing) { klass.new(title: markdown, title_html: html, cached_markdown_version: cache_version) } + + before do + thing.state = 'closed' + thing.save + end + + it { expect(thing.state).to eq('closed') } + it { expect(thing.title).to eq(markdown) } + it { expect(thing.title_html).to eq(html) } + it { expect(thing.cached_markdown_version).to eq(cache_version) } + end + + context 'version is out of date' do + let(:thing) { klass.new(title: updated_markdown, title_html: html, cached_markdown_version: nil) } + + before do + thing.save + end + + it { expect(thing.title_html).to eq(updated_html) } + it { expect(thing.cached_markdown_version).to eq(cache_version) } + end + + context 'when an invalidating field is changed' do + it 'invalidates the cache when project changes' do + thing.project = :new_project + allow(Banzai::Renderer).to receive(:cacheless_render_field).and_return(updated_html) + + thing.save + + expect(thing.title_html).to eq(updated_html) + expect(thing.description_html).to eq(updated_html) + expect(thing.cached_markdown_version).to eq(cache_version) + end + + it 'invalidates the cache when author changes' do + thing.author = :new_author + allow(Banzai::Renderer).to receive(:cacheless_render_field).and_return(updated_html) + + thing.save + + expect(thing.title_html).to eq(updated_html) + expect(thing.description_html).to eq(updated_html) + expect(thing.cached_markdown_version).to eq(cache_version) + end + end + + describe '.attributes' do + it 'excludes cache attributes that is blacklisted by default' do + expect(thing.attributes.keys.sort).not_to include(%w[description_html]) + end + end + + describe '#cached_html_up_to_date?' do + let(:thing) { klass.create(title: updated_markdown, title_html: html, cached_markdown_version: nil) } + subject { thing.cached_html_up_to_date?(:title) } + + it 'returns false if markdown has been changed but html has not' do + thing.title = "changed!" + + is_expected.to be_falsy + end + + it 'returns true if markdown has not been changed but html has' do + thing.title_html = updated_html + + is_expected.to be_truthy + end + + it 'returns true if markdown and html have both been changed' do + thing.title = updated_markdown + thing.title_html = updated_html + + is_expected.to be_truthy + end + + it 'returns false if the markdown field is set but the html is not' do + thing.title_html = nil + + is_expected.to be_falsy + end + end + + describe '#refresh_markdown_cache!' do + before do + thing.title = updated_markdown + end + + it 'skips saving if not persisted' do + expect(thing).to receive(:persisted?).and_return(false) + expect(thing).not_to receive(:update_columns) + + thing.refresh_markdown_cache! + end + + it 'saves the changes' do + expect(thing).to receive(:persisted?).and_return(true) + + expect(thing).to receive(:update_columns) + .with("title_html" => updated_html, + "description_html" => "", + "cached_markdown_version" => cache_version) + + thing.refresh_markdown_cache! + end + end +end diff --git a/spec/lib/gitlab/markdown_cache/field_data_spec.rb b/spec/lib/gitlab/markdown_cache/field_data_spec.rb new file mode 100644 index 00000000000..393bf85aa43 --- /dev/null +++ b/spec/lib/gitlab/markdown_cache/field_data_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' + +describe Gitlab::MarkdownCache::FieldData do + subject(:field_data) { described_class.new } + + before do + field_data[:description] = { project: double('project in context') } + end + + it 'translates a markdown field name into a html field name' do + expect(field_data.html_field(:description)).to eq("description_html") + end +end diff --git a/spec/lib/gitlab/markdown_cache/redis/extension_spec.rb b/spec/lib/gitlab/markdown_cache/redis/extension_spec.rb new file mode 100644 index 00000000000..b6a781de426 --- /dev/null +++ b/spec/lib/gitlab/markdown_cache/redis/extension_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Gitlab::MarkdownCache::Redis::Extension, :clean_gitlab_redis_cache do + let(:klass) do + Class.new do + include CacheMarkdownField + + def initialize(title: nil, description: nil) + @title, @description = title, description + end + + attr_reader :title, :description + + cache_markdown_field :title, pipeline: :single_line + cache_markdown_field :description + + def cache_key + "cache-key" + end + end + end + + let(:cache_version) { Gitlab::MarkdownCache::CACHE_COMMONMARK_VERSION << 16 } + let(:thing) { klass.new(title: "`Hello`", description: "`World`") } + let(:expected_cache_key) { "markdown_cache:cache-key" } + + it 'defines the html attributes' do + expect(thing).to respond_to(:title_html, :description_html, :cached_markdown_version) + end + + it 'loads the markdown from the cache only once' do + expect(thing).to receive(:load_cached_markdown).once.and_call_original + + thing.title_html + thing.description_html + end + + it 'correctly loads the markdown if it was stored in redis' do + Gitlab::Redis::Cache.with do |r| + r.mapped_hmset(expected_cache_key, + title_html: 'hello', + description_html: 'world', + cached_markdown_version: cache_version) + end + + expect(thing.title_html).to eq('hello') + expect(thing.description_html).to eq('world') + expect(thing.cached_markdown_version).to eq(cache_version) + end + + describe "#refresh_markdown_cache!" do + it "stores the value in redis" do + expected_results = { "title_html" => "`Hello`", + "description_html" => "<p data-sourcepos=\"1:1-1:7\" dir=\"auto\"><code>World</code></p>", + "cached_markdown_version" => cache_version.to_s } + + thing.refresh_markdown_cache! + + results = Gitlab::Redis::Cache.with do |r| + r.mapped_hmget(expected_cache_key, + "title_html", "description_html", "cached_markdown_version") + end + + expect(results).to eq(expected_results) + end + + it "assigns the values" do + thing.refresh_markdown_cache! + + expect(thing.title_html).to eq('`Hello`') + expect(thing.description_html).to eq("<p data-sourcepos=\"1:1-1:7\" dir=\"auto\"><code>World</code></p>") + expect(thing.cached_markdown_version).to eq(cache_version) + end + end +end diff --git a/spec/lib/gitlab/markdown_cache/redis/store_spec.rb b/spec/lib/gitlab/markdown_cache/redis/store_spec.rb new file mode 100644 index 00000000000..95c68e7d491 --- /dev/null +++ b/spec/lib/gitlab/markdown_cache/redis/store_spec.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Gitlab::MarkdownCache::Redis::Store, :clean_gitlab_redis_cache do + let(:storable_class) do + Class.new do + cattr_reader :cached_markdown_fields do + Gitlab::MarkdownCache::FieldData.new.tap do |field_data| + field_data[:field_1] = {} + field_data[:field_2] = {} + end + end + + attr_accessor :field_1, :field_2, :field_1_html, :field_2_html, :cached_markdown_version + + def cache_key + "cache-key" + end + end + end + let(:storable) { storable_class.new } + let(:cache_key) { "markdown_cache:#{storable.cache_key}" } + + subject(:store) { described_class.new(storable) } + + def read_values + Gitlab::Redis::Cache.with do |r| + r.mapped_hmget(cache_key, + :field_1_html, :field_2_html, :cached_markdown_version) + end + end + + def store_values(values) + Gitlab::Redis::Cache.with do |r| + r.mapped_hmset(cache_key, + values) + end + end + + describe '#save' do + it 'stores updates to html fields and version' do + values_to_store = { field_1_html: "hello", field_2_html: "world", cached_markdown_version: 1 } + + store.save(values_to_store) + + expect(read_values) + .to eq({ field_1_html: "hello", field_2_html: "world", cached_markdown_version: "1" }) + end + end + + describe '#read' do + it 'reads the html fields and version from redis if they were stored' do + stored_values = { field_1_html: "hello", field_2_html: "world", cached_markdown_version: 1 } + + store_values(stored_values) + + expect(store.read.symbolize_keys).to eq(stored_values) + end + + it 'is mared loaded after reading' do + expect(store).not_to be_loaded + + store.read + + expect(store).to be_loaded + end + end +end |