gitlab-qa 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -25,6 +25,10 @@ command in your system.
25
25
 
26
26
  `gitlab-qa Test::Instance::Image CE|EE|<full image address>`
27
27
 
28
+ 1. Run tests against a Docker image with GitLab and Mattermost:
29
+
30
+ `gitlab-qa Test::Integration::Mattermost CE|EE|<full image address>`
31
+
28
32
  1. Test upgrade process:
29
33
 
30
34
  `gitlab-qa Test::Omnibus::Upgrade CE|EE|<full image address>`
@@ -61,16 +65,29 @@ This scenario tests that the GitLab Docker container works as expected by
61
65
  running tests against it.
62
66
 
63
67
  To run tests against the GitLab containers, a GitLab QA (`gitlab/gitlab-qa`)
64
- container is spin up and tests are run from it by running the `Test::Instance`
68
+ container is spun up and tests are run from it by running the `Test::Instance`
65
69
  scenario (located under `qa/scenario/test/instance` in the GitLab codebase).
66
70
 
71
+ ### `Test::Integration::Mattermost CE|EE|<full image address>`
72
+
73
+ This scenario tests that GitLab instance works as expected when
74
+ enabling the embedded Mattermost server (see `Test::Instance::Image`
75
+ above).
76
+
67
77
  ### `Test::Instance::Any CE|EE|<full image address>`
68
78
 
69
79
  This scenario tests that the any GitLab instance works as expected by running
70
- tests against it (see `Test::Instance::Image` below).
80
+ tests against it (see `Test::Instance::Image` above).
71
81
 
72
82
  ## Supported environment variables
73
83
 
74
84
  * `GITLAB_USERNAME` - username to use when signing in to GitLab
75
- * `GITLAB_PASSWORD` - password to use when signing in to GitLab
85
+ * `GITLAB_PASSWORD` - password to use when signing in to GitLab
76
86
  * `EE_LICENSE` - Enterprise Edition license
87
+ * `QA_SCREENSHOTS_DIR` - Path to a directory where screenshots for failing tests
88
+ will be saved (default: `/tmp/gitlab-qa-screenshots`)
89
+ * `DOCKER_HOST` - Docker host to run tests against (default: `http://localhost`)
90
+
91
+ ## Contributing
92
+
93
+ Please see the [contribution guidelines](CONTRIBUTING.md)
@@ -22,14 +22,22 @@ module Gitlab
22
22
  autoload :Image, 'qa/scenario/test/omnibus/image'
23
23
  autoload :Upgrade, 'qa/scenario/test/omnibus/upgrade'
24
24
  end
25
+
26
+ module Integration
27
+ autoload :Mattermost, 'qa/scenario/test/integration/mattermost'
28
+ end
25
29
  end
26
30
  end
27
31
 
32
+ module Component
33
+ autoload :Gitlab, 'qa/component/gitlab'
34
+ autoload :Specs, 'qa/component/specs'
35
+ end
36
+
28
37
  module Docker
29
38
  autoload :Engine, 'qa/docker/engine'
30
39
  autoload :Command, 'qa/docker/command'
31
- autoload :Gitlab, 'qa/docker/gitlab'
32
- autoload :Specs, 'qa/docker/specs'
40
+ autoload :Shellout, 'qa/docker/shellout'
33
41
  end
34
42
  end
35
43
  end
@@ -1,28 +1,42 @@
1
1
  require 'securerandom'
2
2
  require 'net/http'
3
3
  require 'uri'
4
+ require 'forwardable'
5
+ require 'shellwords'
4
6
 
5
7
  module Gitlab
6
8
  module QA
7
- module Docker
9
+ module Component
8
10
  class Gitlab
11
+ extend Forwardable
9
12
  include Scenario::Actable
10
13
 
11
14
  # rubocop:disable Style/Semicolon
12
15
 
13
- attr_accessor :image, :tag, :volumes, :network
14
- attr_reader :name, :release
16
+ attr_reader :release, :docker
17
+ attr_accessor :volumes, :network, :environment, :network_aliases
18
+
19
+ def_delegators :release, :tag, :image, :edition
15
20
 
