flo 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/flo/task.rb CHANGED
@@ -21,7 +21,7 @@ module Flo
21
21
  @provider = provider
22
22
  @method_sym = method_sym
23
23
 
24
- raise ArgumentError.new("Expected provider_options to be a hash") unless provider_options.is_a? Hash
24
+ raise ArgumentError.new("Expected provider_options to be a Hash") unless provider_options.is_a? Hash
25
25
  @provider_options = provider_options
26
26
  end
27
27
 
@@ -29,25 +29,43 @@ module Flo
29
29
  # passed in that are merged into the parameters that were provided in {initialize}.
30
30
  # Proc values will be evaluated before being passed to the provider.
31
31
  #
32
- # @param [Hash] args={} Additional arguments to pass to the provider method
32
+ # @param [Array] args=[] Additional arguments to pass to the provider method
33
33
  # @return [#success?] Response of the provider's method
34
- def call(args={})
35
- @provider.public_send(method_sym, merged_evaluated_args(args))
34
+ def call(args=[])
35
+ raise ArgumentError.new("Expected Array") unless args.is_a? Array
36
+ @provider.public_send(method_sym, *merged_evaluated_args(args))
36
37
  end
37
38
 
38
39
  private
39
40
  attr_reader :provider, :method_sym, :provider_options
40
41
 
41
42
  def merged_evaluated_args(args)
42
- evaluate_proc_values(provider_options.merge args)
43
+ unless args[-1].is_a? Hash
44
+ args.push Hash.new
45
+ end
46
+
47
+ args[-1] = provider_options.merge(args[-1])
48
+ evaluate_proc_values(args)
43
49
  end
44
50
 
45
- def evaluate_proc_values(args={})
46
- hsh = {}
47
- args.each do |k, v|
48
- hsh[k] = v.is_a?(Proc) ? v.call : v
51
+ # For each value in the args array, evaluate any procs.
52
+ # If the value is a hash, evaluate any values in the hash
53
+ # that are procs.
54
+ def evaluate_proc_values(args=[])
55
+ args.collect do |arg|
56
+ case arg
57
+ when Proc
58
+ arg.call
59
+ when Hash
60
+ hsh = {}
61
+ arg.each do |k, v|
62
+ hsh[k] = v.is_a?(Proc) ? v.call : v
63
+ end
64
+ hsh
65
+ else
66
+ arg
67
+ end
49
68
  end
50
- hsh
51
69
  end
52
70
  end
53
71
  end
data/lib/flo/version.rb CHANGED
@@ -4,5 +4,5 @@
4
4
  # For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
5
5
 
6
6
  module Flo
7
- VERSION = "0.0.2"
7
+ VERSION = "0.0.3"
8
8
  end
data/lib/flo.rb CHANGED
@@ -3,8 +3,7 @@
3
3
  # Licensed under the BSD 3-Clause license.
4
4
  # For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
5
5
 
6
- require "flo/version"
7
- require "flo/runner"
6
+ require 'flo/version'
8
7
 
9
8
  # Parent module for all Flo related functionality. Should not be used directly.
10
9
  # See {file:README.md} or {Runner} for information on overall usage.
@@ -12,3 +11,5 @@ require "flo/runner"
12
11
  module Flo
13
12
 
14
13
  end
14
+
15
+ require 'flo/runner'
@@ -6,9 +6,14 @@
6
6
  require 'flo/provider/developer'
7
7
 
8
8
  config do |cfg|
9
- cfg.provider :developer
9
+ cfg.cred_store = Flo::CredStore::YamlStore.new(File.join(FIXTURES_ROOT, "cred_example.yml"))
10
+ cfg.provider :developer, password: cfg.creds['some_value']
10
11
  end
11
12
 
12
- register_command([:task, :start]) do |success: true|
13
+ register_command('task:start') do |success: true|
13
14
  perform :developer, :is_successful, { success: state(:developer).return_true }
14
15
  end
