[ARVADOS] updated: ebdaedbc54c80730733c61cecb3998e26cf5ee7b

git at public.curoverse.com git at public.curoverse.com
Thu Jun 4 08:57:32 EDT 2015


Summary of changes:
 apps/workbench/app/models/arvados_base.rb          | 16 +++++++++++++-
 .../collections_controller_test.rb                 |  2 +-
 apps/workbench/test/unit/arvados_base_test.rb      | 25 ++++++++++++++++++++++
 .../integration/collections_performance_test.rb    |  2 +-
 4 files changed, 42 insertions(+), 3 deletions(-)

  discards  ab90543d36eb2b9ca261d3df9bcc8f2864a8c276 (commit)
  discards  14c74eb1e3b4e003e2b42dee4e81d812605fadeb (commit)
  discards  f4c41070a14edcbe9ab57f093cd0dbb64b9adfe7 (commit)
  discards  9a9e910fef3c6c1b8c476f4709078da063f3e37f (commit)
       via  ebdaedbc54c80730733c61cecb3998e26cf5ee7b (commit)
       via  375e0f68744fdd73f13921e8449de8c6fb232169 (commit)
       via  55f5486de7676b8906066b290ed0420b19f90eda (commit)
       via  24e15ff4b9d357d59827db9ec4f1bd165086eecb (commit)
       via  4e27d97b0161e56943a5828262a0fb873b826f22 (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 (ab90543d36eb2b9ca261d3df9bcc8f2864a8c276)
            \
             N -- N -- N (ebdaedbc54c80730733c61cecb3998e26cf5ee7b)

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 ebdaedbc54c80730733c61cecb3998e26cf5ee7b
Author: Tom Clegg <tom at curoverse.com>
Date:   Wed Jun 3 14:50:03 2015 -0400

    6087: If attributes are accessed but not loaded due to select(), raise instead of returning nil/{}/[].

diff --git a/apps/workbench/app/models/arvados_base.rb b/apps/workbench/app/models/arvados_base.rb
index 3599cac..c08d747 100644
--- a/apps/workbench/app/models/arvados_base.rb
+++ b/apps/workbench/app/models/arvados_base.rb
@@ -53,6 +53,7 @@ class ArvadosBase < ActiveRecord::Base
       'modified_by_client_uuid' => '203',
       'uuid' => '999',
     }
+    @loaded_attributes = {}
   end
 
   def self.columns
@@ -74,6 +75,12 @@ class ArvadosBase < ActiveRecord::Base
           @columns << column(k, :text)
           serialize k, coldef[:type].constantize
         end
+        define_method k do
+          unless new_record? or @loaded_attributes.include? k
+            raise ActiveModel::MissingAttributeError, "missing attribute: #{k}"
+          end
+          super
+        end
         @attribute_info[k] = coldef
       end
     end
@@ -171,8 +178,14 @@ class ArvadosBase < ActiveRecord::Base
   def save
     obdata = {}
     self.class.columns.each do |col|
+      # Non-nil serialized values must be sent because we can't tell
+      # whether they've changed. Other than that, any given attribute
+      # is either unchanged (in which case there's no need to send its
+      # old value in the update/create command) or has been added to
+      # #changed by ActiveRecord's #attr= method.
       if changed.include? col.name or
-          self.class.serialized_attributes.include? col.name
+          (self.class.serialized_attributes.include? col.name and
+           @loaded_attributes[col.name])
         obdata[col.name.to_sym] = self.send col.name
       end
     end
@@ -268,6 +281,7 @@ class ArvadosBase < ActiveRecord::Base
       hash = arvados_api_client.api(self.class, '/' + uuid_or_hash)
     end
     hash.each do |k,v|
+      @loaded_attributes[k.to_s] = true
       if self.respond_to?(k.to_s + '=')
         self.send(k.to_s + '=', v)
       else
diff --git a/apps/workbench/test/unit/arvados_base_test.rb b/apps/workbench/test/unit/arvados_base_test.rb
index f202fe7..5b16cd6 100644
--- a/apps/workbench/test/unit/arvados_base_test.rb
+++ b/apps/workbench/test/unit/arvados_base_test.rb
@@ -24,6 +24,31 @@ class ArvadosBaseTest < ActiveSupport::TestCase
     end
   end
 
