[ARVADOS] updated: 72912c6b25fcb10c0acc540daf4f8a25d802784b

Git user git at public.curoverse.com
Wed Oct 12 11:32:11 EDT 2016


Summary of changes:
 .../app/controllers/application_controller.rb      |   2 +-
 apps/workbench/config/application.default.yml      |   8 +-
 .../_container_runtime_constraints.liquid          |   1 +
 sdk/cli/test/test_arv-keep-get.rb                  |   4 +-
 sdk/cwl/arvados_cwl/arv-cwl-schema.yml             |  10 +
 sdk/cwl/arvados_cwl/arvcontainer.py                |   5 +
 sdk/cwl/tests/test_container.py                    |   6 +-
 sdk/go/arvados/container.go                        |   7 +-
 sdk/python/arvados/arvfile.py                      |  82 +++-
 sdk/python/arvados/commands/put.py                 | 517 +++++++++++++++------
 sdk/python/tests/test_arv_put.py                   | 178 +++----
 sdk/python/tests/test_collections.py               |  18 +-
 services/api/Gemfile                               |   5 +-
 services/api/Gemfile.lock                          |  15 +-
 services/api/Rakefile                              |  21 +
 .../arvados/v1/collections_controller_test.rb      |  10 +-
 .../functional/arvados/v1/links_controller_test.rb |   4 +-
 .../integration/collections_performance_test.rb    |   6 +-
 .../api/test/integration/database_reset_test.rb    |   9 +-
 services/api/test/integration/websocket_test.rb    |  20 +-
 services/api/test/test_helper.rb                   |  19 +-
 .../api/test/unit/collection_performance_test.rb   |   3 +-
 services/api/test/unit/permission_test.rb          |   4 +-
 ...git-httpd.service => arvados-git-httpd.service} |   0
 .../crunch-dispatch-slurm/crunch-dispatch-slurm.go |   3 +
 .../crunch-dispatch-slurm_test.go                  |  16 +-
 services/crunch-dispatch-slurm/squeue.go           |   2 +-
 27 files changed, 670 insertions(+), 305 deletions(-)
 rename services/arv-git-httpd/{arv-git-httpd.service => arvados-git-httpd.service} (100%)

  discards  b0200d9b2e88ac3b401ae0c16e5921aaa2c560cd (commit)
  discards  3dded76022898b465f868db9b1558789633f6f2c (commit)
  discards  e30527ef55c84573ffb900f10c89b7e7f5acdbac (commit)
  discards  8230466da11f6ef6883340bccd16961088e74a0f (commit)
  discards  16de8f12d6dacc142c78820ff4012a4a0c3f8fae (commit)
  discards  52cf53e2a8ead682bfe44e921b9f9906b6647f77 (commit)
  discards  026461e05b9f544124e6783e592ed7c0a89ef44c (commit)
  discards  427fe9184a8dc2c1ce3b2eeda70e44214583a140 (commit)
  discards  b1171f64673b908d7b8d95dd25efe8eb83afdf8a (commit)
  discards  2ab7edce2bfe9d592bf7f99ae5558b64c3aed38a (commit)
  discards  0450aa064b44894e3e5288d3737310cd329cafd7 (commit)
  discards  9f8e44c0a2514f6051db1228ccee81a108ff6ebb (commit)
  discards  592387b2beaf479299ec3efa6d66e2bc88519348 (commit)
  discards  8ab0c104ccacd4baf20499323bc819ac87684052 (commit)
  discards  98ebf95bb1232175cf97df3cfe0d36b90a667ee2 (commit)
  discards  13e418064a2a23d7c27915b2fa89c14c5e4fe9f6 (commit)
  discards  53ca9d2906648a363ba26bffb90dfee9edfe8a4c (commit)
       via  72912c6b25fcb10c0acc540daf4f8a25d802784b (commit)
       via  8886788e82b7e45c9211f6bf3a23c601ed0b88c1 (commit)
       via  279db7d614a25c5e81c6efda5c8950988682974a (commit)
       via  0b228d13b944b4b94165bf22a8f796070bd711bf (commit)
       via  014f72fcdac2b26f9f2bbf257707eb59c676eebb (commit)
       via  1671eb078bc4d254ebdfe5ac8dd40c83b371e8ac (commit)
       via  554350245276ee082417cdcfcb8fd3f4f593e00f (commit)
       via  c2f6922a1997ca73d46866f03474a23c76c7afa5 (commit)
       via  450cf2524ff41b2a0fcea09e2e6ccbf3bdbf78ed (commit)
       via  c632b87902785c4bbc5242b095e53bcf657f6aae (commit)
       via  61925eaac13ef601879178d6343de9f9714f3da1 (commit)
       via  c6b3743bae761b8802cf7e016e54833d833ba9f7 (commit)
       via  722670d1113e1af551d8470841a38d8d9218b4e8 (commit)
       via  2bb3fb59369abd48211a872ca1a8e49cb70be5f3 (commit)
       via  e34688e4a78595aaabe7307f0184df84ff703c6f (commit)
       via  b8a539e3a0803083b1fcbb23755fc12cffff6f31 (commit)
       via  2e9514e54e31bb37c438cf5d611d49a7c15235b4 (commit)
       via  fd308c814745d9c4eed5c3f79b44b9f9142df28a (commit)
       via  25b000e2eefa9d2cfd454bb9a27518a882bb21a1 (commit)
       via  0087f03f1b12d8ad383388d411a8c97ffe196739 (commit)
       via  c98596a46dc7c166acb2a26b742a09ae0493224a (commit)
       via  083dcfe0946067f32681b4ffc497a7e9a5fdff79 (commit)
       via  5af68e1098ebd0ab749387667c18585a18b71f04 (commit)
       via  e892c7ee96f28bef7d5b2a9314eb9549ee56634d (commit)
       via  f3d4ec1d93cadb51fb55355caa8c08f453bc4c21 (commit)
       via  9f35a3cf10e5d261d83556d5b33f242966101f02 (commit)
       via  87473fd874bfc6fe954089b74bef915543a48d60 (commit)
       via  fd36117b416e1190334d108058dc0c16ef24e964 (commit)
       via  24bcfa0b87b87e4510fffe8a961a5d4a9fd34948 (commit)
       via  31568ea331306a574be758fc60b090ecee3bc005 (commit)
       via  c9180edfa0d7306b9a533a0ed15dd90eca5cfae1 (commit)
       via  84f2296c5c6563f2d61a208d5c427d98003bfecd (commit)
       via  3513c7def7eacdeef16c355f1b9be93830dcf946 (commit)
       via  f678c1f5a1b03a49eb0a40f614990b0fbcad3436 (commit)
       via  14a9cddd966bd1035c48e5fbac5065555ad7bb92 (commit)
       via  800a66e4d96c1fb341d643549d871d36e598ea31 (commit)
       via  a5ce43cd7493e17fe1bb5f67451957b283881228 (commit)
       via  d70adee422f8f68debdf4425fea8afd53a488556 (commit)
       via  6757824d984496469cd929cdbb62643c1cede7fd (commit)
       via  e25a377ed38698cb3eebbd0f43b80a5276595240 (commit)
       via  bf6ef981cea7e923a085c0a9231cebb379c7560a (commit)
       via  e21c8f8c0ba6f2012bc4108f8fa27411ab4375d1 (commit)
       via  b8036cfd2acd1bf2910130deb46be8a38eaff253 (commit)
       via  8d0f1cbda7cb58b15923813d5fca0448cb7b330e (commit)
       via  f35e22ef4abc012cad2260149657b95bfbcbac5d (commit)
       via  a7ee134a2815fad9febc3cdcd7b2a1fc77aff953 (commit)
       via  480df25dc679998b53f9e7299244ac1ff3f90114 (commit)
       via  8e6d577f1381da0d42481ef8dd0479241e3c50bf (commit)
       via  bd7dc68d12f1d134106fd21afe9cbf2d0512c831 (commit)
       via  224f384d411bb1b4cccc7165c55bb64fd5c695ad (commit)
       via  ffe1fe1c77743147ee82aacdc50edde3672cd748 (commit)
       via  f300b641735aa2657cfdcc4303050095c3bd60d5 (commit)
       via  a229ee1c2da50d247c5e7de12096f0f9d6ea3943 (commit)
       via  27b732adbd4d2331436a433394658a0cfcf5fd94 (commit)
       via  4da754586b4529a4480951218a69ec6f41fee98d (commit)
       via  84f3d7048e63fc88b39f329ac5472238df2edc3d (commit)
       via  6d162bfdf0c3cbfc2d723ecff4153f85daa2d003 (commit)
       via  fe0d8506f80a7ce5f1d412823a09a5d7324b7161 (commit)
       via  7b227c653e31449f6c23b4b8d933172bbfb2b172 (commit)
       via  2c640b0e791d9997ff87f4ec2b33af7781286af5 (commit)
       via  3a1f0b616382230c32439b8d7e17ff75a132a10d (commit)
       via  e69ce852e1cbbe5bab82e32ec5d1874ef5a768f3 (commit)
       via  62d56bce0d714cc2df2ab5e7f1005dc3d76f783b (commit)
       via  69902ee6583e1de32786e80b77c8f61870ed6f90 (commit)
       via  9a363fce5687e55c5554b3eaeee16e7f1f0791f6 (commit)
       via  2b52a4885952a8a3eed01b03af33210fc86d6ce5 (commit)
       via  05e30c2874cfee6e448de38254d4eb6007abb1cd (commit)
       via  bca6c8e4c3d880955d19f7b6ff50bc3fbc31146c (commit)
       via  1487c0577921c88801c377d753d1322fd1485968 (commit)
       via  1c3f80531764931c241cd07a3cbc56892b645bce (commit)
       via  e3a7370e35792c4cdfae441099d18d1b0d18e5b3 (commit)
       via  5f909f9dac2cad1eb0ed0c00a3be37c2edc79667 (commit)
       via  8e9ae6053dbe8923f294bb819d9382988c1f43fc (commit)
       via  67c0bb9abe2f9069761a271145ae48368ee3d7d6 (commit)
       via  44c2e41fec0beeab4544103d0a4afb9a775ed706 (commit)
       via  5139cff2d5425debd948131e0f60242845ea0b61 (commit)
       via  82a01df9d9f4f8961978a1383f4b6c09e73fe28d (commit)
       via  dcb4db28681b6949a56a1de579891cb375c423fe (commit)
       via  3847357436978a97470e0769f3200d354a2bd08e (commit)
       via  44ea4c89930d52d142da2c0b7204fd34f61f8f39 (commit)
       via  ef06ae1ddabb8ab6977090deb756baa2e4fb6eb5 (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (b0200d9b2e88ac3b401ae0c16e5921aaa2c560cd)
            \
             N -- N -- N (72912c6b25fcb10c0acc540daf4f8a25d802784b)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 72912c6b25fcb10c0acc540daf4f8a25d802784b
Author: Tom Clegg <tom at curoverse.com>
Date:   Tue Oct 11 22:17:52 2016 -0400

    5737: Return of Minitest

diff --git a/services/api/Gemfile b/services/api/Gemfile
index a151138..dfaa070 100644
--- a/services/api/Gemfile
+++ b/services/api/Gemfile
@@ -9,11 +9,12 @@ group :test, :development do
   gem 'factory_girl_rails'
   gem 'database_cleaner'
   gem 'ruby-prof'
-  gem 'test-unit', require: false
-  gem 'test-unit-activesupport', require: false
   # Note: "require: false" here tells bunder not to automatically
   # 'require' the packages during application startup. Installation is
   # still mandatory.
+  gem 'test-unit', '~> 3.0', require: false
+  gem 'minitest-rails', require: false
+  gem 'minitest', '~> 4.0', require: false
   gem 'simplecov', '~> 0.7.1', require: false
   gem 'simplecov-rcov', require: false
   gem 'mocha', require: false
diff --git a/services/api/Gemfile.lock b/services/api/Gemfile.lock
index 814aa14..d9edcc6 100644
--- a/services/api/Gemfile.lock
+++ b/services/api/Gemfile.lock
@@ -132,6 +132,13 @@ GEM
     memoist (0.15.0)
     metaclass (0.0.4)
     mime-types (1.25.1)
+    minitest (4.7.5)
+    minitest-rails (1.0.1)
+      minitest (~> 4.7)
+      minitest-test (~> 1.0)
+      railties (>= 3.0, < 4.1)
+    minitest-test (1.1.0)
+      minitest (~> 4.0)
     mocha (1.2.0)
       metaclass (~> 0.0.1)
     multi_json (1.12.1)
@@ -223,9 +230,6 @@ GEM
     sshkey (1.8.0)
     test-unit (3.2.1)
       power_assert
-    test-unit-activesupport (1.0.6)
-      activesupport
-      test-unit
     test_after_commit (1.1.0)
       activerecord (>= 3.2)
     themes_for_rails (0.5.1)
@@ -262,6 +266,8 @@ DEPENDENCIES
   jquery-rails
   lograge
   logstash-event
+  minitest (~> 4.0)
+  minitest-rails
   mocha
   multi_json
   oj
@@ -279,8 +285,7 @@ DEPENDENCIES
   simplecov (~> 0.7.1)
   simplecov-rcov
   sshkey
-  test-unit
-  test-unit-activesupport
+  test-unit (~> 3.0)
   test_after_commit
   themes_for_rails
   therubyracer
diff --git a/services/api/test/functional/arvados/v1/collections_controller_test.rb b/services/api/test/functional/arvados/v1/collections_controller_test.rb
index 64f6195..634fce7 100644
--- a/services/api/test/functional/arvados/v1/collections_controller_test.rb
+++ b/services/api/test/functional/arvados/v1/collections_controller_test.rb
@@ -751,13 +751,11 @@ EOS
     [2**8, :success],
     [2**18, 422],
   ].each do |description_size, expected_response|