16
+
17
+ register_command(:validate_password) do |success: true|
18
+ perform :developer, :has_option, { option: :password }
19
+ end
@@ -0,0 +1,3 @@
1
+ :provider:
2
+ key: 'foo'
3
+ some_value: 'bar'
@@ -0,0 +1,115 @@
1
+ # Copyright © 2017, Salesforce.com, Inc.
2
+ # All Rights Reserved.
3
+ # Licensed under the BSD 3-Clause license.
4
+ # For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
5
+
6
+ require_relative '../minitest_helper'
7
+ require 'flo/cli'
8
+ require 'ostruct'
9
+
10
+ module Flo
11
+ class CliTest < Flo::UnitTest
12
+
13
+ def subject
14
+ @subject ||= begin
15
+ runner_class_mock = OpenStruct.new(new: runner_mock)
16
+ Flo::Cli.new(runner_class: runner_class_mock)
17
+ end
18
+ end
19
+
20
+ def runner_mock
21
+ @runner_mock ||= begin
22
+ mock = Minitest::Mock.new
23
+ mock.expect(:load_default_config_files, true)
24
+ mock
25
+ end
26
+ end
27
+
28
+ def test_call_without_options_returns_help
29
+ runner_mock.expect(:commands, {})
30
+
31
+ # This is a portion of the output from the help command.
32
+ # We're only asserting that it outputs some help text
33
+ assert_output(/Use `flo help \[command\]` for usage on individual commands/, nil) do
34
+ subject.call([])
35
+ end
36
+
37
+ runner_mock.verify
38
+ end
39
+
40
+ def test_call_runs_command
41
+ runner_mock.expect(:commands, { 'expected_command' => empty_command } )
42
+ runner_mock.expect(:execute, true, ['expected_command', Array])
43
+
44
+ subject.call(['expected_command'])
45
+
46
+ runner_mock.verify
47
+ end
48
+
49
+ def test_help_includes_command_description
50
+ cmd = empty_command
51
+ cmd[:description] = 'This is the description'
52
+
53
+ runner_mock.expect(:commands, { 'expected_command' => cmd } )
54
+
55
+ assert_output(/This is the description/, nil) do
56
+ subject.call(['help', 'expected_command'])
57
+ end
58
+ end
59
+
60
+ def test_help_includes_command_summary
61
+ cmd = empty_command
62
+ cmd[:summary] = 'This is the summary'
63
+
64
+ runner_mock.expect(:commands, { 'expected_command' => cmd } )
65
+
66
+ assert_output(/This is the summary/, nil) do
67
+ subject.call(['help', 'expected_command'])
68
+ end
69
+ end
70
+
71
+ def test_required_parameters_show_up_in_help
72
+ cmd = empty_command
73
+ cmd[:command].required_parameters = ['foo', 'bar']
74
+
75
+ runner_mock.expect(:commands, { 'expected_command' => cmd } )
76
+
77
+ assert_output(/USAGE\s+flo expected_command foo bar/, nil) do
78
+ subject.call(['help', 'expected_command'])
79
+ end
80
+ end
81
+
82
+ def test_optional_parameters_show_up_in_help
83
+ cmd = empty_command
84
+ cmd[:command].optional_parameters = [:foo, :bar]
85
+
86
+ runner_mock.expect(:commands, { 'expected_command' => cmd } )
87
+
88
+ # The options are shown in alphabetical order
89
+ # The output should look something like this:
90
+ # --bar[=<value>] bar
91
+ # --foo[=<value>] foo
92
+ assert_output(/--bar\[=<value>\]\s+bar\s+--foo\[=<value>\]\s+foo/, nil) do
93
+ subject.call(['help', 'expected_command'])
94
+ end
95
+ end
96
+
97
+ def test_options_and_args_are_passed_on
98
+ cmd = empty_command
99
+ cmd[:command].optional_parameters = ['baz']
100
+ runner_mock.expect(:commands, { 'expected_command' => cmd } )
101
+
102
+ runner_mock.expect(:execute, true, ['expected_command', ['foo', 'bar', {baz: 'something'}]])
103
+
104
+ subject.call(['expected_command', 'foo', 'bar', '--baz=something'])
105
+ end
106
+
107
+
108
+ def empty_command
109
+ cmd = OpenStruct.new
110
+ cmd.required_parameters = []
111
+ cmd.optional_parameters = []
112
+ { command: cmd }
113
+ end
114
+ end
115
+ end
@@ -19,22 +19,6 @@ module Flo
19
19
  assert_same command, subject[:command_name]