+  test '#save does not send unchanged attributes missing because of select' do
+    use_token :active do
+      fixture = api_fixture("collections")["foo_collection_in_aproject"]
+      c = Collection.
+        filter([['uuid','=',fixture['uuid']]]).
+        select(['uuid']).
+        first
+      assert_equal nil, c.properties
+
+      got_query = nil
+      stub_api_calls
+      stub_api_client.expects(:post).with do |url, query, opts={}|
+        got_query = query
+        true
+      end.returns fake_api_response('{}', 200, {})
+      c.name = 'foo'
+      c.save
+
+      updates = JSON.parse got_query['collection']
+      assert_includes updates, 'name'
+      refute_includes updates, 'description'
+      refute_includes updates, 'properties'
+    end
+  end
+
   [false,
    {},
    {'foo' => 'bar'},

commit 375e0f68744fdd73f13921e8449de8c6fb232169
Author: Tom Clegg <tom at curoverse.com>
Date:   Wed Jun 3 12:05:11 2015 -0400

    6087: Remove unneeded CollectionsController#update special case.
    
    ArvadosBase#save now covers the general case of omitting unchanged attributes.

diff --git a/apps/workbench/app/controllers/collections_controller.rb b/apps/workbench/app/controllers/collections_controller.rb
index d4ea86c..e01151c 100644
--- a/apps/workbench/app/controllers/collections_controller.rb
+++ b/apps/workbench/app/controllers/collections_controller.rb
@@ -273,15 +273,6 @@ class CollectionsController < ApplicationController
     sharing_popup
   end
 
-  def update
-    @updates ||= params[@object.resource_param_name.to_sym]
-    if @updates && (@updates.keys - ["name", "description"]).empty?
-      # exclude manifest_text since only name or description is being updated
-      @object.manifest_text = nil
-    end
-    super
-  end
-
   protected
 
   def find_usable_token(token_list)

commit 55f5486de7676b8906066b290ed0420b19f90eda
Author: Tom Clegg <tom at curoverse.com>
Date:   Tue Jun 2 15:23:51 2015 -0400

    6087: Reset changed-attrs list after saving. Fix only-send-changed-attrs logic. Add tests.

diff --git a/apps/workbench/app/models/arvados_base.rb b/apps/workbench/app/models/arvados_base.rb
index 2fca11e..3599cac 100644
--- a/apps/workbench/app/models/arvados_base.rb
+++ b/apps/workbench/app/models/arvados_base.rb
@@ -171,8 +171,9 @@ class ArvadosBase < ActiveRecord::Base
   def save
     obdata = {}
     self.class.columns.each do |col|
-      unless self.send(col.name.to_sym).nil? and !self.changed.include?(col.name)
-          obdata[col.name.to_sym] = self.send(col.name.to_sym)
+      if changed.include? col.name or
+          self.class.serialized_attributes.include? col.name
+        obdata[col.name.to_sym] = self.send col.name
       end
     end
     obdata.delete :id
@@ -199,6 +200,7 @@ class ArvadosBase < ActiveRecord::Base
     end
 
     @new_record = false
+    changes_applied
 
     self
   end
@@ -281,6 +283,7 @@ class ArvadosBase < ActiveRecord::Base
     end
     @all_links = nil
     @new_record = false
+    changes_applied
     self
   end
 
diff --git a/apps/workbench/test/test_helper.rb b/apps/workbench/test/test_helper.rb
index ffc122b..89d15c6 100644
--- a/apps/workbench/test/test_helper.rb
+++ b/apps/workbench/test/test_helper.rb
@@ -95,23 +95,40 @@ module ApiFixtureLoader
 end
 
 module ApiMockHelpers
-  def stub_api_calls_with_body body, status_code=200, headers={}
+  def fake_api_response body, status_code, headers
     resp = mock
-    stubbed_client = ArvadosApiClient.new
-    stubbed_client.instance_eval do
-      resp.responds_like_instance_of HTTP::Message
-      resp.stubs(:headers).returns headers
-      resp.stubs(:content).returns body
-      resp.stubs(:status_code).returns status_code
+    resp.responds_like_instance_of HTTP::Message
+    resp.stubs(:headers).returns headers
+    resp.stubs(:content).returns body
+    resp.stubs(:status_code).returns status_code
+    resp
+  end
+
+  def stub_api_calls_with_body body, status_code=200, headers={}
+    stub_api_calls
+    resp = fake_api_response body, status_code, headers
+    stub_api_client.stubs(:post).returns resp
+  end
+
+  def stub_api_calls
+    @stubbed_client = ArvadosApiClient.new
+    @stubbed_client.instance_eval do
       @api_client = HTTPClient.new
-      @api_client.stubs(:post).returns resp
     end
-    ArvadosApiClient.stubs(:new_or_current).returns(stubbed_client)
+    ArvadosApiClient.stubs(:new_or_current).returns(@stubbed_client)
   end
 
   def stub_api_calls_with_invalid_json
     stub_api_calls_with_body ']"omg,bogus"['
   end
+
+  # Return the HTTPClient mock used by the ArvadosApiClient mock. You
+  # must have called stub_api_calls first.
+  def stub_api_client
+    @stubbed_client.instance_eval do
+      @api_client
+    end
+  end
 end
 
 class ActiveSupport::TestCase
diff --git a/apps/workbench/test/unit/arvados_base_test.rb b/apps/workbench/test/unit/arvados_base_test.rb
new file mode 100644
index 0000000..f202fe7
--- /dev/null
+++ b/apps/workbench/test/unit/arvados_base_test.rb
@@ -0,0 +1,56 @@
+require 'test_helper'
+
+class ArvadosBaseTest < ActiveSupport::TestCase
+  test '#save does not send unchanged string attributes' do
+    use_token :active do
+      fixture = api_fixture("collections")["foo_collection_in_aproject"]
+      c = Collection.find(fixture['uuid'])
+
+      new_name = 'name changed during test'
+
+      got_query = nil
+      stub_api_calls
+      stub_api_client.expects(:post).with do |url, query, opts={}|
+        got_query = query
+        true
+      end.returns fake_api_response('{}', 200, {})
+      c.name = new_name
+      c.save
+
+      updates = JSON.parse got_query['collection']
+      assert_equal updates['name'], new_name
+      refute_includes updates, 'description'
+      refute_includes updates, 'manifest_text'
+    end
+  end
+
+  [false,
+   {},
+   {'foo' => 'bar'},
+  ].each do |init_props|
+    test "#save sends serialized attributes if changed from #{init_props}" do
+      use_token :active do
+        fixture = api_fixture("collections")["foo_collection_in_aproject"]
+        c = Collection.find(fixture['uuid'])
+
+        if init_props
+          c.properties = init_props if init_props
+          c.save!
+        end
+
+        got_query = nil
+        stub_api_calls
+        stub_api_client.expects(:post).with do |url, query, opts={}|
+          got_query = query
+          true
+        end.returns fake_api_response('{"etag":"fake","uuid":"fake"}', 200, {})
+
+        c.properties['baz'] = 'qux'
+        c.save!
+
+        updates = JSON.parse got_query['collection']
+        assert_includes updates, 'properties'
+      end
+    end
+  end
+end

commit 24e15ff4b9d357d59827db9ec4f1bd165086eecb
Author: Tom Clegg <tom at curoverse.com>
Date:   Wed Jun 3 12:00:19 2015 -0400

    6087: Strengthen "manifest_text is not lost in update" test.

diff --git a/apps/workbench/test/controllers/collections_controller_test.rb b/apps/workbench/test/controllers/collections_controller_test.rb
index 65349c6..dc1e4d5 100644
--- a/apps/workbench/test/controllers/collections_controller_test.rb
+++ b/apps/workbench/test/controllers/collections_controller_test.rb
@@ -400,8 +400,15 @@ class CollectionsControllerTest < ActionController::TestCase
     }, session_for(:active)
     assert_response :success
     assert_not_nil assigns(:object)