16
21
  def initialize
17
22
  @docker = Docker::Engine.new
23
+ @environment = {}
24
+ @volumes = {}
25
+ @network_aliases = []
26
+
27
+ self.release = 'CE'
18
28
  end
19
29
 
20
- def name=(name)
21
- @name = "#{name}-#{SecureRandom.hex(4)}"
30
+ def omnibus_config=(config)
31
+ @environment['GITLAB_OMNIBUS_CONFIG'] = config
22
32
  end
23
33
 
24
34
  def release=(release)
25
- @release ||= Release.new(release)
35
+ @release = Release.new(release)
36
+ end
37
+
38
+ def name
39
+ @name ||= "gitlab-qa-#{edition}-#{SecureRandom.hex(4)}"
26
40
  end
27
41
 
28
42
  def address
@@ -30,7 +44,7 @@ module Gitlab
30
44
  end
31
45
 
32
46
  def hostname
33
- "#{@name}.#{@network}"
47
+ "#{name}.#{network}"
34
48
  end
35
49
 
36
50
  def instance
@@ -44,29 +58,40 @@ module Gitlab
44
58
  end
45
59
 
46
60
  def prepare
47
- @docker.pull(@image, @tag)
61
+ @docker.pull(image, tag)
48
62
 
49
- return if @docker.network_exists?(@network)
50
- @docker.network_create(@network)
63
+ return if @docker.network_exists?(network)
64
+ @docker.network_create(network)
51
65
  end
52
66
 
67
+ # rubocop:disable Metrics/MethodLength
68
+ # rubocop:disable Metrics/AbcSize
53
69
  def start
54
- unless [@name, @image, @tag, @network].all?
55
- raise 'Please configure an instance first!'
56
- end
70
+ ensure_configured!
57
71
 
58
- @docker.run(@image, @tag) do |command|
59
- command << "-d --name #{@name} -p 80:80"
60
- command << "--net #{@network} --hostname #{hostname}"
72
+ docker.run(image, tag) do |command|
73
+ command << '-d -p 80:80'
74
+ command << "--name #{name}"
75
+ command << "--net #{network}"
76
+ command << "--hostname #{hostname}"
61
77
 
62
78
  @volumes.to_h.each do |to, from|
63
79
  command << "--volume #{to}:#{from}:Z"
64
80
  end
81
+
82
+ @environment.to_h.each do |key, value|
83
+ escaped_value = Shellwords.escape(value)
84
+ command << "--env #{key}=#{escaped_value}"
85
+ end
86
+
87
+ @network_aliases.to_a.each do |network_alias|
88
+ command << "--network-alias #{network_alias}"
89
+ end
65
90
  end
66
91
  end
67
92
 
68
93
  def reconfigure
69
- @docker.attach(@name) do |line, wait|
94
+ @docker.attach(name) do |line, wait|
70
95
  # TODO, workaround which allows to detach from the container
71
96
  #
72
97
  Process.kill('INT', wait.pid) if line =~ /gitlab Reconfigured!/
@@ -74,14 +99,14 @@ module Gitlab
74
99
  end
75
100
 
76
101
  def restart
77
- @docker.restart(@name)
102
+ @docker.restart(name)
78
103
  end
79
104
 
80
105
  def teardown
81
- raise 'Invalid instance name!' unless @name
106
+ raise 'Invalid instance name!' unless name
82
107
 
83
- @docker.stop(@name)
84
- @docker.remove(@name)
108
+ @docker.stop(name)
109
+ @docker.remove(name)
85
110
  end
86
111
 
87
112
  def wait
@@ -96,6 +121,15 @@ module Gitlab
96
121
  end
97
122
  end
98
123
 
124
+ private
125
+
126
+ # rubocop:disable Style/GuardClause
127
+ def ensure_configured!
128
+ unless [name, release, network].all?
129
+ raise 'Please configure an instance first!'
130
+ end
131
+ end
132
+
99
133
  class Availability
