bosh_common 0.5.4 → 1.5.0.pre.1100

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/common/common.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  # Copyright (c) 2012 VMware, Inc.
2
+ require 'common/errors'
3
+ require 'common/retryable'
2
4
 
3
5
  module Bosh
4
6
 
@@ -43,5 +45,80 @@ module Bosh
43
45
  end
44
46
 
45
47
  module_function :which
48
+
49
+ # Retries execution of given block until block returns true
50
+ #
51
+ # The block is called with two parameters: the number of tries and the most recent
52
+ # exception. If the block returns true retrying is stopped.
53
+ # Examples:
54
+ # Bosh::Common.retryable do |retries, exception|
55
+ # puts "try #{retries} failed with exception: #{exception}" if retries > 0
56
+ # pick_up_soap
57
+ # end
58
+ #
59
+ # # Wait for EC2 instance to be terminated
60
+ # Bosh::Common.retryable(on: AWS::EC2::Errors::RequestLimitExceeded) do |retries, exception|
61
+ # @ec2.instance['i-a3x5g5'].status == :terminated
62
+ # end
63
+ #
64
+ #
65
+ # @param [Hash] options
66
+ # @options opts [Proc] :ensure
67
+ # Default: `Proc.new {}`
68
+ # Ensure that a block of code is executed, regardless of whether an exception
69
+ # was raised. It doesn't matter if the block exits normally, if it retries
70
+ # to execute block of code, or if it is terminated by an uncaught exception
71
+ # -- the ensure block will get run.
72
+ # Example:
73
+ # f = File.open("testfile")
74
+ #
75
+ # ensure_cb = Proc.new do |retries|
76
+ # puts "total retry attempts: #{retries}"
77
+ #
78
+ # f.close
79
+ # end
80
+ #
81
+ # Bosh::Common.retryable(ensure: ensure_cb) do
82
+ # # process file
83
+ # end
84
+ #
85
+ # @options opts [Regexp] :matching
86
+ # Default: `/.*/`
87
+ # Retry based on the exception message
88
+ # Example:
89
+ # Bosh::Common.retryable(matching: /IO timeout/) do |retries, exception|
90
+ # raise "yo, IO timeout!" if retries == 0
91
+ # end
92
+ #
93
+ # @options opts [Array<ExceptionClass>] :on
94
+ # Default: `[]`
95
+ # The array of exception classes to retry on.
96
+ # Example:
97
+ # Bosh::Common.retryable(on: [StandardError, ArgumentError]) do
98
+ # # do something and retry if StandardError or ArgumentError is raised
99
+ # end
100
+ #
101
+ # @options opts [Proc, Fixnum] :sleep
102
+ # Defaults: `lambda { |tries, _| [2**(tries-1), 10].min }`, 1, 2, 4, 8, 10, 10..10 seconds
103
+ # If a Fixnum is given, sleep that many seconds between retries.
104
+ # If a Proc is given, call it with the expectation that a Fixnum is returned
105
+ # and sleep that many seconds. The Proc will be called with the number of tries
106
+ # and the raised exception (or nil)
107
+ # Example:
108
+ # Bosh::Common.retryable(sleep: lambda { |n,e| logger.info(e.message) if e; 4**n }) { }
109
+ #
110
+ # @options opts [Fixnum] :tries
111
+ # Default: 2
112
+ # Number of times to try
113
+ # Example:
114
+ # Bosh::Common.retryable(tries: 3, on: OpenURI::HTTPError) do
115
+ # xml = open("http://example.com/test.xml").read
116
+ # end
117
+ #
118
+ def retryable(options = {}, &block)
119
+ Bosh::Retryable.new(options).retryer(&block)
120
+ end
121
+
122
+ module_function :retryable
46
123
  end
47
124
  end
@@ -0,0 +1,7 @@
1
+ module Bosh::Common
2
+ module DeepCopy
3
+ def self.copy(object)
4
+ Marshal.load(Marshal.dump(object))
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh
4
+ module Common
5
+ class RetryCountExceeded < Exception; end
6
+ end
7
+ end
@@ -23,7 +23,7 @@ module Bosh::Common
23
23
  end