+    # Ensure the Workbench response still has the original manifest_text
     assert_equal 'test description update', assigns(:object).description
     assert_equal collection['manifest_text'], assigns(:object).manifest_text
+    # Ensure the API server still has the original manifest_text after
+    # we called arvados.v1.collections.update
+    use_token :active do
+      assert_equal(Collection.find(collection['uuid']).manifest_text,
+                   collection['manifest_text'])
+    end
   end
 
   test "view collection and verify none of the file types listed are disabled" do

commit 4e27d97b0161e56943a5828262a0fb873b826f22
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon May 25 13:25:22 2015 -0400

    6087: Add big-manifest tests, with some finer-grained performance numbers on stderr.

diff --git a/apps/workbench/app/models/arvados_api_client.rb b/apps/workbench/app/models/arvados_api_client.rb
index 17c5ec6..ca09aa7 100644
--- a/apps/workbench/app/models/arvados_api_client.rb
+++ b/apps/workbench/app/models/arvados_api_client.rb
@@ -134,7 +134,7 @@ class ArvadosApiClient
 
     header = {"Accept" => "application/json"}
 
-    profile_checkpoint { "Prepare request #{url} #{query[:uuid]} #{query[:where]} #{query[:filters]} #{query[:order]}" }
+    profile_checkpoint { "Prepare request #{query["_method"] or "POST"} #{url} #{query[:uuid]} #{query.inspect[0,256]}" }
     msg = @client_mtx.synchronize do
       begin
         @api_client.post(url, query, header: header)
