diff options
Diffstat (limited to 'spec')
-rw-r--r-- | spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js | 15 | ||||
-rw-r--r-- | spec/frontend/monitoring/router_spec.js | 3 | ||||
-rw-r--r-- | spec/frontend_integration/ide/ide_helper.js | 26 | ||||
-rw-r--r-- | spec/frontend_integration/ide/ide_integration_spec.js | 15 | ||||
-rw-r--r-- | spec/frontend_integration/test_helpers/setup/setup_globals.js | 2 | ||||
-rw-r--r-- | spec/lib/backup/database_spec.rb | 21 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/artifact_file_reader_spec.rb | 11 | ||||
-rw-r--r-- | spec/models/ci/build_trace_chunk_spec.rb | 26 | ||||
-rw-r--r-- | spec/models/ci/build_trace_chunks/fog_spec.rb | 20 | ||||
-rw-r--r-- | spec/models/ci/build_trace_chunks/legacy_fog_spec.rb | 164 |
10 files changed, 284 insertions, 19 deletions
diff --git a/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js b/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js index 7c1a4ff1085..d1219627ca7 100644 --- a/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js +++ b/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js @@ -1,6 +1,7 @@ import Vuex from 'vuex'; import { shallowMount, createLocalVue } from '@vue/test-utils'; import { GlDropdownItem, GlDropdown } from '@gitlab/ui'; +import { secondsToHours } from '~/lib/utils/datetime_utility'; import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown.vue'; import createStore from '~/deploy_freeze/store'; @@ -12,6 +13,11 @@ describe('Deploy freeze timezone dropdown', () => { let store; const timezoneDataFixture = getJSONFixture('/api/freeze-periods/timezone_data.json'); + const findTzByName = (identifier = '') => + timezoneDataFixture.find(({ name }) => name.toLowerCase() === identifier.toLowerCase()); + + const formatTz = ({ offset, name }) => `[UTC ${secondsToHours(offset)}] ${name}`; + const createComponent = (searchTerm, selectedTimezone) => { store = createStore({ projectId: '8', @@ -63,8 +69,9 @@ describe('Deploy freeze timezone dropdown', () => { }); it('renders only the time zone searched for', () => { + const selectedTz = findTzByName('Alaska'); expect(findAllDropdownItems()).toHaveLength(1); - expect(findDropdownItemByIndex(0).text()).toBe('[UTC -8] Alaska'); + expect(findDropdownItemByIndex(0).text()).toBe(formatTz(selectedTz)); }); it('should not display empty results message', () => { @@ -72,13 +79,15 @@ describe('Deploy freeze timezone dropdown', () => { }); describe('Custom events', () => { + const selectedTz = findTzByName('Alaska'); + it('should emit input if a time zone is clicked', () => { findDropdownItemByIndex(0).vm.$emit('click'); expect(wrapper.emitted('input')).toEqual([ [ { - formattedTimezone: '[UTC -8] Alaska', - identifier: 'America/Juneau', + formattedTimezone: formatTz(selectedTz), + identifier: selectedTz.identifier, }, ], ]); diff --git a/spec/frontend/monitoring/router_spec.js b/spec/frontend/monitoring/router_spec.js index 2bf2065b178..8b97c8ed125 100644 --- a/spec/frontend/monitoring/router_spec.js +++ b/spec/frontend/monitoring/router_spec.js @@ -105,7 +105,8 @@ describe('Monitoring router', () => { path | currentDashboard ${'/panel/new'} | ${undefined} ${'/dashboard.yml/panel/new'} | ${'dashboard.yml'} - ${'/config%2Fprometheus%2Fcommon_metrics.yml/panel/new'} | ${'config%2Fprometheus%2Fcommon_metrics.yml'} + ${'/config/prometheus/common_metrics.yml/panel/new'} | ${'config/prometheus/common_metrics.yml'} + ${'/config%2Fprometheus%2Fcommon_metrics.yml/panel/new'} | ${'config/prometheus/common_metrics.yml'} `('"$path" renders page with dashboard "$currentDashboard"', ({ path, currentDashboard }) => { const wrapper = createWrapper(BASE_PATH, path); diff --git a/spec/frontend_integration/ide/ide_helper.js b/spec/frontend_integration/ide/ide_helper.js index a43695fea8f..fea8bc24031 100644 --- a/spec/frontend_integration/ide/ide_helper.js +++ b/spec/frontend_integration/ide/ide_helper.js @@ -1,6 +1,6 @@ import { findAllByText, fireEvent, getByLabelText, screen } from '@testing-library/dom'; -const isFileRowOpen = row => row.matches('.is-open'); +const isFolderRowOpen = row => row.matches('.folder.is-open'); const getLeftSidebar = () => screen.getByTestId('left-sidebar'); @@ -24,6 +24,8 @@ const findAndSetEditorValue = async value => { const findTreeBody = () => screen.findByTestId('ide-tree-body', {}, { timeout: 5000 }); +const findRootActions = () => screen.findByTestId('ide-root-actions', {}, { timeout: 7000 }); + const findFileRowContainer = (row = null) => row ? Promise.resolve(row.parentElement) : findTreeBody(); @@ -35,7 +37,7 @@ const findFileChild = async (row, name, index = 0) => { }; const openFileRow = row => { - if (!row || isFileRowOpen(row)) { + if (!row || isFolderRowOpen(row)) { return; } @@ -74,6 +76,19 @@ const findAndSetFileName = async value => { createButton.click(); }; +const findAndClickRootAction = async name => { + const container = await findRootActions(); + const button = getByLabelText(container, name); + + button.click(); +}; + +export const openFile = async path => { + const row = await findAndTraverseToPath(path); + + openFileRow(row); +}; + export const createFile = async (path, content) => { const parentPath = path .split('/') @@ -81,7 +96,12 @@ export const createFile = async (path, content) => { .join('/'); const parentRow = await findAndTraverseToPath(parentPath); - clickFileRowAction(parentRow, 'New file'); + + if (parentRow) { + clickFileRowAction(parentRow, 'New file'); + } else { + await findAndClickRootAction('New file'); + } await findAndSetFileName(path); await findAndSetEditorValue(content); diff --git a/spec/frontend_integration/ide/ide_integration_spec.js b/spec/frontend_integration/ide/ide_integration_spec.js index c4d0c4df8de..1f5c1d38450 100644 --- a/spec/frontend_integration/ide/ide_integration_spec.js +++ b/spec/frontend_integration/ide/ide_integration_spec.js @@ -1,5 +1,6 @@ import { TEST_HOST } from 'helpers/test_constants'; import { waitForText } from 'helpers/wait_for_text'; +import waitForPromises from 'helpers/wait_for_promises'; import { useOverclockTimers } from 'test_helpers/utils/overclock_timers'; import { createCommitId } from 'test_helpers/factories/commit_id'; import { initIde } from '~/ide'; @@ -86,4 +87,18 @@ describe('WebIDE', () => { ], }); }); + + it('user adds file that starts with +', async () => { + createComponent(); + + await ideHelper.createFile('+test', 'Hello world!'); + await ideHelper.openFile('+test'); + + // Wait for monaco things + await waitForPromises(); + + // Assert that +test is the only open tab + const tabs = Array.from(document.querySelectorAll('.multi-file-tab')); + expect(tabs.map(x => x.textContent.trim())).toEqual(['+test']); + }); }); diff --git a/spec/frontend_integration/test_helpers/setup/setup_globals.js b/spec/frontend_integration/test_helpers/setup/setup_globals.js index 2b0e8f76c3c..b63a9a96372 100644 --- a/spec/frontend_integration/test_helpers/setup/setup_globals.js +++ b/spec/frontend_integration/test_helpers/setup/setup_globals.js @@ -6,7 +6,7 @@ beforeEach(() => { relative_url_root: '', }; - setTestTimeout(5000); + setTestTimeout(7000); jest.useRealTimers(); }); diff --git a/spec/lib/backup/database_spec.rb b/spec/lib/backup/database_spec.rb index fccd6db0018..2bce4cab679 100644 --- a/spec/lib/backup/database_spec.rb +++ b/spec/lib/backup/database_spec.rb @@ -48,5 +48,26 @@ RSpec.describe Backup::Database do expect(output).to include(visible_error) end end + + context 'with PostgreSQL settings defined in the environment' do + let(:cmd) { %W[#{Gem.ruby} -e] + ["$stderr.puts ENV.to_h.select { |k, _| k.start_with?('PG') }"] } + let(:config) { YAML.load_file(File.join(Rails.root, 'config', 'database.yml'))['test'] } + + before do + stub_const 'ENV', ENV.to_h.merge({ + 'GITLAB_BACKUP_PGHOST' => 'test.example.com', + 'PGPASSWORD' => 'donotchange' + }) + end + + it 'overrides default config values' do + subject.restore + + expect(output).to include(%("PGHOST"=>"test.example.com")) + expect(output).to include(%("PGPASSWORD"=>"donotchange")) + expect(output).to include(%("PGPORT"=>"#{config['port']}")) if config['port'] + expect(output).to include(%("PGUSER"=>"#{config['username']}")) if config['username'] + end + end end end diff --git a/spec/lib/gitlab/ci/artifact_file_reader_spec.rb b/spec/lib/gitlab/ci/artifact_file_reader_spec.rb index e982f0eb015..83a37655ea9 100644 --- a/spec/lib/gitlab/ci/artifact_file_reader_spec.rb +++ b/spec/lib/gitlab/ci/artifact_file_reader_spec.rb @@ -18,6 +18,17 @@ RSpec.describe Gitlab::Ci::ArtifactFileReader do expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom') end + context 'when FF ci_new_artifact_file_reader is disabled' do + before do + stub_feature_flags(ci_new_artifact_file_reader: false) + end + + it 'returns the content at the path' do + is_expected.to be_present + expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom') + end + end + context 'when path does not exist' do let(:path) { 'file/does/not/exist.txt' } let(:expected_error) do diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb index cdbdd2b1d20..871f279db08 100644 --- a/spec/models/ci/build_trace_chunk_spec.rb +++ b/spec/models/ci/build_trace_chunk_spec.rb @@ -135,11 +135,31 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do context 'when data_store is fog' do let(:data_store) { :fog } - before do - build_trace_chunk.send(:unsafe_set_data!, +'Sample data in fog') + context 'when legacy Fog is enabled' do + before do + stub_feature_flags(ci_trace_new_fog_store: false) + build_trace_chunk.send(:unsafe_set_data!, +'Sample data in fog') + end + + it { is_expected.to eq('Sample data in fog') } + + it 'returns a LegacyFog store' do + expect(described_class.get_store_class(data_store)).to be_a(Ci::BuildTraceChunks::LegacyFog) + end end - it { is_expected.to eq('Sample data in fog') } + context 'when new Fog is enabled' do + before do + stub_feature_flags(ci_trace_new_fog_store: true) + build_trace_chunk.send(:unsafe_set_data!, +'Sample data in fog') + end + + it { is_expected.to eq('Sample data in fog') } + + it 'returns a new Fog store' do + expect(described_class.get_store_class(data_store)).to be_a(Ci::BuildTraceChunks::Fog) + end + end end end diff --git a/spec/models/ci/build_trace_chunks/fog_spec.rb b/spec/models/ci/build_trace_chunks/fog_spec.rb index b7e9adab04a..20ca0c8b710 100644 --- a/spec/models/ci/build_trace_chunks/fog_spec.rb +++ b/spec/models/ci/build_trace_chunks/fog_spec.rb @@ -4,8 +4,12 @@ require 'spec_helper' RSpec.describe Ci::BuildTraceChunks::Fog do let(:data_store) { described_class.new } + let(:bucket) { 'artifacts' } + let(:connection_params) { Gitlab.config.artifacts.object_store.connection.symbolize_keys } + let(:connection) { ::Fog::Storage.new(connection_params) } before do + stub_object_storage(connection_params: connection_params, remote_directory: bucket) stub_artifacts_object_storage end @@ -148,17 +152,17 @@ RSpec.describe Ci::BuildTraceChunks::Fog do end it 'deletes multiple data' do - ::Fog::Storage.new(JobArtifactUploader.object_store_credentials).tap do |connection| - expect(connection.get_object('artifacts', "tmp/builds/#{build.id}/chunks/0.log")[:body]).to be_present - expect(connection.get_object('artifacts', "tmp/builds/#{build.id}/chunks/1.log")[:body]).to be_present - end + files = connection.directories.new(key: bucket).files + + expect(files.count).to eq(2) + expect(files[0].body).to be_present + expect(files[1].body).to be_present subject - ::Fog::Storage.new(JobArtifactUploader.object_store_credentials).tap do |connection| - expect { connection.get_object('artifacts', "tmp/builds/#{build.id}/chunks/0.log")[:body] }.to raise_error(Excon::Error::NotFound) - expect { connection.get_object('artifacts', "tmp/builds/#{build.id}/chunks/1.log")[:body] }.to raise_error(Excon::Error::NotFound) - end + files.reload + + expect(files.count).to eq(0) end end end diff --git a/spec/models/ci/build_trace_chunks/legacy_fog_spec.rb b/spec/models/ci/build_trace_chunks/legacy_fog_spec.rb new file mode 100644 index 00000000000..ca4b414b992 --- /dev/null +++ b/spec/models/ci/build_trace_chunks/legacy_fog_spec.rb @@ -0,0 +1,164 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::BuildTraceChunks::LegacyFog do + let(:data_store) { described_class.new } + + before do + stub_artifacts_object_storage + end + + describe '#available?' do + subject { data_store.available? } + + context 'when object storage is enabled' do + it { is_expected.to be_truthy } + end + + context 'when object storage is disabled' do + before do + stub_artifacts_object_storage(enabled: false) + end + + it { is_expected.to be_falsy } + end + end + + describe '#data' do + subject { data_store.data(model) } + + context 'when data exists' do + let(:model) { create(:ci_build_trace_chunk, :fog_with_data, initial_data: 'sample data in fog') } + + it 'returns the data' do + is_expected.to eq('sample data in fog') + end + end + + context 'when data does not exist' do + let(:model) { create(:ci_build_trace_chunk, :fog_without_data) } + + it 'returns nil' do + expect(data_store.data(model)).to be_nil + end + end + end + + describe '#set_data' do + let(:new_data) { 'abc123' } + + context 'when data exists' do + let(:model) { create(:ci_build_trace_chunk, :fog_with_data, initial_data: 'sample data in fog') } + + it 'overwrites data' do + expect(data_store.data(model)).to eq('sample data in fog') + + data_store.set_data(model, new_data) + + expect(data_store.data(model)).to eq new_data + end + end + + context 'when data does not exist' do + let(:model) { create(:ci_build_trace_chunk, :fog_without_data) } + + it 'sets new data' do + expect(data_store.data(model)).to be_nil + + data_store.set_data(model, new_data) + + expect(data_store.data(model)).to eq new_data + end + end + end + + describe '#delete_data' do + subject { data_store.delete_data(model) } + + context 'when data exists' do + let(:model) { create(:ci_build_trace_chunk, :fog_with_data, initial_data: 'sample data in fog') } + + it 'deletes data' do + expect(data_store.data(model)).to eq('sample data in fog') + + subject + + expect(data_store.data(model)).to be_nil + end + end + + context 'when data does not exist' do + let(:model) { create(:ci_build_trace_chunk, :fog_without_data) } + + it 'does nothing' do + expect(data_store.data(model)).to be_nil + + subject + + expect(data_store.data(model)).to be_nil + end + end + end + + describe '#size' do + context 'when data exists' do + let(:model) { create(:ci_build_trace_chunk, :fog_with_data, initial_data: 'üabcd') } + + it 'returns data bytesize correctly' do + expect(data_store.size(model)).to eq 6 + end + end + + context 'when data does not exist' do + let(:model) { create(:ci_build_trace_chunk, :fog_without_data) } + + it 'returns zero' do + expect(data_store.size(model)).to be_zero + end + end + end + + describe '#keys' do + subject { data_store.keys(relation) } + + let(:build) { create(:ci_build) } + let(:relation) { build.trace_chunks } + + before do + create(:ci_build_trace_chunk, :fog_with_data, chunk_index: 0, build: build) + create(:ci_build_trace_chunk, :fog_with_data, chunk_index: 1, build: build) + end + + it 'returns keys' do + is_expected.to eq([[build.id, 0], [build.id, 1]]) + end + end + + describe '#delete_keys' do + subject { data_store.delete_keys(keys) } + + let(:build) { create(:ci_build) } + let(:relation) { build.trace_chunks } + let(:keys) { data_store.keys(relation) } + + before do + create(:ci_build_trace_chunk, :fog_with_data, chunk_index: 0, build: build) + create(:ci_build_trace_chunk, :fog_with_data, chunk_index: 1, build: build) + end + + it 'deletes multiple data' do + ::Fog::Storage.new(JobArtifactUploader.object_store_credentials).tap do |connection| + expect(connection.get_object('artifacts', "tmp/builds/#{build.id}/chunks/0.log")[:body]).to be_present + expect(connection.get_object('artifacts', "tmp/builds/#{build.id}/chunks/1.log")[:body]).to be_present + end + + subject + + ::Fog::Storage.new(JobArtifactUploader.object_store_credentials).tap do |connection| + expect { connection.get_object('artifacts', "tmp/builds/#{build.id}/chunks/0.log")[:body] }.to raise_error(Excon::Error::NotFound) + expect { connection.get_object('artifacts', "tmp/builds/#{build.id}/chunks/1.log")[:body] }.to raise_error(Excon::Error::NotFound) + end + end + end +end |