-    test "create collection with description size #{description_size}
+    # Descriptions are not part of search indexes. Skip until
+    # full-text search is implemented, at which point replace with a
+    # search in description.
+    skip "create collection with description size #{description_size}
           and expect response #{expected_response}" do
-
-      omit "(Descriptions are not part of search indexes. Skip until
-      full-text search is implemented, at which point replace with a
-      search in description.)"
-
       authorize_with :active
 
       description = 'here is a collection with a very large description'
diff --git a/services/api/test/functional/arvados/v1/links_controller_test.rb b/services/api/test/functional/arvados/v1/links_controller_test.rb
index af3cd3a..6a19bdf 100644
--- a/services/api/test/functional/arvados/v1/links_controller_test.rb
+++ b/services/api/test/functional/arvados/v1/links_controller_test.rb
@@ -305,8 +305,8 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
     assert_response 404
   end
 
-  test "retrieve all permissions using generic links index api" do
-    omit "(not implemented)"
+  # not implemented
+  skip "retrieve all permissions using generic links index api" do
     # Links.readable_by() does not return the full set of permission
     # links that are visible to a user (i.e., all permission links
     # whose head_uuid references an object for which the user has
diff --git a/services/api/test/integration/collections_performance_test.rb b/services/api/test/integration/collections_performance_test.rb
index a952c20..f6f39fe 100644
--- a/services/api/test/integration/collections_performance_test.rb
+++ b/services/api/test/integration/collections_performance_test.rb
@@ -5,8 +5,7 @@ require 'helpers/time_block'
 class CollectionsApiPerformanceTest < ActionDispatch::IntegrationTest
   include ManifestExamples
 
