Welcome to mirror list, hosted at ThFree Co, Russian Federation.

unicorn_http_server_spec.rb « mixins « cluster « gitlab « lib « spec - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 7f7c95b252710d90febeabf2573da55a5c519f21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# frozen_string_literal: true

require 'spec_helper'

# For easier debugging set `UNICORN_DEBUG=1`

RSpec.describe Gitlab::Cluster::Mixins::UnicornHttpServer do
  before do
    stub_const('UNICORN_STARTUP_TIMEOUT', 30)
  end

  context 'when running Unicorn' do
    using RSpec::Parameterized::TableSyntax

    where(:signal, :exitstatus, :termsig) do
      # executes phased restart block
      :USR2 | 140 | nil
      :QUIT | 140 | nil

      # does not execute phased restart block
      :INT | 0 | nil
      :TERM | 0 | nil
    end

    with_them do
      it 'properly handles process lifecycle' do
        with_unicorn(workers: 1) do |pid|
          Process.kill(signal, pid)

          child_pid, child_status = Process.wait2(pid)
          expect(child_pid).to eq(pid)
          expect(child_status.exitstatus).to eq(exitstatus)
          expect(child_status.termsig).to eq(termsig)
        end
      end
    end
  end

  private

  def with_unicorn(workers:, timeout: UNICORN_STARTUP_TIMEOUT)
    with_unicorn_configs(workers: workers) do |unicorn_rb, config_ru|
      cmdline = [
        "bundle", "exec", "unicorn",
        "-I", Rails.root.to_s,
        "-c", unicorn_rb,
        config_ru
      ]

      IO.popen(cmdline) do |process|
        # wait for process to start:
        # I, [2019-10-15T13:21:27.565225 #3089]  INFO -- : master process ready
        wait_for_output(process, /master process ready/, timeout: timeout)
        consume_output(process)

        yield(process.pid)
      ensure
        begin
          Process.kill(:KILL, process.pid)
        rescue Errno::ESRCH
        end
      end
    end
  end

  def with_unicorn_configs(workers:)
    Dir.mktmpdir do |dir|
      File.write "#{dir}/unicorn.rb", <<-EOF
        require './lib/gitlab/cluster/lifecycle_events'
        require './lib/gitlab/cluster/mixins/unicorn_http_server'

        worker_processes #{workers}
        listen "127.0.0.1:0"
        preload_app true

        Unicorn::HttpServer.prepend(#{described_class})

        mutex = Mutex.new

        Gitlab::Cluster::LifecycleEvents.on_before_blackout_period do
          mutex.synchronize do
            exit(140)
          end
        end

        # redirect stderr to stdout
        $stderr.reopen($stdout)
      EOF

      File.write "#{dir}/config.ru", <<-EOF
        run -> (env) { [404, {}, ['']] }
      EOF

      yield("#{dir}/unicorn.rb", "#{dir}/config.ru")
    end
  end

  def wait_for_output(process, output, timeout:)
    Timeout.timeout(timeout) do
      loop do
        line = process.readline
        puts "UNICORN_DEBUG: #{line}" if ENV['UNICORN_DEBUG']
        break if line =~ output
      end
    end
  end

  def consume_output(process)
    Thread.new do
      loop do
        line = process.readline
        puts "UNICORN_DEBUG: #{line}" if ENV['UNICORN_DEBUG']
      end
    rescue StandardError
    end
  end
end