@@ -143,6 +143,12 @@ class ArvadosApiClient
       end
     end
     profile_checkpoint 'API transaction'
+    if @@profiling_enabled
+      if msg.headers['X-Runtime']
+        Rails.logger.info "API server: #{msg.headers['X-Runtime']} runtime reported"
+      end
+      Rails.logger.info "Content-Encoding #{msg.headers['Content-Encoding'].inspect}, Content-Length #{msg.headers['Content-Length'].inspect}, actual content size #{msg.content.size}"
+    end
 
     begin
       resp = Oj.load(msg.content, :symbol_keys => true)
diff --git a/apps/workbench/test/helpers/manifest_examples.rb b/apps/workbench/test/helpers/manifest_examples.rb
new file mode 120000
index 0000000..cb908ef
--- /dev/null
+++ b/apps/workbench/test/helpers/manifest_examples.rb
@@ -0,0 +1 @@
+../../../../services/api/test/helpers/manifest_examples.rb
\ No newline at end of file
diff --git a/apps/workbench/test/helpers/time_block.rb b/apps/workbench/test/helpers/time_block.rb
new file mode 120000
index 0000000..afb43e7
--- /dev/null
+++ b/apps/workbench/test/helpers/time_block.rb
@@ -0,0 +1 @@
+../../../../services/api/test/helpers/time_block.rb
\ No newline at end of file
diff --git a/apps/workbench/test/integration_performance/collection_unit_test.rb b/apps/workbench/test/integration_performance/collection_unit_test.rb
new file mode 100644
index 0000000..6cf14b5
--- /dev/null
+++ b/apps/workbench/test/integration_performance/collection_unit_test.rb
@@ -0,0 +1,71 @@
+require 'test_helper'
+require 'helpers/manifest_examples'
+require 'helpers/time_block'
+
+class Blob
+end
+
+class BigCollectionTest < ActiveSupport::TestCase
+  include ManifestExamples
+
+  setup do
+    Blob.stubs(:sign_locator).returns 'd41d8cd98f00b204e9800998ecf8427e+0'
+  end
+
+  teardown do
+    Thread.current[:arvados_api_client] = nil
+  end
+
+  # You can try with compress=false here too, but at last check it
+  # didn't make a significant difference.
+  [true].each do |compress|
+    test "crud cycle for collection with big manifest (compress=#{compress})" do
+      Rails.configuration.api_response_compression = compress
+      Thread.current[:arvados_api_client] = nil
+      crudtest
+    end
+  end
+
+  def crudtest
+    use_token :active
+    bigmanifest = time_block 'build example' do
+      make_manifest(streams: 100,
+                    files_per_stream: 100,
+                    blocks_per_file: 20,
+                    bytes_per_block: 0)
+    end
+    c = time_block "new (manifest size = #{bigmanifest.length>>20}MiB)" do
+      Collection.new manifest_text: bigmanifest
+    end
+    time_block 'create' do
+      c.save!
+    end
+    time_block 'read' do
+      Collection.find c.uuid
+    end
+    time_block 'read(cached)' do
+      Collection.find c.uuid
+    end
+    time_block 'list' do
+      list = Collection.select(['uuid', 'manifest_text']).filter [['uuid','=',c.uuid]]
+      assert_equal 1, list.count
+      assert_equal c.uuid, list.first.uuid
+      assert_not_nil list.first.manifest_text
+    end
+    time_block 'update(name-only)' do
+      manifest_text_length = c.manifest_text.length
+      c.update_attributes name: 'renamed during test case'
+      assert_equal c.manifest_text.length, manifest_text_length
+    end
+    time_block 'update' do
+      c.manifest_text += ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:empty.txt\n"
+      c.save!
+    end
+    time_block 'delete' do
+      c.destroy
+    end
+    time_block 'read(404)' do
+      assert_empty Collection.filter([['uuid','=',c.uuid]])
+    end
+  end
+end
diff --git a/apps/workbench/test/integration_performance/collections_controller_test.rb b/apps/workbench/test/integration_performance/collections_controller_test.rb
new file mode 100644
index 0000000..3b81c60
--- /dev/null
+++ b/apps/workbench/test/integration_performance/collections_controller_test.rb
@@ -0,0 +1,71 @@
+require 'test_helper'
+require 'helpers/manifest_examples'
+require 'helpers/time_block'
+
+class Blob
+end
+
+class BigCollectionsControllerTest < ActionController::TestCase
+  include ManifestExamples
+
+  setup do
+    Blob.stubs(:sign_locator).returns 'd41d8cd98f00b204e9800998ecf8427e+0'
+  end
+
+  test "combine two big and two small collections" do
+    @controller = ActionsController.new
+    bigmanifest1 = time_block 'build example' do
+      make_manifest(streams: 100,
+                    files_per_stream: 100,
+                    blocks_per_file: 20,
+                    bytes_per_block: 0)
+    end
+    bigmanifest2 = bigmanifest1.gsub '.txt', '.txt2'
+    smallmanifest1 = ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:small1.txt\n"
+    smallmanifest2 = ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:small2.txt\n"
+    totalsize = bigmanifest1.length + bigmanifest2.length +
+      smallmanifest1.length + smallmanifest2.length
+    parts = time_block "create (total #{totalsize>>20}MiB)" do
+      use_token :active do
+        {
+          big1: Collection.create(manifest_text: bigmanifest1),
+          big2: Collection.create(manifest_text: bigmanifest2),
+          small1: Collection.create(manifest_text: smallmanifest1),
+          small2: Collection.create(manifest_text: smallmanifest2),
+        }
+      end
+    end
+    time_block 'combine' do
+      post :combine_selected_files_into_collection, {
+        selection: [parts[:big1].uuid,
+                    parts[:big2].uuid,
+                    parts[:small1].uuid + '/small1.txt',
+                    parts[:small2].uuid + '/small2.txt',
+                   ],
+        format: :html
+      }, session_for(:active)
+    end
+    assert_response :redirect
+  end
+
+  [:json, :html].each do |format|
+    test "show collection with big manifest (#{format})" do
+      bigmanifest = time_block 'build example' do
+        make_manifest(streams: 100,
+                      files_per_stream: 100,
+                      blocks_per_file: 20,
+                      bytes_per_block: 0)
+      end
+      @controller = CollectionsController.new
+      c = time_block "create (manifest size #{bigmanifest.length>>20}MiB)" do
+        use_token :active do
+          Collection.create(manifest_text: bigmanifest)
+        end
+      end
+      time_block 'show' do
+        get :show, {id: c.uuid, format: format}, session_for(:active)
+      end
+      assert_response :success
+    end
+  end
+end
diff --git a/apps/workbench/test/test_helper.rb b/apps/workbench/test/test_helper.rb
index f335722..ffc122b 100644
--- a/apps/workbench/test/test_helper.rb
+++ b/apps/workbench/test/test_helper.rb
@@ -95,11 +95,12 @@ module ApiFixtureLoader
 end
 
 module ApiMockHelpers