-  test "crud cycle for a collection with a big manifest" do
-    slow_test
+  slow_test "crud cycle for a collection with a big manifest" do
     bigmanifest = time_block 'make example' do
       make_manifest(streams: 100,
                     files_per_stream: 100,
@@ -39,8 +38,7 @@ class CollectionsApiPerformanceTest < ActionDispatch::IntegrationTest
     end
   end
 
-  test "memory usage" do
-    slow_test
+  slow_test "memory usage" do
     hugemanifest = make_manifest(streams: 1,
                                  files_per_stream: 2000,
                                  blocks_per_file: 200,
diff --git a/services/api/test/integration/database_reset_test.rb b/services/api/test/integration/database_reset_test.rb
index ecb2f2a..029e37c 100644
--- a/services/api/test/integration/database_reset_test.rb
+++ b/services/api/test/integration/database_reset_test.rb
@@ -3,8 +3,7 @@ require 'test_helper'
 class DatabaseResetTest < ActionDispatch::IntegrationTest
   self.use_transactional_fixtures = false
 
-  test "reset fails when Rails.env != 'test'" do
-    slow_test
+  slow_test "reset fails when Rails.env != 'test'" do
     rails_env_was = Rails.env
     begin
       Rails.env = 'production'
@@ -22,8 +21,7 @@ class DatabaseResetTest < ActionDispatch::IntegrationTest
     assert_response 403
   end
 
-  test "database reset doesn't break basic CRUD operations" do
-    slow_test
+  slow_test "database reset doesn't break basic CRUD operations" do
     active_auth = auth(:active)
     admin_auth = auth(:admin)
 
@@ -49,8 +47,7 @@ class DatabaseResetTest < ActionDispatch::IntegrationTest
     assert_response 404
   end
 
-  test "roll back database change" do
-    slow_test
+  slow_test "roll back database change" do
     active_auth = auth(:active)
     admin_auth = auth(:admin)
 
diff --git a/services/api/test/integration/websocket_test.rb b/services/api/test/integration/websocket_test.rb
index 2128be9..8fd9685 100644
--- a/services/api/test/integration/websocket_test.rb
+++ b/services/api/test/integration/websocket_test.rb
@@ -375,8 +375,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     assert_equal expect_next_logs[1].object_uuid, l2
   end
 
-  test "connect, subscribe, get event, unsubscribe" do
-    slow_test
+  slow_test "connect, subscribe, get event, unsubscribe" do
     state = 1
     spec = nil
     spec_ev_uuid = nil
@@ -425,8 +424,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     assert_equal spec.uuid, spec_ev_uuid
   end
 
-  test "connect, subscribe, get event, unsubscribe with filter" do
-    slow_test
+  slow_test "connect, subscribe, get event, unsubscribe with filter" do
     state = 1
     spec = nil
     spec_ev_uuid = nil
@@ -475,8 +473,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
   end
 
 
-  test "connect, subscribe, get event, try to unsubscribe with bogus filter" do
-    slow_test
+  slow_test "connect, subscribe, get event, try to unsubscribe with bogus filter" do
     state = 1
     spec = nil
     spec_ev_uuid = nil
@@ -526,10 +523,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     assert_equal human.uuid, human_ev_uuid
   end
 
-
-
-  test "connected, not subscribed, no event" do
-    slow_test
+  slow_test "connected, not subscribed, no event" do
     authorize_with :active
 
     ws_helper(token: :active, timeout: false) do |ws|
@@ -549,8 +543,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     end
   end
 
-  test "connected, not authorized to see event" do
-    slow_test
+  slow_test "connected, not authorized to see event" do
     state = 1
 
     authorize_with :admin
@@ -665,8 +658,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
   end
 
-  test "connect, subscribe, lots of events" do
-    slow_test
+  slow_test "connect, subscribe, lots of events" do
     state = 1
     event_count = 0
     log_start = Log.order(:id).last.id
diff --git a/services/api/test/test_helper.rb b/services/api/test/test_helper.rb
index 2986f69..d998c92 100644
--- a/services/api/test/test_helper.rb
+++ b/services/api/test/test_helper.rb
@@ -21,9 +21,11 @@ unless ENV["NO_COVERAGE_TEST"]
 end
 
 require File.expand_path('../../config/environment', __FILE__)
-require 'test/unit/active_support'
+gem 'minitest'
 require 'rails/test_help'
-require 'mocha/test_unit'
+require 'minitest-rails'
+require 'minitest/autorun'
+require 'mocha'
 
 module ArvadosTestSupport
   def json_response
@@ -113,13 +115,18 @@ class ActiveSupport::TestCase
                              "HTTP_AUTHORIZATION" => "OAuth2 #{t}")
   end
 
-  def slow_test
-    omit "RAILS_TEST_SHORT is set" if self.class.skip_slow_tests?
-  end
-
   def self.skip_slow_tests?
     !(ENV['RAILS_TEST_SHORT'] || '').empty?
   end
+
+  def self.skip(*args, &block)
+  end
+
+  def self.slow_test(name, &block)
+    define_method(name, block) unless skip_slow_tests?
+  end
+
+  alias_method :skip, :omit
 end
 
 class ActionController::TestCase
diff --git a/services/api/test/unit/collection_performance_test.rb b/services/api/test/unit/collection_performance_test.rb
index 1c6e4f2..c9e702a 100644
--- a/services/api/test/unit/collection_performance_test.rb
+++ b/services/api/test/unit/collection_performance_test.rb
@@ -17,8 +17,7 @@ class CollectionModelPerformanceTest < ActiveSupport::TestCase
   end
 
   # "crrud" == "create read render update delete", not a typo
-  test "crrud cycle for a collection with a big manifest)" do
-    slow_test
+  slow_test "crrud cycle for a collection with a big manifest)" do
     bigmanifest = time_block 'make example' do
       make_manifest(streams: 100,
                     files_per_stream: 100,
diff --git a/services/api/test/unit/permission_test.rb b/services/api/test/unit/permission_test.rb
index dc3be0b..5653a44 100644
--- a/services/api/test/unit/permission_test.rb
+++ b/services/api/test/unit/permission_test.rb
@@ -142,8 +142,8 @@ class PermissionTest < ActiveSupport::TestCase
     assert test_perm.destroy, "could not delete new permission on target object"
   end
 
-  test "can_manage permission on a non-group object" do
-    omit "bug #3091"
+  # bug #3091
+  skip "can_manage permission on a non-group object" do
     set_user_from_auth :admin
 
     ob = Specimen.create!

commit 8886788e82b7e45c9211f6bf3a23c601ed0b88c1
Author: Tom Clegg <tom at curoverse.com>
Date:   Tue Oct 11 15:57:33 2016 -0400

    5737: Cleanup test and add comment about collation sensitivity.

diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb
index 9da1d78..b2f5c70 100644
--- a/apps/workbench/app/controllers/application_controller.rb
+++ b/apps/workbench/app/controllers/application_controller.rb
@@ -892,7 +892,7 @@ class ApplicationController < ActionController::Base
   # from the top three levels.
   # That is: get toplevel projects under home, get subprojects of
   # these projects, and so on until we hit the limit.
-  def my_wanted_projects user, page_size=100
+  def my_wanted_projects(user, page_size=100)
     return @my_wanted_projects if @my_wanted_projects
 
     from_top = []
@@ -907,7 +907,7 @@ class ApplicationController < ActionController::Base
       break if current_level.results.size == 0
       @too_many_projects = true if current_level.items_available > current_level.results.size
       from_top.concat current_level.results
-      uuids = current_level.results.collect { |x| x.uuid }
+      uuids = current_level.results.collect(&:uuid)
       depth += 1
       if depth >= 3
         @reached_level_limit = true
@@ -918,12 +918,12 @@ class ApplicationController < ActionController::Base
   end
 
   helper_method :my_wanted_projects_tree
-  def my_wanted_projects_tree user, page_size=100
-    build_my_wanted_projects_tree user, page_size
+  def my_wanted_projects_tree(user, page_size=100)
+    build_my_wanted_projects_tree(user, page_size)
     [@my_wanted_projects_tree, @too_many_projects, @reached_level_limit]
   end
 
-  def build_my_wanted_projects_tree user, page_size=100
+  def build_my_wanted_projects_tree(user, page_size=100)
     return @my_wanted_projects_tree if @my_wanted_projects_tree
 
     parent_of = {user.uuid => 'me'}
diff --git a/apps/workbench/test/controllers/projects_controller_test.rb b/apps/workbench/test/controllers/projects_controller_test.rb
index d31d6e3..d0b1e28 100644
--- a/apps/workbench/test/controllers/projects_controller_test.rb
+++ b/apps/workbench/test/controllers/projects_controller_test.rb
@@ -490,27 +490,28 @@ class ProjectsControllerTest < ActionController::TestCase
     ["user1_with_load", 2, ["project_with_10_collections"], "project_with_2_pipelines_and_60_crs"],
     ["admin", 5, ["anonymously_accessible_project", "subproject_in_anonymous_accessible_project"], "aproject"],
   ].each do |user, page_size, tree_segment, unexpected|
+    # Note: this test is sensitive to database collation. It passes
+    # with en_US.UTF-8.
     test "build my projects tree for #{user} user and verify #{unexpected} is omitted" do
       use_token user
-      ctrl = ProjectsController.new
-
-      current_user = User.find(api_fixture('users')[user]['uuid'])
 
-      my_tree = ctrl.send :my_wanted_projects_tree, current_user, page_size
+      tree, _, _ = @controller.send(:my_wanted_projects_tree,
+                                    User.current,
+                                    page_size)
 
       tree_segment_at_depth_1 = api_fixture('groups')[tree_segment[0]]
       tree_segment_at_depth_2 = api_fixture('groups')[tree_segment[1]] if tree_segment[1]
 
-      tree_nodes = {}
-      my_tree[0].each do |x|
-        tree_nodes[x[:object]['uuid']] = x[:depth]
+      node_depth = {}
+      tree.each do |x|
+        node_depth[x[:object]['uuid']] = x[:depth]
       end
 
-      assert_equal(1, tree_nodes[tree_segment_at_depth_1['uuid']])
-      assert_equal(2, tree_nodes[tree_segment_at_depth_2['uuid']]) if tree_segment[1]
+      assert_equal(1, node_depth[tree_segment_at_depth_1['uuid']])
+      assert_equal(2, node_depth[tree_segment_at_depth_2['uuid']]) if tree_segment[1]
 
       unexpected_project = api_fixture('groups')[unexpected]
-      assert_nil(tree_nodes[unexpected_project['uuid']])
+      assert_nil(node_depth[unexpected_project['uuid']], node_depth.inspect)
     end
   end
 

commit 279db7d614a25c5e81c6efda5c8950988682974a
Author: Tom Clegg <tom at curoverse.com>
Date:   Tue Oct 11 11:22:38 2016 -0400

    5737: Tidy up Gemfile and update bundle

diff --git a/apps/workbench/Gemfile b/apps/workbench/Gemfile
index 20d64d1..eac4fdf 100644
--- a/apps/workbench/Gemfile
+++ b/apps/workbench/Gemfile
@@ -1,6 +1,6 @@
 source 'https://rubygems.org'
 
-gem 'rails', '~> 4.1.0'
+gem 'rails', '~> 4.1'
 gem 'arvados', '>= 0.1.20150511150219'
 
 gem 'activerecord-nulldb-adapter'
@@ -19,7 +19,7 @@ gem 'coffee-rails'
 # in production environments by default.
 group :assets do
   gem 'sass-rails'
-  gem 'uglifier', '>= 1.0.3'
+  gem 'uglifier', '~> 2.0'
 
   # See https://github.com/sstephenson/execjs#readme for more supported runtimes
   gem 'therubyracer', :platforms => :ruby
@@ -33,7 +33,7 @@ group :development do
 end
 
 group :test, :diagnostics, :performance do
-  gem 'minitest', '>= 5.0.0'
+  gem 'minitest', '~> 5.0'
   gem 'selenium-webdriver'
   gem 'capybara'
   gem 'poltergeist'
diff --git a/apps/workbench/Gemfile.lock b/apps/workbench/Gemfile.lock
index 11f32d6..0abe868 100644
--- a/apps/workbench/Gemfile.lock
+++ b/apps/workbench/Gemfile.lock
@@ -92,7 +92,7 @@ GEM
     deep_merge (1.0.1)
     docile (1.1.5)
     erubis (2.7.0)
-    execjs (2.2.2)
+    execjs (2.7.0)
     extlib (0.9.16)
     faraday (0.9.2)
       multipart-post (>= 1.2, < 3)
@@ -158,7 +158,7 @@ GEM
       metaclass (~> 0.0.1)
     morrisjs-rails (0.5.1)
       railties (> 3.1, < 5)
-    multi_json (1.12.0)
+    multi_json (1.12.1)
     multipart-post (2.0.0)
     net-scp (1.2.1)
       net-ssh (>= 2.6.5)
@@ -257,7 +257,7 @@ GEM
     tilt (1.4.1)
     tzinfo (1.2.2)
       thread_safe (~> 0.1)
-    uglifier (2.7.0)
+    uglifier (2.7.2)
       execjs (>= 0.3.0)
       json (>= 1.8.0)
     websocket (1.2.2)
@@ -292,7 +292,7 @@ DEPENDENCIES
   less-rails
   lograge
   logstash-event
-  minitest (>= 5.0.0)
+  minitest (~> 5.0)
   mocha
   morrisjs-rails
   multi_json
@@ -301,7 +301,7 @@ DEPENDENCIES
   piwik_analytics
   poltergeist
   rack-mini-profiler
-  rails (~> 4.1.0)
+  rails (~> 4.1)
   rails-perftest
   raphael-rails
   ruby-debug-passenger
@@ -316,7 +316,7 @@ DEPENDENCIES
   sshkey
   themes_for_rails!
   therubyracer
-  uglifier (>= 1.0.3)
+  uglifier (~> 2.0)
   wiselinks
 
 BUNDLED WITH
diff --git a/services/api/Gemfile b/services/api/Gemfile
index 546f816..a151138 100644
--- a/services/api/Gemfile
+++ b/services/api/Gemfile
@@ -1,6 +1,6 @@
 source 'https://rubygems.org'
 
-gem 'rails', '~> 3.2.0'
+gem 'rails', '~> 3.2'
 
 # Bundle edge Rails instead:
 # gem 'rails',     :git => 'git://github.com/rails/rails.git'
@@ -31,13 +31,13 @@ gem 'oj'
 # 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',   '~> 3.2'
+  gem 'coffee-rails', '~> 3.2'
 
   # See https://github.com/sstephenson/execjs#readme for more supported runtimes
   gem 'therubyracer'
 
-  gem 'uglifier', '>= 1.0.3'
+  gem 'uglifier', '~> 2.0'
 end
 
 gem 'jquery-rails'
@@ -60,8 +60,8 @@ gem 'acts_as_api'
 
 gem 'passenger'
 
-gem 'omniauth', '1.1.1'
-gem 'omniauth-oauth2', '1.1.1'
+gem 'omniauth', '~> 1.1'
+gem 'omniauth-oauth2', '~> 1.1'
 
 gem 'andand'
 
@@ -78,7 +78,7 @@ gem 'arvados-cli', '>= 0.1.20151207150126'
 # pg_power lets us use partial indexes in schema.rb in Rails 3
 gem 'pg_power'
 
-gem 'puma'
+gem 'puma', '~> 2.0'
 gem 'sshkey'
 gem 'safe_yaml'
 gem 'lograge'
diff --git a/services/api/Gemfile.lock b/services/api/Gemfile.lock
index 1dfa92d..814aa14 100644
--- a/services/api/Gemfile.lock
+++ b/services/api/Gemfile.lock
@@ -28,26 +28,26 @@ GEM
     activesupport (3.2.22.5)
       i18n (~> 0.6, >= 0.6.4)
       multi_json (~> 1.0)
-    acts_as_api (0.4.2)
+    acts_as_api (0.4.3)
       activemodel (>= 3.0.0)
       activesupport (>= 3.0.0)
       rack (>= 1.1.0)
     addressable (2.4.0)
     andand (1.3.3)
     arel (3.0.3)
-    arvados (0.1.20160420143004)
+    arvados (0.1.20160513152536)
       activesupport (>= 3, < 4.2.6)
       andand (~> 1.3, >= 1.3.3)
-      google-api-client (>= 0.7, < 0.9)
+      google-api-client (>= 0.7, < 0.8.9)
       i18n (~> 0)
       json (~> 1.7, >= 1.7.7)
       jwt (>= 0.1.5, < 2)
-    arvados-cli (0.1.20160503204200)
+    arvados-cli (0.1.20160913140509)
       activesupport (~> 3.2, >= 3.2.13)
       andand (~> 1.3, >= 1.3.3)
       arvados (~> 0.1, >= 0.1.20150128223554)
       curb (~> 0.8)
-      google-api-client (~> 0.6, >= 0.6.3, < 0.9)
+      google-api-client (~> 0.6, >= 0.6.3, < 0.8.9)
       json (~> 1.7, >= 1.7.7)
       oj (~> 2.0, >= 2.0.3)
       trollop (~> 2.0)
@@ -56,61 +56,71 @@ GEM
       extlib (>= 0.9.15)
       multi_json (>= 1.0.0)
     builder (3.0.4)
-    capistrano (2.15.5)
+    capistrano (2.15.9)
       highline
       net-scp (>= 1.0.0)
       net-sftp (>= 2.0.0)
       net-ssh (>= 2.0.14)
       net-ssh-gateway (>= 1.1.0)
-    coffee-rails (3.2.1)
+    coffee-rails (3.2.2)
       coffee-script (>= 2.2.0)
-      railties (~> 3.2.0.beta)
-    coffee-script (2.2.0)
+      railties (~> 3.2.0)
+    coffee-script (2.4.1)
       coffee-script-source
       execjs
-    coffee-script-source (1.7.0)
+    coffee-script-source (1.10.0)
     curb (0.9.3)
-    database_cleaner (1.2.0)
+    database_cleaner (1.5.3)
     erubis (2.7.0)
     eventmachine (1.2.0.1)
-    execjs (2.0.2)
+    execjs (2.7.0)
     extlib (0.9.16)
-    factory_girl (4.4.0)
+    factory_girl (4.7.0)
       activesupport (>= 3.0.0)
-    factory_girl_rails (4.4.1)
-      factory_girl (~> 4.4.0)
+    factory_girl_rails (4.7.0)
+      factory_girl (~> 4.7.0)
       railties (>= 3.0.0)
     faraday (0.9.2)
       multipart-post (>= 1.2, < 3)
     faye-websocket (0.10.4)
       eventmachine (>= 0.12.0)
       websocket-driver (>= 0.5.1)
-    google-api-client (0.7.1)
-      addressable (>= 2.3.2)
-      autoparse (>= 0.3.3)
-      extlib (>= 0.9.15)
-      faraday (>= 0.9.0)
-      jwt (>= 0.1.5)
-      launchy (>= 2.1.1)
-      multi_json (>= 1.0.0)
-      retriable (>= 1.4)
-      signet (>= 0.5.0)
-      uuidtools (>= 2.1.0)
-    hashie (1.2.0)
-    highline (1.6.21)
+    google-api-client (0.8.7)
+      activesupport (>= 3.2, < 5.0)
+      addressable (~> 2.3)
+      autoparse (~> 0.3)
+      extlib (~> 0.9)
+      faraday (~> 0.9)
+      googleauth (~> 0.3)
+      launchy (~> 2.4)
+      multi_json (~> 1.10)
+      retriable (~> 1.4)
+      signet (~> 0.6)
+    googleauth (0.5.1)
+      faraday (~> 0.9)
+      jwt (~> 1.4)
+      logging (~> 2.0)
+      memoist (~> 0.12)
+      multi_json (~> 1.11)
+      os (~> 0.9)
+      signet (~> 0.7)
+    hashie (3.4.6)
+    highline (1.7.8)
     hike (1.2.3)
-    httpauth (0.2.1)
     i18n (0.7.0)
     journey (1.0.4)
-    jquery-rails (3.1.0)
+    jquery-rails (3.1.4)
       railties (>= 3.0, < 5.0)
       thor (>= 0.14, < 2.0)
     json (1.8.3)
-    jwt (0.1.13)
-      multi_json (>= 1.5)
+    jwt (1.5.6)
     launchy (2.4.3)
       addressable (~> 2.3)
-    libv8 (3.16.14.3)
+    libv8 (3.16.14.15)
+    little-plugger (1.1.4)
+    logging (2.1.0)
+      little-plugger (~> 1.1)
+      multi_json (~> 1.10)
     lograge (0.3.6)
       actionpack (>= 3)
       activesupport (>= 3)
@@ -119,32 +129,35 @@ GEM
     mail (2.5.4)
       mime-types (~> 1.16)
       treetop (~> 1.4.8)
+    memoist (0.15.0)
     metaclass (0.0.4)
     mime-types (1.25.1)
-    mocha (1.1.0)
+    mocha (1.2.0)
       metaclass (~> 0.0.1)
     multi_json (1.12.1)
+    multi_xml (0.5.5)
     multipart-post (2.0.0)
-    net-scp (1.2.0)
+    net-scp (1.2.1)
       net-ssh (>= 2.6.5)
     net-sftp (2.1.2)
       net-ssh (>= 2.6.5)
-    net-ssh (2.8.0)
+    net-ssh (3.2.0)
     net-ssh-gateway (1.2.0)
       net-ssh (>= 2.6.5)
-    oauth2 (0.8.1)
-      faraday (~> 0.8)
-      httpauth (~> 0.1)
-      jwt (~> 0.1.4)
-      multi_json (~> 1.0)
-      rack (~> 1.2)
+    oauth2 (1.2.0)
+      faraday (>= 0.8, < 0.10)
+      jwt (~> 1.0)
+      multi_json (~> 1.3)
+      multi_xml (~> 0.5)
+      rack (>= 1.2, < 3)
     oj (2.15.0)
-    omniauth (1.1.1)
-      hashie (~> 1.2)
-      rack
-    omniauth-oauth2 (1.1.1)
-      oauth2 (~> 0.8.0)
-      omniauth (~> 1.0)
+    omniauth (1.3.1)
+      hashie (>= 1.2, < 4)
+      rack (>= 1.0, < 3)
+    omniauth-oauth2 (1.4.0)
+      oauth2 (~> 1.0)
+      omniauth (~> 1.2)
+    os (0.9.6)
     passenger (5.0.30)
       rack
       rake (>= 0.8.1)
@@ -154,8 +167,7 @@ GEM
       rails (~> 3.1)
     polyglot (0.3.5)
     power_assert (0.3.1)
-    puma (2.8.2)
-      rack (>= 1.1, < 2.0)
+    puma (2.16.0)
     rack (1.4.7)
     rack-cache (1.6.1)
       rack (>= 0.4)
@@ -181,22 +193,22 @@ GEM
     rake (11.3.0)
     rdoc (3.12.2)
       json (~> 1.4)
-    ref (1.0.5)
-    retriable (2.1.0)
-    ruby-prof (0.15.2)
-    rvm-capistrano (1.5.1)
+    ref (2.0.0)
+    retriable (1.4.1)
+    ruby-prof (0.16.2)
+    rvm-capistrano (1.5.6)
       capistrano (~> 2.15.4)
     safe_yaml (1.0.4)
-    sass (3.3.4)
+    sass (3.4.22)
     sass-rails (3.2.6)
       railties (~> 3.2.0)
       sass (>= 3.1.10)
       tilt (~> 1.3)
-    signet (0.5.1)
-      addressable (>= 2.2.3)
-      faraday (>= 0.9.0.rc5)
-      jwt (>= 0.1.5)
-      multi_json (>= 1.0.0)
+    signet (0.7.3)
+      addressable (~> 2.3)
+      faraday (~> 0.9)
+      jwt (~> 1.5)
+      multi_json (~> 1.10)
     simplecov (0.7.1)
       multi_json (~> 1.0)
       simplecov-html (~> 0.7.1)
@@ -208,16 +220,17 @@ GEM
       multi_json (~> 1.0)
       rack (~> 1.0)
       tilt (~> 1.1, != 1.3.0)
-    sshkey (1.6.1)
+    sshkey (1.8.0)
     test-unit (3.2.1)
       power_assert
     test-unit-activesupport (1.0.6)
       activesupport
       test-unit
-    test_after_commit (0.2.3)
+    test_after_commit (1.1.0)
+      activerecord (>= 3.2)
     themes_for_rails (0.5.1)
       rails (>= 3.0.0)
-    therubyracer (0.12.1)
+    therubyracer (0.12.2)
       libv8 (~> 3.16.14.0)
       ref
     thor (0.19.1)
@@ -227,10 +240,9 @@ GEM
       polyglot (>= 0.3.1)
     trollop (2.1.2)
     tzinfo (0.3.51)
-    uglifier (2.5.0)
+    uglifier (2.7.2)
       execjs (>= 0.3.0)
       json (>= 1.8.0)
-    uuidtools (2.1.5)
     websocket-driver (0.6.4)
       websocket-extensions (>= 0.1.0)
     websocket-extensions (0.1.2)
@@ -243,7 +255,7 @@ DEPENDENCIES
   andand
   arvados (>= 0.1.20150615153458)
   arvados-cli (>= 0.1.20151207150126)
-  coffee-rails (~> 3.2.0)
+  coffee-rails (~> 3.2)
   database_cleaner
   factory_girl_rails
   faye-websocket
@@ -253,17 +265,17 @@ DEPENDENCIES
   mocha
   multi_json
   oj
-  omniauth (= 1.1.1)
-  omniauth-oauth2 (= 1.1.1)
+  omniauth (~> 1.1)
+  omniauth-oauth2 (~> 1.1)
   passenger
   pg
   pg_power
-  puma
-  rails (~> 3.2.0)
+  puma (~> 2.0)
+  rails (~> 3.2)
   ruby-prof
   rvm-capistrano
   safe_yaml
-  sass-rails (>= 3.2.0)
+  sass-rails (~> 3.2)
   simplecov (~> 0.7.1)
   simplecov-rcov
   sshkey
@@ -273,7 +285,7 @@ DEPENDENCIES
   themes_for_rails
   therubyracer
   trollop
-  uglifier (>= 1.0.3)
+  uglifier (~> 2.0)
 
 BUNDLED WITH
    1.13.2

commit 0b228d13b944b4b94165bf22a8f796070bd711bf
Author: Tom Clegg <tom at curoverse.com>
Date:   Tue Oct 11 02:09:00 2016 -0400

    5737: Fix passenger 502: wait for handshake to finish before closing websocket
    
    [ 2016-10-11 01:51:39.7674 8677/7f00771ec700 age/Cor/Con/InternalUtils.cpp:112 ]: [Client 1-1] Sending 502 response: application did not send a complete response

diff --git a/services/api/lib/eventbus.rb b/services/api/lib/eventbus.rb
index 4f5327c..cb65c7f 100644
--- a/services/api/lib/eventbus.rb
+++ b/services/api/lib/eventbus.rb
@@ -246,7 +246,12 @@ class EventBus
     # current_user is included from CurrentApiClient
     if not current_user
       send_message(ws, {status: 401, message: "Valid API token required"})
-      ws.close
+      # Wait for the handshake to complete before closing the
+      # socket. Otherwise, nginx responds with HTTP 502 Bad gateway,
+      # and the client never sees our real error message.
+      ws.on :open do |event|
+        ws.close
+      end
       return
     end
 

commit 014f72fcdac2b26f9f2bbf257707eb59c676eebb
Author: Tom Clegg <tom at curoverse.com>
Date:   Tue Oct 11 01:48:38 2016 -0400

    5737: Send passenger logs to console
    
    (instead of accumulating services/api/log/passenger.{port}.log files)

diff --git a/services/api/test/integration/websocket_test.rb b/services/api/test/integration/websocket_test.rb
index 2f950a3..2128be9 100644
--- a/services/api/test/integration/websocket_test.rb
+++ b/services/api/test/integration/websocket_test.rb
@@ -24,7 +24,9 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     Dir.chdir(Rails.root) do |apidir|
       # Only passenger seems to be able to run the websockets server
       # successfully.
-      _system('passenger', 'start', '-d', "-p#{@@port}")
+      _system('passenger', 'start', '-d',
+              "-p#{@@port}",
+              "--log-file", "/dev/stderr")
       timeout = Time.now.tv_sec + 10
       begin
         sleep 0.2

commit 1671eb078bc4d254ebdfe5ac8dd40c83b371e8ac
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 21:37:02 2016 -0400

    5737: Fix accidental use of local variable instead of intended instance method

diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index 2de6285..1c3a29a 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -204,7 +204,7 @@ class Collection < ArvadosModel
         utf8 = manifest_text
         utf8.force_encoding Encoding::UTF_8
         if utf8.valid_encoding? and utf8 == manifest_text.encode(Encoding::UTF_8)
-          manifest_text = utf8
+          self.manifest_text = utf8
           return true
         end
       rescue
diff --git a/services/api/app/models/job.rb b/services/api/app/models/job.rb
index f2bd751..ef3d0b5 100644
--- a/services/api/app/models/job.rb
+++ b/services/api/app/models/job.rb
@@ -340,7 +340,7 @@ class Job < ArvadosModel
         assign_uuid
         Commit.tag_in_internal_repository repository, script_version, uuid
       rescue
-        uuid = uuid_was
+        self.uuid = uuid_was
         raise
       end
     end

commit 554350245276ee082417cdcfcb8fd3f4f593e00f
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 20:10:02 2016 -0400

    5737: Tweak websocket tests

diff --git a/services/api/Gemfile.lock b/services/api/Gemfile.lock
index 0eff952..1dfa92d 100644
--- a/services/api/Gemfile.lock
+++ b/services/api/Gemfile.lock
@@ -82,9 +82,9 @@ GEM
       railties (>= 3.0.0)
     faraday (0.9.2)
       multipart-post (>= 1.2, < 3)
-    faye-websocket (0.7.2)
+    faye-websocket (0.10.4)
       eventmachine (>= 0.12.0)
-      websocket-driver (>= 0.3.1)
+      websocket-driver (>= 0.5.1)
     google-api-client (0.7.1)
       addressable (>= 2.3.2)
       autoparse (>= 0.3.3)
@@ -231,7 +231,9 @@ GEM
       execjs (>= 0.3.0)
       json (>= 1.8.0)
     uuidtools (2.1.5)
-    websocket-driver (0.3.2)
+    websocket-driver (0.6.4)
+      websocket-extensions (>= 0.1.0)
+    websocket-extensions (0.1.2)
 
 PLATFORMS
   ruby
diff --git a/services/api/lib/eventbus.rb b/services/api/lib/eventbus.rb
index 16bb030..4f5327c 100644
--- a/services/api/lib/eventbus.rb
+++ b/services/api/lib/eventbus.rb
@@ -78,6 +78,10 @@ class EventBus
     @connection_count = 0
   end
 
+  def send_message(ws, obj)
+    ws.send(Oj.dump(obj, mode: :compat))
+  end
+
   # Push out any pending events to the connection +ws+
   # +notify_id+  the id of the most recent row in the log table, may be nil
   #
@@ -146,7 +150,7 @@ class EventBus
         logs.select('logs.id').find_each do |l|
           if not ws.sent_ids.include?(l.id)
             # only send if not a duplicate
-            ws.send(Log.find(l.id).as_api_response.to_json)
+            send_message(ws, Log.find(l.id).as_api_response)
           end
           if not ws.last_log_id.nil?
             # record ids only when sending "catchup" messages, not notifies
@@ -158,12 +162,12 @@ class EventBus
     rescue ArgumentError => e
       # There was some kind of user error.
       Rails.logger.warn "Error publishing event: #{$!}"
-      ws.send ({status: 500, message: $!}.to_json)
+      send_message(ws, {status: 500, message: $!})
       ws.close
     rescue => e
       Rails.logger.warn "Error publishing event: #{$!}"
       Rails.logger.warn "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
-      ws.send ({status: 500, message: $!}.to_json)
+      send_message(ws, {status: 500, message: $!})
       ws.close
       # These exceptions typically indicate serious server trouble:
       # out of memory issues, database connection problems, etc.  Go ahead and
@@ -180,7 +184,7 @@ class EventBus
         p = (Oj.strict_load event.data).symbolize_keys
         filter = Filter.new(p)
       rescue Oj::Error => e
-        ws.send ({status: 400, message: "malformed request"}.to_json)
+        send_message(ws, {status: 400, message: "malformed request"})
         return
       end
 
@@ -200,12 +204,12 @@ class EventBus
           # Add a filter.  This gets the :filters field which is the same
           # format as used for regular index queries.
           ws.filters << filter
-          ws.send ({status: 200, message: 'subscribe ok', filter: p}.to_json)
+          send_message(ws, {status: 200, message: 'subscribe ok', filter: p})
 
           # Send any pending events
           push_events ws, nil
         else
-          ws.send ({status: 403, message: "maximum of #{Rails.configuration.websocket_max_filters} filters allowed per connection"}.to_json)
+          send_message(ws, {status: 403, message: "maximum of #{Rails.configuration.websocket_max_filters} filters allowed per connection"})
         end
 
       elsif p[:method] == 'unsubscribe'
@@ -214,18 +218,18 @@ class EventBus
         len = ws.filters.length
         ws.filters.select! { |f| not ((f.filters == p[:filters]) or (f.filters.empty? and p[:filters].nil?)) }
         if ws.filters.length < len
-          ws.send ({status: 200, message: 'unsubscribe ok'}.to_json)
+          send_message(ws, {status: 200, message: 'unsubscribe ok'})
         else
-          ws.send ({status: 404, message: 'filter not found'}.to_json)
+          send_message(ws, {status: 404, message: 'filter not found'})
         end
 
       else
-        ws.send ({status: 400, message: "missing or unrecognized method"}.to_json)
+        send_message(ws, {status: 400, message: "missing or unrecognized method"})
       end
     rescue => e
       Rails.logger.warn "Error handling message: #{$!}"
       Rails.logger.warn "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
-      ws.send ({status: 500, message: 'error'}.to_json)
+      send_message(ws, {status: 500, message: 'error'})
       ws.close
     end
   end
@@ -241,7 +245,7 @@ class EventBus
     # Disconnect if no valid API token.
     # current_user is included from CurrentApiClient
     if not current_user
-      ws.send ({status: 401, message: "Valid API token required"}.to_json)
+      send_message(ws, {status: 401, message: "Valid API token required"})
       ws.close
       return
     end
@@ -262,7 +266,7 @@ class EventBus
     # forward them to the thread associated with the connection.
     sub = @channel.subscribe do |msg|
       if ws.queue.length > Rails.configuration.websocket_max_notify_backlog
-        ws.send ({status: 500, message: 'Notify backlog too long'}.to_json)
+        send_message(ws, {status: 500, message: 'Notify backlog too long'})
         ws.close
         @channel.unsubscribe sub
         ws.queue.clear
diff --git a/services/api/test/integration/websocket_test.rb b/services/api/test/integration/websocket_test.rb
index 198ea71..2f950a3 100644
--- a/services/api/test/integration/websocket_test.rb
+++ b/services/api/test/integration/websocket_test.rb
@@ -20,6 +20,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     @@port = s.addr[1]
     s.close
     pidfile = "tmp/pids/passenger.#{@@port}.pid"
+    DatabaseCleaner.start
     Dir.chdir(Rails.root) do |apidir|
       # Only passenger seems to be able to run the websockets server
       # successfully.
@@ -37,7 +38,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
       if not good_pid
         raise RuntimeError, "could not find API server Rails pid"
       end
-      STDERR.puts "Started websocket server on @@port #{@@port} with pid #{server_pid}"
+      STDERR.puts "Started websocket server on port #{@@port} with pid #{server_pid}"
     end
   end
 
@@ -63,7 +64,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     end
   end
 
-  def ws_helper (token = nil, timeout = true)
+  def ws_helper(token: nil, timeout: 8)
     opened = false
     close_status = nil
     too_long = false
@@ -78,13 +79,17 @@ class WebsocketTest < ActionDispatch::IntegrationTest
       ws.on :open do |event|
         opened = true
         if timeout
-          EM::Timer.new 8 do
+          EM::Timer.new(timeout) do
             too_long = true if close_status.nil?
             EM.stop_event_loop
           end
         end
       end
 
+      ws.on :error do |event|
+        STDERR.puts "websocket client error: #{event.inspect}"
+      end
+
       ws.on :close do |event|
         close_status = [:close, event.code, event.reason]
         EM.stop_event_loop
@@ -112,11 +117,10 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     assert_equal 401, status
   end
 
-
   test "connect, subscribe and get response" do
     status = nil
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
       end
@@ -138,7 +142,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
       end
@@ -175,7 +179,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
       end
@@ -215,7 +219,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
       end
@@ -253,7 +257,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
         ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#specimen']]}.to_json)
@@ -298,7 +302,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#trait'], ['event_type', '=', 'update']]}.to_json)
       end
@@ -338,7 +342,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     l1 = nil
     l2 = nil
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe', last_log_id: lastid}.to_json)
       end
@@ -378,7 +382,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active, false do |ws|
+    ws_helper(token: :active, timeout: false) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
         EM::Timer.new 3 do
@@ -427,7 +431,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active, false do |ws|
+    ws_helper(token: :active, timeout: false) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
         EM::Timer.new 6 do
@@ -479,7 +483,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
       end
@@ -526,7 +530,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     slow_test
     authorize_with :active
 
-    ws_helper :active, false do |ws|
+    ws_helper(token: :active, timeout: false) do |ws|
       ws.on :open do |event|
         EM::Timer.new 1 do
           Specimen.create
@@ -549,7 +553,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :admin
 
-    ws_helper :active, false do |ws|
+    ws_helper(token: :active, timeout: false) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
 
@@ -577,7 +581,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
   test "connect, try bogus method" do
     status = nil
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'frobnabble'}.to_json)
       end
