diff --git a/app/models/shipit/lock_providers/config.rb b/app/models/shipit/lock_providers/config.rb new file mode 100644 index 000000000..5d67e3ccb --- /dev/null +++ b/app/models/shipit/lock_providers/config.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Shipit + module LockProviders + class Config + class MissingConfigError < StandardError; end + attr_accessor :provider + + class << self + delegate :provider, to: :config + + def configure + yield config + config + end + + def config + @config ||= new(provider: NullProvider.new) + end + end + + def initialize(provider:) + @provider = provider + end + end + end +end diff --git a/app/models/shipit/lock_providers/null_provider.rb b/app/models/shipit/lock_providers/null_provider.rb new file mode 100644 index 000000000..debe7683d --- /dev/null +++ b/app/models/shipit/lock_providers/null_provider.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Shipit + module LockProviders + class NullProvider < Provider + def try_lock + nil + end + end + end +end diff --git a/app/models/shipit/lock_providers/provider.rb b/app/models/shipit/lock_providers/provider.rb new file mode 100644 index 000000000..614d954d8 --- /dev/null +++ b/app/models/shipit/lock_providers/provider.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Shipit + module LockProviders + class Provider + def try_lock + raise NotImplementedError, "you must implement #try_lock" + end + end + end +end diff --git a/app/models/shipit/stack.rb b/app/models/shipit/stack.rb index 6731d8775..ebb9e3759 100644 --- a/app/models/shipit/stack.rb +++ b/app/models/shipit/stack.rb @@ -469,6 +469,8 @@ def occupied end def locked? + LockProviders::Config.provider.try_lock + lock_reason.present? end diff --git a/test/models/shipit/lock_providers/config_test.rb b/test/models/shipit/lock_providers/config_test.rb new file mode 100644 index 000000000..f03fb34b8 --- /dev/null +++ b/test/models/shipit/lock_providers/config_test.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'test_helper' + +module Shipit + module LockProviders + class ConfigTest < ActiveSupport::TestCase + class TestProvider < Provider + def try_lock + nil + end + end + + def setup + @original_config = Config.config + Config.instance_variable_set(:@config, nil) + end + + def teardown + Config.instance_variable_set(:@config, @original_config) + end + + test "configure creates a new config instance with default provider" do + config = Config.configure do |c| + c.provider = TestProvider + end + assert_equal TestProvider, config.provider + end + end + end +end diff --git a/test/models/shipit/lock_providers/null_provider_test.rb b/test/models/shipit/lock_providers/null_provider_test.rb new file mode 100644 index 000000000..dcda56eb4 --- /dev/null +++ b/test/models/shipit/lock_providers/null_provider_test.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'test_helper' + +module Shipit + module LockProviders + class NullProviderTest < ActiveSupport::TestCase + test "try_lock returns nil" do + assert_nil NullProvider.new.try_lock + end + end + end +end diff --git a/test/models/shipit/lock_providers/provider_test.rb b/test/models/shipit/lock_providers/provider_test.rb new file mode 100644 index 000000000..8fa4df606 --- /dev/null +++ b/test/models/shipit/lock_providers/provider_test.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'test_helper' + +module Shipit + module LockProviders + class ProviderTest < ActiveSupport::TestCase + test "try_lock raises NotImplementedError" do + provider = Provider.new + assert_raises(NotImplementedError, "you must implement #try_lock") do + provider.try_lock + end + end + + test "BaseProvider is abstract and cannot be instantiated directly" do + assert_raises(NotImplementedError) do + Provider.new.try_lock + end + end + end + end +end diff --git a/test/models/shipit/stack_test.rb b/test/models/shipit/stack_test.rb index 693720676..1be34b863 100644 --- a/test/models/shipit/stack_test.rb +++ b/test/models/shipit/stack_test.rb @@ -749,6 +749,25 @@ def self.deliver(event, stack, payload) assert_equal expected, @stack.locked_since end + test "#locked? updates lock if LockProvider finds lock" do + class LockedProvider < LockProviders::Provider + def initialize(stack) + @stack = stack + end + + def try_lock + @stack.lock("test lock", AnonymousUser.new) + end + end + + refute @stack.locked? + LockProviders::Config.configure { |c| c.provider = LockedProvider.new(@stack) } + assert @stack.locked? + assert_equal "test lock", @stack.lock_reason + ensure + LockProviders::Config.configure { |c| c.provider = LockProvides::NullProvider.new } + end + test "#lock sets reason and user" do reason = "Here comes the walrus" user = shipit_users(:walrus)