-  def stub_api_calls_with_body body, status_code=200
+  def stub_api_calls_with_body body, status_code=200, headers={}
     resp = mock
     stubbed_client = ArvadosApiClient.new
     stubbed_client.instance_eval do
       resp.responds_like_instance_of HTTP::Message
+      resp.stubs(:headers).returns headers
       resp.stubs(:content).returns body
       resp.stubs(:status_code).returns status_code
       @api_client = HTTPClient.new
diff --git a/services/api/test/helpers/manifest_examples.rb b/services/api/test/helpers/manifest_examples.rb
new file mode 100644
index 0000000..08712eb
--- /dev/null
+++ b/services/api/test/helpers/manifest_examples.rb
@@ -0,0 +1,31 @@
+module ManifestExamples
+  def make_manifest opts={}
+    opts = {
+      bytes_per_block: 1,
+      blocks_per_file: 1,
+      files_per_stream: 1,
+      streams: 1,
+    }.merge(opts)
+    datablip = "x" * opts[:bytes_per_block]
+    locator = Blob.sign_locator(Digest::MD5.hexdigest(datablip) +
+                                '+' + datablip.length.to_s,
+                                api_token: opts[:api_token])
+    filesize = datablip.length * opts[:blocks_per_file]
+    txt = ''
+    (1..opts[:streams]).each do |s|
+      streamtoken = "./stream#{s}"
+      streamsize = 0
+      blocktokens = []
+      filetokens = []
+      (1..opts[:files_per_stream]).each do |f|
+        filetokens << " #{streamsize}:#{filesize}:file#{f}.txt"
+        (1..opts[:blocks_per_file]).each do |b|
+          blocktokens << locator
+        end
+        streamsize += filesize
+      end
+      txt << ([streamtoken] + blocktokens + filetokens).join(' ') + "\n"
+    end
+    txt
+  end
+end
diff --git a/services/api/test/helpers/time_block.rb b/services/api/test/helpers/time_block.rb
new file mode 100644
index 0000000..a3b03ff
--- /dev/null
+++ b/services/api/test/helpers/time_block.rb
@@ -0,0 +1,11 @@
+class ActiveSupport::TestCase
+  def time_block label
+    t0 = Time.now
+    begin
+      yield
+    ensure
+      t1 = Time.now
+      $stderr.puts "#{t1 - t0}s #{label}"
+    end
+  end
+end
diff --git a/services/api/test/integration/collections_performance_test.rb b/services/api/test/integration/collections_performance_test.rb
new file mode 100644
index 0000000..892060a
--- /dev/null
+++ b/services/api/test/integration/collections_performance_test.rb
@@ -0,0 +1,40 @@
+require 'test_helper'
+require 'helpers/manifest_examples'
+require 'helpers/time_block'
+
+class CollectionsApiPerformanceTest < ActionDispatch::IntegrationTest
+  include ManifestExamples
+
+  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,
+                    blocks_per_file: 20,
+                    bytes_per_block: 2**26,
+                    api_token: api_token(:active))
+    end
+    json = time_block "JSON encode #{bigmanifest.length>>20}MiB manifest" do
+      Oj.dump({manifest_text: bigmanifest})
+    end
+    time_block 'create' do
+      post '/arvados/v1/collections', {collection: json}, auth(:active)
+      assert_response :success
+    end
+    uuid = json_response['uuid']
+    time_block 'read' do
+      get '/arvados/v1/collections/' + uuid, {}, auth(:active)
+      assert_response :success
+    end
+    time_block 'list' do
+      get '/arvados/v1/collections', {select: ['manifest_text'], filters: [['uuid', '=', uuid]].to_json}, auth(:active)
+      assert_response :success
+    end
+    time_block 'update' do
+      put '/arvados/v1/collections/' + uuid, {collection: json}, auth(:active)
+      assert_response :success
+    end
+    time_block 'delete' do
+      delete '/arvados/v1/collections/' + uuid, {}, auth(:active)
+    end
+  end
+end
diff --git a/services/api/test/unit/collection_performance_test.rb b/services/api/test/unit/collection_performance_test.rb
new file mode 100644
index 0000000..075b4c5
--- /dev/null
+++ b/services/api/test/unit/collection_performance_test.rb
@@ -0,0 +1,61 @@
+require 'test_helper'
+require 'helpers/manifest_examples'
+require 'helpers/time_block'
+
+class CollectionModelPerformanceTest < ActiveSupport::TestCase
+  include ManifestExamples
+
+  setup do
+    # The Collection model needs to have a current token, not just a
+    # current user, to sign & verify manifests:
+    Thread.current[:api_client_authorization] =
+      api_client_authorizations(:active)
+  end
+
+  teardown do
+    Thread.current[:api_client_authorization] = nil
+  end
+
+  # "crrud" == "create read render update delete", not a typo
+  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,
+                    blocks_per_file: 20,
+                    bytes_per_block: 2**26,
+                    api_token: api_token(:active))
+    end
+    act_as_user users(:active) do
+      c = time_block "new (manifest_text is #{bigmanifest.length>>20}MiB)" do
+        Collection.new manifest_text: bigmanifest.dup
+      end
+      time_block 'check signatures' do
+        c.check_signatures
+      end
+      time_block 'check signatures + save' do
+        c.save!
+      end
+      c = time_block 'read' do
+        Collection.find_by_uuid(c.uuid)
+      end
+      time_block 'sign' do
+        c.signed_manifest_text
+      end
+      time_block 'sign + render' do
+        resp = c.as_api_response(nil)
+      end
+      loc = Blob.sign_locator(Digest::MD5.hexdigest('foo') + '+3',
+                              api_token: api_token(:active))
+      # Note Collection's strip_manifest_text method has now removed
+      # the signatures from c.manifest_text, so we have to start from
+      # bigmanifest again here instead of just appending with "+=".
+      c.manifest_text = bigmanifest.dup + ". #{loc} 0:3:foo.txt\n"
+      time_block 'update' do
+        c.save!
+      end
+      time_block 'delete' do
+        c.destroy
+      end
+    end
+  end
+end

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list