From fdba7449867ab49aed7cb39449ac41af4bc2d234 Mon Sep 17 00:00:00 2001 From: Alexander Randa Date: Fri, 21 Apr 2017 15:31:18 +0000 Subject: Fix long urls in the title of commit --- spec/models/commit_spec.rb | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index ce31c8ed94c..3a76e207b0d 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -67,11 +67,11 @@ describe Commit, models: true do expect(commit.title).to eq("--no commit message") end - it "truncates a message without a newline at 80 characters" do + it 'truncates a message without a newline at natural break to 80 characters' do message = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis id blandit. Vivamus egestas lacinia lacus, sed rutrum mauris.' allow(commit).to receive(:safe_message).and_return(message) - expect(commit.title).to eq("#{message[0..79]}…") + expect(commit.title).to eq('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis…') end it "truncates a message with a newline before 80 characters at the newline" do @@ -113,6 +113,28 @@ eos end end + describe 'description' do + it 'returns description of commit message if title less than 100 characters' do + message = < Date: Mon, 22 May 2017 18:20:15 -0500 Subject: Add basic tests for groups component [ci skip] --- spec/javascripts/groups/groups_spec.js | 38 ++++++++++++++++++++++++++++++++ spec/javascripts/groups/mock_data.js | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 spec/javascripts/groups/groups_spec.js create mode 100644 spec/javascripts/groups/mock_data.js (limited to 'spec') diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js new file mode 100644 index 00000000000..1427095f21a --- /dev/null +++ b/spec/javascripts/groups/groups_spec.js @@ -0,0 +1,38 @@ +import Vue from 'vue'; +import GroupFolder from '~/groups/components/group_folder.vue'; +import GroupItem from '~/groups/components/group_item.vue'; +import groupsComponent from '~/groups/components/groups.vue'; +import GroupsStore from '~/groups/stores/groups_store'; +import groupsData from './mock_data'; + +describe('Groups', () => { + let GroupsComponent; + let store; + + beforeEach(() => { + Vue.component('group-folder', GroupFolder); + Vue.component('group-item', GroupItem); + + store = new GroupsStore(); + store.setGroups(groupsData.groups); + store.storePagination(groupsData.pagination); + + GroupsComponent = Vue.extend(groupsComponent); + }); + + describe('with data', () => { + it('should render a list of groups', (done) => { + const component = new GroupsComponent({ + propsData: { + groups: store.state.groups, + pageInfo: store.state.pageInfo, + }, + }).$mount(); + + setTimeout(() => { + expect(component.$el.classList.contains('groups-list-tree-container')).toBe(true); + done(); + }); + }); + }); +}); diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js new file mode 100644 index 00000000000..14fe9ef71d0 --- /dev/null +++ b/spec/javascripts/groups/mock_data.js @@ -0,0 +1,40 @@ +export default { + groups: [{ + id: '12', + name: 'level1', + path: 'level1', + description: '', + visibility: 'public', + avatar_url: null, + web_url: 'http://localhost:3000/groups/level1', + full_name: 'level1', + full_path: 'level1', + parent_id: null, + created_at: '2017-05-15T19:01:23.670Z', + updated_at: '2017-05-15T19:01:23.670Z', + permissions: { + group_access: 50, + }, + }, + ], + pagination: { + Date: 'Mon, 22 May 2017 22:31:52 GMT', + 'X-Prev-Page': '1', + 'X-Content-Type-Options': 'nosniff', + 'X-Total': '31', + 'Transfer-Encoding': 'chunked', + 'X-Runtime': '0.611144', + 'X-Xss-Protection': '1; mode=block', + 'X-Request-Id': 'f5db8368-3ce5-4aa4-89d2-a125d9dead09', + 'X-Ua-Compatible': 'IE=edge', + 'X-Per-Page': '20', + Link: '; rel="prev", ; rel="first", ; rel="last"', + 'X-Next-Page': '', + Etag: 'W/"a82f846947136271cdb7d55d19ef33d2"', + 'X-Frame-Options': 'DENY', + 'Content-Type': 'application/json; charset=utf-8', + 'Cache-Control': 'max-age=0, private, must-revalidate', + 'X-Total-Pages': '2', + 'X-Page': '2', + }, +}; -- cgit v1.2.3 From 6d8963e33657b80821900a60f66d0a51416dc59a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 25 May 2017 15:35:09 +0200 Subject: Add PoC of ActiveRecord migration testing --- spec/migrations/migrate_pipeline_stages_spec.rb | 127 ++++++++++++++++++++++++ spec/migrations_helper.rb | 36 +++++++ 2 files changed, 163 insertions(+) create mode 100644 spec/migrations/migrate_pipeline_stages_spec.rb create mode 100644 spec/migrations_helper.rb (limited to 'spec') diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb new file mode 100644 index 00000000000..95c15d53a68 --- /dev/null +++ b/spec/migrations/migrate_pipeline_stages_spec.rb @@ -0,0 +1,127 @@ +require 'migrations_helper' +require Rails.root.join('db', 'migrate', '20170525132202_migrate_pipeline_stages.rb') + +describe MigratePipelineStages, :migration do + ## + # Create tables using schema from which we will migrate stuff. + # + before do + ActiveRecord::Schema.define(version: 20170523091700) do + enable_extension "plpgsql" + enable_extension "pg_trgm" + + create_table "ci_pipelines", force: :cascade do |t| + t.string "ref" + t.string "sha" + t.string "before_sha" + t.datetime "created_at" + t.datetime "updated_at" + t.boolean "tag", default: false + t.text "yaml_errors" + t.datetime "committed_at" + t.integer "project_id" + t.string "status" + t.datetime "started_at" + t.datetime "finished_at" + t.integer "duration" + t.integer "user_id" + t.integer "lock_version" + t.integer "auto_canceled_by_id" + t.integer "pipeline_schedule_id" + end + + add_index "ci_pipelines", ["auto_canceled_by_id"], name: "index_ci_pipelines_on_auto_canceled_by_id", using: :btree + add_index "ci_pipelines", ["pipeline_schedule_id"], name: "index_ci_pipelines_on_pipeline_schedule_id", using: :btree + add_index "ci_pipelines", ["project_id", "ref", "status"], name: "index_ci_pipelines_on_project_id_and_ref_and_status", using: :btree + add_index "ci_pipelines", ["project_id", "sha"], name: "index_ci_pipelines_on_project_id_and_sha", using: :btree + add_index "ci_pipelines", ["project_id"], name: "index_ci_pipelines_on_project_id", using: :btree + add_index "ci_pipelines", ["status"], name: "index_ci_pipelines_on_status", using: :btree + add_index "ci_pipelines", ["user_id"], name: "index_ci_pipelines_on_user_id", using: :btree + + create_table "ci_builds", force: :cascade do |t| + t.string "status" + t.datetime "finished_at" + t.text "trace" + t.datetime "created_at" + t.datetime "updated_at" + t.datetime "started_at" + t.integer "runner_id" + t.float "coverage" + t.integer "commit_id" + t.text "commands" + t.string "name" + t.text "options" + t.boolean "allow_failure", default: false, null: false + t.string "stage" + t.integer "trigger_request_id" + t.integer "stage_idx" + t.boolean "tag" + t.string "ref" + t.integer "user_id" + t.string "type" + t.string "target_url" + t.string "description" + t.text "artifacts_file" + t.integer "project_id" + t.text "artifacts_metadata" + t.integer "erased_by_id" + t.datetime "erased_at" + t.datetime "artifacts_expire_at" + t.string "environment" + t.integer "artifacts_size", limit: 8 + t.string "when" + t.text "yaml_variables" + t.datetime "queued_at" + t.string "token" + t.integer "lock_version" + t.string "coverage_regex" + t.integer "auto_canceled_by_id" + t.boolean "retried" + end + + add_index "ci_builds", ["auto_canceled_by_id"], name: "index_ci_builds_on_auto_canceled_by_id", using: :btree + add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree + add_index "ci_builds", ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree + add_index "ci_builds", ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree + add_index "ci_builds", ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree + add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree + add_index "ci_builds", ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree + add_index "ci_builds", ["status", "type", "runner_id"], name: "index_ci_builds_on_status_and_type_and_runner_id", using: :btree + add_index "ci_builds", ["status"], name: "index_ci_builds_on_status", using: :btree + add_index "ci_builds", ["token"], name: "index_ci_builds_on_token", unique: true, using: :btree + add_index "ci_builds", ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree + add_index "ci_builds", ["user_id"], name: "index_ci_builds_on_user_id", using: :btree + end + end + + let(:pipeline) do + Class.new(ActiveRecord::Base) do + self.table_name = 'ci_pipelines' + end + end + + let(:build) do + Class.new(ActiveRecord::Base) do + self.table_name = 'ci_builds' + end + end + + let(:stage) do + Class.new(ActiveRecord::Base) do + self.table_name = 'ci_stages' + end + end + + ## + # Create test data + # + before do + pipeline.create!(ref: 'master', sha: 'adf43c3a') + end + + it 'correctly migrates pipeline stages' do + described_class.new.change + + expect(stage.table_exists?).to be true + end +end diff --git a/spec/migrations_helper.rb b/spec/migrations_helper.rb new file mode 100644 index 00000000000..bbb810556da --- /dev/null +++ b/spec/migrations_helper.rb @@ -0,0 +1,36 @@ +require File.expand_path("../../config/environment", __FILE__) +require 'rspec/rails' +require 'shoulda/matchers' + +ActiveRecord::Base.establish_connection(:migrate) + +RSpec.configure do |config| + config.mock_with :rspec + config.verbose_retry = true + config.display_try_failure_messages = true + config.use_transactional_fixtures = true + config.infer_spec_type_from_file_location! + config.raise_errors_for_deprecations! + + config.around(:each, :migration) do |example| + ActiveRecord::Tasks::DatabaseTasks.purge_current + + example.run + + ActiveRecord::Tasks::DatabaseTasks.purge_current + end + + config.around(:each, :redis) do |example| + Gitlab::Redis.with(&:flushall) + Sidekiq.redis(&:flushall) + + example.run + + Gitlab::Redis.with(&:flushall) + Sidekiq.redis(&:flushall) + end +end + + +puts "Rails environment: #{Rails.env}" +puts "Database connection: #{ActiveRecord::Base.connection_config[:database]}" -- cgit v1.2.3 From acc22a8422cd1471819510aa375c455b5ea009c5 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 25 May 2017 22:43:16 +0200 Subject: Simplify migrations for specific database schema --- spec/migrations/migrate_pipeline_stages_spec.rb | 122 ++---------------------- spec/migrations_helper.rb | 36 ------- spec/spec_helper.rb | 10 ++ 3 files changed, 19 insertions(+), 149 deletions(-) delete mode 100644 spec/migrations_helper.rb (limited to 'spec') diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb index 95c15d53a68..038e5d7fc6b 100644 --- a/spec/migrations/migrate_pipeline_stages_spec.rb +++ b/spec/migrations/migrate_pipeline_stages_spec.rb @@ -1,127 +1,23 @@ -require 'migrations_helper' +require 'spec_helper' require Rails.root.join('db', 'migrate', '20170525132202_migrate_pipeline_stages.rb') -describe MigratePipelineStages, :migration do - ## - # Create tables using schema from which we will migrate stuff. - # - before do - ActiveRecord::Schema.define(version: 20170523091700) do - enable_extension "plpgsql" - enable_extension "pg_trgm" - - create_table "ci_pipelines", force: :cascade do |t| - t.string "ref" - t.string "sha" - t.string "before_sha" - t.datetime "created_at" - t.datetime "updated_at" - t.boolean "tag", default: false - t.text "yaml_errors" - t.datetime "committed_at" - t.integer "project_id" - t.string "status" - t.datetime "started_at" - t.datetime "finished_at" - t.integer "duration" - t.integer "user_id" - t.integer "lock_version" - t.integer "auto_canceled_by_id" - t.integer "pipeline_schedule_id" - end - - add_index "ci_pipelines", ["auto_canceled_by_id"], name: "index_ci_pipelines_on_auto_canceled_by_id", using: :btree - add_index "ci_pipelines", ["pipeline_schedule_id"], name: "index_ci_pipelines_on_pipeline_schedule_id", using: :btree - add_index "ci_pipelines", ["project_id", "ref", "status"], name: "index_ci_pipelines_on_project_id_and_ref_and_status", using: :btree - add_index "ci_pipelines", ["project_id", "sha"], name: "index_ci_pipelines_on_project_id_and_sha", using: :btree - add_index "ci_pipelines", ["project_id"], name: "index_ci_pipelines_on_project_id", using: :btree - add_index "ci_pipelines", ["status"], name: "index_ci_pipelines_on_status", using: :btree - add_index "ci_pipelines", ["user_id"], name: "index_ci_pipelines_on_user_id", using: :btree - - create_table "ci_builds", force: :cascade do |t| - t.string "status" - t.datetime "finished_at" - t.text "trace" - t.datetime "created_at" - t.datetime "updated_at" - t.datetime "started_at" - t.integer "runner_id" - t.float "coverage" - t.integer "commit_id" - t.text "commands" - t.string "name" - t.text "options" - t.boolean "allow_failure", default: false, null: false - t.string "stage" - t.integer "trigger_request_id" - t.integer "stage_idx" - t.boolean "tag" - t.string "ref" - t.integer "user_id" - t.string "type" - t.string "target_url" - t.string "description" - t.text "artifacts_file" - t.integer "project_id" - t.text "artifacts_metadata" - t.integer "erased_by_id" - t.datetime "erased_at" - t.datetime "artifacts_expire_at" - t.string "environment" - t.integer "artifacts_size", limit: 8 - t.string "when" - t.text "yaml_variables" - t.datetime "queued_at" - t.string "token" - t.integer "lock_version" - t.string "coverage_regex" - t.integer "auto_canceled_by_id" - t.boolean "retried" - end - - add_index "ci_builds", ["auto_canceled_by_id"], name: "index_ci_builds_on_auto_canceled_by_id", using: :btree - add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree - add_index "ci_builds", ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree - add_index "ci_builds", ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree - add_index "ci_builds", ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree - add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree - add_index "ci_builds", ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree - add_index "ci_builds", ["status", "type", "runner_id"], name: "index_ci_builds_on_status_and_type_and_runner_id", using: :btree - add_index "ci_builds", ["status"], name: "index_ci_builds_on_status", using: :btree - add_index "ci_builds", ["token"], name: "index_ci_builds_on_token", unique: true, using: :btree - add_index "ci_builds", ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree - add_index "ci_builds", ["user_id"], name: "index_ci_builds_on_user_id", using: :btree - end - end - - let(:pipeline) do - Class.new(ActiveRecord::Base) do - self.table_name = 'ci_pipelines' - end - end - - let(:build) do - Class.new(ActiveRecord::Base) do - self.table_name = 'ci_builds' - end - end - - let(:stage) do - Class.new(ActiveRecord::Base) do - self.table_name = 'ci_stages' - end +describe MigratePipelineStages, :migration, schema: 20170523091700 do + def table(name) + Class.new(ActiveRecord::Base) { self.table_name = name } end ## # Create test data # before do - pipeline.create!(ref: 'master', sha: 'adf43c3a') + table(:ci_pipelines).create!(ref: 'master', sha: 'adf43c3a') end it 'correctly migrates pipeline stages' do - described_class.new.change + expect(ActiveRecord::Base.connection.table_exists?('ci_stages')).to eq false + + described_class.new.migrate(:up) - expect(stage.table_exists?).to be true + expect(ActiveRecord::Base.connection.table_exists?('ci_stages')).to eq true end end diff --git a/spec/migrations_helper.rb b/spec/migrations_helper.rb deleted file mode 100644 index bbb810556da..00000000000 --- a/spec/migrations_helper.rb +++ /dev/null @@ -1,36 +0,0 @@ -require File.expand_path("../../config/environment", __FILE__) -require 'rspec/rails' -require 'shoulda/matchers' - -ActiveRecord::Base.establish_connection(:migrate) - -RSpec.configure do |config| - config.mock_with :rspec - config.verbose_retry = true - config.display_try_failure_messages = true - config.use_transactional_fixtures = true - config.infer_spec_type_from_file_location! - config.raise_errors_for_deprecations! - - config.around(:each, :migration) do |example| - ActiveRecord::Tasks::DatabaseTasks.purge_current - - example.run - - ActiveRecord::Tasks::DatabaseTasks.purge_current - end - - config.around(:each, :redis) do |example| - Gitlab::Redis.with(&:flushall) - Sidekiq.redis(&:flushall) - - example.run - - Gitlab::Redis.with(&:flushall) - Sidekiq.redis(&:flushall) - end -end - - -puts "Rails environment: #{Rails.env}" -puts "Database connection: #{ActiveRecord::Base.connection_config[:database]}" diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 51571ddebe9..992c0c29c72 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -92,6 +92,16 @@ RSpec.configure do |config| Gitlab::Redis.with(&:flushall) Sidekiq.redis(&:flushall) end + + config.around(:example, migration: true) do |example| + schema_version = example.metadata[:schema] + migrations_paths = ActiveRecord::Migrator.migrations_paths + ActiveRecord::Migrator.migrate(migrations_paths, schema_version) + + example.run + + ActiveRecord::Migration.maintain_test_schema! + end end FactoryGirl::SyntaxRunner.class_eval do -- cgit v1.2.3 From b3666a7829951b028eab5b56e9b914bcb8cda835 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 25 May 2017 19:49:46 -0500 Subject: Add tests for Group item component Also adds more tests fro groups folder component [ci skip] --- spec/javascripts/groups/group_item_spec.js | 39 +++++++++++++ spec/javascripts/groups/groups_spec.js | 62 +++++++++++++------- spec/javascripts/groups/mock_data.js | 94 ++++++++++++++++++++++++------ 3 files changed, 157 insertions(+), 38 deletions(-) create mode 100644 spec/javascripts/groups/group_item_spec.js (limited to 'spec') diff --git a/spec/javascripts/groups/group_item_spec.js b/spec/javascripts/groups/group_item_spec.js new file mode 100644 index 00000000000..08e22728aba --- /dev/null +++ b/spec/javascripts/groups/group_item_spec.js @@ -0,0 +1,39 @@ +import Vue from 'vue'; +import groupItemComponent from '~/groups/components/group_item.vue'; +import GroupsStore from '~/groups/stores/groups_store'; +import { group1 } from './mock_data'; + +describe('Groups Component', () => { + let GroupItemComponent; + let component; + let group; + + beforeEach((done) => { + GroupItemComponent = Vue.extend(groupItemComponent); + group = GroupsStore.decorateGroup(group1); + + component = new GroupItemComponent({ + propsData: { + group, + }, + }).$mount(); + + Vue.nextTick(() => { + done(); + }); + }); + + it('should render the group item', () => { + expect(component.$el.classList.contains('group-row')).toBe(true); + expect(component.$el.querySelector('.number-projects').textContent).toContain(group.numberProjects); + expect(component.$el.querySelector('.number-members').textContent).toContain(group.numberMembers); + expect(component.$el.querySelector('.group-visibility')).toBeDefined(); + expect(component.$el.querySelector('.avatar-container')).toBeDefined(); + expect(component.$el.querySelector('.title').textContent).toContain(group.name); + expect(component.$el.querySelector('.description').textContent).toContain(group.description); + expect(component.$el.querySelector('.edit-group')).toBeDefined(); + expect(component.$el.querySelector('.leave-group')).toBeDefined(); + }); + + // TODO: check for no description class when group has no description +}); diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js index 1427095f21a..47ca90551c7 100644 --- a/spec/javascripts/groups/groups_spec.js +++ b/spec/javascripts/groups/groups_spec.js @@ -1,38 +1,60 @@ import Vue from 'vue'; -import GroupFolder from '~/groups/components/group_folder.vue'; -import GroupItem from '~/groups/components/group_item.vue'; +import groupFolderComponent from '~/groups/components/group_folder.vue'; +import groupItemComponent from '~/groups/components/group_item.vue'; import groupsComponent from '~/groups/components/groups.vue'; import GroupsStore from '~/groups/stores/groups_store'; -import groupsData from './mock_data'; +import { groupsData } from './mock_data'; -describe('Groups', () => { +describe('Groups Component', () => { let GroupsComponent; let store; + let component; + let groups; - beforeEach(() => { - Vue.component('group-folder', GroupFolder); - Vue.component('group-item', GroupItem); + beforeEach((done) => { + Vue.component('group-folder', groupFolderComponent); + Vue.component('group-item', groupItemComponent); store = new GroupsStore(); - store.setGroups(groupsData.groups); + groups = store.setGroups(groupsData.groups); + store.storePagination(groupsData.pagination); GroupsComponent = Vue.extend(groupsComponent); + + component = new GroupsComponent({ + propsData: { + groups: store.state.groups, + pageInfo: store.state.pageInfo, + }, + }).$mount(); + + Vue.nextTick(() => { + done(); + }); }); describe('with data', () => { - it('should render a list of groups', (done) => { - const component = new GroupsComponent({ - propsData: { - groups: store.state.groups, - pageInfo: store.state.pageInfo, - }, - }).$mount(); - - setTimeout(() => { - expect(component.$el.classList.contains('groups-list-tree-container')).toBe(true); - done(); - }); + it('should render a list of groups', () => { + expect(component.$el.classList.contains('groups-list-tree-container')).toBe(true); + expect(component.$el.querySelector('#group-12')).toBeDefined(); + expect(component.$el.querySelector('#group-1119')).toBeDefined(); + expect(component.$el.querySelector('#group-1120')).toBeDefined(); + }); + + it('should render group and its subgroup', () => { + const lists = component.$el.querySelectorAll('.group-list-tree'); + + expect(lists.length).toBe(3); // one parent and two subgroups + + expect(lists[0].querySelector('#group-1119').classList.contains('is-open')).toBe(true); + expect(lists[0].querySelector('#group-1119').classList.contains('is-expandable')).toBe(true); + + expect(lists[2].querySelector('#group-1120').textContent).toContain(groups[1119].subGroups[1120].name); + }); + + it('should remove prefix of parent group', () => { + expect(component.$el.querySelector('#group-12 #group-1128 .title').textContent).toContain('level2 / level3 / level4'); }); }); }); diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js index 14fe9ef71d0..7d6910137fe 100644 --- a/spec/javascripts/groups/mock_data.js +++ b/spec/javascripts/groups/mock_data.js @@ -1,22 +1,78 @@ -export default { - groups: [{ - id: '12', - name: 'level1', - path: 'level1', - description: '', - visibility: 'public', - avatar_url: null, - web_url: 'http://localhost:3000/groups/level1', - full_name: 'level1', - full_path: 'level1', - parent_id: null, - created_at: '2017-05-15T19:01:23.670Z', - updated_at: '2017-05-15T19:01:23.670Z', - permissions: { - group_access: 50, - }, +const group1 = { + id: '12', + name: 'level1', + path: 'level1', + description: '', + visibility: 'public', + avatar_url: null, + web_url: 'http://localhost:3000/groups/level1', + full_name: 'level1', + full_path: 'level1', + parent_id: null, + created_at: '2017-05-15T19:01:23.670Z', + updated_at: '2017-05-15T19:01:23.670Z', + permissions: { + group_access: 50, }, - ], +}; + +// This group has no direct parent, should be placed as subgroup of group1 +const group14 = { + id: 1128, + name: 'level4', + path: 'level4', + description: '', + visibility: 'public', + avatar_url: null, + web_url: 'http://localhost:3000/groups/level1/level2/level3/level4', + full_name: 'level1 / level2 / level3 / level4', + full_path: 'level1/level2/level3/level4', + parent_id: 1127, + created_at: '2017-05-15T19:02:01.645Z', + updated_at: '2017-05-15T19:02:01.645Z', + permissions: { + group_access: 30, + }, +}; + +const group2 = { + id: 1119, + name: 'devops', + path: 'devops', + description: '', + visibility: 'public', + avatar_url: null, + web_url: 'http://localhost:3000/groups/devops', + full_name: 'devops', + full_path: 'devops', + parent_id: null, + created_at: '2017-05-11T19:35:09.635Z', + updated_at: '2017-05-11T19:35:09.635Z', + permissions: { + group_access: 50, + }, +}; + +const group21 = { + id: 1120, + name: 'chef', + path: 'chef', + description: '', + visibility: 'public', + avatar_url: null, + web_url: 'http://localhost:3000/groups/devops/chef', + full_name: 'devops / chef', + full_path: 'devops/chef', + parent_id: 1119, + created_at: '2017-05-11T19:51:04.060Z', + updated_at: '2017-05-11T19:51:04.060Z', + permissions: { + group_access: 50, + }, +}; + +const groupsData = { + groups: [group1, group14, group2, group21], pagination: { Date: 'Mon, 22 May 2017 22:31:52 GMT', 'X-Prev-Page': '1', @@ -38,3 +94,5 @@ export default { 'X-Page': '2', }, }; + +export { groupsData, group1 }; -- cgit v1.2.3 From f7aba153164618522232c912eb833bd7596f5f53 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 26 May 2017 10:29:12 +0200 Subject: Make migration specs by using migrator in around hook --- spec/migrations/migrate_pipeline_stages_spec.rb | 17 +++++++++++++++-- spec/spec_helper.rb | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb index 038e5d7fc6b..d6d26ab52ad 100644 --- a/spec/migrations/migrate_pipeline_stages_spec.rb +++ b/spec/migrations/migrate_pipeline_stages_spec.rb @@ -2,10 +2,23 @@ require 'spec_helper' require Rails.root.join('db', 'migrate', '20170525132202_migrate_pipeline_stages.rb') describe MigratePipelineStages, :migration, schema: 20170523091700 do + ## + # TODO, extract to migrations helper + # def table(name) Class.new(ActiveRecord::Base) { self.table_name = name } end + def migrations_paths + ActiveRecord::Migrator.migrations_paths + end + + def migrate! + ActiveRecord::Migrator.up(migrations_paths) do |migration| + migration.name == described_class.name + end + end + ## # Create test data # @@ -13,10 +26,10 @@ describe MigratePipelineStages, :migration, schema: 20170523091700 do table(:ci_pipelines).create!(ref: 'master', sha: 'adf43c3a') end - it 'correctly migrates pipeline stages' do + it 'correctly migrates pipeline stages' do |migration, meta| expect(ActiveRecord::Base.connection.table_exists?('ci_stages')).to eq false - described_class.new.migrate(:up) + migrate! expect(ActiveRecord::Base.connection.table_exists?('ci_stages')).to eq true end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 992c0c29c72..9ed705a5267 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -100,7 +100,7 @@ RSpec.configure do |config| example.run - ActiveRecord::Migration.maintain_test_schema! + ActiveRecord::Migrator.migrate(migrations_paths) end end -- cgit v1.2.3 From 0f9fbae78a51f7bf4df50d96060087e1cf903b05 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 26 May 2017 10:36:01 +0200 Subject: Add migrations helpers to simplify writing migration specs --- spec/migrations/migrate_pipeline_stages_spec.rb | 17 ----------------- spec/spec_helper.rb | 6 +++--- spec/support/migrations_helpers.rb | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 20 deletions(-) create mode 100644 spec/support/migrations_helpers.rb (limited to 'spec') diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb index d6d26ab52ad..4a469174b9e 100644 --- a/spec/migrations/migrate_pipeline_stages_spec.rb +++ b/spec/migrations/migrate_pipeline_stages_spec.rb @@ -2,23 +2,6 @@ require 'spec_helper' require Rails.root.join('db', 'migrate', '20170525132202_migrate_pipeline_stages.rb') describe MigratePipelineStages, :migration, schema: 20170523091700 do - ## - # TODO, extract to migrations helper - # - def table(name) - Class.new(ActiveRecord::Base) { self.table_name = name } - end - - def migrations_paths - ActiveRecord::Migrator.migrations_paths - end - - def migrate! - ActiveRecord::Migrator.up(migrations_paths) do |migration| - migration.name == described_class.name - end - end - ## # Create test data # diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9ed705a5267..2c1c252be37 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -52,6 +52,7 @@ RSpec.configure do |config| config.include StubGitlabCalls config.include StubGitlabData config.include ApiHelpers, :api + config.include MigrationsHelpers, :migration config.infer_spec_type_from_file_location! @@ -94,9 +95,8 @@ RSpec.configure do |config| end config.around(:example, migration: true) do |example| - schema_version = example.metadata[:schema] - migrations_paths = ActiveRecord::Migrator.migrations_paths - ActiveRecord::Migrator.migrate(migrations_paths, schema_version) + ActiveRecord::Migrator + .migrate(migrations_paths, example.metadata.fetch(:schema)) example.run diff --git a/spec/support/migrations_helpers.rb b/spec/support/migrations_helpers.rb new file mode 100644 index 00000000000..965b00b5731 --- /dev/null +++ b/spec/support/migrations_helpers.rb @@ -0,0 +1,15 @@ +module MigrationsHelpers + def table(name) + Class.new(ActiveRecord::Base) { self.table_name = name } + end + + def migrations_paths + ActiveRecord::Migrator.migrations_paths + end + + def migrate! + ActiveRecord::Migrator.up(migrations_paths) do |migration| + migration.name == described_class.name + end + end +end -- cgit v1.2.3 From 918ababba6fce694c61d54bb2ff6983a886f696a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 26 May 2017 14:46:45 +0200 Subject: Add pipeline stages post deployment migration --- spec/migrations/migrate_pipeline_stages_spec.rb | 44 +++++++++++++++++++++---- spec/spec_helper.rb | 4 +-- spec/support/db_cleaner.rb | 4 +++ spec/support/migrations_helpers.rb | 4 +++ 4 files changed, 47 insertions(+), 9 deletions(-) (limited to 'spec') diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb index 4a469174b9e..9cf13a1dabc 100644 --- a/spec/migrations/migrate_pipeline_stages_spec.rb +++ b/spec/migrations/migrate_pipeline_stages_spec.rb @@ -1,19 +1,49 @@ require 'spec_helper' -require Rails.root.join('db', 'migrate', '20170525132202_migrate_pipeline_stages.rb') +require Rails.root.join('db', 'post_migrate', '20170526101042_migrate_pipeline_stages.rb') -describe MigratePipelineStages, :migration, schema: 20170523091700 do +describe MigratePipelineStages, :migration, schema: 20170525132202 do ## - # Create test data + # Create test data - pipeline and CI/CD jobs. # + + let(:jobs) { table(:ci_builds) } + let(:stages) { table(:ci_stages) } + let(:pipelines) { table(:ci_pipelines) } + before do - table(:ci_pipelines).create!(ref: 'master', sha: 'adf43c3a') + # Create CI/CD pipelines + # + pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a') + pipelines.create!(id: 2, project_id: 456, ref: 'feature', sha: '21a3deb') + + # Create CI/CD jobs + # + jobs.create!(id: 1, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build') + jobs.create!(id: 2, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build') + jobs.create!(id: 3, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test') + jobs.create!(id: 4, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test') + jobs.create!(id: 5, commit_id: 1, project_id: 123, stage_idx: 3, stage: 'deploy') + jobs.create!(id: 6, commit_id: 2, project_id: 456, stage_idx: 3, stage: 'deploy') + jobs.create!(id: 7, commit_id: 2, project_id: 456, stage_idx: 2, stage: 'test:2') + jobs.create!(id: 8, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1') + jobs.create!(id: 9, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1') + jobs.create!(id: 10, commit_id: 2, project_id: 456, stage_idx: 2, stage: 'test:2') + jobs.create!(id: 11, commit_id: 3, project_id: 789, stage_idx: 3, stage: 'deploy') end - it 'correctly migrates pipeline stages' do |migration, meta| - expect(ActiveRecord::Base.connection.table_exists?('ci_stages')).to eq false + it 'correctly migrates pipeline stages' do + expect(stages.count).to be_zero migrate! - expect(ActiveRecord::Base.connection.table_exists?('ci_stages')).to eq true + expect(stages.count).to eq 7 + expect(stages.all.pluck(:name)) + .to match_array %w[test build deploy test:1 test:2 deploy deploy] + expect(stages.where(pipeline_id: 1).order(:id).pluck(:name)) + .to eq %w[test build deploy] + expect(stages.where(pipeline_id: 2).order(:id).pluck(:name)) + .to eq %w[test:1 test:2 deploy] + + expect(jobs.where(stage_id: nil)).to be_empty end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2c1c252be37..b4ece5c60c1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -95,8 +95,8 @@ RSpec.configure do |config| end config.around(:example, migration: true) do |example| - ActiveRecord::Migrator - .migrate(migrations_paths, example.metadata.fetch(:schema)) + schema_version = example.metadata.fetch(:schema) + ActiveRecord::Migrator.migrate(migrations_paths, schema_version) example.run diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb index 6f31828b825..7f5769209bb 100644 --- a/spec/support/db_cleaner.rb +++ b/spec/support/db_cleaner.rb @@ -19,6 +19,10 @@ RSpec.configure do |config| DatabaseCleaner.strategy = :truncation end + config.before(:each, :migration) do + DatabaseCleaner.strategy = :truncation + end + config.before(:each) do DatabaseCleaner.start end diff --git a/spec/support/migrations_helpers.rb b/spec/support/migrations_helpers.rb index 965b00b5731..ee17d1a40b7 100644 --- a/spec/support/migrations_helpers.rb +++ b/spec/support/migrations_helpers.rb @@ -7,6 +7,10 @@ module MigrationsHelpers ActiveRecord::Migrator.migrations_paths end + def table_exists?(name) + ActiveRecord::Base.connection.table_exists?(name) + end + def migrate! ActiveRecord::Migrator.up(migrations_paths) do |migration| migration.name == described_class.name -- cgit v1.2.3 From 33a0fd995bc00bc894243b0d7b2fda0367ae8b4c Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 26 May 2017 21:39:32 +0200 Subject: Migrate build stage reference in a separate migration --- .../migrate_build_stage_reference_spec.rb | 56 ++++++++++++++++++++++ spec/migrations/migrate_pipeline_stages_spec.rb | 2 - 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 spec/migrations/migrate_build_stage_reference_spec.rb (limited to 'spec') diff --git a/spec/migrations/migrate_build_stage_reference_spec.rb b/spec/migrations/migrate_build_stage_reference_spec.rb new file mode 100644 index 00000000000..979f13a1398 --- /dev/null +++ b/spec/migrations/migrate_build_stage_reference_spec.rb @@ -0,0 +1,56 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170526185921_migrate_build_stage_reference.rb') + +describe MigrateBuildStageReference, :migration, schema: 20170526185602 do + ## + # Create test data - pipeline and CI/CD jobs. + # + + let(:jobs) { table(:ci_builds) } + let(:stages) { table(:ci_stages) } + let(:pipelines) { table(:ci_pipelines) } + + before do + # Create CI/CD pipelines + # + pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a') + pipelines.create!(id: 2, project_id: 456, ref: 'feature', sha: '21a3deb') + + # Create CI/CD jobs + # + jobs.create!(id: 1, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build') + jobs.create!(id: 2, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build') + jobs.create!(id: 3, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test') + jobs.create!(id: 4, commit_id: 1, project_id: 123, stage_idx: 3, stage: 'deploy') + jobs.create!(id: 5, commit_id: 2, project_id: 456, stage_idx: 2, stage: 'test:2') + jobs.create!(id: 6, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1') + jobs.create!(id: 7, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1') + jobs.create!(id: 8, commit_id: 3, project_id: 789, stage_idx: 3, stage: 'deploy') + + # Create CI/CD stages + # + stages.create(id: 101, pipeline_id: 1, project_id: 123, name: 'test') + stages.create(id: 102, pipeline_id: 1, project_id: 123, name: 'build') + stages.create(id: 103, pipeline_id: 1, project_id: 123, name: 'deploy') + stages.create(id: 104, pipeline_id: 2, project_id: 456, name: 'test:1') + stages.create(id: 105, pipeline_id: 2, project_id: 456, name: 'test:2') + stages.create(id: 106, pipeline_id: 2, project_id: 456, name: 'deploy') + end + + it 'correctly migrate build stage references' do + expect(jobs.where(stage_id: nil).count).to eq 8 + + migrate! + + expect(jobs.where(stage_id: nil).count).to eq 1 + + expect(jobs.find(1).stage_id).to eq 102 + expect(jobs.find(2).stage_id).to eq 102 + expect(jobs.find(3).stage_id).to eq 101 + expect(jobs.find(4).stage_id).to eq 103 + expect(jobs.find(5).stage_id).to eq 105 + expect(jobs.find(6).stage_id).to eq 104 + expect(jobs.find(7).stage_id).to eq 104 + expect(jobs.find(8).stage_id).to eq nil + end +end diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb index 9cf13a1dabc..6887fcd26c3 100644 --- a/spec/migrations/migrate_pipeline_stages_spec.rb +++ b/spec/migrations/migrate_pipeline_stages_spec.rb @@ -43,7 +43,5 @@ describe MigratePipelineStages, :migration, schema: 20170525132202 do .to eq %w[test build deploy] expect(stages.where(pipeline_id: 2).order(:id).pluck(:name)) .to eq %w[test:1 test:2 deploy] - - expect(jobs.where(stage_id: nil)).to be_empty end end -- cgit v1.2.3 From ff61e2b776badef7cd614e697a7eac20c63534eb Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 26 May 2017 22:33:50 +0200 Subject: Reorder pipeline stages-related migrations --- spec/migrations/migrate_pipeline_stages_spec.rb | 4 ++-- spec/spec_helper.rb | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb index 6887fcd26c3..c9b38086deb 100644 --- a/spec/migrations/migrate_pipeline_stages_spec.rb +++ b/spec/migrations/migrate_pipeline_stages_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -require Rails.root.join('db', 'post_migrate', '20170526101042_migrate_pipeline_stages.rb') +require Rails.root.join('db', 'post_migrate', '20170526185842_migrate_pipeline_stages.rb') -describe MigratePipelineStages, :migration, schema: 20170525132202 do +describe MigratePipelineStages, :migration, schema: 20170526185602 do ## # Create test data - pipeline and CI/CD jobs. # diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b4ece5c60c1..6a0e29f2edb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -95,12 +95,14 @@ RSpec.configure do |config| end config.around(:example, migration: true) do |example| - schema_version = example.metadata.fetch(:schema) - ActiveRecord::Migrator.migrate(migrations_paths, schema_version) + begin + schema_version = example.metadata.fetch(:schema) + ActiveRecord::Migrator.migrate(migrations_paths, schema_version) - example.run - - ActiveRecord::Migrator.migrate(migrations_paths) + example.run + ensure + ActiveRecord::Migrator.migrate(migrations_paths) + end end end -- cgit v1.2.3 From 41203686c3964774bae878be91dc92fa86d8b725 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Tue, 30 May 2017 04:26:46 -0500 Subject: Fix tests and eslint errors [ci skip] --- spec/javascripts/groups/group_item_spec.js | 2 +- spec/javascripts/groups/groups_spec.js | 2 +- spec/javascripts/groups/mock_data.js | 12 ++++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/groups/group_item_spec.js b/spec/javascripts/groups/group_item_spec.js index 08e22728aba..ed441242085 100644 --- a/spec/javascripts/groups/group_item_spec.js +++ b/spec/javascripts/groups/group_item_spec.js @@ -26,7 +26,7 @@ describe('Groups Component', () => { it('should render the group item', () => { expect(component.$el.classList.contains('group-row')).toBe(true); expect(component.$el.querySelector('.number-projects').textContent).toContain(group.numberProjects); - expect(component.$el.querySelector('.number-members').textContent).toContain(group.numberMembers); + expect(component.$el.querySelector('.number-users').textContent).toContain(group.numberUsers); expect(component.$el.querySelector('.group-visibility')).toBeDefined(); expect(component.$el.querySelector('.avatar-container')).toBeDefined(); expect(component.$el.querySelector('.title').textContent).toContain(group.name); diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js index 47ca90551c7..d1f900df3d8 100644 --- a/spec/javascripts/groups/groups_spec.js +++ b/spec/javascripts/groups/groups_spec.js @@ -48,7 +48,7 @@ describe('Groups Component', () => { expect(lists.length).toBe(3); // one parent and two subgroups expect(lists[0].querySelector('#group-1119').classList.contains('is-open')).toBe(true); - expect(lists[0].querySelector('#group-1119').classList.contains('is-expandable')).toBe(true); + expect(lists[0].querySelector('#group-1119').classList.contains('has-subgroups')).toBe(true); expect(lists[2].querySelector('#group-1120').textContent).toContain(groups[1119].subGroups[1120].name); }); diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js index 7d6910137fe..fdb809018cf 100644 --- a/spec/javascripts/groups/mock_data.js +++ b/spec/javascripts/groups/mock_data.js @@ -11,6 +11,9 @@ const group1 = { parent_id: null, created_at: '2017-05-15T19:01:23.670Z', updated_at: '2017-05-15T19:01:23.670Z', + number_projects: '1', + number_users: '1', + has_subgroups: true, permissions: { group_access: 50, }, @@ -30,6 +33,9 @@ const group14 = { parent_id: 1127, created_at: '2017-05-15T19:02:01.645Z', updated_at: '2017-05-15T19:02:01.645Z', + number_projects: '1', + number_users: '1', + has_subgroups: true, permissions: { group_access: 30, }, @@ -48,6 +54,9 @@ const group2 = { parent_id: null, created_at: '2017-05-11T19:35:09.635Z', updated_at: '2017-05-11T19:35:09.635Z', + number_projects: '1', + number_users: '1', + has_subgroups: true, permissions: { group_access: 50, }, @@ -66,6 +75,9 @@ const group21 = { parent_id: 1119, created_at: '2017-05-11T19:51:04.060Z', updated_at: '2017-05-11T19:51:04.060Z', + number_projects: '1', + number_users: '1', + has_subgroups: true, permissions: { group_access: 50, }, -- cgit v1.2.3 From 1f1f5707244bcf4e69ef0fbe01f93e59386d5087 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 30 May 2017 12:48:05 +0200 Subject: Implement CI/CD config attributes for persisted stages --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 41 +++++++++++++++++++++++- spec/services/ci/create_pipeline_service_spec.rb | 2 +- 2 files changed, 41 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index fe2c00bb2ca..f98da1916b4 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -1,7 +1,8 @@ require 'spec_helper' module Ci - describe GitlabCiYamlProcessor, lib: true do + describe GitlabCiYamlProcessor, :lib do + subject { described_class.new(config, path) } let(:path) { 'path' } describe 'our current .gitlab-ci.yml' do @@ -82,6 +83,44 @@ module Ci end end + describe '#stages_for_ref' do + context 'when no refs policy is specified' do + let(:config) do + YAML.dump(production: { stage: 'deploy', script: 'cap prod' }, + rspec: { stage: 'test', script: 'rspec' }, + spinach: { stage: 'test', script: 'spinach' }) + end + + it 'returns model attributes for stages with nested jobs' do + attributes = subject.stages_for_ref('master') + + expect(attributes.size).to eq 2 + expect(attributes.dig(0, :name)).to eq 'test' + expect(attributes.dig(1, :name)).to eq 'deploy' + expect(attributes.dig(0, :builds_attributes, 0, :name)).to eq 'rspec' + expect(attributes.dig(0, :builds_attributes, 1, :name)).to eq 'spinach' + expect(attributes.dig(1, :builds_attributes, 0, :name)).to eq 'production' + end + end + + context 'when refs policy is specified' do + let(:config) do + YAML.dump(production: { stage: 'deploy', script: 'cap prod', only: ['master'] }, + spinach: { stage: 'test', script: 'spinach', only: ['tags'] }) + end + + it 'returns stage attributes except of jobs assigned to master' do + # true flag argument means matching jobs for tags + # + attributes = subject.stages_for_ref('feature', true) + + expect(attributes.size).to eq 1 + expect(attributes.dig(0, :name)).to eq 'test' + expect(attributes.dig(0, :builds_attributes, 0, :name)).to eq 'spinach' + end + end + end + describe "#builds_for_ref" do let(:type) { 'test' } diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index b536103ed65..674de2d80c1 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::CreatePipelineService, services: true do +describe Ci::CreatePipelineService, :services do let(:project) { create(:project, :repository) } let(:user) { create(:admin) } -- cgit v1.2.3 From 6113ff992c9a494ea8c657f20fa92f7f7f2365c4 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 30 May 2017 13:27:46 +0200 Subject: Expose stage model attributes from pipeline object --- spec/models/ci/pipeline_spec.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'spec') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 56b24ce62f3..c4f07c4a693 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -502,6 +502,20 @@ describe Ci::Pipeline, models: true do end end + describe '#has_stages?' do + context 'when pipeline has stages' do + subject { create(:ci_pipeline_with_one_job) } + + it { is_expected.to have_stages } + end + + context 'when pipeline does not have stages' do + subject { create(:ci_pipeline_without_jobs) } + + it { is_expected.not_to have_stages } + end + end + describe '#has_warnings?' do subject { pipeline.has_warnings? } -- cgit v1.2.3 From 805715cc68aabb6992a63356ec7c19940f52c93a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 30 May 2017 15:30:45 +0200 Subject: Add stage seed class that represents attributes --- spec/lib/gitlab/ci/stage/seed_spec.rb | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 spec/lib/gitlab/ci/stage/seed_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb new file mode 100644 index 00000000000..a12093b2c7c --- /dev/null +++ b/spec/lib/gitlab/ci/stage/seed_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Gitlab::Ci::Stage::Seed do + subject do + described_class.new(name: 'test', builds: builds) + end + + let(:builds) do + [{ name: 'rspec' }, { name: 'spinach' }] + end + + describe '#pipeline=' do + let(:pipeline) do + create(:ci_empty_pipeline, ref: 'feature', tag: true) + end + + it 'assignes relevant pipeline attributes' do + trigger_request = pipeline.trigger_requests.first + + subject.pipeline = pipeline + + expect(subject.builds).to all(include(pipeline: pipeline)) + expect(subject.builds).to all(include(project: pipeline.project)) + expect(subject.builds).to all(include(ref: 'feature')) + expect(subject.builds).to all(include(tag: true)) + expect(subject.builds).to all(include(trigger_request: trigger_request)) + end + end + + describe '#user=' do + let(:user) { create(:user) } + + it 'assignes relevant pipeline attributes' do + subject.user = user + + expect(subject.builds).to all(include(user: user)) + end + end + + describe '#to_attributes' do + it 'exposes stage attributes with nested jobs' do + expect(subject.to_attributes).to be_a Hash + expect(subject.to_attributes).to include(name: 'test') + expect(subject.to_attributes).to include(builds_attributes: builds) + end + end +end -- cgit v1.2.3 From 4464c22d6d23d893494682d309aec3fb31c11ae3 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Wed, 3 May 2017 17:26:49 +0200 Subject: Support descriptions for snippets --- .../projects/snippets_controller_spec.rb | 12 ++- spec/controllers/snippets_controller_spec.rb | 40 +++++++++- spec/factories/snippets.rb | 1 + .../projects/snippets/create_snippet_spec.rb | 86 ++++++++++++++++++++++ spec/features/snippets/create_snippet_spec.rb | 51 ++++++++++++- spec/features/snippets/edit_snippet_spec.rb | 38 ++++++++++ .../gitlab/import_export/safe_model_attributes.yml | 1 + spec/requests/api/project_snippets_spec.rb | 28 ++++++- spec/requests/api/snippets_spec.rb | 27 ++++++- spec/uploaders/file_mover_spec.rb | 25 +++++++ 10 files changed, 303 insertions(+), 6 deletions(-) create mode 100644 spec/features/projects/snippets/create_snippet_spec.rb create mode 100644 spec/features/snippets/edit_snippet_spec.rb create mode 100644 spec/uploaders/file_mover_spec.rb (limited to 'spec') diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index 24a59caff4e..8c23c46798e 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -78,8 +78,18 @@ describe Projects::SnippetsController do post :create, { namespace_id: project.namespace.to_param, project_id: project, - project_snippet: { title: 'Title', content: 'Content' }.merge(snippet_params) + project_snippet: { title: 'Title', content: 'Content', description: 'Description' }.merge(snippet_params) }.merge(additional_params) + + Snippet.last + end + + it 'creates the snippet correctly' do + snippet = create_snippet(project, visibility_level: Snippet::PRIVATE) + + expect(snippet.title).to eq('Title') + expect(snippet.content).to eq('Content') + expect(snippet.description).to eq('Description') end context 'when the snippet is spam' do diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb index 930415a4778..9073c39f562 100644 --- a/spec/controllers/snippets_controller_spec.rb +++ b/spec/controllers/snippets_controller_spec.rb @@ -171,12 +171,50 @@ describe SnippetsController do sign_in(user) post :create, { - personal_snippet: { title: 'Title', content: 'Content' }.merge(snippet_params) + personal_snippet: { title: 'Title', content: 'Content', description: 'Description' }.merge(snippet_params) }.merge(additional_params) Snippet.last end + it 'creates the snippet correctly' do + snippet = create_snippet(visibility_level: Snippet::PRIVATE) + + expect(snippet.title).to eq('Title') + expect(snippet.content).to eq('Content') + expect(snippet.description).to eq('Description') + end + + context 'when the snippet description contains a file' do + let(:picture_file) { '/temp/secret56/picture.jpg' } + let(:text_file) { '/temp/secret78/text.txt' } + let(:description) do + "Description with picture: ![picture](/uploads#{picture_file}) and "\ + "text: [text.txt](/uploads#{text_file})" + end + + before do + allow(FileUtils).to receive(:mkdir_p) + allow(FileUtils).to receive(:move) + end + + subject { create_snippet({ description: description }, { files: [picture_file, text_file] }) } + + it 'creates the snippet' do + expect { subject }.to change { Snippet.count }.by(1) + end + + it 'stores the snippet description correctly' do + snippet = subject + + expected_description = "Description with picture: "\ + "![picture](/uploads/personal_snippet/#{snippet.id}/secret56/picture.jpg) and "\ + "text: [text.txt](/uploads/personal_snippet/#{snippet.id}/secret78/text.txt)" + + expect(snippet.description).to eq(expected_description) + end + end + context 'when the snippet is spam' do before do allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true) diff --git a/spec/factories/snippets.rb b/spec/factories/snippets.rb index 18cb0f5de26..388f662e6e5 100644 --- a/spec/factories/snippets.rb +++ b/spec/factories/snippets.rb @@ -3,6 +3,7 @@ FactoryGirl.define do author title { generate(:title) } content { generate(:title) } + description { generate(:title) } file_name { generate(:filename) } trait :public do diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb new file mode 100644 index 00000000000..be9cc9f7029 --- /dev/null +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -0,0 +1,86 @@ +require 'rails_helper' + +feature 'Create Snippet', :js, feature: true do + include DropzoneHelper + + let(:user) { create(:user) } + let(:project) { create(:project, :repository, :public) } + + def fill_form + fill_in 'project_snippet_title', with: 'My Snippet Title' + fill_in 'project_snippet_description', with: 'My Snippet **Description**' + page.within('.file-editor') do + find('.ace_editor').native.send_keys('Hello World!') + end + end + + context 'when a user is authenticated' do + before do + project.team << [user, :master] + login_as(user) + + visit namespace_project_snippets_path(project.namespace, project) + + click_on('New snippet') + end + + it 'creates a new snippet' do + fill_form + click_button('Create snippet') + wait_for_ajax + + expect(page).to have_content('My Snippet Title') + expect(page).to have_content('Hello World!') + page.within('.snippet-header .description') do + expect(page).to have_content('My Snippet Description') + expect(page).to have_selector('strong') + end + end + + it 'uploads a file when dragging into textarea' do + fill_form + dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') + + expect(page.find_field("project_snippet_description").value).to have_content('banana_sample') + + click_button('Create snippet') + wait_for_ajax + + link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] + expect(link).to match(%r{/#{Regexp.escape(project.full_path) }/uploads/\h{32}/banana_sample\.gif\z}) + end + + it 'creates a snippet when all reuiqred fields are filled in after validation failing' do + fill_in 'project_snippet_title', with: 'My Snippet Title' + click_button('Create snippet') + + expect(page).to have_selector('#error_explanation') + + fill_form + dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') + + click_button('Create snippet') + wait_for_ajax + + expect(page).to have_content('My Snippet Title') + expect(page).to have_content('Hello World!') + page.within('.snippet-header .description') do + expect(page).to have_content('My Snippet Description') + expect(page).to have_selector('strong') + end + link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] + expect(link).to match(%r{/#{Regexp.escape(project.full_path) }/uploads/\h{32}/banana_sample\.gif\z}) + end + end + + context 'when a user is not authenticated' do + it 'shows a public snippet on the index page but not the New snippet button' do + snippet = create(:project_snippet, :public, project: project) + + visit namespace_project_snippets_path(project.namespace, project) + + expect(page).to have_content(snippet.title) + expect(page).not_to have_content('New snippet') + end + end +end diff --git a/spec/features/snippets/create_snippet_spec.rb b/spec/features/snippets/create_snippet_spec.rb index 31a2d4ae984..f006057669b 100644 --- a/spec/features/snippets/create_snippet_spec.rb +++ b/spec/features/snippets/create_snippet_spec.rb @@ -1,22 +1,69 @@ require 'rails_helper' feature 'Create Snippet', :js, feature: true do + include DropzoneHelper + before do login_as :user visit new_snippet_path end - scenario 'Authenticated user creates a snippet' do + def fill_form fill_in 'personal_snippet_title', with: 'My Snippet Title' + fill_in 'personal_snippet_description', with: 'My Snippet **Description**' page.within('.file-editor') do find('.ace_editor').native.send_keys 'Hello World!' end + end - click_button 'Create snippet' + scenario 'Authenticated user creates a snippet' do + fill_form + + click_button('Create snippet') wait_for_requests expect(page).to have_content('My Snippet Title') + page.within('.snippet-header .description') do + expect(page).to have_content('My Snippet Description') + expect(page).to have_selector('strong') + end + expect(page).to have_content('Hello World!') + end + + scenario 'uploads a file when dragging into textarea' do + fill_form + + dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') + + expect(page.find_field("personal_snippet_description").value).to have_content('banana_sample') + + click_button('Create snippet') + wait_for_requests + + link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] + expect(link).to match(%r{/uploads/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z}) + end + + scenario 'validation fails for the first time' do + fill_in 'personal_snippet_title', with: 'My Snippet Title' + click_button('Create snippet') + + expect(page).to have_selector('#error_explanation') + + fill_form + dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') + + click_button('Create snippet') + wait_for_requests + + expect(page).to have_content('My Snippet Title') + page.within('.snippet-header .description') do + expect(page).to have_content('My Snippet Description') + expect(page).to have_selector('strong') + end expect(page).to have_content('Hello World!') + link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] + expect(link).to match(%r{/uploads/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z}) end scenario 'Authenticated user creates a snippet with + in filename' do diff --git a/spec/features/snippets/edit_snippet_spec.rb b/spec/features/snippets/edit_snippet_spec.rb new file mode 100644 index 00000000000..ee04792ef73 --- /dev/null +++ b/spec/features/snippets/edit_snippet_spec.rb @@ -0,0 +1,38 @@ +require 'rails_helper' + +feature 'Edit Snippet', :js, feature: true do + include DropzoneHelper + + let(:file_name) { 'test.rb' } + let(:content) { 'puts "test"' } + + let(:user) { create(:user) } + let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, author: user) } + + before do + login_as(user) + + visit edit_snippet_path(snippet) + wait_for_ajax + end + + it 'updates the snippet' do + fill_in 'personal_snippet_title', with: 'New Snippet Title' + + click_button('Save changes') + wait_for_ajax + + expect(page).to have_content('New Snippet Title') + end + + it 'updates the snippet with files attached' do + dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') + expect(page.find_field("personal_snippet_description").value).to have_content('banana_sample') + + click_button('Save changes') + wait_for_ajax + + link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] + expect(link).to match(%r{/uploads/personal_snippet/#{snippet.id}/\h{32}/banana_sample\.gif\z}) + end +end diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 96054c996fd..1dd0c748c7b 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -92,6 +92,7 @@ Milestone: ProjectSnippet: - id - title +- description - content - author_id - project_id diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb index 3ab1764f5c3..4d4631322b1 100644 --- a/spec/requests/api/project_snippets_spec.rb +++ b/spec/requests/api/project_snippets_spec.rb @@ -36,11 +36,34 @@ describe API::ProjectSnippets do end end + describe 'GET /projects/:project_id/snippets/:id' do + let(:user) { create(:user) } + let(:snippet) { create(:project_snippet, :public, project: project) } + + it 'returns snippet json' do + get api("/projects/#{project.id}/snippets/#{snippet.id}", user) + + expect(response).to have_http_status(200) + + expect(json_response['title']).to eq(snippet.title) + expect(json_response['description']).to eq(snippet.description) + expect(json_response['file_name']).to eq(snippet.file_name) + end + + it 'returns 404 for invalid snippet id' do + get api("/projects/#{project.id}/snippets/1234", user) + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Not found') + end + end + describe 'POST /projects/:project_id/snippets/' do let(:params) do { title: 'Test Title', file_name: 'test.rb', + description: 'test description', code: 'puts "hello world"', visibility: 'public' } @@ -52,6 +75,7 @@ describe API::ProjectSnippets do expect(response).to have_http_status(201) snippet = ProjectSnippet.find(json_response['id']) expect(snippet.content).to eq(params[:code]) + expect(snippet.description).to eq(params[:description]) expect(snippet.title).to eq(params[:title]) expect(snippet.file_name).to eq(params[:file_name]) expect(snippet.visibility_level).to eq(Snippet::PUBLIC) @@ -106,12 +130,14 @@ describe API::ProjectSnippets do it 'updates snippet' do new_content = 'New content' + new_description = 'New description' - put api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin), code: new_content + put api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin), code: new_content, description: new_description expect(response).to have_http_status(200) snippet.reload expect(snippet.content).to eq(new_content) + expect(snippet.description).to eq(new_description) end it 'returns 404 for invalid snippet id' do diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb index e429cddcf6a..8741cbd4e80 100644 --- a/spec/requests/api/snippets_spec.rb +++ b/spec/requests/api/snippets_spec.rb @@ -80,11 +80,33 @@ describe API::Snippets do end end + describe 'GET /snippets/:id' do + let(:snippet) { create(:personal_snippet, author: user) } + + it 'returns snippet json' do + get api("/snippets/#{snippet.id}", user) + + expect(response).to have_http_status(200) + + expect(json_response['title']).to eq(snippet.title) + expect(json_response['description']).to eq(snippet.description) + expect(json_response['file_name']).to eq(snippet.file_name) + end + + it 'returns 404 for invalid snippet id' do + get api("/snippets/1234", user) + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Not found') + end + end + describe 'POST /snippets/' do let(:params) do { title: 'Test Title', file_name: 'test.rb', + description: 'test description', content: 'puts "hello world"', visibility: 'public' } @@ -97,6 +119,7 @@ describe API::Snippets do expect(response).to have_http_status(201) expect(json_response['title']).to eq(params[:title]) + expect(json_response['description']).to eq(params[:description]) expect(json_response['file_name']).to eq(params[:file_name]) end @@ -150,12 +173,14 @@ describe API::Snippets do it 'updates snippet' do new_content = 'New content' + new_description = 'New description' - put api("/snippets/#{snippet.id}", user), content: new_content + put api("/snippets/#{snippet.id}", user), content: new_content, description: new_description expect(response).to have_http_status(200) snippet.reload expect(snippet.content).to eq(new_content) + expect(snippet.description).to eq(new_description) end it 'returns 404 for invalid snippet id' do diff --git a/spec/uploaders/file_mover_spec.rb b/spec/uploaders/file_mover_spec.rb new file mode 100644 index 00000000000..99d50e78240 --- /dev/null +++ b/spec/uploaders/file_mover_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe FileMover do + let(:filename) { 'banana_sample.gif' } + let(:file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) } + let(:temp_description) { 'test ![banana_sample](/uploads/temp/secret55/banana_sample.gif)' } + let(:temp_file_path) { File.join('secret55', filename).to_s } + let(:file_path) { File.join('uploads', 'personal_snippet', snippet.id.to_s, 'secret55', filename).to_s } + + let(:snippet) { create(:personal_snippet, description: temp_description) } + + subject { described_class.new(file_path, snippet).execute } + + describe '#execute' do + it 'updates the description correctly' do + expect(FileUtils).to receive(:mkdir_p).with(a_string_including(file_path)) + expect(FileUtils).to receive(:move).with(a_string_including(temp_file_path), a_string_including(file_path)) + + subject + + expect(snippet.reload.description) + .to eq("test ![banana_sample](/uploads/personal_snippet/#{snippet.id}/secret55/banana_sample.gif)") + end + end +end -- cgit v1.2.3 From c881425b665b9c0b022dc2e213486aecc320ec7e Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 31 May 2017 14:40:50 +0200 Subject: Refine pipeline stages seeds class --- spec/lib/gitlab/ci/stage/seed_spec.rb | 47 -------------------------- spec/lib/gitlab/ci/stage/seeds_spec.rb | 62 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 47 deletions(-) delete mode 100644 spec/lib/gitlab/ci/stage/seed_spec.rb create mode 100644 spec/lib/gitlab/ci/stage/seeds_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb deleted file mode 100644 index a12093b2c7c..00000000000 --- a/spec/lib/gitlab/ci/stage/seed_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Ci::Stage::Seed do - subject do - described_class.new(name: 'test', builds: builds) - end - - let(:builds) do - [{ name: 'rspec' }, { name: 'spinach' }] - end - - describe '#pipeline=' do - let(:pipeline) do - create(:ci_empty_pipeline, ref: 'feature', tag: true) - end - - it 'assignes relevant pipeline attributes' do - trigger_request = pipeline.trigger_requests.first - - subject.pipeline = pipeline - - expect(subject.builds).to all(include(pipeline: pipeline)) - expect(subject.builds).to all(include(project: pipeline.project)) - expect(subject.builds).to all(include(ref: 'feature')) - expect(subject.builds).to all(include(tag: true)) - expect(subject.builds).to all(include(trigger_request: trigger_request)) - end - end - - describe '#user=' do - let(:user) { create(:user) } - - it 'assignes relevant pipeline attributes' do - subject.user = user - - expect(subject.builds).to all(include(user: user)) - end - end - - describe '#to_attributes' do - it 'exposes stage attributes with nested jobs' do - expect(subject.to_attributes).to be_a Hash - expect(subject.to_attributes).to include(name: 'test') - expect(subject.to_attributes).to include(builds_attributes: builds) - end - end -end diff --git a/spec/lib/gitlab/ci/stage/seeds_spec.rb b/spec/lib/gitlab/ci/stage/seeds_spec.rb new file mode 100644 index 00000000000..cc4f37d236e --- /dev/null +++ b/spec/lib/gitlab/ci/stage/seeds_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper' + +describe Gitlab::Ci::Stage::Seeds do + before do + subject.append_stage('test', [{ name: 'rspec' }, { name: 'spinach' }]) + subject.append_stage('deploy', [{ name: 'prod', script: 'cap deploy' }]) + end + + describe '#stages' do + it 'returns hashes of all stages' do + expect(subject.stages.size).to eq 2 + expect(subject.stages).to all(be_a Hash) + end + end + + describe '#jobs' do + it 'returns all jobs in all stages' do + expect(subject.jobs.size).to eq 3 + end + end + + describe '#pipeline=' do + let(:pipeline) do + create(:ci_empty_pipeline, ref: 'feature', tag: true) + end + + it 'assignes relevant pipeline attributes' do + trigger_request = pipeline.trigger_requests.first + + subject.pipeline = pipeline + + expect(subject.stages).to all(include(pipeline: pipeline)) + expect(subject.stages).to all(include(project: pipeline.project)) + expect(subject.jobs).to all(include(pipeline: pipeline)) + expect(subject.jobs).to all(include(project: pipeline.project)) + expect(subject.jobs).to all(include(ref: 'feature')) + expect(subject.jobs).to all(include(tag: true)) + expect(subject.jobs).to all(include(trigger_request: trigger_request)) + end + end + + describe '#user=' do + let(:user) { create(:user) } + + it 'assignes relevant pipeline attributes' do + subject.user = user + + expect(subject.jobs).to all(include(user: user)) + end + end + + describe '#to_attributes' do + it 'exposes stage attributes with nested jobs' do + attributes = [{ name: 'test', builds_attributes: + [{ name: 'rspec' }, { name: 'spinach' }] }, + { name: 'deploy', builds_attributes: + [{ name: 'prod', script: 'cap deploy' }] }] + + expect(subject.to_attributes).to eq attributes + end + end +end -- cgit v1.2.3 From c72e21fd9764845a107005562ff8ce1c06cac431 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 31 May 2017 15:13:40 +0200 Subject: Return stage seeds object from YAML processor --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 30 +++++++++++++--------------- spec/lib/gitlab/ci/stage/seeds_spec.rb | 4 ++++ 2 files changed, 18 insertions(+), 16 deletions(-) (limited to 'spec') diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index f98da1916b4..7f652c17ed5 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -83,7 +83,7 @@ module Ci end end - describe '#stages_for_ref' do + describe '#stage_seeds' do context 'when no refs policy is specified' do let(:config) do YAML.dump(production: { stage: 'deploy', script: 'cap prod' }, @@ -91,15 +91,15 @@ module Ci spinach: { stage: 'test', script: 'spinach' }) end - it 'returns model attributes for stages with nested jobs' do - attributes = subject.stages_for_ref('master') + it 'returns correctly fabricated stage seeds object' do + seeds = subject.stage_seeds(ref: 'master') - expect(attributes.size).to eq 2 - expect(attributes.dig(0, :name)).to eq 'test' - expect(attributes.dig(1, :name)).to eq 'deploy' - expect(attributes.dig(0, :builds_attributes, 0, :name)).to eq 'rspec' - expect(attributes.dig(0, :builds_attributes, 1, :name)).to eq 'spinach' - expect(attributes.dig(1, :builds_attributes, 0, :name)).to eq 'production' + expect(seeds.stages.size).to eq 2 + expect(seeds.stages.dig(0, :name)).to eq 'test' + expect(seeds.stages.dig(1, :name)).to eq 'deploy' + expect(seeds.jobs.dig(0, :name)).to eq 'rspec' + expect(seeds.jobs.dig(1, :name)).to eq 'spinach' + expect(seeds.jobs.dig(2, :name)).to eq 'production' end end @@ -109,14 +109,12 @@ module Ci spinach: { stage: 'test', script: 'spinach', only: ['tags'] }) end - it 'returns stage attributes except of jobs assigned to master' do - # true flag argument means matching jobs for tags - # - attributes = subject.stages_for_ref('feature', true) + it 'returns stage seeds only assigned to master to master' do + seeds = subject.stage_seeds(ref: 'feature', tag: true) - expect(attributes.size).to eq 1 - expect(attributes.dig(0, :name)).to eq 'test' - expect(attributes.dig(0, :builds_attributes, 0, :name)).to eq 'spinach' + expect(seeds.stages.size).to eq 1 + expect(seeds.stages.dig(0, :name)).to eq 'test' + expect(seeds.jobs.dig(0, :name)).to eq 'spinach' end end end diff --git a/spec/lib/gitlab/ci/stage/seeds_spec.rb b/spec/lib/gitlab/ci/stage/seeds_spec.rb index cc4f37d236e..3824a868fb2 100644 --- a/spec/lib/gitlab/ci/stage/seeds_spec.rb +++ b/spec/lib/gitlab/ci/stage/seeds_spec.rb @@ -6,6 +6,10 @@ describe Gitlab::Ci::Stage::Seeds do subject.append_stage('deploy', [{ name: 'prod', script: 'cap deploy' }]) end + describe '#has_stages?' do + it { is_expected.to have_stages } + end + describe '#stages' do it 'returns hashes of all stages' do expect(subject.stages.size).to eq 2 -- cgit v1.2.3 From 5c2ce44baf5205c038759c4779a74e3381183e8a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 31 May 2017 15:25:36 +0200 Subject: Expose pipeline stage seeds from pipeline instance --- spec/models/ci/pipeline_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'spec') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index c4f07c4a693..3a1fe666ff0 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -202,6 +202,17 @@ describe Ci::Pipeline, models: true do status: 'success') end + describe '#stage_seeds' do + let(:pipeline) do + create(:ci_pipeline, config: { rspec: { script: 'rake' } }) + end + + it 'returns preseeded stage seeds object' do + expect(pipeline.stage_seeds).to be_a Gitlab::Ci::Stage::Seeds + expect(pipeline.stage_seeds.stages).to all(include(pipeline: pipeline)) + end + end + describe '#stages' do subject { pipeline.stages } -- cgit v1.2.3 From 285049b91b59c846a668602b797f9b75709c6f63 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 31 May 2017 15:34:02 +0100 Subject: spec updates --- spec/controllers/projects/boards/lists_controller_spec.rb | 2 +- spec/factories/lists.rb | 6 ++++++ spec/fixtures/api/schemas/list.json | 2 +- spec/services/boards/create_service_spec.rb | 5 +++-- spec/services/boards/issues/list_service_spec.rb | 9 +++++++++ 5 files changed, 20 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/boards/lists_controller_spec.rb b/spec/controllers/projects/boards/lists_controller_spec.rb index 432f3c53c90..0f2664262e8 100644 --- a/spec/controllers/projects/boards/lists_controller_spec.rb +++ b/spec/controllers/projects/boards/lists_controller_spec.rb @@ -27,7 +27,7 @@ describe Projects::Boards::ListsController do parsed_response = JSON.parse(response.body) expect(response).to match_response_schema('lists') - expect(parsed_response.length).to eq 2 + expect(parsed_response.length).to eq 3 end context 'with unauthorized user' do diff --git a/spec/factories/lists.rb b/spec/factories/lists.rb index f6a78811cbe..48142d3c49b 100644 --- a/spec/factories/lists.rb +++ b/spec/factories/lists.rb @@ -6,6 +6,12 @@ FactoryGirl.define do sequence(:position) end + factory :backlog_list, parent: :list do + list_type :backlog + label nil + position nil + end + factory :closed_list, parent: :list do list_type :closed label nil diff --git a/spec/fixtures/api/schemas/list.json b/spec/fixtures/api/schemas/list.json index 11a4caf6628..622a1e40d07 100644 --- a/spec/fixtures/api/schemas/list.json +++ b/spec/fixtures/api/schemas/list.json @@ -10,7 +10,7 @@ "id": { "type": "integer" }, "list_type": { "type": "string", - "enum": ["label", "closed"] + "enum": ["backlog", "label", "closed"] }, "label": { "type": ["object", "null"], diff --git a/spec/services/boards/create_service_spec.rb b/spec/services/boards/create_service_spec.rb index a8555f5b4a0..effa4633d13 100644 --- a/spec/services/boards/create_service_spec.rb +++ b/spec/services/boards/create_service_spec.rb @@ -14,8 +14,9 @@ describe Boards::CreateService, services: true do it 'creates the default lists' do board = service.execute - expect(board.lists.size).to eq 1 - expect(board.lists.first).to be_closed + expect(board.lists.size).to eq 2 + expect(board.lists.first).to be_backlog + expect(board.lists.last).to be_closed end end diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index c982031c791..a66cc2cd6e9 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -13,6 +13,7 @@ describe Boards::Issues::ListService, services: true do let(:p2) { create(:label, title: 'P2', project: project, priority: 2) } let(:p3) { create(:label, title: 'P3', project: project, priority: 3) } + let!(:backlog) { create(:backlog_list, board: board) } let!(:list1) { create(:list, board: board, label: development, position: 0) } let!(:list2) { create(:list, board: board, label: testing, position: 1) } let!(:closed) { create(:closed_list, board: board) } @@ -53,6 +54,14 @@ describe Boards::Issues::ListService, services: true do expect(issues).to eq [opened_issue2, reopened_issue1, opened_issue1] end + it 'returns opened issues when listing issues from Backlog' do + params = { board_id: board.id, id: backlog.id } + + issues = described_class.new(project, user, params).execute + + expect(issues).to eq [opened_issue2, reopened_issue1, opened_issue1] + end + it 'returns closed issues when listing issues from Closed' do params = { board_id: board.id, id: closed.id } -- cgit v1.2.3 From 76543bce90b51f99f7185d7e9f1cc82f975c6d60 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Wed, 31 May 2017 21:37:56 -0500 Subject: Fix karma tests --- spec/javascripts/groups/mock_data.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js index fdb809018cf..98f2aa52135 100644 --- a/spec/javascripts/groups/mock_data.js +++ b/spec/javascripts/groups/mock_data.js @@ -11,8 +11,8 @@ const group1 = { parent_id: null, created_at: '2017-05-15T19:01:23.670Z', updated_at: '2017-05-15T19:01:23.670Z', - number_projects: '1', - number_users: '1', + number_projects_with_delimiter: '1', + number_users_with_delimiter: '1', has_subgroups: true, permissions: { group_access: 50, @@ -33,8 +33,8 @@ const group14 = { parent_id: 1127, created_at: '2017-05-15T19:02:01.645Z', updated_at: '2017-05-15T19:02:01.645Z', - number_projects: '1', - number_users: '1', + number_projects_with_delimiter: '1', + number_users_with_delimiter: '1', has_subgroups: true, permissions: { group_access: 30, @@ -54,8 +54,8 @@ const group2 = { parent_id: null, created_at: '2017-05-11T19:35:09.635Z', updated_at: '2017-05-11T19:35:09.635Z', - number_projects: '1', - number_users: '1', + number_projects_with_delimiter: '1', + number_users_with_delimiter: '1', has_subgroups: true, permissions: { group_access: 50, @@ -75,8 +75,8 @@ const group21 = { parent_id: 1119, created_at: '2017-05-11T19:51:04.060Z', updated_at: '2017-05-11T19:51:04.060Z', - number_projects: '1', - number_users: '1', + number_projects_with_delimiter: '1', + number_users_with_delimiter: '1', has_subgroups: true, permissions: { group_access: 50, -- cgit v1.2.3 From 854e9de935c2bbb2a7143c73bb5e9edf98d3fc65 Mon Sep 17 00:00:00 2001 From: Simon Knox Date: Tue, 30 May 2017 18:32:49 +1000 Subject: animate adding issue to boards fix some false positive tests for board_new_issue --- spec/javascripts/boards/board_new_issue_spec.js | 45 +++++++++++++++---------- 1 file changed, 27 insertions(+), 18 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/boards/board_new_issue_spec.js b/spec/javascripts/boards/board_new_issue_spec.js index 45d12e252c4..832877de71c 100644 --- a/spec/javascripts/boards/board_new_issue_spec.js +++ b/spec/javascripts/boards/board_new_issue_spec.js @@ -19,6 +19,7 @@ describe('Issue boards new issue form', () => { }; }, }; + const submitIssue = () => { vm.$el.querySelector('.btn-success').click(); }; @@ -107,7 +108,7 @@ describe('Issue boards new issue form', () => { setTimeout(() => { submitIssue(); - expect(vm.$el.querySelector('.btn-success').disbled).not.toBe(true); + expect(vm.$el.querySelector('.btn-success').disabled).toBe(false); done(); }, 0); }); @@ -115,36 +116,43 @@ describe('Issue boards new issue form', () => { it('clears title after submit', (done) => { vm.title = 'submit issue'; - setTimeout(() => { + Vue.nextTick(() => { submitIssue(); - expect(vm.title).toBe(''); - done(); - }, 0); + setTimeout(() => { + expect(vm.title).toBe(''); + done(); + }, 0); + }); }); - it('adds new issue to list after submit', (done) => { + it('adds new issue to top of list after submit request', (done) => { vm.title = 'submit issue'; setTimeout(() => { submitIssue(); - expect(list.issues.length).toBe(2); - expect(list.issues[1].title).toBe('submit issue'); - expect(list.issues[1].subscribed).toBe(true); - done(); + setTimeout(() => { + expect(list.issues.length).toBe(2); + expect(list.issues[0].title).toBe('submit issue'); + expect(list.issues[0].subscribed).toBe(true); + done(); + }, 0); }, 0); }); it('sets detail issue after submit', (done) => { + expect(gl.issueBoards.BoardsStore.detail.issue.title).toBe(undefined); vm.title = 'submit issue'; setTimeout(() => { submitIssue(); - expect(gl.issueBoards.BoardsStore.detail.issue.title).toBe('submit issue'); - done(); - }); + setTimeout(() => { + expect(gl.issueBoards.BoardsStore.detail.issue.title).toBe('submit issue'); + done(); + }, 0); + }, 0); }); it('sets detail list after submit', (done) => { @@ -153,8 +161,10 @@ describe('Issue boards new issue form', () => { setTimeout(() => { submitIssue(); - expect(gl.issueBoards.BoardsStore.detail.list.id).toBe(list.id); - done(); + setTimeout(() => { + expect(gl.issueBoards.BoardsStore.detail.list.id).toBe(list.id); + done(); + }, 0); }, 0); }); }); @@ -169,13 +179,12 @@ describe('Issue boards new issue form', () => { setTimeout(() => { expect(list.issues.length).toBe(1); done(); - }, 500); + }, 0); }, 0); }); it('shows error', (done) => { vm.title = 'error'; - submitIssue(); setTimeout(() => { submitIssue(); @@ -183,7 +192,7 @@ describe('Issue boards new issue form', () => { setTimeout(() => { expect(vm.error).toBe(true); done(); - }, 500); + }, 0); }, 0); }); }); -- cgit v1.2.3 From fd9d8302d92d70370639d1bd8bfc07c478909647 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 1 Jun 2017 10:15:09 +0100 Subject: fixed new_issue_spec [ci skip] --- spec/features/boards/new_issue_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb index 0e98f994018..056224dc436 100644 --- a/spec/features/boards/new_issue_spec.rb +++ b/spec/features/boards/new_issue_spec.rb @@ -15,15 +15,15 @@ describe 'Issue Boards new issue', feature: true, js: true do visit namespace_project_board_path(project.namespace, project, board) wait_for_requests - expect(page).to have_selector('.board', count: 2) + expect(page).to have_selector('.board', count: 3) end it 'displays new issue button' do - expect(page).to have_selector('.board-issue-count-holder .btn', count: 1) + expect(first('.board')).to have_selector('.board-issue-count-holder .btn', count: 1) end it 'does not display new issue button in closed list' do - page.within('.board:nth-child(2)') do + page.within('.board:nth-child(3)') do expect(page).not_to have_selector('.board-issue-count-holder .btn') end end -- cgit v1.2.3 From c00d72b6f33d50b1c5cd6948d54b3addf11f9104 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 1 Jun 2017 11:55:18 +0200 Subject: Rename pipeline methods related to legacy stages --- spec/models/ci/pipeline_spec.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 3a1fe666ff0..46dfa90218d 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -213,8 +213,8 @@ describe Ci::Pipeline, models: true do end end - describe '#stages' do - subject { pipeline.stages } + describe '#legacy_stages' do + subject { pipeline.legacy_stages } context 'stages list' do it 'returns ordered list of stages' do @@ -263,7 +263,7 @@ describe Ci::Pipeline, models: true do end it 'populates stage with correct number of warnings' do - deploy_stage = pipeline.stages.third + deploy_stage = pipeline.legacy_stages.third expect(deploy_stage).not_to receive(:statuses) expect(deploy_stage).to have_warnings @@ -277,15 +277,15 @@ describe Ci::Pipeline, models: true do end end - describe '#stages_name' do + describe '#stages_names' do it 'returns a valid names of stages' do - expect(pipeline.stages_name).to eq(%w(build test deploy)) + expect(pipeline.stages_names).to eq(%w(build test deploy)) end end end - describe '#stage' do - subject { pipeline.stage('test') } + describe '#legacy_stage' do + subject { pipeline.legacy_stage('test') } context 'with status in stage' do before do -- cgit v1.2.3 From 78b2f65cb5320a6a28c1e26bb6ee792a54e1b674 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 1 Jun 2017 12:00:37 +0200 Subject: Rename `Ci::Stage` class to `Ci::LegacyStage` --- spec/factories/ci/stages.rb | 6 +- spec/models/ci/legacy_stage_spec.rb | 262 ++++++++++++++++++++++++++++++++++++ spec/models/ci/pipeline_spec.rb | 2 +- spec/models/ci/stage_spec.rb | 262 ------------------------------------ 4 files changed, 267 insertions(+), 265 deletions(-) create mode 100644 spec/models/ci/legacy_stage_spec.rb delete mode 100644 spec/models/ci/stage_spec.rb (limited to 'spec') diff --git a/spec/factories/ci/stages.rb b/spec/factories/ci/stages.rb index 7f557b25ccb..884661e1030 100644 --- a/spec/factories/ci/stages.rb +++ b/spec/factories/ci/stages.rb @@ -1,5 +1,5 @@ FactoryGirl.define do - factory :ci_stage, class: Ci::Stage do + factory :ci_stage, class: Ci::LegacyStage do transient do name 'test' status nil @@ -8,7 +8,9 @@ FactoryGirl.define do end initialize_with do - Ci::Stage.new(pipeline, name: name, status: status, warnings: warnings) + Ci::LegacyStage.new(pipeline, name: name, + status: status, + warnings: warnings) end end end diff --git a/spec/models/ci/legacy_stage_spec.rb b/spec/models/ci/legacy_stage_spec.rb new file mode 100644 index 00000000000..48116c7e701 --- /dev/null +++ b/spec/models/ci/legacy_stage_spec.rb @@ -0,0 +1,262 @@ +require 'spec_helper' + +describe Ci::LegacyStage, :models do + let(:stage) { build(:ci_stage) } + let(:pipeline) { stage.pipeline } + let(:stage_name) { stage.name } + + describe '#expectations' do + subject { stage } + + it { is_expected.to include_module(StaticModel) } + + it { is_expected.to respond_to(:pipeline) } + it { is_expected.to respond_to(:name) } + + it { is_expected.to delegate_method(:project).to(:pipeline) } + end + + describe '#statuses' do + let!(:stage_build) { create_job(:ci_build) } + let!(:commit_status) { create_job(:commit_status) } + let!(:other_build) { create_job(:ci_build, stage: 'other stage') } + + subject { stage.statuses } + + it "returns only matching statuses" do + is_expected.to contain_exactly(stage_build, commit_status) + end + end + + describe '#groups' do + before do + create_job(:ci_build, name: 'rspec 0 2') + create_job(:ci_build, name: 'rspec 0 1') + create_job(:ci_build, name: 'spinach 0 1') + create_job(:commit_status, name: 'aaaaa') + end + + it 'returns an array of three groups' do + expect(stage.groups).to be_a Array + expect(stage.groups).to all(be_a Ci::Group) + expect(stage.groups.size).to eq 3 + end + + it 'returns groups with correctly ordered statuses' do + expect(stage.groups.first.jobs.map(&:name)) + .to eq ['aaaaa'] + expect(stage.groups.second.jobs.map(&:name)) + .to eq ['rspec 0 1', 'rspec 0 2'] + expect(stage.groups.third.jobs.map(&:name)) + .to eq ['spinach 0 1'] + end + + it 'returns groups with correct names' do + expect(stage.groups.map(&:name)) + .to eq %w[aaaaa rspec spinach] + end + end + + describe '#statuses_count' do + before do + create_job(:ci_build) + create_job(:ci_build, stage: 'other stage') + end + + subject { stage.statuses_count } + + it "counts statuses only from current stage" do + is_expected.to eq(1) + end + end + + describe '#builds' do + let!(:stage_build) { create_job(:ci_build) } + let!(:commit_status) { create_job(:commit_status) } + + subject { stage.builds } + + it "returns only builds" do + is_expected.to contain_exactly(stage_build) + end + end + + describe '#status' do + subject { stage.status } + + context 'if status is already defined' do + let(:stage) { build(:ci_stage, status: 'success') } + + it "returns defined status" do + is_expected.to eq('success') + end + end + + context 'if status has to be calculated' do + let!(:stage_build) { create_job(:ci_build, status: :failed) } + + it "returns status of a build" do + is_expected.to eq('failed') + end + + context 'and builds are retried' do + let!(:new_build) { create_job(:ci_build, status: :success) } + + before do + stage_build.update(retried: true) + end + + it "returns status of latest build" do + is_expected.to eq('success') + end + end + end + end + + describe '#detailed_status' do + let(:user) { create(:user) } + + subject { stage.detailed_status(user) } + + context 'when build is created' do + let!(:stage_build) { create_job(:ci_build, status: :created) } + + it 'returns detailed status for created stage' do + expect(subject.text).to eq 'created' + end + end + + context 'when build is pending' do + let!(:stage_build) { create_job(:ci_build, status: :pending) } + + it 'returns detailed status for pending stage' do + expect(subject.text).to eq 'pending' + end + end + + context 'when build is running' do + let!(:stage_build) { create_job(:ci_build, status: :running) } + + it 'returns detailed status for running stage' do + expect(subject.text).to eq 'running' + end + end + + context 'when build is successful' do + let!(:stage_build) { create_job(:ci_build, status: :success) } + + it 'returns detailed status for successful stage' do + expect(subject.text).to eq 'passed' + end + end + + context 'when build is failed' do + let!(:stage_build) { create_job(:ci_build, status: :failed) } + + it 'returns detailed status for failed stage' do + expect(subject.text).to eq 'failed' + end + end + + context 'when build is canceled' do + let!(:stage_build) { create_job(:ci_build, status: :canceled) } + + it 'returns detailed status for canceled stage' do + expect(subject.text).to eq 'canceled' + end + end + + context 'when build is skipped' do + let!(:stage_build) { create_job(:ci_build, status: :skipped) } + + it 'returns detailed status for skipped stage' do + expect(subject.text).to eq 'skipped' + end + end + end + + describe '#success?' do + context 'when stage is successful' do + before do + create_job(:ci_build, status: :success) + create_job(:generic_commit_status, status: :success) + end + + it 'is successful' do + expect(stage).to be_success + end + end + + context 'when stage is not successful' do + before do + create_job(:ci_build, status: :failed) + create_job(:generic_commit_status, status: :success) + end + + it 'is not successful' do + expect(stage).not_to be_success + end + end + end + + describe '#has_warnings?' do + context 'when stage has warnings' do + context 'when using memoized warnings flag' do + context 'when there are warnings' do + let(:stage) { build(:ci_stage, warnings: 2) } + + it 'returns true using memoized value' do + expect(stage).not_to receive(:statuses) + expect(stage).to have_warnings + end + end + + context 'when there are no warnings' do + let(:stage) { build(:ci_stage, warnings: 0) } + + it 'returns false using memoized value' do + expect(stage).not_to receive(:statuses) + expect(stage).not_to have_warnings + end + end + + context 'when number of warnings is not a valid value' do + let(:stage) { build(:ci_stage, warnings: true) } + + it 'calculates statuses using database queries' do + expect(stage).to receive(:statuses).and_call_original + expect(stage).not_to have_warnings + end + end + end + + context 'when calculating warnings from statuses' do + before do + create(:ci_build, :failed, :allowed_to_fail, + stage: stage_name, pipeline: pipeline) + end + + it 'has warnings calculated from statuses' do + expect(stage).to receive(:statuses).and_call_original + expect(stage).to have_warnings + end + end + end + + context 'when stage does not have warnings' do + before do + create(:ci_build, :success, stage: stage_name, + pipeline: pipeline) + end + + it 'does not have warnings calculated from statuses' do + expect(stage).to receive(:statuses).and_call_original + expect(stage).not_to have_warnings + end + end + end + + def create_job(type, status: 'success', stage: stage_name, **opts) + create(type, pipeline: pipeline, stage: stage, status: status, **opts) + end +end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 46dfa90218d..17e10a5322e 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -292,7 +292,7 @@ describe Ci::Pipeline, models: true do create(:commit_status, pipeline: pipeline, stage: 'test') end - it { expect(subject).to be_a Ci::Stage } + it { expect(subject).to be_a Ci::LegacyStage } it { expect(subject.name).to eq 'test' } it { expect(subject.statuses).not_to be_empty } end diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb deleted file mode 100644 index 8f6ab908987..00000000000 --- a/spec/models/ci/stage_spec.rb +++ /dev/null @@ -1,262 +0,0 @@ -require 'spec_helper' - -describe Ci::Stage, models: true do - let(:stage) { build(:ci_stage) } - let(:pipeline) { stage.pipeline } - let(:stage_name) { stage.name } - - describe '#expectations' do - subject { stage } - - it { is_expected.to include_module(StaticModel) } - - it { is_expected.to respond_to(:pipeline) } - it { is_expected.to respond_to(:name) } - - it { is_expected.to delegate_method(:project).to(:pipeline) } - end - - describe '#statuses' do - let!(:stage_build) { create_job(:ci_build) } - let!(:commit_status) { create_job(:commit_status) } - let!(:other_build) { create_job(:ci_build, stage: 'other stage') } - - subject { stage.statuses } - - it "returns only matching statuses" do - is_expected.to contain_exactly(stage_build, commit_status) - end - end - - describe '#groups' do - before do - create_job(:ci_build, name: 'rspec 0 2') - create_job(:ci_build, name: 'rspec 0 1') - create_job(:ci_build, name: 'spinach 0 1') - create_job(:commit_status, name: 'aaaaa') - end - - it 'returns an array of three groups' do - expect(stage.groups).to be_a Array - expect(stage.groups).to all(be_a Ci::Group) - expect(stage.groups.size).to eq 3 - end - - it 'returns groups with correctly ordered statuses' do - expect(stage.groups.first.jobs.map(&:name)) - .to eq ['aaaaa'] - expect(stage.groups.second.jobs.map(&:name)) - .to eq ['rspec 0 1', 'rspec 0 2'] - expect(stage.groups.third.jobs.map(&:name)) - .to eq ['spinach 0 1'] - end - - it 'returns groups with correct names' do - expect(stage.groups.map(&:name)) - .to eq %w[aaaaa rspec spinach] - end - end - - describe '#statuses_count' do - before do - create_job(:ci_build) - create_job(:ci_build, stage: 'other stage') - end - - subject { stage.statuses_count } - - it "counts statuses only from current stage" do - is_expected.to eq(1) - end - end - - describe '#builds' do - let!(:stage_build) { create_job(:ci_build) } - let!(:commit_status) { create_job(:commit_status) } - - subject { stage.builds } - - it "returns only builds" do - is_expected.to contain_exactly(stage_build) - end - end - - describe '#status' do - subject { stage.status } - - context 'if status is already defined' do - let(:stage) { build(:ci_stage, status: 'success') } - - it "returns defined status" do - is_expected.to eq('success') - end - end - - context 'if status has to be calculated' do - let!(:stage_build) { create_job(:ci_build, status: :failed) } - - it "returns status of a build" do - is_expected.to eq('failed') - end - - context 'and builds are retried' do - let!(:new_build) { create_job(:ci_build, status: :success) } - - before do - stage_build.update(retried: true) - end - - it "returns status of latest build" do - is_expected.to eq('success') - end - end - end - end - - describe '#detailed_status' do - let(:user) { create(:user) } - - subject { stage.detailed_status(user) } - - context 'when build is created' do - let!(:stage_build) { create_job(:ci_build, status: :created) } - - it 'returns detailed status for created stage' do - expect(subject.text).to eq 'created' - end - end - - context 'when build is pending' do - let!(:stage_build) { create_job(:ci_build, status: :pending) } - - it 'returns detailed status for pending stage' do - expect(subject.text).to eq 'pending' - end - end - - context 'when build is running' do - let!(:stage_build) { create_job(:ci_build, status: :running) } - - it 'returns detailed status for running stage' do - expect(subject.text).to eq 'running' - end - end - - context 'when build is successful' do - let!(:stage_build) { create_job(:ci_build, status: :success) } - - it 'returns detailed status for successful stage' do - expect(subject.text).to eq 'passed' - end - end - - context 'when build is failed' do - let!(:stage_build) { create_job(:ci_build, status: :failed) } - - it 'returns detailed status for failed stage' do - expect(subject.text).to eq 'failed' - end - end - - context 'when build is canceled' do - let!(:stage_build) { create_job(:ci_build, status: :canceled) } - - it 'returns detailed status for canceled stage' do - expect(subject.text).to eq 'canceled' - end - end - - context 'when build is skipped' do - let!(:stage_build) { create_job(:ci_build, status: :skipped) } - - it 'returns detailed status for skipped stage' do - expect(subject.text).to eq 'skipped' - end - end - end - - describe '#success?' do - context 'when stage is successful' do - before do - create_job(:ci_build, status: :success) - create_job(:generic_commit_status, status: :success) - end - - it 'is successful' do - expect(stage).to be_success - end - end - - context 'when stage is not successful' do - before do - create_job(:ci_build, status: :failed) - create_job(:generic_commit_status, status: :success) - end - - it 'is not successful' do - expect(stage).not_to be_success - end - end - end - - describe '#has_warnings?' do - context 'when stage has warnings' do - context 'when using memoized warnings flag' do - context 'when there are warnings' do - let(:stage) { build(:ci_stage, warnings: 2) } - - it 'returns true using memoized value' do - expect(stage).not_to receive(:statuses) - expect(stage).to have_warnings - end - end - - context 'when there are no warnings' do - let(:stage) { build(:ci_stage, warnings: 0) } - - it 'returns false using memoized value' do - expect(stage).not_to receive(:statuses) - expect(stage).not_to have_warnings - end - end - - context 'when number of warnings is not a valid value' do - let(:stage) { build(:ci_stage, warnings: true) } - - it 'calculates statuses using database queries' do - expect(stage).to receive(:statuses).and_call_original - expect(stage).not_to have_warnings - end - end - end - - context 'when calculating warnings from statuses' do - before do - create(:ci_build, :failed, :allowed_to_fail, - stage: stage_name, pipeline: pipeline) - end - - it 'has warnings calculated from statuses' do - expect(stage).to receive(:statuses).and_call_original - expect(stage).to have_warnings - end - end - end - - context 'when stage does not have warnings' do - before do - create(:ci_build, :success, stage: stage_name, - pipeline: pipeline) - end - - it 'does not have warnings calculated from statuses' do - expect(stage).to receive(:statuses).and_call_original - expect(stage).not_to have_warnings - end - end - end - - def create_job(type, status: 'success', stage: stage_name, **opts) - create(type, pipeline: pipeline, stage: stage, status: status, **opts) - end -end -- cgit v1.2.3 From 8c3f65f802ebbb3176b35339958cf88a6602ebe6 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 1 Jun 2017 11:11:02 +0100 Subject: fixed boards_spec [ci skip] --- spec/features/boards/boards_spec.rb | 174 ++++++++++++++++++------------------ 1 file changed, 85 insertions(+), 89 deletions(-) (limited to 'spec') diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index ba27db23ced..c80453b8227 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -19,7 +19,7 @@ describe 'Issue Boards', feature: true, js: true do before do visit namespace_project_board_path(project.namespace, project, board) wait_for_requests - expect(page).to have_selector('.board', count: 2) + expect(page).to have_selector('.board', count: 3) end it 'shows blank state' do @@ -36,18 +36,18 @@ describe 'Issue Boards', feature: true, js: true do page.within(find('.board-blank-state')) do click_button("Nevermind, I'll use my own") end - expect(page).to have_selector('.board', count: 1) + expect(page).to have_selector('.board', count: 2) end it 'creates default lists' do - lists = ['To Do', 'Doing', 'Closed'] + lists = ['Backlog', 'To Do', 'Doing', 'Closed'] page.within(find('.board-blank-state')) do click_button('Add default lists') end wait_for_requests - expect(page).to have_selector('.board', count: 3) + expect(page).to have_selector('.board', count: 4) page.all('.board').each_with_index do |list, i| expect(list.find('.board-title')).to have_content(lists[i]) @@ -85,29 +85,25 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - expect(page).to have_selector('.board', count: 3) - expect(find('.board:nth-child(1)')).to have_selector('.card') + expect(page).to have_selector('.board', count: 4) expect(find('.board:nth-child(2)')).to have_selector('.card') expect(find('.board:nth-child(3)')).to have_selector('.card') - end - - it 'shows lists' do - expect(page).to have_selector('.board', count: 3) + expect(find('.board:nth-child(4)')).to have_selector('.card') end it 'shows description tooltip on list title' do - page.within('.board:nth-child(1)') do + page.within('.board:nth-child(2)') do expect(find('.board-title span.has-tooltip')[:title]).to eq('Test') end end it 'shows issues in lists' do - wait_for_board_cards(1, 8) - wait_for_board_cards(2, 2) + wait_for_board_cards(2, 8) + wait_for_board_cards(3, 2) end it 'shows confidential issues with icon' do - page.within(find('.board', match: :first)) do + page.within(find('.board:nth-child(2)')) do expect(page).to have_selector('.confidential-icon', count: 1) end end @@ -118,9 +114,9 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - expect(find('.board:nth-child(1)')).to have_selector('.card', count: 0) expect(find('.board:nth-child(2)')).to have_selector('.card', count: 0) - expect(find('.board:nth-child(3)')).to have_selector('.card', count: 1) + expect(find('.board:nth-child(3)')).to have_selector('.card', count: 0) + expect(find('.board:nth-child(4)')).to have_selector('.card', count: 1) end it 'search list' do @@ -129,32 +125,32 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - expect(find('.board:nth-child(1)')).to have_selector('.card', count: 1) - expect(find('.board:nth-child(2)')).to have_selector('.card', count: 0) + expect(find('.board:nth-child(2)')).to have_selector('.card', count: 1) expect(find('.board:nth-child(3)')).to have_selector('.card', count: 0) + expect(find('.board:nth-child(4)')).to have_selector('.card', count: 0) end it 'allows user to delete board' do - page.within(find('.board:nth-child(1)')) do + page.within(find('.board:nth-child(2)')) do find('.board-delete').click end wait_for_requests - expect(page).to have_selector('.board', count: 2) + expect(page).to have_selector('.board', count: 3) end it 'removes checkmark in new list dropdown after deleting' do click_button 'Add list' wait_for_requests - page.within(find('.board:nth-child(1)')) do + page.within(find('.board:nth-child(2)')) do find('.board-delete').click end wait_for_requests - expect(page).to have_selector('.board', count: 2) + expect(page).to have_selector('.board', count: 3) end it 'infinite scrolls list' do @@ -165,18 +161,18 @@ describe 'Issue Boards', feature: true, js: true do visit namespace_project_board_path(project.namespace, project, board) wait_for_requests - page.within(find('.board', match: :first)) do + page.within(find('.board:nth-child(2)')) do expect(page.find('.board-header')).to have_content('58') expect(page).to have_selector('.card', count: 20) expect(page).to have_content('Showing 20 of 58 issues') - evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight") + evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight") wait_for_requests expect(page).to have_selector('.card', count: 40) expect(page).to have_content('Showing 40 of 58 issues') - evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight") + evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight") wait_for_requests expect(page).to have_selector('.card', count: 58) @@ -186,83 +182,83 @@ describe 'Issue Boards', feature: true, js: true do context 'closed' do it 'shows list of closed issues' do - wait_for_board_cards(3, 1) + wait_for_board_cards(4, 1) wait_for_requests end it 'moves issue to closed' do - drag(list_from_index: 0, list_to_index: 2) + drag(list_from_index: 1, list_to_index: 3) - wait_for_board_cards(1, 7) - wait_for_board_cards(2, 2) + wait_for_board_cards(2, 7) wait_for_board_cards(3, 2) + wait_for_board_cards(4, 2) - expect(find('.board:nth-child(1)')).not_to have_content(issue9.title) - expect(find('.board:nth-child(3)')).to have_selector('.card', count: 2) - expect(find('.board:nth-child(3)')).to have_content(issue9.title) - expect(find('.board:nth-child(3)')).not_to have_content(planning.title) + expect(find('.board:nth-child(2)')).not_to have_content(issue9.title) + expect(find('.board:nth-child(4)')).to have_selector('.card', count: 2) + expect(find('.board:nth-child(4)')).to have_content(issue9.title) + expect(find('.board:nth-child(4)')).not_to have_content(planning.title) end it 'removes all of the same issue to closed' do - drag(list_from_index: 0, list_to_index: 2) + drag(list_from_index: 1, list_to_index: 3) - wait_for_board_cards(1, 7) - wait_for_board_cards(2, 2) + wait_for_board_cards(2, 7) wait_for_board_cards(3, 2) + wait_for_board_cards(4, 2) - expect(find('.board:nth-child(1)')).not_to have_content(issue9.title) - expect(find('.board:nth-child(3)')).to have_content(issue9.title) - expect(find('.board:nth-child(3)')).not_to have_content(planning.title) + expect(find('.board:nth-child(2)')).not_to have_content(issue9.title) + expect(find('.board:nth-child(4)')).to have_content(issue9.title) + expect(find('.board:nth-child(4)')).not_to have_content(planning.title) end end context 'lists' do it 'changes position of list' do - drag(list_from_index: 1, list_to_index: 0, selector: '.board-header') + drag(list_from_index: 2, list_to_index: 1, selector: '.board-header') - wait_for_board_cards(1, 2) - wait_for_board_cards(2, 8) - wait_for_board_cards(3, 1) + wait_for_board_cards(2, 2) + wait_for_board_cards(3, 8) + wait_for_board_cards(4, 1) - expect(find('.board:nth-child(1)')).to have_content(development.title) - expect(find('.board:nth-child(1)')).to have_content(planning.title) + expect(find('.board:nth-child(2)')).to have_content(development.title) + expect(find('.board:nth-child(2)')).to have_content(planning.title) end it 'issue moves between lists' do - drag(list_from_index: 0, from_index: 1, list_to_index: 1) + drag(list_from_index: 1, from_index: 1, list_to_index: 2) - wait_for_board_cards(1, 7) - wait_for_board_cards(2, 2) - wait_for_board_cards(3, 1) + wait_for_board_cards(2, 7) + wait_for_board_cards(3, 2) + wait_for_board_cards(4, 1) - expect(find('.board:nth-child(2)')).to have_content(issue6.title) - expect(find('.board:nth-child(2)').all('.card').last).not_to have_content(development.title) + expect(find('.board:nth-child(3)')).to have_content(issue6.title) + expect(find('.board:nth-child(3)').all('.card').last).not_to have_content(development.title) end it 'issue moves between lists' do - drag(list_from_index: 1, list_to_index: 0) + drag(list_from_index: 2, list_to_index: 1) - wait_for_board_cards(1, 9) - wait_for_board_cards(2, 1) + wait_for_board_cards(2, 9) wait_for_board_cards(3, 1) + wait_for_board_cards(4, 1) - expect(find('.board:nth-child(1)')).to have_content(issue7.title) - expect(find('.board:nth-child(1)').all('.card').first).not_to have_content(planning.title) + expect(find('.board:nth-child(2)')).to have_content(issue7.title) + expect(find('.board:nth-child(2)').all('.card').first).not_to have_content(planning.title) end it 'issue moves from closed' do - drag(list_from_index: 2, list_to_index: 1) + drag(list_from_index: 3, list_to_index: 2) - expect(find('.board:nth-child(2)')).to have_content(issue8.title) + expect(find('.board:nth-child(3)')).to have_content(issue8.title) - wait_for_board_cards(1, 8) - wait_for_board_cards(2, 3) - wait_for_board_cards(3, 0) + wait_for_board_cards(2, 8) + wait_for_board_cards(3, 3) + wait_for_board_cards(4, 0) end context 'issue card' do it 'shows assignee' do - page.within(find('.board', match: :first)) do + page.within(find('.board:nth-child(2)')) do expect(page).to have_selector('.avatar', count: 1) end end @@ -290,7 +286,7 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - expect(page).to have_selector('.board', count: 4) + expect(page).to have_selector('.board', count: 5) end it 'creates new list for Backlog label' do @@ -303,7 +299,7 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - expect(page).to have_selector('.board', count: 4) + expect(page).to have_selector('.board', count: 5) end it 'creates new list for Closed label' do @@ -316,7 +312,7 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - expect(page).to have_selector('.board', count: 4) + expect(page).to have_selector('.board', count: 5) end it 'keeps dropdown open after adding new list' do @@ -348,7 +344,7 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests wait_for_requests - expect(page).to have_selector('.board', count: 4) + expect(page).to have_selector('.board', count: 5) end end end @@ -360,8 +356,8 @@ describe 'Issue Boards', feature: true, js: true do submit_filter wait_for_requests - wait_for_board_cards(1, 1) - wait_for_empty_boards((2..3)) + wait_for_board_cards(2, 1) + wait_for_empty_boards((3..4)) end it 'filters by assignee' do @@ -371,8 +367,8 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - wait_for_board_cards(1, 1) - wait_for_empty_boards((2..3)) + wait_for_board_cards(2, 1) + wait_for_empty_boards((3..4)) end it 'filters by milestone' do @@ -381,9 +377,9 @@ describe 'Issue Boards', feature: true, js: true do submit_filter wait_for_requests - wait_for_board_cards(1, 1) - wait_for_board_cards(2, 0) + wait_for_board_cards(2, 1) wait_for_board_cards(3, 0) + wait_for_board_cards(4, 0) end it 'filters by label' do @@ -392,8 +388,8 @@ describe 'Issue Boards', feature: true, js: true do submit_filter wait_for_requests - wait_for_board_cards(1, 1) - wait_for_empty_boards((2..3)) + wait_for_board_cards(2, 1) + wait_for_empty_boards((3..4)) end it 'filters by label with space after reload' do @@ -403,17 +399,17 @@ describe 'Issue Boards', feature: true, js: true do # Test after reload page.evaluate_script 'window.location.reload()' - wait_for_board_cards(1, 1) - wait_for_empty_boards((2..3)) + wait_for_board_cards(2, 1) + wait_for_empty_boards((3..4)) wait_for_requests - page.within(find('.board', match: :first)) do + page.within(find('.board:nth-child(2)')) do expect(page.find('.board-header')).to have_content('1') expect(page).to have_selector('.card', count: 1) end - page.within(find('.board:nth-child(2)')) do + page.within(find('.board:nth-child(3)')) do expect(page.find('.board-header')).to have_content('0') expect(page).to have_selector('.card', count: 0) end @@ -424,12 +420,12 @@ describe 'Issue Boards', feature: true, js: true do click_filter_link(testing.title) submit_filter - wait_for_board_cards(1, 1) + wait_for_board_cards(2, 1) find('.clear-search').click submit_filter - wait_for_board_cards(1, 8) + wait_for_board_cards(2, 8) end it 'infinite scrolls list with label filter' do @@ -443,17 +439,17 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - page.within(find('.board', match: :first)) do + page.within(find('.board:nth-child(2)')) do expect(page.find('.board-header')).to have_content('51') expect(page).to have_selector('.card', count: 20) expect(page).to have_content('Showing 20 of 51 issues') - evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight") + evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight") expect(page).to have_selector('.card', count: 40) expect(page).to have_content('Showing 40 of 51 issues') - evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight") + evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight") expect(page).to have_selector('.card', count: 51) expect(page).to have_content('Showing all issues') @@ -471,12 +467,12 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - wait_for_board_cards(1, 1) - wait_for_empty_boards((2..3)) + wait_for_board_cards(2, 1) + wait_for_empty_boards((3..4)) end it 'filters by clicking label button on issue' do - page.within(find('.board', match: :first)) do + page.within(find('.board:nth-child(2)')) do expect(page).to have_selector('.card', count: 8) expect(find('.card', match: :first)).to have_content(bug.title) click_button(bug.title) @@ -489,12 +485,12 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - wait_for_board_cards(1, 1) - wait_for_empty_boards((2..3)) + wait_for_board_cards(2, 1) + wait_for_empty_boards((3..4)) end it 'removes label filter by clicking label button on issue' do - page.within(find('.board', match: :first)) do + page.within(find('.board:nth-child(2)')) do page.within(find('.card', match: :first)) do click_button(bug.title) end -- cgit v1.2.3 From 1a438e9f710edfa50408d93a363a240bdcd532c1 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 1 Jun 2017 12:21:34 +0200 Subject: Use stage_id column in code that needs to know about it --- spec/lib/gitlab/import_export/safe_model_attributes.yml | 1 + spec/services/ci/retry_build_service_spec.rb | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 96054c996fd..2388aea24d9 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -212,6 +212,7 @@ CommitStatus: - stage - trigger_request_id - stage_idx +- stage_id - tag - ref - user_id diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 7254e6b357a..2bd5af25847 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -18,11 +18,12 @@ describe Ci::RetryBuildService, :services do updated_at started_at finished_at queued_at erased_by erased_at auto_canceled_by].freeze + # TODO, move stage_id accessor to CLONE_ACCESSOR in a follow-up MR. IGNORE_ACCESSORS = %i[type lock_version target_url base_tags commit_id deployments erased_by_id last_deployment project_id runner_id tag_taggings taggings tags trigger_request_id - user_id auto_canceled_by_id retried].freeze + user_id auto_canceled_by_id retried stage_id].freeze shared_examples 'build duplication' do let(:build) do -- cgit v1.2.3 From 3a4b3a196ddaea1e20f770c551523c55d989a4ce Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 1 Jun 2017 12:39:29 +0100 Subject: fixed issue_ordering_spec --- spec/features/boards/issue_ordering_spec.rb | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'spec') diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb index 6c40cb2c9eb..1c289993e28 100644 --- a/spec/features/boards/issue_ordering_spec.rb +++ b/spec/features/boards/issue_ordering_spec.rb @@ -25,11 +25,11 @@ describe 'Issue Boards', :feature, :js do visit namespace_project_board_path(project.namespace, project, board) wait_for_requests - expect(page).to have_selector('.board', count: 2) + expect(page).to have_selector('.board', count: 3) end it 'has un-ordered issue as last issue' do - page.within(first('.board')) do + page.within(find('.board:nth-child(2)')) do expect(all('.card').last).to have_content(issue4.title) end end @@ -39,7 +39,7 @@ describe 'Issue Boards', :feature, :js do wait_for_requests - page.within(first('.board')) do + page.within(find('.board:nth-child(2)')) do expect(first('.card')).to have_content(issue4.title) end end @@ -50,7 +50,7 @@ describe 'Issue Boards', :feature, :js do visit namespace_project_board_path(project.namespace, project, board) wait_for_requests - expect(page).to have_selector('.board', count: 2) + expect(page).to have_selector('.board', count: 3) end it 'moves from middle to top' do @@ -113,50 +113,50 @@ describe 'Issue Boards', :feature, :js do visit namespace_project_board_path(project.namespace, project, board) wait_for_requests - expect(page).to have_selector('.board', count: 3) + expect(page).to have_selector('.board', count: 4) end it 'moves to top of another list' do - drag(list_from_index: 0, list_to_index: 1) + drag(list_from_index: 1, list_to_index: 2) wait_for_requests - expect(first('.board')).to have_selector('.card', count: 2) - expect(all('.board')[1]).to have_selector('.card', count: 4) + expect(find('.board:nth-child(2)')).to have_selector('.card', count: 2) + expect(all('.board')[2]).to have_selector('.card', count: 4) - page.within(all('.board')[1]) do + page.within(all('.board')[2]) do expect(first('.card')).to have_content(issue3.title) end end it 'moves to bottom of another list' do - drag(list_from_index: 0, list_to_index: 1, to_index: 2) + drag(list_from_index: 1, list_to_index: 2, to_index: 2) wait_for_requests - expect(first('.board')).to have_selector('.card', count: 2) - expect(all('.board')[1]).to have_selector('.card', count: 4) + expect(find('.board:nth-child(2)')).to have_selector('.card', count: 2) + expect(all('.board')[2]).to have_selector('.card', count: 4) - page.within(all('.board')[1]) do + page.within(all('.board')[2]) do expect(all('.card').last).to have_content(issue3.title) end end it 'moves to index of another list' do - drag(list_from_index: 0, list_to_index: 1, to_index: 1) + drag(list_from_index: 1, list_to_index: 2, to_index: 1) wait_for_requests - expect(first('.board')).to have_selector('.card', count: 2) - expect(all('.board')[1]).to have_selector('.card', count: 4) + expect(find('.board:nth-child(2)')).to have_selector('.card', count: 2) + expect(all('.board')[2]).to have_selector('.card', count: 4) - page.within(all('.board')[1]) do + page.within(all('.board')[2]) do expect(all('.card')[1]).to have_content(issue3.title) end end end - def drag(selector: '.board-list', list_from_index: 0, from_index: 0, to_index: 0, list_to_index: 0) + def drag(selector: '.board-list', list_from_index: 1, from_index: 0, to_index: 0, list_to_index: 1) drag_to(selector: selector, scrollable: '#board-app', list_from_index: list_from_index, -- cgit v1.2.3 From 8f5da962a363389c606d1f8427fcc36286ea2285 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 1 Jun 2017 14:54:10 +0100 Subject: fixed boards specs added key to assignee avatar loop --- spec/features/boards/add_issues_modal_spec.rb | 4 ++-- spec/features/boards/sidebar_spec.rb | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb index 32ac265814f..2b8edac4f10 100644 --- a/spec/features/boards/add_issues_modal_spec.rb +++ b/spec/features/boards/add_issues_modal_spec.rb @@ -231,7 +231,7 @@ describe 'Issue Boards add issue modal', :feature, :js do click_button 'Add 1 issue' end - page.within(first('.board')) do + page.within(find('.board:nth-child(2)')) do expect(page).to have_selector('.card') end end @@ -247,7 +247,7 @@ describe 'Issue Boards add issue modal', :feature, :js do click_button 'Add 1 issue' end - page.within(find('.board:nth-child(2)')) do + page.within(find('.board:nth-child(3)')) do expect(page).to have_selector('.card') end end diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index 34f4d765117..235e4899707 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -13,7 +13,7 @@ describe 'Issue Boards', feature: true, js: true do let!(:issue2) { create(:labeled_issue, project: project, labels: [development, stretch], relative_position: 1) } let(:board) { create(:board, project: project) } let!(:list) { create(:list, board: board, label: development, position: 0) } - let(:card) { first('.board').first('.card') } + let(:card) { find('.board:nth-child(2)').first('.card') } before do Timecop.freeze @@ -74,7 +74,7 @@ describe 'Issue Boards', feature: true, js: true do wait_for_requests - page.within(first('.board')) do + page.within(find('.board:nth-child(2)')) do expect(page).to have_selector('.card', count: 1) end end @@ -101,7 +101,7 @@ describe 'Issue Boards', feature: true, js: true do end it 'removes the assignee' do - card_two = first('.board').find('.card:nth-child(2)') + card_two = find('.board:nth-child(2)').find('.card:nth-child(2)') click_card(card_two) page.within('.assignee') do @@ -154,7 +154,7 @@ describe 'Issue Boards', feature: true, js: true do expect(page).to have_content(user.name) end - page.within(first('.board')) do + page.within(find('.board:nth-child(2)')) do find('.card:nth-child(2)').trigger('click') end -- cgit v1.2.3 From 0880094455f3b654733088a18070c17e45f87e74 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 1 Jun 2017 13:40:22 -0500 Subject: Make GroupsStore.store method non-static --- spec/javascripts/groups/group_item_spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/groups/group_item_spec.js b/spec/javascripts/groups/group_item_spec.js index ed441242085..609c45250f1 100644 --- a/spec/javascripts/groups/group_item_spec.js +++ b/spec/javascripts/groups/group_item_spec.js @@ -6,11 +6,13 @@ import { group1 } from './mock_data'; describe('Groups Component', () => { let GroupItemComponent; let component; + let store; let group; beforeEach((done) => { GroupItemComponent = Vue.extend(groupItemComponent); - group = GroupsStore.decorateGroup(group1); + store = new GroupsStore(); + group = store.decorateGroup(group1); component = new GroupItemComponent({ propsData: { -- cgit v1.2.3 From fe0b2f81c7c9680a11288e0cdffc3e80dc1e8d58 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 2 Jun 2017 12:16:11 +0200 Subject: Refine implementation of pipeline stage seeds --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 30 ++++++++----- spec/lib/gitlab/ci/stage/seed_spec.rb | 54 +++++++++++++++++++++++ spec/lib/gitlab/ci/stage/seeds_spec.rb | 66 ---------------------------- spec/models/ci/pipeline_spec.rb | 14 +++--- 4 files changed, 79 insertions(+), 85 deletions(-) create mode 100644 spec/lib/gitlab/ci/stage/seed_spec.rb delete mode 100644 spec/lib/gitlab/ci/stage/seeds_spec.rb (limited to 'spec') diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 7f652c17ed5..72b9cde10e7 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -91,15 +91,17 @@ module Ci spinach: { stage: 'test', script: 'spinach' }) end - it 'returns correctly fabricated stage seeds object' do - seeds = subject.stage_seeds(ref: 'master') + let(:pipeline) { create(:ci_empty_pipeline) } - expect(seeds.stages.size).to eq 2 - expect(seeds.stages.dig(0, :name)).to eq 'test' - expect(seeds.stages.dig(1, :name)).to eq 'deploy' - expect(seeds.jobs.dig(0, :name)).to eq 'rspec' - expect(seeds.jobs.dig(1, :name)).to eq 'spinach' - expect(seeds.jobs.dig(2, :name)).to eq 'production' + it 'correctly fabricates a stage seeds object' do + seeds = subject.stage_seeds(pipeline) + + expect(seeds.size).to eq 2 + expect(seeds.first.stage[:name]).to eq 'test' + expect(seeds.second.stage[:name]).to eq 'deploy' + expect(seeds.first.builds.dig(0, :name)).to eq 'rspec' + expect(seeds.first.builds.dig(1, :name)).to eq 'spinach' + expect(seeds.second.builds.dig(0, :name)).to eq 'production' end end @@ -109,12 +111,16 @@ module Ci spinach: { stage: 'test', script: 'spinach', only: ['tags'] }) end + let(:pipeline) do + create(:ci_empty_pipeline, ref: 'feature', tag: true) + end + it 'returns stage seeds only assigned to master to master' do - seeds = subject.stage_seeds(ref: 'feature', tag: true) + seeds = subject.stage_seeds(pipeline) - expect(seeds.stages.size).to eq 1 - expect(seeds.stages.dig(0, :name)).to eq 'test' - expect(seeds.jobs.dig(0, :name)).to eq 'spinach' + expect(seeds.size).to eq 1 + expect(seeds.first.stage[:name]).to eq 'test' + expect(seeds.first.builds.dig(0, :name)).to eq 'spinach' end end end diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb new file mode 100644 index 00000000000..15bcce04447 --- /dev/null +++ b/spec/lib/gitlab/ci/stage/seed_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +describe Gitlab::Ci::Stage::Seed do + let(:pipeline) { create(:ci_empty_pipeline) } + + let(:builds) do + [{ name: 'rspec' }, { name: 'spinach' }] + end + + subject do + described_class.new(pipeline, 'test', builds) + end + + describe '#stage' do + it 'returns hash attributes of a stage' do + expect(subject.stage).to be_a Hash + expect(subject.stage).to include(:name, :project) + end + end + + describe '#builds' do + it 'returns hash attributes of all builds' do + expect(subject.builds.size).to eq 2 + expect(subject.builds).to all(include(pipeline: pipeline)) + expect(subject.builds).to all(include(project: pipeline.project)) + expect(subject.builds).to all(include(ref: 'master')) + expect(subject.builds).to all(include(tag: false)) + expect(subject.builds) + .to all(include(trigger_request: pipeline.trigger_requests.first)) + end + end + + describe '#user=' do + let(:user) { create(:user) } + + it 'assignes relevant pipeline attributes' do + subject.user = user + + expect(subject.builds).to all(include(user: user)) + end + end + + describe '#create!' do + it 'creates all stages and builds' do + subject.create! + + expect(pipeline.reload.stages.count).to eq 1 + expect(pipeline.reload.builds.count).to eq 2 + expect(pipeline.builds).to all(satisfy { |job| job.stage_id.present? }) + expect(pipeline.builds).to all(satisfy { |job| job.pipeline.present? }) + expect(pipeline.builds).to all(satisfy { |job| job.project.present? }) + end + end +end diff --git a/spec/lib/gitlab/ci/stage/seeds_spec.rb b/spec/lib/gitlab/ci/stage/seeds_spec.rb deleted file mode 100644 index 3824a868fb2..00000000000 --- a/spec/lib/gitlab/ci/stage/seeds_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Ci::Stage::Seeds do - before do - subject.append_stage('test', [{ name: 'rspec' }, { name: 'spinach' }]) - subject.append_stage('deploy', [{ name: 'prod', script: 'cap deploy' }]) - end - - describe '#has_stages?' do - it { is_expected.to have_stages } - end - - describe '#stages' do - it 'returns hashes of all stages' do - expect(subject.stages.size).to eq 2 - expect(subject.stages).to all(be_a Hash) - end - end - - describe '#jobs' do - it 'returns all jobs in all stages' do - expect(subject.jobs.size).to eq 3 - end - end - - describe '#pipeline=' do - let(:pipeline) do - create(:ci_empty_pipeline, ref: 'feature', tag: true) - end - - it 'assignes relevant pipeline attributes' do - trigger_request = pipeline.trigger_requests.first - - subject.pipeline = pipeline - - expect(subject.stages).to all(include(pipeline: pipeline)) - expect(subject.stages).to all(include(project: pipeline.project)) - expect(subject.jobs).to all(include(pipeline: pipeline)) - expect(subject.jobs).to all(include(project: pipeline.project)) - expect(subject.jobs).to all(include(ref: 'feature')) - expect(subject.jobs).to all(include(tag: true)) - expect(subject.jobs).to all(include(trigger_request: trigger_request)) - end - end - - describe '#user=' do - let(:user) { create(:user) } - - it 'assignes relevant pipeline attributes' do - subject.user = user - - expect(subject.jobs).to all(include(user: user)) - end - end - - describe '#to_attributes' do - it 'exposes stage attributes with nested jobs' do - attributes = [{ name: 'test', builds_attributes: - [{ name: 'rspec' }, { name: 'spinach' }] }, - { name: 'deploy', builds_attributes: - [{ name: 'prod', script: 'cap deploy' }] }] - - expect(subject.to_attributes).to eq attributes - end - end -end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 17e10a5322e..63dbf1e9d8b 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -208,8 +208,8 @@ describe Ci::Pipeline, models: true do end it 'returns preseeded stage seeds object' do - expect(pipeline.stage_seeds).to be_a Gitlab::Ci::Stage::Seeds - expect(pipeline.stage_seeds.stages).to all(include(pipeline: pipeline)) + expect(pipeline.stage_seeds).to all(be_a Gitlab::Ci::Stage::Seed) + expect(pipeline.stage_seeds.count).to eq 1 end end @@ -513,17 +513,17 @@ describe Ci::Pipeline, models: true do end end - describe '#has_stages?' do - context 'when pipeline has stages' do + describe '#has_stage_seedss?' do + context 'when pipeline has stage seeds' do subject { create(:ci_pipeline_with_one_job) } - it { is_expected.to have_stages } + it { is_expected.to have_stage_seeds } end - context 'when pipeline does not have stages' do + context 'when pipeline does not have stage seeds' do subject { create(:ci_pipeline_without_jobs) } - it { is_expected.not_to have_stages } + it { is_expected.not_to have_stage_seeds } end end -- cgit v1.2.3 From 626cb8edc3f4421fe7e866c51fddc2715875ddda Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 2 Jun 2017 15:05:14 +0200 Subject: Fix invalid conditional in pipeline create service --- spec/lib/gitlab/ci/stage/seed_spec.rb | 3 +-- spec/services/ci/create_pipeline_service_spec.rb | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb index 15bcce04447..f4353040ce6 100644 --- a/spec/lib/gitlab/ci/stage/seed_spec.rb +++ b/spec/lib/gitlab/ci/stage/seed_spec.rb @@ -21,10 +21,9 @@ describe Gitlab::Ci::Stage::Seed do describe '#builds' do it 'returns hash attributes of all builds' do expect(subject.builds.size).to eq 2 - expect(subject.builds).to all(include(pipeline: pipeline)) - expect(subject.builds).to all(include(project: pipeline.project)) expect(subject.builds).to all(include(ref: 'master')) expect(subject.builds).to all(include(tag: false)) + expect(subject.builds).to all(include(project: pipeline.project)) expect(subject.builds) .to all(include(trigger_request: pipeline.trigger_requests.first)) end diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 674de2d80c1..fe5de2ce227 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -9,10 +9,10 @@ describe Ci::CreatePipelineService, :services do end describe '#execute' do - def execute_service(after: project.commit.id, message: 'Message', ref: 'refs/heads/master') + def execute_service(after_sha: project.commit.id, message: 'Message', ref: 'refs/heads/master') params = { ref: ref, before: '00000000', - after: after, + after: after_sha, commits: [{ message: message }] } described_class.new(project, user, params).execute @@ -30,6 +30,7 @@ describe Ci::CreatePipelineService, :services do it 'creates a pipeline' do expect(pipeline).to be_kind_of(Ci::Pipeline) expect(pipeline).to be_valid + expect(pipeline).to be_persisted expect(pipeline).to eq(project.pipelines.last) expect(pipeline).to have_attributes(user: user) expect(pipeline).to have_attributes(status: 'pending') -- cgit v1.2.3 From a980a4f63856af0b4edc54b2457eeb80321e4f87 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 2 Jun 2017 17:25:18 +0100 Subject: added tests for collapsing --- spec/javascripts/boards/components/board_spec.js | 112 +++++++++++++++++++++++ spec/javascripts/fixtures/boards.rb | 28 ++++++ spec/support/javascript_fixtures_helpers.rb | 2 +- 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 spec/javascripts/boards/components/board_spec.js create mode 100644 spec/javascripts/fixtures/boards.rb (limited to 'spec') diff --git a/spec/javascripts/boards/components/board_spec.js b/spec/javascripts/boards/components/board_spec.js new file mode 100644 index 00000000000..c4e8966ad6c --- /dev/null +++ b/spec/javascripts/boards/components/board_spec.js @@ -0,0 +1,112 @@ +import Vue from 'vue'; +import '~/boards/services/board_service'; +import '~/boards/components/board'; +import '~/boards/models/list'; + +describe('Board component', () => { + let vm; + let el; + + beforeEach((done) => { + loadFixtures('boards/show.html.raw'); + + el = document.createElement('div'); + document.body.appendChild(el); + + // eslint-disable-next-line no-undef + gl.boardService = new BoardService('/', '/', 1); + + vm = new gl.issueBoards.Board({ + propsData: { + boardId: '1', + disabled: false, + issueLinkBase: '/', + rootPath: '/', + // eslint-disable-next-line no-undef + list: new List({ + id: 1, + position: 0, + title: 'test', + list_type: 'backlog', + }), + }, + }).$mount(el); + + Vue.nextTick(done); + }); + + afterEach(() => { + vm.$destroy(); + + // remove the component from the DOM + document.querySelector('.board').remove(); + + localStorage.removeItem(`boards.${vm.boardId}.${vm.list.type}.expanded`); + }); + + it('board is expandable when list type is backlog', () => { + expect( + vm.$el.classList.contains('is-expandable'), + ).toBe(true); + }); + + it('board is expandable when list type is closed', (done) => { + vm.list.type = 'closed'; + + Vue.nextTick(() => { + expect( + vm.$el.classList.contains('is-expandable'), + ).toBe(true); + + done(); + }); + }); + + it('board is not expandable when list type is label', (done) => { + vm.list.type = 'label'; + vm.list.isExpandable = false; + + Vue.nextTick(() => { + expect( + vm.$el.classList.contains('is-expandable'), + ).toBe(false); + + done(); + }); + }); + + it('collapses when clicking header', (done) => { + vm.$el.querySelector('.board-header').click(); + + Vue.nextTick(() => { + expect( + vm.$el.classList.contains('is-collapsed'), + ).toBe(true); + + done(); + }); + }); + + it('created sets isExpanded to true from localStorage', (done) => { + vm.$el.querySelector('.board-header').click(); + + return Vue.nextTick() + .then(() => { + expect( + vm.$el.classList.contains('is-collapsed'), + ).toBe(true); + + // call created manually + vm.$options.created[0].call(vm); + + return Vue.nextTick(); + }) + .then(() => { + expect( + vm.$el.classList.contains('is-collapsed'), + ).toBe(true); + + done(); + }); + }); +}); diff --git a/spec/javascripts/fixtures/boards.rb b/spec/javascripts/fixtures/boards.rb new file mode 100644 index 00000000000..d7c3dc0a235 --- /dev/null +++ b/spec/javascripts/fixtures/boards.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe Projects::BoardsController, '(JavaScript fixtures)', type: :controller do + include JavaScriptFixturesHelpers + + let(:admin) { create(:admin) } + let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} + let(:project) { create(:project, :repository, namespace: namespace, path: 'boards-project') } + + render_views + + before(:all) do + clean_frontend_fixtures('boards/') + end + + before(:each) do + sign_in(admin) + end + + it 'boards/show.html.raw' do |example| + get(:index, + namespace_id: project.namespace, + project_id: project) + + expect(response).to be_success + store_frontend_fixture(response, example.description) + end +end diff --git a/spec/support/javascript_fixtures_helpers.rb b/spec/support/javascript_fixtures_helpers.rb index a982b159b48..aace4b3adee 100644 --- a/spec/support/javascript_fixtures_helpers.rb +++ b/spec/support/javascript_fixtures_helpers.rb @@ -48,7 +48,7 @@ module JavaScriptFixturesHelpers link_tags = doc.css('link') link_tags.remove - scripts = doc.css("script:not([type='text/template'])") + scripts = doc.css("script:not([type='text/template']):not([type='text/x-template'])") scripts.remove fixture = doc.to_html -- cgit v1.2.3 From 3d70eeb5bb9dac8073a149547dc3b85c90d65e7d Mon Sep 17 00:00:00 2001 From: Alexander Randa Date: Fri, 31 Mar 2017 12:54:38 +0000 Subject: Implement ability to update deploy keys --- spec/features/admin/admin_deploy_keys_spec.rb | 63 ++++++++++++----- .../projects/settings/repository_settings_spec.rb | 78 ++++++++++++++++++++++ .../javascripts/deploy_keys/components/key_spec.js | 18 ++++- spec/policies/deploy_key_policy_spec.rb | 56 ++++++++++++++++ .../settings/deploy_keys_presenter_spec.rb | 4 -- spec/requests/api/deploy_keys_spec.rb | 69 +++++++++++++++---- spec/routing/project_routing_spec.rb | 4 +- spec/serializers/deploy_key_entity_spec.rb | 61 +++++++++++------ 8 files changed, 292 insertions(+), 61 deletions(-) create mode 100644 spec/features/projects/settings/repository_settings_spec.rb create mode 100644 spec/policies/deploy_key_policy_spec.rb (limited to 'spec') diff --git a/spec/features/admin/admin_deploy_keys_spec.rb b/spec/features/admin/admin_deploy_keys_spec.rb index c0b6995a84a..5f5fa4e932a 100644 --- a/spec/features/admin/admin_deploy_keys_spec.rb +++ b/spec/features/admin/admin_deploy_keys_spec.rb @@ -11,40 +11,67 @@ RSpec.describe 'admin deploy keys', type: :feature do it 'show all public deploy keys' do visit admin_deploy_keys_path - expect(page).to have_content(deploy_key.title) - expect(page).to have_content(another_deploy_key.title) + page.within(find('.deploy-keys-list', match: :first)) do + expect(page).to have_content(deploy_key.title) + expect(page).to have_content(another_deploy_key.title) + end end - describe 'create new deploy key' do + describe 'create a new deploy key' do + let(:new_ssh_key) { attributes_for(:key)[:key] } + before do visit admin_deploy_keys_path click_link 'New deploy key' end - it 'creates new deploy key' do - fill_deploy_key + it 'creates a new deploy key' do + fill_in 'deploy_key_title', with: 'laptop' + fill_in 'deploy_key_key', with: new_ssh_key + check 'deploy_key_can_push' click_button 'Create' - expect_renders_new_key - end + expect(current_path).to eq admin_deploy_keys_path - it 'creates new deploy key with write access' do - fill_deploy_key - check "deploy_key_can_push" - click_button "Create" + page.within(find('.deploy-keys-list', match: :first)) do + expect(page).to have_content('laptop') + expect(page).to have_content('Yes') + end + end + end - expect_renders_new_key - expect(page).to have_content('Yes') + describe 'update an existing deploy key' do + before do + visit admin_deploy_keys_path + find('tr', text: deploy_key.title).click_link('Edit') end - def expect_renders_new_key + it 'updates an existing deploy key' do + fill_in 'deploy_key_title', with: 'new-title' + check 'deploy_key_can_push' + click_button 'Save changes' + expect(current_path).to eq admin_deploy_keys_path - expect(page).to have_content('laptop') + + page.within(find('.deploy-keys-list', match: :first)) do + expect(page).to have_content('new-title') + expect(page).to have_content('Yes') + end end + end - def fill_deploy_key - fill_in 'deploy_key_title', with: 'laptop' - fill_in 'deploy_key_key', with: 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzrEJUIR6Y03TCE9rIJ+GqTBvgb8t1jI9h5UBzCLuK4VawOmkLornPqLDrGbm6tcwM/wBrrLvVOqi2HwmkKEIecVO0a64A4rIYScVsXIniHRS6w5twyn1MD3sIbN+socBDcaldECQa2u1dI3tnNVcs8wi77fiRe7RSxePsJceGoheRQgC8AZ510UdIlO+9rjIHUdVN7LLyz512auAfYsgx1OfablkQ/XJcdEwDNgi9imI6nAXhmoKUm1IPLT2yKajTIC64AjLOnE0YyCh6+7RFMpiMyu1qiOCpdjYwTgBRiciNRZCH8xIedyCoAmiUgkUT40XYHwLuwiPJICpkAzp7Q== user@laptop' + describe 'remove an existing deploy key' do + before do + visit admin_deploy_keys_path + end + + it 'removes an existing deploy key' do + find('tr', text: deploy_key.title).click_link('Remove') + + expect(current_path).to eq admin_deploy_keys_path + page.within(find('.deploy-keys-list', match: :first)) do + expect(page).not_to have_content(deploy_key.title) + end end end end diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb new file mode 100644 index 00000000000..4cc38c5286e --- /dev/null +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper' + +feature 'Repository settings', feature: true do + let(:project) { create(:project_empty_repo) } + let(:user) { create(:user) } + let(:role) { :developer } + + background do + project.team << [user, role] + login_as(user) + end + + context 'for developer' do + given(:role) { :developer } + + scenario 'is not allowed to view' do + visit namespace_project_settings_repository_path(project.namespace, project) + + expect(page.status_code).to eq(404) + end + end + + context 'for master' do + given(:role) { :master } + + context 'Deploy Keys', js: true do + let(:private_deploy_key) { create(:deploy_key, title: 'private_deploy_key', public: false) } + let(:public_deploy_key) { create(:another_deploy_key, title: 'public_deploy_key', public: true) } + let(:new_ssh_key) { attributes_for(:key)[:key] } + + scenario 'get list of keys' do + project.deploy_keys << private_deploy_key + project.deploy_keys << public_deploy_key + + visit namespace_project_settings_repository_path(project.namespace, project) + + expect(page.status_code).to eq(200) + expect(page).to have_content('private_deploy_key') + expect(page).to have_content('public_deploy_key') + end + + scenario 'add a new deploy key' do + visit namespace_project_settings_repository_path(project.namespace, project) + + fill_in 'deploy_key_title', with: 'new_deploy_key' + fill_in 'deploy_key_key', with: new_ssh_key + check 'deploy_key_can_push' + click_button 'Add key' + + expect(page).to have_content('new_deploy_key') + expect(page).to have_content('Write access allowed') + end + + scenario 'edit an existing deploy key' do + project.deploy_keys << private_deploy_key + visit namespace_project_settings_repository_path(project.namespace, project) + + find('li', text: private_deploy_key.title).click_link('Edit') + + fill_in 'deploy_key_title', with: 'updated_deploy_key' + check 'deploy_key_can_push' + click_button 'Save changes' + + expect(page).to have_content('updated_deploy_key') + expect(page).to have_content('Write access allowed') + end + + scenario 'remove an existing deploy key' do + project.deploy_keys << private_deploy_key + visit namespace_project_settings_repository_path(project.namespace, project) + + find('li', text: private_deploy_key.title).click_button('Remove') + + expect(page).not_to have_content(private_deploy_key.title) + end + end + end +end diff --git a/spec/javascripts/deploy_keys/components/key_spec.js b/spec/javascripts/deploy_keys/components/key_spec.js index 793ab8c451d..a4b98f6140d 100644 --- a/spec/javascripts/deploy_keys/components/key_spec.js +++ b/spec/javascripts/deploy_keys/components/key_spec.js @@ -39,9 +39,15 @@ describe('Deploy keys key', () => { ).toBe(`created ${gl.utils.getTimeago().format(deployKey.created_at)}`); }); + it('shows edit button', () => { + expect( + vm.$el.querySelectorAll('.btn')[0].textContent.trim(), + ).toBe('Edit'); + }); + it('shows remove button', () => { expect( - vm.$el.querySelector('.btn').textContent.trim(), + vm.$el.querySelectorAll('.btn')[1].textContent.trim(), ).toBe('Remove'); }); @@ -71,9 +77,15 @@ describe('Deploy keys key', () => { setTimeout(done); }); + it('shows edit button', () => { + expect( + vm.$el.querySelectorAll('.btn')[0].textContent.trim(), + ).toBe('Edit'); + }); + it('shows enable button', () => { expect( - vm.$el.querySelector('.btn').textContent.trim(), + vm.$el.querySelectorAll('.btn')[1].textContent.trim(), ).toBe('Enable'); }); @@ -82,7 +94,7 @@ describe('Deploy keys key', () => { Vue.nextTick(() => { expect( - vm.$el.querySelector('.btn').textContent.trim(), + vm.$el.querySelectorAll('.btn')[1].textContent.trim(), ).toBe('Disable'); done(); diff --git a/spec/policies/deploy_key_policy_spec.rb b/spec/policies/deploy_key_policy_spec.rb new file mode 100644 index 00000000000..28e10f0bfe2 --- /dev/null +++ b/spec/policies/deploy_key_policy_spec.rb @@ -0,0 +1,56 @@ +require 'spec_helper' + +describe DeployKeyPolicy, models: true do + subject { described_class.abilities(current_user, deploy_key).to_set } + + describe 'updating a deploy_key' do + context 'when a regular user' do + let(:current_user) { create(:user) } + + context 'tries to update private deploy key attached to project' do + let(:deploy_key) { create(:deploy_key, public: false) } + let(:project) { create(:project_empty_repo) } + + before do + project.add_master(current_user) + project.deploy_keys << deploy_key + end + + it { is_expected.to include(:update_deploy_key) } + end + + context 'tries to update private deploy key attached to other project' do + let(:deploy_key) { create(:deploy_key, public: false) } + let(:other_project) { create(:project_empty_repo) } + + before do + other_project.deploy_keys << deploy_key + end + + it { is_expected.not_to include(:update_deploy_key) } + end + + context 'tries to update public deploy key' do + let(:deploy_key) { create(:another_deploy_key, public: true) } + + it { is_expected.not_to include(:update_deploy_key) } + end + end + + context 'when an admin user' do + let(:current_user) { create(:user, :admin) } + + context ' tries to update private deploy key' do + let(:deploy_key) { create(:deploy_key, public: false) } + + it { is_expected.to include(:update_deploy_key) } + end + + context 'when an admin user tries to update public deploy key' do + let(:deploy_key) { create(:another_deploy_key, public: true) } + + it { is_expected.to include(:update_deploy_key) } + end + end + end +end diff --git a/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb b/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb index 6443f86b6a1..5c39e1b5f96 100644 --- a/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb +++ b/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb @@ -51,10 +51,6 @@ describe Projects::Settings::DeployKeysPresenter do expect(presenter.available_project_keys).not_to be_empty end - it 'returns false if any available_project_keys are enabled' do - expect(presenter.any_available_project_keys_enabled?).to eq(true) - end - it 'returns the available_project_keys size' do expect(presenter.available_project_keys_size).to eq(1) end diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb index 843e9862b0c..4d9cd5f3a27 100644 --- a/spec/requests/api/deploy_keys_spec.rb +++ b/spec/requests/api/deploy_keys_spec.rb @@ -13,7 +13,7 @@ describe API::DeployKeys do describe 'GET /deploy_keys' do context 'when unauthenticated' do - it 'should return authentication error' do + it 'returns authentication error' do get api('/deploy_keys') expect(response.status).to eq(401) @@ -21,7 +21,7 @@ describe API::DeployKeys do end context 'when authenticated as non-admin user' do - it 'should return a 403 error' do + it 'returns a 403 error' do get api('/deploy_keys', user) expect(response.status).to eq(403) @@ -29,7 +29,7 @@ describe API::DeployKeys do end context 'when authenticated as admin' do - it 'should return all deploy keys' do + it 'returns all deploy keys' do get api('/deploy_keys', admin) expect(response.status).to eq(200) @@ -43,7 +43,7 @@ describe API::DeployKeys do describe 'GET /projects/:id/deploy_keys' do before { deploy_key } - it 'should return array of ssh keys' do + it 'returns array of ssh keys' do get api("/projects/#{project.id}/deploy_keys", admin) expect(response).to have_http_status(200) @@ -54,14 +54,14 @@ describe API::DeployKeys do end describe 'GET /projects/:id/deploy_keys/:key_id' do - it 'should return a single key' do + it 'returns a single key' do get api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin) expect(response).to have_http_status(200) expect(json_response['title']).to eq(deploy_key.title) end - it 'should return 404 Not Found with invalid ID' do + it 'returns 404 Not Found with invalid ID' do get api("/projects/#{project.id}/deploy_keys/404", admin) expect(response).to have_http_status(404) @@ -69,26 +69,26 @@ describe API::DeployKeys do end describe 'POST /projects/:id/deploy_keys' do - it 'should not create an invalid ssh key' do + it 'does not create an invalid ssh key' do post api("/projects/#{project.id}/deploy_keys", admin), { title: 'invalid key' } expect(response).to have_http_status(400) expect(json_response['error']).to eq('key is missing') end - it 'should not create a key without title' do + it 'does not create a key without title' do post api("/projects/#{project.id}/deploy_keys", admin), key: 'some key' expect(response).to have_http_status(400) expect(json_response['error']).to eq('title is missing') end - it 'should create new ssh key' do + it 'creates new ssh key' do key_attrs = attributes_for :another_key expect do post api("/projects/#{project.id}/deploy_keys", admin), key_attrs - end.to change{ project.deploy_keys.count }.by(1) + end.to change { project.deploy_keys.count }.by(1) end it 'returns an existing ssh key when attempting to add a duplicate' do @@ -117,10 +117,53 @@ describe API::DeployKeys do end end + describe 'PUT /projects/:id/deploy_keys/:key_id' do + let(:private_deploy_key) { create(:another_deploy_key, public: false) } + let(:project_private_deploy_key) do + create(:deploy_keys_project, project: project, deploy_key: private_deploy_key) + end + + it 'updates a public deploy key as admin' do + expect do + put api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin), { title: 'new title' } + end.not_to change(deploy_key, :title) + + expect(response).to have_http_status(200) + end + + it 'does not update a public deploy key as non admin' do + expect do + put api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", user), { title: 'new title' } + end.not_to change(deploy_key, :title) + + expect(response).to have_http_status(404) + end + + it 'does not update a private key with invalid title' do + project_private_deploy_key + + expect do + put api("/projects/#{project.id}/deploy_keys/#{private_deploy_key.id}", admin), { title: '' } + end.not_to change(deploy_key, :title) + + expect(response).to have_http_status(400) + end + + it 'updates a private ssh key with correct attributes' do + project_private_deploy_key + + put api("/projects/#{project.id}/deploy_keys/#{private_deploy_key.id}", admin), { title: 'new title', can_push: true } + + expect(json_response['id']).to eq(private_deploy_key.id) + expect(json_response['title']).to eq('new title') + expect(json_response['can_push']).to eq(true) + end + end + describe 'DELETE /projects/:id/deploy_keys/:key_id' do before { deploy_key } - it 'should delete existing key' do + it 'deletes existing key' do expect do delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin) @@ -128,7 +171,7 @@ describe API::DeployKeys do end.to change{ project.deploy_keys.count }.by(-1) end - it 'should return 404 Not Found with invalid ID' do + it 'returns 404 Not Found with invalid ID' do delete api("/projects/#{project.id}/deploy_keys/404", admin) expect(response).to have_http_status(404) @@ -150,7 +193,7 @@ describe API::DeployKeys do end context 'when authenticated as non-admin user' do - it 'should return a 404 error' do + it 'returns a 404 error' do post api("/projects/#{project2.id}/deploy_keys/#{deploy_key.id}/enable", user) expect(response).to have_http_status(404) diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 54417f6b3e1..0a6778ae2ef 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -201,10 +201,12 @@ describe 'project routing' do # POST /:project_id/deploy_keys(.:format) deploy_keys#create # new_project_deploy_key GET /:project_id/deploy_keys/new(.:format) deploy_keys#new # project_deploy_key GET /:project_id/deploy_keys/:id(.:format) deploy_keys#show + # edit_project_deploy_key GET /:project_id/deploy_keys/:id/edit(.:format) deploy_keys#edit + # project_deploy_key PATCH /:project_id/deploy_keys/:id(.:format) deploy_keys#update # DELETE /:project_id/deploy_keys/:id(.:format) deploy_keys#destroy describe Projects::DeployKeysController, 'routing' do it_behaves_like 'RESTful project resources' do - let(:actions) { [:index, :new, :create] } + let(:actions) { [:index, :new, :create, :edit, :update] } let(:controller) { 'deploy_keys' } end end diff --git a/spec/serializers/deploy_key_entity_spec.rb b/spec/serializers/deploy_key_entity_spec.rb index e73fbe190ca..ed89fccc3d0 100644 --- a/spec/serializers/deploy_key_entity_spec.rb +++ b/spec/serializers/deploy_key_entity_spec.rb @@ -12,27 +12,44 @@ describe DeployKeyEntity do let(:entity) { described_class.new(deploy_key, user: user) } - it 'returns deploy keys with projects a user can read' do - expected_result = { - id: deploy_key.id, - user_id: deploy_key.user_id, - title: deploy_key.title, - fingerprint: deploy_key.fingerprint, - can_push: deploy_key.can_push, - destroyed_when_orphaned: true, - almost_orphaned: false, - created_at: deploy_key.created_at, - updated_at: deploy_key.updated_at, - projects: [ - { - id: project.id, - name: project.name, - full_path: namespace_project_path(project.namespace, project), - full_name: project.full_name - } - ] - } - - expect(entity.as_json).to eq(expected_result) + describe 'returns deploy keys with projects a user can read' do + let(:expected_result) do + { + id: deploy_key.id, + user_id: deploy_key.user_id, + title: deploy_key.title, + fingerprint: deploy_key.fingerprint, + can_push: deploy_key.can_push, + destroyed_when_orphaned: true, + almost_orphaned: false, + created_at: deploy_key.created_at, + updated_at: deploy_key.updated_at, + can_edit: false, + projects: [ + { + id: project.id, + name: project.name, + full_path: namespace_project_path(project.namespace, project), + full_name: project.full_name + } + ] + } + end + + it { expect(entity.as_json).to eq(expected_result) } + end + + describe 'returns can_edit true if user is a master of project' do + before do + project.add_master(user) + end + + it { expect(entity.as_json).to include(can_edit: true) } + end + + describe 'returns can_edit true if a user admin' do + let(:user) { create(:user, :admin) } + + it { expect(entity.as_json).to include(can_edit: true) } end end -- cgit v1.2.3 From 0f4050430d400daffbc5a68b15d79b896bb8a692 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Fri, 19 May 2017 17:03:10 +0200 Subject: Split metrics from health controller into metrics controller --- spec/controllers/health_controller_spec.rb | 39 ---------------------- spec/controllers/metrics_controller_spec.rb | 51 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 39 deletions(-) create mode 100644 spec/controllers/metrics_controller_spec.rb (limited to 'spec') diff --git a/spec/controllers/health_controller_spec.rb b/spec/controllers/health_controller_spec.rb index b8b6e0c3a88..e7c19b47a6a 100644 --- a/spec/controllers/health_controller_spec.rb +++ b/spec/controllers/health_controller_spec.rb @@ -54,43 +54,4 @@ describe HealthController do end end end - - describe '#metrics' do - context 'authorization token provided' do - before do - request.headers['TOKEN'] = token - end - - it 'returns DB ping metrics' do - get :metrics - expect(response.body).to match(/^db_ping_timeout 0$/) - expect(response.body).to match(/^db_ping_success 1$/) - expect(response.body).to match(/^db_ping_latency [0-9\.]+$/) - end - - it 'returns Redis ping metrics' do - get :metrics - expect(response.body).to match(/^redis_ping_timeout 0$/) - expect(response.body).to match(/^redis_ping_success 1$/) - expect(response.body).to match(/^redis_ping_latency [0-9\.]+$/) - end - - it 'returns file system check metrics' do - get :metrics - expect(response.body).to match(/^filesystem_access_latency{shard="default"} [0-9\.]+$/) - expect(response.body).to match(/^filesystem_accessible{shard="default"} 1$/) - expect(response.body).to match(/^filesystem_write_latency{shard="default"} [0-9\.]+$/) - expect(response.body).to match(/^filesystem_writable{shard="default"} 1$/) - expect(response.body).to match(/^filesystem_read_latency{shard="default"} [0-9\.]+$/) - expect(response.body).to match(/^filesystem_readable{shard="default"} 1$/) - end - end - - context 'without authorization token' do - it 'returns proper response' do - get :metrics - expect(response.status).to eq(404) - end - end - end end diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb new file mode 100644 index 00000000000..d2d4b361a62 --- /dev/null +++ b/spec/controllers/metrics_controller_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe MetricsController do + include StubENV + + let(:token) { current_application_settings.health_check_access_token } + let(:json_response) { JSON.parse(response.body) } + + before do + stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') + end + + describe '#metrics' do + context 'authorization token provided' do + before do + request.headers['TOKEN'] = token + end + + it 'returns DB ping metrics' do + get :metrics + expect(response.body).to match(/^db_ping_timeout 0$/) + expect(response.body).to match(/^db_ping_success 1$/) + expect(response.body).to match(/^db_ping_latency [0-9\.]+$/) + end + + it 'returns Redis ping metrics' do + get :metrics + expect(response.body).to match(/^redis_ping_timeout 0$/) + expect(response.body).to match(/^redis_ping_success 1$/) + expect(response.body).to match(/^redis_ping_latency [0-9\.]+$/) + end + + it 'returns file system check metrics' do + get :metrics + expect(response.body).to match(/^filesystem_access_latency{shard="default"} [0-9\.]+$/) + expect(response.body).to match(/^filesystem_accessible{shard="default"} 1$/) + expect(response.body).to match(/^filesystem_write_latency{shard="default"} [0-9\.]+$/) + expect(response.body).to match(/^filesystem_writable{shard="default"} 1$/) + expect(response.body).to match(/^filesystem_read_latency{shard="default"} [0-9\.]+$/) + expect(response.body).to match(/^filesystem_readable{shard="default"} 1$/) + end + end + + context 'without authorization token' do + it 'returns proper response' do + get :metrics + expect(response.status).to eq(404) + end + end + end +end -- cgit v1.2.3 From ef9d9ddeb2e063fa8ed1b01e4f82cc9662b919b2 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Mon, 22 May 2017 15:47:04 +0200 Subject: Add tests for metrics behavior --- spec/lib/gitlab/metrics_spec.rb | 125 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb index 208a8d028cd..65bd06cda08 100644 --- a/spec/lib/gitlab/metrics_spec.rb +++ b/spec/lib/gitlab/metrics_spec.rb @@ -13,6 +13,18 @@ describe Gitlab::Metrics do end end + describe '.prometheus_metrics_enabled?' do + it 'returns a boolean' do + expect([true, false].include?(described_class.prometheus_metrics_enabled?)).to eq(true) + end + end + + describe '.influx_metrics_enabled?' do + it 'returns a boolean' do + expect([true, false].include?(described_class.influx_metrics_enabled?)).to eq(true) + end + end + describe '.submit_metrics' do it 'prepares and writes the metrics to InfluxDB' do connection = double(:connection) @@ -177,4 +189,117 @@ describe Gitlab::Metrics do end end end + + shared_examples 'prometheus metrics API' do + describe '#counter' do + subject { described_class.counter(:couter, 'doc') } + + describe '#increment' do + it { expect { subject.increment }.not_to raise_exception } + it { expect { subject.increment({}) }.not_to raise_exception } + it { expect { subject.increment({}, 1) }.not_to raise_exception } + end + end + + describe '#summary' do + subject { described_class.summary(:summary, 'doc') } + + describe '#observe' do + it { expect { subject.observe({}, 2) }.not_to raise_exception } + end + end + + describe '#gauge' do + subject { described_class.gauge(:gauge, 'doc') } + + describe '#observe' do + it { expect { subject.set({}, 1) }.not_to raise_exception } + end + end + + describe '#histogram' do + subject { described_class.histogram(:histogram, 'doc') } + + describe '#observe' do + it { expect { subject.observe({}, 2) }.not_to raise_exception } + end + end + end + + context 'prometheus metrics disabled' do + before do + allow(described_class).to receive(:prometheus_metrics_enabled?).and_return(false) + end + + it_behaves_like 'prometheus metrics API' + + describe '#dummy_metric' do + subject { described_class.provide_metric(:test) } + + it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } + end + + describe '#counter' do + subject { described_class.counter(:counter, 'doc') } + + it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } + + end + + describe '#summary' do + subject { described_class.summary(:summary, 'doc') } + + it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } + end + + describe '#gauge' do + subject { described_class.gauge(:gauge, 'doc') } + + it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } + end + + describe '#histogram' do + subject { described_class.histogram(:histogram, 'doc') } + + it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } + end + end + + context 'prometheus metrics enabled' do + before do + allow(described_class).to receive(:prometheus_metrics_enabled?).and_return(true) + end + + it_behaves_like 'prometheus metrics API' + + describe '#dummy_metric' do + subject { described_class.provide_metric(:test) } + + it { is_expected.to be_nil } + end + + describe '#counter' do + subject { described_class.counter(:name, 'doc') } + + it { is_expected.not_to be_a(Gitlab::Metrics::DummyMetric) } + end + + describe '#summary' do + subject { described_class.summary(:name, 'doc') } + + it { is_expected.not_to be_a(Gitlab::Metrics::DummyMetric) } + end + + describe '#gauge' do + subject { described_class.gauge(:name, 'doc') } + + it { is_expected.not_to be_a(Gitlab::Metrics::DummyMetric) } + end + + describe '#histogram' do + subject { described_class.histogram(:name, 'doc') } + + it { is_expected.not_to be_a(Gitlab::Metrics::DummyMetric) } + end + end end -- cgit v1.2.3 From 21561f3434021ad35d45c449f489802fd1dced67 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Mon, 22 May 2017 19:49:34 +0200 Subject: Correctly handle temporary folder for testing multiproces metrics --- spec/controllers/metrics_controller_spec.rb | 9 +++++++++ spec/lib/gitlab/metrics_spec.rb | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb index d2d4b361a62..7f2dcd3544f 100644 --- a/spec/controllers/metrics_controller_spec.rb +++ b/spec/controllers/metrics_controller_spec.rb @@ -6,8 +6,17 @@ describe MetricsController do let(:token) { current_application_settings.health_check_access_token } let(:json_response) { JSON.parse(response.body) } + around do |examples| + Dir.mktmpdir do |tmp_dir| + @metrics_multiproc_dir = tmp_dir + examples.run + end + end + before do stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') + stub_env('prometheus_multiproc_dir', @metrics_multiproc_dir) + allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(true) end describe '#metrics' do diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb index 65bd06cda08..020bdbacead 100644 --- a/spec/lib/gitlab/metrics_spec.rb +++ b/spec/lib/gitlab/metrics_spec.rb @@ -243,7 +243,6 @@ describe Gitlab::Metrics do subject { described_class.counter(:counter, 'doc') } it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } - end describe '#summary' do -- cgit v1.2.3 From 62fe37e3f8e8ccee90a748324e1b40a54f4c55c8 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 23 May 2017 14:55:31 +0200 Subject: move check if metrics are enabled to before action --- spec/controllers/metrics_controller_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'spec') diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb index 7f2dcd3544f..c09c3a1f6b7 100644 --- a/spec/controllers/metrics_controller_spec.rb +++ b/spec/controllers/metrics_controller_spec.rb @@ -48,6 +48,15 @@ describe MetricsController do expect(response.body).to match(/^filesystem_read_latency{shard="default"} [0-9\.]+$/) expect(response.body).to match(/^filesystem_readable{shard="default"} 1$/) end + + context 'prometheus metrics are disabled' do + allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(false) + + it 'returns proper response' do + get :metrics + expect(response.status).to eq(404) + end + end end context 'without authorization token' do @@ -56,5 +65,6 @@ describe MetricsController do expect(response.status).to eq(404) end end + end end -- cgit v1.2.3 From 254830c1f963f344585a45d96a03985e1ec2df0e Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 23 May 2017 15:42:36 +0200 Subject: Move most of MetricsController logic to MetricsService --- spec/controllers/metrics_controller_spec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb index c09c3a1f6b7..99ad7b7738b 100644 --- a/spec/controllers/metrics_controller_spec.rb +++ b/spec/controllers/metrics_controller_spec.rb @@ -50,7 +50,9 @@ describe MetricsController do end context 'prometheus metrics are disabled' do - allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(false) + before do + allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(false) + end it 'returns proper response' do get :metrics @@ -65,6 +67,5 @@ describe MetricsController do expect(response.status).to eq(404) end end - end end -- cgit v1.2.3 From ef9f23b797d7467a1d1bda15e29d1f33b070065f Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 23 May 2017 16:09:00 +0200 Subject: Mark migration as requiring no downtime + Add spaces for four phases approach + fix InfluxDB rename --- spec/controllers/metrics_controller_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'spec') diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb index 99ad7b7738b..cd31f750ffd 100644 --- a/spec/controllers/metrics_controller_spec.rb +++ b/spec/controllers/metrics_controller_spec.rb @@ -27,6 +27,7 @@ describe MetricsController do it 'returns DB ping metrics' do get :metrics + expect(response.body).to match(/^db_ping_timeout 0$/) expect(response.body).to match(/^db_ping_success 1$/) expect(response.body).to match(/^db_ping_latency [0-9\.]+$/) @@ -34,6 +35,7 @@ describe MetricsController do it 'returns Redis ping metrics' do get :metrics + expect(response.body).to match(/^redis_ping_timeout 0$/) expect(response.body).to match(/^redis_ping_success 1$/) expect(response.body).to match(/^redis_ping_latency [0-9\.]+$/) @@ -41,6 +43,7 @@ describe MetricsController do it 'returns file system check metrics' do get :metrics + expect(response.body).to match(/^filesystem_access_latency{shard="default"} [0-9\.]+$/) expect(response.body).to match(/^filesystem_accessible{shard="default"} 1$/) expect(response.body).to match(/^filesystem_write_latency{shard="default"} [0-9\.]+$/) @@ -56,6 +59,7 @@ describe MetricsController do it 'returns proper response' do get :metrics + expect(response.status).to eq(404) end end @@ -64,6 +68,7 @@ describe MetricsController do context 'without authorization token' do it 'returns proper response' do get :metrics + expect(response.status).to eq(404) end end -- cgit v1.2.3 From 394e962e52efdff36e3fae974ea51e9e2883f382 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 23 May 2017 16:16:23 +0200 Subject: Make tests of Gitlab::Metrics use explicit descriptions. --- spec/lib/gitlab/metrics_spec.rb | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb index 020bdbacead..863868e1576 100644 --- a/spec/lib/gitlab/metrics_spec.rb +++ b/spec/lib/gitlab/metrics_spec.rb @@ -9,19 +9,19 @@ describe Gitlab::Metrics do describe '.enabled?' do it 'returns a boolean' do - expect([true, false].include?(described_class.enabled?)).to eq(true) + expect(described_class.enabled?).to be_in([true, false]) end end describe '.prometheus_metrics_enabled?' do it 'returns a boolean' do - expect([true, false].include?(described_class.prometheus_metrics_enabled?)).to eq(true) + expect(described_class.prometheus_metrics_enabled?).to be_in([true, false]) end end describe '.influx_metrics_enabled?' do it 'returns a boolean' do - expect([true, false].include?(described_class.influx_metrics_enabled?)).to eq(true) + expect(described_class.influx_metrics_enabled?).to be_in([true, false]) end end @@ -195,9 +195,17 @@ describe Gitlab::Metrics do subject { described_class.counter(:couter, 'doc') } describe '#increment' do - it { expect { subject.increment }.not_to raise_exception } - it { expect { subject.increment({}) }.not_to raise_exception } - it { expect { subject.increment({}, 1) }.not_to raise_exception } + it 'successfully calls #increment without arguments' do + expect { subject.increment }.not_to raise_exception + end + + it 'successfully calls #increment with 1 argument' do + expect { subject.increment({}) }.not_to raise_exception + end + + it 'successfully calls #increment with 2 arguments' do + expect { subject.increment({}, 1) }.not_to raise_exception + end end end @@ -205,15 +213,19 @@ describe Gitlab::Metrics do subject { described_class.summary(:summary, 'doc') } describe '#observe' do - it { expect { subject.observe({}, 2) }.not_to raise_exception } + it 'successfully calls #observe with 2 arguments' do + expect { subject.observe({}, 2) }.not_to raise_exception + end end end describe '#gauge' do subject { described_class.gauge(:gauge, 'doc') } - describe '#observe' do - it { expect { subject.set({}, 1) }.not_to raise_exception } + describe '#set' do + it 'successfully calls #set with 2 arguments' do + expect { subject.set({}, 1) }.not_to raise_exception + end end end @@ -221,7 +233,9 @@ describe Gitlab::Metrics do subject { described_class.histogram(:histogram, 'doc') } describe '#observe' do - it { expect { subject.observe({}, 2) }.not_to raise_exception } + it 'successfully calls #observe with 2 arguments' do + expect { subject.observe({}, 2) }.not_to raise_exception + end end end end -- cgit v1.2.3 From c134a72cdb7e6de8b70dc60de99cf4edc68a9227 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Mon, 29 May 2017 14:19:43 +0200 Subject: Move Prometheus presentation logic to PrometheusText + Use NullMetrics to mock metrics when unused + Use method_missing in NullMetrics mocking + Update prometheus gem to version that correctly uses transitive dependencies + Ensure correct folders are used in Multiprocess prometheus client tests. + rename Sessions controller's metric --- spec/controllers/metrics_controller_spec.rb | 4 ++-- spec/lib/gitlab/metrics_spec.rb | 32 +++++++++++++++++++---------- spec/spec_helper.rb | 1 + 3 files changed, 24 insertions(+), 13 deletions(-) (limited to 'spec') diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb index cd31f750ffd..7baf7d1bef9 100644 --- a/spec/controllers/metrics_controller_spec.rb +++ b/spec/controllers/metrics_controller_spec.rb @@ -6,10 +6,10 @@ describe MetricsController do let(:token) { current_application_settings.health_check_access_token } let(:json_response) { JSON.parse(response.body) } - around do |examples| + around do |example| Dir.mktmpdir do |tmp_dir| @metrics_multiproc_dir = tmp_dir - examples.run + example.run end end diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb index 863868e1576..87c9f4ebda4 100644 --- a/spec/lib/gitlab/metrics_spec.rb +++ b/spec/lib/gitlab/metrics_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe Gitlab::Metrics do + include StubENV + describe '.settings' do it 'returns a Hash' do expect(described_class.settings).to be_an_instance_of(Hash) @@ -247,45 +249,53 @@ describe Gitlab::Metrics do it_behaves_like 'prometheus metrics API' - describe '#dummy_metric' do + describe '#null_metric' do subject { described_class.provide_metric(:test) } - it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } + it { is_expected.to be_a(Gitlab::Metrics::NullMetric) } end describe '#counter' do subject { described_class.counter(:counter, 'doc') } - it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } + it { is_expected.to be_a(Gitlab::Metrics::NullMetric) } end describe '#summary' do subject { described_class.summary(:summary, 'doc') } - it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } + it { is_expected.to be_a(Gitlab::Metrics::NullMetric) } end describe '#gauge' do subject { described_class.gauge(:gauge, 'doc') } - it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } + it { is_expected.to be_a(Gitlab::Metrics::NullMetric) } end describe '#histogram' do subject { described_class.histogram(:histogram, 'doc') } - it { is_expected.to be_a(Gitlab::Metrics::DummyMetric) } + it { is_expected.to be_a(Gitlab::Metrics::NullMetric) } end end context 'prometheus metrics enabled' do + around do |example| + Dir.mktmpdir do |tmp_dir| + @metrics_multiproc_dir = tmp_dir + example.run + end + end + before do + stub_const('Prometheus::Client::Multiprocdir', @metrics_multiproc_dir) allow(described_class).to receive(:prometheus_metrics_enabled?).and_return(true) end it_behaves_like 'prometheus metrics API' - describe '#dummy_metric' do + describe '#null_metric' do subject { described_class.provide_metric(:test) } it { is_expected.to be_nil } @@ -294,25 +304,25 @@ describe Gitlab::Metrics do describe '#counter' do subject { described_class.counter(:name, 'doc') } - it { is_expected.not_to be_a(Gitlab::Metrics::DummyMetric) } + it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) } end describe '#summary' do subject { described_class.summary(:name, 'doc') } - it { is_expected.not_to be_a(Gitlab::Metrics::DummyMetric) } + it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) } end describe '#gauge' do subject { described_class.gauge(:name, 'doc') } - it { is_expected.not_to be_a(Gitlab::Metrics::DummyMetric) } + it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) } end describe '#histogram' do subject { described_class.histogram(:name, 'doc') } - it { is_expected.not_to be_a(Gitlab::Metrics::DummyMetric) } + it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) } end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 994c7dcbb46..f800c5bcb07 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,6 +3,7 @@ SimpleCovEnv.start! ENV["RAILS_ENV"] ||= 'test' ENV["IN_MEMORY_APPLICATION_SETTINGS"] = 'true' +# ENV['prometheus_multiproc_dir'] = 'tmp/prometheus_multiproc_dir_test' require File.expand_path("../../config/environment", __FILE__) require 'rspec/rails' -- cgit v1.2.3 From ae8f7666e597493ab404f8524c1216a924338291 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Mon, 29 May 2017 23:23:19 +0200 Subject: Add prometheus text formatter + rename controler method to #index from #metrics + remove assertion from nullMetric --- spec/controllers/metrics_controller_spec.rb | 12 +++--- .../health_checks/prometheus_text_format_spec.rb | 44 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb (limited to 'spec') diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb index 7baf7d1bef9..b26ebc1377b 100644 --- a/spec/controllers/metrics_controller_spec.rb +++ b/spec/controllers/metrics_controller_spec.rb @@ -19,14 +19,14 @@ describe MetricsController do allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(true) end - describe '#metrics' do + describe '#index' do context 'authorization token provided' do before do request.headers['TOKEN'] = token end it 'returns DB ping metrics' do - get :metrics + get :index expect(response.body).to match(/^db_ping_timeout 0$/) expect(response.body).to match(/^db_ping_success 1$/) @@ -34,7 +34,7 @@ describe MetricsController do end it 'returns Redis ping metrics' do - get :metrics + get :index expect(response.body).to match(/^redis_ping_timeout 0$/) expect(response.body).to match(/^redis_ping_success 1$/) @@ -42,7 +42,7 @@ describe MetricsController do end it 'returns file system check metrics' do - get :metrics + get :index expect(response.body).to match(/^filesystem_access_latency{shard="default"} [0-9\.]+$/) expect(response.body).to match(/^filesystem_accessible{shard="default"} 1$/) @@ -58,7 +58,7 @@ describe MetricsController do end it 'returns proper response' do - get :metrics + get :index expect(response.status).to eq(404) end @@ -67,7 +67,7 @@ describe MetricsController do context 'without authorization token' do it 'returns proper response' do - get :metrics + get :index expect(response.status).to eq(404) end diff --git a/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb b/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb new file mode 100644 index 00000000000..a9feab8ff78 --- /dev/null +++ b/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb @@ -0,0 +1,44 @@ +describe Gitlab::HealthChecks::PrometheusTextFormat do + let(:metric_class) { Gitlab::HealthChecks::Metric } + subject { described_class.new } + + describe '#marshal' do + let(:sample_metrics) do + [ + metric_class.new('metric1', 1), + metric_class.new('metric2', 2) + ] + end + + it 'marshal to text with non repeating type definition' do + expected = <<-EXPECTED +# TYPE metric1 gauge +metric1 1 +# TYPE metric2 gauge +metric2 2 +EXPECTED + expect(subject.marshal(sample_metrics)).to eq(expected.chomp) + end + + context 'metrics where name repeats' do + let(:sample_metrics) do + [ + metric_class.new('metric1', 1), + metric_class.new('metric1', 2), + metric_class.new('metric2', 3) + ] + end + + it 'marshal to text with non repeating type definition' do + expected = <<-EXPECTED +# TYPE metric1 gauge +metric1 1 +metric1 2 +# TYPE metric2 gauge +metric2 3 + EXPECTED + expect(subject.marshal(sample_metrics)).to eq(expected.chomp) + end + end + end +end -- cgit v1.2.3 From e21b1501ff16de7657a4a5eccb3b8124ba07709c Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Fri, 2 Jun 2017 13:41:30 +0200 Subject: Allow enabling Prometheus metrics via ENV variable when db is seeded --- spec/db/production/settings_spec.rb | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 spec/db/production/settings_spec.rb (limited to 'spec') diff --git a/spec/db/production/settings_spec.rb b/spec/db/production/settings_spec.rb new file mode 100644 index 00000000000..c6b772f4e93 --- /dev/null +++ b/spec/db/production/settings_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' +require 'rainbow/ext/string' + +describe 'seed production settings', lib: true do + include StubENV + let(:settings_file) { File.join(__dir__, '../../../db/fixtures/production/010_settings.rb') } + let(:settings) { ApplicationSetting.current || ApplicationSetting.create_from_defaults } + + context 'GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN is set in the environment' do + before do + stub_env('GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN', '013456789') + end + + it 'writes the token to the database' do + load(settings_file) + + expect(settings.runners_registration_token).to eq('013456789') + end + end + + context 'GITLAB_PROMETHEUS_METRICS_ENABLED is set in the environment' do + context 'GITLAB_PROMETHEUS_METRICS_ENABLED is true' do + before do + stub_env('GITLAB_PROMETHEUS_METRICS_ENABLED', 'true') + end + + it 'prometheus_metrics_enabled is set to true ' do + load(settings_file) + + expect(settings.prometheus_metrics_enabled).to eq(true) + end + end + + context 'GITLAB_PROMETHEUS_METRICS_ENABLED is false' do + before do + stub_env('GITLAB_PROMETHEUS_METRICS_ENABLED', 'false') + end + + it 'prometheus_metrics_enabled is set to false' do + load(settings_file) + + expect(settings.prometheus_metrics_enabled).to eq(false) + end + end + end +end -- cgit v1.2.3 From c86e1437eb415e816dcc29f0b1acafeed2dcc266 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Fri, 2 Jun 2017 14:21:58 +0200 Subject: Make fixture message more descriptive + use strip_heredoc to make the text in tests much more readable --- .../health_checks/prometheus_text_format_spec.rb | 25 +++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb b/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb index a9feab8ff78..b07f95443ee 100644 --- a/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb +++ b/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb @@ -11,12 +11,13 @@ describe Gitlab::HealthChecks::PrometheusTextFormat do end it 'marshal to text with non repeating type definition' do - expected = <<-EXPECTED -# TYPE metric1 gauge -metric1 1 -# TYPE metric2 gauge -metric2 2 -EXPECTED + expected = <<-EXPECTED.strip_heredoc + # TYPE metric1 gauge + metric1 1 + # TYPE metric2 gauge + metric2 2 + EXPECTED + expect(subject.marshal(sample_metrics)).to eq(expected.chomp) end @@ -30,12 +31,12 @@ EXPECTED end it 'marshal to text with non repeating type definition' do - expected = <<-EXPECTED -# TYPE metric1 gauge -metric1 1 -metric1 2 -# TYPE metric2 gauge -metric2 3 + expected = <<-EXPECTED.strip_heredoc + # TYPE metric1 gauge + metric1 1 + metric1 2 + # TYPE metric2 gauge + metric2 3 EXPECTED expect(subject.marshal(sample_metrics)).to eq(expected.chomp) end -- cgit v1.2.3 From 6a67148ed3543ee5073ab49dc4e825f3d87cc8b5 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Fri, 2 Jun 2017 15:25:54 +0200 Subject: Make production settings fixture use Gitlab::CurrentSettings.current_application_settings small code formatting changes --- spec/db/production/settings_spec.rb | 4 ++-- .../gitlab/health_checks/prometheus_text_format_spec.rb | 14 +++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) (limited to 'spec') diff --git a/spec/db/production/settings_spec.rb b/spec/db/production/settings_spec.rb index c6b772f4e93..00c631b866e 100644 --- a/spec/db/production/settings_spec.rb +++ b/spec/db/production/settings_spec.rb @@ -3,8 +3,8 @@ require 'rainbow/ext/string' describe 'seed production settings', lib: true do include StubENV - let(:settings_file) { File.join(__dir__, '../../../db/fixtures/production/010_settings.rb') } - let(:settings) { ApplicationSetting.current || ApplicationSetting.create_from_defaults } + let(:settings_file) { Rails.root.join('db/fixtures/production/010_settings.rb') } + let(:settings) { Gitlab::CurrentSettings.current_application_settings } context 'GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN is set in the environment' do before do diff --git a/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb b/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb index b07f95443ee..7573792789a 100644 --- a/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb +++ b/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb @@ -4,10 +4,8 @@ describe Gitlab::HealthChecks::PrometheusTextFormat do describe '#marshal' do let(:sample_metrics) do - [ - metric_class.new('metric1', 1), - metric_class.new('metric2', 2) - ] + [metric_class.new('metric1', 1), + metric_class.new('metric2', 2)] end it 'marshal to text with non repeating type definition' do @@ -23,11 +21,9 @@ describe Gitlab::HealthChecks::PrometheusTextFormat do context 'metrics where name repeats' do let(:sample_metrics) do - [ - metric_class.new('metric1', 1), - metric_class.new('metric1', 2), - metric_class.new('metric2', 3) - ] + [metric_class.new('metric1', 1), + metric_class.new('metric1', 2), + metric_class.new('metric2', 3)] end it 'marshal to text with non repeating type definition' do -- cgit v1.2.3 From d26573c6e3de535f69437deaf54d5c151ac343c8 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Fri, 2 Jun 2017 15:55:44 +0200 Subject: Make PrometheusTextFormat return proper output terminated with '\n' remove file dangling after rebase --- spec/db/production/settings.rb | 16 ---------------- .../gitlab/health_checks/prometheus_text_format_spec.rb | 4 ++-- 2 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 spec/db/production/settings.rb (limited to 'spec') diff --git a/spec/db/production/settings.rb b/spec/db/production/settings.rb deleted file mode 100644 index 3cbb173c4cc..00000000000 --- a/spec/db/production/settings.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'spec_helper' - -describe 'seed production settings', lib: true do - include StubENV - - context 'GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN is set in the environment' do - before do - stub_env('GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN', '013456789') - end - - it 'writes the token to the database' do - load(File.join(__dir__, '../../../db/fixtures/production/010_settings.rb')) - expect(ApplicationSetting.current.runners_registration_token).to eq('013456789') - end - end -end diff --git a/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb b/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb index 7573792789a..ed757ed60d8 100644 --- a/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb +++ b/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb @@ -16,7 +16,7 @@ describe Gitlab::HealthChecks::PrometheusTextFormat do metric2 2 EXPECTED - expect(subject.marshal(sample_metrics)).to eq(expected.chomp) + expect(subject.marshal(sample_metrics)).to eq(expected) end context 'metrics where name repeats' do @@ -34,7 +34,7 @@ describe Gitlab::HealthChecks::PrometheusTextFormat do # TYPE metric2 gauge metric2 3 EXPECTED - expect(subject.marshal(sample_metrics)).to eq(expected.chomp) + expect(subject.marshal(sample_metrics)).to eq(expected) end end end -- cgit v1.2.3 From c88d9cf34c97a27db55f9b90b29ede5d20a1f156 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Fri, 2 Jun 2017 03:52:27 -0500 Subject: Fix NPE with horse racing emoji check Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/32587 --- spec/javascripts/gl_emoji_spec.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/gl_emoji_spec.js b/spec/javascripts/gl_emoji_spec.js index b2b46640e5b..a09e0072fa8 100644 --- a/spec/javascripts/gl_emoji_spec.js +++ b/spec/javascripts/gl_emoji_spec.js @@ -192,6 +192,9 @@ describe('gl_emoji', () => { }); describe('isFlagEmoji', () => { + it('should gracefully handle empty string', () => { + expect(isFlagEmoji('')).toBeFalsy(); + }); it('should detect flag_ac', () => { expect(isFlagEmoji('🇦🇨')).toBeTruthy(); }); @@ -216,6 +219,9 @@ describe('gl_emoji', () => { }); describe('isKeycapEmoji', () => { + it('should gracefully handle empty string', () => { + expect(isKeycapEmoji('')).toBeFalsy(); + }); it('should detect one(keycap)', () => { expect(isKeycapEmoji('1️⃣')).toBeTruthy(); }); @@ -231,6 +237,9 @@ describe('gl_emoji', () => { }); describe('isSkinToneComboEmoji', () => { + it('should gracefully handle empty string', () => { + expect(isSkinToneComboEmoji('')).toBeFalsy(); + }); it('should detect hand_splayed_tone5', () => { expect(isSkinToneComboEmoji('🖐🏿')).toBeTruthy(); }); @@ -255,6 +264,9 @@ describe('gl_emoji', () => { }); describe('isHorceRacingSkinToneComboEmoji', () => { + it('should gracefully handle empty string', () => { + expect(isHorceRacingSkinToneComboEmoji('')).toBeFalsy(); + }); it('should detect horse_racing_tone2', () => { expect(isHorceRacingSkinToneComboEmoji('🏇🏼')).toBeTruthy(); }); @@ -264,6 +276,9 @@ describe('gl_emoji', () => { }); describe('isPersonZwjEmoji', () => { + it('should gracefully handle empty string', () => { + expect(isPersonZwjEmoji('')).toBeFalsy(); + }); it('should detect couple_mm', () => { expect(isPersonZwjEmoji('👨‍❤️‍👨')).toBeTruthy(); }); @@ -300,6 +315,22 @@ describe('gl_emoji', () => { }); describe('isEmojiUnicodeSupported', () => { + it('should gracefully handle empty string with unicode support', () => { + const isSupported = isEmojiUnicodeSupported( + { '1.0': true }, + '', + '1.0', + ); + expect(isSupported).toBeTruthy(); + }); + it('should gracefully handle empty string without unicode support', () => { + const isSupported = isEmojiUnicodeSupported( + {}, + '', + '1.0', + ); + expect(isSupported).toBeFalsy(); + }); it('bomb(6.0) with 6.0 support', () => { const emojiKey = 'bomb'; const unicodeSupportMap = Object.assign({}, emptySupportMap, { -- cgit v1.2.3 From 78f131c0514bc99f73b9c063fac3158ab2e51e17 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Sat, 3 Jun 2017 12:40:20 +1100 Subject: Fix duplication of commits header on commits page --- spec/javascripts/commits_spec.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/commits_spec.js b/spec/javascripts/commits_spec.js index 187db7485a5..44a4386b250 100644 --- a/spec/javascripts/commits_spec.js +++ b/spec/javascripts/commits_spec.js @@ -28,6 +28,32 @@ import '~/commits'; expect(CommitsList).toBeDefined(); }); + describe('processCommits', () => { + it('should join commit headers', () => { + CommitsList.$contentList = $(` +
+
  • + 20 Sep, 2016 + 1 commit +
  • +
  • +
    + `); + + const data = ` +
  • + 20 Sep, 2016 + 1 commit +
  • +
  • + `; + + // The last commit header should be removed + // since the previous one has the same data-day value. + expect(CommitsList.processCommits(data).find('li.commit-header').length).toBe(0); + }); + }); + describe('on entering input', () => { let ajaxSpy; -- cgit v1.2.3 From 469975c783d8c90e555b64d069e412a3b062073b Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 10:30:57 +0200 Subject: Revert invalid changes in new pipeline service specs --- spec/services/ci/create_pipeline_service_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index fe5de2ce227..68242fb4e15 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -9,10 +9,10 @@ describe Ci::CreatePipelineService, :services do end describe '#execute' do - def execute_service(after_sha: project.commit.id, message: 'Message', ref: 'refs/heads/master') + def execute_service(after: project.commit.id, message: 'Message', ref: 'refs/heads/master') params = { ref: ref, before: '00000000', - after: after_sha, + after: after, commits: [{ message: message }] } described_class.new(project, user, params).execute -- cgit v1.2.3 From 028423c2f51ff738d151df32254913664ac8e898 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 11:07:10 +0200 Subject: Calculate previous migration version in specs support This makes it possible to test migration on the schema this migration was written for, without a need to specify a previous schema version manually. --- spec/migrations/migrate_build_stage_reference_spec.rb | 2 +- spec/migrations/migrate_pipeline_stages_spec.rb | 2 +- spec/spec_helper.rb | 6 +++--- spec/support/migrations_helpers.rb | 10 ++++++++++ 4 files changed, 15 insertions(+), 5 deletions(-) (limited to 'spec') diff --git a/spec/migrations/migrate_build_stage_reference_spec.rb b/spec/migrations/migrate_build_stage_reference_spec.rb index 979f13a1398..eaac8f95892 100644 --- a/spec/migrations/migrate_build_stage_reference_spec.rb +++ b/spec/migrations/migrate_build_stage_reference_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20170526185921_migrate_build_stage_reference.rb') -describe MigrateBuildStageReference, :migration, schema: 20170526185602 do +describe MigrateBuildStageReference, :migration do ## # Create test data - pipeline and CI/CD jobs. # diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb index c9b38086deb..36d3bd13ac0 100644 --- a/spec/migrations/migrate_pipeline_stages_spec.rb +++ b/spec/migrations/migrate_pipeline_stages_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20170526185842_migrate_pipeline_stages.rb') -describe MigratePipelineStages, :migration, schema: 20170526185602 do +describe MigratePipelineStages, :migration do ## # Create test data - pipeline and CI/CD jobs. # diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6a0e29f2edb..5cbb3dafcdf 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -94,10 +94,10 @@ RSpec.configure do |config| Sidekiq.redis(&:flushall) end - config.around(:example, migration: true) do |example| + config.around(:example, :migration) do |example| begin - schema_version = example.metadata.fetch(:schema) - ActiveRecord::Migrator.migrate(migrations_paths, schema_version) + ActiveRecord::Migrator + .migrate(migrations_paths, previous_migration.version) example.run ensure diff --git a/spec/support/migrations_helpers.rb b/spec/support/migrations_helpers.rb index ee17d1a40b7..91fbb4eaf48 100644 --- a/spec/support/migrations_helpers.rb +++ b/spec/support/migrations_helpers.rb @@ -11,6 +11,16 @@ module MigrationsHelpers ActiveRecord::Base.connection.table_exists?(name) end + def migrations + ActiveRecord::Migrator.migrations(migrations_paths) + end + + def previous_migration + migrations.each_cons(2) do |previous, migration| + break previous if migration.name == described_class.name + end + end + def migrate! ActiveRecord::Migrator.up(migrations_paths) do |migration| migration.name == described_class.name -- cgit v1.2.3 From 0b81b5ace0dd7c5ba3362238d8be41ce178e1ecc Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Wed, 31 May 2017 15:55:12 +0200 Subject: Create read_registry scope with JWT auth This is the first commit doing mainly 3 things: 1. create a new scope and allow users to use it 2. Have the JWTController respond correctly on this 3. Updates documentation to suggest usage of PATs There is one gotcha, there will be no support for impersonation tokens, as this seems not needed. Fixes gitlab-org/gitlab-ce#19219 --- spec/lib/gitlab/auth_spec.rb | 7 +++++++ spec/models/personal_access_token_spec.rb | 20 ++++++++++++++++++-- spec/requests/jwt_controller_spec.rb | 15 ++++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index 50bc3ef1b7c..6574e6d0087 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -143,6 +143,13 @@ describe Gitlab::Auth, lib: true do expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_token, full_authentication_abilities)) end + it 'succeeds for personal access tokens with the `read_registry` scope' do + personal_access_token = create(:personal_access_token, scopes: ['read_registry']) + + expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '') + expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_token, [:read_container_image])) + end + it 'succeeds if it is an impersonation token' do impersonation_token = create(:personal_access_token, :impersonation, scopes: ['api']) diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb index 823623d96fa..fa781195608 100644 --- a/spec/models/personal_access_token_spec.rb +++ b/spec/models/personal_access_token_spec.rb @@ -35,6 +35,16 @@ describe PersonalAccessToken, models: true do end end + describe 'revoke!' do + let(:active_personal_access_token) { create(:personal_access_token) } + + it 'revokes the token' do + active_personal_access_token.revoke! + + expect(active_personal_access_token.revoked?).to be true + end + end + context "validations" do let(:personal_access_token) { build(:personal_access_token) } @@ -51,11 +61,17 @@ describe PersonalAccessToken, models: true do expect(personal_access_token).to be_valid end - it "rejects creating a token with non-API scopes" do + it "allows creating a token with read_registry scope" do + personal_access_token.scopes = [:read_registry] + + expect(personal_access_token).to be_valid + end + + it "rejects creating a token with unavailable scopes" do personal_access_token.scopes = [:openid, :api] expect(personal_access_token).not_to be_valid - expect(personal_access_token.errors[:scopes].first).to eq "can only contain API scopes" + expect(personal_access_token.errors[:scopes].first).to eq "can only contain available scopes" end end end diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb index a3e7844b2f3..8ddae9f6b89 100644 --- a/spec/requests/jwt_controller_spec.rb +++ b/spec/requests/jwt_controller_spec.rb @@ -41,6 +41,19 @@ describe JwtController do it { expect(response).to have_http_status(401) } end + + context 'using personal access tokens' do + let(:user) { create(:user) } + let(:pat) { create(:personal_access_token, user: user, scopes: ['read_registry']) } + let(:headers) { { authorization: credentials('personal_access_token', pat.token) } } + + subject! { get '/jwt/auth', parameters, headers } + + it 'authenticates correctly' do + expect(response).to have_http_status(200) + expect(service_class).to have_received(:new).with(nil, user, parameters) + end + end end context 'using User login' do @@ -89,7 +102,7 @@ describe JwtController do end it 'allows read access' do - expect(service).to receive(:execute).with(authentication_abilities: Gitlab::Auth.read_authentication_abilities) + expect(service).to receive(:execute).with(authentication_abilities: Gitlab::Auth.read_api_abilities) get '/jwt/auth', parameters end -- cgit v1.2.3 From 3801a0df80306a76dc340ca74427a124a1514dbb Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 10:34:30 +0200 Subject: Export pipeline stages in import/export feature --- spec/lib/gitlab/import_export/all_models.yml | 7 +++++++ spec/lib/gitlab/import_export/safe_model_attributes.yml | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 34f617e23a5..6e6e94d0bbb 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -91,6 +91,7 @@ merge_request_diff: pipelines: - project - user +- stages - statuses - builds - trigger_requests @@ -104,9 +105,15 @@ pipelines: - artifacts - pipeline_schedule - merge_requests +stages: +- project +- pipeline +- statuses +- builds statuses: - project - pipeline +- stage - user - auto_canceled_by variables: diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 2388aea24d9..37783f63843 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -191,6 +191,13 @@ Ci::Pipeline: - lock_version - auto_canceled_by_id - pipeline_schedule_id +Ci::Stage: +- id +- name +- project_id +- pipeline_id +- created_at +- updated_at CommitStatus: - id - project_id -- cgit v1.2.3 From 8808e7bcf518e16fa36762a9b01f6cf224233f06 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 12:54:52 +0200 Subject: Add assertions about new pipeline stage in specs --- spec/lib/gitlab/ci/stage/seed_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb index f4353040ce6..47a797cfe8f 100644 --- a/spec/lib/gitlab/ci/stage/seed_spec.rb +++ b/spec/lib/gitlab/ci/stage/seed_spec.rb @@ -48,6 +48,10 @@ describe Gitlab::Ci::Stage::Seed do expect(pipeline.builds).to all(satisfy { |job| job.stage_id.present? }) expect(pipeline.builds).to all(satisfy { |job| job.pipeline.present? }) expect(pipeline.builds).to all(satisfy { |job| job.project.present? }) + expect(pipeline.stages) + .to all(satisfy { |stage| stage.pipeline.present? }) + expect(pipeline.stages) + .to all(satisfy { |stage| stage.project.present? }) end end end -- cgit v1.2.3 From 25b26c2f2844178d66a6fde7f728a5e72841e9d2 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 15:01:15 +0200 Subject: Fix typo in import/export safe model attributes --- spec/lib/gitlab/import_export/safe_model_attributes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 24665645277..34457bf36fe 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -199,7 +199,7 @@ Ci::Stage: - pipeline_id - created_at - updated_at -ommitStatus: +CommitStatus: - id - project_id - status -- cgit v1.2.3 From da0852e08aa07354706be1e0be9251ccf02e85be Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 5 Jun 2017 15:23:09 +0200 Subject: Improve specs for pipeline and pipeline seeds --- spec/lib/gitlab/ci/stage/seed_spec.rb | 2 +- spec/models/ci/pipeline_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb index 47a797cfe8f..d7e91a5a62c 100644 --- a/spec/lib/gitlab/ci/stage/seed_spec.rb +++ b/spec/lib/gitlab/ci/stage/seed_spec.rb @@ -30,7 +30,7 @@ describe Gitlab::Ci::Stage::Seed do end describe '#user=' do - let(:user) { create(:user) } + let(:user) { build(:user) } it 'assignes relevant pipeline attributes' do subject.user = user diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index a4392ed073a..b50c7700bd3 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -535,9 +535,9 @@ describe Ci::Pipeline, models: true do end end - describe '#has_stage_seedss?' do + describe '#has_stage_seeds?' do context 'when pipeline has stage seeds' do - subject { create(:ci_pipeline_with_one_job) } + subject { build(:ci_pipeline_with_one_job) } it { is_expected.to have_stage_seeds } end -- cgit v1.2.3 From 3fd02428d42546bbfc753130e1bc7d1c1f0fa83a Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 5 Jun 2017 20:37:52 -0300 Subject: Refactor PostReceive worker to limit merge conflicts --- spec/workers/post_receive_spec.rb | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'spec') diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index f4bc63bcc6a..44163c735ba 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -94,26 +94,23 @@ describe PostReceive do it { expect{ subject }.not_to change{ Ci::Pipeline.count } } end end - end - describe '#process_repository_update' do - let(:changes) {'123456 789012 refs/heads/tést'} - let(:fake_hook_data) do - { event_name: 'repository_update' } - end + context 'after project changes hooks' do + let(:changes) { '123456 789012 refs/heads/tést' } + let(:fake_hook_data) { Hash.new(event_name: 'repository_update') } - before do - allow_any_instance_of(Gitlab::GitPostReceive).to receive(:identify).and_return(project.owner) - allow_any_instance_of(Gitlab::DataBuilder::Repository).to receive(:update).and_return(fake_hook_data) - # silence hooks so we can isolate - allow_any_instance_of(Key).to receive(:post_create_hook).and_return(true) - allow(subject).to receive(:process_project_changes).and_return(true) - end + before do + allow_any_instance_of(Gitlab::DataBuilder::Repository).to receive(:update).and_return(fake_hook_data) + # silence hooks so we can isolate + allow_any_instance_of(Key).to receive(:post_create_hook).and_return(true) + allow_any_instance_of(GitPushService).to receive(:execute).and_return(true) + end - it 'calls SystemHooksService' do - expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with(fake_hook_data, :repository_update_hooks).and_return(true) + it 'calls SystemHooksService' do + expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with(fake_hook_data, :repository_update_hooks).and_return(true) - subject.perform(pwd(project), key_id, base64_changes) + described_class.new.perform(project_identifier, key_id, base64_changes) + end end end -- cgit v1.2.3 From 75e0ec0fa6798de220ddeb207a8754d97d9da660 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Tue, 6 Jun 2017 02:56:07 -0500 Subject: Fix rspec --- .../issues/filtered_search/filter_issues_spec.rb | 8 ++++---- .../merge_requests/filter_merge_requests_spec.rb | 16 +++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) (limited to 'spec') diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index e5e4ba06b5a..36f8369c142 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -777,17 +777,17 @@ describe 'Filter issues', js: true, feature: true do end it 'open state' do - find('.issues-state-filters a', text: 'Closed').click + find('.issues-state-filters .state-closed').click wait_for_requests - find('.issues-state-filters a', text: 'Open').click + find('.issues-state-filters .state-opened').click wait_for_requests expect(page).to have_selector('.issues-list .issue', count: 4) end it 'closed state' do - find('.issues-state-filters a', text: 'Closed').click + find('.issues-state-filters .state-closed').click wait_for_requests expect(page).to have_selector('.issues-list .issue', count: 1) @@ -795,7 +795,7 @@ describe 'Filter issues', js: true, feature: true do end it 'all state' do - find('.issues-state-filters a', text: 'All').click + find('.issues-state-filters .state-all').click wait_for_requests expect(page).to have_selector('.issues-list .issue', count: 5) diff --git a/spec/features/merge_requests/filter_merge_requests_spec.rb b/spec/features/merge_requests/filter_merge_requests_spec.rb index 1e26b3d601e..5a13189c5bf 100644 --- a/spec/features/merge_requests/filter_merge_requests_spec.rb +++ b/spec/features/merge_requests/filter_merge_requests_spec.rb @@ -40,13 +40,13 @@ describe 'Filter merge requests', feature: true do end it 'does not change when closed link is clicked' do - find('.issues-state-filters a', text: "Closed").click + find('.issues-state-filters .state-closed').click expect_assignee_visual_tokens() end it 'does not change when all link is clicked' do - find('.issues-state-filters a', text: "All").click + find('.issues-state-filters .state-all').click expect_assignee_visual_tokens() end @@ -73,13 +73,13 @@ describe 'Filter merge requests', feature: true do end it 'does not change when closed link is clicked' do - find('.issues-state-filters a', text: "Closed").click + find('.issues-state-filters .state-closed').click expect_milestone_visual_tokens() end it 'does not change when all link is clicked' do - find('.issues-state-filters a', text: "All").click + find('.issues-state-filters .state-all').click expect_milestone_visual_tokens() end @@ -142,11 +142,9 @@ describe 'Filter merge requests', feature: true do expect_tokens([{ name: 'assignee', value: "@#{user.username}" }]) expect_filtered_search_input_empty - input_filtered_search_keys("label:~#{label.title} ") + input_filtered_search_keys("label:~#{label.title}") expect_mr_list_count(1) - - find("#state-opened[href=\"#{URI.parse(current_url).path}?assignee_username=#{user.username}&label_name%5B%5D=#{label.title}&scope=all&state=opened\"]") end context 'assignee and label', js: true do @@ -163,13 +161,13 @@ describe 'Filter merge requests', feature: true do end it 'does not change when closed link is clicked' do - find('.issues-state-filters a', text: "Closed").click + find('.issues-state-filters .state-closed').click expect_assignee_label_visual_tokens() end it 'does not change when all link is clicked' do - find('.issues-state-filters a', text: "All").click + find('.issues-state-filters .state-all').click expect_assignee_label_visual_tokens() end -- cgit v1.2.3 From 657bc805a4bfee516942a3765eef0a508891a5d7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 6 Jun 2017 13:35:22 +0300 Subject: Add json support to group members leave action in controller Signed-off-by: Dmitriy Zaporozhets --- spec/controllers/groups/group_members_controller_spec.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'spec') diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index 60db0192dfd..b6f10162bc6 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -124,6 +124,13 @@ describe Groups::GroupMembersController do expect(response).to redirect_to(dashboard_groups_path) expect(group.users).not_to include user end + + it 'supports json request' do + delete :leave, group_id: group, format: :json + + expect(response).to have_http_status(200) + expect(response.body).to be_empty + end end context 'and is an owner' do -- cgit v1.2.3 From 4679107fdce6d88733c82329495b667d1a032217 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 6 Jun 2017 13:16:55 +0200 Subject: Handle case where GITLAB_PROMETHEUS_METRICS_ENABLED is non boolean value by defaulting to false --- spec/db/production/settings_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'spec') diff --git a/spec/db/production/settings_spec.rb b/spec/db/production/settings_spec.rb index 00c631b866e..a9d015e0666 100644 --- a/spec/db/production/settings_spec.rb +++ b/spec/db/production/settings_spec.rb @@ -42,5 +42,17 @@ describe 'seed production settings', lib: true do expect(settings.prometheus_metrics_enabled).to eq(false) end end + + context 'GITLAB_PROMETHEUS_METRICS_ENABLED is false' do + before do + stub_env('GITLAB_PROMETHEUS_METRICS_ENABLED', '') + end + + it 'prometheus_metrics_enabled is set to false' do + load(settings_file) + + expect(settings.prometheus_metrics_enabled).to eq(false) + end + end end end -- cgit v1.2.3 From 8df7bcf532c9f0407fcefa12d205cb9d160fe5f4 Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Fri, 19 May 2017 09:07:38 -0500 Subject: Allow numeric pages domain Previously, `PagesDomain` would not allow a domain such as 123.example.com. With this change, this is now allowed, because it is a perfectly valid domain. --- spec/models/pages_domain_spec.rb | 51 ++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 31 deletions(-) (limited to 'spec') diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb index c6c45d78990..f9d060d4e0e 100644 --- a/spec/models/pages_domain_spec.rb +++ b/spec/models/pages_domain_spec.rb @@ -6,7 +6,7 @@ describe PagesDomain, models: true do end describe 'validate domain' do - subject { build(:pages_domain, domain: domain) } + subject(:pages_domain) { build(:pages_domain, domain: domain) } context 'is unique' do let(:domain) { 'my.domain.com' } @@ -14,36 +14,25 @@ describe PagesDomain, models: true do it { is_expected.to validate_uniqueness_of(:domain) } end - context 'valid domain' do - let(:domain) { 'my.domain.com' } - - it { is_expected.to be_valid } - end - - context 'valid hexadecimal-looking domain' do - let(:domain) { '0x12345.com'} - - it { is_expected.to be_valid } - end - - context 'no domain' do - let(:domain) { nil } - - it { is_expected.not_to be_valid } - end - - context 'invalid domain' do - let(:domain) { '0123123' } - - it { is_expected.not_to be_valid } - end - - context 'domain from .example.com' do - let(:domain) { 'my.domain.com' } - - before { allow(Settings.pages).to receive(:host).and_return('domain.com') } - - it { is_expected.not_to be_valid } + { + 'my.domain.com' => true, + '123.456.789' => true, + '0x12345.com' => true, + '0123123' => true, + '_foo.com' => false, + 'reserved.com' => false, + 'a.reserved.com' => false, + nil => false + }.each do |value, validity| + context "domain #{value.inspect} validity" do + before do + allow(Settings.pages).to receive(:host).and_return('reserved.com') + end + + let(:domain) { value } + + it { expect(pages_domain.valid?).to eq(validity) } + end end end -- cgit v1.2.3 From e7b4eade0d69a70400a8d18ec72218c7b0bf1517 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 6 Jun 2017 12:59:50 +0100 Subject: moved creating backlog list into list service --- spec/services/boards/issues/list_service_spec.rb | 2 +- spec/services/boards/lists/list_service_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index a66cc2cd6e9..a1e220c2322 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -67,7 +67,7 @@ describe Boards::Issues::ListService, services: true do issues = described_class.new(project, user, params).execute - expect(issues).to eq [closed_issue4, closed_issue2, closed_issue5, closed_issue3, closed_issue1] + expect(issues).to eq [closed_issue4, closed_issue2, closed_issue3, closed_issue1] end it 'returns opened issues that have label list applied when listing issues from a label list' do diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb index ab9fb1bc914..97063381196 100644 --- a/spec/services/boards/lists/list_service_spec.rb +++ b/spec/services/boards/lists/list_service_spec.rb @@ -10,7 +10,7 @@ describe Boards::Lists::ListService, services: true do service = described_class.new(project, double) - expect(service.execute(board)).to eq [list, board.closed_list] + expect(service.execute(board)).to eq [board.backlog_list, list, board.closed_list] end end end -- cgit v1.2.3 From b55aad4cc3bf7723f4531635bbb31ab44cae17a9 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 6 Jun 2017 14:32:24 +0200 Subject: Migrate stages only with correct foreign references --- spec/migrations/migrate_build_stage_reference_spec.rb | 7 +++++++ spec/migrations/migrate_pipeline_stages_spec.rb | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/migrations/migrate_build_stage_reference_spec.rb b/spec/migrations/migrate_build_stage_reference_spec.rb index eaac8f95892..32f9a0c0642 100644 --- a/spec/migrations/migrate_build_stage_reference_spec.rb +++ b/spec/migrations/migrate_build_stage_reference_spec.rb @@ -9,8 +9,15 @@ describe MigrateBuildStageReference, :migration do let(:jobs) { table(:ci_builds) } let(:stages) { table(:ci_stages) } let(:pipelines) { table(:ci_pipelines) } + let(:projects) { table(:projects) } before do + # Create projects + # + projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1') + projects.create!(id: 456, name: 'gitlab2', path: 'gitlab2') + projects.create!(id: 798, name: 'gitlab3', path: 'gitlab3') + # Create CI/CD pipelines # pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a') diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb index 36d3bd13ac0..c47f2bb8ff9 100644 --- a/spec/migrations/migrate_pipeline_stages_spec.rb +++ b/spec/migrations/migrate_pipeline_stages_spec.rb @@ -9,8 +9,14 @@ describe MigratePipelineStages, :migration do let(:jobs) { table(:ci_builds) } let(:stages) { table(:ci_stages) } let(:pipelines) { table(:ci_pipelines) } + let(:projects) { table(:projects) } before do + # Create projects + # + projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1') + projects.create!(id: 456, name: 'gitlab2', path: 'gitlab2') + # Create CI/CD pipelines # pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a') @@ -28,7 +34,8 @@ describe MigratePipelineStages, :migration do jobs.create!(id: 8, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1') jobs.create!(id: 9, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1') jobs.create!(id: 10, commit_id: 2, project_id: 456, stage_idx: 2, stage: 'test:2') - jobs.create!(id: 11, commit_id: 3, project_id: 789, stage_idx: 3, stage: 'deploy') + jobs.create!(id: 11, commit_id: 3, project_id: 456, stage_idx: 3, stage: 'deploy') + jobs.create!(id: 12, commit_id: 2, project_id: 789, stage_idx: 3, stage: 'deploy') end it 'correctly migrates pipeline stages' do @@ -36,12 +43,14 @@ describe MigratePipelineStages, :migration do migrate! - expect(stages.count).to eq 7 + expect(stages.count).to eq 6 expect(stages.all.pluck(:name)) - .to match_array %w[test build deploy test:1 test:2 deploy deploy] + .to match_array %w[test build deploy test:1 test:2 deploy] expect(stages.where(pipeline_id: 1).order(:id).pluck(:name)) .to eq %w[test build deploy] expect(stages.where(pipeline_id: 2).order(:id).pluck(:name)) .to eq %w[test:1 test:2 deploy] + expect(stages.where(pipeline_id: 3).count).to be_zero + expect(stages.where(project_id: 789).count).to be_zero end end -- cgit v1.2.3 From c9a67266d2a79bd55f944516716a59300c1844f6 Mon Sep 17 00:00:00 2001 From: Bryce Johnson Date: Mon, 15 May 2017 18:12:43 -0400 Subject: Move issuable bulk edit form into a new sidebar. --- .../features/issues/bulk_assignment_labels_spec.rb | 70 ++++++++++++---------- spec/features/issues/update_issues_spec.rb | 24 +++++--- .../merge_requests/update_merge_requests_spec.rb | 13 ++-- .../javascripts/fixtures/issuable_filter.html.haml | 2 +- spec/javascripts/issuable_spec.js | 16 ++--- 5 files changed, 69 insertions(+), 56 deletions(-) (limited to 'spec') diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index 0a6f645b27e..95b4930cd32 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -18,13 +18,13 @@ feature 'Issues > Labels bulk assignment', feature: true do context 'can bulk assign' do before do - visit namespace_project_issues_path(project.namespace, project) + enable_bulk_update end context 'a label' do context 'to all issues' do before do - check 'check_all_issues' + check 'check-all-issues' open_labels_dropdown ['bug'] update_issues end @@ -52,7 +52,7 @@ feature 'Issues > Labels bulk assignment', feature: true do context 'multiple labels' do context 'to all issues' do before do - check 'check_all_issues' + check 'check-all-issues' open_labels_dropdown %w(bug feature) update_issues end @@ -86,9 +86,10 @@ feature 'Issues > Labels bulk assignment', feature: true do before do issue2.labels << bug issue2.labels << feature - visit namespace_project_issues_path(project.namespace, project) - check 'check_all_issues' + enable_bulk_update + check 'check-all-issues' + open_labels_dropdown ['bug'] update_issues end @@ -107,9 +108,8 @@ feature 'Issues > Labels bulk assignment', feature: true do issue2.labels << bug issue2.labels << feature - visit namespace_project_issues_path(project.namespace, project) - - check 'check_all_issues' + enable_bulk_update + check 'check-all-issues' unmark_labels_in_dropdown %w(bug feature) update_issues end @@ -127,8 +127,7 @@ feature 'Issues > Labels bulk assignment', feature: true do issue1.labels << bug issue2.labels << feature - visit namespace_project_issues_path(project.namespace, project) - + enable_bulk_update check_issue issue1 unmark_labels_in_dropdown ['bug'] update_issues @@ -147,8 +146,7 @@ feature 'Issues > Labels bulk assignment', feature: true do issue2.labels << bug issue2.labels << feature - visit namespace_project_issues_path(project.namespace, project) - + enable_bulk_update check_issue issue1 check_issue issue2 unmark_labels_in_dropdown ['bug'] @@ -171,14 +169,15 @@ feature 'Issues > Labels bulk assignment', feature: true do before do issue1.labels << bug issue2.labels << feature - visit namespace_project_issues_path(project.namespace, project) + enable_bulk_update end it 'keeps labels' do expect(find("#issue_#{issue1.id}")).to have_content 'bug' expect(find("#issue_#{issue2.id}")).to have_content 'feature' - check 'check_all_issues' + check 'check-all-issues' + open_milestone_dropdown(['First Release']) update_issues @@ -192,14 +191,13 @@ feature 'Issues > Labels bulk assignment', feature: true do context 'setting a milestone and adding another label' do before do issue1.labels << bug - - visit namespace_project_issues_path(project.namespace, project) + enable_bulk_update end it 'keeps existing label and new label is present' do expect(find("#issue_#{issue1.id}")).to have_content 'bug' - check 'check_all_issues' + check 'check-all-issues' open_milestone_dropdown ['First Release'] open_labels_dropdown ['feature'] update_issues @@ -218,7 +216,7 @@ feature 'Issues > Labels bulk assignment', feature: true do issue1.labels << feature issue2.labels << feature - visit namespace_project_issues_path(project.namespace, project) + enable_bulk_update end it 'keeps existing label and new label is present' do @@ -226,7 +224,8 @@ feature 'Issues > Labels bulk assignment', feature: true do expect(find("#issue_#{issue1.id}")).to have_content 'bug' expect(find("#issue_#{issue2.id}")).to have_content 'feature' - check 'check_all_issues' + check 'check-all-issues' + open_milestone_dropdown ['First Release'] unmark_labels_in_dropdown ['feature'] update_issues @@ -248,7 +247,7 @@ feature 'Issues > Labels bulk assignment', feature: true do issue1.labels << bug issue2.labels << feature - visit namespace_project_issues_path(project.namespace, project) + enable_bulk_update end it 'keeps labels' do @@ -257,7 +256,7 @@ feature 'Issues > Labels bulk assignment', feature: true do expect(find("#issue_#{issue2.id}")).to have_content 'feature' expect(find("#issue_#{issue2.id}")).to have_content 'First Release' - check 'check_all_issues' + check 'check-all-issues' open_milestone_dropdown(['No Milestone']) update_issues @@ -272,8 +271,7 @@ feature 'Issues > Labels bulk assignment', feature: true do context 'toggling checked issues' do before do issue1.labels << bug - - visit namespace_project_issues_path(project.namespace, project) + enable_bulk_update end it do @@ -298,14 +296,14 @@ feature 'Issues > Labels bulk assignment', feature: true do issue1.labels << feature issue2.labels << bug - visit namespace_project_issues_path(project.namespace, project) + enable_bulk_update end it 'applies label from filtered results' do - check 'check_all_issues' + check 'check-all-issues' - page.within('.issues_bulk_update') do - click_button 'Labels' + page.within('.issues-bulk-update') do + click_button 'Select labels' wait_for_requests expect(find('.dropdown-menu-labels li', text: 'bug')).to have_css('.is-active') @@ -340,15 +338,16 @@ feature 'Issues > Labels bulk assignment', feature: true do context 'cannot bulk assign labels' do it do - expect(page).not_to have_css '.check_all_issues' + expect(page).not_to have_button 'Edit Issues' + expect(page).not_to have_css '.check-all-issues' expect(page).not_to have_css '.issue-check' end end end def open_milestone_dropdown(items = []) - page.within('.issues_bulk_update') do - click_button 'Milestone' + page.within('.issues-bulk-update') do + click_button 'Select milestone' wait_for_requests items.map do |item| click_link item @@ -357,8 +356,8 @@ feature 'Issues > Labels bulk assignment', feature: true do end def open_labels_dropdown(items = [], unmark = false) - page.within('.issues_bulk_update') do - click_button 'Labels' + page.within('.issues-bulk-update') do + click_button 'Select labels' wait_for_requests items.map do |item| click_link item @@ -391,7 +390,12 @@ feature 'Issues > Labels bulk assignment', feature: true do end def update_issues - click_button 'Update issues' + click_button 'Update all' wait_for_requests end + + def enable_bulk_update + visit namespace_project_issues_path(project.namespace, project) + click_button 'Edit Issues' + end end diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb index 0911f1db9ba..8595847d313 100644 --- a/spec/features/issues/update_issues_spec.rb +++ b/spec/features/issues/update_issues_spec.rb @@ -14,7 +14,8 @@ feature 'Multiple issue updating from issues#index', feature: true do it 'sets to closed' do visit namespace_project_issues_path(project.namespace, project) - find('#check_all_issues').click + click_button 'Edit Issues' + find('#check-all-issues').click find('.js-issue-status').click find('.dropdown-menu-status a', text: 'Closed').click @@ -26,7 +27,8 @@ feature 'Multiple issue updating from issues#index', feature: true do create_closed visit namespace_project_issues_path(project.namespace, project, state: 'closed') - find('#check_all_issues').click + click_button 'Edit Issues' + find('#check-all-issues').click find('.js-issue-status').click find('.dropdown-menu-status a', text: 'Open').click @@ -39,7 +41,8 @@ feature 'Multiple issue updating from issues#index', feature: true do it 'updates to current user' do visit namespace_project_issues_path(project.namespace, project) - find('#check_all_issues').click + click_button 'Edit Issues' + find('#check-all-issues').click click_update_assignee_button find('.dropdown-menu-user-link', text: user.username).click @@ -54,7 +57,8 @@ feature 'Multiple issue updating from issues#index', feature: true do create_assigned visit namespace_project_issues_path(project.namespace, project) - find('#check_all_issues').click + click_button 'Edit Issues' + find('#check-all-issues').click click_update_assignee_button click_link 'Unassigned' @@ -69,8 +73,9 @@ feature 'Multiple issue updating from issues#index', feature: true do it 'updates milestone' do visit namespace_project_issues_path(project.namespace, project) - find('#check_all_issues').click - find('.issues_bulk_update .js-milestone-select').click + click_button 'Edit Issues' + find('#check-all-issues').click + find('.issues-bulk-update .js-milestone-select').click find('.dropdown-menu-milestone a', text: milestone.title).click click_update_issues_button @@ -84,8 +89,9 @@ feature 'Multiple issue updating from issues#index', feature: true do expect(first('.issue')).to have_content milestone.title - find('#check_all_issues').click - find('.issues_bulk_update .js-milestone-select').click + click_button 'Edit Issues' + find('#check-all-issues').click + find('.issues-bulk-update .js-milestone-select').click find('.dropdown-menu-milestone a', text: "No Milestone").click click_update_issues_button @@ -112,7 +118,7 @@ feature 'Multiple issue updating from issues#index', feature: true do end def click_update_issues_button - find('.update_selected_issues').click + find('.update-selected-issues').click wait_for_requests end end diff --git a/spec/features/merge_requests/update_merge_requests_spec.rb b/spec/features/merge_requests/update_merge_requests_spec.rb index 4ef59a8aeb8..bcdfdf78a44 100644 --- a/spec/features/merge_requests/update_merge_requests_spec.rb +++ b/spec/features/merge_requests/update_merge_requests_spec.rb @@ -98,14 +98,16 @@ feature 'Multiple merge requests updating from merge_requests#index', feature: t end def change_status(text) - find('#check_all_issues').click + click_button 'Edit Merge Requests' + find('#check-all-issues').click find('.js-issue-status').click find('.dropdown-menu-status a', text: text).click click_update_merge_requests_button end def change_assignee(text) - find('#check_all_issues').click + click_button 'Edit Merge Requests' + find('#check-all-issues').click find('.js-update-assignee').click wait_for_requests @@ -117,14 +119,15 @@ feature 'Multiple merge requests updating from merge_requests#index', feature: t end def change_milestone(text) - find('#check_all_issues').click - find('.issues_bulk_update .js-milestone-select').click + click_button 'Edit Merge Requests' + find('#check-all-issues').click + find('.issues-bulk-update .js-milestone-select').click find('.dropdown-menu-milestone a', text: text).click click_update_merge_requests_button end def click_update_merge_requests_button - find('.update_selected_issues').click + find('.update-selected-issues').click wait_for_requests end end diff --git a/spec/javascripts/fixtures/issuable_filter.html.haml b/spec/javascripts/fixtures/issuable_filter.html.haml index ae745b292e6..84fa5395cb8 100644 --- a/spec/javascripts/fixtures/issuable_filter.html.haml +++ b/spec/javascripts/fixtures/issuable_filter.html.haml @@ -1,6 +1,6 @@ %form.js-filter-form{action: '/user/project/issues?scope=all&state=closed'} %input{id: 'utf8', name: 'utf8', value: '✓'} - %input{id: 'check_all_issues', name: 'check_all_issues'} + %input{id: 'check-all-issues', name: 'check-all-issues'} %input{id: 'search', name: 'search'} %input{id: 'author_id', name: 'author_id'} %input{id: 'assignee_id', name: 'assignee_id'} diff --git a/spec/javascripts/issuable_spec.js b/spec/javascripts/issuable_spec.js index 49fa2cb8367..45f55395d3a 100644 --- a/spec/javascripts/issuable_spec.js +++ b/spec/javascripts/issuable_spec.js @@ -1,7 +1,7 @@ -/* global Issuable */ +/* global IssuableIndex */ import '~/lib/utils/url_utility'; -import '~/issuable'; +import '~/issuable_index'; (() => { const BASE_URL = '/user/project/issues?scope=all&state=closed'; @@ -24,11 +24,11 @@ import '~/issuable'; beforeEach(() => { loadFixtures('static/issuable_filter.html.raw'); - Issuable.init(); + IssuableIndex.init(); }); it('should be defined', () => { - expect(window.Issuable).toBeDefined(); + expect(window.IssuableIndex).toBeDefined(); }); describe('filtering', () => { @@ -43,7 +43,7 @@ import '~/issuable'; it('should contain only the default parameters', () => { spyOn(gl.utils, 'visitUrl'); - Issuable.filterResults($filtersForm); + IssuableIndex.filterResults($filtersForm); expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + DEFAULT_PARAMS); }); @@ -52,7 +52,7 @@ import '~/issuable'; spyOn(gl.utils, 'visitUrl'); updateForm({ search: 'broken' }, $filtersForm); - Issuable.filterResults($filtersForm); + IssuableIndex.filterResults($filtersForm); const params = `${DEFAULT_PARAMS}&search=broken`; expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + params); @@ -64,14 +64,14 @@ import '~/issuable'; // initial filter updateForm({ milestone_title: 'v1.0' }, $filtersForm); - Issuable.filterResults($filtersForm); + IssuableIndex.filterResults($filtersForm); let params = `${DEFAULT_PARAMS}&milestone_title=v1.0`; expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + params); // update filter updateForm({ label_name: 'Frontend' }, $filtersForm); - Issuable.filterResults($filtersForm); + IssuableIndex.filterResults($filtersForm); params = `${DEFAULT_PARAMS}&milestone_title=v1.0&label_name=Frontend`; expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + params); }); -- cgit v1.2.3 From 602724fcfc9c482d248e512a07fdf0fda6dd0613 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 6 Jun 2017 15:29:02 +0200 Subject: Clone stage_id when retrying a CI/CD job --- spec/services/ci/retry_build_service_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 2bd5af25847..7254e6b357a 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -18,12 +18,11 @@ describe Ci::RetryBuildService, :services do updated_at started_at finished_at queued_at erased_by erased_at auto_canceled_by].freeze - # TODO, move stage_id accessor to CLONE_ACCESSOR in a follow-up MR. IGNORE_ACCESSORS = %i[type lock_version target_url base_tags commit_id deployments erased_by_id last_deployment project_id runner_id tag_taggings taggings tags trigger_request_id - user_id auto_canceled_by_id retried stage_id].freeze + user_id auto_canceled_by_id retried].freeze shared_examples 'build duplication' do let(:build) do -- cgit v1.2.3 From d919f924bf32220237c389dc913093efead8928c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 6 Jun 2017 21:42:45 +0800 Subject: Backport https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1942 --- spec/models/user_spec.rb | 4 ++++ spec/requests/api/users_spec.rb | 13 +++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 1c3541da44f..a83726b48a0 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -13,6 +13,10 @@ describe User, models: true do it { is_expected.to include_module(TokenAuthenticatable) } end + describe 'delegations' do + it { is_expected.to delegate_method(:path).to(:namespace).with_prefix } + end + describe 'associations' do it { is_expected.to have_one(:namespace) } it { is_expected.to have_many(:snippets).dependent(:destroy) } diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 1c33b8f9502..358cc784afe 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -426,9 +426,14 @@ describe API::Users do expect(user.reload.email).not_to eq('invalid email') end - it "is not available for non admin users" do - put api("/users/#{user.id}", user), attributes_for(:user) - expect(response).to have_http_status(403) + context 'when the current user is not an admin' do + it "is not available" do + expect do + put api("/users/#{user.id}", user), attributes_for(:user) + end.not_to change { user.reload.attributes } + + expect(response).to have_http_status(403) + end end it "returns 404 for non-existing user" do @@ -649,7 +654,7 @@ describe API::Users do end it "returns a 404 for invalid ID" do - put api("/users/ASDF/emails", admin) + get api("/users/ASDF/emails", admin) expect(response).to have_http_status(404) end -- cgit v1.2.3 From 1110def8e21d4927a127783d468fbddf3cc886c7 Mon Sep 17 00:00:00 2001 From: Roman Safronov Date: Tue, 6 Jun 2017 13:55:29 +0000 Subject: Introduce optimistic locking support via optional parameter last_commit_id on File Update API --- spec/requests/api/files_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'spec') diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index deb2cac6869..d325c6eff9d 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -258,6 +258,25 @@ describe API::Files do expect(last_commit.author_name).to eq(user.name) end + it "returns a 400 bad request if update existing file with stale last commit id" do + params_with_stale_id = valid_params.merge(last_commit_id: 'stale') + + put api(route(file_path), user), params_with_stale_id + + expect(response).to have_http_status(400) + expect(json_response['message']).to eq('You are attempting to update a file that has changed since you started editing it.') + end + + it "updates existing file in project repo with accepts correct last commit id" do + last_commit = Gitlab::Git::Commit + .last_for_path(project.repository, 'master', URI.unescape(file_path)) + params_with_correct_id = valid_params.merge(last_commit_id: last_commit.id) + + put api(route(file_path), user), params_with_correct_id + + expect(response).to have_http_status(200) + end + it "returns a 400 bad request if no params given" do put api(route(file_path), user) -- cgit v1.2.3 From d8403ec18f771c28eb566dc3ce6dc08bffd2db22 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Tue, 6 Jun 2017 09:01:42 -0500 Subject: Minor visual adjustments --- spec/javascripts/groups/group_item_spec.js | 2 +- spec/javascripts/groups/groups_spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/groups/group_item_spec.js b/spec/javascripts/groups/group_item_spec.js index 609c45250f1..47af735f4b4 100644 --- a/spec/javascripts/groups/group_item_spec.js +++ b/spec/javascripts/groups/group_item_spec.js @@ -3,7 +3,7 @@ import groupItemComponent from '~/groups/components/group_item.vue'; import GroupsStore from '~/groups/stores/groups_store'; import { group1 } from './mock_data'; -describe('Groups Component', () => { +fdescribe('Groups Component', () => { let GroupItemComponent; let component; let store; diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js index d1f900df3d8..dc144914c60 100644 --- a/spec/javascripts/groups/groups_spec.js +++ b/spec/javascripts/groups/groups_spec.js @@ -5,7 +5,7 @@ import groupsComponent from '~/groups/components/groups.vue'; import GroupsStore from '~/groups/stores/groups_store'; import { groupsData } from './mock_data'; -describe('Groups Component', () => { +fdescribe('Groups Component', () => { let GroupsComponent; let store; let component; -- cgit v1.2.3 From bd951384142f3f5ec71bd78a23aae917f151b47f Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Tue, 6 Jun 2017 09:02:29 -0500 Subject: Remove non existent bundle --- spec/javascripts/test_bundle.js | 1 - 1 file changed, 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js index 13827a26571..2c34402576b 100644 --- a/spec/javascripts/test_bundle.js +++ b/spec/javascripts/test_bundle.js @@ -51,7 +51,6 @@ if (process.env.BABEL_ENV === 'coverage') { './environments/environments_bundle.js', './filtered_search/filtered_search_bundle.js', './graphs/graphs_bundle.js', - './issuable/issuable_bundle.js', './issuable/time_tracking/time_tracking_bundle.js', './main.js', './merge_conflicts/merge_conflicts_bundle.js', -- cgit v1.2.3 From 9fcc3e5982311a380681c822df72fe470a5ea1ca Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Tue, 6 Jun 2017 13:18:01 +0200 Subject: Fix test failures --- spec/features/profiles/personal_access_tokens_spec.rb | 6 +++++- spec/lib/gitlab/auth_spec.rb | 19 ++++++++----------- spec/requests/jwt_controller_spec.rb | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'spec') diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index 27a20e78a43..7e2e685df26 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -17,6 +17,7 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do def disallow_personal_access_token_saves! allow_any_instance_of(PersonalAccessToken).to receive(:save).and_return(false) + errors = ActiveModel::Errors.new(PersonalAccessToken.new).tap { |e| e.add(:name, "cannot be nil") } allow_any_instance_of(PersonalAccessToken).to receive(:errors).and_return(errors) end @@ -91,8 +92,11 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do context "when revocation fails" do it "displays an error message" do - disallow_personal_access_token_saves! visit profile_personal_access_tokens_path + allow_any_instance_of(PersonalAccessToken).to receive(:update!).and_return(false) + + errors = ActiveModel::Errors.new(PersonalAccessToken.new).tap { |e| e.add(:name, "cannot be nil") } + allow_any_instance_of(PersonalAccessToken).to receive(:errors).and_return(errors) click_on "Revoke" expect(active_personal_access_tokens).to have_text(personal_access_token.name) diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index 6574e6d0087..d6006eab0c9 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -17,7 +17,11 @@ describe Gitlab::Auth, lib: true do end it 'OPTIONAL_SCOPES contains all non-default scopes' do - expect(subject::OPTIONAL_SCOPES).to eq [:read_user, :openid] + expect(subject::OPTIONAL_SCOPES).to eq %i[read_user read_registry openid] + end + + it 'REGISTRY_SCOPES contains all registry related scopes' do + expect(subject::REGISTRY_SCOPES).to eq %i[read_registry] end end @@ -157,18 +161,11 @@ describe Gitlab::Auth, lib: true do expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(impersonation_token.user, nil, :personal_token, full_authentication_abilities)) end - it 'fails for personal access tokens with other scopes' do + it 'limits abilities based on scope' do personal_access_token = create(:personal_access_token, scopes: ['read_user']) - expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '') - expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil)) - end - - it 'fails for impersonation token with other scopes' do - impersonation_token = create(:personal_access_token, scopes: ['read_user']) - - expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '') - expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil)) + expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '') + expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_token, [])) end it 'fails if password is nil' do diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb index 8ddae9f6b89..e056353fa6f 100644 --- a/spec/requests/jwt_controller_spec.rb +++ b/spec/requests/jwt_controller_spec.rb @@ -102,7 +102,7 @@ describe JwtController do end it 'allows read access' do - expect(service).to receive(:execute).with(authentication_abilities: Gitlab::Auth.read_api_abilities) + expect(service).to receive(:execute).with(authentication_abilities: Gitlab::Auth.read_authentication_abilities) get '/jwt/auth', parameters end -- cgit v1.2.3 From 3cda57b4abee016c35867760ffd07c7b9c93e041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 6 Jun 2017 16:23:40 +0200 Subject: Actually clean gitlab-test path when TestEnv.set_repo_refs fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/support/test_env.rb | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 72b3b226c1e..3f472e59c49 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -54,6 +54,8 @@ module TestEnv 'conflict-resolvable-fork' => '404fa3f' }.freeze + TMP_TEST_PATH = Rails.root.join('tmp', 'tests', '**') + # Test environment # # See gitlab.yml.example test section for paths @@ -98,9 +100,7 @@ module TestEnv # # Keeps gitlab-shell and gitlab-test def clean_test_path - tmp_test_path = Rails.root.join('tmp', 'tests', '**') - - Dir[tmp_test_path].each do |entry| + Dir[TMP_TEST_PATH].each do |entry| unless File.basename(entry) =~ /\A(gitaly|gitlab-(shell|test|test_bare|test-fork|test-fork_bare))\z/ FileUtils.rm_rf(entry) end @@ -111,6 +111,14 @@ module TestEnv FileUtils.mkdir_p(pages_path) end + def clean_gitlab_test_path + Dir[TMP_TEST_PATH].each do |entry| + if File.basename(entry) =~ /\A(gitlab-(test|test_bare|test-fork|test-fork_bare))\z/ + FileUtils.rm_rf(entry) + end + end + end + def setup_gitlab_shell unless File.directory?(Gitlab.config.gitlab_shell.path) unless system('rake', 'gitlab:shell:install') @@ -249,7 +257,7 @@ module TestEnv # Before we used Git clone's --mirror option, bare repos could end up # with missing refs, clearing them and retrying should fix the issue. - cleanup && init unless reset.call + cleanup && clean_gitlab_test_path && init unless reset.call end end -- cgit v1.2.3 From da8bd81fe7c1042c50d7c693fdf37ea5b7b78285 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 6 Jun 2017 16:45:24 +0200 Subject: Fix reverting builds stage ref migration on MySQL --- spec/migrations/migrate_build_stage_reference_spec.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'spec') diff --git a/spec/migrations/migrate_build_stage_reference_spec.rb b/spec/migrations/migrate_build_stage_reference_spec.rb index 32f9a0c0642..80b321860c2 100644 --- a/spec/migrations/migrate_build_stage_reference_spec.rb +++ b/spec/migrations/migrate_build_stage_reference_spec.rb @@ -16,7 +16,6 @@ describe MigrateBuildStageReference, :migration do # projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1') projects.create!(id: 456, name: 'gitlab2', path: 'gitlab2') - projects.create!(id: 798, name: 'gitlab3', path: 'gitlab3') # Create CI/CD pipelines # -- cgit v1.2.3 From 5c602e306cdf979a70aaa81cd473f491f2eee45a Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 6 Jun 2017 15:55:12 +0100 Subject: Limit non-administrators to adding 100 members at a time to groups and projects --- spec/controllers/admin/groups_controller_spec.rb | 9 +++++++++ .../projects/project_members_controller_spec.rb | 6 +++--- spec/services/members/create_service_spec.rb | 16 ++++++++++++++-- 3 files changed, 26 insertions(+), 5 deletions(-) (limited to 'spec') diff --git a/spec/controllers/admin/groups_controller_spec.rb b/spec/controllers/admin/groups_controller_spec.rb index c29b2fe8946..ddf38967dd7 100644 --- a/spec/controllers/admin/groups_controller_spec.rb +++ b/spec/controllers/admin/groups_controller_spec.rb @@ -36,6 +36,15 @@ describe Admin::GroupsController do expect(group.users).to include group_user end + it 'can add unlimited members' do + put :members_update, id: group, + user_ids: 1.upto(1000).to_a.join(','), + access_level: Gitlab::Access::GUEST + + expect(response).to set_flash.to 'Users were successfully added.' + expect(response).to redirect_to(admin_group_path(group)) + end + it 'adds no user to members' do put :members_update, id: group, user_ids: '', diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index a4b4392d7cc..2294d5df581 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -36,7 +36,7 @@ describe Projects::ProjectMembersController do before { project.team << [user, :master] } it 'adds user to members' do - expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(true) + expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(status: :success) post :create, namespace_id: project.namespace, project_id: project, @@ -48,14 +48,14 @@ describe Projects::ProjectMembersController do end it 'adds no user to members' do - expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(false) + expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(status: :failure, message: 'Message') post :create, namespace_id: project.namespace, project_id: project, user_ids: '', access_level: Gitlab::Access::GUEST - expect(response).to set_flash.to 'No users specified.' + expect(response).to set_flash.to 'Message' expect(response).to redirect_to(namespace_project_settings_members_path(project.namespace, project)) end end diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb index 0670ac2faa2..5ce8e17976b 100644 --- a/spec/services/members/create_service_spec.rb +++ b/spec/services/members/create_service_spec.rb @@ -11,7 +11,7 @@ describe Members::CreateService, services: true do params = { user_ids: project_user.id.to_s, access_level: Gitlab::Access::GUEST } result = described_class.new(project, user, params).execute - expect(result).to be_truthy + expect(result[:status]).to eq(:success) expect(project.users).to include project_user end @@ -19,7 +19,19 @@ describe Members::CreateService, services: true do params = { user_ids: '', access_level: Gitlab::Access::GUEST } result = described_class.new(project, user, params).execute - expect(result).to be_falsey + expect(result[:status]).to eq(:error) + expect(result[:message]).to be_present + expect(project.users).not_to include project_user + end + + it 'limits the number of users to 100' do + user_ids = 1.upto(101).to_a.join(',') + params = { user_ids: user_ids, access_level: Gitlab::Access::GUEST } + + result = described_class.new(project, user, params).execute + + expect(result[:status]).to eq(:error) + expect(result[:message]).to be_present expect(project.users).not_to include project_user end end -- cgit v1.2.3 From 973e8c0fc50bc6614ca42413555a3f73625c7efa Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 6 Jun 2017 16:27:54 +0100 Subject: updated service spec --- spec/services/boards/lists/list_service_spec.rb | 37 ++++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb index 97063381196..99016a8be0c 100644 --- a/spec/services/boards/lists/list_service_spec.rb +++ b/spec/services/boards/lists/list_service_spec.rb @@ -1,16 +1,39 @@ require 'spec_helper' describe Boards::Lists::ListService, services: true do + let(:project) { create(:empty_project) } + let(:board) { create(:board, project: project) } + let(:label) { create(:label, project: project) } + let!(:list) { create(:list, board: board, label: label) } + let(:service) { described_class.new(project, double) } + describe '#execute' do - it "returns board's lists" do - project = create(:empty_project) - board = create(:board, project: project) - label = create(:label, project: project) - list = create(:list, board: board, label: label) + context 'when the board has a backlog list' do + before do + create(:backlog_list, board: board) + end + + it 'does not create a backlog list' do + service.execute(board) + + expect(board.lists.merge(List.backlog)).to eq [board.backlog_list] + end + + it "returns board's lists" do + expect(service.execute(board)).to eq [board.backlog_list, list, board.closed_list] + end + end + + context 'when the board does not have a backlog list' do + it 'creates a backlog list' do + service.execute(board) - service = described_class.new(project, double) + expect(board.backlog_list).not_to be nil + end - expect(service.execute(board)).to eq [board.backlog_list, list, board.closed_list] + it "returns board's lists" do + expect(service.execute(board)).to eq [board.backlog_list, list, board.closed_list] + end end end end -- cgit v1.2.3 From bf6961cad85ab9a60f37f9b2974fb7bdd3975810 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 6 Jun 2017 23:36:41 +0800 Subject: Just let the user to create the namespace --- spec/models/forked_project_link_spec.rb | 4 ++-- spec/services/projects/fork_service_spec.rb | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb index 454550c9710..6e8d43f988c 100644 --- a/spec/models/forked_project_link_spec.rb +++ b/spec/models/forked_project_link_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe ForkedProjectLink, "add link on fork" do let(:project_from) { create(:project, :repository) } - let(:namespace) { create(:namespace) } - let(:user) { create(:user, namespace: namespace) } + let(:user) { create(:user) } + let(:namespace) { user.namespace } before do create(:project_member, :reporter, user: user, project: project_from) diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index f8eb34f2ef4..0df81f3abcb 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe Projects::ForkService, services: true do describe 'fork by user' do before do - @from_namespace = create(:namespace) - @from_user = create(:user, namespace: @from_namespace ) + @from_user = create(:user) + @from_namespace = @from_user.namespace avatar = fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png") @from_project = create(:project, :repository, @@ -13,8 +13,8 @@ describe Projects::ForkService, services: true do star_count: 107, avatar: avatar, description: 'wow such project') - @to_namespace = create(:namespace) - @to_user = create(:user, namespace: @to_namespace) + @to_user = create(:user) + @to_namespace = @to_user.namespace @from_project.add_user(@to_user, :developer) end -- cgit v1.2.3 From 196a3c546c1d341cd2b7d5077a906c6779452fba Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Tue, 6 Jun 2017 10:48:45 -0500 Subject: Change from double click to single click to open dropdown --- .../issues/filtered_search/visual_tokens_spec.rb | 4 +-- .../filtered_search_manager_spec.js | 36 ---------------------- 2 files changed, 2 insertions(+), 38 deletions(-) (limited to 'spec') diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index dbbafc9e004..ff32b0c7d11 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -34,7 +34,7 @@ describe 'Visual tokens', js: true, feature: true do describe 'editing author token' do before do input_filtered_search('author:@root assignee:none', submit: false) - first('.tokens-container .filtered-search-token').double_click + first('.tokens-container .filtered-search-token').click end it 'opens author dropdown' do @@ -331,7 +331,7 @@ describe 'Visual tokens', js: true, feature: true do it 'does not tokenize incomplete token' do filtered_search.send_keys('author:') - find('#content-body').click + find('body').click token = page.all('.tokens-container .js-visual-token')[1] expect_filtered_search_input_empty diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js index 6e59ee96c6b..9c8629ef9f0 100644 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js @@ -316,42 +316,6 @@ describe('Filtered Search Manager', () => { }); }); - describe('unselects token', () => { - beforeEach(() => { - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(` - ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug', true)} - ${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')} - ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~awesome')} - `); - }); - - it('unselects token when input is clicked', () => { - const selectedToken = tokensContainer.querySelector('.js-visual-token .selected'); - - expect(selectedToken.classList.contains('selected')).toEqual(true); - expect(gl.FilteredSearchVisualTokens.unselectTokens).not.toHaveBeenCalled(); - - // Click directly on input attached to document - // so that the click event will propagate properly - document.querySelector('.filtered-search').click(); - - expect(gl.FilteredSearchVisualTokens.unselectTokens).toHaveBeenCalled(); - expect(selectedToken.classList.contains('selected')).toEqual(false); - }); - - it('unselects token when document.body is clicked', () => { - const selectedToken = tokensContainer.querySelector('.js-visual-token .selected'); - - expect(selectedToken.classList.contains('selected')).toEqual(true); - expect(gl.FilteredSearchVisualTokens.unselectTokens).not.toHaveBeenCalled(); - - document.body.click(); - - expect(selectedToken.classList.contains('selected')).toEqual(false); - expect(gl.FilteredSearchVisualTokens.unselectTokens).toHaveBeenCalled(); - }); - }); - describe('toggleInputContainerFocus', () => { it('toggles on focus', () => { input.focus(); -- cgit v1.2.3 From 6b53add3f93caffa830e3bdbb3d8fd8d674ee3aa Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 6 Jun 2017 16:40:07 +0000 Subject: Fix binary encoding error on MR diffs --- spec/models/merge_request_diff_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'spec') diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index 0a10ee01506..ed9fde57bf7 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -139,4 +139,15 @@ describe MergeRequestDiff, models: true do expect(subject.commits_count).to eq 2 end end + + describe '#utf8_st_diffs' do + it 'does not raise error when a hash value is in binary' do + subject.st_diffs = [ + { diff: "\0" }, + { diff: "\x05\x00\x68\x65\x6c\x6c\x6f" } + ] + + expect { subject.utf8_st_diffs }.not_to raise_error + end + end end -- cgit v1.2.3 From d93352825ae1b738d1d1922f26308166447b041d Mon Sep 17 00:00:00 2001 From: Paul Charlton Date: Tue, 6 Jun 2017 16:48:10 +0000 Subject: redesign caching of application settings --- spec/controllers/projects/merge_requests_controller_spec.rb | 2 +- spec/lib/gitlab/current_settings_spec.rb | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index a25db7a65fb..08024a2148b 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -126,7 +126,7 @@ describe Projects::MergeRequestsController do recorded = ActiveRecord::QueryRecorder.new { go(format: :json) } - expect(recorded.count).to be_within(5).of(59) + expect(recorded.count).to be_within(5).of(50) expect(recorded.cached_count).to eq(0) end end diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb index c796c98ec9f..fda39d78610 100644 --- a/spec/lib/gitlab/current_settings_spec.rb +++ b/spec/lib/gitlab/current_settings_spec.rb @@ -14,20 +14,20 @@ describe Gitlab::CurrentSettings do end it 'attempts to use cached values first' do - expect(ApplicationSetting).to receive(:current) - expect(ApplicationSetting).not_to receive(:last) + expect(ApplicationSetting).to receive(:cached) expect(current_application_settings).to be_a(ApplicationSetting) end it 'falls back to DB if Redis returns an empty value' do + expect(ApplicationSetting).to receive(:cached).and_return(nil) expect(ApplicationSetting).to receive(:last).and_call_original expect(current_application_settings).to be_a(ApplicationSetting) end it 'falls back to DB if Redis fails' do - expect(ApplicationSetting).to receive(:current).and_raise(::Redis::BaseError) + expect(ApplicationSetting).to receive(:cached).and_raise(::Redis::BaseError) expect(ApplicationSetting).to receive(:last).and_call_original expect(current_application_settings).to be_a(ApplicationSetting) @@ -37,6 +37,7 @@ describe Gitlab::CurrentSettings do context 'with DB unavailable' do before do allow_any_instance_of(described_class).to receive(:connect_to_db?).and_return(false) + allow_any_instance_of(described_class).to receive(:retrieve_settings_from_database_cache?).and_return(nil) end it 'returns an in-memory ApplicationSetting object' do -- cgit v1.2.3 From 8a417f5ae89a509a006bac8a2d6104d8b169782c Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 4 Jun 2017 22:12:18 -0700 Subject: Set artifact working directory to be in the destination store to prevent unnecessary I/O Similar to #33218, build artifacts were being uploaded into a CarrierWave temporary directory in the Rails root directory before moved to their final destination, which could cause a copy across filesystems. This merge request refactors the work in !11866 so that any uploader can just override `work_dir` to change the default implementation. Closes #33274 --- spec/uploaders/artifact_uploader_spec.rb | 15 +++++++++--- spec/uploaders/gitlab_uploader_spec.rb | 15 ++++++++++++ spec/uploaders/lfs_object_uploader_spec.rb | 39 ++++++++++++++++++------------ 3 files changed, 50 insertions(+), 19 deletions(-) (limited to 'spec') diff --git a/spec/uploaders/artifact_uploader_spec.rb b/spec/uploaders/artifact_uploader_spec.rb index 24e2e3a9f0e..b3fac65c55e 100644 --- a/spec/uploaders/artifact_uploader_spec.rb +++ b/spec/uploaders/artifact_uploader_spec.rb @@ -17,22 +17,29 @@ describe ArtifactUploader do describe '.artifacts_upload_path' do subject { described_class.artifacts_upload_path } - + it { is_expected.to start_with(path) } it { is_expected.to end_with('tmp/uploads/') } end describe '#store_dir' do subject { uploader.store_dir } - + it { is_expected.to start_with(path) } it { is_expected.to end_with("#{job.project_id}/#{job.id}") } end describe '#cache_dir' do subject { uploader.cache_dir } - + + it { is_expected.to start_with(path) } + it { is_expected.to end_with('/tmp/cache') } + end + + describe '#work_dir' do + subject { uploader.work_dir } + it { is_expected.to start_with(path) } - it { is_expected.to end_with('tmp/cache') } + it { is_expected.to end_with('/tmp/work') } end end diff --git a/spec/uploaders/gitlab_uploader_spec.rb b/spec/uploaders/gitlab_uploader_spec.rb index 78e9d9cf46c..a144b39f74f 100644 --- a/spec/uploaders/gitlab_uploader_spec.rb +++ b/spec/uploaders/gitlab_uploader_spec.rb @@ -53,4 +53,19 @@ describe GitlabUploader do expect(subject.move_to_store).to eq(true) end end + + describe '#cache!' do + it 'moves the file from the working directory to the cache directory' do + # One to get the work dir, the other to remove it + expect(subject).to receive(:workfile_path).exactly(2).times.and_call_original + # Test https://github.com/carrierwavesubject/carrierwave/blob/v1.0.0/lib/carrierwave/sanitized_file.rb#L200 + expect(FileUtils).to receive(:mv).with(anything, /^#{subject.work_dir}/).and_call_original + expect(FileUtils).to receive(:mv).with(/^#{subject.work_dir}/, /#{subject.cache_dir}/).and_call_original + + fixture = Rails.root.join('spec', 'fixtures', 'rails_sample.jpg') + subject.cache!(fixture_file_upload(fixture)) + + expect(subject.file.path).to match(/#{subject.cache_dir}/) + end + end end diff --git a/spec/uploaders/lfs_object_uploader_spec.rb b/spec/uploaders/lfs_object_uploader_spec.rb index c3b72e7d677..7088bc23334 100644 --- a/spec/uploaders/lfs_object_uploader_spec.rb +++ b/spec/uploaders/lfs_object_uploader_spec.rb @@ -1,21 +1,9 @@ require 'spec_helper' describe LfsObjectUploader do - let(:uploader) { described_class.new(build_stubbed(:empty_project)) } - - describe '#cache!' do - it 'caches the file in the cache directory' do - # One to get the work dir, the other to remove it - expect(uploader).to receive(:workfile_path).exactly(2).times.and_call_original - expect(FileUtils).to receive(:mv).with(anything, /^#{uploader.work_dir}/).and_call_original - expect(FileUtils).to receive(:mv).with(/^#{uploader.work_dir}/, /^#{uploader.cache_dir}/).and_call_original - - fixture = Rails.root.join('spec', 'fixtures', 'rails_sample.jpg') - uploader.cache!(fixture_file_upload(fixture)) - - expect(uploader.file.path).to start_with(uploader.cache_dir) - end - end + let(:lfs_object) { create(:lfs_object, :with_file) } + let(:uploader) { described_class.new(lfs_object) } + let(:path) { Gitlab.config.lfs.storage_path } describe '#move_to_cache' do it 'is true' do @@ -28,4 +16,25 @@ describe LfsObjectUploader do expect(uploader.move_to_store).to eq(true) end end + + describe '#store_dir' do + subject { uploader.store_dir } + + it { is_expected.to start_with(path) } + it { is_expected.to end_with("#{lfs_object.oid[0, 2]}/#{lfs_object.oid[2, 2]}") } + end + + describe '#cache_dir' do + subject { uploader.cache_dir } + + it { is_expected.to start_with(path) } + it { is_expected.to end_with('/tmp/cache') } + end + + describe '#work_dir' do + subject { uploader.work_dir } + + it { is_expected.to start_with(path) } + it { is_expected.to end_with('/tmp/work') } + end end -- cgit v1.2.3 From 3a5d375e49b808ca203cb40b5f907aafb40f53aa Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 6 Jun 2017 11:46:28 -0500 Subject: Fix Diff::Position#diff_file for positions on straight diffs --- spec/lib/gitlab/diff/diff_refs_spec.rb | 61 ++++++++++++++++++++++++++++++++++ spec/lib/gitlab/diff/position_spec.rb | 48 ++++++++++++++++++++++++++ spec/lib/gitlab/git/compare_spec.rb | 4 +-- 3 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 spec/lib/gitlab/diff/diff_refs_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/diff/diff_refs_spec.rb b/spec/lib/gitlab/diff/diff_refs_spec.rb new file mode 100644 index 00000000000..a8173558c00 --- /dev/null +++ b/spec/lib/gitlab/diff/diff_refs_spec.rb @@ -0,0 +1,61 @@ +require 'spec_helper' + +describe Gitlab::Diff::DiffRefs, lib: true do + let(:project) { create(:project, :repository) } + + describe '#compare_in' do + context 'with diff refs for the initial commit' do + let(:commit) { project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') } + subject { commit.diff_refs } + + it 'returns an appropriate comparison' do + compare = subject.compare_in(project) + + expect(compare.diff_refs).to eq(subject) + end + end + + context 'with diff refs for a commit' do + let(:commit) { project.commit('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } + subject { commit.diff_refs } + + it 'returns an appropriate comparison' do + compare = subject.compare_in(project) + + expect(compare.diff_refs).to eq(subject) + end + end + + context 'with diff refs for a comparison through the base' do + subject do + described_class.new( + start_sha: '0b4bc9a49b562e85de7cc9e834518ea6828729b9', # feature + base_sha: 'ae73cb07c9eeaf35924a10f713b364d32b2dd34f', + head_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a' # master + ) + end + + it 'returns an appropriate comparison' do + compare = subject.compare_in(project) + + expect(compare.diff_refs).to eq(subject) + end + end + + context 'with diff refs for a straight comparison' do + subject do + described_class.new( + start_sha: '0b4bc9a49b562e85de7cc9e834518ea6828729b9', # feature + base_sha: '0b4bc9a49b562e85de7cc9e834518ea6828729b9', + head_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a' # master + ) + end + + it 'returns an appropriate comparison' do + compare = subject.compare_in(project) + + expect(compare.diff_refs).to eq(subject) + end + end + end +end diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb index 7095104d75c..b3d46e69ccb 100644 --- a/spec/lib/gitlab/diff/position_spec.rb +++ b/spec/lib/gitlab/diff/position_spec.rb @@ -381,6 +381,54 @@ describe Gitlab::Diff::Position, lib: true do end end + describe "position for a file in a straight comparison" do + let(:diff_refs) do + Gitlab::Diff::DiffRefs.new( + start_sha: '0b4bc9a49b562e85de7cc9e834518ea6828729b9', # feature + base_sha: '0b4bc9a49b562e85de7cc9e834518ea6828729b9', + head_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a' # master + ) + end + + subject do + described_class.new( + old_path: "files/ruby/feature.rb", + new_path: "files/ruby/feature.rb", + old_line: 3, + new_line: nil, + diff_refs: diff_refs + ) + end + + describe "#diff_file" do + it "returns the correct diff file" do + diff_file = subject.diff_file(project.repository) + + expect(diff_file.deleted_file?).to be true + expect(diff_file.old_path).to eq(subject.old_path) + expect(diff_file.diff_refs).to eq(subject.diff_refs) + end + end + + describe "#diff_line" do + it "returns the correct diff line" do + diff_line = subject.diff_line(project.repository) + + expect(diff_line.removed?).to be true + expect(diff_line.old_line).to eq(subject.old_line) + expect(diff_line.text).to eq("- puts 'bar'") + end + end + + describe "#line_code" do + it "returns the correct line code" do + line_code = Gitlab::Diff::LineCode.generate(subject.file_path, 0, subject.old_line) + + expect(subject.line_code(project.repository)).to eq(line_code) + end + end + end + describe "#to_json" do let(:hash) do { diff --git a/spec/lib/gitlab/git/compare_spec.rb b/spec/lib/gitlab/git/compare_spec.rb index 7c45071ec45..4c9f4a28f32 100644 --- a/spec/lib/gitlab/git/compare_spec.rb +++ b/spec/lib/gitlab/git/compare_spec.rb @@ -2,8 +2,8 @@ require "spec_helper" describe Gitlab::Git::Compare, seed_helper: true do let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) } - let(:compare) { Gitlab::Git::Compare.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, false) } - let(:compare_straight) { Gitlab::Git::Compare.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, true) } + let(:compare) { Gitlab::Git::Compare.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, straight: false) } + let(:compare_straight) { Gitlab::Git::Compare.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, straight: true) } describe '#commits' do subject do -- cgit v1.2.3 From a544e46bb083c27bfa2966ea67ddf97b5dc7cb08 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Wed, 7 Jun 2017 09:45:16 +1100 Subject: Add a rubocop rule to check if a method 'redirect_to' is used without explicitly set 'status' in 'destroy' actions of controllers --- spec/rubocop/cop/redirect_with_status_spec.rb | 86 +++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 spec/rubocop/cop/redirect_with_status_spec.rb (limited to 'spec') diff --git a/spec/rubocop/cop/redirect_with_status_spec.rb b/spec/rubocop/cop/redirect_with_status_spec.rb new file mode 100644 index 00000000000..5ad63567f84 --- /dev/null +++ b/spec/rubocop/cop/redirect_with_status_spec.rb @@ -0,0 +1,86 @@ +require 'spec_helper' + +require 'rubocop' +require 'rubocop/rspec/support' + +require_relative '../../../rubocop/cop/redirect_with_status' + +describe RuboCop::Cop::RedirectWithStatus do + include CopHelper + + subject(:cop) { described_class.new } + let(:controller_fixture_without_status) do + %q( + class UserController < ApplicationController + def show + user = User.find(params[:id]) + redirect_to user_path if user.name == 'John Wick' + end + + def destroy + user = User.find(params[:id]) + + if user.destroy + redirect_to root_path + else + render :show + end + end + end + ) + end + + let(:controller_fixture_with_status) do + %q( + class UserController < ApplicationController + def show + user = User.find(params[:id]) + redirect_to user_path if user.name == 'John Wick' + end + + def destroy + user = User.find(params[:id]) + + if user.destroy + redirect_to root_path, status: 302 + else + render :show + end + end + end + ) + end + + context 'in controller' do + before do + allow(cop).to receive(:in_controller?).and_return(true) + end + + it 'registers an offense when a "destroy" action uses "redirect_to" without "status"' do + inspect_source(cop, controller_fixture_without_status) + + aggregate_failures do + expect(cop.offenses.size).to eq(1) + expect(cop.offenses.map(&:line)).to eq([12]) # 'redirect_to' is located on 12th line in controller_fixture. + expect(cop.highlights).to eq(['redirect_to']) + end + end + + it 'does not register an offense when a "destroy" action uses "redirect_to" with "status"' do + inspect_source(cop, controller_fixture_with_status) + + aggregate_failures do + expect(cop.offenses.size).to eq(0) + end + end + end + + context 'outside of controller' do + it 'registers no offense' do + inspect_source(cop, controller_fixture_without_status) + inspect_source(cop, controller_fixture_with_status) + + expect(cop.offenses.size).to eq(0) + end + end +end -- cgit v1.2.3 From d565b30ce60e0ad83f8a63b235eb923524665712 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Tue, 6 Jun 2017 18:18:31 -0500 Subject: Add jasmine spec for searchState --- .../filtered_search_manager_spec.js | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js index 6e59ee96c6b..406b25db083 100644 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js @@ -97,6 +97,49 @@ describe('Filtered Search Manager', () => { }); }); + describe('searchState', () => { + beforeEach(() => { + spyOn(gl.FilteredSearchManager.prototype, 'search').and.callFake(() => {}); + }); + + it('should blur button', () => { + const e = { + currentTarget: { + blur: () => {}, + classList: [], + }, + }; + spyOn(e.currentTarget, 'blur').and.callThrough(); + manager.searchState(e); + + expect(e.currentTarget.blur).toHaveBeenCalled(); + }); + + it('should not call search if there is no state', () => { + const e = { + currentTarget: { + blur: () => {}, + classList: [], + }, + }; + + manager.searchState(e); + expect(gl.FilteredSearchManager.prototype.search).not.toHaveBeenCalled(); + }); + + it('should call search when there is state', () => { + const e = { + currentTarget: { + blur: () => {}, + classList: ['class-name', 'state-opened'], + }, + }; + + manager.searchState(e); + expect(gl.FilteredSearchManager.prototype.search).toHaveBeenCalledWith('opened'); + }); + }); + describe('search', () => { const defaultParams = '?scope=all&utf8=%E2%9C%93&state=opened'; -- cgit v1.2.3 From c698f10942ebdf44d0c2a6559277bc6a89d26c5b Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Fri, 2 Jun 2017 19:57:40 -0300 Subject: Avoid repeated queries for pipeline builds on merge requests --- .../merge_requests/mini_pipeline_graph_spec.rb | 28 +++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/merge_requests/mini_pipeline_graph_spec.rb b/spec/features/merge_requests/mini_pipeline_graph_spec.rb index 3ceb91d951d..3a11ea3c8b2 100644 --- a/spec/features/merge_requests/mini_pipeline_graph_spec.rb +++ b/spec/features/merge_requests/mini_pipeline_graph_spec.rb @@ -12,13 +12,39 @@ feature 'Mini Pipeline Graph', :js, :feature do build.run login_as(user) - visit namespace_project_merge_request_path(project.namespace, project, merge_request) + visit_merge_request + end + + def visit_merge_request(format = :html) + visit namespace_project_merge_request_path(project.namespace, project, merge_request, format: format) end it 'should display a mini pipeline graph' do expect(page).to have_selector('.mr-widget-pipeline-graph') end + context 'as json' do + let(:artifacts_file1) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } + let(:artifacts_file2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/png') } + + before do + create(:ci_build, pipeline: pipeline, artifacts_file: artifacts_file1) + create(:ci_build, pipeline: pipeline, when: 'manual') + end + + it 'avoids repeated database queries' do + before = ActiveRecord::QueryRecorder.new { visit_merge_request(:json) } + + create(:ci_build, pipeline: pipeline, artifacts_file: artifacts_file2) + create(:ci_build, pipeline: pipeline, when: 'manual') + + after = ActiveRecord::QueryRecorder.new { visit_merge_request(:json) } + + expect(before.count).to eq(after.count) + expect(before.cached_count).to eq(after.cached_count) + end + end + describe 'build list toggle' do let(:toggle) do find('.mini-pipeline-graph-dropdown-toggle') -- cgit v1.2.3 From 1c59ba67a539e9ef7298b1c219123200eeb54b01 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Wed, 7 Jun 2017 04:24:30 +0200 Subject: Do not cleanup temp directory as this apparently causes silent rspec failures on linux in CI --- spec/controllers/metrics_controller_spec.rb | 10 ++-------- spec/lib/gitlab/metrics_spec.rb | 9 ++------- 2 files changed, 4 insertions(+), 15 deletions(-) (limited to 'spec') diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb index b26ebc1377b..044c9f179ed 100644 --- a/spec/controllers/metrics_controller_spec.rb +++ b/spec/controllers/metrics_controller_spec.rb @@ -5,17 +5,11 @@ describe MetricsController do let(:token) { current_application_settings.health_check_access_token } let(:json_response) { JSON.parse(response.body) } - - around do |example| - Dir.mktmpdir do |tmp_dir| - @metrics_multiproc_dir = tmp_dir - example.run - end - end + let(:metrics_multiproc_dir) { Dir.mktmpdir } before do stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') - stub_env('prometheus_multiproc_dir', @metrics_multiproc_dir) + stub_env('prometheus_multiproc_dir', metrics_multiproc_dir) allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(true) end diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb index 87c9f4ebda4..5a87b906609 100644 --- a/spec/lib/gitlab/metrics_spec.rb +++ b/spec/lib/gitlab/metrics_spec.rb @@ -281,15 +281,10 @@ describe Gitlab::Metrics do end context 'prometheus metrics enabled' do - around do |example| - Dir.mktmpdir do |tmp_dir| - @metrics_multiproc_dir = tmp_dir - example.run - end - end + let(:metrics_multiproc_dir) { Dir.mktmpdir } before do - stub_const('Prometheus::Client::Multiprocdir', @metrics_multiproc_dir) + stub_const('Prometheus::Client::Multiprocdir', metrics_multiproc_dir) allow(described_class).to receive(:prometheus_metrics_enabled?).and_return(true) end -- cgit v1.2.3 From 2e311d9d1aac58bbd9c7d6c97c7cbcccf2715347 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Mon, 29 May 2017 09:54:35 +0200 Subject: Support uploads for newly created personal snippets --- spec/controllers/uploads_controller_spec.rb | 34 +++++++++++++++ .../projects/snippets/create_snippet_spec.rb | 6 +-- spec/features/snippets/create_snippet_spec.rb | 22 ++++++++++ spec/features/snippets/edit_snippet_spec.rb | 6 +-- spec/uploaders/file_mover_spec.rb | 50 +++++++++++++++++++--- spec/uploaders/records_uploads_spec.rb | 9 +++- 6 files changed, 114 insertions(+), 13 deletions(-) (limited to 'spec') diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 8000c9dec61..01a0659479b 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -92,6 +92,40 @@ describe UploadsController do end end end + + context 'temporal with valid image' do + subject do + post :create, model: 'personal_snippet', file: jpg, format: :json + end + + it 'returns a content with original filename, new link, and correct type.' do + subject + + expect(response.body).to match '\"alt\":\"rails_sample\"' + expect(response.body).to match "\"url\":\"/uploads/temp" + end + + it 'does not create an Upload record' do + expect { subject }.not_to change { Upload.count } + end + end + + context 'temporal with valid non-image file' do + subject do + post :create, model: 'personal_snippet', file: txt, format: :json + end + + it 'returns a content with original filename, new link, and correct type.' do + subject + + expect(response.body).to match '\"alt\":\"doc_sample.txt\"' + expect(response.body).to match "\"url\":\"/uploads/temp" + end + + it 'does not create an Upload record' do + expect { subject }.not_to change { Upload.count } + end + end end end diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index be9cc9f7029..5ac1ca45c74 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -27,7 +27,7 @@ feature 'Create Snippet', :js, feature: true do it 'creates a new snippet' do fill_form click_button('Create snippet') - wait_for_ajax + wait_for_requests expect(page).to have_content('My Snippet Title') expect(page).to have_content('Hello World!') @@ -44,7 +44,7 @@ feature 'Create Snippet', :js, feature: true do expect(page.find_field("project_snippet_description").value).to have_content('banana_sample') click_button('Create snippet') - wait_for_ajax + wait_for_requests link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] expect(link).to match(%r{/#{Regexp.escape(project.full_path) }/uploads/\h{32}/banana_sample\.gif\z}) @@ -60,7 +60,7 @@ feature 'Create Snippet', :js, feature: true do dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') click_button('Create snippet') - wait_for_ajax + wait_for_requests expect(page).to have_content('My Snippet Title') expect(page).to have_content('Hello World!') diff --git a/spec/features/snippets/create_snippet_spec.rb b/spec/features/snippets/create_snippet_spec.rb index f006057669b..ddd31ede064 100644 --- a/spec/features/snippets/create_snippet_spec.rb +++ b/spec/features/snippets/create_snippet_spec.rb @@ -30,6 +30,22 @@ feature 'Create Snippet', :js, feature: true do expect(page).to have_content('Hello World!') end + scenario 'previews a snippet with file' do + fill_in 'personal_snippet_description', with: 'My Snippet' + dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') + find('.js-md-preview-button').click + + page.within('#new_personal_snippet .md-preview') do + expect(page).to have_content('My Snippet') + + link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] + expect(link).to match(%r{/uploads/temp/\h{32}/banana_sample\.gif\z}) + + visit(link) + expect(page.status_code).to eq(200) + end + end + scenario 'uploads a file when dragging into textarea' do fill_form @@ -42,6 +58,9 @@ feature 'Create Snippet', :js, feature: true do link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] expect(link).to match(%r{/uploads/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z}) + + visit(link) + expect(page.status_code).to eq(200) end scenario 'validation fails for the first time' do @@ -64,6 +83,9 @@ feature 'Create Snippet', :js, feature: true do expect(page).to have_content('Hello World!') link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] expect(link).to match(%r{/uploads/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z}) + + visit(link) + expect(page.status_code).to eq(200) end scenario 'Authenticated user creates a snippet with + in filename' do diff --git a/spec/features/snippets/edit_snippet_spec.rb b/spec/features/snippets/edit_snippet_spec.rb index ee04792ef73..89ae593db88 100644 --- a/spec/features/snippets/edit_snippet_spec.rb +++ b/spec/features/snippets/edit_snippet_spec.rb @@ -13,14 +13,14 @@ feature 'Edit Snippet', :js, feature: true do login_as(user) visit edit_snippet_path(snippet) - wait_for_ajax + wait_for_requests end it 'updates the snippet' do fill_in 'personal_snippet_title', with: 'New Snippet Title' click_button('Save changes') - wait_for_ajax + wait_for_requests expect(page).to have_content('New Snippet Title') end @@ -30,7 +30,7 @@ feature 'Edit Snippet', :js, feature: true do expect(page.find_field("personal_snippet_description").value).to have_content('banana_sample') click_button('Save changes') - wait_for_ajax + wait_for_requests link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] expect(link).to match(%r{/uploads/personal_snippet/#{snippet.id}/\h{32}/banana_sample\.gif\z}) diff --git a/spec/uploaders/file_mover_spec.rb b/spec/uploaders/file_mover_spec.rb index 99d50e78240..896cb410ed5 100644 --- a/spec/uploaders/file_mover_spec.rb +++ b/spec/uploaders/file_mover_spec.rb @@ -3,7 +3,10 @@ require 'spec_helper' describe FileMover do let(:filename) { 'banana_sample.gif' } let(:file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) } - let(:temp_description) { 'test ![banana_sample](/uploads/temp/secret55/banana_sample.gif)' } + let(:temp_description) do + 'test ![banana_sample](/uploads/temp/secret55/banana_sample.gif) same ![banana_sample]'\ + '(/uploads/temp/secret55/banana_sample.gif)' + end let(:temp_file_path) { File.join('secret55', filename).to_s } let(:file_path) { File.join('uploads', 'personal_snippet', snippet.id.to_s, 'secret55', filename).to_s } @@ -12,14 +15,49 @@ describe FileMover do subject { described_class.new(file_path, snippet).execute } describe '#execute' do - it 'updates the description correctly' do - expect(FileUtils).to receive(:mkdir_p).with(a_string_including(file_path)) + before do + expect(FileUtils).to receive(:mkdir_p).with(a_string_including(File.dirname(file_path))) expect(FileUtils).to receive(:move).with(a_string_including(temp_file_path), a_string_including(file_path)) + allow_any_instance_of(CarrierWave::SanitizedFile).to receive(:exists?).and_return(true) + allow_any_instance_of(CarrierWave::SanitizedFile).to receive(:size).and_return(10) + end + + context 'when move and field update successful' do + it 'updates the description correctly' do + subject + + expect(snippet.reload.description) + .to eq( + "test ![banana_sample](/uploads/personal_snippet/#{snippet.id}/secret55/banana_sample.gif)"\ + " same ![banana_sample](/uploads/personal_snippet/#{snippet.id}/secret55/banana_sample.gif)" + ) + end + + it 'creates a new update record' do + expect { subject }.to change { Upload.count }.by(1) + end + end + + context 'when update_markdown fails' do + before do + expect(FileUtils).to receive(:move).with(a_string_including(file_path), a_string_including(temp_file_path)) + end + + subject { described_class.new(file_path, snippet, :non_existing_field).execute } + + it 'does not update the description' do + subject - subject + expect(snippet.reload.description) + .to eq( + "test ![banana_sample](/uploads/temp/secret55/banana_sample.gif)"\ + " same ![banana_sample](/uploads/temp/secret55/banana_sample.gif)" + ) + end - expect(snippet.reload.description) - .to eq("test ![banana_sample](/uploads/personal_snippet/#{snippet.id}/secret55/banana_sample.gif)") + it 'does not create a new update record' do + expect { subject }.not_to change { Upload.count } + end end end end diff --git a/spec/uploaders/records_uploads_spec.rb b/spec/uploaders/records_uploads_spec.rb index 5c26e334a6e..bb32ee62ccb 100644 --- a/spec/uploaders/records_uploads_spec.rb +++ b/spec/uploaders/records_uploads_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe RecordsUploads do - let(:uploader) do + let!(:uploader) do class RecordsUploadsExampleUploader < GitlabUploader include RecordsUploads @@ -57,6 +57,13 @@ describe RecordsUploads do uploader.store!(upload_fixture('rails_sample.jpg')) end + it 'does not create an Upload record if model is missing' do + expect_any_instance_of(RecordsUploadsExampleUploader).to receive(:model).and_return(nil) + expect(Upload).not_to receive(:record).with(uploader) + + uploader.store!(upload_fixture('rails_sample.jpg')) + end + it 'it destroys Upload records at the same path before recording' do existing = Upload.create!( path: File.join('uploads', 'rails_sample.jpg'), -- cgit v1.2.3 From 223b87d7b1eccfc844631118e454c69a6312004d Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Tue, 6 Jun 2017 11:49:36 +0300 Subject: Backport Fix '/unassign' slash command --- spec/services/issuable/bulk_update_service_spec.rb | 2 +- spec/services/slash_commands/interpret_service_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb index 6437d00e451..eb9b1670c71 100644 --- a/spec/services/issuable/bulk_update_service_spec.rb +++ b/spec/services/issuable/bulk_update_service_spec.rb @@ -72,7 +72,7 @@ describe Issuable::BulkUpdateService, services: true do end context "when the new assignee ID is #{IssuableFinder::NONE}" do - it "unassigns the issues" do + it 'unassigns the issues' do expect { bulk_update(merge_request, assignee_id: IssuableFinder::NONE) } .to change { merge_request.reload.assignee }.to(nil) end diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/slash_commands/interpret_service_spec.rb index e5e400ee281..4db491fd5f3 100644 --- a/spec/services/slash_commands/interpret_service_spec.rb +++ b/spec/services/slash_commands/interpret_service_spec.rb @@ -384,7 +384,7 @@ describe SlashCommands::InterpretService, services: true do it 'fetches assignee and populates assignee_id if content contains /assign' do _, updates = service.execute(content, issue) - expect(updates[:assignee_ids]).to match_array([developer.id, developer2.id]) + expect(updates[:assignee_ids]).to match_array([developer.id]) end end -- cgit v1.2.3 From 1633d3d7d8b8589a3d04358d6473cfd168633a10 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 7 Jun 2017 08:39:02 +0100 Subject: change tests based on backend feedback --- spec/services/boards/lists/list_service_spec.rb | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb index 99016a8be0c..68140759600 100644 --- a/spec/services/boards/lists/list_service_spec.rb +++ b/spec/services/boards/lists/list_service_spec.rb @@ -9,26 +9,20 @@ describe Boards::Lists::ListService, services: true do describe '#execute' do context 'when the board has a backlog list' do - before do - create(:backlog_list, board: board) - end + let!(:backlog_list) { create(:backlog_list, board: board) } it 'does not create a backlog list' do - service.execute(board) - - expect(board.lists.merge(List.backlog)).to eq [board.backlog_list] + expect { service.execute(board) }.not_to change(board.lists, :count) end it "returns board's lists" do - expect(service.execute(board)).to eq [board.backlog_list, list, board.closed_list] + expect(service.execute(board)).to eq [backlog_list, list, board.closed_list] end end context 'when the board does not have a backlog list' do it 'creates a backlog list' do - service.execute(board) - - expect(board.backlog_list).not_to be nil + expect { service.execute(board) }.to change(board.lists, :count).by(1) end it "returns board's lists" do -- cgit v1.2.3 From 4b1d956e1308f6c0a9dc03a2693f52eb1d782fd7 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 7 Jun 2017 08:11:44 +0000 Subject: Resolve "Simplified Repository Settings page" --- spec/features/protected_branches_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb index 884d1bbb10c..667895bffa5 100644 --- a/spec/features/protected_branches_spec.rb +++ b/spec/features/protected_branches_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projected Branches', feature: true, js: true do +feature 'Protected Branches', feature: true, js: true do let(:user) { create(:user, :admin) } let(:project) { create(:project, :repository) } -- cgit v1.2.3 From 4edde47e7332bf3c29f030dfdac6a017f4ea8b6c Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 7 Jun 2017 10:05:40 +0200 Subject: Fix retry build service specs related to the stage --- spec/services/ci/retry_build_service_spec.rb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 7254e6b357a..ef9927c5969 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -25,12 +25,24 @@ describe Ci::RetryBuildService, :services do user_id auto_canceled_by_id retried].freeze shared_examples 'build duplication' do + let(:stage) do + # TODO, we still do not have factory for new stages, we will need to + # switch existing factory to persist stages, instead of using LegacyStage + # + Ci::Stage.create!(project: project, pipeline: pipeline, name: 'test') + end + let(:build) do create(:ci_build, :failed, :artifacts_expired, :erased, :queued, :coverage, :tags, :allowed_to_fail, :on_tag, - :teardown_environment, :triggered, :trace, - description: 'some build', pipeline: pipeline, - auto_canceled_by: create(:ci_empty_pipeline)) + :triggered, :trace, :teardown_environment, + description: 'my-job', stage: 'test', pipeline: pipeline, + auto_canceled_by: create(:ci_empty_pipeline)) do |build| + ## + # TODO, workaround for FactoryGirl limitation when having both + # stage (text) and stage_id (integer) columns in the table. + build.stage_id = stage.id + end end describe 'clone accessors' do -- cgit v1.2.3 From 6e92d902e6df21dcfba2b2b592137825822d9d88 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 7 Jun 2017 10:38:12 +0200 Subject: add repository spec --- spec/lib/gitlab/backup/repository_spec.rb | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 spec/lib/gitlab/backup/repository_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb new file mode 100644 index 00000000000..3d4bc39e17c --- /dev/null +++ b/spec/lib/gitlab/backup/repository_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe Backup::Repository, lib: true do + include StubENV + + let(:progress) { StringIO.new } + let!(:project) { create(:empty_project) } + + before do + allow(progress).to receive(:puts) + allow(progress).to receive(:print) + + allow_any_instance_of(String).to receive(:color) do |string, _color| + string + end + + @old_progress = $progress # rubocop:disable Style/GlobalVars + $progress = progress # rubocop:disable Style/GlobalVars + end + + after do + $progress = @old_progress # rubocop:disable Style/GlobalVars + end + + describe 'repo failure' do + before do + allow_any_instance_of(Project).to receive(:empty_repo?).and_raise(Rugged::OdbError) + allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0]) + end + + it 'does not raise error' do + expect { described_class.new.dump }.not_to raise_error + end + end +end -- cgit v1.2.3 From c61d598b3ae02cabc2e9406a1f8d6363a6273e9c Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Wed, 31 May 2017 17:23:48 +0200 Subject: Fixing more broken unscoped tests --- spec/features/admin/admin_groups_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb index d5f595894d6..cf9d7bca255 100644 --- a/spec/features/admin/admin_groups_spec.rb +++ b/spec/features/admin/admin_groups_spec.rb @@ -24,7 +24,9 @@ feature 'Admin Groups', feature: true do it 'creates new group' do visit admin_groups_path - click_link "New group" + page.within '#content-body' do + click_link "New group" + end path_component = 'gitlab' group_name = 'GitLab group name' group_description = 'Description of group for GitLab' -- cgit v1.2.3 From 280529c7f40db6af7bb0bfd3ef30d330bbafc225 Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Wed, 7 Jun 2017 11:11:26 +0200 Subject: Fix incorrect ETag cache key when relative instance URL is used --- spec/lib/gitlab/etag_caching/middleware_spec.rb | 19 +++++++++++ spec/lib/gitlab/etag_caching/router_spec.rb | 44 ++++++++++++------------- 2 files changed, 41 insertions(+), 22 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb index 24df04e985a..3c6ef7c7ccb 100644 --- a/spec/lib/gitlab/etag_caching/middleware_spec.rb +++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb @@ -164,6 +164,25 @@ describe Gitlab::EtagCaching::Middleware do end end + context 'when GitLab instance is using a relative URL' do + before do + mock_app_response + end + + it 'uses full path as cache key' do + env = { + 'PATH_INFO' => enabled_path, + 'SCRIPT_NAME' => '/relative-gitlab' + } + + expect_any_instance_of(Gitlab::EtagCaching::Store) + .to receive(:get).with("/relative-gitlab#{enabled_path}") + .and_return(nil) + + middleware.call(env) + end + end + def mock_app_response allow(app).to receive(:call).and_return([app_status_code, {}, ['body']]) end diff --git a/spec/lib/gitlab/etag_caching/router_spec.rb b/spec/lib/gitlab/etag_caching/router_spec.rb index 269798c7c9e..2bb40827fcf 100644 --- a/spec/lib/gitlab/etag_caching/router_spec.rb +++ b/spec/lib/gitlab/etag_caching/router_spec.rb @@ -2,115 +2,115 @@ require 'spec_helper' describe Gitlab::EtagCaching::Router do it 'matches issue notes endpoint' do - env = build_env( + request = build_request( '/my-group/and-subgroup/here-comes-the-project/noteable/issue/1/notes' ) - result = described_class.match(env) + result = described_class.match(request) expect(result).to be_present expect(result.name).to eq 'issue_notes' end it 'matches issue title endpoint' do - env = build_env( + request = build_request( '/my-group/my-project/issues/123/realtime_changes' ) - result = described_class.match(env) + result = described_class.match(request) expect(result).to be_present expect(result.name).to eq 'issue_title' end it 'matches project pipelines endpoint' do - env = build_env( + request = build_request( '/my-group/my-project/pipelines.json' ) - result = described_class.match(env) + result = described_class.match(request) expect(result).to be_present expect(result.name).to eq 'project_pipelines' end it 'matches commit pipelines endpoint' do - env = build_env( + request = build_request( '/my-group/my-project/commit/aa8260d253a53f73f6c26c734c72fdd600f6e6d4/pipelines.json' ) - result = described_class.match(env) + result = described_class.match(request) expect(result).to be_present expect(result.name).to eq 'commit_pipelines' end it 'matches new merge request pipelines endpoint' do - env = build_env( + request = build_request( '/my-group/my-project/merge_requests/new.json' ) - result = described_class.match(env) + result = described_class.match(request) expect(result).to be_present expect(result.name).to eq 'new_merge_request_pipelines' end it 'matches merge request pipelines endpoint' do - env = build_env( + request = build_request( '/my-group/my-project/merge_requests/234/pipelines.json' ) - result = described_class.match(env) + result = described_class.match(request) expect(result).to be_present expect(result.name).to eq 'merge_request_pipelines' end it 'matches build endpoint' do - env = build_env( + request = build_request( '/my-group/my-project/builds/234.json' ) - result = described_class.match(env) + result = described_class.match(request) expect(result).to be_present expect(result.name).to eq 'project_build' end it 'does not match blob with confusing name' do - env = build_env( + request = build_request( '/my-group/my-project/blob/master/pipelines.json' ) - result = described_class.match(env) + result = described_class.match(request) expect(result).to be_blank end it 'matches the environments path' do - env = build_env( + request = build_request( '/my-group/my-project/environments.json' ) - result = described_class.match(env) + result = described_class.match(request) expect(result).to be_present expect(result.name).to eq 'environments' end it 'matches pipeline#show endpoint' do - env = build_env( + request = build_request( '/my-group/my-project/pipelines/2.json' ) - result = described_class.match(env) + result = described_class.match(request) expect(result).to be_present expect(result.name).to eq 'project_pipeline' end - def build_env(path) - { 'PATH_INFO' => path } + def build_request(path) + double(path_info: path) end end -- cgit v1.2.3 From f5dfd98856c0fcc8762a38812c71414b3faec951 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Wed, 7 Jun 2017 03:45:48 -0500 Subject: Address feedback --- spec/javascripts/groups/group_item_spec.js | 73 ++++++++++++++++++++---------- spec/javascripts/groups/groups_spec.js | 2 +- spec/javascripts/groups/mock_data.js | 8 ++-- 3 files changed, 54 insertions(+), 29 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/groups/group_item_spec.js b/spec/javascripts/groups/group_item_spec.js index 47af735f4b4..64b0f31e435 100644 --- a/spec/javascripts/groups/group_item_spec.js +++ b/spec/javascripts/groups/group_item_spec.js @@ -3,39 +3,64 @@ import groupItemComponent from '~/groups/components/group_item.vue'; import GroupsStore from '~/groups/stores/groups_store'; import { group1 } from './mock_data'; -fdescribe('Groups Component', () => { +describe('Groups Component', () => { let GroupItemComponent; let component; let store; let group; - beforeEach((done) => { - GroupItemComponent = Vue.extend(groupItemComponent); - store = new GroupsStore(); - group = store.decorateGroup(group1); + describe('group with default data', () => { + beforeEach((done) => { + GroupItemComponent = Vue.extend(groupItemComponent); + store = new GroupsStore(); + group = store.decorateGroup(group1); - component = new GroupItemComponent({ - propsData: { - group, - }, - }).$mount(); + component = new GroupItemComponent({ + propsData: { + group, + }, + }).$mount(); - Vue.nextTick(() => { - done(); + Vue.nextTick(() => { + done(); + }); }); - }); - it('should render the group item', () => { - expect(component.$el.classList.contains('group-row')).toBe(true); - expect(component.$el.querySelector('.number-projects').textContent).toContain(group.numberProjects); - expect(component.$el.querySelector('.number-users').textContent).toContain(group.numberUsers); - expect(component.$el.querySelector('.group-visibility')).toBeDefined(); - expect(component.$el.querySelector('.avatar-container')).toBeDefined(); - expect(component.$el.querySelector('.title').textContent).toContain(group.name); - expect(component.$el.querySelector('.description').textContent).toContain(group.description); - expect(component.$el.querySelector('.edit-group')).toBeDefined(); - expect(component.$el.querySelector('.leave-group')).toBeDefined(); + it('should render the group item correctly', () => { + expect(component.$el.classList.contains('group-row')).toBe(true); + expect(component.$el.classList.contains('.no-description')).toBe(false); + expect(component.$el.querySelector('.number-projects').textContent).toContain(group.numberProjects); + expect(component.$el.querySelector('.number-users').textContent).toContain(group.numberUsers); + expect(component.$el.querySelector('.group-visibility')).toBeDefined(); + expect(component.$el.querySelector('.avatar-container')).toBeDefined(); + expect(component.$el.querySelector('.title').textContent).toContain(group.name); + expect(component.$el.querySelector('.description').textContent).toContain(group.description); + expect(component.$el.querySelector('.edit-group')).toBeDefined(); + expect(component.$el.querySelector('.leave-group')).toBeDefined(); + }); }); - // TODO: check for no description class when group has no description + describe('group without description', () => { + beforeEach((done) => { + GroupItemComponent = Vue.extend(groupItemComponent); + store = new GroupsStore(); + group1.description = ''; + group = store.decorateGroup(group1); + + component = new GroupItemComponent({ + propsData: { + group, + }, + }).$mount(); + + Vue.nextTick(() => { + done(); + }); + }); + + it('should render group item correctly', () => { + expect(component.$el.querySelector('.description').textContent).toBe(''); + expect(component.$el.classList.contains('.no-description')).toBe(false); + }); + }); }); diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js index dc144914c60..d1f900df3d8 100644 --- a/spec/javascripts/groups/groups_spec.js +++ b/spec/javascripts/groups/groups_spec.js @@ -5,7 +5,7 @@ import groupsComponent from '~/groups/components/groups.vue'; import GroupsStore from '~/groups/stores/groups_store'; import { groupsData } from './mock_data'; -fdescribe('Groups Component', () => { +describe('Groups Component', () => { let GroupsComponent; let store; let component; diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js index 98f2aa52135..9951abcc2dc 100644 --- a/spec/javascripts/groups/mock_data.js +++ b/spec/javascripts/groups/mock_data.js @@ -2,7 +2,7 @@ const group1 = { id: '12', name: 'level1', path: 'level1', - description: '', + description: 'foo', visibility: 'public', avatar_url: null, web_url: 'http://localhost:3000/groups/level1', @@ -24,7 +24,7 @@ const group14 = { id: 1128, name: 'level4', path: 'level4', - description: '', + description: 'foo', visibility: 'public', avatar_url: null, web_url: 'http://localhost:3000/groups/level1/level2/level3/level4', @@ -45,7 +45,7 @@ const group2 = { id: 1119, name: 'devops', path: 'devops', - description: '', + description: 'foo', visibility: 'public', avatar_url: null, web_url: 'http://localhost:3000/groups/devops', @@ -66,7 +66,7 @@ const group21 = { id: 1120, name: 'chef', path: 'chef', - description: '', + description: 'foo', visibility: 'public', avatar_url: null, web_url: 'http://localhost:3000/groups/devops/chef', -- cgit v1.2.3 From b45567c5b3fba3f6d5dbd734ef585ec21bf796d0 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Wed, 7 Jun 2017 07:01:38 -0500 Subject: Fix failing spec --- spec/controllers/groups/group_members_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index b6f10162bc6..ed4ad7b600e 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -129,7 +129,7 @@ describe Groups::GroupMembersController do delete :leave, group_id: group, format: :json expect(response).to have_http_status(200) - expect(response.body).to be_empty + expect(json_response['notice']).to eq "You left the \"#{group.name}\" group." end end -- cgit v1.2.3 From 1b76c7196b3b50074e6f2eba64d988ead90e7264 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 7 Jun 2017 14:57:26 +0200 Subject: add more spec examples --- spec/lib/gitlab/backup/repository_spec.rb | 47 +++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb index 3d4bc39e17c..5399b4ac805 100644 --- a/spec/lib/gitlab/backup/repository_spec.rb +++ b/spec/lib/gitlab/backup/repository_spec.rb @@ -22,14 +22,49 @@ describe Backup::Repository, lib: true do $progress = @old_progress # rubocop:disable Style/GlobalVars end - describe 'repo failure' do - before do - allow_any_instance_of(Project).to receive(:empty_repo?).and_raise(Rugged::OdbError) - allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0]) + describe '.dump' do + describe 'repo failure' do + before do + allow_any_instance_of(Project).to receive(:empty_repo?).and_raise(Rugged::OdbError) + allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0]) + end + + it 'does not raise error' do + expect { described_class.new.dump }.not_to raise_error + end + + it 'shows the appropriate error' do + described_class.new.dump + + expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} repository - Rugged::OdbError") + end + end + + describe 'command failure' do + before do + allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false) + allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1]) + end + + it 'shows the appropriate error' do + described_class.new.dump + + expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} - error") + end end + end + + describe '.restore' do + describe 'command failure' do + before do + allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1]) + end + + it 'shows the appropriate error' do + described_class.new.restore - it 'does not raise error' do - expect { described_class.new.dump }.not_to raise_error + expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} - error") + end end end end -- cgit v1.2.3 From 8f07afe31121f61e71db8b8fc45455066a5453f4 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 7 Jun 2017 15:44:58 +0200 Subject: fix spec and added changelog --- spec/lib/gitlab/backup/repository_spec.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb index 5399b4ac805..2d62e8c7b47 100644 --- a/spec/lib/gitlab/backup/repository_spec.rb +++ b/spec/lib/gitlab/backup/repository_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe Backup::Repository, lib: true do - include StubENV - let(:progress) { StringIO.new } let!(:project) { create(:empty_project) } -- cgit v1.2.3 From e2eb0b6f77e66fee1bb50e86ebbc013e1afb784e Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 7 Jun 2017 15:49:35 +0200 Subject: fix spec and added changelog --- spec/lib/gitlab/backup/repository_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb index 2d62e8c7b47..7d0d537f2f2 100644 --- a/spec/lib/gitlab/backup/repository_spec.rb +++ b/spec/lib/gitlab/backup/repository_spec.rb @@ -20,7 +20,7 @@ describe Backup::Repository, lib: true do $progress = @old_progress # rubocop:disable Style/GlobalVars end - describe '.dump' do + describe '#dump' do describe 'repo failure' do before do allow_any_instance_of(Project).to receive(:empty_repo?).and_raise(Rugged::OdbError) @@ -52,7 +52,7 @@ describe Backup::Repository, lib: true do end end - describe '.restore' do + describe '#restore' do describe 'command failure' do before do allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1]) -- cgit v1.2.3 From 8acb0f55961500658377a1f941584dddb7952570 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 7 Jun 2017 16:50:21 +0200 Subject: refactor code and spec --- spec/lib/gitlab/backup/repository_spec.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb index 7d0d537f2f2..51c1e9d657b 100644 --- a/spec/lib/gitlab/backup/repository_spec.rb +++ b/spec/lib/gitlab/backup/repository_spec.rb @@ -12,18 +12,13 @@ describe Backup::Repository, lib: true do string end - @old_progress = $progress # rubocop:disable Style/GlobalVars - $progress = progress # rubocop:disable Style/GlobalVars - end - - after do - $progress = @old_progress # rubocop:disable Style/GlobalVars + allow_any_instance_of(described_class).to receive(:progress).and_return(progress) end describe '#dump' do describe 'repo failure' do before do - allow_any_instance_of(Project).to receive(:empty_repo?).and_raise(Rugged::OdbError) + allow_any_instance_of(Repository).to receive(:empty_repo?).and_raise(Rugged::OdbError) allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0]) end @@ -34,13 +29,13 @@ describe Backup::Repository, lib: true do it 'shows the appropriate error' do described_class.new.dump - expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} repository - Rugged::OdbError") + expect(progress).to have_received(:puts).with("Ignoring repository error and continuing backing up project: #{project.full_path} - Rugged::OdbError") end end describe 'command failure' do before do - allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false) + allow_any_instance_of(Repository).to receive(:empty_repo?).and_return(false) allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1]) end -- cgit v1.2.3 From a65f07a256b95ce1c38342518f9469cbf3abf609 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Wed, 7 Jun 2017 10:05:17 -0500 Subject: Address feedback --- spec/javascripts/groups/group_item_spec.js | 4 ++++ spec/javascripts/groups/groups_spec.js | 4 ++++ spec/javascripts/lib/utils/common_utils_spec.js | 8 ++++++++ 3 files changed, 16 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/groups/group_item_spec.js b/spec/javascripts/groups/group_item_spec.js index 64b0f31e435..9d70f60cd57 100644 --- a/spec/javascripts/groups/group_item_spec.js +++ b/spec/javascripts/groups/group_item_spec.js @@ -26,6 +26,10 @@ describe('Groups Component', () => { }); }); + afterEach(() => { + component.$destroy(); + }); + it('should render the group item correctly', () => { expect(component.$el.classList.contains('group-row')).toBe(true); expect(component.$el.classList.contains('.no-description')).toBe(false); diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js index d1f900df3d8..2a77f7259da 100644 --- a/spec/javascripts/groups/groups_spec.js +++ b/spec/javascripts/groups/groups_spec.js @@ -34,6 +34,10 @@ describe('Groups Component', () => { }); }); + afterEach(() => { + component.$destroy(); + }); + describe('with data', () => { it('should render a list of groups', () => { expect(component.$el.classList.contains('groups-list-tree-container')).toBe(true); diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js index e3938a77680..52cf217c25f 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js +++ b/spec/javascripts/lib/utils/common_utils_spec.js @@ -150,6 +150,14 @@ import '~/lib/utils/common_utils'; const value = gl.utils.getParameterByName('fakeParameter'); expect(value).toBe(null); }); + + it('should return valid paramentes if URL is provided', () => { + let value = gl.utils.getParameterByName('foo', 'http://cocteau.twins/?foo=bar'); + expect(value).toBe('bar'); + + value = gl.utils.getParameterByName('manan', 'http://cocteau.twins/?foo=bar&manan=canchu'); + expect(value).toBe('canchu'); + }); }); describe('gl.utils.normalizedHeaders', () => { -- cgit v1.2.3 From 469acd190e497cda8516da0ee481f33e038d7e9e Mon Sep 17 00:00:00 2001 From: Robin Bobbitt Date: Tue, 6 Jun 2017 11:39:54 -0400 Subject: Sync email address from specified omniauth provider --- spec/controllers/profiles_controller_spec.rb | 31 ++++++++++++++++++++ spec/helpers/profiles_helper_spec.rb | 36 +++++++++++++++++++++++ spec/lib/gitlab/ldap/user_spec.rb | 14 +++++---- spec/lib/gitlab/o_auth/user_spec.rb | 44 +++++++++++++++++++++++++--- 4 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 spec/controllers/profiles_controller_spec.rb create mode 100644 spec/helpers/profiles_helper_spec.rb (limited to 'spec') diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb new file mode 100644 index 00000000000..9d60dab12d1 --- /dev/null +++ b/spec/controllers/profiles_controller_spec.rb @@ -0,0 +1,31 @@ +require('spec_helper') + +describe ProfilesController do + describe "PUT update" do + it "allows an email update from a user without an external email address" do + user = create(:user) + sign_in(user) + + put :update, + user: { email: "john@gmail.com", name: "John" } + + user.reload + + expect(response.status).to eq(302) + expect(user.unconfirmed_email).to eq('john@gmail.com') + end + + it "ignores an email update from a user with an external email address" do + ldap_user = create(:omniauth_user, external_email: true) + sign_in(ldap_user) + + put :update, + user: { email: "john@gmail.com", name: "John" } + + ldap_user.reload + + expect(response.status).to eq(302) + expect(ldap_user.unconfirmed_email).not_to eq('john@gmail.com') + end + end +end diff --git a/spec/helpers/profiles_helper_spec.rb b/spec/helpers/profiles_helper_spec.rb new file mode 100644 index 00000000000..b33b3f3a228 --- /dev/null +++ b/spec/helpers/profiles_helper_spec.rb @@ -0,0 +1,36 @@ +require 'rails_helper' + +describe ProfilesHelper do + describe '#email_provider_label' do + it "returns nil for users without external email" do + user = create(:user) + allow(helper).to receive(:current_user).and_return(user) + + expect(helper.email_provider_label).to be_nil + end + + it "returns omniauth provider label for users with external email" do + stub_cas_omniauth_provider + cas_user = create(:omniauth_user, provider: 'cas3', external_email: true, email_provider: 'cas3') + allow(helper).to receive(:current_user).and_return(cas_user) + + expect(helper.email_provider_label).to eq('CAS') + end + + it "returns 'LDAP' for users with external email but no email provider" do + ldap_user = create(:omniauth_user, external_email: true) + allow(helper).to receive(:current_user).and_return(ldap_user) + + expect(helper.email_provider_label).to eq('LDAP') + end + end + + def stub_cas_omniauth_provider + provider = OpenStruct.new( + 'name' => 'cas3', + 'label' => 'CAS' + ) + + stub_omniauth_setting(providers: [provider]) + end +end diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb index f4aab429931..a0eda685ca3 100644 --- a/spec/lib/gitlab/ldap/user_spec.rb +++ b/spec/lib/gitlab/ldap/user_spec.rb @@ -37,7 +37,7 @@ describe Gitlab::LDAP::User, lib: true do end it "does not mark existing ldap user as changed" do - create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain', ldap_email: true) + create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain', external_email: true, email_provider: 'ldapmain') expect(ldap_user.changed?).to be_falsey end end @@ -141,8 +141,12 @@ describe Gitlab::LDAP::User, lib: true do expect(ldap_user.gl_user.email).to eq(info[:email]) end - it "has ldap_email set to true" do - expect(ldap_user.gl_user.ldap_email?).to be(true) + it "has external_email set to true" do + expect(ldap_user.gl_user.external_email?).to be(true) + end + + it "has email_provider set to provider" do + expect(ldap_user.gl_user.email_provider).to eql 'ldapmain' end end @@ -155,8 +159,8 @@ describe Gitlab::LDAP::User, lib: true do expect(ldap_user.gl_user.temp_oauth_email?).to be(true) end - it "has ldap_email set to false" do - expect(ldap_user.gl_user.ldap_email?).to be(false) + it "has external_email set to false" do + expect(ldap_user.gl_user.external_email?).to be(false) end end end diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index 828c953197d..8943d1aa488 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -28,11 +28,11 @@ describe Gitlab::OAuth::User, lib: true do end end - describe '#save' do - def stub_omniauth_config(messages) - allow(Gitlab.config.omniauth).to receive_messages(messages) - end + def stub_omniauth_config(messages) + allow(Gitlab.config.omniauth).to receive_messages(messages) + end + describe '#save' do def stub_ldap_config(messages) allow(Gitlab::LDAP::Config).to receive_messages(messages) end @@ -377,4 +377,40 @@ describe Gitlab::OAuth::User, lib: true do end end end + + describe 'updating email' do + let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') } + + before do + stub_omniauth_config(sync_email_from_provider: 'my-provider') + end + + context "when provider sets an email" do + it "updates the user email" do + expect(gl_user.email).to eq(info_hash[:email]) + end + + it "has external_email set to true" do + expect(gl_user.external_email?).to be(true) + end + + it "has email_provider set to provider" do + expect(gl_user.email_provider).to eql 'my-provider' + end + end + + context "when provider doesn't set an email" do + before do + info_hash.delete(:email) + end + + it "does not update the user email" do + expect(gl_user.email).not_to eq(info_hash[:email]) + end + + it "has external_email set to false" do + expect(gl_user.external_email?).to be(false) + end + end + end end -- cgit v1.2.3 From 6c8e72b4108e5c671970a3965b214c8b1dda53ae Mon Sep 17 00:00:00 2001 From: Filip Krakowski Date: Thu, 1 Jun 2017 11:58:34 +0200 Subject: Add 'schedules' keyword to 'only' and 'except' --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'spec') diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 72b9cde10e7..83085f61b37 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -230,6 +230,17 @@ module Ci expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, true).size).to eq(1) end + it "returns builds if only has a schedules keyword specified and a schedule is provided" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, only: ["schedules"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, false, true).size).to eq(1) + end + it "does not return builds if only has a triggers keyword specified and no trigger is provided" do config = YAML.dump({ before_script: ["pwd"], @@ -241,6 +252,17 @@ module Ci expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) end + it "does not return builds if only has a schedules keyword specified and no schedule is provided" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, only: ["schedules"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + end + it "returns builds if only has current repository path" do config = YAML.dump({ before_script: ["pwd"], @@ -386,6 +408,17 @@ module Ci expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, true).size).to eq(0) end + it "does not return builds if except has a schedules keyword specified and a schedule is provided" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, except: ["schedules"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, false, true).size).to eq(0) + end + it "returns builds if except has a triggers keyword specified and no trigger is provided" do config = YAML.dump({ before_script: ["pwd"], @@ -397,6 +430,17 @@ module Ci expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) end + it "returns builds if except has a schedules keyword specified and no schedule is provided" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, except: ["schedules"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + end + it "does not return builds if except has current repository path" do config = YAML.dump({ before_script: ["pwd"], -- cgit v1.2.3 From 8db63b26284d949000316a38676ef6fad970f657 Mon Sep 17 00:00:00 2001 From: Filip Krakowski Date: Thu, 1 Jun 2017 21:55:57 +0200 Subject: Use pipeline.source to determine what triggered a pipeline --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 83085f61b37..aa281301faf 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -227,7 +227,7 @@ module Ci config_processor = GitlabCiYamlProcessor.new(config, path) - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, true).size).to eq(1) + expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, 'trigger').size).to eq(1) end it "returns builds if only has a schedules keyword specified and a schedule is provided" do @@ -238,7 +238,7 @@ module Ci config_processor = GitlabCiYamlProcessor.new(config, path) - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, false, true).size).to eq(1) + expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, 'schedule').size).to eq(1) end it "does not return builds if only has a triggers keyword specified and no trigger is provided" do @@ -405,7 +405,7 @@ module Ci config_processor = GitlabCiYamlProcessor.new(config, path) - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, true).size).to eq(0) + expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, 'trigger').size).to eq(0) end it "does not return builds if except has a schedules keyword specified and a schedule is provided" do @@ -416,7 +416,7 @@ module Ci config_processor = GitlabCiYamlProcessor.new(config, path) - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, false, true).size).to eq(0) + expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, 'schedule').size).to eq(0) end it "returns builds if except has a triggers keyword specified and no trigger is provided" do -- cgit v1.2.3 From ecb54cddd164fbf83288d7903c4692df462bae5e Mon Sep 17 00:00:00 2001 From: Filip Krakowski Date: Fri, 2 Jun 2017 19:02:56 +0200 Subject: Add all sources as special keywords for only and except --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 134 +++++++++++++-------------- 1 file changed, 63 insertions(+), 71 deletions(-) (limited to 'spec') diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index aa281301faf..79ed1366336 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -219,48 +219,44 @@ module Ci expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) end - it "returns builds if only has a triggers keyword specified and a trigger is provided" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", type: type, only: ["triggers"] } - }) - - config_processor = GitlabCiYamlProcessor.new(config, path) - - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, 'trigger').size).to eq(1) - end - - it "returns builds if only has a schedules keyword specified and a schedule is provided" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", type: type, only: ["schedules"] } - }) - - config_processor = GitlabCiYamlProcessor.new(config, path) - - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, 'schedule').size).to eq(1) + it "returns builds if only has special keywords specified and source matches" do + possibilities = [{keyword: 'pushes', source: 'push'}, + {keyword: 'web', source: 'web'}, + {keyword: 'triggers', source: 'trigger'}, + {keyword: 'schedules', source: 'schedule'}, + {keyword: 'api', source: 'api'}, + {keyword: 'external', source: 'external'}] + + possibilities.each do |possibility| + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, only: [possibility[:keyword]] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(1) + end end - it "does not return builds if only has a triggers keyword specified and no trigger is provided" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", type: type, only: ["triggers"] } - }) - - config_processor = GitlabCiYamlProcessor.new(config, path) - - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) - end + it "does not return builds if only has special keywords specified and source doesn't match" do + possibilities = [{keyword: 'pushes', source: 'web'}, + {keyword: 'web', source: 'push'}, + {keyword: 'triggers', source: 'schedule'}, + {keyword: 'schedules', source: 'external'}, + {keyword: 'api', source: 'trigger'}, + {keyword: 'external', source: 'api'}] - it "does not return builds if only has a schedules keyword specified and no schedule is provided" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", type: type, only: ["schedules"] } - }) + possibilities.each do |possibility| + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, only: [possibility[:keyword]] } + }) - config_processor = GitlabCiYamlProcessor.new(config, path) + config_processor = GitlabCiYamlProcessor.new(config, path) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(0) + end end it "returns builds if only has current repository path" do @@ -397,48 +393,44 @@ module Ci expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) end - it "does not return builds if except has a triggers keyword specified and a trigger is provided" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", type: type, except: ["triggers"] } - }) - - config_processor = GitlabCiYamlProcessor.new(config, path) - - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, 'trigger').size).to eq(0) - end + it "does not return builds if except has special keywords specified and source matches" do + possibilities = [{keyword: 'pushes', source: 'push'}, + {keyword: 'web', source: 'web'}, + {keyword: 'triggers', source: 'trigger'}, + {keyword: 'schedules', source: 'schedule'}, + {keyword: 'api', source: 'api'}, + {keyword: 'external', source: 'external'}] - it "does not return builds if except has a schedules keyword specified and a schedule is provided" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", type: type, except: ["schedules"] } - }) + possibilities.each do |possibility| + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, except: [possibility[:keyword]] } + }) - config_processor = GitlabCiYamlProcessor.new(config, path) + config_processor = GitlabCiYamlProcessor.new(config, path) - expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, 'schedule').size).to eq(0) + expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(0) + end end - it "returns builds if except has a triggers keyword specified and no trigger is provided" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", type: type, except: ["triggers"] } - }) + it "returns builds if except has special keywords specified and source doesn't match" do + possibilities = [{keyword: 'pushes', source: 'web'}, + {keyword: 'web', source: 'push'}, + {keyword: 'triggers', source: 'schedule'}, + {keyword: 'schedules', source: 'external'}, + {keyword: 'api', source: 'trigger'}, + {keyword: 'external', source: 'api'}] - config_processor = GitlabCiYamlProcessor.new(config, path) + possibilities.each do |possibility| + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, only: [possibility[:keyword]] } + }) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) - end + config_processor = GitlabCiYamlProcessor.new(config, path) - it "returns builds if except has a schedules keyword specified and no schedule is provided" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", type: type, except: ["schedules"] } - }) - - config_processor = GitlabCiYamlProcessor.new(config, path) - - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(1) + end end it "does not return builds if except has current repository path" do -- cgit v1.2.3 From 1dd054e1788fa7b308a9088f3bb35808a027e76d Mon Sep 17 00:00:00 2001 From: Filip Krakowski Date: Fri, 2 Jun 2017 19:58:20 +0200 Subject: Fix static-analysis offenses --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 79ed1366336..fef2d992aaa 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -394,12 +394,12 @@ module Ci end it "does not return builds if except has special keywords specified and source matches" do - possibilities = [{keyword: 'pushes', source: 'push'}, - {keyword: 'web', source: 'web'}, - {keyword: 'triggers', source: 'trigger'}, - {keyword: 'schedules', source: 'schedule'}, - {keyword: 'api', source: 'api'}, - {keyword: 'external', source: 'external'}] + possibilities = [{ keyword: 'pushes', source: 'push' }, + { keyword: 'web', source: 'web' }, + { keyword: 'triggers', source: 'trigger' }, + { keyword: 'schedules', source: 'schedule' }, + { keyword: 'api', source: 'api' }, + { keyword: 'external', source: 'external' }] possibilities.each do |possibility| config = YAML.dump({ -- cgit v1.2.3 From cd0c472711a0283ba82517d31e678380251e6401 Mon Sep 17 00:00:00 2001 From: Filip Krakowski Date: Fri, 2 Jun 2017 21:11:04 +0200 Subject: Fix static-analysis offenses (again) --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'spec') diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index fef2d992aaa..af102198068 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -220,12 +220,12 @@ module Ci end it "returns builds if only has special keywords specified and source matches" do - possibilities = [{keyword: 'pushes', source: 'push'}, - {keyword: 'web', source: 'web'}, - {keyword: 'triggers', source: 'trigger'}, - {keyword: 'schedules', source: 'schedule'}, - {keyword: 'api', source: 'api'}, - {keyword: 'external', source: 'external'}] + possibilities = [{ keyword: 'pushes', source: 'push' }, + { keyword: 'web', source: 'web' }, + { keyword: 'triggers', source: 'trigger' }, + { keyword: 'schedules', source: 'schedule' }, + { keyword: 'api', source: 'api' }, + { keyword: 'external', source: 'external' }] possibilities.each do |possibility| config = YAML.dump({ @@ -240,12 +240,12 @@ module Ci end it "does not return builds if only has special keywords specified and source doesn't match" do - possibilities = [{keyword: 'pushes', source: 'web'}, - {keyword: 'web', source: 'push'}, - {keyword: 'triggers', source: 'schedule'}, - {keyword: 'schedules', source: 'external'}, - {keyword: 'api', source: 'trigger'}, - {keyword: 'external', source: 'api'}] + possibilities = [{ keyword: 'pushes', source: 'web' }, + { keyword: 'web', source: 'push' }, + { keyword: 'triggers', source: 'schedule' }, + { keyword: 'schedules', source: 'external' }, + { keyword: 'api', source: 'trigger' }, + { keyword: 'external', source: 'api' }] possibilities.each do |possibility| config = YAML.dump({ @@ -414,12 +414,12 @@ module Ci end it "returns builds if except has special keywords specified and source doesn't match" do - possibilities = [{keyword: 'pushes', source: 'web'}, - {keyword: 'web', source: 'push'}, - {keyword: 'triggers', source: 'schedule'}, - {keyword: 'schedules', source: 'external'}, - {keyword: 'api', source: 'trigger'}, - {keyword: 'external', source: 'api'}] + possibilities = [{ keyword: 'pushes', source: 'web' }, + { keyword: 'web', source: 'push' }, + { keyword: 'triggers', source: 'schedule' }, + { keyword: 'schedules', source: 'external' }, + { keyword: 'api', source: 'trigger' }, + { keyword: 'external', source: 'api' }] possibilities.each do |possibility| config = YAML.dump({ -- cgit v1.2.3 From 7d16f698d575c5988820699e8ec164638b701b50 Mon Sep 17 00:00:00 2001 From: Filip Krakowski Date: Fri, 2 Jun 2017 21:52:23 +0200 Subject: Fix typo in test --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index af102198068..2a3196616fa 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -424,7 +424,7 @@ module Ci possibilities.each do |possibility| config = YAML.dump({ before_script: ["pwd"], - rspec: { script: "rspec", type: type, only: [possibility[:keyword]] } + rspec: { script: "rspec", type: type, except: [possibility[:keyword]] } }) config_processor = GitlabCiYamlProcessor.new(config, path) -- cgit v1.2.3 From ecd9c30930f4391b5cdfa631b8920d660c750058 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 8 Jun 2017 00:34:46 +0900 Subject: Add source policy spec --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'spec') diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 2a3196616fa..2ca0773ad1d 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -123,6 +123,25 @@ module Ci expect(seeds.first.builds.dig(0, :name)).to eq 'spinach' end end + + context 'when source policy is specified' do + let(:config) do + YAML.dump(production: { stage: 'deploy', script: 'cap prod', only: ['triggers'] }, + spinach: { stage: 'test', script: 'spinach', only: ['schedules'] }) + end + + let(:pipeline) do + create(:ci_empty_pipeline, source: :schedule) + end + + it 'returns stage seeds only assigned to schedules' do + seeds = subject.stage_seeds(pipeline) + + expect(seeds.size).to eq 1 + expect(seeds.first.stage[:name]).to eq 'test' + expect(seeds.first.builds.dig(0, :name)).to eq 'spinach' + end + end end describe "#builds_for_ref" do -- cgit v1.2.3 From 5819ca1a249d1daf3b4feb655c217c98a1b70225 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 2 Jun 2017 14:29:30 +0200 Subject: Added Cop to blacklist polymorphic associations One should really use a separate table instead of using polymorphic associations. See https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11168 for more information. --- spec/rubocop/cop/activerecord_serialize_spec.rb | 4 +-- spec/rubocop/cop/polymorphic_associations_spec.rb | 33 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 spec/rubocop/cop/polymorphic_associations_spec.rb (limited to 'spec') diff --git a/spec/rubocop/cop/activerecord_serialize_spec.rb b/spec/rubocop/cop/activerecord_serialize_spec.rb index a303b16d264..5bd7e5fa926 100644 --- a/spec/rubocop/cop/activerecord_serialize_spec.rb +++ b/spec/rubocop/cop/activerecord_serialize_spec.rb @@ -10,7 +10,7 @@ describe RuboCop::Cop::ActiverecordSerialize do context 'inside the app/models directory' do it 'registers an offense when serialize is used' do - allow(cop).to receive(:in_models?).and_return(true) + allow(cop).to receive(:in_model?).and_return(true) inspect_source(cop, 'serialize :foo') @@ -23,7 +23,7 @@ describe RuboCop::Cop::ActiverecordSerialize do context 'outside the app/models directory' do it 'does nothing' do - allow(cop).to receive(:in_models?).and_return(false) + allow(cop).to receive(:in_model?).and_return(false) inspect_source(cop, 'serialize :foo') diff --git a/spec/rubocop/cop/polymorphic_associations_spec.rb b/spec/rubocop/cop/polymorphic_associations_spec.rb new file mode 100644 index 00000000000..49959aa6419 --- /dev/null +++ b/spec/rubocop/cop/polymorphic_associations_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' +require 'rubocop' +require 'rubocop/rspec/support' +require_relative '../../../rubocop/cop/polymorphic_associations' + +describe RuboCop::Cop::PolymorphicAssociations do + include CopHelper + + subject(:cop) { described_class.new } + + context 'inside the app/models directory' do + it 'registers an offense when polymorphic: true is used' do + allow(cop).to receive(:in_model?).and_return(true) + + inspect_source(cop, 'belongs_to :foo, polymorphic: true') + + aggregate_failures do + expect(cop.offenses.size).to eq(1) + expect(cop.offenses.map(&:line)).to eq([1]) + end + end + end + + context 'outside the app/models directory' do + it 'does nothing' do + allow(cop).to receive(:in_model?).and_return(false) + + inspect_source(cop, 'belongs_to :foo, polymorphic: true') + + expect(cop.offenses).to be_empty + end + end +end -- cgit v1.2.3 From 60d2a7c3557964da7425c37bb871c5131f615d5e Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Wed, 7 Jun 2017 10:54:54 -0500 Subject: Use data attributes instead of class --- spec/features/issues/filtered_search/filter_issues_spec.rb | 8 ++++---- spec/features/merge_requests/filter_merge_requests_spec.rb | 12 ++++++------ .../filtered_search/filtered_search_manager_spec.js | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'spec') diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index 36f8369c142..863f8f75cd8 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -777,17 +777,17 @@ describe 'Filter issues', js: true, feature: true do end it 'open state' do - find('.issues-state-filters .state-closed').click + find('.issues-state-filters [data-state="closed"]').click wait_for_requests - find('.issues-state-filters .state-opened').click + find('.issues-state-filters [data-state="opened"]').click wait_for_requests expect(page).to have_selector('.issues-list .issue', count: 4) end it 'closed state' do - find('.issues-state-filters .state-closed').click + find('.issues-state-filters [data-state="closed"]').click wait_for_requests expect(page).to have_selector('.issues-list .issue', count: 1) @@ -795,7 +795,7 @@ describe 'Filter issues', js: true, feature: true do end it 'all state' do - find('.issues-state-filters .state-all').click + find('.issues-state-filters [data-state="all"]').click wait_for_requests expect(page).to have_selector('.issues-list .issue', count: 5) diff --git a/spec/features/merge_requests/filter_merge_requests_spec.rb b/spec/features/merge_requests/filter_merge_requests_spec.rb index 5a13189c5bf..d086be70d69 100644 --- a/spec/features/merge_requests/filter_merge_requests_spec.rb +++ b/spec/features/merge_requests/filter_merge_requests_spec.rb @@ -40,13 +40,13 @@ describe 'Filter merge requests', feature: true do end it 'does not change when closed link is clicked' do - find('.issues-state-filters .state-closed').click + find('.issues-state-filters [data-state="closed"]').click expect_assignee_visual_tokens() end it 'does not change when all link is clicked' do - find('.issues-state-filters .state-all').click + find('.issues-state-filters [data-state="all"]').click expect_assignee_visual_tokens() end @@ -73,13 +73,13 @@ describe 'Filter merge requests', feature: true do end it 'does not change when closed link is clicked' do - find('.issues-state-filters .state-closed').click + find('.issues-state-filters [data-state="closed"]').click expect_milestone_visual_tokens() end it 'does not change when all link is clicked' do - find('.issues-state-filters .state-all').click + find('.issues-state-filters [data-state="all"]').click expect_milestone_visual_tokens() end @@ -161,13 +161,13 @@ describe 'Filter merge requests', feature: true do end it 'does not change when closed link is clicked' do - find('.issues-state-filters .state-closed').click + find('.issues-state-filters [data-state="closed"]').click expect_assignee_label_visual_tokens() end it 'does not change when all link is clicked' do - find('.issues-state-filters .state-all').click + find('.issues-state-filters [data-state="all"]').click expect_assignee_label_visual_tokens() end diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js index 406b25db083..2d19b1da7b3 100644 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js @@ -106,7 +106,6 @@ describe('Filtered Search Manager', () => { const e = { currentTarget: { blur: () => {}, - classList: [], }, }; spyOn(e.currentTarget, 'blur').and.callThrough(); @@ -119,7 +118,6 @@ describe('Filtered Search Manager', () => { const e = { currentTarget: { blur: () => {}, - classList: [], }, }; @@ -131,7 +129,9 @@ describe('Filtered Search Manager', () => { const e = { currentTarget: { blur: () => {}, - classList: ['class-name', 'state-opened'], + dataset: { + state: 'opened', + }, }, }; -- cgit v1.2.3 From 32cac597275706930b221b19fb20b29ccebc7130 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Wed, 7 Jun 2017 18:33:50 +0000 Subject: Added more actions and report as abuse to all notes --- spec/features/issues/note_polling_spec.rb | 17 +++++++--- .../merge_requests/diff_notes_avatars_spec.rb | 4 +++ .../merge_requests/user_posts_notes_spec.rb | 8 +++++ spec/features/reportable_note/commit_spec.rb | 33 ++++++++++++++++++++ spec/features/reportable_note/issue_spec.rb | 17 ++++++++++ .../features/reportable_note/merge_request_spec.rb | 26 ++++++++++++++++ spec/features/reportable_note/snippets_spec.rb | 33 ++++++++++++++++++++ .../snippets/notes_on_personal_snippets_spec.rb | 12 +++++++- spec/helpers/notes_helper_spec.rb | 10 ++++++ spec/lib/gitlab/url_builder_spec.rb | 11 +++++++ .../features/reportable_note_shared_examples.rb | 36 ++++++++++++++++++++++ spec/support/helpers/note_interaction_helpers.rb | 8 +++++ 12 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 spec/features/reportable_note/commit_spec.rb create mode 100644 spec/features/reportable_note/issue_spec.rb create mode 100644 spec/features/reportable_note/merge_request_spec.rb create mode 100644 spec/features/reportable_note/snippets_spec.rb create mode 100644 spec/support/features/reportable_note_shared_examples.rb create mode 100644 spec/support/helpers/note_interaction_helpers.rb (limited to 'spec') diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb index 80f57906506..2c0a6ffd3cb 100644 --- a/spec/features/issues/note_polling_spec.rb +++ b/spec/features/issues/note_polling_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' feature 'Issue notes polling', :feature, :js do + include NoteInteractionHelpers + let(:project) { create(:empty_project, :public) } let(:issue) { create(:issue, project: project) } @@ -48,7 +50,7 @@ feature 'Issue notes polling', :feature, :js do end it 'when editing but have not changed anything, and an update comes in, show the updated content in the textarea' do - find("#note_#{existing_note.id} .js-note-edit").click + click_edit_action(existing_note) expect(page).to have_field("note[note]", with: note_text) @@ -58,19 +60,18 @@ feature 'Issue notes polling', :feature, :js do end it 'when editing but you changed some things, and an update comes in, show a warning' do - find("#note_#{existing_note.id} .js-note-edit").click + click_edit_action(existing_note) expect(page).to have_field("note[note]", with: note_text) find("#note_#{existing_note.id} .js-note-text").set('something random') - update_note(existing_note, updated_text) expect(page).to have_selector(".alert") end it 'when editing but you changed some things, an update comes in, and you press cancel, show the updated content' do - find("#note_#{existing_note.id} .js-note-edit").click + click_edit_action(existing_note) expect(page).to have_field("note[note]", with: note_text) @@ -128,4 +129,12 @@ feature 'Issue notes polling', :feature, :js do note.update(note: new_text) page.execute_script('notes.refresh();') end + + def click_edit_action(note) + note_element = find("#note_#{note.id}") + + open_more_actions_dropdown(note) + + note_element.find('.js-note-edit').click + end end diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb index 854e2d1758f..e23dc2cd940 100644 --- a/spec/features/merge_requests/diff_notes_avatars_spec.rb +++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' feature 'Diff note avatars', feature: true, js: true do + include NoteInteractionHelpers + let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") } @@ -110,6 +112,8 @@ feature 'Diff note avatars', feature: true, js: true do end it 'removes avatar when note is deleted' do + open_more_actions_dropdown(note) + page.within find(".note-row-#{note.id}") do find('.js-note-delete').click end diff --git a/spec/features/merge_requests/user_posts_notes_spec.rb b/spec/features/merge_requests/user_posts_notes_spec.rb index 06de072257a..22552529b9e 100644 --- a/spec/features/merge_requests/user_posts_notes_spec.rb +++ b/spec/features/merge_requests/user_posts_notes_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe 'Merge requests > User posts notes', :js do + include NoteInteractionHelpers + let(:project) { create(:project) } let(:merge_request) do create(:merge_request, source_project: project, target_project: project) @@ -73,6 +75,8 @@ describe 'Merge requests > User posts notes', :js do describe 'editing the note' do before do find('.note').hover + open_more_actions_dropdown(note) + find('.js-note-edit').click end @@ -100,6 +104,8 @@ describe 'Merge requests > User posts notes', :js do wait_for_requests find('.note').hover + open_more_actions_dropdown(note) + find('.js-note-edit').click page.within('.current-note-edit-form') do @@ -126,6 +132,8 @@ describe 'Merge requests > User posts notes', :js do describe 'deleting an attachment' do before do find('.note').hover + open_more_actions_dropdown(note) + find('.js-note-edit').click end diff --git a/spec/features/reportable_note/commit_spec.rb b/spec/features/reportable_note/commit_spec.rb new file mode 100644 index 00000000000..39b1c4acf52 --- /dev/null +++ b/spec/features/reportable_note/commit_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe 'Reportable note on commit', :feature, :js do + include RepoHelpers + + let(:user) { create(:user) } + let(:project) { create(:project) } + + before do + project.add_master(user) + login_as user + end + + context 'a normal note' do + let!(:note) { create(:note_on_commit, commit_id: sample_commit.id, project: project) } + + before do + visit namespace_project_commit_path(project.namespace, project, sample_commit.id) + end + + it_behaves_like 'reportable note' + end + + context 'a diff note' do + let!(:note) { create(:diff_note_on_commit, commit_id: sample_commit.id, project: project) } + + before do + visit namespace_project_commit_path(project.namespace, project, sample_commit.id) + end + + it_behaves_like 'reportable note' + end +end diff --git a/spec/features/reportable_note/issue_spec.rb b/spec/features/reportable_note/issue_spec.rb new file mode 100644 index 00000000000..5f526818994 --- /dev/null +++ b/spec/features/reportable_note/issue_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe 'Reportable note on issue', :feature, :js do + let(:user) { create(:user) } + let(:project) { create(:empty_project) } + let(:issue) { create(:issue, project: project) } + let!(:note) { create(:note_on_issue, noteable: issue, project: project) } + + before do + project.add_master(user) + login_as user + + visit namespace_project_issue_path(project.namespace, project, issue) + end + + it_behaves_like 'reportable note' +end diff --git a/spec/features/reportable_note/merge_request_spec.rb b/spec/features/reportable_note/merge_request_spec.rb new file mode 100644 index 00000000000..6d053d26626 --- /dev/null +++ b/spec/features/reportable_note/merge_request_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe 'Reportable note on merge request', :feature, :js do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:merge_request) { create(:merge_request, source_project: project) } + + before do + project.add_master(user) + login_as user + + visit namespace_project_merge_request_path(project.namespace, project, merge_request) + end + + context 'a normal note' do + let!(:note) { create(:note_on_merge_request, noteable: merge_request, project: project) } + + it_behaves_like 'reportable note' + end + + context 'a diff note' do + let!(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) } + + it_behaves_like 'reportable note' + end +end diff --git a/spec/features/reportable_note/snippets_spec.rb b/spec/features/reportable_note/snippets_spec.rb new file mode 100644 index 00000000000..3f1e0cf9097 --- /dev/null +++ b/spec/features/reportable_note/snippets_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe 'Reportable note on snippets', :feature, :js do + let(:user) { create(:user) } + let(:project) { create(:empty_project) } + + before do + project.add_master(user) + login_as user + end + + describe 'on project snippet' do + let(:snippet) { create(:project_snippet, :public, project: project, author: user) } + let!(:note) { create(:note_on_project_snippet, noteable: snippet, project: project) } + + before do + visit namespace_project_snippet_path(project.namespace, project, snippet) + end + + it_behaves_like 'reportable note' + end + + describe 'on personal snippet' do + let(:snippet) { create(:personal_snippet, :public, author: user) } + let!(:note) { create(:note_on_personal_snippet, noteable: snippet, author: user) } + + before do + visit snippet_path(snippet) + end + + it_behaves_like 'reportable note' + end +end diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb index f7afc174019..44b0c89fac7 100644 --- a/spec/features/snippets/notes_on_personal_snippets_spec.rb +++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe 'Comments on personal snippets', :js, feature: true do + include NoteInteractionHelpers + let!(:user) { create(:user) } let!(:snippet) { create(:personal_snippet, :public) } let!(:snippet_notes) do @@ -22,6 +24,8 @@ describe 'Comments on personal snippets', :js, feature: true do it 'contains notes for a snippet with correct action icons' do expect(page).to have_selector('#notes-list li', count: 2) + open_more_actions_dropdown(snippet_notes[0]) + # comment authored by current user page.within("#notes-list li#note_#{snippet_notes[0].id}") do expect(page).to have_content(snippet_notes[0].note) @@ -29,6 +33,8 @@ describe 'Comments on personal snippets', :js, feature: true do expect(page).to have_selector('.note-emoji-button') end + open_more_actions_dropdown(snippet_notes[1]) + page.within("#notes-list li#note_#{snippet_notes[1].id}") do expect(page).to have_content(snippet_notes[1].note) expect(page).not_to have_selector('.js-note-delete') @@ -68,6 +74,8 @@ describe 'Comments on personal snippets', :js, feature: true do context 'when editing a note' do it 'changes the text' do + open_more_actions_dropdown(snippet_notes[0]) + page.within("#notes-list li#note_#{snippet_notes[0].id}") do click_on 'Edit comment' end @@ -89,8 +97,10 @@ describe 'Comments on personal snippets', :js, feature: true do context 'when deleting a note' do it 'removes the note from the snippet detail page' do + open_more_actions_dropdown(snippet_notes[0]) + page.within("#notes-list li#note_#{snippet_notes[0].id}") do - click_on 'Remove comment' + click_on 'Delete comment' end wait_for_requests diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb index 355a4845afb..cc861af8533 100644 --- a/spec/helpers/notes_helper_spec.rb +++ b/spec/helpers/notes_helper_spec.rb @@ -256,4 +256,14 @@ describe NotesHelper do expect(helper.form_resources).to eq([@project.namespace, @project, @note]) end end + + describe '#noteable_note_url' do + let(:project) { create(:empty_project) } + let(:issue) { create(:issue, project: project) } + let(:note) { create(:note_on_issue, noteable: issue, project: project) } + + it 'returns the noteable url with an anchor to the note' do + expect(noteable_note_url(note)).to match("/#{project.namespace.path}/#{project.path}/issues/#{issue.iid}##{dom_id(note)}") + end + end end diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb index 3fe8cf43934..e8a37e8d77b 100644 --- a/spec/lib/gitlab/url_builder_spec.rb +++ b/spec/lib/gitlab/url_builder_spec.rb @@ -97,6 +97,17 @@ describe Gitlab::UrlBuilder, lib: true do end end + context 'on a PersonalSnippet' do + it 'returns a proper URL' do + personal_snippet = create(:personal_snippet) + note = build_stubbed(:note_on_personal_snippet, noteable: personal_snippet) + + url = described_class.build(note) + + expect(url).to eq "#{Settings.gitlab['url']}/snippets/#{note.noteable_id}#note_#{note.id}" + end + end + context 'on another object' do it 'returns a proper URL' do project = build_stubbed(:empty_project) diff --git a/spec/support/features/reportable_note_shared_examples.rb b/spec/support/features/reportable_note_shared_examples.rb new file mode 100644 index 00000000000..0d80c95e826 --- /dev/null +++ b/spec/support/features/reportable_note_shared_examples.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +shared_examples 'reportable note' do + include NotesHelper + + let(:comment) { find("##{ActionView::RecordIdentifier.dom_id(note)}") } + let(:more_actions_selector) { '.more-actions.dropdown' } + let(:abuse_report_path) { new_abuse_report_path(user_id: note.author.id, ref_url: noteable_note_url(note)) } + + it 'has a `More actions` dropdown' do + expect(comment).to have_selector(more_actions_selector) + end + + it 'dropdown has Edit, Report and Delete links' do + dropdown = comment.find(more_actions_selector) + + dropdown.click + dropdown.find('.dropdown-menu li', match: :first) + + expect(dropdown).to have_button('Edit comment') + expect(dropdown).to have_link('Report as abuse', href: abuse_report_path) + expect(dropdown).to have_link('Delete comment', href: note_url(note, project)) + end + + it 'Report button links to a report page' do + dropdown = comment.find(more_actions_selector) + + dropdown.click + dropdown.find('.dropdown-menu li', match: :first) + + dropdown.click_link('Report as abuse') + + expect(find('#user_name')['value']).to match(note.author.username) + expect(find('#abuse_report_message')['value']).to match(noteable_note_url(note)) + end +end diff --git a/spec/support/helpers/note_interaction_helpers.rb b/spec/support/helpers/note_interaction_helpers.rb new file mode 100644 index 00000000000..551c759133c --- /dev/null +++ b/spec/support/helpers/note_interaction_helpers.rb @@ -0,0 +1,8 @@ +module NoteInteractionHelpers + def open_more_actions_dropdown(note) + note_element = find("#note_#{note.id}") + + note_element.find('.more-actions').click + note_element.find('.more-actions .dropdown-menu li', match: :first) + end +end -- cgit v1.2.3 From dbffaaa97e7a195dc5421237392788a03a6b763a Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 6 Jun 2017 16:20:24 -0500 Subject: =?UTF-8?q?Blob#load=5Fall=5Fdata!=20doesn=E2=80=99t=20need=20an?= =?UTF-8?q?=20argument?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/requests/git_http_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index f018b48ceb2..c09be0ce1b9 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -648,7 +648,7 @@ describe 'Git HTTP requests', lib: true do # Provide a dummy file in its place allow_any_instance_of(Repository).to receive(:blob_at).and_call_original allow_any_instance_of(Repository).to receive(:blob_at).with('b83d6e391c22777fca1ed3012fce84f633d7fed0', 'info/refs') do - Gitlab::Git::Blob.find(project.repository, 'master', 'bar/branch-test.txt') + Blob.decorate(Gitlab::Git::Blob.find(project.repository, 'master', 'bar/branch-test.txt'), project) end get "/#{project.path_with_namespace}/blob/master/info/refs" -- cgit v1.2.3 From c7bf2bfdaaa2f1aaff0cb1118260db744abb5633 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Wed, 7 Jun 2017 22:11:43 +0200 Subject: Converting Tests to Spec Tests --- spec/features/explore/new_menu_spec.rb | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 spec/features/explore/new_menu_spec.rb (limited to 'spec') diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb new file mode 100644 index 00000000000..8fc8d0e8975 --- /dev/null +++ b/spec/features/explore/new_menu_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe 'Top Plus Menu', :js, :feature do + let!(:user) { create :user } + let!(:group) { create(:group) } + let!(:public_group) { create(:group, :public) } + let!(:private_group) { create(:group, :private) } + let!(:empty_project) { create(:empty_project, group: public_group) } + + before do + group.add_owner(user) + + login_as(user) + + visit explore_groups_path + end + + context 'used by full user' do + before do + login_as :user + end + + scenario 'click on New project shows new project page' + visit root_dashboard_path + + click_topmenuitem("New project") + + expect(page).to have_content('Project path') + expect(page).to have_content('Project name') + end + + scenario 'click on New group shows new group page' + visit root_dashboard_path + + click_topmenuitem("New group") + + expect(page).to have_content('Group path') + expect(page).to have_content('Group name') + end + + scenario 'click on New group shows new group page' + visit root_dashboard_path + + click_topmenuitem("New snippet") + + expect(page).to have_content('New Snippet') + expect(page).to have_content('Title') + end + end + + def click_topmenuitem(item_name) + page.within '.header-content' do + find('.header-new-dropdown-toggle').trigger('click') + expect(page).to have_selector('.header-new.dropdown.open', count: 1) + click_link item_name + end + end +end -- cgit v1.2.3 From bdebe849b8251f390378dd446d9022fca1b2d55c Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 7 Jun 2017 20:13:44 +0000 Subject: Translate project & repository pages --- spec/features/projects/new_project_spec.rb | 4 ++-- spec/helpers/notifications_helper_spec.rb | 6 ++++++ spec/javascripts/build_spec.js | 2 +- spec/javascripts/datetime_utility_spec.js | 20 ++++++++++++++++++++ spec/services/projects/create_service_spec.rb | 2 +- 5 files changed, 30 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index c66b9a34b86..b1f9eb15667 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -17,10 +17,10 @@ feature "New project", feature: true do expect(find_field("project_visibility_level_#{level}")).to be_checked end - it 'saves visibility level on validation error' do + it "saves visibility level #{level} on validation error" do visit new_project_path - choose(key) + choose(s_(key)) click_button('Create project') expect(find_field("project_visibility_level_#{level}")).to be_checked diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb index 9d5f009ebe1..9ecaabc04ed 100644 --- a/spec/helpers/notifications_helper_spec.rb +++ b/spec/helpers/notifications_helper_spec.rb @@ -12,5 +12,11 @@ describe NotificationsHelper do describe 'notification_title' do it { expect(notification_title(:watch)).to match('Watch') } it { expect(notification_title(:mention)).to match('On mention') } + it { expect(notification_title(:global)).to match('Global') } + end + + describe '#notification_event_name' do + it { expect(notification_event_name(:success_pipeline)).to match('Successful pipeline') } + it { expect(notification_event_name(:failed_pipeline)).to match('Failed pipeline') } end end diff --git a/spec/javascripts/build_spec.js b/spec/javascripts/build_spec.js index 461908f3fde..4c8a48580d7 100644 --- a/spec/javascripts/build_spec.js +++ b/spec/javascripts/build_spec.js @@ -58,7 +58,7 @@ describe('Build', () => { it('displays the remove date correctly', () => { const removeDateElement = document.querySelector('.js-artifacts-remove'); - expect(removeDateElement.innerText.trim()).toBe('1 year'); + expect(removeDateElement.innerText.trim()).toBe('1 year remaining'); }); }); diff --git a/spec/javascripts/datetime_utility_spec.js b/spec/javascripts/datetime_utility_spec.js index e347c980c78..c82ad0bea48 100644 --- a/spec/javascripts/datetime_utility_spec.js +++ b/spec/javascripts/datetime_utility_spec.js @@ -2,6 +2,26 @@ import '~/lib/utils/datetime_utility'; (() => { describe('Date time utils', () => { + describe('timeFor', () => { + it('returns `past due` when in past', () => { + const date = new Date(); + date.setFullYear(date.getFullYear() - 1); + + expect( + gl.utils.timeFor(date), + ).toBe('Past due'); + }); + + it('returns remaining time when in the future', () => { + const date = new Date(); + date.setFullYear(date.getFullYear() + 1); + + expect( + gl.utils.timeFor(date), + ).toBe('1 year remaining'); + }); + }); + describe('get day name', () => { it('should return Sunday', () => { const day = gl.utils.getDayName(new Date('07/17/2016')); diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index 3c566c04d6b..40298dcb723 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -115,7 +115,7 @@ describe Projects::CreateService, '#execute', services: true do stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) opts.merge!( - visibility_level: Gitlab::VisibilityLevel.options['Public'] + visibility_level: Gitlab::VisibilityLevel::PUBLIC ) end -- cgit v1.2.3 From bf601f0775d0138f30721f350f9ed3535c7e701f Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Wed, 7 Jun 2017 22:49:22 +0200 Subject: Fixed spec test syntax errors --- spec/features/explore/new_menu_spec.rb | 62 +++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb index 8fc8d0e8975..eaf431f82b1 100644 --- a/spec/features/explore/new_menu_spec.rb +++ b/spec/features/explore/new_menu_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Top Plus Menu', :js, :feature do +feature 'Top Plus Menu', feature: true, js: true do let!(:user) { create :user } let!(:group) { create(:group) } let!(:public_group) { create(:group, :public) } @@ -20,7 +20,7 @@ describe 'Top Plus Menu', :js, :feature do login_as :user end - scenario 'click on New project shows new project page' + scenario 'click on New project shows new project page' do visit root_dashboard_path click_topmenuitem("New project") @@ -29,7 +29,7 @@ describe 'Top Plus Menu', :js, :feature do expect(page).to have_content('Project name') end - scenario 'click on New group shows new group page' + scenario 'click on New group shows new group page' do visit root_dashboard_path click_topmenuitem("New group") @@ -38,7 +38,7 @@ describe 'Top Plus Menu', :js, :feature do expect(page).to have_content('Group name') end - scenario 'click on New group shows new group page' + scenario 'click on New snippet shows new snippet page' do visit root_dashboard_path click_topmenuitem("New snippet") @@ -46,6 +46,60 @@ describe 'Top Plus Menu', :js, :feature do expect(page).to have_content('New Snippet') expect(page).to have_content('Title') end + + scenario 'click on New issue shows new issue page' do + visit namespace_project_path(empty_project.namespace, empty_project) + + click_topmenuitem("New issue") + + expect(page).to have_content('New Issue') + expect(page).to have_content('Title') + end + + scenario 'click on New merge request shows new merge request page' do + visit namespace_project_path(empty_project.namespace, empty_project) + + click_topmenuitem("New merge request") + + expect(page).to have_content('New Merge Request') + expect(page).to have_content('Source branch') + expect(page).to have_content('Target branch') + end + + scenario 'click on New project snippet shows new snippet page' do + visit namespace_project_path(empty_project.namespace, empty_project) + + page.within '.header-content' do + find('.header-new-dropdown-toggle').trigger('click') + expect(page).to have_selector('.header-new.dropdown.open', count: 1) + find('.header-new-project-snippet a').trigger('click') + end + + expect(page).to have_content('New Snippet') + expect(page).to have_content('Title') + end + + scenario 'Click on New subgroup shows new group page' do + visit group_path(group) + + click_topmenuitem("New subgroup") + + expect(page).to have_content('Group path') + expect(page).to have_content('Group name') + end + + scenario 'Click on New project in group shows new project page' do + visit group_path(group) + + page.within '.header-content' do + find('.header-new-dropdown-toggle').trigger('click') + expect(page).to have_selector('.header-new.dropdown.open', count: 1) + find('.header-new-group-project a').trigger('click') + end + + expect(page).to have_content('Project path') + expect(page).to have_content('Project name') + end end def click_topmenuitem(item_name) -- cgit v1.2.3 From 8f64a5a80a1479550fb5c5d346b1cf52865fc080 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Fri, 2 Jun 2017 11:19:33 -0500 Subject: Improve form spec --- spec/features/issues/form_spec.rb | 41 +++++++++++---------------------------- 1 file changed, 11 insertions(+), 30 deletions(-) (limited to 'spec') diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index 8949dbcb663..96d37e33f3d 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -24,37 +24,17 @@ describe 'New/edit issue', :feature, :js do visit new_namespace_project_issue_path(project.namespace, project) end - describe 'shorten users API pagination limit' do + describe 'shorten users API pagination limit (CE)' do before do + # Using `allow_any_instance_of`/`and_wrap_original`, `original` would + # somehow refer to the very block we defined to _wrap_ that method, instead of + # the original method, resulting in infinite recurison when called. + # This is likely a bug with helper modules included into dynamically generated view classes. + # To work around this, we have to hold on to and call to the original implementation manually. + original_issue_dropdown_options = FormHelper.instance_method(:issue_dropdown_options) allow_any_instance_of(FormHelper).to receive(:issue_dropdown_options).and_wrap_original do |original, *args| - has_multiple_assignees = *args[1] - - options = { - toggle_class: 'js-user-search js-assignee-search js-multiselect js-save-user-data', - title: 'Select assignee', - filter: true, - dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee', - placeholder: 'Search users', - data: { - per_page: 1, - null_user: true, - current_user: true, - project_id: project.try(:id), - field_name: "issue[assignee_ids][]", - default_label: 'Assignee', - 'max-select': 1, - 'dropdown-header': 'Assignee', - multi_select: true, - 'input-meta': 'name', - 'always-show-selectbox': true - } - } - - if has_multiple_assignees - options[:title] = 'Select assignee(s)' - options[:data][:'dropdown-header'] = 'Assignee(s)' - options[:data].delete(:'max-select') - end + options = original_issue_dropdown_options.bind(original.receiver).call(*args) + options[:data][:per_page] = 2 options end @@ -74,6 +54,7 @@ describe 'New/edit issue', :feature, :js do click_link user2.name end + find('.js-assignee-search').click find('.js-dropdown-input-clear').click page.within '.dropdown-menu-user' do @@ -83,7 +64,7 @@ describe 'New/edit issue', :feature, :js do end end - describe 'single assignee' do + describe 'single assignee (CE)' do before do click_button 'Unassigned' -- cgit v1.2.3 From 9647d2e76d05e8720bfe695918e292e57307900e Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Wed, 7 Jun 2017 23:59:25 +0200 Subject: Enhancing Spec's with negative cases --- spec/features/explore/new_menu_spec.rb | 67 ++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb index eaf431f82b1..ae65f25d48b 100644 --- a/spec/features/explore/new_menu_spec.rb +++ b/spec/features/explore/new_menu_spec.rb @@ -1,23 +1,22 @@ require 'spec_helper' feature 'Top Plus Menu', feature: true, js: true do - let!(:user) { create :user } - let!(:group) { create(:group) } - let!(:public_group) { create(:group, :public) } - let!(:private_group) { create(:group, :private) } - let!(:empty_project) { create(:empty_project, group: public_group) } + let(:user) { create :user } + let(:guest_user) { create :user} + let(:group) { create(:group) } + let(:public_group) { create(:group, :public) } + let(:project) { create(:project, :repository, creator: user, namespace: user.namespace) } before do group.add_owner(user) + group.add_guest(guest_user) - login_as(user) - - visit explore_groups_path + project.add_guest(guest_user) end context 'used by full user' do before do - login_as :user + login_as(user) end scenario 'click on New project shows new project page' do @@ -48,7 +47,7 @@ feature 'Top Plus Menu', feature: true, js: true do end scenario 'click on New issue shows new issue page' do - visit namespace_project_path(empty_project.namespace, empty_project) + visit namespace_project_path(project.namespace, project) click_topmenuitem("New issue") @@ -57,7 +56,7 @@ feature 'Top Plus Menu', feature: true, js: true do end scenario 'click on New merge request shows new merge request page' do - visit namespace_project_path(empty_project.namespace, empty_project) + visit namespace_project_path(project.namespace, project) click_topmenuitem("New merge request") @@ -67,7 +66,7 @@ feature 'Top Plus Menu', feature: true, js: true do end scenario 'click on New project snippet shows new snippet page' do - visit namespace_project_path(empty_project.namespace, empty_project) + visit namespace_project_path(project.namespace, project) page.within '.header-content' do find('.header-new-dropdown-toggle').trigger('click') @@ -102,6 +101,45 @@ feature 'Top Plus Menu', feature: true, js: true do end end + context 'used by guest user' do + before do + login_as(guest_user) + end + + scenario 'click on New issue shows new issue page' do + visit namespace_project_path(project.namespace, project) + + click_topmenuitem("New issue") + + expect(page).to have_content('New Issue') + expect(page).to have_content('Title') + end + + scenario 'has no New merge request menu item' do + visit namespace_project_path(project.namespace, project) + + hasnot_topmenuitem("New merge request") + end + + scenario 'has no New project snippet menu item' do + visit namespace_project_path(project.namespace, project) + + expect(find('.header-new.dropdown')).not_to have_selector('.header-new-project-snippet') + end + + scenario 'has no New subgroup menu item' do + visit group_path(group) + + hasnot_topmenuitem("New subgroup") + end + + scenario 'has no New project for group menu item' do + visit group_path(group) + + expect(find('.header-new.dropdown')).not_to have_selector('.header-new-group-project') + end + end + def click_topmenuitem(item_name) page.within '.header-content' do find('.header-new-dropdown-toggle').trigger('click') @@ -109,4 +147,9 @@ feature 'Top Plus Menu', feature: true, js: true do click_link item_name end end + + def hasnot_topmenuitem(item_name) + expect(find('.header-new.dropdown')).not_to have_content(item_name) + end + end end -- cgit v1.2.3 From 81b565ee36179561dcae8d428a712fa5fe1cc04b Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Thu, 8 Jun 2017 00:02:31 +0200 Subject: Fix End Syntax Error --- spec/features/explore/new_menu_spec.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb index ae65f25d48b..cbd97ff74b3 100644 --- a/spec/features/explore/new_menu_spec.rb +++ b/spec/features/explore/new_menu_spec.rb @@ -149,7 +149,6 @@ feature 'Top Plus Menu', feature: true, js: true do end def hasnot_topmenuitem(item_name) - expect(find('.header-new.dropdown')).not_to have_content(item_name) - end - end + expect(find('.header-new.dropdown')).not_to have_content(item_name) + end end -- cgit v1.2.3 From 39d976cf5881c947eefeb45a2f8fe2922923eac6 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Thu, 8 Jun 2017 00:37:45 +0200 Subject: Added more negative checks for public project --- spec/features/explore/new_menu_spec.rb | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb index cbd97ff74b3..15a6354211b 100644 --- a/spec/features/explore/new_menu_spec.rb +++ b/spec/features/explore/new_menu_spec.rb @@ -4,8 +4,8 @@ feature 'Top Plus Menu', feature: true, js: true do let(:user) { create :user } let(:guest_user) { create :user} let(:group) { create(:group) } - let(:public_group) { create(:group, :public) } let(:project) { create(:project, :repository, creator: user, namespace: user.namespace) } + let(:public_project) { create(:project, :public) } before do group.add_owner(user) @@ -127,6 +127,24 @@ feature 'Top Plus Menu', feature: true, js: true do expect(find('.header-new.dropdown')).not_to have_selector('.header-new-project-snippet') end + scenario 'public project has no New Issue Button' do + visit namespace_project_path(public_project.namespace, public_project) + + hasnot_topmenuitem("New issue") + end + + scenario 'public project has no New merge request menu item' do + visit namespace_project_path(public_project.namespace, public_project) + + hasnot_topmenuitem("New merge request") + end + + scenario 'public project has no New project snippet menu item' do + visit namespace_project_path(public_project.namespace, public_project) + + expect(find('.header-new.dropdown')).not_to have_selector('.header-new-project-snippet') + end + scenario 'has no New subgroup menu item' do visit group_path(group) -- cgit v1.2.3 From 7a07ecebaf507632c255b7743c858a861845f4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20Carlb=C3=A4cker?= Date: Thu, 8 Jun 2017 00:47:10 +0000 Subject: nil-check Repository::is_ancestor? --- spec/models/repository_spec.rb | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'spec') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 718b7d5e86b..a6d4d92c450 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1905,19 +1905,43 @@ describe Repository, models: true do end describe '#is_ancestor?' do - context 'Gitaly is_ancestor feature enabled' do - let(:commit) { repository.commit } - let(:ancestor) { commit.parents.first } + let(:commit) { repository.commit } + let(:ancestor) { commit.parents.first } + context 'with Gitaly enabled' do + it 'it is an ancestor' do + expect(repository.is_ancestor?(ancestor.id, commit.id)).to eq(true) + end + + it 'it is not an ancestor' do + expect(repository.is_ancestor?(commit.id, ancestor.id)).to eq(false) + end + + it 'returns false on nil-values' do + expect(repository.is_ancestor?(nil, commit.id)).to eq(false) + expect(repository.is_ancestor?(ancestor.id, nil)).to eq(false) + expect(repository.is_ancestor?(nil, nil)).to eq(false) + end + end + + context 'with Gitaly disabled' do before do - allow(Gitlab::GitalyClient).to receive(:enabled?).and_return(true) - allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:is_ancestor).and_return(true) + allow(Gitlab::GitalyClient).to receive(:enabled?).and_return(false) + allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:is_ancestor).and_return(false) end - it "asks Gitaly server if it's an ancestor" do - expect_any_instance_of(Gitlab::GitalyClient::Commit).to receive(:is_ancestor).with(ancestor.id, commit.id) + it 'it is an ancestor' do + expect(repository.is_ancestor?(ancestor.id, commit.id)).to eq(true) + end + + it 'it is not an ancestor' do + expect(repository.is_ancestor?(commit.id, ancestor.id)).to eq(false) + end - repository.is_ancestor?(ancestor.id, commit.id) + it 'returns false on nil-values' do + expect(repository.is_ancestor?(nil, commit.id)).to eq(false) + expect(repository.is_ancestor?(ancestor.id, nil)).to eq(false) + expect(repository.is_ancestor?(nil, nil)).to eq(false) end end end -- cgit v1.2.3 From cb5a5eb89265f7261ecc97b6de5bd26ca092960c Mon Sep 17 00:00:00 2001 From: Robin Bobbitt Date: Wed, 7 Jun 2017 15:49:45 -0400 Subject: Instruct user to use a personal access token for Git over HTTP If internal auth is disabled and LDAP is not configured on the instance, present the user with a message to create a personal access token if his Git over HTTP auth attempt fails. --- spec/lib/gitlab/auth_spec.rb | 6 +++++ spec/requests/git_http_spec.rb | 43 ++++++++++++++++++++++++++++++++---- spec/requests/jwt_controller_spec.rb | 21 +++++++++++++++--- 3 files changed, 63 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index d6006eab0c9..d09da951869 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -204,6 +204,12 @@ describe Gitlab::Auth, lib: true do expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login) expect(gl_auth.find_for_git_client(login, 'bar', project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new) end + + it 'throws an error suggesting user create a PAT when internal auth is disabled' do + allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false } + + expect { gl_auth.find_for_git_client('foo', 'bar', project: nil, ip: 'ip') }.to raise_error(Gitlab::Auth::MissingPersonalTokenError) + end end describe 'find_with_user_password' do diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index f018b48ceb2..ae2ec39f402 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -418,17 +418,17 @@ describe 'Git HTTP requests', lib: true do end context 'when username and password are provided' do - it 'rejects pulls with 2FA error message' do + it 'rejects pulls with personal access token error message' do download(path, user: user.username, password: user.password) do |response| expect(response).to have_http_status(:unauthorized) - expect(response.body).to include('You have 2FA enabled, please use a personal access token for Git over HTTP') + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') end end - it 'rejects the push attempt' do + it 'rejects the push attempt with personal access token error message' do upload(path, user: user.username, password: user.password) do |response| expect(response).to have_http_status(:unauthorized) - expect(response.body).to include('You have 2FA enabled, please use a personal access token for Git over HTTP') + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') end end end @@ -441,6 +441,41 @@ describe 'Git HTTP requests', lib: true do end end + context 'when internal auth is disabled' do + before do + allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false } + end + + it 'rejects pulls with personal access token error message' do + download(path, user: 'foo', password: 'bar') do |response| + expect(response).to have_http_status(:unauthorized) + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') + end + end + + it 'rejects pushes with personal access token error message' do + upload(path, user: 'foo', password: 'bar') do |response| + expect(response).to have_http_status(:unauthorized) + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') + end + end + + context 'when LDAP is configured' do + before do + allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true) + allow_any_instance_of(Gitlab::LDAP::Authentication). + to receive(:login).and_return(nil) + end + + it 'does not display the personal access token error message' do + upload(path, user: 'foo', password: 'bar') do |response| + expect(response).to have_http_status(:unauthorized) + expect(response.body).not_to include('You must use a personal access token with \'api\' scope for Git over HTTP') + end + end + end + end + context "when blank password attempts follow a valid login" do def attempt_login(include_password) password = include_password ? user.password : "" diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb index e056353fa6f..54d7cf5f10d 100644 --- a/spec/requests/jwt_controller_spec.rb +++ b/spec/requests/jwt_controller_spec.rb @@ -70,7 +70,7 @@ describe JwtController do context 'without personal token' do it 'rejects the authorization attempt' do expect(response).to have_http_status(401) - expect(response.body).to include('You have 2FA enabled, please use a personal access token for Git over HTTP') + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') end end @@ -88,9 +88,24 @@ describe JwtController do context 'using invalid login' do let(:headers) { { authorization: credentials('invalid', 'password') } } - subject! { get '/jwt/auth', parameters, headers } + context 'when internal auth is enabled' do + it 'rejects the authorization attempt' do + get '/jwt/auth', parameters, headers + + expect(response).to have_http_status(401) + expect(response.body).not_to include('You must use a personal access token with \'api\' scope for Git over HTTP') + end + end - it { expect(response).to have_http_status(401) } + context 'when internal auth is disabled' do + it 'rejects the authorization attempt with personal access token message' do + allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false } + get '/jwt/auth', parameters, headers + + expect(response).to have_http_status(401) + expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') + end + end end end -- cgit v1.2.3 From ff05275797bf56e49db238ff57e28b988663eb3e Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Wed, 7 Jun 2017 22:42:41 -0500 Subject: Add feature tests for Dashboard Groups page --- spec/features/dashboard/groups_list_spec.rb | 122 +++++++++++++++++++++++----- 1 file changed, 103 insertions(+), 19 deletions(-) (limited to 'spec') diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb index b0e2953dda2..7eb254f8451 100644 --- a/spec/features/dashboard/groups_list_spec.rb +++ b/spec/features/dashboard/groups_list_spec.rb @@ -6,40 +6,124 @@ describe 'Dashboard Groups page', js: true, feature: true do let!(:nested_group) { create(:group, :nested) } let!(:another_group) { create(:group) } - before do + it 'shows groups user is member of' do group.add_owner(user) nested_group.add_owner(user) login_as(user) - visit dashboard_groups_path - end - it 'shows groups user is member of' do expect(page).to have_content(group.full_name) expect(page).to have_content(nested_group.full_name) expect(page).not_to have_content(another_group.full_name) end - it 'filters groups' do - fill_in 'filter_groups', with: group.name - wait_for_requests + describe 'when filtering groups' do + before do + group.add_owner(user) + nested_group.add_owner(user) - expect(page).to have_content(group.full_name) - expect(page).not_to have_content(nested_group.full_name) - expect(page).not_to have_content(another_group.full_name) + login_as(user) + + visit dashboard_groups_path + end + + it 'filters groups' do + fill_in 'filter_groups', with: group.name + wait_for_requests + + expect(page).to have_content(group.full_name) + expect(page).not_to have_content(nested_group.full_name) + expect(page).not_to have_content(another_group.full_name) + end + + it 'resets search when user cleans the input' do + fill_in 'filter_groups', with: group.name + wait_for_requests + + fill_in 'filter_groups', with: "" + wait_for_requests + + expect(page).to have_content(group.full_name) + expect(page).to have_content(nested_group.full_name) + expect(page).not_to have_content(another_group.full_name) + expect(page.all('.js-groups-list-holder .content-list li').length).to eq 2 + end end - it 'resets search when user cleans the input' do - fill_in 'filter_groups', with: group.name - wait_for_requests + describe 'group with subgroups' do + let!(:subgroup) { create(:group, :public, parent: group) } - fill_in 'filter_groups', with: "" - wait_for_requests + before do + group.add_owner(user) + subgroup.add_owner(user) - expect(page).to have_content(group.full_name) - expect(page).to have_content(nested_group.full_name) - expect(page).not_to have_content(another_group.full_name) - expect(page.all('.js-groups-list-holder .content-list li').length).to eq 2 + login_as(user) + + visit dashboard_groups_path + end + + it 'shows subgroups inside of its parent group' do + expect(page).to have_selector('.groups-list-tree-container .group-list-tree', count: 2) + expect(page).to have_selector(".groups-list-tree-container #group-#{group.id} #group-#{subgroup.id}", count: 1) + end + + it 'can toggle parent group' do + # Expanded by default + expect(page).to have_selector("#group-#{group.id} .fa-caret-down", count: 1) + expect(page).not_to have_selector("#group-#{group.id} .fa-caret-right") + + # Collapse + find("#group-#{group.id}").trigger('click') + + expect(page).not_to have_selector("#group-#{group.id} .fa-caret-down") + expect(page).to have_selector("#group-#{group.id} .fa-caret-right", count: 1) + expect(page).not_to have_selector("#group-#{group.id} #group-#{subgroup.id}") + + # Expand + find("#group-#{group.id}").trigger('click') + + expect(page).to have_selector("#group-#{group.id} .fa-caret-down", count: 1) + expect(page).not_to have_selector("#group-#{group.id} .fa-caret-right") + expect(page).to have_selector("#group-#{group.id} #group-#{subgroup.id}") + end + end + + describe 'when using pagination' do + let(:group2) { create(:group) } + + before do + group.add_owner(user) + group2.add_owner(user) + + allow(Kaminari.config).to receive(:default_per_page).and_return(1) + + login_as(user) + visit dashboard_groups_path + end + + it 'shows pagination' do + expect(page).to have_selector('.gl-pagination') + expect(page).to have_selector('.gl-pagination .page', count: 2) + end + + it 'loads results for next page' do + # Check first page + expect(page).to have_content(group2.full_name) + expect(page).to have_selector("#group-#{group2.id}") + expect(page).not_to have_content(group.full_name) + expect(page).not_to have_selector("#group-#{group.id}") + + # Go to next page + find(".gl-pagination .page:not(.active) a").trigger('click') + + wait_for_requests + + # Check second page + expect(page).to have_content(group.full_name) + expect(page).to have_selector("#group-#{group.id}") + expect(page).not_to have_content(group2.full_name) + expect(page).not_to have_selector("#group-#{group2.id}") + end end end -- cgit v1.2.3 From 7ff17980ce58fc7b9e6ba5ee95cb34f52e871b18 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Wed, 7 Jun 2017 23:00:03 -0500 Subject: Display user access type for each group Also adds unit tests for this --- spec/javascripts/groups/group_item_spec.js | 1 + spec/javascripts/groups/mock_data.js | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/groups/group_item_spec.js b/spec/javascripts/groups/group_item_spec.js index 9d70f60cd57..73ea86e6756 100644 --- a/spec/javascripts/groups/group_item_spec.js +++ b/spec/javascripts/groups/group_item_spec.js @@ -38,6 +38,7 @@ describe('Groups Component', () => { expect(component.$el.querySelector('.group-visibility')).toBeDefined(); expect(component.$el.querySelector('.avatar-container')).toBeDefined(); expect(component.$el.querySelector('.title').textContent).toContain(group.name); + expect(component.$el.querySelector('.access-type').textContent).toContain(group.permissions.humanGroupAccess); expect(component.$el.querySelector('.description').textContent).toContain(group.description); expect(component.$el.querySelector('.edit-group')).toBeDefined(); expect(component.$el.querySelector('.leave-group')).toBeDefined(); diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js index 9951abcc2dc..1c0ec7a97d0 100644 --- a/spec/javascripts/groups/mock_data.js +++ b/spec/javascripts/groups/mock_data.js @@ -15,7 +15,7 @@ const group1 = { number_users_with_delimiter: '1', has_subgroups: true, permissions: { - group_access: 50, + human_group_access: 'Master', }, }; @@ -37,7 +37,7 @@ const group14 = { number_users_with_delimiter: '1', has_subgroups: true, permissions: { - group_access: 30, + human_group_access: 'Master', }, }; @@ -58,7 +58,7 @@ const group2 = { number_users_with_delimiter: '1', has_subgroups: true, permissions: { - group_access: 50, + human_group_access: 'Master', }, }; @@ -79,7 +79,7 @@ const group21 = { number_users_with_delimiter: '1', has_subgroups: true, permissions: { - group_access: 50, + human_group_access: 'Master', }, }; -- cgit v1.2.3 From 1d1363e2bb8a0aee7e2849fd463ea415035710d9 Mon Sep 17 00:00:00 2001 From: DJ Mountney Date: Wed, 7 Jun 2017 20:32:38 -0700 Subject: Bring in security changes from the 9.2.5 release Ran: - git format-patch v9.2.2..v9.2.5 --stdout > patchfile.patch - git checkout -b 9-2-5-security-patch origin/v9.2.2 - git apply patchfile.patch - git commit - [Got the sha ref for the commit] - git checkout -b upstream-9-2-security master - git cherry-pick - [Resolved conflicts] - git cherry-pick --continue --- spec/controllers/autocomplete_controller_spec.rb | 30 ++- spec/factories/uploads.rb | 8 + spec/features/admin/admin_appearance_spec.rb | 4 +- .../uploads/user_uploads_avatar_to_group_spec.rb | 2 +- .../uploads/user_uploads_avatar_to_profile_spec.rb | 2 +- spec/helpers/application_helper_spec.rb | 13 +- spec/helpers/emails_helper_spec.rb | 2 +- spec/helpers/groups_helper_spec.rb | 2 +- spec/helpers/page_layout_helper_spec.rb | 2 +- spec/javascripts/notes_spec.js | 39 ++++ .../vue_shared/components/commit_spec.js | 4 +- .../banzai/reference_parser/base_parser_spec.rb | 2 +- .../banzai/reference_parser/snippet_parser_spec.rb | 189 +++++++++++++++- spec/lib/gitlab/uploads_transfer_spec.rb | 11 + spec/migrations/clean_upload_symlinks_spec.rb | 46 ++++ spec/migrations/move_uploads_to_system_dir_spec.rb | 68 ++++++ spec/migrations/rename_system_namespaces_spec.rb | 252 +++++++++++++++++++++ .../update_upload_paths_to_system_spec.rb | 53 +++++ spec/models/group_spec.rb | 2 +- spec/models/namespace_spec.rb | 10 +- spec/models/project_spec.rb | 2 +- spec/models/user_spec.rb | 2 +- spec/policies/project_snippet_policy_spec.rb | 4 +- spec/requests/openid_connect_spec.rb | 2 +- .../services/projects/participants_service_spec.rb | 4 +- spec/uploaders/attachment_uploader_spec.rb | 11 + spec/uploaders/avatar_uploader_spec.rb | 11 + spec/uploaders/file_uploader_spec.rb | 10 + 28 files changed, 746 insertions(+), 41 deletions(-) create mode 100644 spec/factories/uploads.rb create mode 100644 spec/lib/gitlab/uploads_transfer_spec.rb create mode 100644 spec/migrations/clean_upload_symlinks_spec.rb create mode 100644 spec/migrations/move_uploads_to_system_dir_spec.rb create mode 100644 spec/migrations/rename_system_namespaces_spec.rb create mode 100644 spec/migrations/update_upload_paths_to_system_spec.rb (limited to 'spec') diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb index 2c9d1ffc9c2..4c3a5ec49ef 100644 --- a/spec/controllers/autocomplete_controller_spec.rb +++ b/spec/controllers/autocomplete_controller_spec.rb @@ -170,22 +170,32 @@ describe AutocompleteController do end context 'author of issuable included' do - before do - sign_in(user) - end - let(:body) { JSON.parse(response.body) } - it 'includes the author' do - get(:users, author_id: non_member.id) + context 'authenticated' do + before do + sign_in(user) + end + + it 'includes the author' do + get(:users, author_id: non_member.id) + + expect(body.first["username"]).to eq non_member.username + end + + it 'rejects non existent user ids' do + get(:users, author_id: 99999) - expect(body.first["username"]).to eq non_member.username + expect(body.collect { |u| u['id'] }).not_to include(99999) + end end - it 'rejects non existent user ids' do - get(:users, author_id: 99999) + context 'without authenticating' do + it 'returns empty result' do + get(:users, author_id: non_member.id) - expect(body.collect { |u| u['id'] }).not_to include(99999) + expect(body).to be_empty + end end end diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb new file mode 100644 index 00000000000..1383420fb44 --- /dev/null +++ b/spec/factories/uploads.rb @@ -0,0 +1,8 @@ +FactoryGirl.define do + factory :upload do + model { build(:project) } + path { "uploads/system/project/avatar/avatar.jpg" } + size 100.kilobytes + uploader "AvatarUploader" + end +end diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index 96d715ef383..595366ce352 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -63,11 +63,11 @@ feature 'Admin Appearance', feature: true do end def logo_selector - '//img[@src^="/uploads/appearance/logo"]' + '//img[@src^="/uploads/system/appearance/logo"]' end def header_logo_selector - '//img[@src^="/uploads/appearance/header_logo"]' + '//img[@src^="/uploads/system/appearance/header_logo"]' end def logo_fixture diff --git a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb index f88a515f7fc..d9d6f2e2382 100644 --- a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb @@ -18,7 +18,7 @@ feature 'User uploads avatar to group', feature: true do visit group_path(group) - expect(page).to have_selector(%Q(img[src$="/uploads/group/avatar/#{group.id}/dk.png"])) + expect(page).to have_selector(%Q(img[src$="/uploads/system/group/avatar/#{group.id}/dk.png"])) # Cheating here to verify something that isn't user-facing, but is important expect(group.reload.avatar.file).to exist diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb index 0dfd29045e5..eb8dbd76aab 100644 --- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb @@ -16,7 +16,7 @@ feature 'User uploads avatar to profile', feature: true do visit user_path(user) - expect(page).to have_selector(%Q(img[src$="/uploads/user/avatar/#{user.id}/dk.png"])) + expect(page).to have_selector(%Q(img[src$="/uploads/system/user/avatar/#{user.id}/dk.png"])) # Cheating here to verify something that isn't user-facing, but is important expect(user.reload.avatar.file).to exist diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 785fb724132..49df91b236f 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -1,3 +1,4 @@ +# coding: utf-8 require 'spec_helper' describe ApplicationHelper do @@ -58,13 +59,13 @@ describe ApplicationHelper do describe 'project_icon' do it 'returns an url for the avatar' do project = create(:empty_project, avatar: File.open(uploaded_image_temp_path)) - avatar_url = "/uploads/project/avatar/#{project.id}/banana_sample.gif" + avatar_url = "/uploads/system/project/avatar/#{project.id}/banana_sample.gif" expect(helper.project_icon(project.full_path).to_s). to eq "\"Banana" allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host) - avatar_url = "#{gitlab_host}/uploads/project/avatar/#{project.id}/banana_sample.gif" + avatar_url = "#{gitlab_host}/uploads/system/project/avatar/#{project.id}/banana_sample.gif" expect(helper.project_icon(project.full_path).to_s). to eq "\"Banana" @@ -84,12 +85,12 @@ describe ApplicationHelper do it 'returns an url for the avatar' do user = create(:user, avatar: File.open(uploaded_image_temp_path)) - avatar_url = "/uploads/user/avatar/#{user.id}/banana_sample.gif" + avatar_url = "/uploads/system/user/avatar/#{user.id}/banana_sample.gif" expect(helper.avatar_icon(user.email).to_s).to match(avatar_url) allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host) - avatar_url = "#{gitlab_host}/uploads/user/avatar/#{user.id}/banana_sample.gif" + avatar_url = "#{gitlab_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif" expect(helper.avatar_icon(user.email).to_s).to match(avatar_url) end @@ -102,7 +103,7 @@ describe ApplicationHelper do user = create(:user, avatar: File.open(uploaded_image_temp_path)) expect(helper.avatar_icon(user.email).to_s). - to match("/gitlab/uploads/user/avatar/#{user.id}/banana_sample.gif") + to match("/gitlab/uploads/system/user/avatar/#{user.id}/banana_sample.gif") end it 'calls gravatar_icon when no User exists with the given email' do @@ -116,7 +117,7 @@ describe ApplicationHelper do user = create(:user, avatar: File.open(uploaded_image_temp_path)) expect(helper.avatar_icon(user).to_s). - to match("/uploads/user/avatar/#{user.id}/banana_sample.gif") + to match("/uploads/system/user/avatar/#{user.id}/banana_sample.gif") end end end diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb index cd112dbb2fb..c68e4f56b05 100644 --- a/spec/helpers/emails_helper_spec.rb +++ b/spec/helpers/emails_helper_spec.rb @@ -52,7 +52,7 @@ describe EmailsHelper do ) expect(header_logo).to eq( - %{Dk} + %{Dk} ) end end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index c8b0d86425f..0337afa4452 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -9,7 +9,7 @@ describe GroupsHelper do group.avatar = fixture_file_upload(avatar_file_path) group.save! expect(group_icon(group.path).to_s). - to match("/uploads/group/avatar/#{group.id}/banana_sample.gif") + to match("/uploads/system/group/avatar/#{group.id}/banana_sample.gif") end it 'gives default avatar_icon when no avatar is present' do diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index 2cc0b40b2d0..dff2784f21f 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -60,7 +60,7 @@ describe PageLayoutHelper do %w(project user group).each do |type| context "with @#{type} assigned" do it "uses #{type.titlecase} avatar if available" do - object = double(avatar_url: 'http://example.com/uploads/avatar.png') + object = double(avatar_url: 'http://example.com/uploads/system/avatar.png') assign(type, object) expect(helper.page_image).to eq object.avatar_url diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 24335614e09..bfd8b8648a6 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -461,6 +461,45 @@ import '~/notes'; }); }); + describe('update comment with script tags', () => { + const sampleComment = ''; + const updatedComment = ''; + const note = { + id: 1234, + html: `
  • +
    ${sampleComment}
    +
  • `, + note: sampleComment, + valid: true + }; + let $form; + let $notesContainer; + + beforeEach(() => { + this.notes = new Notes('', []); + window.gon.current_username = 'root'; + window.gon.current_user_fullname = 'Administrator'; + $form = $('form.js-main-target-form'); + $notesContainer = $('ul.main-notes-list'); + $form.find('textarea.js-note-text').html(sampleComment); + }); + + it('should not render a script tag', () => { + const deferred = $.Deferred(); + spyOn($, 'ajax').and.returnValue(deferred.promise()); + $('.js-comment-button').click(); + + deferred.resolve(note); + const $noteEl = $notesContainer.find(`#note_${note.id}`); + $noteEl.find('.js-note-edit').click(); + $noteEl.find('textarea.js-note-text').html(updatedComment); + $noteEl.find('.js-comment-save-button').click(); + + const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`).find('.js-task-list-container'); + expect($updatedNoteEl.find('.note-text').text().trim()).toEqual(''); + }); + }); + describe('getFormData', () => { let $form; let sampleComment; diff --git a/spec/javascripts/vue_shared/components/commit_spec.js b/spec/javascripts/vue_shared/components/commit_spec.js index 050170a54e9..540245fe71e 100644 --- a/spec/javascripts/vue_shared/components/commit_spec.js +++ b/spec/javascripts/vue_shared/components/commit_spec.js @@ -22,7 +22,7 @@ describe('Commit component', () => { shortSha: 'b7836edd', title: 'Commit message', author: { - avatar_url: 'https://gitlab.com/uploads/user/avatar/300478/avatar.png', + avatar_url: 'https://gitlab.com/uploads/system/user/avatar/300478/avatar.png', web_url: 'https://gitlab.com/jschatz1', path: '/jschatz1', username: 'jschatz1', @@ -45,7 +45,7 @@ describe('Commit component', () => { shortSha: 'b7836edd', title: 'Commit message', author: { - avatar_url: 'https://gitlab.com/uploads/user/avatar/300478/avatar.png', + avatar_url: 'https://gitlab.com/uploads/system/user/avatar/300478/avatar.png', web_url: 'https://gitlab.com/jschatz1', path: '/jschatz1', username: 'jschatz1', diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb index d5746107ee1..f4f42bfc3ed 100644 --- a/spec/lib/banzai/reference_parser/base_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb @@ -30,7 +30,7 @@ describe Banzai::ReferenceParser::BaseParser, lib: true do it 'checks if user can read the resource' do link['data-project'] = project.id.to_s - expect(subject).to receive(:can_read_reference?).with(user, project) + expect(subject).to receive(:can_read_reference?).with(user, project, link) subject.nodes_visible_to_user(user, [link]) end diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb index d217a775802..620875ece20 100644 --- a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb @@ -4,20 +4,199 @@ describe Banzai::ReferenceParser::SnippetParser, lib: true do include ReferenceParserHelpers let(:project) { create(:empty_project, :public) } + let(:user) { create(:user) } - let(:snippet) { create(:snippet, project: project) } + let(:external_user) { create(:user, :external) } + let(:project_member) { create(:user) } + subject { described_class.new(project, user) } let(:link) { empty_html_link } + def visible_references(snippet_visibility, user = nil) + snippet = create(:project_snippet, snippet_visibility, project: project) + link['data-project'] = project.id.to_s + link['data-snippet'] = snippet.id.to_s + + subject.nodes_visible_to_user(user, [link]) + end + + before do + project.add_user(project_member, :developer) + end + describe '#nodes_visible_to_user' do - context 'when the link has a data-issue attribute' do - before { link['data-snippet'] = snippet.id.to_s } + context 'when a project is public and the snippets feature is enabled for everyone' do + before do + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::ENABLED) + end + + it 'creates a reference for guest for a public snippet' do + expect(visible_references(:public)).to eq([link]) + end + + it 'creates a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to eq([link]) + end + + it 'creates a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to eq([link]) + end + + it 'does not create a reference for an external user for an internal snippet' do + expect(visible_references(:internal, external_user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is public and the snippets feature is enabled for project team members' do + before do + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE) + end + + it 'creates a reference for a project member for a public snippet' do + expect(visible_references(:public, project_member)).to eq([link]) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public, nil)).to be_empty + end + + it 'does not create a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to be_empty + end + + it 'creates a reference for a project member for an internal snippet' do + expect(visible_references(:internal, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is internal and the snippets feature is enabled for everyone' do + before do + project.update_attribute(:visibility, Gitlab::VisibilityLevel::INTERNAL) + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::ENABLED) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public)).to be_empty + end + + it 'does not create a reference for an external user for a public snippet' do + expect(visible_references(:public, external_user)).to be_empty + end - it_behaves_like "referenced feature visibility", "snippets" + it 'creates a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to eq([link]) + end + + it 'creates a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to eq([link]) + end + + it 'does not create a reference for an external user for an internal snippet' do + expect(visible_references(:internal, external_user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is internal and the snippets feature is enabled for project team members' do + before do + project.update_attribute(:visibility, Gitlab::VisibilityLevel::INTERNAL) + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE) + end + + it 'creates a reference for a project member for a public snippet' do + expect(visible_references(:public, project_member)).to eq([link]) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public, nil)).to be_empty + end + + it 'does not create reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to be_empty + end + + it 'creates a reference for a project member for an internal snippet' do + expect(visible_references(:internal, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is private and the snippets feature is enabled for project team members' do + before do + project.update_attribute(:visibility, Gitlab::VisibilityLevel::PRIVATE) + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE) + end + + it 'creates a reference for a project member for a public snippet' do + expect(visible_references(:public, project_member)).to eq([link]) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public, nil)).to be_empty + end + + it 'does not create a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to be_empty + end + + it 'creates a reference for a project member for an internal snippet' do + expect(visible_references(:internal, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end end end describe '#referenced_by' do + let(:snippet) { create(:snippet, project: project) } describe 'when the link has a data-snippet attribute' do context 'using an existing snippet ID' do it 'returns an Array of snippets' do @@ -31,7 +210,7 @@ describe Banzai::ReferenceParser::SnippetParser, lib: true do it 'returns an empty Array' do link['data-snippet'] = '' - expect(subject.referenced_by([link])).to eq([]) + expect(subject.referenced_by([link])).to be_empty end end end diff --git a/spec/lib/gitlab/uploads_transfer_spec.rb b/spec/lib/gitlab/uploads_transfer_spec.rb new file mode 100644 index 00000000000..109559bb01c --- /dev/null +++ b/spec/lib/gitlab/uploads_transfer_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe Gitlab::UploadsTransfer do + it 'leaves avatar uploads where they are' do + project_with_avatar = create(:empty_project, :with_avatar) + + described_class.new.rename_namespace('project', 'project-renamed') + + expect(File.exist?(project_with_avatar.avatar.path)).to be_truthy + end +end diff --git a/spec/migrations/clean_upload_symlinks_spec.rb b/spec/migrations/clean_upload_symlinks_spec.rb new file mode 100644 index 00000000000..cecb3ddac53 --- /dev/null +++ b/spec/migrations/clean_upload_symlinks_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170406111121_clean_upload_symlinks.rb') + +describe CleanUploadSymlinks do + let(:migration) { described_class.new } + let(:test_dir) { File.join(Rails.root, "tmp", "tests", "move_uploads_test") } + let(:uploads_dir) { File.join(test_dir, "public", "uploads") } + let(:new_uploads_dir) { File.join(uploads_dir, "system") } + let(:original_path) { File.join(new_uploads_dir, 'user') } + let(:symlink_path) { File.join(uploads_dir, 'user') } + + before do + FileUtils.remove_dir(test_dir) if File.directory?(test_dir) + FileUtils.mkdir_p(uploads_dir) + allow(migration).to receive(:base_directory).and_return(test_dir) + allow(migration).to receive(:say) + end + + describe "#up" do + before do + FileUtils.mkdir_p(original_path) + FileUtils.ln_s(original_path, symlink_path) + end + + it 'removes the symlink' do + migration.up + + expect(File.symlink?(symlink_path)).to be(false) + end + end + + describe '#down' do + before do + FileUtils.mkdir_p(File.join(original_path)) + FileUtils.touch(File.join(original_path, 'dummy.file')) + end + + it 'creates a symlink' do + expected_path = File.join(symlink_path, "dummy.file") + migration.down + + expect(File.exist?(expected_path)).to be(true) + expect(File.symlink?(symlink_path)).to be(true) + end + end +end diff --git a/spec/migrations/move_uploads_to_system_dir_spec.rb b/spec/migrations/move_uploads_to_system_dir_spec.rb new file mode 100644 index 00000000000..37d66452447 --- /dev/null +++ b/spec/migrations/move_uploads_to_system_dir_spec.rb @@ -0,0 +1,68 @@ +require "spec_helper" +require Rails.root.join("db", "migrate", "20170316163845_move_uploads_to_system_dir.rb") + +describe MoveUploadsToSystemDir do + let(:migration) { described_class.new } + let(:test_dir) { File.join(Rails.root, "tmp", "move_uploads_test") } + let(:uploads_dir) { File.join(test_dir, "public", "uploads") } + let(:new_uploads_dir) { File.join(uploads_dir, "system") } + + before do + FileUtils.remove_dir(test_dir) if File.directory?(test_dir) + FileUtils.mkdir_p(uploads_dir) + allow(migration).to receive(:base_directory).and_return(test_dir) + allow(migration).to receive(:say) + end + + describe "#up" do + before do + FileUtils.mkdir_p(File.join(uploads_dir, 'user')) + FileUtils.touch(File.join(uploads_dir, 'user', 'dummy.file')) + end + + it 'moves the directory to the new path' do + expected_path = File.join(new_uploads_dir, 'user', 'dummy.file') + + migration.up + + expect(File.exist?(expected_path)).to be(true) + end + + it 'creates a symlink in the old location' do + symlink_path = File.join(uploads_dir, 'user') + expected_path = File.join(symlink_path, 'dummy.file') + + migration.up + + expect(File.exist?(expected_path)).to be(true) + expect(File.symlink?(symlink_path)).to be(true) + end + end + + describe "#down" do + before do + FileUtils.mkdir_p(File.join(new_uploads_dir, 'user')) + FileUtils.touch(File.join(new_uploads_dir, 'user', 'dummy.file')) + end + + it 'moves the directory to the old path' do + expected_path = File.join(uploads_dir, 'user', 'dummy.file') + + migration.down + + expect(File.exist?(expected_path)).to be(true) + end + + it 'removes the symlink if it existed' do + FileUtils.ln_s(File.join(new_uploads_dir, 'user'), File.join(uploads_dir, 'user')) + + directory = File.join(uploads_dir, 'user') + expected_path = File.join(directory, 'dummy.file') + + migration.down + + expect(File.exist?(expected_path)).to be(true) + expect(File.symlink?(directory)).to be(false) + end + end +end diff --git a/spec/migrations/rename_system_namespaces_spec.rb b/spec/migrations/rename_system_namespaces_spec.rb new file mode 100644 index 00000000000..ad1b83d8e2e --- /dev/null +++ b/spec/migrations/rename_system_namespaces_spec.rb @@ -0,0 +1,252 @@ +require "spec_helper" +require Rails.root.join("db", "migrate", "20170316163800_rename_system_namespaces.rb") + +describe RenameSystemNamespaces, truncate: true do + let(:migration) { described_class.new } + let(:test_dir) { File.join(Rails.root, "tmp", "tests", "rename_namespaces_test") } + let(:uploads_dir) { File.join(test_dir, "public", "uploads") } + let(:system_namespace) do + namespace = build(:namespace, path: "system") + namespace.save(validate: false) + namespace + end + + def save_invalid_routable(routable) + routable.__send__(:prepare_route) + routable.save(validate: false) + end + + before do + FileUtils.remove_dir(test_dir) if File.directory?(test_dir) + FileUtils.mkdir_p(uploads_dir) + FileUtils.remove_dir(TestEnv.repos_path) if File.directory?(TestEnv.repos_path) + allow(migration).to receive(:say) + allow(migration).to receive(:uploads_dir).and_return(uploads_dir) + end + + describe "#system_namespace" do + it "only root namespaces called with path `system`" do + system_namespace + system_namespace_with_parent = build(:namespace, path: 'system', parent: create(:namespace)) + system_namespace_with_parent.save(validate: false) + + expect(migration.system_namespace.id).to eq(system_namespace.id) + end + end + + describe "#up" do + before do + system_namespace + end + + it "doesn't break if there are no namespaces called system" do + Namespace.delete_all + + migration.up + end + + it "renames namespaces called system" do + migration.up + + expect(system_namespace.reload.path).to eq("system0") + end + + it "renames the route to the namespace" do + migration.up + + expect(system_namespace.reload.full_path).to eq("system0") + end + + it "renames the route for projects of the namespace" do + project = build(:project, path: "project-path", namespace: system_namespace) + save_invalid_routable(project) + + migration.up + + expect(project.route.reload.path).to eq("system0/project-path") + end + + it "doesn't touch routes of namespaces that look like system" do + namespace = create(:group, path: 'systemlookalike') + project = create(:project, namespace: namespace, path: 'the-project') + + migration.up + + expect(project.route.reload.path).to eq('systemlookalike/the-project') + expect(namespace.route.reload.path).to eq('systemlookalike') + end + + it "moves the the repository for a project in the namespace" do + project = build(:project, namespace: system_namespace, path: "system-project") + save_invalid_routable(project) + TestEnv.copy_repo(project) + expected_repo = File.join(TestEnv.repos_path, "system0", "system-project.git") + + migration.up + + expect(File.directory?(expected_repo)).to be(true) + end + + it "moves the uploads for the namespace" do + allow(migration).to receive(:move_namespace_folders).with(Settings.pages.path, "system", "system0") + expect(migration).to receive(:move_namespace_folders).with(uploads_dir, "system", "system0") + + migration.up + end + + it "moves the pages for the namespace" do + allow(migration).to receive(:move_namespace_folders).with(uploads_dir, "system", "system0") + expect(migration).to receive(:move_namespace_folders).with(Settings.pages.path, "system", "system0") + + migration.up + end + + describe "clears the markdown cache for projects in the system namespace" do + let!(:project) do + project = build(:project, namespace: system_namespace) + save_invalid_routable(project) + project + end + + it 'removes description_html from projects' do + migration.up + + expect(project.reload.description_html).to be_nil + end + + it 'removes issue descriptions' do + issue = create(:issue, project: project, description_html: 'Issue description') + + migration.up + + expect(issue.reload.description_html).to be_nil + end + + it 'removes merge request descriptions' do + merge_request = create(:merge_request, + source_project: project, + target_project: project, + description_html: 'MergeRequest description') + + migration.up + + expect(merge_request.reload.description_html).to be_nil + end + + it 'removes note html' do + note = create(:note, + project: project, + noteable: create(:issue, project: project), + note_html: 'note description') + + migration.up + + expect(note.reload.note_html).to be_nil + end + + it 'removes milestone description' do + milestone = create(:milestone, + project: project, + description_html: 'milestone description') + + migration.up + + expect(milestone.reload.description_html).to be_nil + end + end + + context "system namespace -> subgroup -> system0 project" do + it "updates the route of the project correctly" do + subgroup = build(:group, path: "subgroup", parent: system_namespace) + save_invalid_routable(subgroup) + project = build(:project, path: "system0", namespace: subgroup) + save_invalid_routable(project) + + migration.up + + expect(project.route.reload.path).to eq("system0/subgroup/system0") + end + end + end + + describe "#move_repositories" do + let(:namespace) { create(:group, name: "hello-group") } + it "moves a project for a namespace" do + create(:project, namespace: namespace, path: "hello-project") + expected_path = File.join(TestEnv.repos_path, "bye-group", "hello-project.git") + + migration.move_repositories(namespace, "hello-group", "bye-group") + + expect(File.directory?(expected_path)).to be(true) + end + + it "moves a namespace in a subdirectory correctly" do + child_namespace = create(:group, name: "sub-group", parent: namespace) + create(:project, namespace: child_namespace, path: "hello-project") + + expected_path = File.join(TestEnv.repos_path, "hello-group", "renamed-sub-group", "hello-project.git") + + migration.move_repositories(child_namespace, "hello-group/sub-group", "hello-group/renamed-sub-group") + + expect(File.directory?(expected_path)).to be(true) + end + + it "moves a parent namespace with subdirectories" do + child_namespace = create(:group, name: "sub-group", parent: namespace) + create(:project, namespace: child_namespace, path: "hello-project") + expected_path = File.join(TestEnv.repos_path, "renamed-group", "sub-group", "hello-project.git") + + migration.move_repositories(child_namespace, "hello-group", "renamed-group") + + expect(File.directory?(expected_path)).to be(true) + end + end + + describe "#move_namespace_folders" do + it "moves a namespace with files" do + source = File.join(uploads_dir, "parent-group", "sub-group") + FileUtils.mkdir_p(source) + destination = File.join(uploads_dir, "parent-group", "moved-group") + FileUtils.touch(File.join(source, "test.txt")) + expected_file = File.join(destination, "test.txt") + + migration.move_namespace_folders(uploads_dir, File.join("parent-group", "sub-group"), File.join("parent-group", "moved-group")) + + expect(File.exist?(expected_file)).to be(true) + end + + it "moves a parent namespace uploads" do + source = File.join(uploads_dir, "parent-group", "sub-group") + FileUtils.mkdir_p(source) + destination = File.join(uploads_dir, "moved-parent", "sub-group") + FileUtils.touch(File.join(source, "test.txt")) + expected_file = File.join(destination, "test.txt") + + migration.move_namespace_folders(uploads_dir, "parent-group", "moved-parent") + + expect(File.exist?(expected_file)).to be(true) + end + end + + describe "#child_ids_for_parent" do + it "collects child ids for all levels" do + parent = create(:namespace) + first_child = create(:namespace, parent: parent) + second_child = create(:namespace, parent: parent) + third_child = create(:namespace, parent: second_child) + all_ids = [parent.id, first_child.id, second_child.id, third_child.id] + + collected_ids = migration.child_ids_for_parent(parent, ids: [parent.id]) + + expect(collected_ids).to contain_exactly(*all_ids) + end + end + + describe "#remove_last_ocurrence" do + it "removes only the last occurance of a string" do + input = "this/is/system/namespace/with/system" + + expect(migration.remove_last_occurrence(input, "system")).to eq("this/is/system/namespace/with/") + end + end +end diff --git a/spec/migrations/update_upload_paths_to_system_spec.rb b/spec/migrations/update_upload_paths_to_system_spec.rb new file mode 100644 index 00000000000..7df44515424 --- /dev/null +++ b/spec/migrations/update_upload_paths_to_system_spec.rb @@ -0,0 +1,53 @@ +require "spec_helper" +require Rails.root.join("db", "post_migrate", "20170317162059_update_upload_paths_to_system.rb") + +describe UpdateUploadPathsToSystem do + let(:migration) { described_class.new } + + before do + allow(migration).to receive(:say) + end + + describe "#uploads_to_switch_to_new_path" do + it "contains only uploads with the old path for the correct models" do + _upload_for_other_type = create(:upload, model: create(:ci_pipeline), path: "uploads/ci_pipeline/avatar.jpg") + _upload_with_system_path = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg") + _upload_with_other_path = create(:upload, model: create(:empty_project), path: "thelongsecretforafileupload/avatar.jpg") + old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg") + group_upload = create(:upload, model: create(:group), path: "uploads/group/avatar.jpg") + + expect(Upload.where(migration.uploads_to_switch_to_new_path)).to contain_exactly(old_upload, group_upload) + end + end + + describe "#uploads_to_switch_to_old_path" do + it "contains only uploads with the new path for the correct models" do + _upload_for_other_type = create(:upload, model: create(:ci_pipeline), path: "uploads/ci_pipeline/avatar.jpg") + upload_with_system_path = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg") + _upload_with_other_path = create(:upload, model: create(:empty_project), path: "thelongsecretforafileupload/avatar.jpg") + _old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg") + + expect(Upload.where(migration.uploads_to_switch_to_old_path)).to contain_exactly(upload_with_system_path) + end + end + + describe "#up", truncate: true do + it "updates old upload records to the new path" do + old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg") + + migration.up + + expect(old_upload.reload.path).to eq("uploads/system/project/avatar.jpg") + end + end + + describe "#down", truncate: true do + it "updates the new system patsh to the old paths" do + new_upload = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg") + + migration.down + + expect(new_upload.reload.path).to eq("uploads/project/avatar.jpg") + end + end +end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 316bf153660..3d437ca0fcc 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -179,7 +179,7 @@ describe Group, models: true do let!(:group) { create(:group, :access_requestable, :with_avatar) } let(:user) { create(:user) } let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } - let(:avatar_path) { "/uploads/group/avatar/#{group.id}/dk.png" } + let(:avatar_path) { "/uploads/system/group/avatar/#{group.id}/dk.png" } context 'when avatar file is uploaded' do before { group.add_master(user) } diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 0e74f1ab1bd..145c7ad5770 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -43,6 +43,12 @@ describe Namespace, models: true do end end + context "is case insensitive" do + let(:group) { build(:group, path: "System") } + + it { expect(group).not_to be_valid } + end + context 'top-level group' do let(:group) { build(:group, path: 'tree') } @@ -178,8 +184,8 @@ describe Namespace, models: true do let(:parent) { create(:group, name: 'parent', path: 'parent') } let(:child) { create(:group, name: 'child', path: 'child', parent: parent) } let!(:project) { create(:project_empty_repo, path: 'the-project', namespace: child) } - let(:uploads_dir) { File.join(CarrierWave.root, 'uploads') } - let(:pages_dir) { TestEnv.pages_path } + let(:uploads_dir) { File.join(CarrierWave.root, FileUploader.base_dir) } + let(:pages_dir) { File.join(TestEnv.pages_path) } before do FileUtils.mkdir_p(File.join(uploads_dir, 'parent', 'child', 'the-project')) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 3ed52d42f86..454eeb58ecd 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -812,7 +812,7 @@ describe Project, models: true do context 'when avatar file is uploaded' do let(:project) { create(:empty_project, :with_avatar) } - let(:avatar_path) { "/uploads/project/avatar/#{project.id}/dk.png" } + let(:avatar_path) { "/uploads/system/project/avatar/#{project.id}/dk.png" } let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } it 'shows correct url' do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index a83726b48a0..d5bd9946ab6 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -987,7 +987,7 @@ describe User, models: true do context 'when avatar file is uploaded' do let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } - let(:avatar_path) { "/uploads/user/avatar/#{user.id}/dk.png" } + let(:avatar_path) { "/uploads/system/user/avatar/#{user.id}/dk.png" } it 'shows correct avatar url' do expect(user.avatar_url).to eq(avatar_path) diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb index e1771b636b8..ddbed5f781e 100644 --- a/spec/policies/project_snippet_policy_spec.rb +++ b/spec/policies/project_snippet_policy_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe ProjectSnippetPolicy, models: true do let(:regular_user) { create(:user) } let(:external_user) { create(:user, :external) } - let(:project) { create(:empty_project) } + let(:project) { create(:empty_project, :public) } let(:author_permissions) do [ @@ -107,7 +107,7 @@ describe ProjectSnippetPolicy, models: true do end context 'snippet author' do - let(:snippet) { create(:project_snippet, :private, author: regular_user) } + let(:snippet) { create(:project_snippet, :private, author: regular_user, project: project) } subject { described_class.abilities(regular_user, snippet).to_set } diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb index 05176c3beaa..6d1f0b24196 100644 --- a/spec/requests/openid_connect_spec.rb +++ b/spec/requests/openid_connect_spec.rb @@ -79,7 +79,7 @@ describe 'OpenID Connect requests' do 'email_verified' => true, 'website' => 'https://example.com', 'profile' => 'http://localhost/alice', - 'picture' => "http://localhost/uploads/user/avatar/#{user.id}/dk.png" + 'picture' => "http://localhost/uploads/system/user/avatar/#{user.id}/dk.png" }) end end diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb index 0657b7e93fe..d75851134ee 100644 --- a/spec/services/projects/participants_service_spec.rb +++ b/spec/services/projects/participants_service_spec.rb @@ -13,7 +13,7 @@ describe Projects::ParticipantsService, services: true do groups = participants.groups expect(groups.size).to eq 1 - expect(groups.first[:avatar_url]).to eq("/uploads/group/avatar/#{group.id}/dk.png") + expect(groups.first[:avatar_url]).to eq("/uploads/system/group/avatar/#{group.id}/dk.png") end it 'should return an url for the avatar with relative url' do @@ -24,7 +24,7 @@ describe Projects::ParticipantsService, services: true do groups = participants.groups expect(groups.size).to eq 1 - expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/group/avatar/#{group.id}/dk.png") + expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/system/group/avatar/#{group.id}/dk.png") end end end diff --git a/spec/uploaders/attachment_uploader_spec.rb b/spec/uploaders/attachment_uploader_spec.rb index ea714fb08f0..d82dbe871d5 100644 --- a/spec/uploaders/attachment_uploader_spec.rb +++ b/spec/uploaders/attachment_uploader_spec.rb @@ -3,6 +3,17 @@ require 'spec_helper' describe AttachmentUploader do let(:uploader) { described_class.new(build_stubbed(:user)) } + describe "#store_dir" do + it "stores in the system dir" do + expect(uploader.store_dir).to start_with("uploads/system/user") + end + + it "uses the old path when using object storage" do + expect(described_class).to receive(:file_storage?).and_return(false) + expect(uploader.store_dir).to start_with("uploads/user") + end + end + describe '#move_to_cache' do it 'is true' do expect(uploader.move_to_cache).to eq(true) diff --git a/spec/uploaders/avatar_uploader_spec.rb b/spec/uploaders/avatar_uploader_spec.rb index c4d558805ab..201fe6949aa 100644 --- a/spec/uploaders/avatar_uploader_spec.rb +++ b/spec/uploaders/avatar_uploader_spec.rb @@ -3,6 +3,17 @@ require 'spec_helper' describe AvatarUploader do let(:uploader) { described_class.new(build_stubbed(:user)) } + describe "#store_dir" do + it "stores in the system dir" do + expect(uploader.store_dir).to start_with("uploads/system/user") + end + + it "uses the old path when using object storage" do + expect(described_class).to receive(:file_storage?).and_return(false) + expect(uploader.store_dir).to start_with("uploads/user") + end + end + describe '#move_to_cache' do it 'is false' do expect(uploader.move_to_cache).to eq(false) diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb index d9113ef4095..47e9365e13d 100644 --- a/spec/uploaders/file_uploader_spec.rb +++ b/spec/uploaders/file_uploader_spec.rb @@ -15,6 +15,16 @@ describe FileUploader do end end + describe "#store_dir" do + it "stores in the namespace path" do + project = build_stubbed(:empty_project) + uploader = described_class.new(project) + + expect(uploader.store_dir).to include(project.path_with_namespace) + expect(uploader.store_dir).not_to include("system") + end + end + describe 'initialize' do it 'generates a secret if none is provided' do expect(SecureRandom).to receive(:hex).and_return('secret') -- cgit v1.2.3 From ff1bc1778d7fe40ac96d8515dc04195d56aced07 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Thu, 8 Jun 2017 09:58:38 +0200 Subject: Add test for prom metric gathering --- spec/services/ci/create_pipeline_service_spec.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'spec') diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index e9c2b865b47..77c07b71c68 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -38,6 +38,14 @@ describe Ci::CreatePipelineService, :services do expect(pipeline.builds.first).to be_kind_of(Ci::Build) end + it 'increments the prometheus counter' do + expect(Gitlab::Metrics).to receive(:counter) + .with(:pipelines_created_count, "Pipelines created count") + .and_call_original + + pipeline + end + context 'when merge requests already exist for this source branch' do it 'updates head pipeline of each merge request' do merge_request_1 = create(:merge_request, source_branch: 'master', target_branch: "branch_1", source_project: project) -- cgit v1.2.3 From c24b70682448f23d7eb01853026cfe6abdf86190 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 8 Jun 2017 03:45:18 -0500 Subject: Add tests when user has no direct acces to a group --- spec/javascripts/groups/group_item_spec.js | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/groups/group_item_spec.js b/spec/javascripts/groups/group_item_spec.js index 73ea86e6756..25e10552d95 100644 --- a/spec/javascripts/groups/group_item_spec.js +++ b/spec/javascripts/groups/group_item_spec.js @@ -63,9 +63,40 @@ describe('Groups Component', () => { }); }); + afterEach(() => { + component.$destroy(); + }); + it('should render group item correctly', () => { expect(component.$el.querySelector('.description').textContent).toBe(''); expect(component.$el.classList.contains('.no-description')).toBe(false); }); }); + + describe('user has not access to group', () => { + beforeEach((done) => { + GroupItemComponent = Vue.extend(groupItemComponent); + store = new GroupsStore(); + group1.permissions.human_group_access = null; + group = store.decorateGroup(group1); + + component = new GroupItemComponent({ + propsData: { + group, + }, + }).$mount(); + + Vue.nextTick(() => { + done(); + }); + }); + + afterEach(() => { + component.$destroy(); + }); + + it('should not display access type', () => { + expect(component.$el.querySelector('.access-type')).toBeNull(); + }); + }); }); -- cgit v1.2.3 From 737d194c0826beb7783c34e982cea673e3f6a61a Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 8 Jun 2017 11:44:33 +0100 Subject: Allow group reporters to promote labels They can admin group labels anyway, we weren't checking the more specific permission. --- spec/controllers/projects/labels_controller_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb index 130b0b744b5..bf1776eb320 100644 --- a/spec/controllers/projects/labels_controller_spec.rb +++ b/spec/controllers/projects/labels_controller_spec.rb @@ -117,7 +117,7 @@ describe Projects::LabelsController do let!(:promoted_label_name) { "Promoted Label" } let!(:label_1) { create(:label, title: promoted_label_name, project: project) } - context 'not group owner' do + context 'not group reporters' do it 'denies access' do post :promote, namespace_id: project.namespace.to_param, project_id: project, id: label_1.to_param @@ -125,9 +125,9 @@ describe Projects::LabelsController do end end - context 'group owner' do + context 'group reporter' do before do - GroupMember.add_users(group, [user], :owner) + group.add_reporter(user) end it 'gives access' do -- cgit v1.2.3 From b4c6dc1d813e179f87678116ed7625311af78c4d Mon Sep 17 00:00:00 2001 From: tauriedavis Date: Tue, 6 Jun 2017 14:31:47 -0700 Subject: fixes project_group_links spec by adding click tab event --- spec/features/projects/group_links_spec.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/projects/group_links_spec.rb b/spec/features/projects/group_links_spec.rb index 4e5682c8636..1a27ca3002a 100644 --- a/spec/features/projects/group_links_spec.rb +++ b/spec/features/projects/group_links_spec.rb @@ -16,6 +16,8 @@ feature 'Project group links', :feature, :js do before do visit namespace_project_settings_members_path(project.namespace, project) + click_on 'share-with-group-tab' + select2 group.id, from: '#link_group_id' fill_in 'expires_at_groups', with: (Time.current + 4.5.days).strftime('%Y-%m-%d') page.find('body').click @@ -23,7 +25,7 @@ feature 'Project group links', :feature, :js do end it 'shows the expiration time with a warning class' do - page.within('.enabled-groups') do + page.within('.project-members-groups') do expect(page).to have_content('expires in 4 days') expect(page).to have_selector('.text-warning') end @@ -43,6 +45,7 @@ feature 'Project group links', :feature, :js do it 'does not show ancestors', :nested_groups do visit namespace_project_settings_members_path(project.namespace, project) + click_on 'share-with-group-tab' click_link 'Search for a group' page.within '.select2-drop' do -- cgit v1.2.3 From 59b0f3e5d487cdced3ea92d93d531bded44b1753 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Thu, 8 Jun 2017 09:15:14 -0500 Subject: Fix specs --- spec/features/projects/group_links_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/group_links_spec.rb b/spec/features/projects/group_links_spec.rb index 1a27ca3002a..1b680a56492 100644 --- a/spec/features/projects/group_links_spec.rb +++ b/spec/features/projects/group_links_spec.rb @@ -21,12 +21,12 @@ feature 'Project group links', :feature, :js do select2 group.id, from: '#link_group_id' fill_in 'expires_at_groups', with: (Time.current + 4.5.days).strftime('%Y-%m-%d') page.find('body').click - click_on 'Share' + find('.btn-create').trigger('click') end it 'shows the expiration time with a warning class' do page.within('.project-members-groups') do - expect(page).to have_content('expires in 4 days') + expect(page).to have_content('Expires in 4 days') expect(page).to have_selector('.text-warning') end end -- cgit v1.2.3 From 565ead610215d32fc6fe57a78f595fad51588e49 Mon Sep 17 00:00:00 2001 From: DJ Mountney Date: Wed, 7 Jun 2017 20:32:38 -0700 Subject: Bring in security changes from the 9.2.5 release Ran: - git format-patch v9.2.2..v9.2.5 --stdout > patchfile.patch - git checkout -b 9-2-5-security-patch origin/v9.2.2 - git apply patchfile.patch - git commit - [Got the sha ref for the commit] - git checkout -b upstream-9-2-security master - git cherry-pick - [Resolved conflicts] - git cherry-pick --continue --- spec/controllers/autocomplete_controller_spec.rb | 30 ++- spec/factories/uploads.rb | 8 + spec/features/admin/admin_appearance_spec.rb | 4 +- .../uploads/user_uploads_avatar_to_group_spec.rb | 2 +- .../uploads/user_uploads_avatar_to_profile_spec.rb | 2 +- spec/helpers/application_helper_spec.rb | 13 +- spec/helpers/emails_helper_spec.rb | 2 +- spec/helpers/groups_helper_spec.rb | 2 +- spec/helpers/page_layout_helper_spec.rb | 2 +- spec/javascripts/notes_spec.js | 39 ++++ .../vue_shared/components/commit_spec.js | 4 +- .../banzai/reference_parser/base_parser_spec.rb | 2 +- .../banzai/reference_parser/snippet_parser_spec.rb | 189 +++++++++++++++- spec/lib/gitlab/uploads_transfer_spec.rb | 11 + spec/migrations/clean_upload_symlinks_spec.rb | 46 ++++ spec/migrations/move_uploads_to_system_dir_spec.rb | 68 ++++++ spec/migrations/rename_system_namespaces_spec.rb | 252 +++++++++++++++++++++ .../update_upload_paths_to_system_spec.rb | 53 +++++ spec/models/group_spec.rb | 2 +- spec/models/namespace_spec.rb | 10 +- spec/models/project_spec.rb | 2 +- spec/models/user_spec.rb | 2 +- spec/policies/project_snippet_policy_spec.rb | 4 +- spec/requests/openid_connect_spec.rb | 2 +- .../services/projects/participants_service_spec.rb | 4 +- spec/uploaders/attachment_uploader_spec.rb | 11 + spec/uploaders/avatar_uploader_spec.rb | 11 + spec/uploaders/file_uploader_spec.rb | 10 + 28 files changed, 746 insertions(+), 41 deletions(-) create mode 100644 spec/factories/uploads.rb create mode 100644 spec/lib/gitlab/uploads_transfer_spec.rb create mode 100644 spec/migrations/clean_upload_symlinks_spec.rb create mode 100644 spec/migrations/move_uploads_to_system_dir_spec.rb create mode 100644 spec/migrations/rename_system_namespaces_spec.rb create mode 100644 spec/migrations/update_upload_paths_to_system_spec.rb (limited to 'spec') diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb index 2c9d1ffc9c2..4c3a5ec49ef 100644 --- a/spec/controllers/autocomplete_controller_spec.rb +++ b/spec/controllers/autocomplete_controller_spec.rb @@ -170,22 +170,32 @@ describe AutocompleteController do end context 'author of issuable included' do - before do - sign_in(user) - end - let(:body) { JSON.parse(response.body) } - it 'includes the author' do - get(:users, author_id: non_member.id) + context 'authenticated' do + before do + sign_in(user) + end + + it 'includes the author' do + get(:users, author_id: non_member.id) + + expect(body.first["username"]).to eq non_member.username + end + + it 'rejects non existent user ids' do + get(:users, author_id: 99999) - expect(body.first["username"]).to eq non_member.username + expect(body.collect { |u| u['id'] }).not_to include(99999) + end end - it 'rejects non existent user ids' do - get(:users, author_id: 99999) + context 'without authenticating' do + it 'returns empty result' do + get(:users, author_id: non_member.id) - expect(body.collect { |u| u['id'] }).not_to include(99999) + expect(body).to be_empty + end end end diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb new file mode 100644 index 00000000000..1383420fb44 --- /dev/null +++ b/spec/factories/uploads.rb @@ -0,0 +1,8 @@ +FactoryGirl.define do + factory :upload do + model { build(:project) } + path { "uploads/system/project/avatar/avatar.jpg" } + size 100.kilobytes + uploader "AvatarUploader" + end +end diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index 96d715ef383..595366ce352 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -63,11 +63,11 @@ feature 'Admin Appearance', feature: true do end def logo_selector - '//img[@src^="/uploads/appearance/logo"]' + '//img[@src^="/uploads/system/appearance/logo"]' end def header_logo_selector - '//img[@src^="/uploads/appearance/header_logo"]' + '//img[@src^="/uploads/system/appearance/header_logo"]' end def logo_fixture diff --git a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb index f88a515f7fc..d9d6f2e2382 100644 --- a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb @@ -18,7 +18,7 @@ feature 'User uploads avatar to group', feature: true do visit group_path(group) - expect(page).to have_selector(%Q(img[src$="/uploads/group/avatar/#{group.id}/dk.png"])) + expect(page).to have_selector(%Q(img[src$="/uploads/system/group/avatar/#{group.id}/dk.png"])) # Cheating here to verify something that isn't user-facing, but is important expect(group.reload.avatar.file).to exist diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb index 0dfd29045e5..eb8dbd76aab 100644 --- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb @@ -16,7 +16,7 @@ feature 'User uploads avatar to profile', feature: true do visit user_path(user) - expect(page).to have_selector(%Q(img[src$="/uploads/user/avatar/#{user.id}/dk.png"])) + expect(page).to have_selector(%Q(img[src$="/uploads/system/user/avatar/#{user.id}/dk.png"])) # Cheating here to verify something that isn't user-facing, but is important expect(user.reload.avatar.file).to exist diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 785fb724132..49df91b236f 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -1,3 +1,4 @@ +# coding: utf-8 require 'spec_helper' describe ApplicationHelper do @@ -58,13 +59,13 @@ describe ApplicationHelper do describe 'project_icon' do it 'returns an url for the avatar' do project = create(:empty_project, avatar: File.open(uploaded_image_temp_path)) - avatar_url = "/uploads/project/avatar/#{project.id}/banana_sample.gif" + avatar_url = "/uploads/system/project/avatar/#{project.id}/banana_sample.gif" expect(helper.project_icon(project.full_path).to_s). to eq "\"Banana" allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host) - avatar_url = "#{gitlab_host}/uploads/project/avatar/#{project.id}/banana_sample.gif" + avatar_url = "#{gitlab_host}/uploads/system/project/avatar/#{project.id}/banana_sample.gif" expect(helper.project_icon(project.full_path).to_s). to eq "\"Banana" @@ -84,12 +85,12 @@ describe ApplicationHelper do it 'returns an url for the avatar' do user = create(:user, avatar: File.open(uploaded_image_temp_path)) - avatar_url = "/uploads/user/avatar/#{user.id}/banana_sample.gif" + avatar_url = "/uploads/system/user/avatar/#{user.id}/banana_sample.gif" expect(helper.avatar_icon(user.email).to_s).to match(avatar_url) allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host) - avatar_url = "#{gitlab_host}/uploads/user/avatar/#{user.id}/banana_sample.gif" + avatar_url = "#{gitlab_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif" expect(helper.avatar_icon(user.email).to_s).to match(avatar_url) end @@ -102,7 +103,7 @@ describe ApplicationHelper do user = create(:user, avatar: File.open(uploaded_image_temp_path)) expect(helper.avatar_icon(user.email).to_s). - to match("/gitlab/uploads/user/avatar/#{user.id}/banana_sample.gif") + to match("/gitlab/uploads/system/user/avatar/#{user.id}/banana_sample.gif") end it 'calls gravatar_icon when no User exists with the given email' do @@ -116,7 +117,7 @@ describe ApplicationHelper do user = create(:user, avatar: File.open(uploaded_image_temp_path)) expect(helper.avatar_icon(user).to_s). - to match("/uploads/user/avatar/#{user.id}/banana_sample.gif") + to match("/uploads/system/user/avatar/#{user.id}/banana_sample.gif") end end end diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb index cd112dbb2fb..c68e4f56b05 100644 --- a/spec/helpers/emails_helper_spec.rb +++ b/spec/helpers/emails_helper_spec.rb @@ -52,7 +52,7 @@ describe EmailsHelper do ) expect(header_logo).to eq( - %{Dk} + %{Dk} ) end end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index c8b0d86425f..0337afa4452 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -9,7 +9,7 @@ describe GroupsHelper do group.avatar = fixture_file_upload(avatar_file_path) group.save! expect(group_icon(group.path).to_s). - to match("/uploads/group/avatar/#{group.id}/banana_sample.gif") + to match("/uploads/system/group/avatar/#{group.id}/banana_sample.gif") end it 'gives default avatar_icon when no avatar is present' do diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index 2cc0b40b2d0..dff2784f21f 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -60,7 +60,7 @@ describe PageLayoutHelper do %w(project user group).each do |type| context "with @#{type} assigned" do it "uses #{type.titlecase} avatar if available" do - object = double(avatar_url: 'http://example.com/uploads/avatar.png') + object = double(avatar_url: 'http://example.com/uploads/system/avatar.png') assign(type, object) expect(helper.page_image).to eq object.avatar_url diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 24335614e09..bfd8b8648a6 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -461,6 +461,45 @@ import '~/notes'; }); }); + describe('update comment with script tags', () => { + const sampleComment = ''; + const updatedComment = ''; + const note = { + id: 1234, + html: `
  • +
    ${sampleComment}
    +
  • `, + note: sampleComment, + valid: true + }; + let $form; + let $notesContainer; + + beforeEach(() => { + this.notes = new Notes('', []); + window.gon.current_username = 'root'; + window.gon.current_user_fullname = 'Administrator'; + $form = $('form.js-main-target-form'); + $notesContainer = $('ul.main-notes-list'); + $form.find('textarea.js-note-text').html(sampleComment); + }); + + it('should not render a script tag', () => { + const deferred = $.Deferred(); + spyOn($, 'ajax').and.returnValue(deferred.promise()); + $('.js-comment-button').click(); + + deferred.resolve(note); + const $noteEl = $notesContainer.find(`#note_${note.id}`); + $noteEl.find('.js-note-edit').click(); + $noteEl.find('textarea.js-note-text').html(updatedComment); + $noteEl.find('.js-comment-save-button').click(); + + const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`).find('.js-task-list-container'); + expect($updatedNoteEl.find('.note-text').text().trim()).toEqual(''); + }); + }); + describe('getFormData', () => { let $form; let sampleComment; diff --git a/spec/javascripts/vue_shared/components/commit_spec.js b/spec/javascripts/vue_shared/components/commit_spec.js index 050170a54e9..540245fe71e 100644 --- a/spec/javascripts/vue_shared/components/commit_spec.js +++ b/spec/javascripts/vue_shared/components/commit_spec.js @@ -22,7 +22,7 @@ describe('Commit component', () => { shortSha: 'b7836edd', title: 'Commit message', author: { - avatar_url: 'https://gitlab.com/uploads/user/avatar/300478/avatar.png', + avatar_url: 'https://gitlab.com/uploads/system/user/avatar/300478/avatar.png', web_url: 'https://gitlab.com/jschatz1', path: '/jschatz1', username: 'jschatz1', @@ -45,7 +45,7 @@ describe('Commit component', () => { shortSha: 'b7836edd', title: 'Commit message', author: { - avatar_url: 'https://gitlab.com/uploads/user/avatar/300478/avatar.png', + avatar_url: 'https://gitlab.com/uploads/system/user/avatar/300478/avatar.png', web_url: 'https://gitlab.com/jschatz1', path: '/jschatz1', username: 'jschatz1', diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb index d5746107ee1..f4f42bfc3ed 100644 --- a/spec/lib/banzai/reference_parser/base_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb @@ -30,7 +30,7 @@ describe Banzai::ReferenceParser::BaseParser, lib: true do it 'checks if user can read the resource' do link['data-project'] = project.id.to_s - expect(subject).to receive(:can_read_reference?).with(user, project) + expect(subject).to receive(:can_read_reference?).with(user, project, link) subject.nodes_visible_to_user(user, [link]) end diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb index d217a775802..620875ece20 100644 --- a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb @@ -4,20 +4,199 @@ describe Banzai::ReferenceParser::SnippetParser, lib: true do include ReferenceParserHelpers let(:project) { create(:empty_project, :public) } + let(:user) { create(:user) } - let(:snippet) { create(:snippet, project: project) } + let(:external_user) { create(:user, :external) } + let(:project_member) { create(:user) } + subject { described_class.new(project, user) } let(:link) { empty_html_link } + def visible_references(snippet_visibility, user = nil) + snippet = create(:project_snippet, snippet_visibility, project: project) + link['data-project'] = project.id.to_s + link['data-snippet'] = snippet.id.to_s + + subject.nodes_visible_to_user(user, [link]) + end + + before do + project.add_user(project_member, :developer) + end + describe '#nodes_visible_to_user' do - context 'when the link has a data-issue attribute' do - before { link['data-snippet'] = snippet.id.to_s } + context 'when a project is public and the snippets feature is enabled for everyone' do + before do + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::ENABLED) + end + + it 'creates a reference for guest for a public snippet' do + expect(visible_references(:public)).to eq([link]) + end + + it 'creates a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to eq([link]) + end + + it 'creates a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to eq([link]) + end + + it 'does not create a reference for an external user for an internal snippet' do + expect(visible_references(:internal, external_user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is public and the snippets feature is enabled for project team members' do + before do + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE) + end + + it 'creates a reference for a project member for a public snippet' do + expect(visible_references(:public, project_member)).to eq([link]) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public, nil)).to be_empty + end + + it 'does not create a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to be_empty + end + + it 'creates a reference for a project member for an internal snippet' do + expect(visible_references(:internal, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is internal and the snippets feature is enabled for everyone' do + before do + project.update_attribute(:visibility, Gitlab::VisibilityLevel::INTERNAL) + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::ENABLED) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public)).to be_empty + end + + it 'does not create a reference for an external user for a public snippet' do + expect(visible_references(:public, external_user)).to be_empty + end - it_behaves_like "referenced feature visibility", "snippets" + it 'creates a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to eq([link]) + end + + it 'creates a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to eq([link]) + end + + it 'does not create a reference for an external user for an internal snippet' do + expect(visible_references(:internal, external_user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is internal and the snippets feature is enabled for project team members' do + before do + project.update_attribute(:visibility, Gitlab::VisibilityLevel::INTERNAL) + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE) + end + + it 'creates a reference for a project member for a public snippet' do + expect(visible_references(:public, project_member)).to eq([link]) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public, nil)).to be_empty + end + + it 'does not create reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to be_empty + end + + it 'creates a reference for a project member for an internal snippet' do + expect(visible_references(:internal, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is private and the snippets feature is enabled for project team members' do + before do + project.update_attribute(:visibility, Gitlab::VisibilityLevel::PRIVATE) + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE) + end + + it 'creates a reference for a project member for a public snippet' do + expect(visible_references(:public, project_member)).to eq([link]) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public, nil)).to be_empty + end + + it 'does not create a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to be_empty + end + + it 'creates a reference for a project member for an internal snippet' do + expect(visible_references(:internal, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end end end describe '#referenced_by' do + let(:snippet) { create(:snippet, project: project) } describe 'when the link has a data-snippet attribute' do context 'using an existing snippet ID' do it 'returns an Array of snippets' do @@ -31,7 +210,7 @@ describe Banzai::ReferenceParser::SnippetParser, lib: true do it 'returns an empty Array' do link['data-snippet'] = '' - expect(subject.referenced_by([link])).to eq([]) + expect(subject.referenced_by([link])).to be_empty end end end diff --git a/spec/lib/gitlab/uploads_transfer_spec.rb b/spec/lib/gitlab/uploads_transfer_spec.rb new file mode 100644 index 00000000000..109559bb01c --- /dev/null +++ b/spec/lib/gitlab/uploads_transfer_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe Gitlab::UploadsTransfer do + it 'leaves avatar uploads where they are' do + project_with_avatar = create(:empty_project, :with_avatar) + + described_class.new.rename_namespace('project', 'project-renamed') + + expect(File.exist?(project_with_avatar.avatar.path)).to be_truthy + end +end diff --git a/spec/migrations/clean_upload_symlinks_spec.rb b/spec/migrations/clean_upload_symlinks_spec.rb new file mode 100644 index 00000000000..cecb3ddac53 --- /dev/null +++ b/spec/migrations/clean_upload_symlinks_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170406111121_clean_upload_symlinks.rb') + +describe CleanUploadSymlinks do + let(:migration) { described_class.new } + let(:test_dir) { File.join(Rails.root, "tmp", "tests", "move_uploads_test") } + let(:uploads_dir) { File.join(test_dir, "public", "uploads") } + let(:new_uploads_dir) { File.join(uploads_dir, "system") } + let(:original_path) { File.join(new_uploads_dir, 'user') } + let(:symlink_path) { File.join(uploads_dir, 'user') } + + before do + FileUtils.remove_dir(test_dir) if File.directory?(test_dir) + FileUtils.mkdir_p(uploads_dir) + allow(migration).to receive(:base_directory).and_return(test_dir) + allow(migration).to receive(:say) + end + + describe "#up" do + before do + FileUtils.mkdir_p(original_path) + FileUtils.ln_s(original_path, symlink_path) + end + + it 'removes the symlink' do + migration.up + + expect(File.symlink?(symlink_path)).to be(false) + end + end + + describe '#down' do + before do + FileUtils.mkdir_p(File.join(original_path)) + FileUtils.touch(File.join(original_path, 'dummy.file')) + end + + it 'creates a symlink' do + expected_path = File.join(symlink_path, "dummy.file") + migration.down + + expect(File.exist?(expected_path)).to be(true) + expect(File.symlink?(symlink_path)).to be(true) + end + end +end diff --git a/spec/migrations/move_uploads_to_system_dir_spec.rb b/spec/migrations/move_uploads_to_system_dir_spec.rb new file mode 100644 index 00000000000..37d66452447 --- /dev/null +++ b/spec/migrations/move_uploads_to_system_dir_spec.rb @@ -0,0 +1,68 @@ +require "spec_helper" +require Rails.root.join("db", "migrate", "20170316163845_move_uploads_to_system_dir.rb") + +describe MoveUploadsToSystemDir do + let(:migration) { described_class.new } + let(:test_dir) { File.join(Rails.root, "tmp", "move_uploads_test") } + let(:uploads_dir) { File.join(test_dir, "public", "uploads") } + let(:new_uploads_dir) { File.join(uploads_dir, "system") } + + before do + FileUtils.remove_dir(test_dir) if File.directory?(test_dir) + FileUtils.mkdir_p(uploads_dir) + allow(migration).to receive(:base_directory).and_return(test_dir) + allow(migration).to receive(:say) + end + + describe "#up" do + before do + FileUtils.mkdir_p(File.join(uploads_dir, 'user')) + FileUtils.touch(File.join(uploads_dir, 'user', 'dummy.file')) + end + + it 'moves the directory to the new path' do + expected_path = File.join(new_uploads_dir, 'user', 'dummy.file') + + migration.up + + expect(File.exist?(expected_path)).to be(true) + end + + it 'creates a symlink in the old location' do + symlink_path = File.join(uploads_dir, 'user') + expected_path = File.join(symlink_path, 'dummy.file') + + migration.up + + expect(File.exist?(expected_path)).to be(true) + expect(File.symlink?(symlink_path)).to be(true) + end + end + + describe "#down" do + before do + FileUtils.mkdir_p(File.join(new_uploads_dir, 'user')) + FileUtils.touch(File.join(new_uploads_dir, 'user', 'dummy.file')) + end + + it 'moves the directory to the old path' do + expected_path = File.join(uploads_dir, 'user', 'dummy.file') + + migration.down + + expect(File.exist?(expected_path)).to be(true) + end + + it 'removes the symlink if it existed' do + FileUtils.ln_s(File.join(new_uploads_dir, 'user'), File.join(uploads_dir, 'user')) + + directory = File.join(uploads_dir, 'user') + expected_path = File.join(directory, 'dummy.file') + + migration.down + + expect(File.exist?(expected_path)).to be(true) + expect(File.symlink?(directory)).to be(false) + end + end +end diff --git a/spec/migrations/rename_system_namespaces_spec.rb b/spec/migrations/rename_system_namespaces_spec.rb new file mode 100644 index 00000000000..ad1b83d8e2e --- /dev/null +++ b/spec/migrations/rename_system_namespaces_spec.rb @@ -0,0 +1,252 @@ +require "spec_helper" +require Rails.root.join("db", "migrate", "20170316163800_rename_system_namespaces.rb") + +describe RenameSystemNamespaces, truncate: true do + let(:migration) { described_class.new } + let(:test_dir) { File.join(Rails.root, "tmp", "tests", "rename_namespaces_test") } + let(:uploads_dir) { File.join(test_dir, "public", "uploads") } + let(:system_namespace) do + namespace = build(:namespace, path: "system") + namespace.save(validate: false) + namespace + end + + def save_invalid_routable(routable) + routable.__send__(:prepare_route) + routable.save(validate: false) + end + + before do + FileUtils.remove_dir(test_dir) if File.directory?(test_dir) + FileUtils.mkdir_p(uploads_dir) + FileUtils.remove_dir(TestEnv.repos_path) if File.directory?(TestEnv.repos_path) + allow(migration).to receive(:say) + allow(migration).to receive(:uploads_dir).and_return(uploads_dir) + end + + describe "#system_namespace" do + it "only root namespaces called with path `system`" do + system_namespace + system_namespace_with_parent = build(:namespace, path: 'system', parent: create(:namespace)) + system_namespace_with_parent.save(validate: false) + + expect(migration.system_namespace.id).to eq(system_namespace.id) + end + end + + describe "#up" do + before do + system_namespace + end + + it "doesn't break if there are no namespaces called system" do + Namespace.delete_all + + migration.up + end + + it "renames namespaces called system" do + migration.up + + expect(system_namespace.reload.path).to eq("system0") + end + + it "renames the route to the namespace" do + migration.up + + expect(system_namespace.reload.full_path).to eq("system0") + end + + it "renames the route for projects of the namespace" do + project = build(:project, path: "project-path", namespace: system_namespace) + save_invalid_routable(project) + + migration.up + + expect(project.route.reload.path).to eq("system0/project-path") + end + + it "doesn't touch routes of namespaces that look like system" do + namespace = create(:group, path: 'systemlookalike') + project = create(:project, namespace: namespace, path: 'the-project') + + migration.up + + expect(project.route.reload.path).to eq('systemlookalike/the-project') + expect(namespace.route.reload.path).to eq('systemlookalike') + end + + it "moves the the repository for a project in the namespace" do + project = build(:project, namespace: system_namespace, path: "system-project") + save_invalid_routable(project) + TestEnv.copy_repo(project) + expected_repo = File.join(TestEnv.repos_path, "system0", "system-project.git") + + migration.up + + expect(File.directory?(expected_repo)).to be(true) + end + + it "moves the uploads for the namespace" do + allow(migration).to receive(:move_namespace_folders).with(Settings.pages.path, "system", "system0") + expect(migration).to receive(:move_namespace_folders).with(uploads_dir, "system", "system0") + + migration.up + end + + it "moves the pages for the namespace" do + allow(migration).to receive(:move_namespace_folders).with(uploads_dir, "system", "system0") + expect(migration).to receive(:move_namespace_folders).with(Settings.pages.path, "system", "system0") + + migration.up + end + + describe "clears the markdown cache for projects in the system namespace" do + let!(:project) do + project = build(:project, namespace: system_namespace) + save_invalid_routable(project) + project + end + + it 'removes description_html from projects' do + migration.up + + expect(project.reload.description_html).to be_nil + end + + it 'removes issue descriptions' do + issue = create(:issue, project: project, description_html: 'Issue description') + + migration.up + + expect(issue.reload.description_html).to be_nil + end + + it 'removes merge request descriptions' do + merge_request = create(:merge_request, + source_project: project, + target_project: project, + description_html: 'MergeRequest description') + + migration.up + + expect(merge_request.reload.description_html).to be_nil + end + + it 'removes note html' do + note = create(:note, + project: project, + noteable: create(:issue, project: project), + note_html: 'note description') + + migration.up + + expect(note.reload.note_html).to be_nil + end + + it 'removes milestone description' do + milestone = create(:milestone, + project: project, + description_html: 'milestone description') + + migration.up + + expect(milestone.reload.description_html).to be_nil + end + end + + context "system namespace -> subgroup -> system0 project" do + it "updates the route of the project correctly" do + subgroup = build(:group, path: "subgroup", parent: system_namespace) + save_invalid_routable(subgroup) + project = build(:project, path: "system0", namespace: subgroup) + save_invalid_routable(project) + + migration.up + + expect(project.route.reload.path).to eq("system0/subgroup/system0") + end + end + end + + describe "#move_repositories" do + let(:namespace) { create(:group, name: "hello-group") } + it "moves a project for a namespace" do + create(:project, namespace: namespace, path: "hello-project") + expected_path = File.join(TestEnv.repos_path, "bye-group", "hello-project.git") + + migration.move_repositories(namespace, "hello-group", "bye-group") + + expect(File.directory?(expected_path)).to be(true) + end + + it "moves a namespace in a subdirectory correctly" do + child_namespace = create(:group, name: "sub-group", parent: namespace) + create(:project, namespace: child_namespace, path: "hello-project") + + expected_path = File.join(TestEnv.repos_path, "hello-group", "renamed-sub-group", "hello-project.git") + + migration.move_repositories(child_namespace, "hello-group/sub-group", "hello-group/renamed-sub-group") + + expect(File.directory?(expected_path)).to be(true) + end + + it "moves a parent namespace with subdirectories" do + child_namespace = create(:group, name: "sub-group", parent: namespace) + create(:project, namespace: child_namespace, path: "hello-project") + expected_path = File.join(TestEnv.repos_path, "renamed-group", "sub-group", "hello-project.git") + + migration.move_repositories(child_namespace, "hello-group", "renamed-group") + + expect(File.directory?(expected_path)).to be(true) + end + end + + describe "#move_namespace_folders" do + it "moves a namespace with files" do + source = File.join(uploads_dir, "parent-group", "sub-group") + FileUtils.mkdir_p(source) + destination = File.join(uploads_dir, "parent-group", "moved-group") + FileUtils.touch(File.join(source, "test.txt")) + expected_file = File.join(destination, "test.txt") + + migration.move_namespace_folders(uploads_dir, File.join("parent-group", "sub-group"), File.join("parent-group", "moved-group")) + + expect(File.exist?(expected_file)).to be(true) + end + + it "moves a parent namespace uploads" do + source = File.join(uploads_dir, "parent-group", "sub-group") + FileUtils.mkdir_p(source) + destination = File.join(uploads_dir, "moved-parent", "sub-group") + FileUtils.touch(File.join(source, "test.txt")) + expected_file = File.join(destination, "test.txt") + + migration.move_namespace_folders(uploads_dir, "parent-group", "moved-parent") + + expect(File.exist?(expected_file)).to be(true) + end + end + + describe "#child_ids_for_parent" do + it "collects child ids for all levels" do + parent = create(:namespace) + first_child = create(:namespace, parent: parent) + second_child = create(:namespace, parent: parent) + third_child = create(:namespace, parent: second_child) + all_ids = [parent.id, first_child.id, second_child.id, third_child.id] + + collected_ids = migration.child_ids_for_parent(parent, ids: [parent.id]) + + expect(collected_ids).to contain_exactly(*all_ids) + end + end + + describe "#remove_last_ocurrence" do + it "removes only the last occurance of a string" do + input = "this/is/system/namespace/with/system" + + expect(migration.remove_last_occurrence(input, "system")).to eq("this/is/system/namespace/with/") + end + end +end diff --git a/spec/migrations/update_upload_paths_to_system_spec.rb b/spec/migrations/update_upload_paths_to_system_spec.rb new file mode 100644 index 00000000000..7df44515424 --- /dev/null +++ b/spec/migrations/update_upload_paths_to_system_spec.rb @@ -0,0 +1,53 @@ +require "spec_helper" +require Rails.root.join("db", "post_migrate", "20170317162059_update_upload_paths_to_system.rb") + +describe UpdateUploadPathsToSystem do + let(:migration) { described_class.new } + + before do + allow(migration).to receive(:say) + end + + describe "#uploads_to_switch_to_new_path" do + it "contains only uploads with the old path for the correct models" do + _upload_for_other_type = create(:upload, model: create(:ci_pipeline), path: "uploads/ci_pipeline/avatar.jpg") + _upload_with_system_path = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg") + _upload_with_other_path = create(:upload, model: create(:empty_project), path: "thelongsecretforafileupload/avatar.jpg") + old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg") + group_upload = create(:upload, model: create(:group), path: "uploads/group/avatar.jpg") + + expect(Upload.where(migration.uploads_to_switch_to_new_path)).to contain_exactly(old_upload, group_upload) + end + end + + describe "#uploads_to_switch_to_old_path" do + it "contains only uploads with the new path for the correct models" do + _upload_for_other_type = create(:upload, model: create(:ci_pipeline), path: "uploads/ci_pipeline/avatar.jpg") + upload_with_system_path = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg") + _upload_with_other_path = create(:upload, model: create(:empty_project), path: "thelongsecretforafileupload/avatar.jpg") + _old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg") + + expect(Upload.where(migration.uploads_to_switch_to_old_path)).to contain_exactly(upload_with_system_path) + end + end + + describe "#up", truncate: true do + it "updates old upload records to the new path" do + old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg") + + migration.up + + expect(old_upload.reload.path).to eq("uploads/system/project/avatar.jpg") + end + end + + describe "#down", truncate: true do + it "updates the new system patsh to the old paths" do + new_upload = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg") + + migration.down + + expect(new_upload.reload.path).to eq("uploads/project/avatar.jpg") + end + end +end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 316bf153660..3d437ca0fcc 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -179,7 +179,7 @@ describe Group, models: true do let!(:group) { create(:group, :access_requestable, :with_avatar) } let(:user) { create(:user) } let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } - let(:avatar_path) { "/uploads/group/avatar/#{group.id}/dk.png" } + let(:avatar_path) { "/uploads/system/group/avatar/#{group.id}/dk.png" } context 'when avatar file is uploaded' do before { group.add_master(user) } diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 0e74f1ab1bd..145c7ad5770 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -43,6 +43,12 @@ describe Namespace, models: true do end end + context "is case insensitive" do + let(:group) { build(:group, path: "System") } + + it { expect(group).not_to be_valid } + end + context 'top-level group' do let(:group) { build(:group, path: 'tree') } @@ -178,8 +184,8 @@ describe Namespace, models: true do let(:parent) { create(:group, name: 'parent', path: 'parent') } let(:child) { create(:group, name: 'child', path: 'child', parent: parent) } let!(:project) { create(:project_empty_repo, path: 'the-project', namespace: child) } - let(:uploads_dir) { File.join(CarrierWave.root, 'uploads') } - let(:pages_dir) { TestEnv.pages_path } + let(:uploads_dir) { File.join(CarrierWave.root, FileUploader.base_dir) } + let(:pages_dir) { File.join(TestEnv.pages_path) } before do FileUtils.mkdir_p(File.join(uploads_dir, 'parent', 'child', 'the-project')) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 3ed52d42f86..454eeb58ecd 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -812,7 +812,7 @@ describe Project, models: true do context 'when avatar file is uploaded' do let(:project) { create(:empty_project, :with_avatar) } - let(:avatar_path) { "/uploads/project/avatar/#{project.id}/dk.png" } + let(:avatar_path) { "/uploads/system/project/avatar/#{project.id}/dk.png" } let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } it 'shows correct url' do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index a83726b48a0..d5bd9946ab6 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -987,7 +987,7 @@ describe User, models: true do context 'when avatar file is uploaded' do let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } - let(:avatar_path) { "/uploads/user/avatar/#{user.id}/dk.png" } + let(:avatar_path) { "/uploads/system/user/avatar/#{user.id}/dk.png" } it 'shows correct avatar url' do expect(user.avatar_url).to eq(avatar_path) diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb index e1771b636b8..ddbed5f781e 100644 --- a/spec/policies/project_snippet_policy_spec.rb +++ b/spec/policies/project_snippet_policy_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe ProjectSnippetPolicy, models: true do let(:regular_user) { create(:user) } let(:external_user) { create(:user, :external) } - let(:project) { create(:empty_project) } + let(:project) { create(:empty_project, :public) } let(:author_permissions) do [ @@ -107,7 +107,7 @@ describe ProjectSnippetPolicy, models: true do end context 'snippet author' do - let(:snippet) { create(:project_snippet, :private, author: regular_user) } + let(:snippet) { create(:project_snippet, :private, author: regular_user, project: project) } subject { described_class.abilities(regular_user, snippet).to_set } diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb index 05176c3beaa..6d1f0b24196 100644 --- a/spec/requests/openid_connect_spec.rb +++ b/spec/requests/openid_connect_spec.rb @@ -79,7 +79,7 @@ describe 'OpenID Connect requests' do 'email_verified' => true, 'website' => 'https://example.com', 'profile' => 'http://localhost/alice', - 'picture' => "http://localhost/uploads/user/avatar/#{user.id}/dk.png" + 'picture' => "http://localhost/uploads/system/user/avatar/#{user.id}/dk.png" }) end end diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb index 0657b7e93fe..d75851134ee 100644 --- a/spec/services/projects/participants_service_spec.rb +++ b/spec/services/projects/participants_service_spec.rb @@ -13,7 +13,7 @@ describe Projects::ParticipantsService, services: true do groups = participants.groups expect(groups.size).to eq 1 - expect(groups.first[:avatar_url]).to eq("/uploads/group/avatar/#{group.id}/dk.png") + expect(groups.first[:avatar_url]).to eq("/uploads/system/group/avatar/#{group.id}/dk.png") end it 'should return an url for the avatar with relative url' do @@ -24,7 +24,7 @@ describe Projects::ParticipantsService, services: true do groups = participants.groups expect(groups.size).to eq 1 - expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/group/avatar/#{group.id}/dk.png") + expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/system/group/avatar/#{group.id}/dk.png") end end end diff --git a/spec/uploaders/attachment_uploader_spec.rb b/spec/uploaders/attachment_uploader_spec.rb index ea714fb08f0..d82dbe871d5 100644 --- a/spec/uploaders/attachment_uploader_spec.rb +++ b/spec/uploaders/attachment_uploader_spec.rb @@ -3,6 +3,17 @@ require 'spec_helper' describe AttachmentUploader do let(:uploader) { described_class.new(build_stubbed(:user)) } + describe "#store_dir" do + it "stores in the system dir" do + expect(uploader.store_dir).to start_with("uploads/system/user") + end + + it "uses the old path when using object storage" do + expect(described_class).to receive(:file_storage?).and_return(false) + expect(uploader.store_dir).to start_with("uploads/user") + end + end + describe '#move_to_cache' do it 'is true' do expect(uploader.move_to_cache).to eq(true) diff --git a/spec/uploaders/avatar_uploader_spec.rb b/spec/uploaders/avatar_uploader_spec.rb index c4d558805ab..201fe6949aa 100644 --- a/spec/uploaders/avatar_uploader_spec.rb +++ b/spec/uploaders/avatar_uploader_spec.rb @@ -3,6 +3,17 @@ require 'spec_helper' describe AvatarUploader do let(:uploader) { described_class.new(build_stubbed(:user)) } + describe "#store_dir" do + it "stores in the system dir" do + expect(uploader.store_dir).to start_with("uploads/system/user") + end + + it "uses the old path when using object storage" do + expect(described_class).to receive(:file_storage?).and_return(false) + expect(uploader.store_dir).to start_with("uploads/user") + end + end + describe '#move_to_cache' do it 'is false' do expect(uploader.move_to_cache).to eq(false) diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb index d9113ef4095..47e9365e13d 100644 --- a/spec/uploaders/file_uploader_spec.rb +++ b/spec/uploaders/file_uploader_spec.rb @@ -15,6 +15,16 @@ describe FileUploader do end end + describe "#store_dir" do + it "stores in the namespace path" do + project = build_stubbed(:empty_project) + uploader = described_class.new(project) + + expect(uploader.store_dir).to include(project.path_with_namespace) + expect(uploader.store_dir).not_to include("system") + end + end + describe 'initialize' do it 'generates a secret if none is provided' do expect(SecureRandom).to receive(:hex).and_return('secret') -- cgit v1.2.3 From 70d7ded5b38376809365cadd7e542254003f8210 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Thu, 8 Jun 2017 10:10:44 +0200 Subject: Update rename_system_namespace_spec to new validations. --- spec/migrations/rename_system_namespaces_spec.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'spec') diff --git a/spec/migrations/rename_system_namespaces_spec.rb b/spec/migrations/rename_system_namespaces_spec.rb index ad1b83d8e2e..626a6005838 100644 --- a/spec/migrations/rename_system_namespaces_spec.rb +++ b/spec/migrations/rename_system_namespaces_spec.rb @@ -79,7 +79,9 @@ describe RenameSystemNamespaces, truncate: true do it "moves the the repository for a project in the namespace" do project = build(:project, namespace: system_namespace, path: "system-project") save_invalid_routable(project) - TestEnv.copy_repo(project) + TestEnv.copy_repo(project, + bare_repo: TestEnv.factory_repo_path_bare, + refs: TestEnv::BRANCH_SHA) expected_repo = File.join(TestEnv.repos_path, "system0", "system-project.git") migration.up @@ -230,10 +232,10 @@ describe RenameSystemNamespaces, truncate: true do describe "#child_ids_for_parent" do it "collects child ids for all levels" do - parent = create(:namespace) - first_child = create(:namespace, parent: parent) - second_child = create(:namespace, parent: parent) - third_child = create(:namespace, parent: second_child) + parent = create(:group) + first_child = create(:group, parent: parent) + second_child = create(:group, parent: parent) + third_child = create(:group, parent: second_child) all_ids = [parent.id, first_child.id, second_child.id, third_child.id] collected_ids = migration.child_ids_for_parent(parent, ids: [parent.id]) -- cgit v1.2.3 From ffbbd4112eb5a0a927925e70644128bf25145414 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 6 Jun 2017 16:24:32 -0500 Subject: Move diffable? method from Repository to Diff::File --- .../file_collection/merge_request_diff_spec.rb | 12 ++----- spec/lib/gitlab/diff/file_spec.rb | 28 +++++++++++++-- spec/lib/gitlab/git/repository_spec.rb | 41 ---------------------- .../merge_request_diff_cache_service_spec.rb | 4 +-- 4 files changed, 29 insertions(+), 56 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb index f2bc15d39d7..d81774c8b8f 100644 --- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb +++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb @@ -5,15 +5,7 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do let(:diff_files) { described_class.new(merge_request.merge_request_diff, diff_options: nil).diff_files } it 'does not highlight binary files' do - allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(double("text?" => false)) - - expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines) - - diff_files - end - - it 'does not highlight file if blob is not accessable' do - allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(nil) + allow_any_instance_of(Gitlab::Diff::File).to receive(:text?).and_return(false) expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines) @@ -21,7 +13,7 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do end it 'does not files marked as undiffable in .gitattributes' do - allow_any_instance_of(Repository).to receive(:diffable?).and_return(false) + allow_any_instance_of(Gitlab::Diff::File).to receive(:diffable?).and_return(false) expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines) diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index 050689b7c9a..a9953bb0d01 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::Diff::File, lib: true do let(:project) { create(:project, :repository) } let(:commit) { project.commit(sample_commit.id) } let(:diff) { commit.raw_diffs.first } - let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: commit.diff_refs, repository: project.repository) } + let(:diff_file) { described_class.new(diff, diff_refs: commit.diff_refs, repository: project.repository) } describe '#diff_lines' do let(:diff_lines) { diff_file.diff_lines } @@ -63,11 +63,33 @@ describe Gitlab::Diff::File, lib: true do end end - describe '#blob' do + describe '#new_blob' do it 'returns blob of new commit' do - data = diff_file.blob.data + data = diff_file.new_blob.data expect(data).to include('raise RuntimeError, "System commands must be given as an array of strings"') end end + + describe '#diffable?' do + let(:commit) { project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') } + let(:diffs) { commit.diffs } + + before do + info_dir_path = File.join(project.repository.path_to_repo, 'info') + + FileUtils.mkdir(info_dir_path) unless File.exist?(info_dir_path) + File.write(File.join(info_dir_path, 'attributes'), "*.md -diff\n") + end + + it "returns true for files that do not have attributes" do + diff_file = diffs.diff_file_with_new_path('LICENSE') + expect(diff_file.diffable?).to be_truthy + end + + it "returns false for files that have been marked as not being diffable in attributes" do + diff_file = diffs.diff_file_with_new_path('README.md') + expect(diff_file.diffable?).to be_falsey + end + end end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 26215381cc4..e1e4aa9fde9 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1235,47 +1235,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe '#diffable' do - info_dir_path = attributes_path = File.join(SEED_STORAGE_PATH, TEST_REPO_PATH, 'info') - attributes_path = File.join(info_dir_path, 'attributes') - - before(:all) do - FileUtils.mkdir(info_dir_path) unless File.exist?(info_dir_path) - File.write(attributes_path, "*.md -diff\n") - end - - it "should return true for files which are text and do not have attributes" do - blob = Gitlab::Git::Blob.find( - repository, - '33bcff41c232a11727ac6d660bd4b0c2ba86d63d', - 'LICENSE' - ) - expect(repository.diffable?(blob)).to be_truthy - end - - it "should return false for binary files which do not have attributes" do - blob = Gitlab::Git::Blob.find( - repository, - '33bcff41c232a11727ac6d660bd4b0c2ba86d63d', - 'files/images/logo-white.png' - ) - expect(repository.diffable?(blob)).to be_falsey - end - - it "should return false for text files which have been marked as not being diffable in attributes" do - blob = Gitlab::Git::Blob.find( - repository, - '33bcff41c232a11727ac6d660bd4b0c2ba86d63d', - 'README.md' - ) - expect(repository.diffable?(blob)).to be_falsey - end - - after(:all) do - FileUtils.rm_rf(info_dir_path) - end - end - describe '#tag_exists?' do it 'returns true for an existing tag' do tag = repository.tag_names.first diff --git a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb index 935f4710851..bb46e1dd9ab 100644 --- a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb +++ b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb @@ -10,8 +10,8 @@ describe MergeRequests::MergeRequestDiffCacheService do expect(Rails.cache).to receive(:read).with(cache_key).and_return({}) expect(Rails.cache).to receive(:write).with(cache_key, anything) - allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(double("text?" => true)) - allow_any_instance_of(Repository).to receive(:diffable?).and_return(true) + allow_any_instance_of(Gitlab::Diff::File).to receive(:text?).and_return(true) + allow_any_instance_of(Gitlab::Diff::File).to receive(:diffable?).and_return(true) subject.execute(merge_request) end -- cgit v1.2.3 From e6e29f9220a676f86ad035ae6430888deab4e8c5 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 6 Jun 2017 16:21:29 -0500 Subject: Use Diff::File blob methods from diff highlighter --- spec/lib/gitlab/highlight_spec.rb | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index a20cef3b000..c2bb9f9a166 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -7,30 +7,6 @@ describe Gitlab::Highlight, lib: true do let(:repository) { project.repository } let(:commit) { project.commit(sample_commit.id) } - describe '.highlight_lines' do - let(:lines) do - Gitlab::Highlight.highlight_lines(project.repository, commit.id, 'files/ruby/popen.rb') - end - - it 'highlights all the lines properly' do - expect(lines[4]).to eq(%Q{ extend self\n}) - expect(lines[21]).to eq(%Q{ unless File.directory?(path)\n}) - expect(lines[26]).to eq(%Q{ @cmd_status = 0\n}) - end - - describe 'with CRLF' do - let(:branch) { 'crlf-diff' } - let(:blob) { repository.blob_at_branch(branch, path) } - let(:lines) do - Gitlab::Highlight.highlight_lines(project.repository, 'crlf-diff', 'files/whitespace') - end - - it 'strips extra LFs' do - expect(lines[0]).to eq("test ") - end - end - end - describe 'custom highlighting from .gitattributes' do let(:branch) { 'gitattributes' } let(:blob) { repository.blob_at_branch(branch, path) } @@ -59,6 +35,19 @@ describe Gitlab::Highlight, lib: true do end describe '#highlight' do + describe 'with CRLF' do + let(:branch) { 'crlf-diff' } + let(:path) { 'files/whitespace' } + let(:blob) { repository.blob_at_branch(branch, path) } + let(:lines) do + Gitlab::Highlight.highlight(blob.path, blob.data, repository: repository).lines + end + + it 'strips extra LFs' do + expect(lines[0]).to eq("test ") + end + end + it 'links dependencies via DependencyLinker' do expect(Gitlab::DependencyLinker).to receive(:link). with('file.name', 'Contents', anything).and_call_original -- cgit v1.2.3 From 369d681eec8177f03bf3b4f694e03098447dae09 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 6 Jun 2017 16:26:31 -0500 Subject: Add Blob#file_type convenience method --- spec/models/blob_spec.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'spec') diff --git a/spec/models/blob_spec.rb b/spec/models/blob_spec.rb index f19e1af65a6..e1193e0d19a 100644 --- a/spec/models/blob_spec.rb +++ b/spec/models/blob_spec.rb @@ -199,6 +199,14 @@ describe Blob do end end + describe '#file_type' do + it 'returns the file type' do + blob = fake_blob(path: 'README.md') + + expect(blob.file_type).to eq(:readme) + end + end + describe '#simple_viewer' do context 'when the blob is empty' do it 'returns an empty viewer' do -- cgit v1.2.3 From ef3adb65797a5479ea9c7cbbdf6039c3ea21641c Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 8 Jun 2017 18:35:55 +0200 Subject: Increase unicorn test boot timeout to 5 minutes --- spec/unicorn/unicorn_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/unicorn/unicorn_spec.rb b/spec/unicorn/unicorn_spec.rb index 8518c047a47..41de94d35c2 100644 --- a/spec/unicorn/unicorn_spec.rb +++ b/spec/unicorn/unicorn_spec.rb @@ -67,8 +67,8 @@ describe 'Unicorn' do end def wait_unicorn_boot!(master_pid, ready_file) - # Unicorn should boot in under 60 seconds so 120 seconds seems like a good timeout. - timeout = 120 + # We have seen the boot timeout after 2 minutes in CI so let's set it to 5 minutes. + timeout = 5 * 60 timeout.times do return if File.exist?(ready_file) pid = Process.waitpid(master_pid, Process::WNOHANG) -- cgit v1.2.3 From 7113b1a45bd29318c3ec5ea5f61b1d523868ef4d Mon Sep 17 00:00:00 2001 From: DJ Mountney Date: Thu, 8 Jun 2017 09:48:10 -0700 Subject: Merge branch 'cherry-pick-dc2ac993' into 'security-9-2' Escapes html content before appending it to the DOM See merge request !2107 --- spec/javascripts/notes_spec.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 24335614e09..bfd8b8648a6 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -461,6 +461,45 @@ import '~/notes'; }); }); + describe('update comment with script tags', () => { + const sampleComment = ''; + const updatedComment = ''; + const note = { + id: 1234, + html: `
  • +
    ${sampleComment}
    +
  • `, + note: sampleComment, + valid: true + }; + let $form; + let $notesContainer; + + beforeEach(() => { + this.notes = new Notes('', []); + window.gon.current_username = 'root'; + window.gon.current_user_fullname = 'Administrator'; + $form = $('form.js-main-target-form'); + $notesContainer = $('ul.main-notes-list'); + $form.find('textarea.js-note-text').html(sampleComment); + }); + + it('should not render a script tag', () => { + const deferred = $.Deferred(); + spyOn($, 'ajax').and.returnValue(deferred.promise()); + $('.js-comment-button').click(); + + deferred.resolve(note); + const $noteEl = $notesContainer.find(`#note_${note.id}`); + $noteEl.find('.js-note-edit').click(); + $noteEl.find('textarea.js-note-text').html(updatedComment); + $noteEl.find('.js-comment-save-button').click(); + + const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`).find('.js-task-list-container'); + expect($updatedNoteEl.find('.note-text').text().trim()).toEqual(''); + }); + }); + describe('getFormData', () => { let $form; let sampleComment; -- cgit v1.2.3 From 982368dc55bbd22f82bf908f8af220056202a65a Mon Sep 17 00:00:00 2001 From: DJ Mountney Date: Thu, 8 Jun 2017 09:52:27 -0700 Subject: Merge branch 'dz-restrict-autocomplete' into 'security-9-1' Allow users autocomplete by author_id only for authenticated users See merge request !2100 --- spec/controllers/autocomplete_controller_spec.rb | 30 ++++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb index 2c9d1ffc9c2..4c3a5ec49ef 100644 --- a/spec/controllers/autocomplete_controller_spec.rb +++ b/spec/controllers/autocomplete_controller_spec.rb @@ -170,22 +170,32 @@ describe AutocompleteController do end context 'author of issuable included' do - before do - sign_in(user) - end - let(:body) { JSON.parse(response.body) } - it 'includes the author' do - get(:users, author_id: non_member.id) + context 'authenticated' do + before do + sign_in(user) + end + + it 'includes the author' do + get(:users, author_id: non_member.id) + + expect(body.first["username"]).to eq non_member.username + end + + it 'rejects non existent user ids' do + get(:users, author_id: 99999) - expect(body.first["username"]).to eq non_member.username + expect(body.collect { |u| u['id'] }).not_to include(99999) + end end - it 'rejects non existent user ids' do - get(:users, author_id: 99999) + context 'without authenticating' do + it 'returns empty result' do + get(:users, author_id: non_member.id) - expect(body.collect { |u| u['id'] }).not_to include(99999) + expect(body).to be_empty + end end end -- cgit v1.2.3 From ae6adf165ce7d9a85d7b8886eefdbe96aac2816b Mon Sep 17 00:00:00 2001 From: DJ Mountney Date: Thu, 8 Jun 2017 09:56:39 -0700 Subject: Merge branch '25934-project-snippet-vis' into 'security-9-2' Fix visibility when referencing snippets See merge request !2101 --- .../banzai/reference_parser/base_parser_spec.rb | 2 +- .../banzai/reference_parser/snippet_parser_spec.rb | 189 ++++++++++++++++++++- spec/policies/project_snippet_policy_spec.rb | 4 +- 3 files changed, 187 insertions(+), 8 deletions(-) (limited to 'spec') diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb index d5746107ee1..f4f42bfc3ed 100644 --- a/spec/lib/banzai/reference_parser/base_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb @@ -30,7 +30,7 @@ describe Banzai::ReferenceParser::BaseParser, lib: true do it 'checks if user can read the resource' do link['data-project'] = project.id.to_s - expect(subject).to receive(:can_read_reference?).with(user, project) + expect(subject).to receive(:can_read_reference?).with(user, project, link) subject.nodes_visible_to_user(user, [link]) end diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb index d217a775802..620875ece20 100644 --- a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb @@ -4,20 +4,199 @@ describe Banzai::ReferenceParser::SnippetParser, lib: true do include ReferenceParserHelpers let(:project) { create(:empty_project, :public) } + let(:user) { create(:user) } - let(:snippet) { create(:snippet, project: project) } + let(:external_user) { create(:user, :external) } + let(:project_member) { create(:user) } + subject { described_class.new(project, user) } let(:link) { empty_html_link } + def visible_references(snippet_visibility, user = nil) + snippet = create(:project_snippet, snippet_visibility, project: project) + link['data-project'] = project.id.to_s + link['data-snippet'] = snippet.id.to_s + + subject.nodes_visible_to_user(user, [link]) + end + + before do + project.add_user(project_member, :developer) + end + describe '#nodes_visible_to_user' do - context 'when the link has a data-issue attribute' do - before { link['data-snippet'] = snippet.id.to_s } + context 'when a project is public and the snippets feature is enabled for everyone' do + before do + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::ENABLED) + end + + it 'creates a reference for guest for a public snippet' do + expect(visible_references(:public)).to eq([link]) + end + + it 'creates a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to eq([link]) + end + + it 'creates a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to eq([link]) + end + + it 'does not create a reference for an external user for an internal snippet' do + expect(visible_references(:internal, external_user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is public and the snippets feature is enabled for project team members' do + before do + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE) + end + + it 'creates a reference for a project member for a public snippet' do + expect(visible_references(:public, project_member)).to eq([link]) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public, nil)).to be_empty + end + + it 'does not create a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to be_empty + end + + it 'creates a reference for a project member for an internal snippet' do + expect(visible_references(:internal, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is internal and the snippets feature is enabled for everyone' do + before do + project.update_attribute(:visibility, Gitlab::VisibilityLevel::INTERNAL) + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::ENABLED) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public)).to be_empty + end + + it 'does not create a reference for an external user for a public snippet' do + expect(visible_references(:public, external_user)).to be_empty + end - it_behaves_like "referenced feature visibility", "snippets" + it 'creates a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to eq([link]) + end + + it 'creates a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to eq([link]) + end + + it 'does not create a reference for an external user for an internal snippet' do + expect(visible_references(:internal, external_user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is internal and the snippets feature is enabled for project team members' do + before do + project.update_attribute(:visibility, Gitlab::VisibilityLevel::INTERNAL) + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE) + end + + it 'creates a reference for a project member for a public snippet' do + expect(visible_references(:public, project_member)).to eq([link]) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public, nil)).to be_empty + end + + it 'does not create reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to be_empty + end + + it 'creates a reference for a project member for an internal snippet' do + expect(visible_references(:internal, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end + end + + context 'when a project is private and the snippets feature is enabled for project team members' do + before do + project.update_attribute(:visibility, Gitlab::VisibilityLevel::PRIVATE) + project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE) + end + + it 'creates a reference for a project member for a public snippet' do + expect(visible_references(:public, project_member)).to eq([link]) + end + + it 'does not create a reference for guest for a public snippet' do + expect(visible_references(:public, nil)).to be_empty + end + + it 'does not create a reference for a regular user for a public snippet' do + expect(visible_references(:public, user)).to be_empty + end + + it 'creates a reference for a project member for an internal snippet' do + expect(visible_references(:internal, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for an internal snippet' do + expect(visible_references(:internal, user)).to be_empty + end + + it 'creates a reference for a project member for a private snippet' do + expect(visible_references(:private, project_member)).to eq([link]) + end + + it 'does not create a reference for a regular user for a private snippet' do + expect(visible_references(:private, user)).to be_empty + end end end describe '#referenced_by' do + let(:snippet) { create(:snippet, project: project) } describe 'when the link has a data-snippet attribute' do context 'using an existing snippet ID' do it 'returns an Array of snippets' do @@ -31,7 +210,7 @@ describe Banzai::ReferenceParser::SnippetParser, lib: true do it 'returns an empty Array' do link['data-snippet'] = '' - expect(subject.referenced_by([link])).to eq([]) + expect(subject.referenced_by([link])).to be_empty end end end diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb index e1771b636b8..ddbed5f781e 100644 --- a/spec/policies/project_snippet_policy_spec.rb +++ b/spec/policies/project_snippet_policy_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe ProjectSnippetPolicy, models: true do let(:regular_user) { create(:user) } let(:external_user) { create(:user, :external) } - let(:project) { create(:empty_project) } + let(:project) { create(:empty_project, :public) } let(:author_permissions) do [ @@ -107,7 +107,7 @@ describe ProjectSnippetPolicy, models: true do end context 'snippet author' do - let(:snippet) { create(:project_snippet, :private, author: regular_user) } + let(:snippet) { create(:project_snippet, :private, author: regular_user, project: project) } subject { described_class.abilities(regular_user, snippet).to_set } -- cgit v1.2.3 From c3d5faa0ee1ed4df484eb9f494e008e08ced8b52 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Thu, 8 Jun 2017 14:03:08 -0300 Subject: Use RequestStore on MR show.json query count spec --- spec/controllers/projects/merge_requests_controller_spec.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 08024a2148b..0a64fe2beda 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -121,13 +121,18 @@ describe Projects::MergeRequestsController do context 'number of queries' do it 'verifies number of queries' do + RequestStore.begin! + # pre-create objects merge_request recorded = ActiveRecord::QueryRecorder.new { go(format: :json) } - expect(recorded.count).to be_within(5).of(50) + expect(recorded.count).to be_within(5).of(30) expect(recorded.cached_count).to eq(0) + + RequestStore.end! + RequestStore.clear! end end end -- cgit v1.2.3 From dfa4a440f032020cf000841d7e1c799d142f92c8 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 8 Jun 2017 16:48:29 +0100 Subject: Fixed dropdown filter input not focusing after transition Closes #33216 --- spec/javascripts/gl_dropdown_spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/gl_dropdown_spec.js b/spec/javascripts/gl_dropdown_spec.js index 3292590b9ed..10fcc590c89 100644 --- a/spec/javascripts/gl_dropdown_spec.js +++ b/spec/javascripts/gl_dropdown_spec.js @@ -185,7 +185,7 @@ import '~/lib/utils/url_utility'; expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); }); - it('should focus on input when opening for the second time', () => { + it('should focus on input when opening for the second time after transition', () => { remoteCallback(); this.dropdownContainerElement.trigger({ type: 'keyup', @@ -193,6 +193,7 @@ import '~/lib/utils/url_utility'; keyCode: ARROW_KEYS.ESC }); this.dropdownButtonElement.click(); + this.dropdownContainerElement.trigger('transitionend'); expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); }); }); @@ -201,6 +202,7 @@ import '~/lib/utils/url_utility'; it('should focus input when passing array data to drop down', () => { initDropDown.call(this, false, true); this.dropdownButtonElement.click(); + this.dropdownContainerElement.trigger('transitionend'); expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR)); }); }); -- cgit v1.2.3 From 370bc86fb007c1683495bdf4082bf5442b517895 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 7 Jun 2017 16:07:57 -0500 Subject: Detect if file that appears to be text in the first 1024 bytes is actually binary afer loading all data --- spec/features/projects/blobs/blob_show_spec.rb | 37 +++++++++++++++++++++++--- spec/models/blob_viewer/base_spec.rb | 4 +-- 2 files changed, 36 insertions(+), 5 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb index 82cfbfda157..45fdb36e506 100644 --- a/spec/features/projects/blobs/blob_show_spec.rb +++ b/spec/features/projects/blobs/blob_show_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' feature 'File blob', :js, feature: true do let(:project) { create(:project, :public) } - def visit_blob(path, fragment = nil) - visit namespace_project_blob_path(project.namespace, project, File.join('master', path), anchor: fragment) + def visit_blob(path, anchor: nil, ref: 'master') + visit namespace_project_blob_path(project.namespace, project, File.join(ref, path), anchor: anchor) wait_for_requests end @@ -101,7 +101,7 @@ feature 'File blob', :js, feature: true do context 'visiting with a line number anchor' do before do - visit_blob('files/markdown/ruby-style-guide.md', 'L1') + visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1') end it 'displays the blob using the simple viewer' do @@ -352,6 +352,37 @@ feature 'File blob', :js, feature: true do end end + context 'binary file that appears to be text in the first 1024 bytes' do + before do + visit_blob('encoding/binary-1.bin', ref: 'binary-encoding') + end + + it 'displays the blob' do + aggregate_failures do + # shows a download link + expect(page).to have_link('Download (23.8 KB)') + + # does not show a viewer switcher + expect(page).not_to have_selector('.js-blob-viewer-switcher') + + # The specs below verify an arguably incorrect result, but since we only + # learn that the file is not actually text once the text viewer content + # is loaded asynchronously, there is no straightforward way to get these + # synchronously loaded elements to display correctly. + # + # Clicking the copy button will result in nothing being copied. + # Clicking the raw button will result in the binary file being downloaded, + # as expected. + + # shows an enabled copy button, incorrectly + expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') + + # shows a raw button, incorrectly + expect(page).to have_link('Open raw') + end + end + end + context '.gitlab-ci.yml' do before do project.add_master(project.creator) diff --git a/spec/models/blob_viewer/base_spec.rb b/spec/models/blob_viewer/base_spec.rb index d56379eb59d..574438838d8 100644 --- a/spec/models/blob_viewer/base_spec.rb +++ b/spec/models/blob_viewer/base_spec.rb @@ -106,9 +106,9 @@ describe BlobViewer::Base, model: true do end describe '#render_error' do - context 'when expanded' do + context 'when the blob is expanded' do before do - viewer.expanded = true + blob.expand! end context 'when the blob size is larger than the size limit' do -- cgit v1.2.3 From 4bfd06e60e22a8100eddc2391d4842a8b6e53a6f Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Thu, 8 Jun 2017 18:09:04 +0200 Subject: Display issue state in issue links section of merge request widget --- spec/presenters/merge_request_presenter_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'spec') diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb index 44720fc4448..f5a14b1d04d 100644 --- a/spec/presenters/merge_request_presenter_spec.rb +++ b/spec/presenters/merge_request_presenter_spec.rb @@ -132,6 +132,11 @@ describe MergeRequestPresenter do it 'does not present related issues links' do is_expected.not_to match("#{project.full_path}/issues/#{issue_b.iid}") end + + it 'appends status when closing issue is already closed' do + issue_a.close + is_expected.to match('(closed)') + end end describe '#mentioned_issues_links' do @@ -147,6 +152,11 @@ describe MergeRequestPresenter do it 'does not present closing issues links' do is_expected.not_to match("#{project.full_path}/issues/#{issue_a.iid}") end + + it 'appends status when mentioned issue is already closed' do + issue_b.close + is_expected.to match('(closed)') + end end describe '#assign_to_closing_issues_link' do -- cgit v1.2.3 From 7188b4d83989dcfcc672f88e19d1ddb550b4917a Mon Sep 17 00:00:00 2001 From: Toon Claes Date: Thu, 8 Jun 2017 15:43:06 +0200 Subject: Make the revision on the `/help` page clickable For quicker access, add hyperlink to the gitlab.com commits page for the current REVISION of GitLab. --- spec/views/help/index.html.haml_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/views/help/index.html.haml_spec.rb b/spec/views/help/index.html.haml_spec.rb index 6b07fcfc987..1f8261cc46b 100644 --- a/spec/views/help/index.html.haml_spec.rb +++ b/spec/views/help/index.html.haml_spec.rb @@ -21,7 +21,7 @@ describe 'help/index' do render expect(rendered).to match '8.0.2' - expect(rendered).to match 'abcdefg' + expect(rendered).to have_link('abcdefg', 'https://gitlab.com/gitlab-org/gitlab-ce/commits/abcdefg') end end -- cgit v1.2.3 From c0c82368da57caac07f25227dac74d9c119b806e Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 8 Jun 2017 17:43:05 +0100 Subject: Fixed dashboard milestone tabs not loading Closes #33477 --- .../dashboard/milestones_controller_spec.rb | 38 ++++++++++++++++++++ spec/features/dashboard/milestone_tabs_spec.rb | 40 ++++++++++++++++++++++ spec/support/milestone_tabs_examples.rb | 14 +++++--- 3 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 spec/controllers/dashboard/milestones_controller_spec.rb create mode 100644 spec/features/dashboard/milestone_tabs_spec.rb (limited to 'spec') diff --git a/spec/controllers/dashboard/milestones_controller_spec.rb b/spec/controllers/dashboard/milestones_controller_spec.rb new file mode 100644 index 00000000000..424f39fd3b8 --- /dev/null +++ b/spec/controllers/dashboard/milestones_controller_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +describe Dashboard::MilestonesController do + let(:project) { create(:empty_project) } + let(:user) { create(:user) } + let(:project_milestone) { create(:milestone, project: project) } + let(:milestone) do + DashboardMilestone.build( + [project], + project_milestone.title + ) + end + let(:issue) { create(:issue, project: project, milestone: project_milestone) } + let!(:label) { create(:label, project: project, title: 'Issue Label', issues: [issue]) } + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: project_milestone) } + let(:milestone_path) { dashboard_milestone_path(milestone.safe_title, title: milestone.title) } + + before do + sign_in(user) + project.team << [user, :master] + end + + it_behaves_like 'milestone tabs' + + describe "#show" do + render_views + + def view_milestone + get :show, id: milestone.safe_title, title: milestone.title + end + + it 'shows milestone page' do + view_milestone + + expect(response).to have_http_status(200) + end + end +end diff --git a/spec/features/dashboard/milestone_tabs_spec.rb b/spec/features/dashboard/milestone_tabs_spec.rb new file mode 100644 index 00000000000..0c7b992c500 --- /dev/null +++ b/spec/features/dashboard/milestone_tabs_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe 'Dashboard milestone tabs', :js, :feature do + let(:user) { create(:user) } + let(:project) { create(:empty_project) } + let!(:label) { create(:label, project: project) } + let(:project_milestone) { create(:milestone, project: project) } + let(:milestone) do + DashboardMilestone.build( + [project], + project_milestone.title + ) + end + let!(:merge_request) { create(:labeled_merge_request, source_project: project, target_project: project, milestone: project_milestone, labels: [label]) } + + before do + project.add_master(user) + login_as(user) + + visit dashboard_milestone_path(milestone.safe_title, title: milestone.title) + end + + it 'loads merge requests async' do + click_link 'Merge Requests' + + expect(page).to have_selector('.merge_requests-sortable-list') + end + + it 'loads participants async' do + click_link 'Participants' + + expect(page).to have_selector('#tab-participants .bordered-list') + end + + it 'loads labels async' do + click_link 'Labels' + + expect(page).to have_selector('#tab-labels .bordered-list') + end +end diff --git a/spec/support/milestone_tabs_examples.rb b/spec/support/milestone_tabs_examples.rb index 4ad8b0a16e1..7cfc1e06975 100644 --- a/spec/support/milestone_tabs_examples.rb +++ b/spec/support/milestone_tabs_examples.rb @@ -1,10 +1,14 @@ shared_examples 'milestone tabs' do def go(path, extra_params = {}) - params = if milestone.is_a?(GlobalMilestone) - { group_id: group.to_param, id: milestone.safe_title, title: milestone.title } - else - { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid } - end + params = + case milestone + when DashboardMilestone + { id: milestone.safe_title, title: milestone.title } + when GroupMilestone + { group_id: group.to_param, id: milestone.safe_title, title: milestone.title } + else + { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid } + end get path, params.merge(extra_params) end -- cgit v1.2.3 From 519ffaeb7afb563adf544acb29b0ab46c59ce728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 9 Jun 2017 13:12:42 +0200 Subject: Ensure wiki is created before we visit the Wiki page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :facepalm: Signed-off-by: Rémy Coutable --- spec/features/projects/wiki/markdown_preview_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb index 49d7ef09e64..94f6bb16730 100644 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ b/spec/features/projects/wiki/markdown_preview_spec.rb @@ -14,11 +14,12 @@ feature 'Projects > Wiki > User previews markdown changes', feature: true, js: t background do project.team << [user, :master] + WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute + login_as(user) visit namespace_project_path(project.namespace, project) find('.shortcuts-wiki').trigger('click') - WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute end context "while creating a new wiki page" do -- cgit v1.2.3 From b38c74d696a8592878d92f8d40c8c3e1b42678b1 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 8 Jun 2017 10:33:25 -0500 Subject: Revert 'New file from interface on existing branch' --- .../projects/branches_controller_spec.rb | 14 --- spec/features/projects/blobs/edit_spec.rb | 6 +- spec/features/projects/blobs/user_create_spec.rb | 94 ---------------- spec/features/projects/user_create_dir_spec.rb | 16 +-- .../blob/create_branch_dropdown_spec.js | 106 ------------------ .../blob/target_branch_dropdown_spec.js | 118 --------------------- spec/javascripts/fixtures/project_branches.json | 5 - .../fixtures/target_branch_dropdown.html.haml | 28 ----- spec/support/target_branch_helpers.rb | 16 --- 9 files changed, 4 insertions(+), 399 deletions(-) delete mode 100644 spec/features/projects/blobs/user_create_spec.rb delete mode 100644 spec/javascripts/blob/create_branch_dropdown_spec.js delete mode 100644 spec/javascripts/blob/target_branch_dropdown_spec.js delete mode 100644 spec/javascripts/fixtures/project_branches.json delete mode 100644 spec/javascripts/fixtures/target_branch_dropdown.html.haml delete mode 100644 spec/support/target_branch_helpers.rb (limited to 'spec') diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index f285e5333d6..f9e21f9d8f6 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -367,19 +367,5 @@ describe Projects::BranchesController do expect(parsed_response.first).to eq 'master' end end - - context 'show_all = true' do - it 'returns all the branches name' do - get :index, - namespace_id: project.namespace, - project_id: project, - format: :json, - show_all: true - - parsed_response = JSON.parse(response.body) - - expect(parsed_response.length).to eq(project.repository.branches.count) - end - end end end diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb index 1a38997450d..d04c3248ead 100644 --- a/spec/features/projects/blobs/edit_spec.rb +++ b/spec/features/projects/blobs/edit_spec.rb @@ -102,7 +102,7 @@ feature 'Editing file blob', feature: true, js: true do it 'shows blob editor with same branch' do expect(page).to have_current_path(namespace_project_edit_blob_path(project.namespace, project, tree_join(branch, file_path))) - expect(find('.js-target-branch .dropdown-toggle-text').text).to eq(branch) + expect(find('.js-branch-name').value).to eq(branch) end end @@ -112,7 +112,7 @@ feature 'Editing file blob', feature: true, js: true do end it 'shows blob editor with patch branch' do - expect(find('.js-target-branch .dropdown-toggle-text').text).to eq('patch-1') + expect(find('.js-branch-name').value).to eq('patch-1') end end end @@ -128,7 +128,7 @@ feature 'Editing file blob', feature: true, js: true do it 'shows blob editor with same branch' do expect(page).to have_current_path(namespace_project_edit_blob_path(project.namespace, project, tree_join(branch, file_path))) - expect(find('.js-target-branch .dropdown-toggle-text').text).to eq(branch) + expect(find('.js-branch-name').value).to eq(branch) end end end diff --git a/spec/features/projects/blobs/user_create_spec.rb b/spec/features/projects/blobs/user_create_spec.rb deleted file mode 100644 index 4b6c55f5f44..00000000000 --- a/spec/features/projects/blobs/user_create_spec.rb +++ /dev/null @@ -1,94 +0,0 @@ -require 'spec_helper' - -feature 'New blob creation', feature: true, js: true do - include TargetBranchHelpers - - given(:user) { create(:user) } - given(:role) { :developer } - given(:project) { create(:project) } - given(:content) { 'class NextFeature\nend\n' } - - background do - login_as(user) - project.team << [user, role] - visit namespace_project_new_blob_path(project.namespace, project, 'master') - end - - def edit_file - wait_for_requests - fill_in 'file_name', with: 'feature.rb' - execute_script("ace.edit('editor').setValue('#{content}')") - end - - def commit_file - click_button 'Commit changes' - end - - context 'with default target branch' do - background do - edit_file - commit_file - end - - scenario 'creates the blob in the default branch' do - expect(page).to have_content 'master' - expect(page).to have_content 'successfully created' - expect(page).to have_content 'NextFeature' - end - end - - context 'with different target branch' do - background do - edit_file - select_branch('feature') - commit_file - end - - scenario 'creates the blob in the different branch' do - expect(page).to have_content 'feature' - expect(page).to have_content 'successfully created' - end - end - - context 'with a new target branch' do - given(:new_branch_name) { 'new-feature' } - - background do - edit_file - create_new_branch(new_branch_name) - commit_file - end - - scenario 'creates the blob in the new branch' do - expect(page).to have_content new_branch_name - expect(page).to have_content 'successfully created' - end - scenario 'returns you to the mr' do - expect(page).to have_content 'New Merge Request' - expect(page).to have_content "From #{new_branch_name} into master" - expect(page).to have_content 'Add new file' - end - end - - context 'the file already exist in the source branch' do - background do - Files::CreateService.new( - project, - user, - start_branch: 'master', - branch_name: 'master', - commit_message: 'Create file', - file_path: 'feature.rb', - file_content: content - ).execute - edit_file - commit_file - end - - scenario 'shows error message' do - expect(page).to have_content('A file with this name already exists') - expect(page).to have_content('New file') - expect(page).to have_content('NextFeature') - end - end -end diff --git a/spec/features/projects/user_create_dir_spec.rb b/spec/features/projects/user_create_dir_spec.rb index 5dfdc465d7d..aeb7e0b7c33 100644 --- a/spec/features/projects/user_create_dir_spec.rb +++ b/spec/features/projects/user_create_dir_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' feature 'New directory creation', feature: true, js: true do - include TargetBranchHelpers - given(:user) { create(:user) } given(:role) { :developer } given(:project) { create(:project) } @@ -36,23 +34,11 @@ feature 'New directory creation', feature: true, js: true do end end - context 'with different target branch' do - background do - select_branch('feature') - create_directory - end - - scenario 'creates the directory in the different branch' do - expect(page).to have_content 'feature' - expect(page).to have_content 'The directory has been successfully created' - end - end - context 'with a new target branch' do given(:new_branch_name) { 'new-feature' } background do - create_new_branch(new_branch_name) + fill_in :branch_name, with: new_branch_name create_directory end diff --git a/spec/javascripts/blob/create_branch_dropdown_spec.js b/spec/javascripts/blob/create_branch_dropdown_spec.js deleted file mode 100644 index 6dbaa47c544..00000000000 --- a/spec/javascripts/blob/create_branch_dropdown_spec.js +++ /dev/null @@ -1,106 +0,0 @@ -import '~/gl_dropdown'; -import '~/blob/create_branch_dropdown'; -import '~/blob/target_branch_dropdown'; - -describe('CreateBranchDropdown', () => { - const fixtureTemplate = 'static/target_branch_dropdown.html.raw'; - // selectors - const createBranchSel = '.js-new-branch-btn'; - const backBtnSel = '.dropdown-menu-back'; - const cancelBtnSel = '.js-cancel-branch-btn'; - const branchNameSel = '#new_branch_name'; - const branchName = 'new_name'; - let dropdown; - - function createDropdown() { - const dropdownEl = document.querySelector('.js-project-branches-dropdown'); - const projectBranches = getJSONFixture('project_branches.json'); - dropdown = new gl.TargetBranchDropDown(dropdownEl); - dropdown.cachedRefs = projectBranches; - return dropdown; - } - - function createBranchBtn() { - return document.querySelector(createBranchSel); - } - - function backBtn() { - return document.querySelector(backBtnSel); - } - - function cancelBtn() { - return document.querySelector(cancelBtnSel); - } - - function branchNameEl() { - return document.querySelector(branchNameSel); - } - - function changeBranchName(text) { - branchNameEl().value = text; - branchNameEl().dispatchEvent(new Event('change')); - } - - preloadFixtures(fixtureTemplate); - - beforeEach(() => { - loadFixtures(fixtureTemplate); - createDropdown(); - }); - - it('disable submit when branch name is empty', () => { - expect(createBranchBtn()).toBeDisabled(); - }); - - it('enable submit when branch name is present', () => { - changeBranchName(branchName); - - expect(createBranchBtn()).not.toBeDisabled(); - }); - - it('resets the form when cancel btn is clicked and triggers dropdownback', () => { - const spyBackEvent = spyOnEvent(backBtnSel, 'click'); - changeBranchName(branchName); - - cancelBtn().click(); - - expect(branchNameEl()).toHaveValue(''); - expect(spyBackEvent).toHaveBeenTriggered(); - }); - - it('resets the form when back btn is clicked', () => { - changeBranchName(branchName); - - backBtn().click(); - - expect(branchNameEl()).toHaveValue(''); - }); - - describe('new branch creation', () => { - beforeEach(() => { - changeBranchName(branchName); - }); - it('sets the new branch name and updates the dropdown', () => { - spyOn(dropdown, 'setNewBranch'); - - createBranchBtn().click(); - - expect(dropdown.setNewBranch).toHaveBeenCalledWith(branchName); - }); - - it('resets the form', () => { - createBranchBtn().click(); - - expect(branchNameEl()).toHaveValue(''); - }); - - it('is triggered with enter keypress', () => { - spyOn(dropdown, 'setNewBranch'); - const enterEvent = new Event('keydown'); - enterEvent.which = 13; - branchNameEl().dispatchEvent(enterEvent); - - expect(dropdown.setNewBranch).toHaveBeenCalledWith(branchName); - }); - }); -}); diff --git a/spec/javascripts/blob/target_branch_dropdown_spec.js b/spec/javascripts/blob/target_branch_dropdown_spec.js deleted file mode 100644 index 99c9537d2ec..00000000000 --- a/spec/javascripts/blob/target_branch_dropdown_spec.js +++ /dev/null @@ -1,118 +0,0 @@ -import '~/gl_dropdown'; -import '~/blob/create_branch_dropdown'; -import '~/blob/target_branch_dropdown'; - -describe('TargetBranchDropdown', () => { - const fixtureTemplate = 'static/target_branch_dropdown.html.raw'; - let dropdown; - - function createDropdown() { - const projectBranches = getJSONFixture('project_branches.json'); - const dropdownEl = document.querySelector('.js-project-branches-dropdown'); - dropdown = new gl.TargetBranchDropDown(dropdownEl); - dropdown.cachedRefs = projectBranches; - dropdown.refreshData(); - return dropdown; - } - - function submitBtn() { - return document.querySelector('button[type="submit"]'); - } - - function searchField() { - return document.querySelector('.dropdown-page-one .dropdown-input-field'); - } - - function element() { - return document.querySelectorAll('div.dropdown-content li a'); - } - - function elementAtIndex(index) { - return element()[index]; - } - - function clickElementAtIndex(index) { - elementAtIndex(index).click(); - } - - preloadFixtures(fixtureTemplate); - - beforeEach(() => { - loadFixtures(fixtureTemplate); - createDropdown(); - }); - - it('disable submit when branch is not selected', () => { - document.querySelector('input[name="target_branch"]').value = null; - clickElementAtIndex(1); - - expect(submitBtn().getAttribute('disabled')).toEqual(''); - }); - - it('enable submit when a branch is selected', () => { - clickElementAtIndex(1); - - expect(submitBtn().getAttribute('disabled')).toBe(null); - }); - - it('triggers change.branch event on a branch click', () => { - spyOnEvent(dropdown.$dropdown, 'change.branch'); - clickElementAtIndex(0); - - expect('change.branch').toHaveBeenTriggeredOn(dropdown.$dropdown); - }); - - describe('dropdownData', () => { - it('cache the refs', () => { - const refs = dropdown.cachedRefs; - dropdown.cachedRefs = null; - - dropdown.dropdownData(refs); - - expect(dropdown.cachedRefs).toEqual(refs); - }); - - it('returns the Branches with the newBranch and defaultBranch', () => { - const refs = dropdown.cachedRefs; - dropdown.branchInput.value = 'master'; - dropdown.newBranch = { id: 'new_branch', text: 'new_branch', title: 'new_branch' }; - - const branches = dropdown.dropdownData(refs).Branches; - - expect(branches.length).toEqual(4); - expect(branches[0]).toEqual(dropdown.newBranch); - expect(branches[1]).toEqual({ id: 'master', text: 'master', title: 'master' }); - expect(branches[2]).toEqual({ id: 'development', text: 'development', title: 'development' }); - expect(branches[3]).toEqual({ id: 'staging', text: 'staging', title: 'staging' }); - }); - }); - - describe('setNewBranch', () => { - it('adds the new branch and select it', () => { - const branchName = 'new_branch'; - - dropdown.setNewBranch(branchName); - - expect(elementAtIndex(0)).toHaveClass('is-active'); - expect(elementAtIndex(0)).toContainHtml(branchName); - }); - - it("doesn't add a new branch if already exists in the list", () => { - const branchName = elementAtIndex(0).text; - const initialLength = element().length; - - dropdown.setNewBranch(branchName); - - expect(element().length).toEqual(initialLength); - }); - - it('clears the search filter', () => { - const branchName = elementAtIndex(0).text; - searchField().value = 'searching'; - - dropdown.setNewBranch(branchName); - - expect(searchField().value).toEqual(''); - }); - }); -}); diff --git a/spec/javascripts/fixtures/project_branches.json b/spec/javascripts/fixtures/project_branches.json deleted file mode 100644 index a96a4c0c095..00000000000 --- a/spec/javascripts/fixtures/project_branches.json +++ /dev/null @@ -1,5 +0,0 @@ -[ - "master", - "development", - "staging" -] diff --git a/spec/javascripts/fixtures/target_branch_dropdown.html.haml b/spec/javascripts/fixtures/target_branch_dropdown.html.haml deleted file mode 100644 index 821fb7940a0..00000000000 --- a/spec/javascripts/fixtures/target_branch_dropdown.html.haml +++ /dev/null @@ -1,28 +0,0 @@ -%form.js-edit-blob-form - %input{type: 'hidden', name: 'target_branch', value: 'master'} - %div - .dropdown - %button.dropdown-menu-toggle.js-project-branches-dropdown.js-target-branch{type: 'button', data: {toggle: 'dropdown', selected: 'master', field_name: 'target_branch', form_id: '.js-edit-blob-form'}} - .dropdown-menu.dropdown-menu-selectable.dropdown-menu-paging - .dropdown-page-one - .dropdown-title 'Select branch' - .dropdown-input - %input.dropdown-input-field{type: 'search', value: ''} - %i.fa.fa-search.dropdown-input-search - %i.fa.fa-times-dropdown-input-clear.js-dropdown-input-clear{role: 'button'} - .dropdown-content - .dropdown-footer - %ul.dropdown-footer-list - %li - %a.create-new-branch.dropdown-toggle-page{href: "#"} - Create new branch - .dropdown-page-two.dropdown-new-branch - %button.dropdown-title-button.dropdown-menu-back{type: 'button'} - .dropdown_title 'Create new branch' - .dropdown_content - %input#new_branch_name.default-dropdown-input{ type: "text", placeholder: "Name new branch" } - %button.btn.btn-primary.pull-left.js-new-branch-btn{ type: "button" } - Create - %button.btn.btn-default.pull-right.js-cancel-branch-btn{ type: "button" } - Cancel - %button{type: 'submit'} diff --git a/spec/support/target_branch_helpers.rb b/spec/support/target_branch_helpers.rb deleted file mode 100644 index 01d1c53fe6c..00000000000 --- a/spec/support/target_branch_helpers.rb +++ /dev/null @@ -1,16 +0,0 @@ -module TargetBranchHelpers - def select_branch(name) - first('button.js-target-branch').click - wait_for_requests - all('a[data-group="Branches"]').find do |el| - el.text == name - end.click - end - - def create_new_branch(name) - first('button.js-target-branch').click - click_link 'Create new branch' - fill_in 'new_branch_name', with: name - click_button 'Create' - end -end -- cgit v1.2.3 From 54c04f53fddc36d62a3d3d4125c9fe205138fc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 7 Jun 2017 21:45:03 +0200 Subject: Fix spec failures and add a feature flag for the performance bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/models/commit_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 140fd2720bf..3905240f48d 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -21,7 +21,7 @@ describe Commit, models: true do it 'caches the author' do user = create(:user, email: commit.author_email) - expect(RequestStore).to receive(:active?).twice.and_return(true) + expect(RequestStore).to receive(:active?).and_return(true) expect_any_instance_of(Commit).to receive(:find_author_by_any_email).and_call_original expect(commit.author).to eq(user) -- cgit v1.2.3 From b173ae6b48323b22f5650e97cd797fa9c49e6cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 7 Jun 2017 23:51:13 +0200 Subject: Fix linting, route, and specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/models/commit_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 3905240f48d..ba247dcc5cf 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -20,8 +20,8 @@ describe Commit, models: true do end it 'caches the author' do + allow(RequestStore).to receive(:active?).and_return(true) user = create(:user, email: commit.author_email) - expect(RequestStore).to receive(:active?).and_return(true) expect_any_instance_of(Commit).to receive(:find_author_by_any_email).and_call_original expect(commit.author).to eq(user) -- cgit v1.2.3 From 058aeb1ce7e45baf7ebb16a435924554501712ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 8 Jun 2017 14:59:55 +0200 Subject: Add a feature spec for the performance bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- .../user_can_display_performance_bar_spec.rb | 81 ++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 spec/features/user_can_display_performance_bar_spec.rb (limited to 'spec') diff --git a/spec/features/user_can_display_performance_bar_spec.rb b/spec/features/user_can_display_performance_bar_spec.rb new file mode 100644 index 00000000000..c2842255b86 --- /dev/null +++ b/spec/features/user_can_display_performance_bar_spec.rb @@ -0,0 +1,81 @@ +require 'rails_helper' + +describe 'User can display performacne bar', :js do + shared_examples 'performance bar is disabled' do + it 'does not show the performance bar by default' do + expect(page).not_to have_css('#peek') + end + + context 'when user press `pb`' do + before do + find('body').native.send_keys('pb') + end + + it 'does not show the performance bar by default' do + expect(page).not_to have_css('#peek') + end + end + end + + shared_examples 'performance bar is enabled' do + it 'does not show the performance bar by default' do + expect(page).not_to have_css('#peek') + end + + context 'when user press `pb`' do + before do + find('body').native.send_keys('pb') + end + + it 'does not show the performance bar by default' do + expect(page).not_to have_css('#peek') + end + end + end + + context 'when user is logged-out' do + before do + visit root_path + end + + context 'when the gitlab_performance_bar feature is disabled' do + before do + Feature.disable('gitlab_performance_bar') + end + + it_behaves_like 'performance bar is disabled' + end + + context 'when the gitlab_performance_bar feature is enabled' do + before do + Feature.enable('gitlab_performance_bar') + end + + it_behaves_like 'performance bar is disabled' + end + end + + context 'when user is logged-in' do + before do + login_as :user + + visit root_path + end + + context 'when the gitlab_performance_bar feature is disabled' do + before do + Feature.disable('gitlab_performance_bar') + end + + it_behaves_like 'performance bar is disabled' + end + + context 'when the gitlab_performance_bar feature is enabled' do + before do + Feature.enable('gitlab_performance_bar') + end + + it_behaves_like 'performance bar is enabled' + end + end +end -- cgit v1.2.3 From 4ccd79983274442ca21e6c73ef0863097b57350c Mon Sep 17 00:00:00 2001 From: vanadium23 Date: Fri, 9 Jun 2017 22:49:57 +0300 Subject: Accept image for avatar in project API --- spec/requests/api/projects_spec.rb | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'spec') diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 86c57204971..3e831373514 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -398,6 +398,15 @@ describe API::Projects do expect(json_response['tag_list']).to eq(%w[tagFirst tagSecond]) end + it 'uploads avatar for project a project' do + project = attributes_for(:project, avatar: fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif')) + + post api('/projects', user), project + + project_id = json_response['id'] + expect(json_response['avatar_url']).to eq("http://localhost/uploads/system/project/avatar/#{project_id}/banana_sample.gif") + end + it 'sets a project as allowing merge even if build fails' do project = attributes_for(:project, { only_allow_merge_if_pipeline_succeeds: false }) post api('/projects', user), project -- cgit v1.2.3 From 34ba80392dd23614f60a759ec41b4df1f2915f49 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Fri, 9 Jun 2017 14:12:51 -0300 Subject: Use :request_store hooks on specs --- spec/controllers/projects/jobs_controller_spec.rb | 11 ++--------- spec/controllers/projects/merge_requests_controller_spec.rb | 7 +------ spec/controllers/projects/pipelines_controller_spec.rb | 9 +-------- spec/lib/banzai/filter/abstract_reference_filter_spec.rb | 11 +---------- spec/lib/banzai/issuable_extractor_spec.rb | 11 +---------- spec/lib/banzai/reference_parser/user_parser_spec.rb | 11 +---------- spec/models/concerns/routable_spec.rb | 11 +---------- spec/models/project_team_spec.rb | 11 +---------- spec/serializers/pipeline_serializer_spec.rb | 11 ++--------- spec/spec_helper.rb | 9 +++++++++ 10 files changed, 20 insertions(+), 82 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 7211acc53dc..4a737587899 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -69,18 +69,11 @@ describe Projects::JobsController do Ci::Build::AVAILABLE_STATUSES.each do |status| create_build(status, status) end - - RequestStore.begin! - end - - after do - RequestStore.end! - RequestStore.clear! end - it "verifies number of queries" do + it 'verifies number of queries', :request_store do recorded = ActiveRecord::QueryRecorder.new { get_index } - expect(recorded.count).to be_within(5).of(8) + expect(recorded.count).to be_within(5).of(7) end def create_build(name, status) diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 0a64fe2beda..6e1c91738db 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -119,10 +119,8 @@ describe Projects::MergeRequestsController do end end - context 'number of queries' do + context 'number of queries', :request_store do it 'verifies number of queries' do - RequestStore.begin! - # pre-create objects merge_request @@ -130,9 +128,6 @@ describe Projects::MergeRequestsController do expect(recorded.count).to be_within(5).of(30) expect(recorded.cached_count).to eq(0) - - RequestStore.end! - RequestStore.clear! end end end diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index c880da1e36a..954f89e3854 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -49,21 +49,14 @@ describe Projects::PipelinesController do expect(json_response['details']).to have_key 'stages' end - context 'when the pipeline has multiple stages and groups' do + context 'when the pipeline has multiple stages and groups', :request_store do before do - RequestStore.begin! - create_build('build', 0, 'build') create_build('test', 1, 'rspec 0') create_build('deploy', 2, 'production') create_build('post deploy', 3, 'pages 0') end - after do - RequestStore.end! - RequestStore.clear! - end - let(:project) { create(:project) } let(:pipeline) do create(:ci_empty_pipeline, project: project, user: user, sha: project.commit.id) diff --git a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb index 27684882435..787c2372c5b 100644 --- a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb @@ -47,16 +47,7 @@ describe Banzai::Filter::AbstractReferenceFilter do end end - context 'with RequestStore enabled' do - before do - RequestStore.begin! - end - - after do - RequestStore.end! - RequestStore.clear! - end - + context 'with RequestStore enabled', :request_store do it 'returns a list of Projects for a list of paths' do expect(filter.find_projects_for_paths([project.path_with_namespace])). to eq([project]) diff --git a/spec/lib/banzai/issuable_extractor_spec.rb b/spec/lib/banzai/issuable_extractor_spec.rb index e5d332efb08..866297f94a9 100644 --- a/spec/lib/banzai/issuable_extractor_spec.rb +++ b/spec/lib/banzai/issuable_extractor_spec.rb @@ -29,16 +29,7 @@ describe Banzai::IssuableExtractor, lib: true do expect(result).to eq(issue_link => issue, merge_request_link => merge_request) end - describe 'caching' do - before do - RequestStore.begin! - end - - after do - RequestStore.end! - RequestStore.clear! - end - + describe 'caching', :request_store do it 'saves records to cache' do extractor.extract([issue_link, merge_request_link]) diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb index 592ed0d2b98..4d560667342 100644 --- a/spec/lib/banzai/reference_parser/user_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb @@ -43,18 +43,9 @@ describe Banzai::ReferenceParser::UserParser, lib: true do expect(subject.referenced_by([link])).to eq([user]) end - context 'when RequestStore is active' do + context 'when RequestStore is active', :request_store do let(:other_user) { create(:user) } - before do - RequestStore.begin! - end - - after do - RequestStore.end! - RequestStore.clear! - end - it 'does not return users from the first call in the second' do link['data-user'] = user.id.to_s diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb index 0e10d91836d..65f05121b40 100644 --- a/spec/models/concerns/routable_spec.rb +++ b/spec/models/concerns/routable_spec.rb @@ -122,16 +122,7 @@ describe Group, 'Routable' do it { expect(group.full_path).to eq(group.path) } it { expect(nested_group.full_path).to eq("#{group.full_path}/#{nested_group.path}") } - context 'with RequestStore active' do - before do - RequestStore.begin! - end - - after do - RequestStore.end! - RequestStore.clear! - end - + context 'with RequestStore active', :request_store do it 'does not load the route table more than once' do expect(group).to receive(:uncached_full_path).once.and_call_original diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 362565506e5..497e3cdf415 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -389,16 +389,7 @@ describe ProjectTeam, models: true do end describe '#max_member_access_for_user_ids' do - context 'with RequestStore enabled' do - before do - RequestStore.begin! - end - - after do - RequestStore.end! - RequestStore.clear! - end - + context 'with RequestStore enabled', :request_store do include_examples 'max member access for users' def access_levels(users) diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 088f24eb180..34b19fb9fc4 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -102,18 +102,11 @@ describe PipelineSerializer do Ci::Pipeline::AVAILABLE_STATUSES.each do |status| create_pipeline(status) end - - RequestStore.begin! - end - - after do - RequestStore.end! - RequestStore.clear! end - it "verifies number of queries" do + it 'verifies number of queries', :request_store do recorded = ActiveRecord::QueryRecorder.new { subject } - expect(recorded.count).to be_within(1).of(60) + expect(recorded.count).to be_within(1).of(57) expect(recorded.cached_count).to eq(0) end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8b8fbf6e862..110428da794 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -74,6 +74,15 @@ RSpec.configure do |config| TestEnv.cleanup end + config.before(:example, :request_store) do + RequestStore.begin! + end + + config.after(:example, :request_store) do + RequestStore.end! + RequestStore.clear! + end + if ENV['CI'] # Retry only on feature specs that use JS config.around :each, :js do |ex| -- cgit v1.2.3 From f2dee8e8555409d3b1d333703581c6d62166cf83 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 9 Jun 2017 18:12:00 -0400 Subject: Test todos_count_format helper at the correct level to improve speed Instead of an integration test that creates 101 Todo records to test a simple view helper, just unit test the helper. --- spec/features/todos/todos_spec.rb | 23 ----------------------- spec/helpers/todos_helper_spec.rb | 13 +++++++++++++ 2 files changed, 13 insertions(+), 23 deletions(-) (limited to 'spec') diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb index bb4b2aed0e3..feb2fe8a7d1 100644 --- a/spec/features/todos/todos_spec.rb +++ b/spec/features/todos/todos_spec.rb @@ -333,29 +333,6 @@ describe 'Dashboard Todos', feature: true do end end - context 'User have large number of todos' do - before do - create_list(:todo, 101, :mentioned, user: user, project: project, target: issue, author: author) - - login_as(user) - visit dashboard_todos_path - end - - it 'shows 99+ for count >= 100 in notification' do - expect(page).to have_selector('.todos-count', text: '99+') - end - - it 'shows exact number in To do tab' do - expect(page).to have_selector('.todos-pending .badge', text: '101') - end - - it 'shows exact number for count < 100' do - 3.times { first('.js-done-todo').click } - - expect(page).to have_selector('.todos-count', text: '98') - end - end - context 'User has a Build Failed todo' do let!(:todo) { create(:todo, :build_failed, user: user, project: project, author: author) } diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb index 50060a0925d..18a41ca24e3 100644 --- a/spec/helpers/todos_helper_spec.rb +++ b/spec/helpers/todos_helper_spec.rb @@ -1,6 +1,19 @@ require "spec_helper" describe TodosHelper do + describe '#todos_count_format' do + it 'shows fuzzy count for 100 or more items' do + expect(helper.todos_count_format(100)).to eq '99+' + expect(helper.todos_count_format(1000)).to eq '99+' + end + + it 'shows exact count for 99 or fewer items' do + expect(helper.todos_count_format(99)).to eq '99' + expect(helper.todos_count_format(50)).to eq '50' + expect(helper.todos_count_format(1)).to eq '1' + end + end + describe '#todo_projects_options' do let(:projects) { create_list(:empty_project, 3) } let(:user) { create(:user) } -- cgit v1.2.3 From 9cf6adc111181d0ddc299d7a56e4dbd615607717 Mon Sep 17 00:00:00 2001 From: Jared Deckard Date: Thu, 8 Jun 2017 12:53:38 -0500 Subject: Fix incorrect spec description --- spec/services/system_note_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index c499b1bb343..9295c09aefc 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -1052,7 +1052,7 @@ describe SystemNoteService, services: true do let(:action) { 'task' } end - it "posts the 'marked as a Work In Progress from commit' system note" do + it "posts the 'marked the task as complete' system note" do expect(subject.note).to eq("marked the task **task** as completed") end end -- cgit v1.2.3 From a7e82cbd61c613ebd2d6a8efe464400d2da13faf Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sat, 10 Jun 2017 03:28:30 -0700 Subject: Make sure reCAPTCHA configuration is loaded when spam checks are initiated Previously it was possible when an issue was updated and Akismet flagged it as spam that the reCAPTCHA configuration was not loaded. Closes #33532 --- spec/controllers/projects/issues_controller_spec.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'spec') diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index a38ae2eb990..b65e9e0dfc0 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -260,6 +260,7 @@ describe Projects::IssuesController do before { allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) } it 'rejects an issue recognized as a spam' do + expect(Gitlab::Recaptcha).to receive(:load_configurations!).and_return(true) expect { update_spam_issue }.not_to change{ issue.reload.title } end -- cgit v1.2.3 From ef77fcf9d56d6f34541521ffbe5c1ca143f853b8 Mon Sep 17 00:00:00 2001 From: Jonas Kalderstam Date: Sun, 11 Jun 2017 17:05:23 +0200 Subject: Add test for u2f helper and changelog entry --- spec/helpers/u2f_helper_spec.rb | 49 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 spec/helpers/u2f_helper_spec.rb (limited to 'spec') diff --git a/spec/helpers/u2f_helper_spec.rb b/spec/helpers/u2f_helper_spec.rb new file mode 100644 index 00000000000..0d65b4fe0b8 --- /dev/null +++ b/spec/helpers/u2f_helper_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe U2fHelper do + describe 'when not on mobile' do + it 'does not inject u2f on chrome 40' do + device = double(mobile?: false) + browser = double(chrome?: true, opera?: false, version: 40, device: device) + allow(helper).to receive(:browser).and_return(browser) + expect(helper.inject_u2f_api?).to eq false + end + + it 'injects u2f on chrome 41' do + device = double(mobile?: false) + browser = double(chrome?: true, opera?: false, version: 41, device: device) + allow(helper).to receive(:browser).and_return(browser) + expect(helper.inject_u2f_api?).to eq true + end + + it 'does not inject u2f on opera 39' do + device = double(mobile?: false) + browser = double(chrome?: false, opera?: true, version: 39, device: device) + allow(helper).to receive(:browser).and_return(browser) + expect(helper.inject_u2f_api?).to eq false + end + + it 'injects u2f on opera 40' do + device = double(mobile?: false) + browser = double(chrome?: false, opera?: true, version: 40, device: device) + allow(helper).to receive(:browser).and_return(browser) + expect(helper.inject_u2f_api?).to eq true + end + end + + describe 'when on mobile' do + it 'does not inject u2f on chrome 41' do + device = double(mobile?: true) + browser = double(chrome?: true, opera?: false, version: 41, device: device) + allow(helper).to receive(:browser).and_return(browser) + expect(helper.inject_u2f_api?).to eq false + end + + it 'does not inject u2f on opera 40' do + device = double(mobile?: true) + browser = double(chrome?: false, opera?: true, version: 40, device: device) + allow(helper).to receive(:browser).and_return(browser) + expect(helper.inject_u2f_api?).to eq false + end + end +end -- cgit v1.2.3 From 5279a39e97e46aba4aad38adca8b9f9100a36c74 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 12 Jun 2017 07:48:54 +0000 Subject: Use vue files for navigation tabs and buttons --- spec/javascripts/pipelines/nav_controls_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/pipelines/nav_controls_spec.js b/spec/javascripts/pipelines/nav_controls_spec.js index 601eebce38a..f1697840fcd 100644 --- a/spec/javascripts/pipelines/nav_controls_spec.js +++ b/spec/javascripts/pipelines/nav_controls_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import navControlsComp from '~/pipelines/components/nav_controls'; +import navControlsComp from '~/pipelines/components/nav_controls.vue'; describe('Pipelines Nav Controls', () => { let NavControlsComponent; -- cgit v1.2.3 From 3a33665c9cb768584ce6296b3bacf34a285e0ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 9 Jun 2017 19:08:40 +0200 Subject: Attempts to run RSpec tests twice (1 retry) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/spec_helper.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8b8fbf6e862..9c0862ac9ff 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -75,9 +75,8 @@ RSpec.configure do |config| end if ENV['CI'] - # Retry only on feature specs that use JS - config.around :each, :js do |ex| - ex.run_with_retry retry: 3 + config.around(:each) do |ex| + ex.run_with_retry retry: 2 end end -- cgit v1.2.3 From 452202e36d3e20755b099a718a92d3f7b80fabb8 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 12 Jun 2017 09:20:19 +0000 Subject: Improve Job detail view to make it refreshed in real-time instead of reloading --- spec/features/projects/jobs_spec.rb | 115 +++++++++++-------- spec/javascripts/build_spec.js | 17 --- spec/javascripts/datetime_utility_spec.js | 11 +- spec/javascripts/jobs/header_spec.js | 63 +++++++++++ spec/javascripts/jobs/job_details_mediator_spec.js | 43 +++++++ spec/javascripts/jobs/job_store_spec.js | 26 +++++ spec/javascripts/jobs/mock_data.js | 123 +++++++++++++++++++++ spec/javascripts/jobs/sidebar_detail_row_spec.js | 40 +++++++ .../javascripts/jobs/sidebar_details_block_spec.js | 111 +++++++++++++++++++ .../components/header_ci_component_spec.js | 5 + spec/serializers/build_entity_spec.rb | 32 +++++- spec/views/projects/jobs/show.html.haml_spec.rb | 79 ------------- 12 files changed, 518 insertions(+), 147 deletions(-) create mode 100644 spec/javascripts/jobs/header_spec.js create mode 100644 spec/javascripts/jobs/job_details_mediator_spec.js create mode 100644 spec/javascripts/jobs/job_store_spec.js create mode 100644 spec/javascripts/jobs/mock_data.js create mode 100644 spec/javascripts/jobs/sidebar_detail_row_spec.js create mode 100644 spec/javascripts/jobs/sidebar_details_block_spec.js (limited to 'spec') diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 0eda46649db..727ae7081b0 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -5,6 +5,7 @@ feature 'Jobs', :feature do let(:user) { create(:user) } let(:user_access_level) { :developer } let(:project) { create(:project) } + let(:namespace) { project.namespace } let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, :trace, pipeline: pipeline) } @@ -113,10 +114,16 @@ feature 'Jobs', :feature do describe "GET /:project/jobs/:id" do context "Job from project" do + let(:build) { create(:ci_build, :success, pipeline: pipeline) } + before do visit namespace_project_job_path(project.namespace, project, build) end + it 'shows status name', :js do + expect(page).to have_css('.ci-status.ci-success', text: 'passed') + end + it 'shows commit`s data' do expect(page.status_code).to eq(200) expect(page).to have_content pipeline.sha[0..7] @@ -129,6 +136,48 @@ feature 'Jobs', :feature do end end + context 'when job is not running', :js do + let(:build) { create(:ci_build, :success, pipeline: pipeline) } + + before do + visit namespace_project_job_path(project.namespace, project, build) + end + + it 'shows retry button' do + expect(page).to have_link('Retry') + end + + context 'if build passed' do + it 'does not show New issue button' do + expect(page).not_to have_link('New issue') + end + end + + context 'if build failed' do + let(:build) { create(:ci_build, :failed, pipeline: pipeline) } + + before do + visit namespace_project_job_path(namespace, project, build) + end + + it 'shows New issue button' do + expect(page).to have_link('New issue') + end + + it 'links to issues/new with the title and description filled in' do + button_title = "Build Failed ##{build.id}" + build_path = namespace_project_job_path(namespace, project, build) + options = { issue: { title: button_title, description: build_path } } + + href = new_namespace_project_issue_path(namespace, project, options) + + page.within('.header-action-buttons') do + expect(find('.js-new-issue')['href']).to include(href) + end + end + end + end + context "Job from other project" do before do visit namespace_project_job_path(project.namespace, project, build2) @@ -305,63 +354,38 @@ feature 'Jobs', :feature do end end - describe "POST /:project/jobs/:id/cancel" do + describe "POST /:project/jobs/:id/cancel", :js do context "Job from project" do before do build.run! visit namespace_project_job_path(project.namespace, project, build) - click_link "Cancel" + find('.js-cancel-job').click() end it 'loads the page and shows all needed controls' do expect(page.status_code).to eq(200) - expect(page).to have_content 'canceled' expect(page).to have_content 'Retry' end end - - context "Job from other project" do - before do - build.run! - visit namespace_project_job_path(project.namespace, project, build) - page.driver.post(cancel_namespace_project_job_path(project.namespace, project, build2)) - end - - it { expect(page.status_code).to eq(404) } - end end describe "POST /:project/jobs/:id/retry" do - context "Job from project" do + context "Job from project", :js do before do build.run! visit namespace_project_job_path(project.namespace, project, build) - click_link 'Cancel' - page.within('.build-header') do - click_link 'Retry job' - end + find('.js-cancel-job').click() + find('.js-retry-button').trigger('click') end - it 'shows the right status and buttons' do + it 'shows the right status and buttons', :js do expect(page).to have_http_status(200) - expect(page).to have_content 'pending' page.within('aside.right-sidebar') do expect(page).to have_content 'Cancel' end end end - context "Job from other project" do - before do - build.run! - visit namespace_project_job_path(project.namespace, project, build) - click_link 'Cancel' - page.driver.post(retry_namespace_project_job_path(project.namespace, project, build2)) - end - - it { expect(page).to have_http_status(404) } - end - context "Job that current user is not allowed to retry" do before do build.run! @@ -435,20 +459,17 @@ feature 'Jobs', :feature do Capybara.current_session.driver.headers = { 'X-Sendfile-Type' => 'X-Sendfile' } build.run! - - allow_any_instance_of(Gitlab::Ci::Trace).to receive(:paths) - .and_return(paths) - - visit namespace_project_job_path(project.namespace, project, build) end context 'when build has trace in file', :js do - let(:paths) do - [existing_file] - end - before do - find('.js-raw-link-controller').click() + allow_any_instance_of(Gitlab::Ci::Trace) + .to receive(:paths) + .and_return([existing_file]) + + visit namespace_project_job_path(namespace, project, build) + + find('.js-raw-link-controller').click end it 'sends the right headers' do @@ -458,11 +479,17 @@ feature 'Jobs', :feature do end end - context 'when job has trace in DB' do - let(:paths) { [] } + context 'when job has trace in the database', :js do + before do + allow_any_instance_of(Gitlab::Ci::Trace) + .to receive(:paths) + .and_return([]) + + visit namespace_project_job_path(namespace, project, build) + end it 'sends the right headers' do - expect(page.status_code).not_to have_selector('.js-raw-link-controller') + expect(page).not_to have_selector('.js-raw-link-controller') end end end diff --git a/spec/javascripts/build_spec.js b/spec/javascripts/build_spec.js index 4c8a48580d7..be90dbdd88a 100644 --- a/spec/javascripts/build_spec.js +++ b/spec/javascripts/build_spec.js @@ -132,23 +132,6 @@ describe('Build', () => { expect($('#build-trace .js-build-output').text()).not.toMatch(/Update/); expect($('#build-trace .js-build-output').text()).toMatch(/Different/); }); - - it('reloads the page when the build is done', () => { - spyOn(gl.utils, 'visitUrl'); - const deferred = $.Deferred(); - - spyOn($, 'ajax').and.returnValue(deferred.promise()); - deferred.resolve({ - html: 'Final', - status: 'passed', - append: true, - complete: true, - }); - - this.build = new Build(); - - expect(gl.utils.visitUrl).toHaveBeenCalledWith(BUILD_URL); - }); }); describe('truncated information', () => { diff --git a/spec/javascripts/datetime_utility_spec.js b/spec/javascripts/datetime_utility_spec.js index c82ad0bea48..e54ea11b08c 100644 --- a/spec/javascripts/datetime_utility_spec.js +++ b/spec/javascripts/datetime_utility_spec.js @@ -1,4 +1,4 @@ -import '~/lib/utils/datetime_utility'; +import { timeIntervalInWords } from '~/lib/utils/datetime_utility'; (() => { describe('Date time utils', () => { @@ -82,4 +82,13 @@ import '~/lib/utils/datetime_utility'; }); }); }); + + describe('timeIntervalInWords', () => { + it('should return string with number of minutes and seconds', () => { + expect(timeIntervalInWords(9.54)).toEqual('9 seconds'); + expect(timeIntervalInWords(1)).toEqual('1 second'); + expect(timeIntervalInWords(200)).toEqual('3 minutes 20 seconds'); + expect(timeIntervalInWords(6008)).toEqual('100 minutes 8 seconds'); + }); + }); })(); diff --git a/spec/javascripts/jobs/header_spec.js b/spec/javascripts/jobs/header_spec.js new file mode 100644 index 00000000000..c7179b3e03d --- /dev/null +++ b/spec/javascripts/jobs/header_spec.js @@ -0,0 +1,63 @@ +import Vue from 'vue'; +import headerComponent from '~/jobs/components/header.vue'; + +describe('Job details header', () => { + let HeaderComponent; + let vm; + let props; + + beforeEach(() => { + HeaderComponent = Vue.extend(headerComponent); + + const threeWeeksAgo = new Date(); + threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21); + + props = { + job: { + status: { + group: 'failed', + icon: 'ci-status-failed', + label: 'failed', + text: 'failed', + details_path: 'path', + }, + id: 123, + created_at: threeWeeksAgo.toISOString(), + user: { + web_url: 'path', + name: 'Foo', + username: 'foobar', + email: 'foo@bar.com', + avatar_url: 'link', + }, + retry_path: 'path', + new_issue_path: 'path', + }, + isLoading: false, + }; + + vm = new HeaderComponent({ propsData: props }).$mount(); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('should render provided job information', () => { + expect( + vm.$el.querySelector('.header-main-content').textContent.replace(/\s+/g, ' ').trim(), + ).toEqual('failed Job #123 triggered 3 weeks ago by Foo'); + }); + + it('should render retry link', () => { + expect( + vm.$el.querySelector('.js-retry-button').getAttribute('href'), + ).toEqual(props.job.retry_path); + }); + + it('should render new issue link', () => { + expect( + vm.$el.querySelector('.js-new-issue').getAttribute('href'), + ).toEqual(props.job.new_issue_path); + }); +}); diff --git a/spec/javascripts/jobs/job_details_mediator_spec.js b/spec/javascripts/jobs/job_details_mediator_spec.js new file mode 100644 index 00000000000..1d7fa7e12fc --- /dev/null +++ b/spec/javascripts/jobs/job_details_mediator_spec.js @@ -0,0 +1,43 @@ +import Vue from 'vue'; +import JobMediator from '~/jobs/job_details_mediator'; +import job from './mock_data'; + +describe('JobMediator', () => { + let mediator; + + beforeEach(() => { + mediator = new JobMediator({ endpoint: 'foo' }); + }); + + it('should set defaults', () => { + expect(mediator.store).toBeDefined(); + expect(mediator.service).toBeDefined(); + expect(mediator.options).toEqual({ endpoint: 'foo' }); + expect(mediator.state.isLoading).toEqual(false); + }); + + describe('request and store data', () => { + const interceptor = (request, next) => { + next(request.respondWith(JSON.stringify(job), { + status: 200, + })); + }; + + beforeEach(() => { + Vue.http.interceptors.push(interceptor); + }); + + afterEach(() => { + Vue.http.interceptors = _.without(Vue.http.interceptor, interceptor); + }); + + it('should store received data', (done) => { + mediator.fetchJob(); + + setTimeout(() => { + expect(mediator.store.state.job).toEqual(job); + done(); + }, 0); + }); + }); +}); diff --git a/spec/javascripts/jobs/job_store_spec.js b/spec/javascripts/jobs/job_store_spec.js new file mode 100644 index 00000000000..d00faf29d1e --- /dev/null +++ b/spec/javascripts/jobs/job_store_spec.js @@ -0,0 +1,26 @@ +import JobStore from '~/jobs/stores/job_store'; +import job from './mock_data'; + +describe('Job Store', () => { + let store; + + beforeEach(() => { + store = new JobStore(); + }); + + it('should set defaults', () => { + expect(store.state.job).toEqual({}); + }); + + describe('storeJob', () => { + it('should store empty object if none is provided', () => { + store.storeJob(); + expect(store.state.job).toEqual({}); + }); + + it('should store provided argument', () => { + store.storeJob(job); + expect(store.state.job).toEqual(job); + }); + }); +}); diff --git a/spec/javascripts/jobs/mock_data.js b/spec/javascripts/jobs/mock_data.js new file mode 100644 index 00000000000..17e4ef26b2c --- /dev/null +++ b/spec/javascripts/jobs/mock_data.js @@ -0,0 +1,123 @@ +const threeWeeksAgo = new Date(); +threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21); + +export default { + id: 4757, + name: 'test', + build_path: '/root/ci-mock/-/jobs/4757', + retry_path: '/root/ci-mock/-/jobs/4757/retry', + cancel_path: '/root/ci-mock/-/jobs/4757/cancel', + new_issue_path: '/root/ci-mock/issues/new', + playable: false, + created_at: threeWeeksAgo.toISOString(), + updated_at: threeWeeksAgo.toISOString(), + finished_at: threeWeeksAgo.toISOString(), + queued: 9.54, + status: { + icon: 'icon_status_success', + text: 'passed', + label: 'passed', + group: 'success', + has_details: true, + details_path: '/root/ci-mock/-/jobs/4757', + favicon: '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + action: { + icon: 'icon_action_retry', + title: 'Retry', + path: '/root/ci-mock/-/jobs/4757/retry', + method: 'post', + }, + }, + coverage: 20, + erased_at: threeWeeksAgo.toISOString(), + duration: 6.785563, + tags: ['tag'], + user: { + name: 'Root', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + erase_path: '/root/ci-mock/-/jobs/4757/erase', + artifacts: [null], + runner: { + id: 1, + description: 'local ci runner', + edit_path: '/root/ci-mock/runners/1/edit', + }, + pipeline: { + id: 140, + user: { + name: 'Root', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + active: false, + coverage: null, + source: 'unknown', + created_at: '2017-05-24T09:59:58.634Z', + updated_at: '2017-06-01T17:32:00.062Z', + path: '/root/ci-mock/pipelines/140', + flags: { + latest: true, + stuck: false, + yaml_errors: false, + retryable: false, + cancelable: false, + }, + details: { + status: { + icon: 'icon_status_success', + text: 'passed', + label: 'passed', + group: 'success', + has_details: true, + details_path: '/root/ci-mock/pipelines/140', + favicon: '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + }, + duration: 6, + finished_at: '2017-06-01T17:32:00.042Z', + }, + ref: { + name: 'abc', + path: '/root/ci-mock/commits/abc', + tag: false, + branch: true, + }, + commit: { + id: 'c58647773a6b5faf066d4ad6ff2c9fbba5f180f6', + short_id: 'c5864777', + title: 'Add new file', + created_at: '2017-05-24T10:59:52.000+01:00', + parent_ids: ['798e5f902592192afaba73f4668ae30e56eae492'], + message: 'Add new file', + author_name: 'Root', + author_email: 'admin@example.com', + authored_date: '2017-05-24T10:59:52.000+01:00', + committer_name: 'Root', + committer_email: 'admin@example.com', + committed_date: '2017-05-24T10:59:52.000+01:00', + author: { + name: 'Root', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + author_gravatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + commit_url: 'http://localhost:3000/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6', + commit_path: '/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6', + }, + }, + merge_request: { + iid: 2, + path: '/root/ci-mock/merge_requests/2', + }, + raw_path: '/root/ci-mock/builds/4757/raw', +}; diff --git a/spec/javascripts/jobs/sidebar_detail_row_spec.js b/spec/javascripts/jobs/sidebar_detail_row_spec.js new file mode 100644 index 00000000000..3ac65709c4a --- /dev/null +++ b/spec/javascripts/jobs/sidebar_detail_row_spec.js @@ -0,0 +1,40 @@ +import Vue from 'vue'; +import sidebarDetailRow from '~/jobs/components/sidebar_detail_row.vue'; + +describe('Sidebar detail row', () => { + let SidebarDetailRow; + let vm; + + beforeEach(() => { + SidebarDetailRow = Vue.extend(sidebarDetailRow); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('should render no title', () => { + vm = new SidebarDetailRow({ + propsData: { + value: 'this is the value', + }, + }).$mount(); + + expect(vm.$el.textContent.replace(/\s+/g, ' ').trim()).toEqual('this is the value'); + }); + + beforeEach(() => { + vm = new SidebarDetailRow({ + propsData: { + title: 'this is the title', + value: 'this is the value', + }, + }).$mount(); + }); + + it('should render provided title and value', () => { + expect( + vm.$el.textContent.replace(/\s+/g, ' ').trim(), + ).toEqual('this is the title: this is the value'); + }); +}); diff --git a/spec/javascripts/jobs/sidebar_details_block_spec.js b/spec/javascripts/jobs/sidebar_details_block_spec.js new file mode 100644 index 00000000000..95532ef5382 --- /dev/null +++ b/spec/javascripts/jobs/sidebar_details_block_spec.js @@ -0,0 +1,111 @@ +import Vue from 'vue'; +import sidebarDetailsBlock from '~/jobs/components/sidebar_details_block.vue'; +import job from './mock_data'; + +describe('Sidebar details block', () => { + let SidebarComponent; + let vm; + + function trimWhitespace(element) { + return element.textContent.replace(/\s+/g, ' ').trim(); + } + + beforeEach(() => { + SidebarComponent = Vue.extend(sidebarDetailsBlock); + }); + + afterEach(() => { + vm.$destroy(); + }); + + describe('when it is loading', () => { + it('should render a loading spinner', () => { + vm = new SidebarComponent({ + propsData: { + job: {}, + isLoading: true, + }, + }).$mount(); + + expect(vm.$el.querySelector('.fa-spinner')).toBeDefined(); + }); + }); + + beforeEach(() => { + vm = new SidebarComponent({ + propsData: { + job, + isLoading: false, + }, + }).$mount(); + }); + + describe('actions', () => { + it('should render link to new issue', () => { + expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual(job.new_issue_path); + expect(vm.$el.querySelector('.js-new-issue').textContent.trim()).toEqual('New issue'); + }); + + it('should render link to retry job', () => { + expect(vm.$el.querySelector('.js-retry-job').getAttribute('href')).toEqual(job.retry_path); + }); + + it('should render link to cancel job', () => { + expect(vm.$el.querySelector('.js-cancel-job').getAttribute('href')).toEqual(job.cancel_path); + }); + }); + + describe('information', () => { + it('should render merge request link', () => { + expect( + trimWhitespace(vm.$el.querySelector('.js-job-mr')), + ).toEqual('Merge Request: !2'); + + expect( + vm.$el.querySelector('.js-job-mr a').getAttribute('href'), + ).toEqual(job.merge_request.path); + }); + + it('should render job duration', () => { + expect( + trimWhitespace(vm.$el.querySelector('.js-job-duration')), + ).toEqual('Duration: 6 seconds'); + }); + + it('should render erased date', () => { + expect( + trimWhitespace(vm.$el.querySelector('.js-job-erased')), + ).toEqual('Erased: 3 weeks ago'); + }); + + it('should render finished date', () => { + expect( + trimWhitespace(vm.$el.querySelector('.js-job-finished')), + ).toEqual('Finished: 3 weeks ago'); + }); + + it('should render queued date', () => { + expect( + trimWhitespace(vm.$el.querySelector('.js-job-queued')), + ).toEqual('Queued: 9 seconds'); + }); + + it('should render runner ID', () => { + expect( + trimWhitespace(vm.$el.querySelector('.js-job-runner')), + ).toEqual('Runner: #1'); + }); + + it('should render coverage', () => { + expect( + trimWhitespace(vm.$el.querySelector('.js-job-coverage')), + ).toEqual('Coverage: 20%'); + }); + + it('should render tags', () => { + expect( + trimWhitespace(vm.$el.querySelector('.js-job-tags')), + ).toEqual('Tags: tag'); + }); + }); +}); diff --git a/spec/javascripts/vue_shared/components/header_ci_component_spec.js b/spec/javascripts/vue_shared/components/header_ci_component_spec.js index 2b51c89f311..e28639f12f3 100644 --- a/spec/javascripts/vue_shared/components/header_ci_component_spec.js +++ b/spec/javascripts/vue_shared/components/header_ci_component_spec.js @@ -43,6 +43,7 @@ describe('Header CI Component', () => { isLoading: false, }, ], + hasSidebarButton: true, }; vm = new HeaderCi({ @@ -90,4 +91,8 @@ describe('Header CI Component', () => { done(); }); }); + + it('should render sidebar toggle button', () => { + expect(vm.$el.querySelector('.js-sidebar-build-toggle')).toBeDefined(); + }); }); diff --git a/spec/serializers/build_entity_spec.rb b/spec/serializers/build_entity_spec.rb index 46d43a80ef7..e51ff9fc709 100644 --- a/spec/serializers/build_entity_spec.rb +++ b/spec/serializers/build_entity_spec.rb @@ -2,12 +2,13 @@ require 'spec_helper' describe BuildEntity do let(:user) { create(:user) } - let(:build) { create(:ci_build, :failed) } + let(:build) { create(:ci_build) } let(:project) { build.project } let(:request) { double('request') } before do allow(request).to receive(:current_user).and_return(user) + project.add_developer(user) end let(:entity) do @@ -16,9 +17,8 @@ describe BuildEntity do subject { entity.as_json } - it 'contains paths to build page and retry action' do - expect(subject).to include(:build_path, :retry_path) - expect(subject[:retry_path]).not_to be_nil + it 'contains paths to build page action' do + expect(subject).to include(:build_path) end it 'does not contain sensitive information' do @@ -39,12 +39,32 @@ describe BuildEntity do expect(subject[:status]).to include :icon, :favicon, :text, :label end - context 'when build is a regular job' do + context 'when build is retryable' do + before do + build.update(status: :failed) + end + + it 'contains cancel path' do + expect(subject).to include(:retry_path) + end + end + + context 'when build is cancelable' do + before do + build.update(status: :running) + end + + it 'contains cancel path' do + expect(subject).to include(:cancel_path) + end + end + + context 'when build is a regular build' do it 'does not contain path to play action' do expect(subject).not_to include(:play_path) end - it 'is not a playable job' do + it 'is not a playable build' do expect(subject[:playable]).to be false end end diff --git a/spec/views/projects/jobs/show.html.haml_spec.rb b/spec/views/projects/jobs/show.html.haml_spec.rb index 8f2822f5dc5..d9a7ba265f8 100644 --- a/spec/views/projects/jobs/show.html.haml_spec.rb +++ b/spec/views/projects/jobs/show.html.haml_spec.rb @@ -15,36 +15,6 @@ describe 'projects/jobs/show', :view do allow(view).to receive(:can?).and_return(true) end - describe 'job information in header' do - let(:build) do - create(:ci_build, :success, environment: 'staging') - end - - before do - render - end - - it 'shows status name' do - expect(rendered).to have_css('.ci-status.ci-success', text: 'passed') - end - - it 'does not render a link to the job' do - expect(rendered).not_to have_link('passed') - end - - it 'shows job id' do - expect(rendered).to have_css('.js-build-id', text: build.id) - end - - it 'shows a link to the pipeline' do - expect(rendered).to have_link(build.pipeline.id) - end - - it 'shows a link to the commit' do - expect(rendered).to have_link(build.pipeline.short_sha) - end - end - describe 'environment info in job view' do context 'job with latest deployment' do let(:build) do @@ -215,34 +185,6 @@ describe 'projects/jobs/show', :view do end end - context 'when job is not running' do - before do - build.success! - render - end - - it 'shows retry button' do - expect(rendered).to have_link('Retry') - end - - context 'if build passed' do - it 'does not show New issue button' do - expect(rendered).not_to have_link('New issue') - end - end - - context 'if build failed' do - before do - build.status = 'failed' - render - end - - it 'shows New issue button' do - expect(rendered).to have_link('New issue') - end - end - end - describe 'commit title in sidebar' do let(:commit_title) { project.commit.title } @@ -269,25 +211,4 @@ describe 'projects/jobs/show', :view do expect(rendered).to have_css('.js-build-value', visible: false, text: 'TRIGGER_VALUE_2') end end - - describe 'New issue button' do - before do - build.status = 'failed' - render - end - - it 'links to issues/new with the title and description filled in' do - title = "Build Failed ##{build.id}" - build_url = namespace_project_job_url(project.namespace, project, build) - href = new_namespace_project_issue_path( - project.namespace, - project, - issue: { - title: title, - description: build_url - } - ) - expect(rendered).to have_link('New issue', href: href) - end - end end -- cgit v1.2.3 From d83ee2bbd10d8fe2f2e9521bb3c266cf696aa98c Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 2 Jun 2017 17:12:36 +0200 Subject: Add the ability to perform background migrations Background migrations can be used to perform long running data migrations without these blocking a deployment procedure. See MR https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11854 for more information. --- spec/lib/gitlab/background_migration_spec.rb | 48 ++++++++++++++++++++++++ spec/workers/background_migration_worker_spec.rb | 13 +++++++ 2 files changed, 61 insertions(+) create mode 100644 spec/lib/gitlab/background_migration_spec.rb create mode 100644 spec/workers/background_migration_worker_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/background_migration_spec.rb b/spec/lib/gitlab/background_migration_spec.rb new file mode 100644 index 00000000000..f2073b9bcb3 --- /dev/null +++ b/spec/lib/gitlab/background_migration_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe Gitlab::BackgroundMigration do + describe '.steal' do + it 'steals jobs from a queue' do + queue = [double(:job, args: ['Foo', [10, 20]])] + + allow(Sidekiq::Queue).to receive(:new). + with(BackgroundMigrationWorker.sidekiq_options['queue']). + and_return(queue) + + expect(queue[0]).to receive(:delete) + + expect(described_class).to receive(:perform).with('Foo', [10, 20]) + + described_class.steal('Foo') + end + + it 'does not steal jobs for a different migration' do + queue = [double(:job, args: ['Foo', [10, 20]])] + + allow(Sidekiq::Queue).to receive(:new). + with(BackgroundMigrationWorker.sidekiq_options['queue']). + and_return(queue) + + expect(described_class).not_to receive(:perform) + + expect(queue[0]).not_to receive(:delete) + + described_class.steal('Bar') + end + end + + describe '.perform' do + it 'performs a background migration' do + instance = double(:instance) + klass = double(:klass, new: instance) + + expect(described_class).to receive(:const_get). + with('Foo'). + and_return(klass) + + expect(instance).to receive(:perform).with(10, 20) + + described_class.perform('Foo', [10, 20]) + end + end +end diff --git a/spec/workers/background_migration_worker_spec.rb b/spec/workers/background_migration_worker_spec.rb new file mode 100644 index 00000000000..0d742ae9dc7 --- /dev/null +++ b/spec/workers/background_migration_worker_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' + +describe BackgroundMigrationWorker do + describe '.perform' do + it 'performs a background migration' do + expect(Gitlab::BackgroundMigration). + to receive(:perform). + with('Foo', [10, 20]) + + described_class.new.perform('Foo', [10, 20]) + end + end +end -- cgit v1.2.3 From 2e7db162fa1e1d375688c8eb66fabac2f67e8eb3 Mon Sep 17 00:00:00 2001 From: Jared Deckard Date: Thu, 8 Jun 2017 12:56:41 -0500 Subject: Only add a description change note when no tasks are updated --- spec/services/issues/update_service_spec.rb | 27 ++++++++++++++++++---- .../services/merge_requests/update_service_spec.rb | 13 +++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'spec') diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 5184c1d5f19..a78866a2c32 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -31,6 +31,13 @@ describe Issues::UpdateService, services: true do end end + def find_notes(action) + issue + .notes + .joins(:system_note_metadata) + .where(system_note_metadata: { action: action }) + end + def update_issue(opts) described_class.new(project, user, opts).execute(issue) end @@ -330,6 +337,9 @@ describe Issues::UpdateService, services: true do expect(note1).not_to be_nil expect(note2).not_to be_nil + + description_notes = find_notes('description') + expect(description_notes.length).to eq(1) end end @@ -345,6 +355,9 @@ describe Issues::UpdateService, services: true do expect(note1).not_to be_nil expect(note2).not_to be_nil + + description_notes = find_notes('description') + expect(description_notes.length).to eq(1) end end @@ -354,10 +367,12 @@ describe Issues::UpdateService, services: true do update_issue(description: "- [x] Task 1\n- [ ] Task 3\n- [ ] Task 2") end - it 'does not create a system note' do - note = find_note('marked the task **Task 2** as incomplete') + it 'does not create a system note for the task' do + task_note = find_note('marked the task **Task 2** as incomplete') + description_notes = find_notes('description') - expect(note).to be_nil + expect(task_note).to be_nil + expect(description_notes.length).to eq(2) end end @@ -368,9 +383,11 @@ describe Issues::UpdateService, services: true do end it 'does not create a system note referencing the position the old item' do - note = find_note('marked the task **Two** as incomplete') + task_note = find_note('marked the task **Two** as incomplete') + description_notes = find_notes('description') - expect(note).to be_nil + expect(task_note).to be_nil + expect(description_notes.length).to eq(2) end it 'does not generate a new note at all' do diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index d371fc68312..091c193aaa6 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -30,6 +30,13 @@ describe MergeRequests::UpdateService, services: true do end end + def find_notes(action) + @merge_request + .notes + .joins(:system_note_metadata) + .where(system_note_metadata: { action: action }) + end + def update_merge_request(opts) @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request) @merge_request.reload @@ -394,6 +401,9 @@ describe MergeRequests::UpdateService, services: true do expect(note1).not_to be_nil expect(note2).not_to be_nil + + description_notes = find_notes('description') + expect(description_notes.length).to eq(1) end end @@ -409,6 +419,9 @@ describe MergeRequests::UpdateService, services: true do expect(note1).not_to be_nil expect(note2).not_to be_nil + + description_notes = find_notes('description') + expect(description_notes.length).to eq(1) end end end -- cgit v1.2.3 From 448fc23e4743198f2c1bf3cd10eb515eeb9f424b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 8 Jun 2017 11:55:07 +0200 Subject: Let PhantomJS load local images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change fix a memory leak due to a Webkit bug: https://github.com/ariya/phantomjs/issues/12903 Also: - Whitelist only localhost and 127.0.0.1 in Capybara + JS specs - Blacklist all requests to media such as images, videos, PDFs, CSVs etc. - Log all the requests made. Signed-off-by: Rémy Coutable --- spec/features/help_pages_spec.rb | 16 +++++----------- spec/features/projects/artifacts/file_spec.rb | 1 + spec/support/capybara.rb | 4 +++- 3 files changed, 9 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb index e0b2404e60a..31014f5cad2 100644 --- a/spec/features/help_pages_spec.rb +++ b/spec/features/help_pages_spec.rb @@ -34,7 +34,7 @@ describe 'Help Pages', feature: true do end end - context 'in a production environment with version check enabled', js: true do + context 'in a production environment with version check enabled', :js do before do allow(Rails.env).to receive(:production?) { true } allow(current_application_settings).to receive(:version_check_enabled) { true } @@ -44,18 +44,12 @@ describe 'Help Pages', feature: true do visit help_path end - it 'should display a version check image' do - expect(find('.js-version-status-badge')).to be_visible + it 'has a version check image' do + expect(find('.js-version-status-badge', visible: false)['src']).to end_with('/version-check-url') end - it 'should have a src url' do - expect(find('.js-version-status-badge')['src']).to match(/\/version-check-url/) - end - - it 'should hide the version check image if the image request fails' do - # We use '--load-images=no' with poltergeist so we must trigger manually - execute_script("$('.js-version-status-badge').trigger('error');") - + it 'hides the version check image if the image request fails' do + # We use '--load-images=yes' with poltergeist so the image fails to load expect(find('.js-version-status-badge', visible: false)).not_to be_visible end end diff --git a/spec/features/projects/artifacts/file_spec.rb b/spec/features/projects/artifacts/file_spec.rb index 25c4f3c87a2..860373e531b 100644 --- a/spec/features/projects/artifacts/file_spec.rb +++ b/spec/features/projects/artifacts/file_spec.rb @@ -39,6 +39,7 @@ feature 'Artifact file', :js, feature: true do context 'JPG file' do before do + page.driver.browser.url_blacklist = [] visit_file('rails_sample.jpg') wait_for_requests diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index b8ca8f22a3d..c34e76fa72f 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -14,8 +14,10 @@ Capybara.register_driver :poltergeist do |app| js_errors: true, timeout: timeout, window_size: [1366, 768], + url_whitelist: %w[localhost 127.0.0.1], + url_blacklist: %w[.mp4 .png .gif .avi .bmp .jpg .jpeg], phantomjs_options: [ - '--load-images=no' + '--load-images=yes' ] ) end -- cgit v1.2.3 From 05683f313b40e1c37fbfbb04bd4d0e368dc5b39a Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 12 Jun 2017 23:42:11 +0200 Subject: Fix filename method of GitlabUploader to return always real filename --- spec/requests/api/runner_spec.rb | 25 +++++++++++++++++++++++-- spec/uploaders/artifact_uploader_spec.rb | 16 ++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb index be83514ed9c..9556c99dea1 100644 --- a/spec/requests/api/runner_spec.rb +++ b/spec/requests/api/runner_spec.rb @@ -431,8 +431,29 @@ describe API::Runner do expect(response).to have_http_status(201) expect(json_response['id']).to eq(test_job.id) expect(json_response['dependencies'].count).to eq(2) - expect(json_response['dependencies']).to include({ 'id' => job.id, 'name' => job.name, 'token' => job.token }, - { 'id' => job2.id, 'name' => job2.name, 'token' => job2.token }) + expect(json_response['dependencies']).to include( + { 'id' => job.id, 'name' => job.name, 'token' => job.token }, + { 'id' => job2.id, 'name' => job2.name, 'token' => job2.token }) + end + end + + context 'when pipeline have jobs with artifacts' do + let!(:job) { create(:ci_build_tag, :artifacts, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) } + let!(:test_job) { create(:ci_build, pipeline: pipeline, name: 'deploy', stage: 'deploy', stage_idx: 1) } + + before do + job.success + end + + it 'returns dependent jobs' do + request_job + + expect(response).to have_http_status(201) + expect(json_response['id']).to eq(test_job.id) + expect(json_response['dependencies'].count).to eq(1) + expect(json_response['dependencies']).to include( + { 'id' => job.id, 'name' => job.name, 'token' => job.token, + 'artifacts_file' => { 'filename' => 'ci_build_artifacts.zip', 'size' => 106365 } }) end end diff --git a/spec/uploaders/artifact_uploader_spec.rb b/spec/uploaders/artifact_uploader_spec.rb index b3fac65c55e..2a3bd0e3bb2 100644 --- a/spec/uploaders/artifact_uploader_spec.rb +++ b/spec/uploaders/artifact_uploader_spec.rb @@ -42,4 +42,20 @@ describe ArtifactUploader do it { is_expected.to start_with(path) } it { is_expected.to end_with('/tmp/work') } end + + describe '#filename' do + # we need to use uploader, as this makes to use mounter + # which initialises uploader.file object + let(:uploader) { job.artifacts_file } + + subject { uploader.filename } + + it { is_expected.to be_nil } + + context 'with artifacts' do + let(:job) { create(:ci_build, :artifacts) } + + it { is_expected.not_to be_nil } + end + end end -- cgit v1.2.3