24
24
 
25
25
  dst_ref[keys[-1]] ||= {}
26
- dst_ref[keys[-1]] = src_ref || default
26
+ dst_ref[keys[-1]] = src_ref.nil? ? default : src_ref
27
27
  end
28
28
 
29
29
  # @param [Hash] collection Property collection
@@ -40,4 +40,4 @@ module Bosh::Common
40
40
  ref
41
41
  end
42
42
  end
43
- end
43
+ end
@@ -73,18 +73,14 @@ module Bosh::Common
73
73
  # @return [Object] Property value
74
74
  # @raise [Bosh::Common::UnknownProperty]
75
75
  def p(*args)
76
- names = args[0]
77
- default_given = args.size > 1
78
- default = args[1]
79
-
80
- names = Array(names) unless names.kind_of?(Array)
76
+ names = Array(args[0])
81
77
 
82
78
  names.each do |name|
83
79
  result = lookup_property(@raw_properties, name)
84
80
  return result unless result.nil?
85
81
  end
86
82
 
87
- return default if default_given
83
+ return args[1] if args.length == 2
88
84
  raise UnknownProperty.new(names)
89
85
  end
90
86
 
@@ -94,11 +90,12 @@ module Bosh::Common
94
90
  def if_p(*names)
95
91
  values = names.map do |name|
96
92
  value = lookup_property(@raw_properties, name)
97
- return if value.nil?
93
+ return ActiveElseBlock.new(self) if value.nil?
98
94
  value
99
95
  end
100
96
 
101
97
  yield *values
98
+ InactiveElseBlock.new
102
99
  end
103
100
 
104
101
  # @return [Object] Object representation where all hashes are unrolled
@@ -115,5 +112,29 @@ module Bosh::Common
115
112
  object
116
113
  end
117
114
  end
115
+
116
+ private
117
+ class ActiveElseBlock
118
+ def initialize(template_context)
119
+ @context = template_context
120
+ end
121
+
122
+ def else
123
+ yield
124
+ end
125
+
126
+ def else_if_p(*names, &block)
127
+ @context.if_p(*names, &block)
128
+ end
129
+ end
130
+
131
+ class InactiveElseBlock
132
+ def else
133
+ end
134
+
135
+ def else_if_p(*names)
136
+ InactiveElseBlock.new
137
+ end
138
+ end
118
139
  end