@@ -595,7 +599,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
   test "connect, missing method" do
     status = nil
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({fizzbuzz: 'frobnabble'}.to_json)
       end
@@ -613,7 +617,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
   test "connect, send malformed request" do
     status = nil
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send '<XML4EVER></XML4EVER>'
       end
@@ -634,7 +638,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         (1..17).each do |i|
           ws.send ({method: 'subscribe', filters: [['object_uuid', '=', i]]}.to_json)
@@ -667,7 +671,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active, false do |ws|
+    ws_helper(token: :active, timeout: false) do |ws|
       EM::Timer.new 45 do
         # Needs a longer timeout than the default
         ws.close
@@ -710,7 +714,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         # test that #6451 is fixed (invalid filter crashes websockets)
         ws.send ({method: 'subscribe', filters: [['object_blarg', 'is_a', 'arvados#human']]}.to_json)

commit c2f6922a1997ca73d46866f03474a23c76c7afa5
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 17:39:58 2016 -0400

    5737: Fix test so call counts are as expected

diff --git a/services/api/test/unit/app_version_test.rb b/services/api/test/unit/app_version_test.rb
index 4718ac2..2e58505 100644
--- a/services/api/test/unit/app_version_test.rb
+++ b/services/api/test/unit/app_version_test.rb
@@ -20,9 +20,12 @@ class AppVersionTest < ActiveSupport::TestCase
     end
   end
 