20
20
  end
21
21
 
22
- def test_an_array_of_symbols_can_be_used_as_a_storage_key
23
- command = Object.new
24
- subject[:name, :spaced, :command] = command
25
- assert_same command, subject[:name, :spaced, :command]
26
- end
27
-
28
- def test_properly_selects_correct_command
29
- command1 = Object.new
30
- command2 = Object.new
31
- subject[:name, :spaced, :command1] = command1
32
- subject[:name, :spaced, :command2] = command2
33
-
34
- assert_same command1, subject[:name, :spaced, :command1]
35
- assert_same command2, subject[:name, :spaced, :command2]
36
- end
37
-
38
22
  def test_selecting_a_command_that_doesnt_exist_raises_error
39
23
  assert_raises(Flo::CommandNotDefinedError) do
40
24
  subject[:undefined_command]
@@ -72,6 +72,18 @@ module Flo
72
72
  subject.perform :mocked_provider, :provider_method, {evaluated_later: subject.state(:mocked_provider).state_method }
73
73
  end
74
74
 
75
+ def test_required_parameters_returns_array
76
+ @subject_block = lambda{|a,b,c: nil, d: 'foo'| }
77
+ assert_equal [:a, :b], subject.required_parameters
78
+ end
79
+
80
+
81
+
82
+ def test_optional_parameters_returns_array
83
+ @subject_block = lambda{|a,b,c: nil, d: 'foo'| }
84
+ assert_equal [:c, :d], subject.optional_parameters
85
+ end
86
+
75
87
  class MockProvider
76
88
  attr_reader :args, :state_method_called
77
89
 
@@ -5,12 +5,17 @@
5
5
 
6
6
  require_relative '../minitest_helper'
7
7
  require 'flo/config'
8
+ require 'yaml'
8
9
 
9
10
  module Flo
10
11
  class ConfigTest < Flo::UnitTest
11
12
 
12
13
  def subject
13
- @subject ||= Flo::Config.new
14
+ @subject ||= begin
15
+ subj = Flo::Config.new()
16
+ subj.cred_store = MockCredStore.new
17
+ subj
18
+ end
14
19
  end
15
20
 
16
21
  def test_provider_instantiates_new_provider
@@ -25,11 +30,33 @@ module Flo
25
30
  end
26
31
  end
27
32
 
33
+ def test_cred_store_defaults_to_yaml
34
+ assert_kind_of Flo::CredStore::YamlStore, Flo::Config.new.cred_store
35
+ end
36
+
37
+ def test_cred_store_can_be_assigned
38
+ expected_cred_store = Object.new
39
+
40
+ subject.cred_store = expected_cred_store
41
+
42
+ assert_same expected_cred_store, subject.cred_store
43
+ end
44
+
45
+ def test_creds_returns_a_lambda
46
+ assert_respond_to subject.creds[:some_value], :call
47
+ end
28
48
  end
49
+
29
50
  module Provider
30
51
  class MockProvider
52
+ attr_writer :cred_store
31
53
  def initialize(args={})
32
54
  end
33
55
  end
34
56
  end
57
+ class MockCredStore
58
+ def credentials_for(provider)
59
+ {}
60
+ end
61
+ end
35
62
  end