119
- end
140
+ end
@@ -0,0 +1,74 @@
1
+ require_relative 'errors'
2
+
3
+ module Bosh
4
+ class Retryable
5
+ def initialize(options = {})
6
+ opts = validate_options(options)
7
+
8
+ @ensure_callback = opts[:ensure]
9
+ @matching = opts[:matching]
10
+ @on_exception = [opts[:on]].flatten
11
+ @try_count = 0
12
+ @retry_exception = nil
13
+ @retry_limit = opts[:tries]
14
+ @sleeper = opts[:sleep]
15
+ end
16
+
17
+ # this method will loop until the block returns a true value
18
+ def retryer(&block)
19
+ loop do
20
+ @try_count += 1
21
+ y = yield @try_count, @retry_exception
22
+ @retry_exception = nil # no exception was raised in the block
23
+ return y if y
24
+ raise Bosh::Common::RetryCountExceeded if @try_count >= @retry_limit
25
+ wait
26
+ end
27
+ rescue *@on_exception => exception
28
+ raise unless exception.message =~ @matching
29
+ raise if @try_count >= @retry_limit
30
+
31
+ @retry_exception = exception
32
+ wait
33
+ retry
34
+ ensure
35
+ @ensure_callback.call(@try_count)
36
+ end
37
+
38
+ private
39
+
40
+ def validate_options(options)
41
+ merged_options = default_options.merge(options)
42
+ invalid_options = merged_options.keys - default_options.keys
43
+ raise ArgumentError.new("Invalid options: #{invalid_options.join(", ")}") unless invalid_options.empty?
44
+
45
+ merged_options
46
+ end
47
+
48
+ def default_options
49
+ {
50
+ tries: 2,
51
+ sleep: exponential_sleeper,
52
+ on: [],
53
+ matching: /.*/,
54
+ ensure: Proc.new {}
55
+ }
56
+ end
57
+
58
+ def wait
59
+ sleep(@sleeper.respond_to?(:call) ? @sleeper.call(@try_count, @retry_exception) : @sleeper)
60
+ rescue *@on_exception
61
+ # SignalException could be raised while sleeping, so if you want to catch it,
62
+ # it need to be passed in the list of exceptions to ignore
63
+ end
64
+
65
+ def exponential_sleeper
66
+ lambda { |tries, _| [2**(tries-1), 10].min } # 1, 2, 4, 8, 10, 10..10 seconds
67
+ end
68
+
69
+ def sleep(*args, &blk)
70
+ Kernel.sleep(*args, &blk)
71
+ end
72
+ end
73
+ end
74
+
@@ -0,0 +1,12 @@
1
+ require 'common/exec'
2
+
3
+ # Mixin to make it easy to inject an alternate command runner into a class that runs commands.
4
+ module Bosh
5
+ module RunsCommands
6
+ def sh(command)
7
+ (@command_runner || Bosh::Exec).sh(command)
8
+ end
9
+
10
+ attr_accessor :command_runner
11
+ end
12
+ end
data/lib/common/ssl.rb ADDED
@@ -0,0 +1,107 @@
1
+ require 'openssl'
2
+
3
+ module Bosh
4
+ module Ssl
5
+ class Certificate
6
+ class SubjectsDoNotMatchException < RuntimeError;
7
+ end
8
+ class MatchingFileNotFound < RuntimeError;
9
+ end
10
+
11
+ attr_reader :key_path, :certificate_path
12
+
13
+ def initialize(key_path, certificate_path, common_name, chain_path = nil)
14
+ @key_path = key_path
15
+ @certificate_path = certificate_path
16
+ @chain_path = chain_path
17
+ @subject_string = subject_string(common_name)
18
+ end
19
+
20
+ def key
21
+ @key.to_pem
22
+ end
23
+
24
+ def certificate
25
+ @csr_cert.to_pem
26
+ end
27
+
28
+ def chain
29
+ @chain.to_pem if @chain
30
+ end
31
+
32
+ def load_or_create
33
+ @key, @csr_cert = load_or_create_key_and_csr_cert
34
+ @chain = OpenSSL::X509::Certificate.new(File.read(@chain_path)) if @chain_path
35
+
36
+ self
37
+ end
38
+
39
+ private
40
+
41
+ def load_or_create_key_and_csr_cert
42
+ if File.exists?(@key_path) && !File.exists?(@certificate_path)
43
+ raise MatchingFileNotFound, 'The key that matches the given certificate could not be found.'
44
+ end
45
+
46
+ if File.exists?(@certificate_path) && !File.exists?(@key_path)
47
+ raise MatchingFileNotFound, 'The certificate that matches the given key could not be found.'
48
+ end
49
+
50
+ if File.exists?(@key_path) && File.exists?(@certificate_path)
51
+ load_key_and_csr_cert
52
+ else
53
+ create_key_and_csr_cert
54
+ end
55
+ end
56
+
57
+ def load_key_and_csr_cert
58
+ key = OpenSSL::PKey::RSA.new(File.read(@key_path))
59
+ csr_cert = OpenSSL::X509::Certificate.new(File.read(@certificate_path))
60
+
61
+ [key, csr_cert]
62
+ end
63
+
64
+ def create_key_and_csr_cert
65
+ subject = OpenSSL::X509::Name.parse(@subject_string)
66
+ key = OpenSSL::PKey::RSA.new(2048)
67
+ csr = new_csr(key, subject)
68
+ csr_cert = new_csr_certificate(key, csr)
69
+
70
+ File.write(@key_path, key.to_pem)
71
+ File.write(@certificate_path, csr_cert.to_pem)
72
+
73
+ [key, csr_cert]
74
+ end
75
+
76
+ def new_csr(key, subject)
77
+ csr = OpenSSL::X509::Request.new
78
+ csr.version = 0
79
+ csr.subject = subject
80
+ csr.public_key = key.public_key
81
+ csr.sign key, OpenSSL::Digest::SHA1.new
82
+
83
+ csr
84
+ end
85
+
86
+ def new_csr_certificate(key, csr)
87
+ csr_cert = OpenSSL::X509::Certificate.new
88
+ csr_cert.serial = 0
89
+ csr_cert.version = 2
90
+ csr_cert.not_before = Time.now - 60 * 60 * 24
91
+ csr_cert.not_after = Time.now + 94608000
92
+
93
+ csr_cert.subject = csr.subject
94
+ csr_cert.public_key = csr.public_key
95
+ csr_cert.issuer = csr.subject
96
+
97
+ csr_cert.sign key, OpenSSL::Digest::SHA1.new
98
+
99
+ csr_cert
100
+ end
101
+
102
+ def subject_string(common_name)
103
+ "/C=US/O=Pivotal/CN=#{common_name}"
104
+ end
105
+ end
106
+ end
107
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bosh
4
4
  module Common
