4389: Merge branch 'master' into 4389-breadcrumbs-infinite-loop
[arvados.git] / apps / workbench / test / test_helper.rb
1 ENV["RAILS_ENV"] = "test" if (ENV["RAILS_ENV"] != "diagnostics")
2
3 unless ENV["NO_COVERAGE_TEST"]
4   begin
5     require 'simplecov'
6     require 'simplecov-rcov'
7     class SimpleCov::Formatter::MergedFormatter
8       def format(result)
9         SimpleCov::Formatter::HTMLFormatter.new.format(result)
10         SimpleCov::Formatter::RcovFormatter.new.format(result)
11       end
12     end
13     SimpleCov.formatter = SimpleCov::Formatter::MergedFormatter
14     SimpleCov.start do
15       add_filter '/test/'
16       add_filter 'initializers/secret_token'
17     end
18   rescue Exception => e
19     $stderr.puts "SimpleCov unavailable (#{e}). Proceeding without."
20   end
21 end
22
23 require File.expand_path('../../config/environment', __FILE__)
24 require 'rails/test_help'
25 require 'mocha/mini_test'
26
27 class ActiveSupport::TestCase
28   # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in
29   # alphabetical order.
30   #
31   # Note: You'll currently still have to declare fixtures explicitly
32   # in integration tests -- they do not yet inherit this setting
33   fixtures :all
34   def use_token token_name
35     auth = api_fixture('api_client_authorizations')[token_name.to_s]
36     Thread.current[:arvados_api_token] = auth['api_token']
37   end
38
39   teardown do
40     Thread.current[:arvados_api_token] = nil
41     Thread.current[:user] = nil
42     Thread.current[:reader_tokens] = nil
43     # Diagnostics suite doesn't run a server, so there's no cache to clear.
44     Rails.cache.clear unless (Rails.env == "diagnostics")
45     # Restore configuration settings changed during tests
46     $application_config.each do |k,v|
47       if k.match /^[^.]*$/
48         Rails.configuration.send (k + '='), v
49       end
50     end
51   end
52 end
53
54 module ApiFixtureLoader
55   def self.included(base)
56     base.extend(ClassMethods)
57   end
58
59   module ClassMethods
60     @@api_fixtures = {}
61     def api_fixture(name, *keys)
62       # Returns the data structure from the named API server test fixture.
63       @@api_fixtures[name] ||= \
64       begin
65         path = File.join(ApiServerForTests::ARV_API_SERVER_DIR,
66                          'test', 'fixtures', "#{name}.yml")
67         file = IO.read(path)
68         trim_index = file.index('# Test Helper trims the rest of the file')
69         file = file[0, trim_index] if trim_index
70         YAML.load(file)
71       end
72       keys.inject(@@api_fixtures[name]) { |hash, key| hash[key] }
73     end
74   end
75   def api_fixture(name, *keys)
76     self.class.api_fixture(name, *keys)
77   end
78
79   def find_fixture(object_class, name)
80     object_class.find(api_fixture(object_class.to_s.pluralize.underscore,
81                                   name, "uuid"))
82   end
83 end
84
85 class ActiveSupport::TestCase
86   include ApiFixtureLoader
87   def session_for api_client_auth_name
88     {
89       arvados_api_token: api_fixture('api_client_authorizations')[api_client_auth_name.to_s]['api_token']
90     }
91   end
92   def json_response
93     Oj.load(@response.body)
94   end
95 end
96
97 class ApiServerForTests
98   ARV_API_SERVER_DIR = File.expand_path('../../../../services/api', __FILE__)
99   SERVER_PID_PATH = File.expand_path('tmp/pids/wbtest-server.pid', ARV_API_SERVER_DIR)
100   @main_process_pid = $$
101
102   def self._system(*cmd)
103     $stderr.puts "_system #{cmd.inspect}"
104     Bundler.with_clean_env do
105       if not system({'RAILS_ENV' => 'test'}, *cmd)
106         raise RuntimeError, "#{cmd[0]} returned exit code #{$?.exitstatus}"
107       end
108     end
109   end
110
111   def self.make_ssl_cert
112     unless File.exists? './self-signed.key'
113       _system('openssl', 'req', '-new', '-x509', '-nodes',
114               '-out', './self-signed.pem',
115               '-keyout', './self-signed.key',
116               '-days', '3650',
117               '-subj', '/CN=localhost')
118     end
119   end
120
121   def self.kill_server
122     if (pid = find_server_pid)
123       $stderr.puts "Sending TERM to API server, pid #{pid}"
124       Process.kill 'TERM', pid
125     end
126   end
127
128   def self.find_server_pid
129     pid = nil
130     begin
131       pid = IO.read(SERVER_PID_PATH).to_i
132       $stderr.puts "API server is running, pid #{pid.inspect}"
133     rescue Errno::ENOENT
134     end
135     return pid
136   end
137
138   def self.run(args=[])
139     ::MiniTest.after_run do
140       self.kill_server
141     end
142
143     # Kill server left over from previous test run
144     self.kill_server
145
146     Capybara.javascript_driver = :poltergeist
147     Dir.chdir(ARV_API_SERVER_DIR) do |apidir|
148       ENV["NO_COVERAGE_TEST"] = "1"
149       make_ssl_cert
150       _system('bundle', 'exec', 'rake', 'db:test:load')
151       _system('bundle', 'exec', 'rake', 'db:fixtures:load')
152       _system('bundle', 'exec', 'passenger', 'start', '-d', '-p3000',
153               '--pid-file', SERVER_PID_PATH,
154               '--ssl',
155               '--ssl-certificate', 'self-signed.pem',
156               '--ssl-certificate-key', 'self-signed.key')
157       timeout = Time.now.tv_sec + 10
158       good_pid = false
159       while (not good_pid) and (Time.now.tv_sec < timeout)
160         sleep 0.2
161         server_pid = find_server_pid
162         good_pid = (server_pid and
163                     (server_pid > 0) and
164                     (Process.kill(0, server_pid) rescue false))
165       end
166       if not good_pid
167         raise RuntimeError, "could not find API server Rails pid"
168       end
169     end
170   end
171 end
172
173 class ActionController::TestCase
174   setup do
175     @counter = 0
176   end
177
178   def check_counter action
179     @counter += 1
180     if @counter == 2
181       assert_equal 1, 2, "Multiple actions in functional test"
182     end
183   end
184
185   [:get, :post, :put, :patch, :delete].each do |method|
186     define_method method do |action, *args|
187       check_counter action
188       super action, *args
189     end
190   end
191 end
192
193 # If it quacks like a duck, it must be a HTTP request object.
194 class RequestDuck
195   def self.host
196     "localhost"
197   end
198
199   def self.port
200     8080
201   end
202
203   def self.protocol
204     "http"
205   end
206 end
207
208 if ENV["RAILS_ENV"].eql? 'test'
209   ApiServerForTests.run
210 end