100
134
  def initialize(address)
101
135
  @uri = URI.join(address, '/help')
@@ -0,0 +1,59 @@
1
+ module Gitlab
2
+ module QA
3
+ module Component
4
+ ##
5
+ # This class represents GitLab QA specs image that is implemented in
6
+ # the `qa/` directory located in GitLab CE / EE repositories.
7
+ #
8
+ # TODO, it needs some refactoring.
9
+ #
10
+ class Specs
11
+ include Scenario::Actable
12
+
13
+ IMAGE_NAME = 'gitlab/gitlab-qa'.freeze
14
+
15
+ def initialize
16
+ @docker = Docker::Engine.new
17
+ end
18
+
19
+ def test(gitlab:, suite: 'Test::Instance', extra_args: [])
20
+ test_address(
21
+ release: gitlab.release,
22
+ address: gitlab.address,
23
+ name: "#{gitlab.name}-specs",
24
+ network: gitlab.network,
25
+ suite: suite,
26
+ extra_args: extra_args
27
+ )
28
+ end
29
+
30
+ # rubocop:disable Metrics/ParameterLists
31
+ def test_address(release:, address:, name: nil, network: nil,
32
+ suite: 'Test::Instance', extra_args: [])
33
+ puts "Running instance suite #{suite} for Gitlab " \
34
+ "#{release.edition.upcase} at #{address}"
35
+
36
+ args = [suite, address] + extra_args
37
+
38
+ @docker.run(IMAGE_NAME, release.edition_tag, *args) do |command|
39
+ build_command(command, name, network)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def build_command(command, name, network)
46
+ command << "-t --rm --net=#{network || 'bridge'}"
47
+
48
+ Runtime::Env.delegated.each do |env|
49
+ command.env(env, "$#{env}")
50
+ end
51
+
52
+ command.volume('/var/run/docker.sock', '/var/run/docker.sock')
53
+ command.volume(Runtime::Env.screenshots_dir, '/home/qa/tmp')
54
+ command.name(name || "gitlab-specs-#{Time.now.to_i}")
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,17 +1,9 @@
1
- require 'open3'
2
-
3
1
  module Gitlab
4
2
  module QA
5
3
  module Docker
6
4
  class Command
7
- class StatusError < StandardError; end
8
-
9
5
  attr_reader :args
10
6
 
11
- def self.execute(cmd, &block)
12
- new(cmd).execute!(&block)
13
- end
14
-
15
7
  def initialize(cmd = nil)
16
8
  @args = Array(cmd)
17
9
  end
@@ -20,25 +12,28 @@ module Gitlab
20
12
  tap { @args.concat(args) }
21
13
  end
22
14
 
23
- def execute!(&block)
24
- engine("docker #{@args.join(' ')}", &block)
15
+ def volume(from, to)
16
+ tap { @args << "-v #{from}:#{to}" }
25
17
  end
26
18
 
27
- private
19
+ def name(identity)
20
+ tap { @args << "--name #{identity}" }
21
+ end
28
22
 