5
- VERSION = "0.5.4"
5
+ VERSION = '1.5.0.pre.1100'
6
6
  end
7
7
  end
@@ -0,0 +1,53 @@
1
+ module Bosh::Common
2
+ class VersionNumber
3
+ include Comparable
4
+
5
+ def initialize(version_value)
6
+ @version = version_value.to_s
7
+ end
8
+
9
+ def <=>(other)
10
+ v1 = @version
11
+ v2 = other.to_s
12
+ return v1 <=> v2 if [v1, v2].all? { |v| v.to_s.match(/^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$/) }
13
+
14
+ vp1 = components
15
+ vp2 = other.components
16
+
17
+ [vp1.size, vp2.size].max.times do |i|
18
+ result = vp1[i].to_i <=> vp2[i].to_i
19
+ return result unless result == 0
20
+ end
21
+
22
+ 0
23
+ end
24
+
25
+ def major
26
+ components[0].to_i
27
+ end
28
+
29
+ def minor
30
+ components[1].to_i
31
+ end
32
+
33
+ def components
34
+ @version.split('.')
35
+ end
36
+
37
+ def to_s
38
+ @version
39
+ end
40
+
41
+ def final?
42
+ !@version.end_with?('-dev')
43
+ end
44
+
45
+ def next_minor
46
+ self.class.new("#{major}.#{minor + 1}")
47
+ end
48
+
49
+ def dev
50
+ final? ? self.class.new("#{@version}-dev") : self
51
+ end
52
+ end
53
+ end
metadata CHANGED
@@ -1,23 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bosh_common
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
5
- prerelease:
4
+ version: 1.5.0.pre.1100
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - VMware
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-01 00:00:00.000000000 Z
12
+ date: 2013-10-12 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: BOSH common
15
- email: support@vmware.com
14
+ description: ! 'BOSH common
15
+
16
+ a5984f'
17
+ email: support@cloudfoundry.com
16
18
  executables: []
17
19
  extensions: []
18
20
  extra_rdoc_files: []
19
21
  files:
20
22
  - lib/common/common.rb
23
+ - lib/common/deep_copy.rb
24
+ - lib/common/errors.rb
21
25
  - lib/common/exec.rb
22
26
  - lib/common/exec/error.rb
23
27
  - lib/common/exec/result.rb
@@ -25,21 +29,17 @@ files:
25
29
  - lib/common/properties/errors.rb
26
30
  - lib/common/properties/property_helper.rb
27
31
  - lib/common/properties/template_evaluation_context.rb
32
+ - lib/common/retryable.rb
33
+ - lib/common/runs_commands.rb
34
+ - lib/common/ssl.rb
28
35
  - lib/common/thread_formatter.rb
29
36
  - lib/common/thread_pool.rb
30
37
  - lib/common/version.rb
38
+ - lib/common/version_number.rb
31
39
  - README
