From: Tom Clegg Date: Thu, 15 May 2014 18:19:06 +0000 (-0400) Subject: 2809: Merge branch 'master' into 2809-workbench-rails4 refs #2809 X-Git-Tag: 1.1.0~2607^2~13^2 X-Git-Url: https://git.arvados.org/arvados.git/commitdiff_plain/03395937ba05b9e3192e346a355c691f45cc7c85?hp=ce5b843c32f6ee74f02a40044073dd4288d16dee 2809: Merge branch 'master' into 2809-workbench-rails4 refs #2809 Conflicts: apps/workbench/app/models/arvados_api_client.rb --- diff --git a/apps/workbench/Gemfile b/apps/workbench/Gemfile index bcbe3ef36f..754d5c6043 100644 --- a/apps/workbench/Gemfile +++ b/apps/workbench/Gemfile @@ -1,6 +1,7 @@ source 'https://rubygems.org' -gem 'rails', '~> 3.2.0' +gem 'rails', '~> 4.1.0' +gem 'minitest', '>= 5.0.0' # Bundle edge Rails instead: # gem 'rails', :git => 'git://github.com/rails/rails.git' @@ -11,11 +12,17 @@ gem 'multi_json' gem 'oj' gem 'sass' +# Note: keeping this out of the "group :assets" section "may" allow us +# to use Coffescript for UJS responses. It also prevents a +# warning/problem when running tests: "WARN: tilt autoloading +# 'coffee_script' in a non thread-safe way; explicit require +# 'coffee_script' suggested." +gem 'coffee-rails' + # Gems used only for assets and not required # in production environments by default. group :assets do - gem 'sass-rails', '~> 3.2.0' - gem 'coffee-rails', '~> 3.2.0' + gem 'sass-rails' # See https://github.com/sstephenson/execjs#readme for more supported runtimes gem 'therubyracer', :platforms => :ruby @@ -64,5 +71,8 @@ gem 'RedCloth' gem 'piwik_analytics' gem 'httpclient' -gem 'themes_for_rails' + +# This fork has Rails 4 compatible routes +gem 'themes_for_rails', git: 'https://github.com/holtkampw/themes_for_rails', ref: '1fd2d7897d75ae0d6375f4c390df87b8e91ad417' + gem "deep_merge", :require => 'deep_merge/rails_compat' diff --git a/apps/workbench/Gemfile.lock b/apps/workbench/Gemfile.lock index 8e748326a1..173be13cc3 100644 --- a/apps/workbench/Gemfile.lock +++ b/apps/workbench/Gemfile.lock @@ -1,41 +1,48 @@ +GIT + remote: https://github.com/holtkampw/themes_for_rails + revision: 1fd2d7897d75ae0d6375f4c390df87b8e91ad417 + ref: 1fd2d7897d75ae0d6375f4c390df87b8e91ad417 + specs: + themes_for_rails (0.5.1) + rails (>= 3.0.0) + GEM remote: https://rubygems.org/ specs: RedCloth (4.2.9) - actionmailer (3.2.15) - actionpack (= 3.2.15) + actionmailer (4.1.1) + actionpack (= 4.1.1) + actionview (= 4.1.1) mail (~> 2.5.4) - actionpack (3.2.15) - activemodel (= 3.2.15) - activesupport (= 3.2.15) - builder (~> 3.0.0) + actionpack (4.1.1) + actionview (= 4.1.1) + activesupport (= 4.1.1) + rack (~> 1.5.2) + rack-test (~> 0.6.2) + actionview (4.1.1) + activesupport (= 4.1.1) + builder (~> 3.1) erubis (~> 2.7.0) - journey (~> 1.0.4) - rack (~> 1.4.5) - rack-cache (~> 1.2) - rack-test (~> 0.6.1) - sprockets (~> 2.2.1) - activemodel (3.2.15) - activesupport (= 3.2.15) - builder (~> 3.0.0) - activerecord (3.2.15) - activemodel (= 3.2.15) - activesupport (= 3.2.15) - arel (~> 3.0.2) - tzinfo (~> 0.3.29) - activeresource (3.2.15) - activemodel (= 3.2.15) - activesupport (= 3.2.15) - activesupport (3.2.15) - i18n (~> 0.6, >= 0.6.4) - multi_json (~> 1.0) + activemodel (4.1.1) + activesupport (= 4.1.1) + builder (~> 3.1) + activerecord (4.1.1) + activemodel (= 4.1.1) + activesupport (= 4.1.1) + arel (~> 5.0.0) + activesupport (4.1.1) + i18n (~> 0.6, >= 0.6.9) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.1) + tzinfo (~> 1.1) andand (1.3.3) - arel (3.0.2) + arel (5.0.1.20140414130214) bootstrap-sass (3.1.0.1) sass (~> 3.2) bootstrap-x-editable-rails (1.5.1.1) railties (>= 3.0) - builder (3.0.4) + builder (3.2.2) capistrano (2.15.5) highline net-scp (>= 1.0.0) @@ -51,13 +58,13 @@ GEM childprocess (0.5.1) ffi (~> 1.0, >= 1.0.11) cliver (0.3.2) - coffee-rails (3.2.2) + coffee-rails (4.0.1) coffee-script (>= 2.2.0) - railties (~> 3.2.0) + railties (>= 4.0.0, < 5.0) coffee-script (2.2.0) coffee-script-source execjs - coffee-script-source (1.6.3) + coffee-script-source (1.7.0) commonjs (0.2.7) daemon_controller (1.1.7) deep_merge (1.0.1) @@ -68,8 +75,7 @@ GEM highline (1.6.20) hike (1.2.3) httpclient (2.3.4.1) - i18n (0.6.5) - journey (1.0.4) + i18n (0.6.9) jquery-rails (3.0.4) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) @@ -83,9 +89,10 @@ GEM mail (2.5.4) mime-types (~> 1.16) treetop (~> 1.4.8) - mime-types (1.25) + mime-types (1.25.1) mini_portile (0.5.2) - multi_json (1.8.2) + minitest (5.3.3) + multi_json (1.10.0) net-scp (1.1.2) net-ssh (>= 2.6.5) net-sftp (2.1.2) @@ -109,41 +116,36 @@ GEM cliver (~> 0.3.1) multi_json (~> 1.0) websocket-driver (>= 0.2.0) - polyglot (0.3.3) - rack (1.4.5) - rack-cache (1.2) - rack (>= 0.4) - rack-ssl (1.3.3) - rack + polyglot (0.3.4) + rack (1.5.2) rack-test (0.6.2) rack (>= 1.0) - rails (3.2.15) - actionmailer (= 3.2.15) - actionpack (= 3.2.15) - activerecord (= 3.2.15) - activeresource (= 3.2.15) - activesupport (= 3.2.15) - bundler (~> 1.0) - railties (= 3.2.15) - railties (3.2.15) - actionpack (= 3.2.15) - activesupport (= 3.2.15) - rack-ssl (~> 1.3.2) + rails (4.1.1) + actionmailer (= 4.1.1) + actionpack (= 4.1.1) + actionview (= 4.1.1) + activemodel (= 4.1.1) + activerecord (= 4.1.1) + activesupport (= 4.1.1) + bundler (>= 1.3.0, < 2.0) + railties (= 4.1.1) + sprockets-rails (~> 2.0) + railties (4.1.1) + actionpack (= 4.1.1) + activesupport (= 4.1.1) rake (>= 0.8.7) - rdoc (~> 3.4) - thor (>= 0.14.6, < 2.0) - rake (10.1.0) - rdoc (3.12.2) - json (~> 1.4) + thor (>= 0.18.1, < 2.0) + rake (10.3.1) ref (1.0.5) rubyzip (1.1.0) rvm-capistrano (1.5.1) capistrano (~> 2.15.4) sass (3.2.12) - sass-rails (3.2.6) - railties (~> 3.2.0) - sass (>= 3.1.10) - tilt (~> 1.3) + sass-rails (4.0.3) + railties (>= 4.0.0, < 5.0) + sass (~> 3.2.0) + sprockets (~> 2.8, <= 2.11.0) + sprockets-rails (~> 2.0) selenium-webdriver (2.40.0) childprocess (>= 0.5.0) multi_json (~> 1.0) @@ -155,23 +157,27 @@ GEM simplecov-html (0.7.1) simplecov-rcov (0.2.3) simplecov (>= 0.4.1) - sprockets (2.2.2) + sprockets (2.11.0) hike (~> 1.2) multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) + sprockets-rails (2.1.3) + actionpack (>= 3.0) + activesupport (>= 3.0) + sprockets (~> 2.8) sqlite3 (1.3.8) - themes_for_rails (0.5.1) - rails (>= 3.0.0) therubyracer (0.12.0) libv8 (~> 3.16.14.0) ref - thor (0.18.1) + thor (0.19.1) + thread_safe (0.3.3) tilt (1.4.1) treetop (1.4.15) polyglot polyglot (>= 0.3.1) - tzinfo (0.3.38) + tzinfo (1.1.0) + thread_safe (~> 0.1) uglifier (2.3.1) execjs (>= 0.3.0) json (>= 1.8.0) @@ -189,26 +195,27 @@ DEPENDENCIES bootstrap-sass (~> 3.1.0) bootstrap-x-editable-rails capybara - coffee-rails (~> 3.2.0) + coffee-rails deep_merge headless httpclient jquery-rails less less-rails + minitest (>= 5.0.0) multi_json oj passenger piwik_analytics poltergeist - rails (~> 3.2.0) + rails (~> 4.1.0) rvm-capistrano sass - sass-rails (~> 3.2.0) + sass-rails selenium-webdriver simplecov (~> 0.7.1) simplecov-rcov sqlite3 - themes_for_rails + themes_for_rails! therubyracer uglifier (>= 1.0.3) diff --git a/apps/workbench/app/assets/javascripts/api_client_authorizations.js.coffee b/apps/workbench/app/assets/javascripts/api_client_authorizations.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/api_client_authorizations.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/authorized_keys.js.coffee b/apps/workbench/app/assets/javascripts/authorized_keys.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/authorized_keys.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/folders.js.coffee b/apps/workbench/app/assets/javascripts/folders.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/folders.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/groups.js.coffee b/apps/workbench/app/assets/javascripts/groups.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/groups.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/humans.js.coffee b/apps/workbench/app/assets/javascripts/humans.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/humans.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/job_tasks.js.coffee b/apps/workbench/app/assets/javascripts/job_tasks.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/job_tasks.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/jobs.js.coffee b/apps/workbench/app/assets/javascripts/jobs.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/jobs.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/keep_disks.js.coffee b/apps/workbench/app/assets/javascripts/keep_disks.js.coffee index cc3aac784c..e4aa4b4321 100644 --- a/apps/workbench/app/assets/javascripts/keep_disks.js.coffee +++ b/apps/workbench/app/assets/javascripts/keep_disks.js.coffee @@ -1,7 +1,3 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ - cache_age_in_days = (milliseconds_age) -> ONE_DAY = 1000 * 60 * 60 * 24 milliseconds_age / ONE_DAY diff --git a/apps/workbench/app/assets/javascripts/links.js.coffee b/apps/workbench/app/assets/javascripts/links.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/links.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/logs.js.coffee b/apps/workbench/app/assets/javascripts/logs.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/logs.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/nodes.js.coffee b/apps/workbench/app/assets/javascripts/nodes.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/nodes.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/pipeline_instances.js b/apps/workbench/app/assets/javascripts/pipeline_instances.js index ee14e3b781..a9ca4df2a5 100644 --- a/apps/workbench/app/assets/javascripts/pipeline_instances.js +++ b/apps/workbench/app/assets/javascripts/pipeline_instances.js @@ -1,4 +1,3 @@ - (function() { var run_pipeline_button_state = function() { var a = $('a.editable.required.editable-empty'); diff --git a/apps/workbench/app/assets/javascripts/pipeline_templates.js.coffee b/apps/workbench/app/assets/javascripts/pipeline_templates.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/pipeline_templates.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/repositories.js.coffee b/apps/workbench/app/assets/javascripts/repositories.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/repositories.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/sessions.js.coffee b/apps/workbench/app/assets/javascripts/sessions.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/sessions.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/specimens.js.coffee b/apps/workbench/app/assets/javascripts/specimens.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/specimens.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/traits.js.coffee b/apps/workbench/app/assets/javascripts/traits.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/traits.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/user_agreements.js.coffee b/apps/workbench/app/assets/javascripts/user_agreements.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/user_agreements.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/users.js.coffee b/apps/workbench/app/assets/javascripts/users.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/users.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/assets/javascripts/virtual_machines.js.coffee b/apps/workbench/app/assets/javascripts/virtual_machines.js.coffee deleted file mode 100644 index 761567942f..0000000000 --- a/apps/workbench/app/assets/javascripts/virtual_machines.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/apps/workbench/app/controllers/actions_controller.rb b/apps/workbench/app/controllers/actions_controller.rb index 2dab6dd6a8..368d9a8e8c 100644 --- a/apps/workbench/app/controllers/actions_controller.rb +++ b/apps/workbench/app/controllers/actions_controller.rb @@ -86,7 +86,7 @@ class ActionsController < ApplicationController env = Hash[ENV]. merge({ 'ARVADOS_API_HOST' => - $arvados_api_client.arvados_v1_base. + arvados_api_client.arvados_v1_base. sub(/\/arvados\/v1/, ''). sub(/^https?:\/\//, ''), 'ARVADOS_API_TOKEN' => Thread.current[:arvados_api_token], diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb index 2fbd8c560f..b62838f655 100644 --- a/apps/workbench/app/controllers/application_controller.rb +++ b/apps/workbench/app/controllers/application_controller.rb @@ -1,4 +1,6 @@ class ApplicationController < ActionController::Base + include ArvadosApiClientHelper + respond_to :html, :json, :js protect_from_forgery @@ -198,7 +200,7 @@ class ApplicationController < ActionController::Base respond_to do |f| f.html { if request.method == 'GET' - redirect_to $arvados_api_client.arvados_login_url(return_to: request.url) + redirect_to arvados_api_client.arvados_login_url(return_to: request.url) else flash[:error] = "Either you are not logged in, or your session has timed out. I can't automatically log you in and re-attempt this request." redirect_to :back diff --git a/apps/workbench/app/controllers/collections_controller.rb b/apps/workbench/app/controllers/collections_controller.rb index 4178e38361..7ef85a5cfc 100644 --- a/apps/workbench/app/controllers/collections_controller.rb +++ b/apps/workbench/app/controllers/collections_controller.rb @@ -233,7 +233,7 @@ class CollectionsController < ApplicationController env = Hash[ENV]. merge({ 'ARVADOS_API_HOST' => - $arvados_api_client.arvados_v1_base. + arvados_api_client.arvados_v1_base. sub(/\/arvados\/v1/, ''). sub(/^https?:\/\//, ''), 'ARVADOS_API_TOKEN' => diff --git a/apps/workbench/app/controllers/sessions_controller.rb b/apps/workbench/app/controllers/sessions_controller.rb index 488c67c3c2..585f322a85 100644 --- a/apps/workbench/app/controllers/sessions_controller.rb +++ b/apps/workbench/app/controllers/sessions_controller.rb @@ -4,7 +4,7 @@ class SessionsController < ApplicationController skip_before_filter :find_object_by_uuid, :only => [:destroy, :index] def destroy session.clear - redirect_to $arvados_api_client.arvados_logout_url(return_to: root_url) + redirect_to arvados_api_client.arvados_logout_url(return_to: root_url) end def index redirect_to root_url if session[:arvados_api_token] diff --git a/apps/workbench/app/controllers/users_controller.rb b/apps/workbench/app/controllers/users_controller.rb index 863876137f..3d8c8530ad 100644 --- a/apps/workbench/app/controllers/users_controller.rb +++ b/apps/workbench/app/controllers/users_controller.rb @@ -107,11 +107,11 @@ class UsersController < ApplicationController end def sudo - resp = $arvados_api_client.api(ApiClientAuthorization, '', { - api_client_authorization: { - owner_uuid: @object.uuid - } - }) + resp = arvados_api_client.api(ApiClientAuthorization, '', { + api_client_authorization: { + owner_uuid: @object.uuid + } + }) redirect_to root_url(api_token: resp[:api_token]) end diff --git a/apps/workbench/app/helpers/arvados_api_client_helper.rb b/apps/workbench/app/helpers/arvados_api_client_helper.rb new file mode 100644 index 0000000000..b6c29a9070 --- /dev/null +++ b/apps/workbench/app/helpers/arvados_api_client_helper.rb @@ -0,0 +1,13 @@ +module ArvadosApiClientHelper + def arvados_api_client + ArvadosApiClient.new_or_current + end +end + +# For the benefit of themes that still expect $arvados_api_client to work: +class ArvadosClientProxyHack + def method_missing *args + ArvadosApiClient.new_or_current.send *args + end +end +$arvados_api_client = ArvadosClientProxyHack.new diff --git a/apps/workbench/app/models/arvados_api_client.rb b/apps/workbench/app/models/arvados_api_client.rb index c6d8720c92..25e776a942 100644 --- a/apps/workbench/app/models/arvados_api_client.rb +++ b/apps/workbench/app/models/arvados_api_client.rb @@ -7,21 +7,31 @@ class ArvadosApiClient class InvalidApiResponseException < StandardError end - @@client_mtx = Mutex.new - @@api_client = nil @@profiling_enabled = Rails.configuration.profiling_enabled + @@discovery = nil + + # An API client object suitable for handling API requests on behalf + # of the current thread. + def self.new_or_current + Thread.current[:arvados_api_client] ||= new + end + + def initialize *args + @api_client = nil + @client_mtx = Mutex.new + end def api(resources_kind, action, data=nil) profile_checkpoint - @@client_mtx.synchronize do - if not @@api_client - @@api_client = HTTPClient.new + if not @api_client + @client_mtx.synchronize do + @api_client = HTTPClient.new if Rails.configuration.arvados_insecure_https - @@api_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE + @api_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE else # Use system CA certificates - @@api_client.ssl_config.add_trust_ca('/etc/ssl/certs') + @api_client.ssl_config.add_trust_ca('/etc/ssl/certs') end end end @@ -58,9 +68,11 @@ class ArvadosApiClient header = {"Accept" => "application/json"} profile_checkpoint { "Prepare request #{url} #{query[:uuid]} #{query[:where]} #{query[:filters]}" } - msg = @@api_client.post(url, - query, - header: header) + msg = @client_mtx.synchronize do + @api_client.post(url, + query, + header: header) + end profile_checkpoint 'API transaction' if msg.status_code == 401 @@ -158,7 +170,7 @@ class ArvadosApiClient end def discovery - @discovery ||= api '../../discovery/v1/apis/arvados/v1/rest', '' + @@discovery ||= api '../../discovery/v1/apis/arvados/v1/rest', '' end def kind_class(kind) diff --git a/apps/workbench/app/models/arvados_base.rb b/apps/workbench/app/models/arvados_base.rb index 1a0da6424a..1ad0230512 100644 --- a/apps/workbench/app/models/arvados_base.rb +++ b/apps/workbench/app/models/arvados_base.rb @@ -2,11 +2,19 @@ class ArvadosBase < ActiveRecord::Base self.abstract_class = true attr_accessor :attribute_sortkey + def self.arvados_api_client + ArvadosApiClient.new_or_current + end + + def arvados_api_client + ArvadosApiClient.new_or_current + end + def self.uuid_infix_object_kind @@uuid_infix_object_kind ||= begin infix_kind = {} - $arvados_api_client.discovery[:schemas].each do |name, schema| + arvados_api_client.discovery[:schemas].each do |name, schema| if schema[:uuidPrefix] infix_kind[schema[:uuidPrefix]] = 'arvados#' + name.to_s.camelcase(:lower) @@ -21,8 +29,8 @@ class ArvadosBase < ActiveRecord::Base end end - def initialize(*args) - super(*args) + def initialize raw_params={} + super self.class.permit_attribute_params(raw_params) @attribute_sortkey ||= { 'id' => nil, 'name' => '000', @@ -49,7 +57,7 @@ class ArvadosBase < ActiveRecord::Base return @columns unless @columns.nil? @columns = [] @attribute_info ||= {} - schema = $arvados_api_client.discovery[:schemas][self.to_s.to_sym] + schema = arvados_api_client.discovery[:schemas][self.to_s.to_sym] return @columns if schema.nil? schema[:properties].each do |k, coldef| case k @@ -64,7 +72,6 @@ class ArvadosBase < ActiveRecord::Base @columns << column(k, :text) serialize k, coldef[:type].constantize end - attr_accessible k @attribute_info[k] = coldef end end @@ -94,10 +101,10 @@ class ArvadosBase < ActiveRecord::Base # request} unless {cache: false} is given via opts. cache_key = "request_#{Thread.current.object_id}_#{self.to_s}_#{uuid}" if opts[:cache] == false - Rails.cache.write cache_key, $arvados_api_client.api(self, '/' + uuid) + Rails.cache.write cache_key, arvados_api_client.api(self, '/' + uuid) end hash = Rails.cache.fetch cache_key do - $arvados_api_client.api(self, '/' + uuid) + arvados_api_client.api(self, '/' + uuid) end new.private_reload(hash) end @@ -126,6 +133,25 @@ class ArvadosBase < ActiveRecord::Base ArvadosResourceList.new(self).all(*args) end + def self.permit_attribute_params raw_params + # strong_parameters does not provide security in Workbench: anyone + # who can get this far can just as well do a call directly to our + # database (Arvados) with the same credentials we use. + # + # The following permit! is necessary even with + # "ActionController::Parameters.permit_all_parameters = true", + # because permit_all does not permit nested attributes. + ActionController::Parameters.new(raw_params).permit! + end + + def self.create raw_params={} + super(permit_attribute_params(raw_params)) + end + + def update_attributes raw_params={} + super(self.class.permit_attribute_params(raw_params)) + end + def save obdata = {} self.class.columns.each do |col| @@ -136,9 +162,9 @@ class ArvadosBase < ActiveRecord::Base if etag postdata['_method'] = 'PUT' obdata.delete :uuid - resp = $arvados_api_client.api(self.class, '/' + uuid, postdata) + resp = arvados_api_client.api(self.class, '/' + uuid, postdata) else - resp = $arvados_api_client.api(self.class, '', postdata) + resp = arvados_api_client.api(self.class, '', postdata) end return false if !resp[:etag] || !resp[:uuid] @@ -165,7 +191,7 @@ class ArvadosBase < ActiveRecord::Base def destroy if etag || uuid postdata = { '_method' => 'DELETE' } - resp = $arvados_api_client.api(self.class, '/' + uuid, postdata) + resp = arvados_api_client.api(self.class, '/' + uuid, postdata) resp[:etag] && resp[:uuid] && resp else true @@ -192,13 +218,13 @@ class ArvadosBase < ActiveRecord::Base ok end end - @links = $arvados_api_client.api Link, '', { _method: 'GET', where: o, eager: true } - @links = $arvados_api_client.unpack_api_response(@links) + @links = arvados_api_client.api Link, '', { _method: 'GET', where: o, eager: true } + @links = arvados_api_client.unpack_api_response(@links) end def all_links return @all_links if @all_links - res = $arvados_api_client.api Link, '', { + res = arvados_api_client.api Link, '', { _method: 'GET', where: { tail_kind: self.kind, @@ -206,7 +232,7 @@ class ArvadosBase < ActiveRecord::Base }, eager: true } - @all_links = $arvados_api_client.unpack_api_response(res) + @all_links = arvados_api_client.unpack_api_response(res) end def reload @@ -218,7 +244,7 @@ class ArvadosBase < ActiveRecord::Base if uuid_or_hash.is_a? Hash hash = uuid_or_hash else - hash = $arvados_api_client.api(self.class, '/' + uuid_or_hash) + hash = arvados_api_client.api(self.class, '/' + uuid_or_hash) end hash.each do |k,v| if self.respond_to?(k.to_s + '=') @@ -299,13 +325,13 @@ class ArvadosBase < ActiveRecord::Base end resource_class = nil uuid.match /^[0-9a-z]{5}-([0-9a-z]{5})-[0-9a-z]{15}$/ do |re| - resource_class ||= $arvados_api_client. + resource_class ||= arvados_api_client. kind_class(self.uuid_infix_object_kind[re[1]]) end if opts[:referring_object] and opts[:referring_attr] and opts[:referring_attr].match /_uuid$/ - resource_class ||= $arvados_api_client. + resource_class ||= arvados_api_client. kind_class(opts[:referring_object]. attributes[opts[:referring_attr]. sub(/_uuid$/, '_kind')]) diff --git a/apps/workbench/app/models/arvados_resource_list.rb b/apps/workbench/app/models/arvados_resource_list.rb index 3f74407c01..dedd18c81d 100644 --- a/apps/workbench/app/models/arvados_resource_list.rb +++ b/apps/workbench/app/models/arvados_resource_list.rb @@ -1,4 +1,5 @@ class ArvadosResourceList + include ArvadosApiClientHelper include Enumerable def initialize resource_class=nil @@ -53,7 +54,7 @@ class ArvadosResourceList end cond.keys.select { |x| x.match /_kind$/ }.each do |kind_key| if cond[kind_key].is_a? Class - cond = cond.merge({ kind_key => 'arvados#' + $arvados_api_client.class_kind(cond[kind_key]) }) + cond = cond.merge({ kind_key => 'arvados#' + arvados_api_client.class_kind(cond[kind_key]) }) end end api_params = { @@ -65,8 +66,8 @@ class ArvadosResourceList api_params[:offset] = @offset if @offset api_params[:order] = @orderby_spec if @orderby_spec api_params[:filters] = @filters if @filters - res = $arvados_api_client.api @resource_class, '', api_params - @results = $arvados_api_client.unpack_api_response res + res = arvados_api_client.api @resource_class, '', api_params + @results = arvados_api_client.unpack_api_response res self end diff --git a/apps/workbench/app/models/collection.rb b/apps/workbench/app/models/collection.rb index a63bf90cb0..6022d82433 100644 --- a/apps/workbench/app/models/collection.rb +++ b/apps/workbench/app/models/collection.rb @@ -31,11 +31,11 @@ class Collection < ArvadosBase end def provenance - $arvados_api_client.api "collections/#{self.uuid}/", "provenance" + arvados_api_client.api "collections/#{self.uuid}/", "provenance" end def used_by - $arvados_api_client.api "collections/#{self.uuid}/", "used_by" + arvados_api_client.api "collections/#{self.uuid}/", "used_by" end end diff --git a/apps/workbench/app/models/group.rb b/apps/workbench/app/models/group.rb index dde6019e9c..8d8d3900c7 100644 --- a/apps/workbench/app/models/group.rb +++ b/apps/workbench/app/models/group.rb @@ -1,10 +1,10 @@ class Group < ArvadosBase def contents params={} - res = $arvados_api_client.api self.class, "/#{self.uuid}/contents", { + res = arvados_api_client.api self.class, "/#{self.uuid}/contents", { _method: 'GET' }.merge(params) ret = ArvadosResourceList.new - ret.results = $arvados_api_client.unpack_api_response(res) + ret.results = arvados_api_client.unpack_api_response(res) ret end diff --git a/apps/workbench/app/models/user.rb b/apps/workbench/app/models/user.rb index 44d615b89f..c1656bde69 100644 --- a/apps/workbench/app/models/user.rb +++ b/apps/workbench/app/models/user.rb @@ -6,15 +6,15 @@ class User < ArvadosBase end def self.current - res = $arvados_api_client.api self, '/current' - $arvados_api_client.unpack_api_response(res) + res = arvados_api_client.api self, '/current' + arvados_api_client.unpack_api_response(res) end def self.system - $arvados_system_user ||= begin - res = $arvados_api_client.api self, '/system' - $arvados_api_client.unpack_api_response(res) - end + @@arvados_system_user ||= begin + res = arvados_api_client.api self, '/system' + arvados_api_client.unpack_api_response(res) + end end def full_name @@ -22,9 +22,9 @@ class User < ArvadosBase end def activate - self.private_reload($arvados_api_client.api(self.class, - "/#{self.uuid}/activate", - {})) + self.private_reload(arvados_api_client.api(self.class, + "/#{self.uuid}/activate", + {})) end def attributes_for_display @@ -40,13 +40,13 @@ class User < ArvadosBase end def unsetup - self.private_reload($arvados_api_client.api(self.class, - "/#{self.uuid}/unsetup", - {})) + self.private_reload(arvados_api_client.api(self.class, + "/#{self.uuid}/unsetup", + {})) end def self.setup params - $arvados_api_client.api(self, "/setup", params) + arvados_api_client.api(self, "/setup", params) end end diff --git a/apps/workbench/app/models/user_agreement.rb b/apps/workbench/app/models/user_agreement.rb index 63b845228f..d77038cdd5 100644 --- a/apps/workbench/app/models/user_agreement.rb +++ b/apps/workbench/app/models/user_agreement.rb @@ -1,10 +1,10 @@ class UserAgreement < ArvadosBase def self.signatures - res = $arvados_api_client.api self, '/signatures' - $arvados_api_client.unpack_api_response(res) + res = arvados_api_client.api self, '/signatures' + arvados_api_client.unpack_api_response(res) end def self.sign(params) - res = $arvados_api_client.api self, '/sign', params - $arvados_api_client.unpack_api_response(res) + res = arvados_api_client.api self, '/sign', params + arvados_api_client.unpack_api_response(res) end end diff --git a/apps/workbench/app/views/layouts/application.html.erb b/apps/workbench/app/views/layouts/application.html.erb index e2db3d9b7e..2d3c4c0de0 100644 --- a/apps/workbench/app/views/layouts/application.html.erb +++ b/apps/workbench/app/views/layouts/application.html.erb @@ -232,7 +232,7 @@ <% else %> -
  • Log in
  • +
  • Log in
  • <% end %> diff --git a/apps/workbench/app/views/links/_recent.html.erb b/apps/workbench/app/views/links/_recent.html.erb index 7548ae111f..1e60bf511d 100644 --- a/apps/workbench/app/views/links/_recent.html.erb +++ b/apps/workbench/app/views/links/_recent.html.erb @@ -38,7 +38,7 @@ <% if current_user and (current_user.is_admin or current_user.uuid == link.owner_uuid) %> - <%= link_to raw(''), { action: 'destroy', id: link.uuid }, { confirm: 'Delete this link?', method: 'delete' } %> + <%= link_to raw(''), { action: 'destroy', id: link.uuid }, data: {confirm: 'Delete this link?', method: 'delete'} %> <% end %> diff --git a/apps/workbench/app/views/users/_show_admin.html.erb b/apps/workbench/app/views/users/_show_admin.html.erb index e2f5fdfa64..f667f388bd 100644 --- a/apps/workbench/app/views/users/_show_admin.html.erb +++ b/apps/workbench/app/views/users/_show_admin.html.erb @@ -15,7 +15,7 @@ account.

    As an admin, you can deactivate and reset this user. This will remove all repository/VM permissions for the user. If you "setup" the user again, the user will have to sign the user agreement again.

    -<%= button_to "Deactivate #{@object.full_name}", unsetup_user_url(id: @object.uuid), class: 'btn btn-primary', confirm: "Are you sure you want to deactivate #{@object.full_name}?"%> +<%= button_to "Deactivate #{@object.full_name}", unsetup_user_url(id: @object.uuid), class: 'btn btn-primary', data: {confirm: "Are you sure you want to deactivate #{@object.full_name}?"} %>
    <% content_for :footer_html do %> diff --git a/apps/workbench/app/views/users/welcome.html.erb b/apps/workbench/app/views/users/welcome.html.erb index 4fe5518093..537041e8f8 100644 --- a/apps/workbench/app/views/users/welcome.html.erb +++ b/apps/workbench/app/views/users/welcome.html.erb @@ -13,7 +13,7 @@ beyond that.

    - + Click here to log in to <%= Rails.configuration.site_name %> with a Google account

    diff --git a/apps/workbench/app/views/websocket/index.html.erb b/apps/workbench/app/views/websocket/index.html.erb index 85202b8662..d805371877 100644 --- a/apps/workbench/app/views/websocket/index.html.erb +++ b/apps/workbench/app/views/websocket/index.html.erb @@ -18,7 +18,7 @@ putStuffThere = function (content) { $("#PutStuffHere").append(content + "
    "); }; -var dispatcher = new WebSocket('<%= $arvados_api_client.discovery[:websocketUrl] %>?api_token=<%= Thread.current[:arvados_api_token] %>'); +var dispatcher = new WebSocket('<%= arvados_api_client.discovery[:websocketUrl] %>?api_token=<%= Thread.current[:arvados_api_token] %>'); dispatcher.onmessage = function(event) { //putStuffThere(JSON.parse(event.data)); putStuffThere(event.data); diff --git a/apps/workbench/config/application.default.yml b/apps/workbench/config/application.default.yml index c80b7f960a..2fe701afcb 100644 --- a/apps/workbench/config/application.default.yml +++ b/apps/workbench/config/application.default.yml @@ -3,15 +3,12 @@ development: cache_classes: false - whiny_nils: true + eager_load: true consider_all_requests_local: true action_controller.perform_caching: false action_mailer.raise_delivery_errors: false active_support.deprecation: :log action_dispatch.best_standards_support: :builtin - active_record.mass_assignment_sanitizer: :strict - active_record.auto_explain_threshold_in_seconds: 0.5 - assets.compress: false assets.debug: true profiling_enabled: true site_name: Arvados Workbench (dev) @@ -19,10 +16,10 @@ development: production: force_ssl: true cache_classes: true + eager_load: true consider_all_requests_local: false action_controller.perform_caching: true serve_static_assets: false - assets.compress: true assets.compile: false assets.digest: true i18n.fallbacks: true @@ -38,18 +35,18 @@ production: test: cache_classes: true + eager_load: false serve_static_assets: true static_cache_control: public, max-age=3600 - whiny_nils: true consider_all_requests_local: true action_controller.perform_caching: false action_dispatch.show_exceptions: false action_controller.allow_forgery_protection: false action_mailer.delivery_method: :test - active_record.mass_assignment_sanitizer: :strict active_support.deprecation: :stderr profiling_enabled: false secret_token: <%= rand(2**256).to_s(36) %> + secret_key_base: <%= rand(2**256).to_s(36) %> # When you run the Workbench's integration tests, it starts the API # server as a dependency. These settings should match the API @@ -62,6 +59,8 @@ test: site_name: Workbench:test common: + assets.js_compressor: false + assets.css_compressor: false data_import_dir: /tmp/arvados-workbench-upload data_export_dir: /tmp/arvados-workbench-download arvados_login_base: https://arvados.local/login @@ -72,5 +71,6 @@ common: arvados_theme: default show_user_agreement_inline: false secret_token: ~ + secret_key_base: false default_openid_prefix: https://www.google.com/accounts/o8/id send_user_setup_notification_email: true diff --git a/apps/workbench/config/application.rb b/apps/workbench/config/application.rb index 0e1ec9604c..4ac68198e8 100644 --- a/apps/workbench/config/application.rb +++ b/apps/workbench/config/application.rb @@ -2,12 +2,7 @@ require File.expand_path('../boot', __FILE__) require 'rails/all' -if defined?(Bundler) - # If you precompile assets before deploying to production, use this line - Bundler.require(*Rails.groups(:assets => %w(development test))) - # If you want your assets lazily compiled in production, use this line - # Bundler.require(:default, :assets, Rails.env) -end +Bundler.require(:default, Rails.env) module ArvadosWorkbench class Application < Rails::Application @@ -47,12 +42,6 @@ module ArvadosWorkbench # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql - # Enforce whitelist mode for mass assignment. - # This will create an empty whitelist of attributes available for mass-assignment for all models - # in your app. As such, your models will need to explicitly whitelist or blacklist accessible - # parameters by using an attr_accessible or attr_protected declaration. - config.active_record.whitelist_attributes = true - # Enable the asset pipeline config.assets.enabled = true @@ -60,3 +49,5 @@ module ArvadosWorkbench config.assets.version = '1.0' end end + +require File.expand_path('../load_config', __FILE__) diff --git a/apps/workbench/config/environments/development.rb.example b/apps/workbench/config/environments/development.rb.example index 389a25420f..3ea9ec2016 100644 --- a/apps/workbench/config/environments/development.rb.example +++ b/apps/workbench/config/environments/development.rb.example @@ -6,9 +6,6 @@ ArvadosWorkbench::Application.configure do # since you don't have to restart the web server when you make code changes. config.cache_classes = false - # Log error messages when you accidentally call methods on nil. - config.whiny_nils = true - # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false @@ -22,15 +19,8 @@ ArvadosWorkbench::Application.configure do # Only use best-standards-support built into browsers config.action_dispatch.best_standards_support = :builtin - # Raise exception on mass assignment protection for Active Record models - config.active_record.mass_assignment_sanitizer = :strict - - # Log the query plan for queries taking more than this (works - # with SQLite, MySQL, and PostgreSQL) - config.active_record.auto_explain_threshold_in_seconds = 0.5 - # Do not compress assets - config.assets.compress = false + config.assets.js_compressor = false # Expands the lines which load the assets config.assets.debug = true diff --git a/apps/workbench/config/environments/production.rb.example b/apps/workbench/config/environments/production.rb.example index bb7595454e..209556cbf4 100644 --- a/apps/workbench/config/environments/production.rb.example +++ b/apps/workbench/config/environments/production.rb.example @@ -12,7 +12,7 @@ ArvadosWorkbench::Application.configure do config.serve_static_assets = false # Compress JavaScripts and CSS - config.assets.compress = true + config.assets.js_compressor = :yui # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = false @@ -61,10 +61,6 @@ ArvadosWorkbench::Application.configure do # Send deprecation notices to registered listeners config.active_support.deprecation = :notify - # Log the query plan for queries taking more than this (works - # with SQLite, MySQL, and PostgreSQL) - # config.active_record.auto_explain_threshold_in_seconds = 0.5 - # Log timing data for API transactions config.profiling_enabled = false diff --git a/apps/workbench/config/environments/test.rb.example b/apps/workbench/config/environments/test.rb.example index b3cb72aff2..fd034d3185 100644 --- a/apps/workbench/config/environments/test.rb.example +++ b/apps/workbench/config/environments/test.rb.example @@ -11,9 +11,6 @@ ArvadosWorkbench::Application.configure do config.serve_static_assets = true config.static_cache_control = "public, max-age=3600" - # Log error messages when you accidentally call methods on nil - config.whiny_nils = true - # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false @@ -29,9 +26,6 @@ ArvadosWorkbench::Application.configure do # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test - # Raise exception on mass assignment protection for Active Record models - config.active_record.mass_assignment_sanitizer = :strict - # Print deprecation notices to the stderr config.active_support.deprecation = :stderr diff --git a/apps/workbench/config/initializers/zzz_arvados_api_client.rb b/apps/workbench/config/initializers/zzz_arvados_api_client.rb deleted file mode 100644 index 20ddd8c90c..0000000000 --- a/apps/workbench/config/initializers/zzz_arvados_api_client.rb +++ /dev/null @@ -1,8 +0,0 @@ -# The client object must be instantiated _after_ zza_load_config.rb -# runs, because it relies on configuration settings. -# -if not $application_config - raise "Fatal: Config must be loaded before instantiating ArvadosApiClient." -end - -$arvados_api_client = ArvadosApiClient.new diff --git a/apps/workbench/config/initializers/zza_load_config.rb b/apps/workbench/config/load_config.rb similarity index 100% rename from apps/workbench/config/initializers/zza_load_config.rb rename to apps/workbench/config/load_config.rb diff --git a/apps/workbench/config/routes.rb b/apps/workbench/config/routes.rb index e8862c2426..e0c93ec04b 100644 --- a/apps/workbench/config/routes.rb +++ b/apps/workbench/config/routes.rb @@ -18,8 +18,8 @@ ArvadosWorkbench::Application.routes.draw do resources :authorized_keys resources :job_tasks resources :jobs - match '/logout' => 'sessions#destroy' - match '/logged_out' => 'sessions#index' + match '/logout' => 'sessions#destroy', via: [:get, :post] + get '/logged_out' => 'sessions#index' resources :users do get 'home', :on => :member get 'welcome', :on => :collection @@ -39,7 +39,7 @@ ArvadosWorkbench::Application.routes.draw do get 'compare', on: :collection end resources :links - match '/collections/graph' => 'collections#graph' + get '/collections/graph' => 'collections#graph' resources :collections do post 'set_persistent', on: :member end @@ -55,5 +55,5 @@ ArvadosWorkbench::Application.routes.draw do # Send unroutable requests to an arbitrary controller # (ends up at ApplicationController#render_not_found) - match '*a', :to => 'links#render_not_found' + match '*a', to: 'links#render_not_found', via: [:get, :post] end diff --git a/apps/workbench/test/integration/users_test.rb b/apps/workbench/test/integration/users_test.rb index 6df7ee3a61..765156376f 100644 --- a/apps/workbench/test/integration/users_test.rb +++ b/apps/workbench/test/integration/users_test.rb @@ -63,6 +63,7 @@ class UsersTest < ActionDispatch::IntegrationTest fill_in "email", :with => "foo@example.com" fill_in "repo_name", :with => "test_repo" click_button "Submit" + wait_for_ajax end visit '/users' @@ -119,9 +120,9 @@ class UsersTest < ActionDispatch::IntegrationTest assert has_text? 'Virtual Machine' fill_in "repo_name", :with => "test_repo" click_button "Submit" + wait_for_ajax end - sleep(1) assert page.has_text? 'modified_by_client_uuid' click_link 'Metadata' @@ -138,9 +139,9 @@ class UsersTest < ActionDispatch::IntegrationTest fill_in "repo_name", :with => "second_test_repo" select("testvm.shell", :from => 'vm_uuid') click_button "Submit" + wait_for_ajax end - sleep(0.1) assert page.has_text? 'modified_by_client_uuid' click_link 'Metadata' @@ -203,9 +204,9 @@ class UsersTest < ActionDispatch::IntegrationTest fill_in "repo_name", :with => "second_test_repo" select("testvm.shell", :from => 'vm_uuid') click_button "Submit" + wait_for_ajax end - sleep(0.1) assert page.has_text? 'modified_by_client_uuid' click_link 'Metadata' diff --git a/apps/workbench/test/test_helper.rb b/apps/workbench/test/test_helper.rb index 05be43cb5f..c1eed5cd7b 100644 --- a/apps/workbench/test/test_helper.rb +++ b/apps/workbench/test/test_helper.rb @@ -22,9 +22,6 @@ end require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' -$ARV_API_SERVER_DIR = File.expand_path('../../../../services/api', __FILE__) -SERVER_PID_PATH = 'tmp/pids/server.pid' - class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in # alphabetical order. @@ -54,7 +51,8 @@ module ApiFixtureLoader # Returns the data structure from the named API server test fixture. @@api_fixtures[name] ||= \ begin - path = File.join($ARV_API_SERVER_DIR, 'test', 'fixtures', "#{name}.yml") + path = File.join(ApiServerForTests::ARV_API_SERVER_DIR, + 'test', 'fixtures', "#{name}.yml") YAML.load(IO.read(path)) end end @@ -73,8 +71,13 @@ class ActiveSupport::TestCase end end -class ApiServerBackedTestRunner < MiniTest::Unit - def _system(*cmd) +class ApiServerForTests + ARV_API_SERVER_DIR = File.expand_path('../../../../services/api', __FILE__) + SERVER_PID_PATH = File.expand_path('tmp/pids/wbtest-server.pid', ARV_API_SERVER_DIR) + @main_process_pid = $$ + + def self._system(*cmd) + $stderr.puts "_system #{cmd.inspect}" Bundler.with_clean_env do if not system({'RAILS_ENV' => 'test'}, *cmd) raise RuntimeError, "#{cmd[0]} returned exit code #{$?.exitstatus}" @@ -82,35 +85,66 @@ class ApiServerBackedTestRunner < MiniTest::Unit end end - def _run(args=[]) + def self.make_ssl_cert + unless File.exists? './self-signed.key' + _system('openssl', 'req', '-new', '-x509', '-nodes', + '-out', './self-signed.pem', + '-keyout', './self-signed.key', + '-days', '3650', + '-subj', '/CN=localhost') + end + end + + def self.kill_server + if (pid = find_server_pid) + $stderr.puts "Sending TERM to API server, pid #{pid}" + Process.kill 'TERM', pid + end + end + + def self.find_server_pid + pid = nil + begin + pid = IO.read(SERVER_PID_PATH).to_i + $stderr.puts "API server is running, pid #{pid.inspect}" + rescue Errno::ENOENT + end + return pid + end + + def self.run(args=[]) + ::MiniTest.after_run do + self.kill_server + end + + # Kill server left over from previous test run + self.kill_server + Capybara.javascript_driver = :poltergeist - server_pid = Dir.chdir($ARV_API_SERVER_DIR) do |apidir| + Dir.chdir(ARV_API_SERVER_DIR) do |apidir| ENV["NO_COVERAGE_TEST"] = "1" + make_ssl_cert _system('bundle', 'exec', 'rake', 'db:test:load') _system('bundle', 'exec', 'rake', 'db:fixtures:load') - _system('bundle', 'exec', 'rails', 'server', '-d') + _system('bundle', 'exec', 'passenger', 'start', '-d', '-p3001', + '--pid-file', SERVER_PID_PATH, + '--ssl', + '--ssl-certificate', 'self-signed.pem', + '--ssl-certificate-key', 'self-signed.key') timeout = Time.now.tv_sec + 10 good_pid = false while (not good_pid) and (Time.now.tv_sec < timeout) sleep 0.2 - begin - server_pid = IO.read(SERVER_PID_PATH).to_i - good_pid = (server_pid > 0) and (Process.kill(0, server_pid) rescue false) - rescue Errno::ENOENT - good_pid = false - end + server_pid = find_server_pid + good_pid = (server_pid and + (server_pid > 0) and + (Process.kill(0, server_pid) rescue false)) end if not good_pid raise RuntimeError, "could not find API server Rails pid" end - server_pid - end - begin - super(args) - ensure - Process.kill('TERM', server_pid) end end end -MiniTest::Unit.runner = ApiServerBackedTestRunner.new +ApiServerForTests.run diff --git a/doc/install/install-workbench-app.html.textile.liquid b/doc/install/install-workbench-app.html.textile.liquid index eaf4edecdd..055ef47892 100644 --- a/doc/install/install-workbench-app.html.textile.liquid +++ b/doc/install/install-workbench-app.html.textile.liquid @@ -49,6 +49,17 @@ Alternatively, if you don't have sudo/root privileges on the host, install the g ~/arvados/apps/workbench$ bundle install --path=vendor/bundle +The @bundle install@ command might produce a warning about the themes_for_rails gem. This is OK: + + +
    themes_for_rails at /home/you/.rvm/gems/ruby-2.1.1/bundler/gems/themes_for_rails-1fd2d7897d75 did not have a valid gemspec.
    +This prevents bundler from installing bins or native extensions, but that may not affect its functionality.
    +The validation message from Rubygems was:
    +  duplicate dependency on rails (= 3.0.11, development), (>= 3.0.0) use:
    +    add_runtime_dependency 'rails', '= 3.0.11', '>= 3.0.0'
    +Using themes_for_rails (0.5.1) from https://github.com/holtkampw/themes_for_rails (at 1fd2d78)
    +
    + h2. Configure the Workbench application This application needs a secret token. Generate a new secret: