diff options
author | Zeger-Jan van de Weg <zegerjan@gitlab.com> | 2018-01-04 15:37:30 +0300 |
---|---|---|
committer | Zeger-Jan van de Weg <zegerjan@gitlab.com> | 2018-01-04 15:37:30 +0300 |
commit | 31c8ac664e83563db72604ed4277ea2e46b16e5e (patch) | |
tree | 074d953393aa105dc8b0ebaf0448cfcbe5d140f3 | |
parent | 041babfa3775e3e48a490cf2b1dd59b489916f09 (diff) | |
parent | d724550940072bd01233d3c2d9488347f9600dee (diff) |
Merge branch 'rspec-tests' into 'master'
Add rspec unit and integration tests
Closes #832
See merge request gitlab-org/gitaly!504
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 17 | ||||
-rw-r--r-- | ruby/Gemfile | 1 | ||||
-rw-r--r-- | ruby/Gemfile.lock | 14 | ||||
-rw-r--r-- | ruby/README.md | 17 | ||||
-rw-r--r-- | ruby/spec/gitaly/ref_service_spec.rb | 31 | ||||
-rw-r--r-- | ruby/spec/gitaly/repository_service_spec.rb | 22 | ||||
-rw-r--r-- | ruby/spec/integration_helper.rb | 47 | ||||
-rw-r--r-- | ruby/spec/lib/gitlab/config_spec.rb | 20 | ||||
-rw-r--r-- | ruby/spec/spec_helper.rb | 2 | ||||
-rw-r--r-- | ruby/spec/test_repo_helper.rb | 46 |
11 files changed, 212 insertions, 7 deletions
diff --git a/.gitignore b/.gitignore index 6fd3edea3..4b01bfbd4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ /.ruby-bundle /ruby/vendor/bundle /ruby/.bundle +/ruby/tmp +*.socket @@ -72,10 +72,16 @@ force-ruby-bundle: # Assembles all runtime components into a directory # Used by the GDK: run `make assemble ASSEMBLY_ROOT=.../gitaly` .PHONY: assemble -assemble: force-ruby-bundle build +assemble: force-ruby-bundle build assemble-internal + +# assemble-internal does not force 'bundle install' to run again +.PHONY: assemble-internal +assemble-internal: build rm -rf $(ASSEMBLY_ROOT)/bin $(ASSEMBLY_ROOT)/ruby mkdir -p $(ASSEMBLY_ROOT)/bin + rm -rf ruby/tmp cp -r ruby $(ASSEMBLY_ROOT)/ruby + rm -rf $(ASSEMBLY_ROOT)/ruby/spec install $(foreach cmd,$(COMMANDS),$(BIN_BUILD_DIR)/$(cmd)) $(ASSEMBLY_ROOT)/bin binaries: assemble @@ -109,9 +115,16 @@ $(TEST_REPO): prepare-tests: $(TARGET_SETUP) $(TEST_REPO) .ruby-bundle .PHONY: test -test: prepare-tests +test: test-go rspec + +.PHONY: test-go +test-go: prepare-tests @go test $(LOCAL_PACKAGES) +.PHONY: rspec +rspec: assemble-internal prepare-tests + cd ruby && bundle exec rspec + .PHONY: test-changes test-changes: prepare-tests cd $(PKG_BUILD_DIR) && go test $(CHANGED_LOCAL_GO_PACKAGES) diff --git a/ruby/Gemfile b/ruby/Gemfile index 4276c25a5..95bf6367f 100644 --- a/ruby/Gemfile +++ b/ruby/Gemfile @@ -9,4 +9,5 @@ gem 'gollum-rugged_adapter', '~> 0.4.4', require: false group :development, :test do gem 'gitlab-styles', '~> 2.0.0', require: false + gem 'rspec', require: false end diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock index 6a6019b14..d8976893f 100644 --- a/ruby/Gemfile.lock +++ b/ruby/Gemfile.lock @@ -89,6 +89,19 @@ GEM rake (12.1.0) rdoc (4.3.0) rouge (2.2.1) + rspec (3.6.0) + rspec-core (~> 3.6.0) + rspec-expectations (~> 3.6.0) + rspec-mocks (~> 3.6.0) + rspec-core (3.6.0) + rspec-support (~> 3.6.0) + rspec-expectations (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-mocks (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-support (3.6.0) rubocop (0.50.0) parallel (~> 1.10) parser (>= 2.3.3.1, < 3.0) @@ -126,6 +139,7 @@ DEPENDENCIES gollum-lib (~> 4.2) gollum-rugged_adapter (~> 0.4.4) rdoc (~> 4.2) + rspec BUNDLED WITH 1.16.0 diff --git a/ruby/README.md b/ruby/README.md index 8125f97bf..7a8dc3cfa 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -22,11 +22,18 @@ mode 0700. It runs as the same user as the Gitaly parent process. ## Testing -All tests for code in Gitaly-ruby go through the parent Gitaly process -for two reasons. Firstly, testing through the parent proves that the -Ruby code under test is reachable. Secondly, testing through the -parent will make it easier to create a Go implementation in the parent -if we ever want to do that. +There are three sets of test that exercise gitaly-ruby: + +- Top-level Go integration tests +- Rspec integration tests (`spec/gitaly`) +- Rspec unit tests (`spec/lib`) + +If you are working on the Ruby code and you want to run the Rspec +tests only, without recompiling the Go parts then do the following: + +- run `make rspec` at the top level at least once, to compile Go binaries and get the test repo; +- edit code under the current directory (`ruby`); +- run `bundle exec rspec` in the current directory. ## Vendored copy of Gitlab::Git diff --git a/ruby/spec/gitaly/ref_service_spec.rb b/ruby/spec/gitaly/ref_service_spec.rb new file mode 100644 index 000000000..96a648639 --- /dev/null +++ b/ruby/spec/gitaly/ref_service_spec.rb @@ -0,0 +1,31 @@ +require 'integration_helper' +require 'securerandom' + +describe Gitaly::RefService do + include IntegrationClient + include TestRepo + + let(:service_stub) { gitaly_stub(:RefService) } + + describe 'CreateBranch' do + it 'can create a branch' do + repo = new_mutable_test_repo + branch_name = 'branch-' + SecureRandom.hex(10) + request = Gitaly::CreateBranchRequest.new( + repository: repo, + name: branch_name, + start_point: 'master' + ) + + response = service_stub.create_branch(request) + + expect(response.status).to eq(:OK) + + # Intentionally instatiate this Rugged::Repository after we performed + # the RPC, to ensure we don't see stale repository state. + rugged = rugged_from_gitaly(repo) + + expect(response.branch.target_commit.id).to eq(rugged.branches[branch_name].target_id) + end + end +end diff --git a/ruby/spec/gitaly/repository_service_spec.rb b/ruby/spec/gitaly/repository_service_spec.rb new file mode 100644 index 000000000..e66458ab5 --- /dev/null +++ b/ruby/spec/gitaly/repository_service_spec.rb @@ -0,0 +1,22 @@ +require 'integration_helper' + +describe Gitaly::RepositoryService do + include IntegrationClient + include TestRepo + + subject { gitaly_stub(:RepositoryService) } + + describe 'RepositoryExists' do + it 'returns false if the repository does not exist' do + request = Gitaly::RepositoryExistsRequest.new(repository: gitaly_repo('default', 'foobar.git')) + response = subject.repository_exists(request) + expect(response.exists).to eq(false) + end + + it 'returns true if the repository exists' do + request = Gitaly::RepositoryExistsRequest.new(repository: test_repo_read_only) + response = subject.repository_exists(request) + expect(response.exists).to eq(true) + end + end +end diff --git a/ruby/spec/integration_helper.rb b/ruby/spec/integration_helper.rb new file mode 100644 index 000000000..0186d0514 --- /dev/null +++ b/ruby/spec/integration_helper.rb @@ -0,0 +1,47 @@ +require 'gitaly' +require 'test_repo_helper' + +SOCKET_PATH = 'gitaly.socket'.freeze +TMP_DIR = File.expand_path('../../tmp', __FILE__) + +module IntegrationClient + def gitaly_stub(service) + klass = Gitaly.const_get(service).const_get(:Stub) + klass.new("unix:tmp/#{SOCKET_PATH}", :this_channel_is_insecure) + end + + def gitaly_repo(storage, relative_path) + Gitaly::Repository.new(storage_name: storage, relative_path: relative_path) + end +end + +def start_gitaly + build_dir = File.expand_path('../../../_build', __FILE__) + gitlab_shell_dir = File.join(TMP_DIR, 'gitlab-shell') + + FileUtils.mkdir_p([TMP_DIR, File.join(gitlab_shell_dir, 'hooks')]) + + config_toml = <<~CONFIG + socket_path = "#{SOCKET_PATH}" + bin_dir = "#{build_dir}/bin" + + [gitlab-shell] + dir = "#{gitlab_shell_dir}" + + [gitaly-ruby] + dir = "#{build_dir}/assembly/ruby" + + [[storage]] + name = "#{DEFAULT_STORAGE_NAME}" + path = "#{DEFAULT_STORAGE_DIR}" + CONFIG + config_path = File.join(TMP_DIR, 'gitaly-rspec-config.toml') + File.write(config_path, config_toml) + + test_log = File.join(TMP_DIR, 'gitaly-rspec-test.log') + options = { out: test_log, err: test_log, chdir: TMP_DIR } + gitaly_pid = spawn(File.join(build_dir, 'bin/gitaly'), config_path, options) + at_exit { Process.kill('KILL', gitaly_pid) } +end + +start_gitaly diff --git a/ruby/spec/lib/gitlab/config_spec.rb b/ruby/spec/lib/gitlab/config_spec.rb new file mode 100644 index 000000000..bd2aaaede --- /dev/null +++ b/ruby/spec/lib/gitlab/config_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe Gitlab::Config do + describe '#gitlab_shell' do + subject { described_class.new.gitlab_shell } + + let(:gitlab_shell_path) { '/foo/bar/gitlab-shell' } + + before do + ENV['GITALY_RUBY_GITLAB_SHELL_PATH'] = gitlab_shell_path + end + + after do + ENV.delete('GITALY_RUBY_GITLAB_SHELL_PATH') + end + + it { expect(subject.path).to eq(gitlab_shell_path) } + it { expect(subject.hooks_path).to eq(File.join(gitlab_shell_path, 'hooks')) } + end +end diff --git a/ruby/spec/spec_helper.rb b/ruby/spec/spec_helper.rb new file mode 100644 index 000000000..2480c77c7 --- /dev/null +++ b/ruby/spec/spec_helper.rb @@ -0,0 +1,2 @@ +require_relative '../lib/gitlab/git.rb' +require 'test_repo_helper' diff --git a/ruby/spec/test_repo_helper.rb b/ruby/spec/test_repo_helper.rb new file mode 100644 index 000000000..53cdfe536 --- /dev/null +++ b/ruby/spec/test_repo_helper.rb @@ -0,0 +1,46 @@ +require 'fileutils' +require 'securerandom' +require 'gitaly' +require 'rugged' + +DEFAULT_STORAGE_DIR = File.expand_path('../../tmp/repositories', __FILE__) +DEFAULT_STORAGE_NAME = 'default'.freeze +TEST_REPO_PATH = File.join(DEFAULT_STORAGE_DIR, 'gitlab-test.git') +TEST_REPO_ORIGIN = '../internal/testhelper/testdata/data/gitlab-test.git'.freeze + +module TestRepo + def self.prepare_test_repository + FileUtils.rm_rf(Dir["#{DEFAULT_STORAGE_DIR}/mutable-*"]) + return if File.directory?(TEST_REPO_PATH) + + FileUtils.mkdir_p(DEFAULT_STORAGE_DIR) + clone_new_repo!(TEST_REPO_PATH) + end + + def test_repo_read_only + Gitaly::Repository.new(storage_name: DEFAULT_STORAGE_NAME, relative_path: File.basename(TEST_REPO_PATH)) + end + + def new_mutable_test_repo + relative_path = "mutable-#{SecureRandom.hex(6)}.git" + TestRepo.clone_new_repo!(File.join(DEFAULT_STORAGE_DIR, relative_path)) + Gitaly::Repository.new(storage_name: DEFAULT_STORAGE_NAME, relative_path: relative_path) + end + + def rugged_from_gitaly(gitaly_repo) + Rugged::Repository.new(repo_path_from_gitaly(gitaly_repo)) + end + + def repo_path_from_gitaly(gitaly_repo) + storage_name = gitaly_repo.storage_name + raise "this helper does not know storage #{storage_name.inspect}" unless storage_name == DEFAULT_STORAGE_NAME + File.join(DEFAULT_STORAGE_DIR, gitaly_repo.relative_path) + end + + def self.clone_new_repo!(destination) + return if system(*%W[git clone --quiet --bare #{TEST_REPO_ORIGIN} #{destination}]) + abort "Failed to clone test repo. Try running 'make prepare-tests' and try again." + end +end + +TestRepo.prepare_test_repository |