32
- - Rakefile
33
- - spec/assets/foo1
34
- - spec/assets/foo2
35
- - spec/spec_helper.rb
36
- - spec/unit/common_spec.rb
37
- - spec/unit/exec_spec.rb
38
- - spec/unit/properties/property_helper_spec.rb
39
- - spec/unit/properties/template_evaluation_context_spec.rb
40
- - spec/unit/thread_pool_spec.rb
41
- homepage: http://www.vmware.com
42
- licenses: []
40
+ homepage: https://github.com/cloudfoundry/bosh
41
+ licenses:
42
+ - Apache 2.0
43
43
  post_install_message:
44
44
  rdoc_options: []
45
45
  require_paths:
@@ -49,26 +49,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
49
49
  requirements:
50
50
  - - ! '>='
51
51
  - !ruby/object:Gem::Version
52
- version: '0'
52
+ version: 1.9.3
53
53
  required_rubygems_version: !ruby/object:Gem::Requirement
54
54
  none: false
55
55
  requirements:
56
- - - ! '>='
56
+ - - ! '>'
57
57
  - !ruby/object:Gem::Version
58
- version: '0'
58
+ version: 1.3.1
59
59
  requirements: []
60
60
  rubyforge_project:
61
- rubygems_version: 1.8.24
61
+ rubygems_version: 1.8.23
62
62
  signing_key:
63
63
  specification_version: 3
64
64
  summary: BOSH common
