From 4cd962ec6ec2b037983c1a0d7c1097e8b1f70f52 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 30 Dec 2016 14:46:41 -0600 Subject: allow storage of raw string fixtures --- spec/support/javascript_fixtures_helpers.rb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'spec/support') diff --git a/spec/support/javascript_fixtures_helpers.rb b/spec/support/javascript_fixtures_helpers.rb index 99e98eebdb4..29dd4de62ff 100644 --- a/spec/support/javascript_fixtures_helpers.rb +++ b/spec/support/javascript_fixtures_helpers.rb @@ -20,11 +20,24 @@ module JavaScriptFixturesHelpers # Public: Store a response object as fixture file # - # response - response object to store + # response - string or response object to store # fixture_file_name - file name to store the fixture in (relative to FIXTURE_PATH) # def store_frontend_fixture(response, fixture_file_name) fixture_file_name = File.expand_path(fixture_file_name, FIXTURE_PATH) + fixture = response.respond_to?(:body) ? parse_response(response) : response + + FileUtils.mkdir_p(File.dirname(fixture_file_name)) + File.write(fixture_file_name, fixture) + end + + private + + # Private: Prepare a response object for use as a frontend fixture + # + # response - response object to prepare + # + def parse_response(response) fixture = response.body response_mime_type = Mime::Type.lookup(response.content_type) @@ -44,7 +57,6 @@ module JavaScriptFixturesHelpers fixture.gsub!(%r{="/}, "=\"http://#{test_host}/") end - FileUtils.mkdir_p(File.dirname(fixture_file_name)) - File.write(fixture_file_name, fixture) + fixture end end -- cgit v1.2.1 From 6370e326995ccb1c1c816b007c63f10d0c7cda25 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 30 Dec 2016 14:50:07 -0600 Subject: recursively clean compiled fixtures --- spec/support/javascript_fixtures_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec/support') diff --git a/spec/support/javascript_fixtures_helpers.rb b/spec/support/javascript_fixtures_helpers.rb index 29dd4de62ff..6817ccb1da7 100644 --- a/spec/support/javascript_fixtures_helpers.rb +++ b/spec/support/javascript_fixtures_helpers.rb @@ -13,7 +13,7 @@ module JavaScriptFixturesHelpers # def clean_frontend_fixtures(directory_name) directory_name = File.expand_path(directory_name, FIXTURE_PATH) - Dir[File.expand_path('*.html.raw', directory_name)].each do |file_name| + Dir[File.expand_path('**/*.html.raw', directory_name)].each do |file_name| FileUtils.rm(file_name) end end -- cgit v1.2.1 From 5f192c77e09a9af19268e5c5cf860ffd8c0c6216 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 30 Dec 2016 15:27:40 -0600 Subject: update all frontend tests to point to precompiled fixtures --- spec/support/javascript_fixtures_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec/support') diff --git a/spec/support/javascript_fixtures_helpers.rb b/spec/support/javascript_fixtures_helpers.rb index 6817ccb1da7..29dd4de62ff 100644 --- a/spec/support/javascript_fixtures_helpers.rb +++ b/spec/support/javascript_fixtures_helpers.rb @@ -13,7 +13,7 @@ module JavaScriptFixturesHelpers # def clean_frontend_fixtures(directory_name) directory_name = File.expand_path(directory_name, FIXTURE_PATH) - Dir[File.expand_path('**/*.html.raw', directory_name)].each do |file_name| + Dir[File.expand_path('*.html.raw', directory_name)].each do |file_name| FileUtils.rm(file_name) end end -- cgit v1.2.1 From a00578ce5cdf4bab95990bca9e806c6322bb1384 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 4 Jan 2017 13:43:06 -0500 Subject: Absorb gitlab_git --- spec/support/matchers/be_valid_commit.rb | 8 ++ spec/support/seed_helper.rb | 112 ++++++++++++++++++++++++ spec/support/seed_repo.rb | 143 +++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 spec/support/matchers/be_valid_commit.rb create mode 100644 spec/support/seed_helper.rb create mode 100644 spec/support/seed_repo.rb (limited to 'spec/support') diff --git a/spec/support/matchers/be_valid_commit.rb b/spec/support/matchers/be_valid_commit.rb new file mode 100644 index 00000000000..3696e4d5f03 --- /dev/null +++ b/spec/support/matchers/be_valid_commit.rb @@ -0,0 +1,8 @@ +RSpec::Matchers.define :be_valid_commit do + match do |actual| + actual && + actual.id == SeedRepo::Commit::ID && + actual.message == SeedRepo::Commit::MESSAGE && + actual.author_name == SeedRepo::Commit::AUTHOR_FULL_NAME + end +end diff --git a/spec/support/seed_helper.rb b/spec/support/seed_helper.rb new file mode 100644 index 00000000000..3f8398a31e3 --- /dev/null +++ b/spec/support/seed_helper.rb @@ -0,0 +1,112 @@ +# This file is specific to specs in spec/lib/gitlab/git/ + +SEED_REPOSITORY_PATH = File.expand_path('../../tmp/repositories', __dir__) +TEST_REPO_PATH = File.join(SEED_REPOSITORY_PATH, 'gitlab-git-test.git') +TEST_NORMAL_REPO_PATH = File.join(SEED_REPOSITORY_PATH, "not-bare-repo.git") +TEST_MUTABLE_REPO_PATH = File.join(SEED_REPOSITORY_PATH, "mutable-repo.git") +TEST_BROKEN_REPO_PATH = File.join(SEED_REPOSITORY_PATH, "broken-repo.git") + +module SeedHelper + GITLAB_URL = "https://gitlab.com/gitlab-org/gitlab-git-test.git" + + def ensure_seeds + if File.exist?(SEED_REPOSITORY_PATH) + FileUtils.rm_r(SEED_REPOSITORY_PATH) + end + + FileUtils.mkdir_p(SEED_REPOSITORY_PATH) + + create_bare_seeds + create_normal_seeds + create_mutable_seeds + create_broken_seeds + create_git_attributes + create_invalid_git_attributes + end + + def create_bare_seeds + system(git_env, *%W(git clone --bare #{GITLAB_URL}), + chdir: SEED_REPOSITORY_PATH, + out: '/dev/null', + err: '/dev/null') + end + + def create_normal_seeds + system(git_env, *%W(git clone #{TEST_REPO_PATH} #{TEST_NORMAL_REPO_PATH}), + out: '/dev/null', + err: '/dev/null') + end + + def create_mutable_seeds + system(git_env, *%W(git clone #{TEST_REPO_PATH} #{TEST_MUTABLE_REPO_PATH}), + out: '/dev/null', + err: '/dev/null') + + system(git_env, *%w(git branch -t feature origin/feature), + chdir: TEST_MUTABLE_REPO_PATH, out: '/dev/null', err: '/dev/null') + + system(git_env, *%W(git remote add expendable #{GITLAB_URL}), + chdir: TEST_MUTABLE_REPO_PATH, out: '/dev/null', err: '/dev/null') + end + + def create_broken_seeds + system(git_env, *%W(git clone --bare #{TEST_REPO_PATH} #{TEST_BROKEN_REPO_PATH}), + out: '/dev/null', + err: '/dev/null') + + refs_path = File.join(TEST_BROKEN_REPO_PATH, 'refs') + + FileUtils.rm_r(refs_path) + end + + def create_git_attributes + dir = File.join(SEED_REPOSITORY_PATH, 'with-git-attributes.git', 'info') + + FileUtils.mkdir_p(dir) + + File.open(File.join(dir, 'attributes'), 'w') do |handle| + handle.write <<-EOF.strip +# This is a comment, it should be ignored. + +*.txt text +*.jpg -text +*.sh eol=lf gitlab-language=shell +*.haml.* gitlab-language=haml +foo/bar.* foo +*.cgi key=value?p1=v1&p2=v2 +/*.png gitlab-language=png +*.binary binary + +# This uses a tab instead of spaces to ensure the parser also supports this. +*.md\tgitlab-language=markdown +bla/bla.txt + EOF + end + end + + def create_invalid_git_attributes + dir = File.join(SEED_REPOSITORY_PATH, 'with-invalid-git-attributes.git', 'info') + + FileUtils.mkdir_p(dir) + + enc = Encoding::UTF_16 + + File.open(File.join(dir, 'attributes'), 'w', encoding: enc) do |handle| + handle.write('# hello'.encode(enc)) + end + end + + # Prevent developer git configurations from being persisted to test + # repositories + def git_env + { 'GIT_TEMPLATE_DIR' => '' } + end +end + +RSpec.configure do |config| + config.include SeedHelper, :seed_helper + + config.before(:all, :seed_helper) do + ensure_seeds + end +end diff --git a/spec/support/seed_repo.rb b/spec/support/seed_repo.rb new file mode 100644 index 00000000000..9f2cd7c67c5 --- /dev/null +++ b/spec/support/seed_repo.rb @@ -0,0 +1,143 @@ +# Seed repo: +# 0e50ec4d3c7ce42ab74dda1d422cb2cbffe1e326 Merge branch 'lfs_pointers' into 'master' +# 33bcff41c232a11727ac6d660bd4b0c2ba86d63d Add valid and invalid lfs pointers +# 732401c65e924df81435deb12891ef570167d2e2 Update year in license file +# b0e52af38d7ea43cf41d8a6f2471351ac036d6c9 Empty commit +# 40f4a7a617393735a95a0bb67b08385bc1e7c66d Add ISO-8859-encoded file +# 66028349a123e695b589e09a36634d976edcc5e8 Merge branch 'add-comments-to-gitmodules' into 'master' +# de5714f34c4e34f1d50b9a61a2e6c9132fe2b5fd Add comments to the end of .gitmodules to test parsing +# fa1b1e6c004a68b7d8763b86455da9e6b23e36d6 Merge branch 'add-files' into 'master' +# eb49186cfa5c4338011f5f590fac11bd66c5c631 Add submodules nested deeper than the root +# 18d9c205d0d22fdf62bc2f899443b83aafbf941f Add executables and links files +# 5937ac0a7beb003549fc5fd26fc247adbce4a52e Add submodule from gitlab.com +# 570e7b2abdd848b95f2f578043fc23bd6f6fd24d Change some files +# 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9 More submodules +# d14d6c0abdd253381df51a723d58691b2ee1ab08 Remove ds_store files +# c1acaa58bbcbc3eafe538cb8274ba387047b69f8 Ignore DS files +# ae73cb07c9eeaf35924a10f713b364d32b2dd34f Binary file added +# 874797c3a73b60d2187ed6e2fcabd289ff75171e Ruby files modified +# 2f63565e7aac07bcdadb654e253078b727143ec4 Modified image +# 33f3729a45c02fc67d00adb1b8bca394b0e761d9 Image added +# 913c66a37b4a45b9769037c55c2d238bd0942d2e Files, encoding and much more +# cfe32cf61b73a0d5e9f13e774abde7ff789b1660 Add submodule +# 6d394385cf567f80a8fd85055db1ab4c5295806f Added contributing guide +# 1a0b36b3cdad1d2ee32457c102a8c0b7056fa863 Initial commit + +module SeedRepo + module BigCommit + ID = "913c66a37b4a45b9769037c55c2d238bd0942d2e" + PARENT_ID = "cfe32cf61b73a0d5e9f13e774abde7ff789b1660" + MESSAGE = "Files, encoding and much more" + AUTHOR_FULL_NAME = "Dmitriy Zaporozhets" + FILES_COUNT = 2 + end + + module Commit + ID = "570e7b2abdd848b95f2f578043fc23bd6f6fd24d" + PARENT_ID = "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9" + MESSAGE = "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \n" + AUTHOR_FULL_NAME = "Dmitriy Zaporozhets" + FILES = ["files/ruby/popen.rb", "files/ruby/regex.rb"] + FILES_COUNT = 2 + C_FILE_PATH = "files/ruby" + C_FILES = ["popen.rb", "regex.rb", "version_info.rb"] + BLOB_FILE = %{%h3= @key.title\n%hr\n%pre= @key.key\n.actions\n = link_to 'Remove', @key, :confirm => 'Are you sure?', :method => :delete, :class => \"btn danger delete-key\"\n\n\n} + BLOB_FILE_PATH = "app/views/keys/show.html.haml" + end + + module EmptyCommit + ID = "b0e52af38d7ea43cf41d8a6f2471351ac036d6c9" + PARENT_ID = "40f4a7a617393735a95a0bb67b08385bc1e7c66d" + MESSAGE = "Empty commit" + AUTHOR_FULL_NAME = "Rémy Coutable" + FILES = [] + FILES_COUNT = FILES.count + end + + module EncodingCommit + ID = "40f4a7a617393735a95a0bb67b08385bc1e7c66d" + PARENT_ID = "66028349a123e695b589e09a36634d976edcc5e8" + MESSAGE = "Add ISO-8859-encoded file" + AUTHOR_FULL_NAME = "Stan Hu" + FILES = ["encoding/iso8859.txt"] + FILES_COUNT = FILES.count + end + + module FirstCommit + ID = "1a0b36b3cdad1d2ee32457c102a8c0b7056fa863" + PARENT_ID = nil + MESSAGE = "Initial commit" + AUTHOR_FULL_NAME = "Dmitriy Zaporozhets" + FILES = ["LICENSE", ".gitignore", "README.md"] + FILES_COUNT = 3 + end + + module LastCommit + ID = "4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6" + PARENT_ID = "0e1b353b348f8477bdbec1ef47087171c5032cd9" + MESSAGE = "Merge branch 'master' into 'master'" + AUTHOR_FULL_NAME = "Stan Hu" + FILES = ["bin/executable"] + FILES_COUNT = FILES.count + end + + module Repo + HEAD = "master" + BRANCHES = %w[ + feature + fix + fix-blob-path + fix-existing-submodule-dir + fix-mode + gitattributes + gitattributes-updated + master + merge-test + ] + TAGS = %w[v1.0.0 v1.1.0 v1.2.0 v1.2.1] + end + + module RubyBlob + ID = "7e3e39ebb9b2bf433b4ad17313770fbe4051649c" + NAME = "popen.rb" + CONTENT = <<-eos +require 'fileutils' +require 'open3' + +module Popen + extend self + + def popen(cmd, path=nil) + unless cmd.is_a?(Array) + raise RuntimeError, "System commands must be given as an array of strings" + end + + path ||= Dir.pwd + + vars = { + "PWD" => path + } + + options = { + chdir: path + } + + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + + @cmd_output = "" + @cmd_status = 0 + + Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + @cmd_output << stdout.read + @cmd_output << stderr.read + @cmd_status = wait_thr.value.exitstatus + end + + return @cmd_output, @cmd_status + end +end + eos + end +end -- cgit v1.2.1 From 22a34c81aa3801e5b453fd2c0a9364917e0aedbe Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Thu, 5 Jan 2017 13:46:26 +0100 Subject: Use configured git rather than system git --- spec/support/seed_helper.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'spec/support') diff --git a/spec/support/seed_helper.rb b/spec/support/seed_helper.rb index 3f8398a31e3..03fa0a66b9a 100644 --- a/spec/support/seed_helper.rb +++ b/spec/support/seed_helper.rb @@ -25,32 +25,32 @@ module SeedHelper end def create_bare_seeds - system(git_env, *%W(git clone --bare #{GITLAB_URL}), + system(git_env, *%W(#{Gitlab.config.git.bin_path} clone --bare #{GITLAB_URL}), chdir: SEED_REPOSITORY_PATH, out: '/dev/null', err: '/dev/null') end def create_normal_seeds - system(git_env, *%W(git clone #{TEST_REPO_PATH} #{TEST_NORMAL_REPO_PATH}), + system(git_env, *%W(#{Gitlab.config.git.bin_path} clone #{TEST_REPO_PATH} #{TEST_NORMAL_REPO_PATH}), out: '/dev/null', err: '/dev/null') end def create_mutable_seeds - system(git_env, *%W(git clone #{TEST_REPO_PATH} #{TEST_MUTABLE_REPO_PATH}), + system(git_env, *%W(#{Gitlab.config.git.bin_path} clone #{TEST_REPO_PATH} #{TEST_MUTABLE_REPO_PATH}), out: '/dev/null', err: '/dev/null') system(git_env, *%w(git branch -t feature origin/feature), chdir: TEST_MUTABLE_REPO_PATH, out: '/dev/null', err: '/dev/null') - system(git_env, *%W(git remote add expendable #{GITLAB_URL}), + system(git_env, *%W(#{Gitlab.config.git.bin_path} remote add expendable #{GITLAB_URL}), chdir: TEST_MUTABLE_REPO_PATH, out: '/dev/null', err: '/dev/null') end def create_broken_seeds - system(git_env, *%W(git clone --bare #{TEST_REPO_PATH} #{TEST_BROKEN_REPO_PATH}), + system(git_env, *%W(#{Gitlab.config.git.bin_path} clone --bare #{TEST_REPO_PATH} #{TEST_BROKEN_REPO_PATH}), out: '/dev/null', err: '/dev/null') -- cgit v1.2.1 From ca404170f0173f180b530fbc331fc73e122a4317 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Tue, 3 Jan 2017 10:46:17 -0600 Subject: exclude script type=text/template from dom scrubbing --- spec/support/javascript_fixtures_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec/support') diff --git a/spec/support/javascript_fixtures_helpers.rb b/spec/support/javascript_fixtures_helpers.rb index 99e98eebdb4..7cf0e29db34 100644 --- a/spec/support/javascript_fixtures_helpers.rb +++ b/spec/support/javascript_fixtures_helpers.rb @@ -34,7 +34,7 @@ module JavaScriptFixturesHelpers link_tags = doc.css('link') link_tags.remove - scripts = doc.css('script') + scripts = doc.css("script:not([type='text/template'])") scripts.remove fixture = doc.to_html -- cgit v1.2.1 From 8cee3b1d36afdb95934e8867fb60c23565c2d330 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Tue, 3 Jan 2017 15:26:14 -0600 Subject: force utf-8 encoding for prior to fixture parsing to prevent nokogiri issues --- spec/support/javascript_fixtures_helpers.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'spec/support') diff --git a/spec/support/javascript_fixtures_helpers.rb b/spec/support/javascript_fixtures_helpers.rb index 7cf0e29db34..d15aac61b18 100644 --- a/spec/support/javascript_fixtures_helpers.rb +++ b/spec/support/javascript_fixtures_helpers.rb @@ -26,6 +26,7 @@ module JavaScriptFixturesHelpers def store_frontend_fixture(response, fixture_file_name) fixture_file_name = File.expand_path(fixture_file_name, FIXTURE_PATH) fixture = response.body + fixture.force_encoding("utf-8") response_mime_type = Mime::Type.lookup(response.content_type) if response_mime_type.html? -- cgit v1.2.1 From a8177e03e5eeade5b8af405dbb4bcd8a6d06bb0a Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Mon, 9 Jan 2017 18:19:48 +0100 Subject: Introduce "stub_env" test helper for safely stubbing environment variables --- spec/support/stub_env.rb | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 spec/support/stub_env.rb (limited to 'spec/support') diff --git a/spec/support/stub_env.rb b/spec/support/stub_env.rb new file mode 100644 index 00000000000..18597b5c71f --- /dev/null +++ b/spec/support/stub_env.rb @@ -0,0 +1,7 @@ +module StubENV + def stub_env(key, value) + allow(ENV).to receive(:[]).and_call_original unless @env_already_stubbed + @env_already_stubbed ||= true + allow(ENV).to receive(:[]).with(key).and_return(value) + end +end -- cgit v1.2.1 From e75b1f11057829964dd9c3aac3b0a0deb964707e Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 12 Jan 2017 22:31:02 +0000 Subject: Merge branch '24185-legacy-ci-status-reactive-cache' into 'security' Use ReactiveCaching to update external CI status asynchronously See https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/2055 --- spec/support/reactive_caching_helpers.rb | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'spec/support') diff --git a/spec/support/reactive_caching_helpers.rb b/spec/support/reactive_caching_helpers.rb index 279db3c5748..98eb57f8b54 100644 --- a/spec/support/reactive_caching_helpers.rb +++ b/spec/support/reactive_caching_helpers.rb @@ -3,31 +3,35 @@ module ReactiveCachingHelpers ([subject.class.reactive_cache_key.call(subject)].flatten + qualifiers).join(':') end - def stub_reactive_cache(subject = nil, data = nil) + def alive_reactive_cache_key(subject, *qualifiers) + reactive_cache_key(subject, *(qualifiers + ['alive'])) + end + + def stub_reactive_cache(subject = nil, data = nil, *qualifiers) allow(ReactiveCachingWorker).to receive(:perform_async) allow(ReactiveCachingWorker).to receive(:perform_in) - write_reactive_cache(subject, data) if data + write_reactive_cache(subject, data, *qualifiers) if data end - def read_reactive_cache(subject) - Rails.cache.read(reactive_cache_key(subject)) + def read_reactive_cache(subject, *qualifiers) + Rails.cache.read(reactive_cache_key(subject, *qualifiers)) end - def write_reactive_cache(subject, data) - start_reactive_cache_lifetime(subject) - Rails.cache.write(reactive_cache_key(subject), data) + def write_reactive_cache(subject, data, *qualifiers) + start_reactive_cache_lifetime(subject, *qualifiers) + Rails.cache.write(reactive_cache_key(subject, *qualifiers), data) end - def reactive_cache_alive?(subject) - Rails.cache.read(reactive_cache_key(subject, 'alive')) + def reactive_cache_alive?(subject, *qualifiers) + Rails.cache.read(alive_reactive_cache_key(subject, *qualifiers)) end - def invalidate_reactive_cache(subject) - Rails.cache.delete(reactive_cache_key(subject, 'alive')) + def invalidate_reactive_cache(subject, *qualifiers) + Rails.cache.delete(alive_reactive_cache_key(subject, *qualifiers)) end - def start_reactive_cache_lifetime(subject) - Rails.cache.write(reactive_cache_key(subject, 'alive'), true) + def start_reactive_cache_lifetime(subject, *qualifiers) + Rails.cache.write(alive_reactive_cache_key(subject, *qualifiers), true) end def expect_reactive_cache_update_queued(subject) -- cgit v1.2.1 From c3a940000ea20d6682313640e1a0fda9ff68dbdf Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Wed, 12 Oct 2016 19:07:36 +0200 Subject: Handles unsubscribe from notifications via email - allows unsubscription processing of email in format "reply+%{key}+unsubscribe@acme.com" (example) - if config.address includes %{key} and replies are enabled every unsubscriable message will include mailto: link in its List-Unsubscribe header --- spec/support/notify_shared_examples.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'spec/support') diff --git a/spec/support/notify_shared_examples.rb b/spec/support/notify_shared_examples.rb index 49867aa5cc4..a3724b801b3 100644 --- a/spec/support/notify_shared_examples.rb +++ b/spec/support/notify_shared_examples.rb @@ -179,9 +179,24 @@ shared_examples 'it should show Gmail Actions View Commit link' do end shared_examples 'an unsubscribeable thread' do + it_behaves_like 'an unsubscribeable thread with incoming address without %{key}' + + it 'has a List-Unsubscribe header in the correct format' do + is_expected.to have_header 'List-Unsubscribe', /unsubscribe/ + is_expected.to have_header 'List-Unsubscribe', /mailto/ + is_expected.to have_header 'List-Unsubscribe', /^<.+,.+>$/ + end + + it { is_expected.to have_body_text /unsubscribe/ } +end + +shared_examples 'an unsubscribeable thread with incoming address without %{key}' do + include_context 'reply-by-email is enabled with incoming address without %{key}' + it 'has a List-Unsubscribe header in the correct format' do is_expected.to have_header 'List-Unsubscribe', /unsubscribe/ - is_expected.to have_header 'List-Unsubscribe', /^<.+>$/ + is_expected.not_to have_header 'List-Unsubscribe', /mailto/ + is_expected.to have_header 'List-Unsubscribe', /^<[^,]+>$/ end it { is_expected.to have_body_text /unsubscribe/ } -- cgit v1.2.1 From 64dd41a0e21360c380cab394f8a5c9b4945b7fd1 Mon Sep 17 00:00:00 2001 From: Bryce Johnson Date: Tue, 20 Dec 2016 15:44:24 +0100 Subject: Backport timetracking frontend to CE. --- spec/support/time_tracking_shared_examples.rb | 82 +++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 spec/support/time_tracking_shared_examples.rb (limited to 'spec/support') diff --git a/spec/support/time_tracking_shared_examples.rb b/spec/support/time_tracking_shared_examples.rb new file mode 100644 index 00000000000..02657684b57 --- /dev/null +++ b/spec/support/time_tracking_shared_examples.rb @@ -0,0 +1,82 @@ +shared_examples 'issuable time tracker' do + it 'renders the sidebar component empty state' do + page.within '.time-tracking-no-tracking-pane' do + expect(page).to have_content 'No estimate or time spent' + end + end + + it 'updates the sidebar component when estimate is added' do + submit_time('/estimate 3w 1d 1h') + + page.within '.time-tracking-estimate-only-pane' do + expect(page).to have_content '3w 1d 1h' + end + end + + it 'updates the sidebar component when spent is added' do + submit_time('/spend 3w 1d 1h') + + page.within '.time-tracking-spend-only-pane' do + expect(page).to have_content '3w 1d 1h' + end + end + + it 'shows the comparison when estimate and spent are added' do + submit_time('/estimate 3w 1d 1h') + submit_time('/spend 3w 1d 1h') + + page.within '.time-tracking-comparison-pane' do + expect(page).to have_content '3w 1d 1h' + end + end + + it 'updates the sidebar component when estimate is removed' do + submit_time('/estimate 3w 1d 1h') + submit_time('/remove_estimate') + + page.within '#issuable-time-tracker' do + expect(page).to have_content 'No estimate or time spent' + end + end + + it 'updates the sidebar component when spent is removed' do + submit_time('/spend 3w 1d 1h') + submit_time('/remove_time_spent') + + page.within '#issuable-time-tracker' do + expect(page).to have_content 'No estimate or time spent' + end + end + + it 'shows the help state when icon is clicked' do + page.within '#issuable-time-tracker' do + find('.help-button').click + expect(page).to have_content 'Track time with slash commands' + expect(page).to have_content 'Learn more' + end + end + + it 'hides the help state when close icon is clicked' do + page.within '#issuable-time-tracker' do + find('.help-button').click + find('.close-help-button').click + + expect(page).not_to have_content 'Track time with slash commands' + expect(page).not_to have_content 'Learn more' + end + end + + it 'displays the correct help url' do + page.within '#issuable-time-tracker' do + find('.help-button').click + + expect(find_link('Learn more')[:href]).to have_content('/help/workflow/time_tracking.md') + end + end +end + +def submit_time(slash_command) + fill_in 'note[note]', with: slash_command + click_button 'Comment' + wait_for_ajax +end -- cgit v1.2.1 From 02e1e4819234662faddd7d8eb5c54d9bfdf9e7e6 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 22 Nov 2016 14:29:25 +0100 Subject: more refactoring and fixing old specs --- spec/support/cycle_analytics_helpers/test_generation.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'spec/support') diff --git a/spec/support/cycle_analytics_helpers/test_generation.rb b/spec/support/cycle_analytics_helpers/test_generation.rb index 8e19a6c92e2..ab624161616 100644 --- a/spec/support/cycle_analytics_helpers/test_generation.rb +++ b/spec/support/cycle_analytics_helpers/test_generation.rb @@ -1,8 +1,13 @@ +class CycleAnalyticsTest < CycleAnalytics + def method_missing(method_sym, *arguments, &block) + classify_stage(method_sym).new(project: @project, options: @options, stage: method_sym).median + end +end + # rubocop:disable Metrics/AbcSize # Note: The ABC size is large here because we have a method generating test cases with # multiple nested contexts. This shouldn't count as a violation. - module CycleAnalyticsHelpers module TestGeneration # Generate the most common set of specs that all cycle analytics phases need to have. -- cgit v1.2.1 From 8183e848648bc737e4a09f76f4f55ee1cf106b26 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 23 Nov 2016 15:35:47 +0100 Subject: fix tricky test failure to do with private method --- spec/support/cycle_analytics_helpers/test_generation.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'spec/support') diff --git a/spec/support/cycle_analytics_helpers/test_generation.rb b/spec/support/cycle_analytics_helpers/test_generation.rb index ab624161616..dc866b11429 100644 --- a/spec/support/cycle_analytics_helpers/test_generation.rb +++ b/spec/support/cycle_analytics_helpers/test_generation.rb @@ -56,7 +56,7 @@ module CycleAnalyticsHelpers end median_time_difference = time_differences.sort[2] - expect(subject.send(phase)).to be_within(5).of(median_time_difference) + expect(subject.public_send(phase)).to be_within(5).of(median_time_difference) end context "when the data belongs to another project" do @@ -88,7 +88,7 @@ module CycleAnalyticsHelpers # Turn off the stub before checking assertions allow(self).to receive(:project).and_call_original - expect(subject.send(phase)).to be_nil + expect(subject.public_send(phase)).to be_nil end end @@ -111,7 +111,7 @@ module CycleAnalyticsHelpers Timecop.freeze(end_time + 1.day) { post_fn[self, data] } if post_fn - expect(subject.send(phase)).to be_nil + expect(subject.public_send(phase)).to be_nil end end end @@ -131,7 +131,7 @@ module CycleAnalyticsHelpers Timecop.freeze(end_time + 1.day) { post_fn[self, data] } if post_fn end - expect(subject.send(phase)).to be_nil + expect(subject.public_send(phase)).to be_nil end end end @@ -150,7 +150,7 @@ module CycleAnalyticsHelpers post_fn[self, data] if post_fn end - expect(subject.send(phase)).to be_nil + expect(subject.public_send(phase)).to be_nil end end end @@ -158,7 +158,7 @@ module CycleAnalyticsHelpers context "when none of the start / end conditions are matched" do it "returns nil" do - expect(subject.send(phase)).to be_nil + expect(subject.public_send(phase)).to be_nil end end end -- cgit v1.2.1 From 69ecd951a9e0acbc31f0a4b9b02e8a1981ceff1e Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 1 Dec 2016 12:44:35 +0100 Subject: refactor fetcher and fixed specs --- .../support/cycle_analytics_helpers/test_generation.rb | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'spec/support') diff --git a/spec/support/cycle_analytics_helpers/test_generation.rb b/spec/support/cycle_analytics_helpers/test_generation.rb index dc866b11429..35b40d73191 100644 --- a/spec/support/cycle_analytics_helpers/test_generation.rb +++ b/spec/support/cycle_analytics_helpers/test_generation.rb @@ -1,9 +1,3 @@ -class CycleAnalyticsTest < CycleAnalytics - def method_missing(method_sym, *arguments, &block) - classify_stage(method_sym).new(project: @project, options: @options, stage: method_sym).median - end -end - # rubocop:disable Metrics/AbcSize # Note: The ABC size is large here because we have a method generating test cases with @@ -56,7 +50,7 @@ module CycleAnalyticsHelpers end median_time_difference = time_differences.sort[2] - expect(subject.public_send(phase)).to be_within(5).of(median_time_difference) + expect(subject[phase].median).to be_within(5).of(median_time_difference) end context "when the data belongs to another project" do @@ -88,7 +82,7 @@ module CycleAnalyticsHelpers # Turn off the stub before checking assertions allow(self).to receive(:project).and_call_original - expect(subject.public_send(phase)).to be_nil + expect(subject[phase].median).to be_nil end end @@ -111,7 +105,7 @@ module CycleAnalyticsHelpers Timecop.freeze(end_time + 1.day) { post_fn[self, data] } if post_fn - expect(subject.public_send(phase)).to be_nil + expect(subject[phase].median).to be_nil end end end @@ -131,7 +125,7 @@ module CycleAnalyticsHelpers Timecop.freeze(end_time + 1.day) { post_fn[self, data] } if post_fn end - expect(subject.public_send(phase)).to be_nil + expect(subject[phase].median).to be_nil end end end @@ -150,7 +144,7 @@ module CycleAnalyticsHelpers post_fn[self, data] if post_fn end - expect(subject.public_send(phase)).to be_nil + expect(subject[phase].median).to be_nil end end end @@ -158,7 +152,7 @@ module CycleAnalyticsHelpers context "when none of the start / end conditions are matched" do it "returns nil" do - expect(subject.public_send(phase)).to be_nil + expect(subject[phase].median).to be_nil end end end -- cgit v1.2.1 From 0f3c9355c1b57a56b4027df4deb78a2520596b15 Mon Sep 17 00:00:00 2001 From: Ruben Davila Date: Wed, 18 Jan 2017 10:48:16 -0600 Subject: Add some API endpoints for time tracking. New endpoints are: POST :project_id/(issues|merge_requests)/(:issue_id|:merge_request_id)/time_estimate" POST :project_id/(issues|merge_requests)/(:issue_id|:merge_request_id)/reset_time_estimate" POST :project_id/(issues|merge_requests)/(:issue_id|:merge_request_id)/add_spent_time" POST :project_id/(issues|merge_requests)/(:issue_id|:merge_request_id)/reset_spent_time" GET :project_id/(issues|merge_requests)/(:issue_id|:merge_request_id)/time_stats" --- spec/support/api/time_tracking_shared_examples.rb | 132 ++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 spec/support/api/time_tracking_shared_examples.rb (limited to 'spec/support') diff --git a/spec/support/api/time_tracking_shared_examples.rb b/spec/support/api/time_tracking_shared_examples.rb new file mode 100644 index 00000000000..210cd5817e0 --- /dev/null +++ b/spec/support/api/time_tracking_shared_examples.rb @@ -0,0 +1,132 @@ +shared_examples 'an unauthorized API user' do + it { is_expected.to eq(403) } +end + +shared_examples 'time tracking endpoints' do |issuable_name| + issuable_collection_name = issuable_name.pluralize + + describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_estimate" do + context 'with an unauthorized user' do + subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_estimate", non_member), duration: '1w') } + + it_behaves_like 'an unauthorized API user' + end + + it "sets the time estimate for #{issuable_name}" do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_estimate", user), duration: '1w' + + expect(response).to have_http_status(200) + expect(json_response['human_time_estimate']).to eq('1w') + end + + describe 'updating the current estimate' do + before do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_estimate", user), duration: '1w' + end + + context 'when duration has a bad format' do + it 'does not modify the original estimate' do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_estimate", user), duration: 'foo' + + expect(response).to have_http_status(400) + expect(issuable.reload.human_time_estimate).to eq('1w') + end + end + + context 'with a valid duration' do + it 'updates the estimate' do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_estimate", user), duration: '3w1h' + + expect(response).to have_http_status(200) + expect(issuable.reload.human_time_estimate).to eq('3w 1h') + end + end + end + end + + describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/reset_time_estimate" do + context 'with an unauthorized user' do + subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/reset_time_estimate", non_member)) } + + it_behaves_like 'an unauthorized API user' + end + + it "resets the time estimate for #{issuable_name}" do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/reset_time_estimate", user) + + expect(response).to have_http_status(200) + expect(json_response['time_estimate']).to eq(0) + end + end + + describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/add_spent_time" do + context 'with an unauthorized user' do + subject do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", non_member), + duration: '2h' + end + + it_behaves_like 'an unauthorized API user' + end + + it "add spent time for #{issuable_name}" do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", user), + duration: '2h' + + expect(response).to have_http_status(201) + expect(json_response['human_total_time_spent']).to eq('2h') + end + + context 'when subtracting time' do + it 'subtracts time of the total spent time' do + issuable.update_attributes!(spend_time: { duration: 7200, user: user }) + + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", user), + duration: '-1h' + + expect(response).to have_http_status(201) + expect(json_response['total_time_spent']).to eq(3600) + end + end + + context 'when time to subtract is greater than the total spent time' do + it 'does not modify the total time spent' do + issuable.update_attributes!(spend_time: { duration: 7200, user: user }) + + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/add_spent_time", user), + duration: '-1w' + + expect(response).to have_http_status(400) + expect(json_response['message']['time_spent'].first).to match(/exceeds the total time spent/) + end + end + end + + describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/reset_spent_time" do + context 'with an unauthorized user' do + subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/reset_spent_time", non_member)) } + + it_behaves_like 'an unauthorized API user' + end + + it "resets spent time for #{issuable_name}" do + post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/reset_spent_time", user) + + expect(response).to have_http_status(200) + expect(json_response['total_time_spent']).to eq(0) + end + end + + describe "GET /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_stats" do + it "returns the time stats for #{issuable_name}" do + issuable.update_attributes!(spend_time: { duration: 1800, user: user }, + time_estimate: 3600) + + get api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.id}/time_stats", user) + + expect(response).to have_http_status(200) + expect(json_response['total_time_spent']).to eq(1800) + expect(json_response['time_estimate']).to eq(3600) + end + end +end -- cgit v1.2.1 From e59623e7388d67433ede87db1dad134f6f176f98 Mon Sep 17 00:00:00 2001 From: jurre Date: Thu, 15 Dec 2016 21:48:26 +0100 Subject: Mark MR as WIP when pushing WIP commits --- spec/support/test_env.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'spec/support') diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 4cf81be3adc..90f1a9c8798 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -35,7 +35,8 @@ module TestEnv 'conflict-missing-side' => 'eb227b3', 'conflict-non-utf8' => 'd0a293c', 'conflict-too-large' => '39fa04f', - 'deleted-image-test' => '6c17798' + 'deleted-image-test' => '6c17798', + 'wip' => 'b9238ee' } # gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily -- cgit v1.2.1 From f30ad3ff1f958ccb783f3fab68269e61f1a79b3d Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Wed, 18 Jan 2017 08:33:13 -0500 Subject: fix nested tasks in ordered list --- spec/support/taskable_shared_examples.rb | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'spec/support') diff --git a/spec/support/taskable_shared_examples.rb b/spec/support/taskable_shared_examples.rb index ad1c783df4d..1b6c33248c9 100644 --- a/spec/support/taskable_shared_examples.rb +++ b/spec/support/taskable_shared_examples.rb @@ -33,6 +33,30 @@ shared_examples 'a Taskable' do end end + describe 'with nested tasks' do + before do + subject.description = <<-EOT.strip_heredoc + - [ ] Task a + - [x] Task a.1 + - [ ] Task a.2 + - [ ] Task b + + 1. [ ] Task 1 + 1. [ ] Task 1.1 + 1. [ ] Task 1.2 + 1. [x] Task 2 + 1. [x] Task 2.1 + EOT + end + + it 'returns the correct task status' do + expect(subject.task_status).to match('3 of') + expect(subject.task_status).to match('9 tasks completed') + expect(subject.task_status_short).to match('3/') + expect(subject.task_status_short).to match('9 tasks') + end + end + describe 'with an incomplete task' do before do subject.description = <<-EOT.strip_heredoc -- cgit v1.2.1 From 88e627cf14b47ca5d63f2cb0ffe24124fb4b116a Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Sun, 22 Jan 2017 18:22:02 +0100 Subject: Fix race conditions for AuthorizedProjectsWorker There were two cases that could be problematic: 1. Because sometimes AuthorizedProjectsWorker would be scheduled in a transaction it was possible for a job to run/complete before a COMMIT; resulting in it either producing an error, or producing no new data. 2. When scheduling jobs the code would not wait until completion. This could lead to a user creating a project and then immediately trying to push to it. Usually this will work fine, but given enough load it might take a few seconds before a user has access. The first one is problematic, the second one is mostly just annoying (but annoying enough to warrant a solution). This commit changes two things to deal with this: 1. Sidekiq scheduling now takes places after a COMMIT, this is ensured by scheduling using Rails' after_commit hook instead of doing so in an arbitrary method. 2. When scheduling jobs the calling thread now waits for all jobs to complete. Solution 2 requires tracking of job completions. Sidekiq provides a way to find a job by its ID, but this involves scanning over the entire queue; something that is very in-efficient for large queues. As such a more efficient solution is necessary. There are two main Gems that can do this in a more efficient manner: * sidekiq-status * sidekiq_status No, this is not a joke. Both Gems do a similar thing (but slightly different), and the only difference in their name is a dash vs an underscore. Both Gems however provide far more than just checking if a job has been completed, and both have their problems. sidekiq-status does not appear to be actively maintained, with the last release being in 2015. It also has some issues during testing as API calls are not stubbed in any way. sidekiq_status on the other hand does not appear to be very popular, and introduces a similar amount of code. Because of this I opted to write a simple home grown solution. After all, all we need is storing a job ID somewhere so we can efficiently look it up; we don't need extra web UIs (as provided by sidekiq-status) or complex APIs to update progress, etc. This is where Gitlab::SidekiqStatus comes in handy. This namespace contains some code used for tracking, removing, and looking up job IDs; all without having to scan over an entire queue. Data is removed explicitly, but also expires automatically just in case. Using this API we can now schedule jobs in a fork-join like manner: we schedule the jobs in Sidekiq, process them in parallel, then wait for completion. By using Sidekiq we can leverage all the benefits such as being able to scale across multiple cores and hosts, retrying failed jobs, etc. The one downside is that we need to make sure we can deal with unexpected increases in job processing timings. To deal with this the class Gitlab::JobWaiter (used for waiting for jobs to complete) will only wait a number of seconds (30 by default). Once this timeout is reached it will simply return. For GitLab.com almost all AuthorizedProjectWorker jobs complete in seconds, only very rarely do we spike to job timings of around a minute. These in turn seem to be the result of external factors (e.g. deploys), in which case a user is most likely not able to use the system anyway. In short, this new solution should ensure that jobs are processed properly and that in almost all cases a user has access to their resources whenever they need to have access. --- spec/support/sidekiq.rb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 spec/support/sidekiq.rb (limited to 'spec/support') diff --git a/spec/support/sidekiq.rb b/spec/support/sidekiq.rb new file mode 100644 index 00000000000..575d3451150 --- /dev/null +++ b/spec/support/sidekiq.rb @@ -0,0 +1,5 @@ +require 'sidekiq/testing/inline' + +Sidekiq::Testing.server_middleware do |chain| + chain.add Gitlab::SidekiqStatus::ServerMiddleware +end -- cgit v1.2.1