@@ -0,0 +1,29 @@
1
+ # Copyright © 2017, Salesforce.com, Inc.
2
+ # All Rights Reserved.
3
+ # Licensed under the BSD 3-Clause license.
4
+ # For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
5
+
6
+ require_relative '../../minitest_helper'
7
+ require 'flo/cred_store/yaml_store'
8
+
9
+ module Flo
10
+ module CredStore
11
+ class CredsTest < Flo::UnitTest
12
+
13
+ def subject
14
+ @subject ||= Flo::CredStore::Creds.new(key: 'foo')
15
+ end
16
+
17
+ def test_element_reference_fetches_a_value_from_yaml_file
18
+ assert_equal 'foo', subject[:key]
19
+ end
20
+
21
+ def test_element_reference_raises_on_missing_value
22
+ assert_raises(Flo::MissingCredentialError) do
23
+ subject[:missing_key]
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,91 @@
1
+ # Copyright © 2017, Salesforce.com, Inc.
2
+ # All Rights Reserved.
3
+ # Licensed under the BSD 3-Clause license.
4
+ # For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
5
+
6
+ require_relative '../../minitest_helper'
7
+ require 'flo/cred_store/pw_protected_store'
8
+ require 'gpgme'
9
+ require 'yaml'
10
+
11
+ module Flo
12
+ module CredStore
13
+ class PwProtectedStoreTest < Flo::UnitTest
14
+
15
+ def subject
16
+ @password ||= 'blah'
17
+ @subject ||= Flo::CredStore::PwProtectedStore.new(password: @password, cred_file_location: cred_file_location)
18
+ end
19
+
20
+ def encryptor
21
+ @password ||= 'blah'
22
+ GPGME::Crypto.new(password: @password)
23
+ end
24
+
25
+ def cred_file_location
26
+ @cred_file_location ||= Tempfile.new('cred_store.yml.gpg')
27
+ end
28
+
29
+ # Must use GPG 1.4, otherwise interactive password prompt
30
+ # will always pop up in the middle of the tests.
31
+ def ensure_gpg_version!
32
+ @testable_version ||= GPGME::Engine.info.select { |e| e.version && e.version.match(/^1\.4/) }.first
33
+ skip('GPG 1.4 not found, skipping gpg tests') unless @testable_version
34
+ GPGME::gpgme_set_engine_info(GPGME::PROTOCOL_OpenPGP, @testable_version.file_name, nil)
35
+ end
36
+
37
+ def teardown
38
+ if cred_file_location.is_a? Tempfile
39
+ cred_file_location.close
40
+ cred_file_location.unlink
41
+ end
42
+ end
43
+
44
+ def yaml_fixture
45
+ @yaml_fixture ||= File.join(FIXTURES_ROOT, 'cred_example.yml')
46
+ end
47
+
48
+ # # TODO: Make this test work with GPG 2.0 or 2.1
49
+ # def test_element_reference_fetches_a_value_from_yaml_file
50
+ # ensure_gpg_version!
51
+
52
+ # fixture_content = File.read(yaml_fixture)
53
+ # assert_equal 'foo', ::YAML.load(fixture_content)['provider']['key'], "Yaml fixture doesn't contain the required value, test will fail for the wrong reason"
54
+ # encryptor.encrypt(fixture_content, symmetric: true, output: cred_file_location)
55
+
56
+ # assert_equal 'foo', subject['provider']['key'], "The key either doesn't exist or the file did not decrypt properly"
57
+ # end
58
+
59
+ def test_credentials_for_fetches_credentials_for_provider
60
+ ensure_gpg_version!
61
+
62
+ fixture_content = File.read(yaml_fixture)
63
+ assert_equal 'foo', ::YAML.load(fixture_content)[:provider]['key'], "Yaml fixture doesn't contain the required value, test will fail for the wrong reason"
64
+ encryptor.encrypt(fixture_content, symmetric: true, output: cred_file_location)
65
+
66
+ assert_equal 'foo', subject.credentials_for(:provider)['key'], "The key either doesn't exist or the file did not decrypt properly"
67
+ end
68
+
69
+ def test_can_initialize_with_file_path_string
70
+ @cred_file_location = yaml_fixture
71
+ assert_kind_of File, subject.cred_file
72
+ end
73
+
74
+ def test_inspect_does_not_reveal_password
75
+ @password = 'should_not_be_revealed'
76
+ refute_match(/#{@password}/, subject.inspect)
77
+ end
78
+
79
+ def test_encrypt_file_properly_encrypts_existing_file
80
+ ensure_gpg_version!
81
+
82
+ expected = File.read(yaml_fixture)
83
+
84
+ encrypted_outcome = subject.encrypt_file(yaml_fixture)
85
+
86
+ decrypted_outcome = encryptor.decrypt(encrypted_outcome).to_s
87
+ assert_equal expected, decrypted_outcome
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright © 2017, Salesforce.com, Inc.
2
+ # All Rights Reserved.
3
+ # Licensed under the BSD 3-Clause license.
4
+ # For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
5
+
6
+ require_relative '../../minitest_helper'
7
+ require 'flo/cred_store/yaml_store'
8
+
9
+ module Flo
10
+ module CredStore
11
+ class YamlStoreTest < Flo::UnitTest
12
+
13
+ def subject
14
+ @subject ||= Flo::CredStore::YamlStore.new(yaml_fixture)
15
+ end
16
+
17
+ def yaml_fixture
18
+ @yaml_fixture ||= File.join(FIXTURES_ROOT, 'cred_example.yml')
19
+ end
20
+
21
+ def test_credentials_for_returns_credentials_object
22
+ refute_nil ::YAML.load(File.read(yaml_fixture))[:provider]
23
+ assert_kind_of Flo::CredStore::Creds, subject.credentials_for(:provider)
24
+ end
25
+
26
+ def test_credentials_for_returns_creds_object_if_provider_is_not_present
27
+ assert_nil ::YAML.load(File.read(yaml_fixture))[:missing_provider]
28
+
29
+ assert_kind_of Flo::CredStore::Creds, subject.credentials_for(:missing_provider)
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright © 2017, Salesforce.com, Inc.
2
+ # All Rights Reserved.
3
+ # Licensed under the BSD 3-Clause license.
4
+ # For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
5
+
6
+ require_relative '../../minitest_helper'
7
+ require 'flo/provider/base'
8
+
9
+ module Flo
10
+ module Provider
11
+ class BaseTest < Flo::UnitTest
12
+
13
+ def subject
14
+ @subject ||= begin
15
+ klass = Class.new(Flo::Provider::Base)
16
+ klass.class_eval do
17
+ def fetch_option(name)
18
+ options.fetch name
19
+ end
20
+ end
21
+ klass
22
+ end
23
+ end
24
+
25
+ def test_option_adds_configuration_to_class
26
+ subject.class_eval { option :some_option }
27
+
28
+ instance = subject.new(some_option: :foo)
29
+
30
+ assert_equal :foo, instance.fetch_option(:some_option)
31
+ end
32
+
33
+ def test_option_allows_for_a_default_value
34
+ subject.class_eval { option :default_option, :default_value }
35
+
36
+ instance = subject.new
37
+
38
+ assert_equal :default_value, instance.fetch_option(:default_option)
39
+ end
40
+
41
+ def test_required_options_raise_when_option_not_provided
42
+ subject.class_eval { option :required_option, nil, required: true }
43
+
44
+ assert_raises(Flo::Provider::MissingOptionError) do
45
+ subject.new
46
+ end
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -19,17 +19,23 @@ module Flo
19
19
  end
20
20
 
21
21
  def test_execute_returns_success
22
- response = subject.execute([:task, :start])
22
+ response = subject.execute('task:start')
23
23
 
24
24
  assert_equal true, response.success?
25
25
  end
26
26
 
27
27
  def test_execute_success_is_false_when_perform_fails
28
- response = subject.execute([:task, :start], success: false)
28
+ response = subject.execute('task:start', [{success: false}])
29
29
 
30
30
  assert_equal false, response.success?
31
31
  end
32
32
 
33
+ def test_credentials_are_utilized
34
+ response = subject.execute(:validate_password)
35
+
36
+ assert_equal true, response.success?
37
+ end
38
+
33
39
  end
34
40
  end
35
41
 
@@ -56,21 +56,7 @@ module Flo
56
56
 
57
57
  subject.register_command(:foo) { }
58
58
 
59
- assert_equal new_command, subject.commands[:foo]
60
-
61
- command_class_mock.verify
62
- end
63
-
64
- def test_register_command_namespaced_adds_new_command_to_collection
65
- config_mock.expect(:providers, {})
66
- new_command = Object.new
67
- command_class_mock.expect(:new, new_command, [{ providers: {} }])
68
-
69
- @command_collection_mock = {}
70
-
71
- subject.register_command([:foo, :bar]) { }
72
-
73
- assert_equal(new_command, subject.commands[[:foo, :bar]])
59
+ assert_equal new_command, subject.commands[:foo][:command]
74
60
 
75
61
  command_class_mock.verify
76
62
  end
@@ -78,7 +64,7 @@ module Flo
78
64
  def test_execute_calls_command_with_args
79
65
  args = {foo: :bar}
80
66
  providers_hash = Object.new
81
- new_command = lambda { |args| true }
67
+ new_command = lambda { |_args| true }
82
68
 
83
69
  command_class_mock.expect(:new, new_command, [{ providers: providers_hash }])
84
70
  config_mock.expect(:providers, providers_hash)
@@ -95,6 +81,17 @@ module Flo
95
81
  config_mock.verify
96
82
  end
97
83
 
84
+ def test_load_default_config_files_loads_available_config_files
85
+ File.stub(:exist?, true) do
86
+ loaded_files = []
87
+ subject.stub(:load_config_file, lambda { |file| loaded_files << file } ) do
88
+
89
+ subject.load_default_config_files
90
+ end
91
+
92
+ assert_equal [File.join(Dir.pwd, '.flo'), File.join(Dir.home, '.flo')], loaded_files
93
+ end
94
+ end
98
95
 
99
96
  end
100
97
  end
@@ -31,14 +31,14 @@ module Flo
31
31
 
32
32
  def test_passes_on_args
33
33
  provider.expect(:foo, true, [{ bar: 1 }])
34
- subject.call(bar: 1)
34
+ subject.call([{bar: 1}])
35
35
  provider.verify
36
36
  end
37
37
 
38
38
  def test_merges_args_with_provider_options
39
39
  @provider_options = { baz: 2 }
40
40
  provider.expect(:foo, true, [{ bar: 1, baz: 2 }])
41
- subject.call(bar: 1)
41
+ subject.call([{bar: 1}])
42
42
  provider.verify
43
43
  end
44
44
 
@@ -50,14 +50,24 @@ module Flo
50
50
  def test_called_args_override_provider_options
51
51
  @provider_options = { bar: 2 }
52
52
  provider.expect(:foo, true, [{ bar: 1 }])
53
- subject.call(bar: 1)
53
+ subject.call([{bar: 1}])
54
54
  provider.verify
55
55
  end
56
56
 
57
57
  def test_procs_in_options_are_evaluated_before_provider_method_is_called
58
- @provider_options = { baz: Proc.new { 2 }}
58
+ @provider_options = { baz: Proc.new { 2 } }
59
+ provider.expect(:foo, true, [:sym, :proc_result, { baz: 2 }])
60
+ subject.call([:sym, Proc.new { :proc_result }])
61
+
62
+ provider.verify
63
+ end
64
+
65
+ def test_procs_in_args_are_evaluated_before_provider_method_is_called
66
+ @provider_options = { baz: Proc.new { 2 } }
59
67
  provider.expect(:foo, true, [{ bar: 1, baz: 2 }])
60
- subject.call(bar: Proc.new { 1 })
68
+ subject.call([{bar: Proc.new { 1 }}])
69
+
70
+ provider.verify
61
71
  end
62
72
  end
63
73
  end
@@ -17,6 +17,7 @@ ENV["MT_NO_SKIP_MSG"] = "true"
17
17
 
18
18
  require 'minitest/autorun'
19
19
  require 'pry'
20
+ require 'minitest/hell'
20
21
 
21
22
  module Flo
22
23
  class UnitTest < Minitest::Test