65
- test_files:
66
- - spec/assets/foo1
67
- - spec/assets/foo2
68
- - spec/spec_helper.rb
69
- - spec/unit/common_spec.rb
70
- - spec/unit/exec_spec.rb
71
- - spec/unit/properties/property_helper_spec.rb
72
- - spec/unit/properties/template_evaluation_context_spec.rb
73
- - spec/unit/thread_pool_spec.rb
74
- has_rdoc:
65
+ test_files: []
data/Rakefile DELETED
@@ -1,50 +0,0 @@
1
- # Copyright (c) 2009-2012 VMware, Inc.
2
-
3
- $:.unshift(File.expand_path("../../rake", __FILE__))
4
-
5
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __FILE__)
6
-
7
- require "rubygems"
8
- require "bundler"
9
- Bundler.setup(:default, :test)
10
-
11
- require "rake"
12
- begin
13
- require "rspec/core/rake_task"
14
- rescue LoadError
15
- end
16
-
17
- require "bundler_task"
18
- require "ci_task"
19
-
20
- gem_helper = Bundler::GemHelper.new(Dir.pwd)
21
-
22
- desc "Build BOSH Common gem into the pkg directory"
23
- task "build" do
24
- gem_helper.build_gem
25
- end
26
-
27
- desc "Build and install BOSH Common into system gems"
28
- task "install" do
29
- Rake::Task["bundler:install"].invoke
30
- gem_helper.install_gem
31
- end
32
-
33
- BundlerTask.new
34
-
35
- if defined?(RSpec)
36
- namespace :spec do
37
- desc "Run Unit Tests"
38
- rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
39
- t.pattern = "spec/unit/**/*_spec.rb"
40
- t.rspec_opts = %w(--format progress --colour)
41
- end
42
-
43
- CiTask.new do |task|
44
- task.rspec_task = rspec_task
45
- end
46
- end
47
-
48
- desc "Run tests"
49
- task :spec => %w(spec:unit)
50
- end
data/spec/assets/foo1 DELETED
File without changes
data/spec/assets/foo2 DELETED
File without changes
data/spec/spec_helper.rb DELETED
@@ -1,13 +0,0 @@
1
- # Copyright (c) 2009-2012 VMware, Inc.
2
-
3
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
4
-
5
- require "rubygems"
6
- require "bundler"
7
- Bundler.setup(:default, :test)
8
-
9
- require "rspec"
10
-
11
- def asset(file)
12
- File.expand_path(File.join(File.dirname(__FILE__), "assets", file))
13
- end
@@ -1,59 +0,0 @@
1
- # Copyright (c) 2012 VMware, Inc.
2
-
3
- require "spec_helper"
4
-
5
- require "common/common"
6
-
7
- describe Bosh::Common do
8
-
9
- describe "#symbolize_keys" do
10
- ORIGINAL = {
11
- "foo1" => "bar",
12
- :foo2 => "bar",
13
- "foo3" => {
14
- "foo4" => "bar"
15
- }
16
- }.freeze
17
-
18
- EXPECTED = {
19
- :foo1 => "bar",
20
- :foo2 => "bar",
21
- :foo3 => {
22
- :foo4 => "bar"
23
- }
24
- }.freeze
25
-
26
- it "should not modify the original hash" do
27
- duplicate = ORIGINAL.dup
28
- Bosh::Common.symbolize_keys(ORIGINAL)
29
- ORIGINAL.should == duplicate
30
- end
31
-
32
- it "should return a new hash with all keys as symbols" do
33
- Bosh::Common.symbolize_keys(ORIGINAL).should == EXPECTED
34
- end
35
- end
36
-
37
- describe "#which" do
38
- let(:path) {
39
- path = ENV["PATH"]
40
- path += ":#{File.expand_path('../../assets', __FILE__)}"
41
- }
42
-
43
- it "should return the path when it finds the executable" do
44
- Bosh::Common.which("foo1", path).should_not be_nil
45
- end
46
-
47
- it "should return the path when it finds an executable" do
48
- Bosh::Common.which(%w[foo2 foo1], path).should match(%r{/foo1$})
49
- end
50
-
51
- it "should return nil when it isn't executable" do
52
- Bosh::Common.which("foo2", path).should be_nil
53
- end
54
-
55
- it "should return nil when it doesn't find an executable" do
56
- Bosh::Common.which("foo1").should be_nil
57
- end
58
- end
59
- end
@@ -1,114 +0,0 @@
1
- # Copyright (c) 2012 VMware, Inc.
2
-
3
- require "spec_helper"
4
- require "common/exec"
5
-
6
- describe Bosh::Exec do
7
- let(:opts) { {} }
8
-
9
- context "existing command" do
10
-
11
- context "executes successfully" do
12
- it "should not fail" do
13
- Bosh::Exec.sh("ls /", opts).failed?.should be_false
14
- end
15
-
16
- it "should execute block" do
17
- block = false
18
- Bosh::Exec.sh("ls /", opts) do
19
- block = true
20
- end
21
- block.should be_true
22
- end
23
- end
24
-
25
- context "fails to execute" do
26
- it "should raise error by default" do
27
- expect {
28
- Bosh::Exec.sh("ls /asdasd 2>&1", opts)
29
- }.to raise_error { |error|
30
- error.should be_a Bosh::Exec::Error
31
- error.output.should match /No such file or directory/
32
- }
33
- end
34
-
35
- it "should yield block on false" do
36
- opts[:yield] = :on_false
37
- block = false
38
- Bosh::Exec.sh("ls /asdasd 2>&1", opts) do
39
- block = true
40
- end
41
- block.should be_true
42
- end
43
-
44
- it "should return result" do
45
- opts[:on_error] = :return
46
- Bosh::Exec.sh("ls /asdasd 2>&1", opts).failed?.should be_true
47
- end
48
- end
49
-
50
- end
51
-
52
- context "missing command" do
53
- it "should raise error by default" do
54
- expect {
55
- Bosh::Exec.sh("/asdasd 2>&1", opts)
56
- }.to raise_error Bosh::Exec::Error
57
- end
58
-
59
- it "should not raise error when requested" do
60
- opts[:on_error] = :return
61
- expect {
62
- Bosh::Exec.sh("/asdasd 2>&1", opts)
63
- }.to_not raise_error Bosh::Exec::Error
64
- end
65
-
66
- it "should execute block when requested" do
67
- opts[:yield] = :on_false
68
- expect {
69
- Bosh::Exec.sh("/asdasd 2>&1", opts) do
70
- raise "foo"
71
- end
72
- }.to raise_error "foo"
73
- end
74
-
75
- end
76
-
77
- context "mock" do
78
- it "should be possible fake result" do
79
- cmd = "ls /"
80
- result = Bosh::Exec::Result.new(cmd, "output", 0)
81
- Bosh::Exec.should_receive(:sh).with(cmd).and_return(result)
82
- result = Bosh::Exec.sh(cmd)
83
- result.success?.should be_true
84
- end
85
- end
86
-
87
- context "module" do
88
- it "should be possible to invoke as a module" do
89
- Bosh::Exec.sh("ls /").success?.should be_true
90
- end
91
- end
92
-
93
- context "include" do
94
- class IncludeTest
95
- include Bosh::Exec
96
- def run
97
- sh("ls /")
98
- end
99
-
100
- def self.run
101
- sh("ls /")
102
- end
103
- end
104
-
105
- it "should add instance method" do
106
- inc = IncludeTest.new
107
- inc.run.success?.should be_true
108
- end
109
-
110
- it "should add class method" do
111
- IncludeTest.run.success?.should be_true
112
- end
113
- end
114
- end
@@ -1,39 +0,0 @@
1
- # Copyright (c) 2012 VMware, Inc.
2
-
3
- require "spec_helper"
4
- require "common/properties"
5
-
6
- describe Bosh::Common::PropertyHelper do
7
-
8
- before(:each) do
9
- @helper = Object.new
10
- @helper.extend(Bosh::Common::PropertyHelper)
11
- end
12
-
13
- it "can copy named property from one collection to another" do
14
- dst = {}
15
- src = {"foo" => {"bar" => "baz", "secret" => "zazzle"}}
16
-
17
- @helper.copy_property(dst, src, "foo.bar")
18
- dst.should == {"foo" => {"bar" => "baz"}}
19
-
20
- @helper.copy_property(dst, src, "no.such.prop", "default")
21
- dst.should == {
22
- "foo" => {"bar" => "baz"},
23
- "no" => {
24
- "such" => {"prop" => "default"}
25
- }
26
- }
27
- end
28
-
29
- it "can lookup the property in a Hash using dot-syntax" do
30
- properties = {
31
- "foo" => {"bar" => "baz"},
32
- "router" => {"token" => "foo"}
33
- }
34
-
35
- @helper.lookup_property(properties, "foo.bar").should == "baz"
36
- @helper.lookup_property(properties, "router").should == {"token" => "foo"}
37
- @helper.lookup_property(properties, "no.prop").should be_nil
38
- end
39
- end
@@ -1,112 +0,0 @@
1
- # Copyright (c) 2012 VMware, Inc.
2
-
3
- require "spec_helper"
4
- require "common/properties"
5
-
6
- describe Bosh::Common::TemplateEvaluationContext do
7
-
8
- def eval_template(erb, context)
9
- ERB.new(erb).result(context.get_binding)
10
- end
11
-
12
- def make(spec)
13
- Bosh::Common::TemplateEvaluationContext.new(spec)
14
- end
15
-
16
- before(:each) do
17
- @spec = {
18
- "job" => {
19
- "name" => "foobar"
20
- },
21
- "properties" => {
22
- "foo" => "bar",
23
- "router" => {"token" => "zbb"},
24
- "vtrue" => true,
25
- "vfalse" => false
26
- },
27
- "index" => 0,
28
- }
29
-
30
- @context = make(@spec)
31
- end
32
-
33
- it "unrolls properties into OpenStruct" do
34
- eval_template("<%= properties.foo %>", @context).should == "bar"
35
- end
36
-
37
- it "retains raw_properties" do
38
- eval_template("<%= raw_properties['router']['token'] %>", @context).
39
- should == "zbb"
40
- end
41
-
42
- it "supports looking up template index" do
43
- eval_template("<%= spec.index %>", @context).should == "0"
44
- end
45
-
46
- it "supports 'p' helper" do
47
- eval_template("<%= p('router.token') %>", @context).should == "zbb"
48
-
49
- eval_template("<%= p('vtrue') %>", @context).should == "true"
50
- eval_template("<%= p('vfalse') %>", @context).should == "false"
51
-
52
- expect {
53
- eval_template("<%= p('bar.baz') %>", @context)
54
- }.to raise_error(Bosh::Common::UnknownProperty,
55
- "Can't find property `[\"bar.baz\"]'")
56
- eval_template("<%= p('bar.baz', 22) %>", @context).should == "22"
57
- end
58
-
59
- it "supports chaining property lookup via 'p' helper" do
60
- eval_template(<<-TMPL, @context).strip.should == "zbb"
61
- <%= p(%w(a b router.token c)) %>
62
- TMPL
63
-
64
- expect {
65
- eval_template(<<-TMPL, @context)
66
- <%= p(%w(a b c)) %>
67
- TMPL
68
- }.to raise_error(Bosh::Common::UnknownProperty,
69
- "Can't find property `[\"a\", \"b\", \"c\"]'")
70
-
71
- eval_template(<<-TMPL, @context).strip.should == "22"
72
- <%= p(%w(a b c), 22) %>
73
- TMPL
74
- end
75
-
76
- it "allows 'false' and 'nil' defaults for 'p' helper" do
77
- eval_template(<<-TMPL, @context).strip.should == "false"
78
- <%= p(%w(a b c), false) %>
79
- TMPL
80
-
81
- eval_template(<<-TMPL, @context).strip.should == ""
82
- <%= p(%w(a b c), nil) %>
83
- TMPL
84
- end
85
-
86
- it "supports 'if_p' helper" do
87
- template = <<-TMPL
88
- <% if_p("router.token") do |token| %>
89
- <%= token %>
90
- <% end %>
91
- TMPL
92
-
93
- eval_template(template, @context).strip.should == "zbb"
94
-
95
- template = <<-TMPL
96
- <% if_p("router.token", "foo") do |token, foo| %>
97
- <%= token %>, <%= foo %>
98
- <% end %>
99
- TMPL
100
-
101
- eval_template(template, @context).strip.should == "zbb, bar"
102
-
103
- template = <<-TMPL
104
- <% if_p("router.token", "no.such.prop") do |token, none| %>
105
- test output
106
- <% end %>
107
- TMPL
108
-
109
- eval_template(template, @context).strip.should == ""
110
- end
111
-
112
- end
@@ -1,69 +0,0 @@
1
- # Copyright (c) 2009-2012 VMware, Inc.
2
-
3
- require File.expand_path("../../spec_helper", __FILE__)
4
-
5
- require "common/thread_pool"
6
-
7
- describe Bosh::ThreadPool do
8
-
9
- before(:all) do
10
- @logger = Logger.new(STDOUT)
11
- @logger.level = Logger::INFO
12
- end
13
-
14
- it "should respect max threads" do
15
- max = 0
16
- current = 0
17
- lock = Mutex.new
18
-
19
- Bosh::ThreadPool.new(:max_threads => 2, :logger => @logger).wrap do |pool|
20
- 4.times do
21
- pool.process do
22
- lock.synchronize do
23
- current += 1
24
- max = current if current > max
25
- end
26
- sleep(0.050)
27
- lock.synchronize do
28
- max = current if current > max
29
- current -= 1
30
- end
31
- end
32
- end
33
- end
34
- max.should be <= 2
35
- end
36
-
37
- it "should raise exceptions" do
38
- lambda {
39
- Bosh::ThreadPool.new(:max_threads => 2, :logger => @logger).wrap do |pool|
40
- 5.times do |index|
41
- pool.process do
42
- sleep(0.050)
43
- raise "bad" if index == 4
44
- end
45
- end
46
- end
47
- }.should raise_exception("bad")
48
- end
49
-
50
- it "should stop processing new work when there was an exception" do
51
- max = 0
52
- lock = Mutex.new
53
-
54
- lambda {
55
- Bosh::ThreadPool.new(:max_threads => 1, :logger => @logger).wrap do |pool|
56
- 10.times do |index|
57
- pool.process do
58
- lock.synchronize { max = index if index > max }
59
- sleep(0.050)
60
- raise "bad" if index == 4
61
- end
62
- end
63
- end
64
- }.should raise_exception("bad")
65
-
66
- max.should be == 4
67
- end
68
-
69
- end