-  test 'override with configuration' do
+  test 'override with configuration "foobar"' do
     Rails.configuration.source_version = 'foobar'
     assert_equal 'foobar', AppVersion.hash
+  end
+
+  test 'override with configuration false' do
     Rails.configuration.source_version = false
     assert_not_equal 'foobar', AppVersion.hash
   end

commit 450cf2524ff41b2a0fcea09e2e6ccbf3bdbf78ed
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 16:35:49 2016 -0400

    5737: Fix some ruby warnings

diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index 672374b..fe6833c 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -239,7 +239,7 @@ class ArvadosModel < ActiveRecord::Base
   end
 
   def logged_attributes
-    attributes.except *Rails.configuration.unlogged_attributes
+    attributes.except(*Rails.configuration.unlogged_attributes)
   end
 
   def self.full_text_searchable_columns
@@ -490,7 +490,7 @@ class ArvadosModel < ActiveRecord::Base
   end
 
   def foreign_key_attributes
-    attributes.keys.select { |a| a.match /_uuid$/ }
+    attributes.keys.select { |a| a.match(/_uuid$/) }
   end
 
   def skip_uuid_read_permission_check
@@ -505,7 +505,7 @@ class ArvadosModel < ActiveRecord::Base
     foreign_key_attributes.each do |attr|
       attr_value = send attr
       if attr_value.is_a? String and
-          attr_value.match /^[0-9a-f]{32,}(\+[@\w]+)*$/
+          attr_value.match(/^[0-9a-f]{32,}(\+[@\w]+)*$/)
         begin
           send "#{attr}=", Collection.normalize_uuid(attr_value)
         rescue
@@ -584,13 +584,12 @@ class ArvadosModel < ActiveRecord::Base
     unless uuid.is_a? String
       return nil
     end
-    resource_class = nil
 
     uuid.match HasUuid::UUID_REGEX do |re|
       return uuid_prefixes[re[1]] if uuid_prefixes[re[1]]
     end
 
-    if uuid.match /.+ at .+/
+    if uuid.match(/.+ at .+/)
       return Email
     end
 
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index 98b29f4..2de6285 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -32,6 +32,11 @@ class Collection < ArvadosModel
     t.add :expires_at
   end
 
+  after_initialize do
+    @signatures_checked = false
+    @computed_pdh_for_manifest_text = false
+  end
+
   def self.attributes_required_columns
     super.merge(
                 # If we don't list manifest_text explicitly, the
@@ -50,18 +55,6 @@ class Collection < ArvadosModel
     super + ["updated_at", "file_names"]
   end
 
-  def initialize(*args)
-    super
-    @signatures_checked = false
-    @computed_pdh_for_manifest_text = false
-  end
-
-  def initialize_copy(*args)
-    super
-    @signatures_checked = false
-    @computed_pdh_for_manifest_text = false
-  end
-
   FILE_TOKEN = /^[[:digit:]]+:[[:digit:]]+:/
   def check_signatures
     return false if self.manifest_text.nil?
@@ -297,10 +290,10 @@ class Collection < ArvadosModel
     hash_part = nil
     size_part = nil
     uuid.split('+').each do |token|
-      if token.match /^[0-9a-f]{32,}$/
+      if token.match(/^[0-9a-f]{32,}$/)
         raise "uuid #{uuid} has multiple hash parts" if hash_part
         hash_part = token
-      elsif token.match /^\d+$/
+      elsif token.match(/^\d+$/)
         raise "uuid #{uuid} has multiple size parts" if size_part
         size_part = token
       end
diff --git a/services/api/app/models/commit_ancestor.rb b/services/api/app/models/commit_ancestor.rb
index 71ea57f..419eca2 100644
--- a/services/api/app/models/commit_ancestor.rb
+++ b/services/api/app/models/commit_ancestor.rb
@@ -16,13 +16,13 @@ class CommitAncestor < ActiveRecord::Base
     @gitdirbase = Rails.configuration.git_repositories_dir
     self.is = nil
     Dir.foreach @gitdirbase do |repo|
-      next if repo.match /^\./
+      next if repo.match(/^\./)
       git_dir = repo.match(/\.git$/) ? repo : File.join(repo, '.git')
       repo_name = repo.sub(/\.git$/, '')
       ENV['GIT_DIR'] = File.join(@gitdirbase, git_dir)
-      IO.foreach("|git rev-list --format=oneline '#{self.descendant.gsub /[^0-9a-f]/,""}'") do |line|
+      IO.foreach("|git rev-list --format=oneline '#{self.descendant.gsub(/[^0-9a-f]/,"")}'") do |line|
         self.is = false
-        sha1, message = line.strip.split(" ", 2)
+        sha1, _ = line.strip.split(" ", 2)
         if sha1 == self.ancestor
           self.is = true
           break
diff --git a/services/api/app/models/job.rb b/services/api/app/models/job.rb
index a75af86..f2bd751 100644
--- a/services/api/app/models/job.rb
+++ b/services/api/app/models/job.rb
@@ -67,8 +67,7 @@ class Job < ArvadosModel
             (Complete = 'Complete'),
            ]
 
-  def initialize(*args)
-    super
+  after_initialize do
     @need_crunch_dispatch_trigger = false
   end
 
diff --git a/services/api/app/models/link.rb b/services/api/app/models/link.rb
index 24872b2..649a6f8 100644
--- a/services/api/app/models/link.rb
+++ b/services/api/app/models/link.rb
@@ -8,7 +8,6 @@ class Link < ArvadosModel
   after_update :maybe_invalidate_permissions_cache
   after_create :maybe_invalidate_permissions_cache
   after_destroy :maybe_invalidate_permissions_cache
-  attr_accessor :head_kind, :tail_kind
   validate :name_links_are_obsolete
 
   api_accessible :user, extend: :common do |t|
diff --git a/services/api/app/models/log.rb b/services/api/app/models/log.rb
index f8d624a..df80ea5 100644
--- a/services/api/app/models/log.rb
+++ b/services/api/app/models/log.rb
@@ -4,7 +4,6 @@ class Log < ArvadosModel
   include CommonApiTemplate
   serialize :properties, Hash
   before_validation :set_default_event_at
-  attr_accessor :object, :object_kind
   after_save :send_notify
 
   api_accessible :user, extend: :common do |t|
diff --git a/services/api/app/models/node.rb b/services/api/app/models/node.rb
index f92c78b..c16e59a 100644
--- a/services/api/app/models/node.rb
+++ b/services/api/app/models/node.rb
@@ -30,8 +30,7 @@ class Node < ArvadosModel
     t.add lambda { |x| Rails.configuration.compute_node_nameservers }, :as => :nameservers
   end
 
-  def initialize(*args)
-    super
+  after_initialize do
     @bypass_arvados_authorization = false
   end
 
@@ -227,7 +226,7 @@ class Node < ArvadosModel
     (0..Rails.configuration.max_compute_nodes-1).each do |slot_number|
       hostname = hostname_for_slot(slot_number)
       hostfile = File.join Rails.configuration.dns_server_conf_dir, "#{hostname}.conf"
-      if !File.exists? hostfile
+      if !File.exist? hostfile
         n = Node.where(:slot_number => slot_number).first
         if n.nil? or n.ip_address.nil?
           dns_server_update(hostname, '127.40.4.0')
diff --git a/services/api/app/models/repository.rb b/services/api/app/models/repository.rb
index f361a49..13b00df 100644
--- a/services/api/app/models/repository.rb
+++ b/services/api/app/models/repository.rb
@@ -86,7 +86,7 @@ class Repository < ArvadosModel
       prefix_match = Regexp.escape(owner.username + "/")
       errmsg_start = "must be the owner's username, then '/', then"
     end
-    if not /^#{prefix_match}[A-Za-z][A-Za-z0-9]*$/.match(name)
+    if not (/^#{prefix_match}[A-Za-z][A-Za-z0-9]*$/.match(name))
       errors.add(:name,
                  "#{errmsg_start} a letter followed by alphanumerics")
       false
diff --git a/services/api/app/models/user.rb b/services/api/app/models/user.rb
index 18d33a6..28b9a26 100644
--- a/services/api/app/models/user.rb
+++ b/services/api/app/models/user.rb
@@ -64,7 +64,7 @@ class User < ArvadosModel
   def is_invited
     !!(self.is_active ||
        Rails.configuration.new_users_are_active ||
-       self.groups_i_can(:read).select { |x| x.match /-f+$/ }.first)
+       self.groups_i_can(:read).select { |x| x.match(/-f+$/) }.first)
   end
 
   def groups_i_can(verb)
@@ -242,7 +242,7 @@ class User < ArvadosModel
 
     # delete "All users" group read permissions for this user
     group = Group.where(name: 'All users').select do |g|
-      g[:uuid].match /-f+$/
+      g[:uuid].match(/-f+$/)
     end.first
     Link.destroy_all(tail_uuid: self.uuid,
                      head_uuid: group[:uuid],
diff --git a/services/api/config/boot.rb b/services/api/config/boot.rb
index 4489e58..f2830ae 100644
--- a/services/api/config/boot.rb
+++ b/services/api/config/boot.rb
@@ -3,4 +3,4 @@ require 'rubygems'
 # Set up gems listed in the Gemfile.
 ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
 
-require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
+require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
diff --git a/services/api/config/initializers/inflections.rb b/services/api/config/initializers/inflections.rb
index 79bca3a..b6dadf7 100644
--- a/services/api/config/initializers/inflections.rb
+++ b/services/api/config/initializers/inflections.rb
@@ -10,8 +10,8 @@
 # end
 
 ActiveSupport::Inflector.inflections do |inflect|
-  inflect.plural /^([Ss]pecimen)$/i, '\1s'
-  inflect.singular /^([Ss]pecimen)s?/i, '\1'
-  inflect.plural /^([Hh]uman)$/i, '\1s'
-  inflect.singular /^([Hh]uman)s?/i, '\1'
+  inflect.plural(/^([Ss]pecimen)$/i, '\1s')
+  inflect.singular(/^([Ss]pecimen)s?/i, '\1')
+  inflect.plural(/^([Hh]uman)$/i, '\1s')
+  inflect.singular(/^([Hh]uman)s?/i, '\1')
 end
diff --git a/services/api/config/initializers/load_config.rb b/services/api/config/initializers/load_config.rb
index 76234d3..fd3c977 100644
--- a/services/api/config/initializers/load_config.rb
+++ b/services/api/config/initializers/load_config.rb
@@ -6,7 +6,7 @@ rescue LoadError
   # configured by application.yml (i.e., here!) instead.
 end
 
-if (File.exists?(File.expand_path '../omniauth.rb', __FILE__) and
+if (File.exist?(File.expand_path '../omniauth.rb', __FILE__) and
     not defined? WARNED_OMNIAUTH_CONFIG)
   Rails.logger.warn <<-EOS
 DEPRECATED CONFIGURATION:
@@ -26,7 +26,7 @@ $application_config = {}
 
 %w(application.default application).each do |cfgfile|
   path = "#{::Rails.root.to_s}/config/#{cfgfile}.yml"
-  if File.exists? path
+  if File.exist? path
     yaml = ERB.new(IO.read path).result(binding)
     confs = YAML.load(yaml, deserialize_symbols: true)
     # Ignore empty YAML file:
diff --git a/services/api/lib/crunch_dispatch.rb b/services/api/lib/crunch_dispatch.rb
index ce94f73..83cd1b9 100644
--- a/services/api/lib/crunch_dispatch.rb
+++ b/services/api/lib/crunch_dispatch.rb
@@ -27,7 +27,7 @@ class CrunchDispatch
     @cgroup_root = ENV['CRUNCH_CGROUP_ROOT']
 
     @arvados_internal = Rails.configuration.git_internal_dir
-    if not File.exists? @arvados_internal
+    if not File.exist? @arvados_internal
       $stderr.puts `mkdir -p #{@arvados_internal.shellescape} && git init --bare #{@arvados_internal.shellescape}`
       raise "No internal git repository available" unless ($? == 0)
     end
diff --git a/services/api/lib/current_api_client.rb b/services/api/lib/current_api_client.rb
index 1d7dc41..97348d5 100644
--- a/services/api/lib/current_api_client.rb
+++ b/services/api/lib/current_api_client.rb
@@ -91,9 +91,7 @@ module CurrentApiClient
             User.all.collect(&:uuid).each do |user_uuid|
               Link.create!(link_class: 'permission',
                            name: 'can_manage',
-                           tail_kind: 'arvados#group',
                            tail_uuid: system_group_uuid,
-                           head_kind: 'arvados#user',
                            head_uuid: user_uuid)
             end
           end
diff --git a/services/api/lib/load_param.rb b/services/api/lib/load_param.rb
index 5b22274..3bab33f 100644
--- a/services/api/lib/load_param.rb
+++ b/services/api/lib/load_param.rb
@@ -92,11 +92,11 @@ module LoadParam
         # has used set_table_name to use an alternate table name from the Rails standard.
         # I could not find a perfect way to handle this well, but ActiveRecord::Base.send(:descendants)
         # would be a place to start if this ever becomes necessary.
-        if attr.match /^[a-z][_a-z0-9]+$/ and
+        if attr.match(/^[a-z][_a-z0-9]+$/) and
             model_class.columns.collect(&:name).index(attr) and
             ['asc','desc'].index direction.downcase
           @orders << "#{table_name}.#{attr} #{direction.downcase}"
-        elsif attr.match /^([a-z][_a-z0-9]+)\.([a-z][_a-z0-9]+)$/ and
+        elsif attr.match(/^([a-z][_a-z0-9]+)\.([a-z][_a-z0-9]+)$/) and
             ['asc','desc'].index(direction.downcase) and
             ActiveRecord::Base.connection.tables.include?($1) and
             $1.classify.constantize.columns.collect(&:name).index($2)
diff --git a/services/api/script/arvados-git-sync.rb b/services/api/script/arvados-git-sync.rb
index 3a8ed27..b785534 100755
--- a/services/api/script/arvados-git-sync.rb
+++ b/services/api/script/arvados-git-sync.rb
@@ -22,7 +22,7 @@ DEBUG = 1
 # load and merge in the environment-specific application config info
 # if present, overriding base config parameters as specified
 path = File.absolute_path('../../config/arvados-clients.yml', __FILE__)
-if File.exists?(path) then
+if File.exist?(path) then
   cp_config = YAML.load_file(path)[ENV['RAILS_ENV']]
 else
   puts "Please create a\n #{path}\n file"
@@ -214,7 +214,7 @@ end
 
 begin
   # Get our local gitolite-admin repo up to snuff
-  if not File.exists?(gitolite_admin) then
+  if not File.exist?(gitolite_admin) then
     ensure_directory(gitolite_tmpdir, 0700)
     Dir.chdir(gitolite_tmpdir)
     `git clone #{gitolite_url}`
diff --git a/services/api/script/migrate-gitolite-to-uuid-storage.rb b/services/api/script/migrate-gitolite-to-uuid-storage.rb
index 8db1a0e..169509f 100755
--- a/services/api/script/migrate-gitolite-to-uuid-storage.rb
+++ b/services/api/script/migrate-gitolite-to-uuid-storage.rb
@@ -35,7 +35,7 @@ DEBUG = 1
 # load and merge in the environment-specific application config info
 # if present, overriding base config parameters as specified
 path = File.dirname(__FILE__) + '/config/arvados-clients.yml'
-if File.exists?(path) then
+if File.exist?(path) then
   cp_config = YAML.load_file(path)[ENV['RAILS_ENV']]
 else
   puts "Please create a\n " + File.dirname(__FILE__) + "/config/arvados-clients.yml\n file"
@@ -186,7 +186,7 @@ end
 
 begin
   # Get our local gitolite-admin repo up to snuff
-  if not File.exists?(gitolite_admin) then
+  if not File.exist?(gitolite_admin) then
     ensure_directory(gitolite_tmpdir, 0700)
     Dir.chdir(gitolite_tmpdir)
     `git clone #{gitolite_url}`
diff --git a/services/api/test/functional/arvados/v1/jobs_controller_test.rb b/services/api/test/functional/arvados/v1/jobs_controller_test.rb
index b84c93d..9a0aa50 100644
--- a/services/api/test/functional/arvados/v1/jobs_controller_test.rb
+++ b/services/api/test/functional/arvados/v1/jobs_controller_test.rb
@@ -97,7 +97,7 @@ class Arvados::V1::JobsControllerTest < ActionController::TestCase
                  'server should correct bogus cancelled_at ' +
                  job['cancelled_at'])
     assert_equal(true,
-                 File.exists?(Rails.configuration.crunch_refresh_trigger),
+                 File.exist?(Rails.configuration.crunch_refresh_trigger),
                  'trigger file should be created when job is cancelled')
   end
 
diff --git a/services/api/test/unit/app_version_test.rb b/services/api/test/unit/app_version_test.rb
index 3e9b167..4718ac2 100644
--- a/services/api/test/unit/app_version_test.rb
+++ b/services/api/test/unit/app_version_test.rb
@@ -29,7 +29,7 @@ class AppVersionTest < ActiveSupport::TestCase
 
   test 'override with file' do
     path = Rails.root.join 'git-commit.version'
-    assert(!File.exists?(path),
+    assert(!File.exist?(path),
            "Packaged version file found in source tree: #{path}")
     begin
       File.open(path, 'w') do |f|
diff --git a/services/api/test/unit/commit_test.rb b/services/api/test/unit/commit_test.rb
index b57c23b..301e071 100644
--- a/services/api/test/unit/commit_test.rb
+++ b/services/api/test/unit/commit_test.rb
@@ -183,34 +183,34 @@ class CommitTest < ActiveSupport::TestCase
     Dir.mktmpdir do |touchdir|
       # invalid input to maximum
       a = Commit.find_commit_range('active/foo', nil, "31ce37fe365b3dc204300a3e4c396ad333ed0556 ; touch #{touchdir}/uh_oh", nil)
-      assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'maximum' parameter of find_commit_range is exploitable"
+      assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'maximum' parameter of find_commit_range is exploitable"
       assert_equal [], a
 
       # invalid input to maximum
       a = Commit.find_commit_range('active/foo', nil, "$(uname>#{touchdir}/uh_oh)", nil)
-      assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'maximum' parameter of find_commit_range is exploitable"
+      assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'maximum' parameter of find_commit_range is exploitable"
       assert_equal [], a
 
       # invalid input to minimum
       a = Commit.find_commit_range('active/foo', "31ce37fe365b3dc204300a3e4c396ad333ed0556 ; touch #{touchdir}/uh_oh", "31ce37fe365b3dc204300a3e4c396ad333ed0556", nil)
-      assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'minimum' parameter of find_commit_range is exploitable"
+      assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'minimum' parameter of find_commit_range is exploitable"
       assert_equal [], a
 
       # invalid input to minimum
       a = Commit.find_commit_range('active/foo', "$(uname>#{touchdir}/uh_oh)", "31ce37fe365b3dc204300a3e4c396ad333ed0556", nil)
-      assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'minimum' parameter of find_commit_range is exploitable"
+      assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'minimum' parameter of find_commit_range is exploitable"
       assert_equal [], a
 
       # invalid input to 'excludes'
       # complains "fatal: bad object 077ba2ad3ea24a929091a9e6ce545c93199b8e57"
       a = Commit.find_commit_range('active/foo', "31ce37fe365b3dc204300a3e4c396ad333ed0556", "077ba2ad3ea24a929091a9e6ce545c93199b8e57", ["4fe459abe02d9b365932b8f5dc419439ab4e2577 ; touch #{touchdir}/uh_oh"])
-      assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'excludes' parameter of find_commit_range is exploitable"
+      assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'excludes' parameter of find_commit_range is exploitable"
       assert_equal [], a
 
       # invalid input to 'excludes'
       # complains "fatal: bad object 077ba2ad3ea24a929091a9e6ce545c93199b8e57"
       a = Commit.find_commit_range('active/foo', "31ce37fe365b3dc204300a3e4c396ad333ed0556", "077ba2ad3ea24a929091a9e6ce545c93199b8e57", ["$(uname>#{touchdir}/uh_oh)"])
-      assert !File.exists?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'excludes' parameter of find_commit_range is exploitable"
+      assert !File.exist?("#{touchdir}/uh_oh"), "#{touchdir}/uh_oh should not exist, 'excludes' parameter of find_commit_range is exploitable"
       assert_equal [], a
     end
   end

commit c632b87902785c4bbc5242b095e53bcf657f6aae
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 16:25:48 2016 -0400

    5737: Update httpclient gem

diff --git a/apps/workbench/Gemfile.lock b/apps/workbench/Gemfile.lock
index a8431a7..11f32d6 100644
--- a/apps/workbench/Gemfile.lock
+++ b/apps/workbench/Gemfile.lock
@@ -123,7 +123,7 @@ GEM
       signet (~> 0.7)
     headless (1.0.2)
     highline (1.6.21)
-    httpclient (2.6.0.1)
+    httpclient (2.8.2.4)
     i18n (0.7.0)
     jquery-rails (3.1.2)
       railties (>= 3.0, < 5.0)
@@ -320,4 +320,4 @@ DEPENDENCIES
   wiselinks
 
 BUNDLED WITH
-   1.12.1
+   1.13.2

commit 61925eaac13ef601879178d6343de9f9714f3da1
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 16:19:25 2016 -0400

    5737: Use test-unit-activesupport gem. Fixes "omit".

diff --git a/services/api/Gemfile b/services/api/Gemfile
index 77605aa..546f816 100644
--- a/services/api/Gemfile
+++ b/services/api/Gemfile
@@ -9,7 +9,8 @@ group :test, :development do
   gem 'factory_girl_rails'
   gem 'database_cleaner'
   gem 'ruby-prof'
-  gem 'test-unit', '~> 3.0'
+  gem 'test-unit', require: false
+  gem 'test-unit-activesupport', require: false
   # Note: "require: false" here tells bunder not to automatically
   # 'require' the packages during application startup. Installation is
   # still mandatory.
diff --git a/services/api/Gemfile.lock b/services/api/Gemfile.lock
index c02cbd1..0eff952 100644
--- a/services/api/Gemfile.lock
+++ b/services/api/Gemfile.lock
@@ -153,7 +153,7 @@ GEM
       pg
       rails (~> 3.1)
     polyglot (0.3.5)
-    power_assert (0.2.6)
+    power_assert (0.3.1)
     puma (2.8.2)
       rack (>= 1.1, < 2.0)
     rack (1.4.7)
@@ -209,8 +209,11 @@ GEM
       rack (~> 1.0)
       tilt (~> 1.1, != 1.3.0)
     sshkey (1.6.1)
-    test-unit (3.1.5)
+    test-unit (3.2.1)
       power_assert
+    test-unit-activesupport (1.0.6)
+      activesupport
+      test-unit
     test_after_commit (0.2.3)
     themes_for_rails (0.5.1)
       rails (>= 3.0.0)
@@ -262,7 +265,8 @@ DEPENDENCIES
   simplecov (~> 0.7.1)
   simplecov-rcov
   sshkey
-  test-unit (~> 3.0)
+  test-unit
+  test-unit-activesupport
   test_after_commit
   themes_for_rails
   therubyracer
diff --git a/services/api/test/test_helper.rb b/services/api/test/test_helper.rb
index f35b5fc..2986f69 100644
--- a/services/api/test/test_helper.rb
+++ b/services/api/test/test_helper.rb
@@ -21,8 +21,9 @@ unless ENV["NO_COVERAGE_TEST"]
 end
 
 require File.expand_path('../../config/environment', __FILE__)
+require 'test/unit/active_support'
 require 'rails/test_help'
-require 'mocha/mini_test'
+require 'mocha/test_unit'
 
 module ArvadosTestSupport
   def json_response

commit c6b3743bae761b8802cf7e016e54833d833ba9f7
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 15:20:08 2016 -0400

    5737: Fix some ruby warnings

diff --git a/services/api/app/controllers/application_controller.rb b/services/api/app/controllers/application_controller.rb
index 3c5bf94..6229b49 100644
--- a/services/api/app/controllers/application_controller.rb
+++ b/services/api/app/controllers/application_controller.rb
@@ -58,6 +58,18 @@ class ApplicationController < ActionController::Base
                 :with => :render_not_found)
   end
 
+  def initialize *args
+    super
+    @object = nil
+    @objects = nil
+    @offset = nil
+    @limit = nil
+    @select = nil
+    @distinct = nil
+    @response_resource_name = nil
+    @attrs = nil
+  end
+
   def default_url_options
     if Rails.configuration.host
       {:host => Rails.configuration.host}
diff --git a/services/api/app/middlewares/arvados_api_token.rb b/services/api/app/middlewares/arvados_api_token.rb
index d8c04a1..2487f2e 100644
--- a/services/api/app/middlewares/arvados_api_token.rb
+++ b/services/api/app/middlewares/arvados_api_token.rb
@@ -7,7 +7,7 @@ class ArvadosApiToken
   # Create a new ArvadosApiToken handler
   # +app+  The next layer of the Rack stack.
   def initialize(app = nil, options = nil)
-    @app = app if app.respond_to?(:call)
+    @app = app.respond_to?(:call) ? app : nil
   end
 
   def call env
diff --git a/services/api/app/models/blob.rb b/services/api/app/models/blob.rb
index 41d5b27..00c2501 100644
--- a/services/api/app/models/blob.rb
+++ b/services/api/app/models/blob.rb
@@ -64,9 +64,9 @@ class Blob
   #   Return value: true if the locator has a valid signature, false otherwise
   #   Arguments: signed_blob_locator, opts
   #
-  def self.verify_signature *args
+  def self.verify_signature(*args)
     begin
-      self.verify_signature! *args
+      self.verify_signature!(*args)
       true
     rescue Blob::InvalidSignatureError
       false
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index 4a05441..98b29f4 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -50,6 +50,18 @@ class Collection < ArvadosModel
     super + ["updated_at", "file_names"]
   end
 
+  def initialize(*args)
+    super
+    @signatures_checked = false
+    @computed_pdh_for_manifest_text = false
+  end
+
+  def initialize_copy(*args)
+    super
+    @signatures_checked = false
+    @computed_pdh_for_manifest_text = false
+  end
+
   FILE_TOKEN = /^[[:digit:]]+:[[:digit:]]+:/
   def check_signatures
     return false if self.manifest_text.nil?
@@ -61,7 +73,9 @@ class Collection < ArvadosModel
     # subsequent passes without checking any signatures. This is
     # important because the signatures have probably been stripped off
     # by the time we get to a second validation pass!
-    return true if @signatures_checked and @signatures_checked == computed_pdh
+    if @signatures_checked && @signatures_checked == computed_pdh
+      return true
+    end
 
     if self.manifest_text_changed?
       # Check permissions on the collection manifest.
diff --git a/services/api/app/models/job.rb b/services/api/app/models/job.rb
index 1c47425..a75af86 100644
--- a/services/api/app/models/job.rb
+++ b/services/api/app/models/job.rb
@@ -67,6 +67,11 @@ class Job < ArvadosModel
             (Complete = 'Complete'),
            ]
 
+  def initialize(*args)
+    super
+    @need_crunch_dispatch_trigger = false
+  end
+
   def assert_finished
     update_attributes(finished_at: finished_at || db_current_time,
                       success: success.nil? ? false : success,
diff --git a/services/api/app/models/node.rb b/services/api/app/models/node.rb
index abb46fd..f92c78b 100644
--- a/services/api/app/models/node.rb
+++ b/services/api/app/models/node.rb
@@ -30,6 +30,11 @@ class Node < ArvadosModel
     t.add lambda { |x| Rails.configuration.compute_node_nameservers }, :as => :nameservers
   end
 
+  def initialize(*args)
+    super
+    @bypass_arvados_authorization = false
+  end
+
   def domain
     super || Rails.configuration.compute_node_domain
   end
diff --git a/services/api/lib/current_api_client.rb b/services/api/lib/current_api_client.rb
index fbd4ef5..1d7dc41 100644
--- a/services/api/lib/current_api_client.rb
+++ b/services/api/lib/current_api_client.rb
@@ -1,3 +1,11 @@
+$system_user = nil
+$system_group = nil
+$all_users_group = nil
+$anonymous_user = nil
+$anonymous_group = nil
+$anonymous_group_read_permission = nil
+$empty_collection = nil
+
 module CurrentApiClient
   def current_user
     Thread.current[:user]

commit 722670d1113e1af551d8470841a38d8d9218b4e8
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 15:18:28 2016 -0400

    5737: Update passenger gem

diff --git a/services/api/Gemfile.lock b/services/api/Gemfile.lock
index ce31316..c02cbd1 100644
--- a/services/api/Gemfile.lock
+++ b/services/api/Gemfile.lock
@@ -70,7 +70,6 @@ GEM
       execjs
     coffee-script-source (1.7.0)
     curb (0.9.3)
-    daemon_controller (1.2.0)
     database_cleaner (1.2.0)
     erubis (2.7.0)
     eventmachine (1.2.0.1)
@@ -146,11 +145,10 @@ GEM
     omniauth-oauth2 (1.1.1)
       oauth2 (~> 0.8.0)
       omniauth (~> 1.0)
-    passenger (4.0.41)
-      daemon_controller (>= 1.2.0)
+    passenger (5.0.30)
       rack
       rake (>= 0.8.1)
-    pg (0.17.1)
+    pg (0.19.0)
     pg_power (1.6.4)
       pg
       rails (~> 3.1)

commit 2bb3fb59369abd48211a872ca1a8e49cb70be5f3
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 15:17:53 2016 -0400

    5737: Rename "skip" to "omit"

diff --git a/services/api/test/functional/arvados/v1/collections_controller_test.rb b/services/api/test/functional/arvados/v1/collections_controller_test.rb
index a8583be..64f6195 100644
--- a/services/api/test/functional/arvados/v1/collections_controller_test.rb
+++ b/services/api/test/functional/arvados/v1/collections_controller_test.rb
@@ -753,8 +753,10 @@ EOS
   ].each do |description_size, expected_response|
     test "create collection with description size #{description_size}
           and expect response #{expected_response}" do
-      skip "(Descriptions are not part of search indexes. Skip until full-text search
-            is implemented, at which point replace with a search in description.)"
+
+      omit "(Descriptions are not part of search indexes. Skip until
+      full-text search is implemented, at which point replace with a
+      search in description.)"
 
       authorize_with :active
 
diff --git a/services/api/test/functional/arvados/v1/links_controller_test.rb b/services/api/test/functional/arvados/v1/links_controller_test.rb
index 1345701..af3cd3a 100644
--- a/services/api/test/functional/arvados/v1/links_controller_test.rb
+++ b/services/api/test/functional/arvados/v1/links_controller_test.rb
@@ -306,7 +306,7 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
   end
 
   test "retrieve all permissions using generic links index api" do
-    skip "(not implemented)"
+    omit "(not implemented)"
     # Links.readable_by() does not return the full set of permission
     # links that are visible to a user (i.e., all permission links
     # whose head_uuid references an object for which the user has
diff --git a/services/api/test/test_helper.rb b/services/api/test/test_helper.rb
index 38aebf5..f35b5fc 100644
--- a/services/api/test/test_helper.rb
+++ b/services/api/test/test_helper.rb
@@ -113,7 +113,11 @@ class ActiveSupport::TestCase
   end
 
   def slow_test
-    skip "RAILS_TEST_SHORT is set" unless (ENV['RAILS_TEST_SHORT'] || '').empty?
+    omit "RAILS_TEST_SHORT is set" if self.class.skip_slow_tests?
+  end
+
+  def self.skip_slow_tests?
+    !(ENV['RAILS_TEST_SHORT'] || '').empty?
   end
 end
 
diff --git a/services/api/test/unit/permission_test.rb b/services/api/test/unit/permission_test.rb
index 79fc1f2..dc3be0b 100644
--- a/services/api/test/unit/permission_test.rb
+++ b/services/api/test/unit/permission_test.rb
@@ -142,9 +142,8 @@ class PermissionTest < ActiveSupport::TestCase
     assert test_perm.destroy, "could not delete new permission on target object"
   end
 
-  # TODO(twp): fix bug #3091, which should fix this test.
   test "can_manage permission on a non-group object" do
-    skip
+    omit "bug #3091"
     set_user_from_auth :admin
 
     ob = Specimen.create!

commit e34688e4a78595aaabe7307f0184df84ff703c6f
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 15:03:08 2016 -0400

    5737: Refactor websocket test suite setup to behave well under test-unit

diff --git a/services/api/test/integration/websocket_test.rb b/services/api/test/integration/websocket_test.rb
index 99ca7ac..198ea71 100644
--- a/services/api/test/integration/websocket_test.rb
+++ b/services/api/test/integration/websocket_test.rb
@@ -1,5 +1,4 @@
 require 'test_helper'
-require 'websocket_runner'
 require 'oj'
 require 'database_cleaner'
 
@@ -16,16 +15,64 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     DatabaseCleaner.clean
   end
 
+  def self.startup
+    s = TCPServer.new('0.0.0.0', 0)
+    @@port = s.addr[1]
+    s.close
+    pidfile = "tmp/pids/passenger.#{@@port}.pid"
+    Dir.chdir(Rails.root) do |apidir|
+      # Only passenger seems to be able to run the websockets server
+      # successfully.
+      _system('passenger', 'start', '-d', "-p#{@@port}")
+      timeout = Time.now.tv_sec + 10
+      begin
+        sleep 0.2
+        begin
+          server_pid = IO.read(pidfile).to_i
+          good_pid = (server_pid > 0) and (Process.kill(0, pid) rescue false)
+        rescue Errno::ENOENT
+          good_pid = false
+        end
+      end while (not good_pid) and (Time.now.tv_sec < timeout)
+      if not good_pid
+        raise RuntimeError, "could not find API server Rails pid"
+      end
+      STDERR.puts "Started websocket server on @@port #{@@port} with pid #{server_pid}"
+    end
+  end
+
+  def self.shutdown
+    Dir.chdir(Rails.root) do
+      _system('passenger', 'stop', "-p#{@@port}")
+    end
+    # DatabaseCleaner leaves the database empty. Prefer to leave it full.
+    dc = DatabaseController.new
+    dc.define_singleton_method :render do |*args| end
+    dc.reset
+  end
+
+  def self._system(*cmd)
+    Bundler.with_clean_env do
+      env = {
+        'ARVADOS_WEBSOCKETS' => 'ws-only',
+        'RAILS_ENV' => 'test',
+      }
+      if not system(env, *cmd)
+        raise RuntimeError, "Command exited #{$?}: #{cmd.inspect}"
+      end
+    end
+  end
+
   def ws_helper (token = nil, timeout = true)
     opened = false
     close_status = nil
     too_long = false
 
-    EM.run {
+    EM.run do
       if token
-        ws = Faye::WebSocket::Client.new("ws://localhost:#{WEBSOCKET_PORT}/websocket?api_token=#{api_client_authorizations(token).api_token}")
+        ws = Faye::WebSocket::Client.new("ws://localhost:#{@@port}/websocket?api_token=#{api_client_authorizations(token).api_token}")
       else
-        ws = Faye::WebSocket::Client.new("ws://localhost:#{WEBSOCKET_PORT}/websocket")
+        ws = Faye::WebSocket::Client.new("ws://localhost:#{@@port}/websocket")
       end
 
       ws.on :open do |event|
@@ -44,7 +91,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
       end
 
       yield ws
-    }
+    end
 
     assert opened, "Should have opened web socket"
     assert (not too_long), "Test took too long"
diff --git a/services/api/test/test_helper.rb b/services/api/test/test_helper.rb
index 417ddf6..38aebf5 100644
--- a/services/api/test/test_helper.rb
+++ b/services/api/test/test_helper.rb
@@ -135,6 +135,21 @@ class ActionController::TestCase
       super action, *args
     end
   end
+
+  def self.suite
+    s = super
+    def s.run(*args)
+      @test_case.startup()
+      begin
+        super
+      ensure
+        @test_case.shutdown()
+      end
+    end
+    s
+  end
+  def self.startup; end
+  def self.shutdown; end
 end
 
 class ActionDispatch::IntegrationTest

commit b8a539e3a0803083b1fcbb23755fc12cffff6f31
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 13:45:11 2016 -0400

    5737: Avoid redefining recursive_hash_search() on each use

diff --git a/services/api/app/models/job.rb b/services/api/app/models/job.rb
index 30ca7f8..1c47425 100644
--- a/services/api/app/models/job.rb
+++ b/services/api/app/models/job.rb
@@ -565,24 +565,6 @@ class Job < ArvadosModel
   end
 
   def ensure_no_collection_uuids_in_script_params
-    # recursive_hash_search searches recursively through hashes and
-    # arrays in 'thing' for string fields matching regular expression
-    # 'pattern'.  Returns true if pattern is found, false otherwise.
-    def recursive_hash_search thing, pattern
-      if thing.is_a? Hash
-        thing.each do |k, v|
-          return true if recursive_hash_search v, pattern
-        end
-      elsif thing.is_a? Array
-        thing.each do |k|
-          return true if recursive_hash_search k, pattern
-        end
-      elsif thing.is_a? String
-        return true if thing.match pattern
-      end
-      false
-    end
-
     # Fail validation if any script_parameters field includes a string containing a
     # collection uuid pattern.
     if self.script_parameters_changed?
@@ -593,4 +575,22 @@ class Job < ArvadosModel
     end
     true
   end
+
+  # recursive_hash_search searches recursively through hashes and
+  # arrays in 'thing' for string fields matching regular expression
+  # 'pattern'.  Returns true if pattern is found, false otherwise.
+  def recursive_hash_search thing, pattern
+    if thing.is_a? Hash
+      thing.each do |k, v|
+        return true if recursive_hash_search v, pattern
+      end
+    elsif thing.is_a? Array
+      thing.each do |k|
+        return true if recursive_hash_search k, pattern
+      end
+    elsif thing.is_a? String
+      return true if thing.match pattern
+    end
+    false
+  end
 end

commit 2e9514e54e31bb37c438cf5d611d49a7c15235b4
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 11:15:35 2016 -0400

    5737: Swap comparison so we get non-equal strings instead of a time parse error.

diff --git a/services/api/test/unit/job_test.rb b/services/api/test/unit/job_test.rb
index 3da2c83..2d401a3 100644
--- a/services/api/test/unit/job_test.rb
+++ b/services/api/test/unit/job_test.rb
@@ -223,7 +223,7 @@ class JobTest < ActiveSupport::TestCase
 
       parameters.each do |parameter|
         expectations = parameter[2]
-        if parameter[1] == 'use_current_user_uuid'
+        if 'use_current_user_uuid' == parameter[1]
           parameter[1] = Thread.current[:user].uuid
         end
 

commit fd308c814745d9c4eed5c3f79b44b9f9142df28a
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Oct 10 11:12:57 2016 -0400

    5737: Update gems so tests run in Ruby >2.1

diff --git a/build/run-tests.sh b/build/run-tests.sh
index 2797ec3..ef84a2f 100755
--- a/build/run-tests.sh
+++ b/build/run-tests.sh
@@ -155,6 +155,12 @@ sanity_checks() {
     echo -n 'virtualenv: '
     virtualenv --version \
         || fatal "No virtualenv. Try: apt-get install virtualenv (on ubuntu: python-virtualenv)"
+    echo -n 'ruby: '
+    ruby -v \
+        || fatal "No ruby. Install >=2.1.9 (using rbenv, rvm, or source)"
+    echo -n 'bundler: '
+    bundle version \
+        || fatal "No bundler. Try: gem install bundler"
     echo -n 'go: '
     go version \
         || fatal "No go binary. See http://golang.org/doc/install"
diff --git a/services/api/Gemfile b/services/api/Gemfile
index 5134fc4..77605aa 100644
--- a/services/api/Gemfile
+++ b/services/api/Gemfile
@@ -9,6 +9,7 @@ group :test, :development do
   gem 'factory_girl_rails'
   gem 'database_cleaner'
   gem 'ruby-prof'
+  gem 'test-unit', '~> 3.0'
   # Note: "require: false" here tells bunder not to automatically
   # 'require' the packages during application startup. Installation is
   # still mandatory.
@@ -17,9 +18,7 @@ group :test, :development do
   gem 'mocha', require: false
 end
 
-# This might not be needed in :test and :development, but we load it
-# anyway to make sure it always gets in Gemfile.lock and to help
-# reveal install problems sooner rather than later.
+# pg is the only supported database driver.
 gem 'pg'
 
 # Start using multi_json once we are on Rails 3.2;
diff --git a/services/api/Gemfile.lock b/services/api/Gemfile.lock
index 1fb4369..ce31316 100644
--- a/services/api/Gemfile.lock
+++ b/services/api/Gemfile.lock
@@ -1,12 +1,12 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    actionmailer (3.2.17)
-      actionpack (= 3.2.17)
+    actionmailer (3.2.22.5)
+      actionpack (= 3.2.22.5)
       mail (~> 2.5.4)
-    actionpack (3.2.17)
-      activemodel (= 3.2.17)
-      activesupport (= 3.2.17)
+    actionpack (3.2.22.5)
+      activemodel (= 3.2.22.5)
+      activesupport (= 3.2.22.5)
       builder (~> 3.0.0)
       erubis (~> 2.7.0)
       journey (~> 1.0.4)
@@ -14,18 +14,18 @@ GEM
       rack-cache (~> 1.2)
       rack-test (~> 0.6.1)
       sprockets (~> 2.2.1)
-    activemodel (3.2.17)
-      activesupport (= 3.2.17)
+    activemodel (3.2.22.5)
+      activesupport (= 3.2.22.5)
       builder (~> 3.0.0)
-    activerecord (3.2.17)
-      activemodel (= 3.2.17)
-      activesupport (= 3.2.17)
+    activerecord (3.2.22.5)
+      activemodel (= 3.2.22.5)
+      activesupport (= 3.2.22.5)
       arel (~> 3.0.2)
       tzinfo (~> 0.3.29)
-    activeresource (3.2.17)
-      activemodel (= 3.2.17)
-      activesupport (= 3.2.17)
-    activesupport (3.2.17)
+    activeresource (3.2.22.5)
+      activemodel (= 3.2.22.5)
+      activesupport (= 3.2.22.5)
+    activesupport (3.2.22.5)
       i18n (~> 0.6, >= 0.6.4)
       multi_json (~> 1.0)
     acts_as_api (0.4.2)
@@ -73,7 +73,7 @@ GEM
     daemon_controller (1.2.0)
     database_cleaner (1.2.0)
     erubis (2.7.0)
-    eventmachine (1.0.3)
+    eventmachine (1.2.0.1)
     execjs (2.0.2)
     extlib (0.9.16)
     factory_girl (4.4.0)
@@ -124,7 +124,7 @@ GEM
     mime-types (1.25.1)
     mocha (1.1.0)
       metaclass (~> 0.0.1)
-    multi_json (1.12.0)
+    multi_json (1.12.1)
     multipart-post (2.0.0)
     net-scp (1.2.0)
       net-ssh (>= 2.6.5)
@@ -154,32 +154,33 @@ GEM
     pg_power (1.6.4)
       pg
       rails (~> 3.1)
-    polyglot (0.3.4)
+    polyglot (0.3.5)
+    power_assert (0.2.6)
     puma (2.8.2)
       rack (>= 1.1, < 2.0)
-    rack (1.4.5)
-    rack-cache (1.2)
+    rack (1.4.7)
+    rack-cache (1.6.1)
       rack (>= 0.4)
     rack-ssl (1.3.4)
       rack
-    rack-test (0.6.2)
+    rack-test (0.6.3)
       rack (>= 1.0)
-    rails (3.2.17)
-      actionmailer (= 3.2.17)
-      actionpack (= 3.2.17)
-      activerecord (= 3.2.17)
-      activeresource (= 3.2.17)
-      activesupport (= 3.2.17)
+    rails (3.2.22.5)
+      actionmailer (= 3.2.22.5)
+      actionpack (= 3.2.22.5)
+      activerecord (= 3.2.22.5)
+      activeresource (= 3.2.22.5)
+      activesupport (= 3.2.22.5)
       bundler (~> 1.0)
-      railties (= 3.2.17)
-    railties (3.2.17)
-      actionpack (= 3.2.17)
-      activesupport (= 3.2.17)
+      railties (= 3.2.22.5)
+    railties (3.2.22.5)
+      actionpack (= 3.2.22.5)
+      activesupport (= 3.2.22.5)
       rack-ssl (~> 1.3.2)
       rake (>= 0.8.7)
       rdoc (~> 3.4)
       thor (>= 0.14.6, < 2.0)
-    rake (10.2.2)
+    rake (11.3.0)
     rdoc (3.12.2)
       json (~> 1.4)
     ref (1.0.5)
@@ -204,12 +205,14 @@ GEM
     simplecov-html (0.7.1)
     simplecov-rcov (0.2.3)
       simplecov (>= 0.4.1)
-    sprockets (2.2.2)
+    sprockets (2.2.3)
       hike (~> 1.2)
       multi_json (~> 1.0)
       rack (~> 1.0)
       tilt (~> 1.1, != 1.3.0)
     sshkey (1.6.1)
+    test-unit (3.1.5)
+      power_assert
     test_after_commit (0.2.3)
     themes_for_rails (0.5.1)
       rails (>= 3.0.0)
@@ -222,7 +225,7 @@ GEM
       polyglot
       polyglot (>= 0.3.1)
     trollop (2.1.2)
-    tzinfo (0.3.39)
+    tzinfo (0.3.51)
     uglifier (2.5.0)
       execjs (>= 0.3.0)
       json (>= 1.8.0)
@@ -261,8 +264,12 @@ DEPENDENCIES
   simplecov (~> 0.7.1)
   simplecov-rcov
   sshkey
+  test-unit (~> 3.0)
   test_after_commit
   themes_for_rails
   therubyracer
   trollop
   uglifier (>= 1.0.3)
+
+BUNDLED WITH
+   1.13.2
diff --git a/services/api/test/websocket_runner.rb b/services/api/test/websocket_runner.rb
deleted file mode 100644
index be32a0f..0000000
--- a/services/api/test/websocket_runner.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require 'bundler'
-require 'socket'
-
-$ARV_API_SERVER_DIR = File.expand_path('../..', __FILE__)
-
-s = TCPServer.new('0.0.0.0', 0)
-WEBSOCKET_PORT = s.addr[1]
-s.close
-SERVER_PID_PATH = "tmp/pids/passenger.#{WEBSOCKET_PORT}.pid"
-
-class WebsocketTestRunner < MiniTest::Unit
-  def _system(*cmd)
-    Bundler.with_clean_env do
-      if not system({'ARVADOS_WEBSOCKETS' => 'ws-only', 'RAILS_ENV' => 'test'}, *cmd)
-        raise RuntimeError, "Command failed with exit status #{$?}: #{cmd.inspect}"
-      end
-    end
-  end
-
-  def _run(args=[])
-    server_pid = Dir.chdir($ARV_API_SERVER_DIR) do |apidir|
-      # Only passenger seems to be able to run the websockets server successfully.
-      _system('passenger', 'start', '-d', "-p#{WEBSOCKET_PORT}")
-      timeout = Time.now.tv_sec + 10
-      begin
-        sleep 0.2
-        begin
-          server_pid = IO.read(SERVER_PID_PATH).to_i
-          good_pid = (server_pid > 0) and (Process.kill(0, pid) rescue false)
-        rescue Errno::ENOENT
-          good_pid = false
-        end
-      end while (not good_pid) and (Time.now.tv_sec < timeout)
-      if not good_pid
-        raise RuntimeError, "could not find API server Rails pid"
-      end
-      server_pid
-    end
-    begin
-      super(args)
-    ensure
-      Dir.chdir($ARV_API_SERVER_DIR) do
-        _system('passenger', 'stop', "-p#{WEBSOCKET_PORT}")
-      end
-      # DatabaseCleaner leaves the database empty. Prefer to leave it full.
-      dc = DatabaseController.new
-      dc.define_singleton_method :render do |*args| end
-      dc.reset
-    end
-  end
-end
-
-MiniTest::Unit.runner = WebsocketTestRunner.new

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list