29
- def engine(cmd)
30
- puts "Running shell command: `#{cmd}`"
23
+ def env(name, value)
24
+ tap { @args << %(-e #{name}="#{value}") }
25
+ end
31
26
 
32
- Open3.popen2e(cmd) do |_in, out, wait|
33
- out.each do |line|
34
- puts line
35
- yield line, wait if block_given?
36
- end
27
+ def to_s
28
+ "docker #{@args.join(' ')}"
29
+ end
37
30
 
38
- if wait.value.exited? && wait.value.exitstatus.nonzero?
39
- raise StatusError, "Docker command `#{cmd}` failed!"
40
- end
41
- end
31
+ def execute!(&block)
32
+ Docker::Shellout.execute!(self, &block)
33
+ end
34
+
35
+ def self.execute(cmd, &block)
36
+ new(cmd).execute!(&block)
42
37
  end
43
38
  end
44
39
  end
@@ -41,7 +41,7 @@ module Gitlab
41
41
 
42
42
  def network_exists?(name)
43
43
  Docker::Command.execute("network inspect #{name}")
44
- rescue Docker::Command::StatusError
44
+ rescue Docker::Shellout::StatusError
45
45
  false
46
46
  else
47
47
  true
@@ -0,0 +1,27 @@
1
+ require 'open3'
2
+
3
+ module Gitlab
4
+ module QA
5
+ module Docker
6
+ class Shellout
7
+ class StatusError < StandardError; end
8
+
9
+ def self.execute!(command)
10
+ puts "Running shell command: `#{command}`"
11
+
12
+ Open3.popen2e(command.to_s) do |_in, out, wait|
13
+ out.each do |line|
14
+ puts line
15
+
16
+ yield line, wait if block_given?
17
+ end
18
+
19
+ if wait.value.exited? && wait.value.exitstatus.nonzero?
20
+ raise StatusError, "Docker command `#{command}` failed!"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -5,33 +5,55 @@ module Gitlab
5
5
  DEFAULT_TAG = 'nightly'.freeze
6
6
 
7
7
  attr_reader :release
8
+ attr_writer :tag
8
9
 
9
10
  def initialize(release)
10
11
  @release = release.to_s
11
12
  end
12
13
 
14
+ def to_s
15
+ "#{image}:#{tag}"
16
+ end
17
+
18
+ def previous_stable
19
+ # The previous stable is always gitlab/gitlab-ce:latest or
20
+ # gitlab/gitlab-ee:latest
21
+ self.class.new("#{canonical_image}:latest")
22
+ end
23
+
13
24
  def edition
14
- if canonical?
15
- release.downcase.to_sym
16
- else
17
- release.match(CUSTOM_GITLAB_IMAGE_REGEX)[1].to_sym
18
- end
25
+ @edition ||=
26
+ if canonical?
27
+ release.downcase.to_sym
28
+ else
29
+ release.match(CUSTOM_GITLAB_IMAGE_REGEX)[1].to_sym
30
+ end
19
31
  end
20
32
 
21
33
  def image
22
- if canonical?
23
- "gitlab/gitlab-#{edition}"
24
- else
25
- release.sub(/:.+\z/, '')
26
- end
34
+ @image ||=
35
+ if canonical?
36
+ "gitlab/gitlab-#{edition}"
37
+ else
38
+ release.sub(/:.+\z/, '')
39
+ end
40
+ end
41
+
42
+ def canonical_image
43
+ @canonical_image ||= "gitlab/gitlab-#{edition}"
27
44
  end
28
45
 
29
46
  def tag
30
- if canonical?
31
- DEFAULT_TAG
32
- else
33
- release.match(CUSTOM_GITLAB_IMAGE_REGEX)[2]
34
- end
47
+ @tag ||=
48
+ if canonical?
49
+ DEFAULT_TAG
50
+ else
51
+ release.match(CUSTOM_GITLAB_IMAGE_REGEX)[2]
52
+ end
53
+ end
54
+
55
+ def edition_tag
56
+ @edition_tag ||= "#{edition}-#{tag}"
35
57
  end
36
58
 
37
59
  private
@@ -4,12 +4,17 @@ module Gitlab
4
4
  module Env
5
5
  extend self
6
6
 
7
+ VARIABLES = %w(GITLAB_USERNAME
8
+ GITLAB_PASSWORD
9
+ GITLAB_URL
10
+ EE_LICENSE).freeze
11
+
7
12
  def screenshots_dir
8
13
  ENV['QA_SCREENSHOTS_DIR'] || '/tmp/gitlab-qa-screenshots'
9
14
  end
10
15
 
11
16
  def delegated
12
- %w(GITLAB_USERNAME GITLAB_PASSWORD GITLAB_URL EE_LICENSE).freeze
17
+ VARIABLES.select { |name| ENV[name] }
13
18
  end
14
19
  end
15
20
  end