From fed3c1202446d7b72d202bb4759aa91b9655e605 Mon Sep 17 00:00:00 2001 From: exAspArk Date: Mon, 6 Nov 2017 10:45:22 -0500 Subject: [PATCH] Add test for a race-condition --- lib/batch_loader.rb | 7 ++++--- spec/batch_loader_spec.rb | 14 ++++++++++++++ spec/spec_helper.rb | 8 ++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/batch_loader.rb b/lib/batch_loader.rb index 9bd64c9..bfc7819 100644 --- a/lib/batch_loader.rb +++ b/lib/batch_loader.rb @@ -18,8 +18,9 @@ def self.for(item) new(item: item) end - def initialize(item:) + def initialize(item:, executor_proxy: nil) @item = item + @__executor_proxy = executor_proxy end def batch(default_value: nil, cache: true, &batch_block) @@ -76,7 +77,7 @@ def __ensure_batched return if __executor_proxy.value_loaded?(item: @item) items = __executor_proxy.list_items - loader = -> (item, value = (no_value = true; nil), &block) { + loader = -> (item, value = (no_value = true; nil), &block) do if no_value && !block raise ArgumentError, "Please pass a value or a block" elsif block && !no_value @@ -85,7 +86,7 @@ def __ensure_batched next_value = block ? block.call(__executor_proxy.loaded_value(item: item)) : value __executor_proxy.load(item: item, value: next_value) - } + end @batch_block.call(items, loader) items.each do |item| diff --git a/spec/batch_loader_spec.rb b/spec/batch_loader_spec.rb index 46bad8c..9705a52 100644 --- a/spec/batch_loader_spec.rb +++ b/spec/batch_loader_spec.rb @@ -99,6 +99,20 @@ expect(lazy).to eq(2) end + it 'is thread-safe' do + batch_block = Proc.new do |ids, loader| + ids.each do |id| + thread = Thread.new { loader.call(id) { |value| value << id } } + loader.call(id) { |value| value << id + 1 } + thread.join + end + end + slow_executor_proxy = SlowExecutorProxy.new([], &batch_block) + lazy = BatchLoader.new(item: 1, executor_proxy: slow_executor_proxy).batch(default_value: [], &batch_block) + + expect(lazy).to eq([1, 2]) + end + it 'supports alternative default values' do lazy = BatchLoader.for(1).batch(default_value: 123) do |nums, loader| # No-op, so default is returned diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7b75edd..68b0934 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,6 +11,14 @@ require_relative "./fixtures/models" require_relative "./fixtures/graphql_schema" +class SlowExecutorProxy < BatchLoader::ExecutorProxy + def value_loaded?(item:) + result = loaded.key?(item) + sleep 0.5 + result + end +end + RSpec.configure do |config| # Enable flags like --only-failures and --next-failure config.example_status_persistence_file_path = ".rspec_status"