derelict 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +5 -13
  2. data/.cane +2 -0
  3. data/.coveralls.yml +1 -0
  4. data/.travis.yml +13 -0
  5. data/README.md +55 -9
  6. data/Rakefile +21 -0
  7. data/derelict.gemspec +25 -1
  8. data/lib/derelict/connection/invalid.rb +14 -0
  9. data/lib/derelict/connection/not_found.rb +13 -0
  10. data/lib/derelict/connection.rb +84 -0
  11. data/lib/derelict/exception/optional_reason.rb +32 -0
  12. data/lib/derelict/exception.rb +3 -2
  13. data/lib/derelict/instance/command_failed.rb +28 -0
  14. data/lib/derelict/instance/invalid.rb +11 -11
  15. data/lib/derelict/instance/missing_binary.rb +13 -0
  16. data/lib/derelict/instance/non_directory.rb +10 -8
  17. data/lib/derelict/instance/not_found.rb +10 -8
  18. data/lib/derelict/instance.rb +105 -33
  19. data/lib/derelict/parser/status/invalid_format.rb +16 -0
  20. data/lib/derelict/parser/status.rb +89 -0
  21. data/lib/derelict/parser/version/invalid_format.rb +16 -0
  22. data/lib/derelict/parser/version.rb +28 -0
  23. data/lib/derelict/parser.rb +25 -0
  24. data/lib/derelict/utils/logger/array_outputter.rb +43 -0
  25. data/lib/derelict/utils/logger/invalid_type.rb +15 -0
  26. data/lib/derelict/utils/logger/raw_formatter.rb +12 -0
  27. data/lib/derelict/utils/logger.rb +51 -0
  28. data/lib/derelict/utils.rb +11 -0
  29. data/lib/derelict/version.rb +2 -2
  30. data/lib/derelict/virtual_machine/invalid.rb +14 -0
  31. data/lib/derelict/virtual_machine/not_found.rb +18 -0
  32. data/lib/derelict/virtual_machine.rb +154 -0
  33. data/lib/derelict.rb +61 -14
  34. data/spec/coverage_helper.rb +16 -0
  35. data/spec/derelict/connection/invalid_spec.rb +16 -0
  36. data/spec/derelict/connection/not_found_spec.rb +13 -0
  37. data/spec/derelict/connection_spec.rb +107 -0
  38. data/spec/derelict/exception/optional_reason_spec.rb +41 -0
  39. data/spec/derelict/exception_spec.rb +11 -0
  40. data/spec/derelict/instance/command_failed_spec.rb +40 -0
  41. data/spec/derelict/instance/invalid_spec.rb +16 -0
  42. data/spec/derelict/instance/missing_binary_spec.rb +13 -0
  43. data/spec/derelict/instance/non_directory_spec.rb +13 -0
  44. data/spec/derelict/instance/not_found_spec.rb +13 -0
  45. data/spec/derelict/instance_spec.rb +226 -0
  46. data/spec/derelict/parser/status/invalid_format_spec.rb +16 -0
  47. data/spec/derelict/parser/status_spec.rb +214 -0
  48. data/spec/derelict/parser/version/invalid_format_spec.rb +16 -0
  49. data/spec/derelict/parser/version_spec.rb +31 -0
  50. data/spec/derelict/parser_spec.rb +24 -0
  51. data/spec/derelict/utils/logger/array_outputter_spec.rb +40 -0
  52. data/spec/derelict/utils/logger/invalid_type_spec.rb +13 -0
  53. data/spec/derelict/utils/logger/raw_formatter_spec.rb +17 -0
  54. data/spec/derelict/utils/logger_spec.rb +35 -0
  55. data/spec/derelict/virtual_machine/invalid_spec.rb +16 -0
  56. data/spec/derelict/virtual_machine/not_found_spec.rb +34 -0
  57. data/spec/derelict/virtual_machine_spec.rb +295 -0
  58. data/spec/derelict_spec.rb +50 -0
  59. data/spec/spec_helper.rb +28 -3
  60. data/spec/support/log_context.rb +36 -0
  61. metadata +175 -22
  62. data/lib/derelict/instance/already_active.rb +0 -9
  63. data/spec/system_spec.spec +0 -10
@@ -0,0 +1,89 @@
1
+ module Derelict
2
+ # Parses the output of "vagrant status"
3
+ class Parser::Status < Parser
4
+ autoload :InvalidFormat, "derelict/parser/status/invalid_format"
5
+
6
+ # Include "memoize" class method to memoize methods
7
+ extend Memoist
8
+
9
+ # Regexp to extract the VM list from the "vagrant status" output
10
+ PARSE_LIST_FROM_OUTPUT = /\n\n((?:.*\n)+)\n/
11
+
12
+ # Regexp to extract the state from a line in the VM list
13
+ PARSE_STATE_FROM_LIST_ITEM = %r[
14
+ ^(.*?) # VM name starts at the start of the line,
15
+ \s{2,} # to the first instance of 2 or more spaces.
16
+ (.*?) # VM state starts after the whitespace,
17
+ \s+\( # continuing until whitespace and open bracket.
18
+ (.*) # The provider name starts after the bracket,
19
+ \)$ # and ends at a closing bracket at line end.
20
+ ]x # Ignore whitespace to allow these comments
21
+
22
+ # Retrieves the names of all virtual machines in the output
23
+ #
24
+ # The names are returned as a Set of symbols.
25
+ def vm_names
26
+ Set[*states.keys]
27
+ end
28
+
29
+ # Determines if a particular virtual machine exists in the output
30
+ #
31
+ # * vm_name: The name of the virtual machine to look for
32
+ def exists?(vm_name)
33
+ vm_names.include? vm_name.to_sym
34
+ end
35
+
36
+ # Determines the state of a particular virtual machine
37
+ #
38
+ # The state is returned as a symbol, e.g. :running.
39
+ #
40
+ # * vm_name: The name of the virtual machine to retrieve state
41
+ def state(vm_name)
42
+ unless states.include? vm_name.to_sym
43
+ raise Derelict::VirtualMachine::NotFound.new vm_name
44
+ end
45
+
46
+ states[vm_name.to_sym]
47
+ end
48
+
49
+ # Provides a description of this Parser
50
+ #
51
+ # Mainly used for log messages.
52
+ def description
53
+ "Derelict::Parser::Status instance"
54
+ end
55
+
56
+ private
57
+ # Retrieves the virtual machine list section of the output
58
+ def vm_lines
59
+ output.match(PARSE_LIST_FROM_OUTPUT).tap {|list|
60
+ logger.debug "Parsing VM list from output using #{description}"
61
+ raise InvalidFormat.new "Couldn't find VM list" if list.nil?
62
+ }.captures[0].lines
63
+ end
64
+ memoize :vm_lines
65
+
66
+ # Retrieves the state data for all virtual machines in the output
67
+ #
68
+ # The state is returned as a Hash, mapping virtual machine names
69
+ # (as symbols) to their state (also as a symbol). Both of these
70
+ # symbols have spaces converted to underscores (for convenience
71
+ # when writing literals in other code).
72
+ def states
73
+ logger.debug "Parsing states from VM list using #{description}"
74
+ vm_lines.inject Hash.new do |hash, line|
75
+ hash.merge! parse_line(line.match PARSE_STATE_FROM_LIST_ITEM)
76
+ end
77
+ end
78
+ memoize :states
79
+
80
+ def parse_line(match)
81
+ raise InvalidFormat.new "Couldn't parse VM list" if match.nil?
82
+ Hash[*match.captures[0..1].map {|value| sanitize value }]
83
+ end
84
+
85
+ def sanitize(value)
86
+ value.to_s.gsub(/\s+/, "_").downcase.to_sym
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,16 @@
1
+ module Derelict
2
+ class Parser
3
+ class Version
4
+ # The version wasn't in the expected format and couldn't be parsed
5
+ class InvalidFormat < Derelict::Exception
6
+ include Derelict::Exception::OptionalReason
7
+
8
+ private
9
+ # Retrieves the default error message
10
+ def default_message
11
+ "Output from 'vagrant --version' was in an unexpected format"
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ module Derelict
2
+ # Parses the output of "vagrant --version"
3
+ class Parser::Version < Parser
4
+ autoload :InvalidFormat, "derelict/parser/version/invalid_format"
5
+
6
+ # Include "memoize" class method to memoize methods
7
+ extend Memoist
8
+
9
+ # Regexp to extract the version from the "vagrant --version" output
10
+ PARSE_VERSION_FROM_OUTPUT = /^Vagrant v(?:ersion )?(.*)?$/
11
+
12
+ # Determines the version of Vagrant based on the output
13
+ def version
14
+ logger.debug "Parsing version from output using #{description}"
15
+ matches = output.match PARSE_VERSION_FROM_OUTPUT
16
+ raise InvalidFormat.new output if matches.nil?
17
+ matches.captures[0]
18
+ end
19
+ memoize :version
20
+
21
+ # Provides a description of this Parser
22
+ #
23
+ # Mainly used for log messages.
24
+ def description
25
+ "Derelict::Parser::Version instance"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ module Derelict
2
+ # Base class for parsers, which extract data from command output
3
+ class Parser
4
+ autoload :Status, "derelict/parser/status"
5
+ autoload :Version, "derelict/parser/version"
6
+
7
+ # Include "logger" method to get a logger for this class
8
+ include Utils::Logger
9
+
10
+ attr_reader :output
11
+
12
+ # Initializes the parser with the output it will be parsing
13
+ def initialize(output)
14
+ @output = output
15
+ logger.debug "Successfully initialized #{description}"
16
+ end
17
+
18
+ # Provides a description of this Parser
19
+ #
20
+ # Mainly used for log messages.
21
+ def description
22
+ "Derelict::Parser (unknown type)"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,43 @@
1
+ module Derelict
2
+ module Utils
3
+ module Logger
4
+ # A Log4r Outputter which stores all logs in an array
5
+ #
6
+ # Logs are stored in the internal array by #write. Logs can be
7
+ # cleared using #flush, which returns the flushed logs too.
8
+ class ArrayOutputter < Log4r::Outputter
9
+ # Include "memoize" class method to memoize methods
10
+ extend Memoist
11
+
12
+ # Force the outputter to receive and store all levels of messages
13
+ def level
14
+ Log4r::ALL
15
+ end
16
+
17
+ # The internal array of messages
18
+ def messages
19
+ []
20
+ end
21
+ memoize :messages
22
+
23
+ # Clear internal log messages array and return the erased data
24
+ def flush
25
+ messages.dup.tap { messages.clear }
26
+ end
27
+
28
+ private
29
+
30
+ # Write a message to the internal array
31
+ #
32
+ # This is an abstract method in the parent class, and handles
33
+ # persisting the log data. In this class, it saves the message
34
+ # into an internal array to be retrieved later.
35
+ #
36
+ # * message: The log message to be persisted
37
+ def write(message)
38
+ messages << message
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ module Derelict
2
+ module Utils
3
+ module Logger
4
+ # The "type" option when requesting the logger was invalid
5
+ class InvalidType < ::Derelict::Exception
6
+ # Initializes a new instance of this exception for a type
7
+ #
8
+ # * type: The (invalid) requested type
9
+ def initialize(type)
10
+ super "Invalid logger type '#{type}'"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module Derelict
2
+ module Utils
3
+ module Logger
4
+ # A Formatter that passes the log message through untouched
5
+ class RawFormatter < Log4r::Formatter
6
+ def format(event)
7
+ event.data
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,51 @@
1
+ module Derelict
2
+ module Utils
3
+ # Provides a method to retrieve a logger
4
+ module Logger
5
+ autoload :ArrayOutputter, "derelict/utils/logger/array_outputter"
6
+ autoload :InvalidType, "derelict/utils/logger/invalid_type"
7
+ autoload :RawFormatter, "derelict/utils/logger/raw_formatter"
8
+
9
+ # Retrieves the logger for this class
10
+ def logger(options = {})
11
+ options = {:type => :internal}.merge(options)
12
+
13
+ case options[:type].to_sym
14
+ when :external
15
+ external_logger
16
+ when :internal
17
+ find_or_create_logger(logger_name)
18
+ else raise InvalidType.new options[:type]
19
+ end
20
+ end
21
+
22
+ private
23
+ # Finds or creates a Logger with a particular fullname
24
+ def find_or_create_logger(fullname)
25
+ Log4r::Logger[fullname.to_s] || Log4r::Logger.new(fullname.to_s)
26
+ end
27
+
28
+ # Gets the "external" logger, used to print to stdout
29
+ def external_logger
30
+ @@external ||= find_or_create_logger("external").tap do |external|
31
+ logger.debug "Created external logger instance"
32
+ external.add(Log4r::Outputter.stdout.tap do |outputter|
33
+ outputter.formatter = RawFormatter.new
34
+ end)
35
+ end
36
+ end
37
+
38
+ # Retrieves the name of the logger for this class
39
+ #
40
+ # By default, the name of the logger is just the lowercase
41
+ # version of the class name.
42
+ def logger_name
43
+ if self.is_a? Module
44
+ self.name.downcase
45
+ else
46
+ self.class.name.downcase
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,11 @@
1
+ module Derelict
2
+ # A namespaced collection of utilities for general purpose use
3
+ #
4
+ # Derelict::Utils contains all the individual sub-modules inside it.
5
+ module Utils
6
+ autoload :Logger, "derelict/utils/logger"
7
+
8
+ # Include sub-modules here
9
+ include Derelict::Utils::Logger
10
+ end
11
+ end
@@ -1,3 +1,3 @@
1
- class Derelict
2
- VERSION = "0.0.1"
1
+ module Derelict
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,14 @@
1
+ module Derelict
2
+ class VirtualMachine
3
+ # Represents an invalid virtual machine, which Derelict can't use
4
+ class Invalid < ::Derelict::Exception
5
+ include Derelict::Exception::OptionalReason
6
+
7
+ private
8
+ # Retrieves the default error message
9
+ def default_message
10
+ "Invalid Derelict virtual machine"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ module Derelict
2
+ class VirtualMachine
3
+ # The requested virtual machine isn't defined in the Vagrantfile
4
+ class NotFound < Invalid
5
+ # Initializes a new instance of this exception for a given name
6
+ #
7
+ # * name: The requested name of the virtual machine
8
+ # * connection: The Derelict connection used for this VM
9
+ def initialize(name, connection = nil)
10
+ if connection.respond_to? :path
11
+ super "Virtual machine #{name} not found in #{connection.path}"
12
+ else
13
+ super "Virtual machine #{name} not found"
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,154 @@
1
+ module Derelict
2
+ # A Vagrant virtual machine in a particular Derelict connection
3
+ class VirtualMachine
4
+ autoload :Invalid, "derelict/virtual_machine/invalid"
5
+ autoload :NotFound, "derelict/virtual_machine/not_found"
6
+
7
+ # Include "memoize" class method to memoize methods
8
+ extend Memoist
9
+
10
+ # Include "logger" method to get a logger for this class
11
+ include Utils::Logger
12
+
13
+ COMMANDS = [
14
+ :up,
15
+ :halt,
16
+ :destroy,
17
+ :reload,
18
+ :suspend,
19
+ :resume,
20
+ ]
21
+
22
+ attr_reader :connection
23
+ attr_reader :name
24
+
25
+ # Initializes a new VirtualMachine for a connection and name
26
+ #
27
+ # * connection: The +Derelict::Connection+ to use to manipulate
28
+ # the VirtualMachine instance
29
+ # * name: The name of the virtual machine, used when
30
+ # communicating with the connection)
31
+ def initialize(connection, name)
32
+ @connection = connection
33
+ @name = name
34
+ logger.debug "Successfully initialized #{description}"
35
+ end
36
+
37
+ # Validates the data used for this connection
38
+ #
39
+ # Raises exceptions on failure:
40
+ #
41
+ # * +Derelict::VirtualMachine::NotFound+ if the connection
42
+ # doesn't know about a virtual machine with the requested
43
+ # name
44
+ def validate!
45
+ logger.debug "Starting validation for #{description}"
46
+ raise NotFound.new name, connection unless exists?
47
+ logger.info "Successfully validated #{description}"
48
+ self
49
+ end
50
+
51
+ # Determines whether this Vagrant virtual machine exists
52
+ #
53
+ # Returns +true+ if the connection reports a virtual machine with
54
+ # the requested name, otherwise returns +false+.
55
+ def exists?
56
+ status.exists? name
57
+ end
58
+ memoize :exists?
59
+
60
+ # Gets the current state of this Vagrant virtual machine
61
+ #
62
+ # The state is returned as a symbol, e.g. :running.
63
+ def state
64
+ status.state name
65
+ end
66
+ memoize :state
67
+
68
+ # Determines whether this virtual machine is currently running
69
+ def running?
70
+ (state == :running)
71
+ end
72
+ memoize :running?
73
+
74
+ # Add methods for each command
75
+ #
76
+ # A method is defined for each of the symbols in COMMANDS. The
77
+ # method name will be the symbol with an added bang (!). For
78
+ # example, #up!, #halt!, etc.
79
+ #
80
+ # Each method takes an options hash as an argument. For example:
81
+ #
82
+ # vm.up! :log => true
83
+ #
84
+ # This example will run the "up" command with logging enabled. The
85
+ # option keys can optionally include any of the following symbols:
86
+ #
87
+ # * log: Should the log output be printed? (defaults to false)
88
+ COMMANDS.each do |command|
89
+ define_method :"#{command}!" do |options|
90
+ # Log message if there's one for this command
91
+ message = log_message_for command
92
+ logger.info message unless message.nil?
93
+
94
+ # Set defaults for the options hash
95
+ options = {:log => false}.merge options
96
+
97
+ # Execute the command, optionally logging output
98
+ log_block = options[:log] ? shell_log_block : nil
99
+ connection.execute! command, name, *arguments_for(command), &log_block
100
+ end
101
+ end
102
+
103
+ # Retrieves the (parsed) status from the connection
104
+ def status
105
+ logger.info "Retrieving Vagrant status for #{description}"
106
+ output = connection.execute!(:status).stdout
107
+ Derelict::Parser::Status.new(output)
108
+ end
109
+ memoize :status
110
+
111
+ # Provides a description of this Connection
112
+ #
113
+ # Mainly used for log messages.
114
+ def description
115
+ "Derelict::VirtualMachine '#{name}' from #{connection.description}"
116
+ end
117
+
118
+ private
119
+ # A block that can be passed to #execute to log the output
120
+ def shell_log_block
121
+ Proc.new do |line|
122
+ logger(:type => :external).info line
123
+ end
124
+ end
125
+ memoize :shell_log_block
126
+
127
+ # Retrieves the arguments for a particular action
128
+ #
129
+ # * action: The symbol representing the action (one of :up,
130
+ # :halt, :destroy, :reload, :suspend, :resume)
131
+ def arguments_for(action)
132
+ case action
133
+ when :destroy then ['--force']
134
+ else []
135
+ end
136
+ end
137
+
138
+ # Retrieves the correct log message for a particular action
139
+ #
140
+ # * action: The symbol representing the action (one of :up,
141
+ # :halt, :destroy, :reload, :suspend, :resume)
142
+ def log_message_for(action)
143
+ case action
144
+ when :up then "Bringing up #{description}"
145
+ when :halt then "Halting #{description}"
146
+ when :destroy then "Destroying #{description}"
147
+ when :reload then "Reloading #{description}"
148
+ when :suspend then "Suspending #{description}"
149
+ when :resume then "Resuming #{description}"
150
+ else nil
151
+ end
152
+ end
153
+ end
154
+ end
data/lib/derelict.rb CHANGED
@@ -1,22 +1,69 @@
1
- require "rubygems"
2
1
  require "derelict/version"
2
+ require "log4r"
3
+ require "memoist"
4
+ require "shell/executer"
3
5
 
4
- # Controls a Vagrant instance
5
- class Derelict
6
- autoload :Instance, "derelict/instance"
7
- autoload :Exception, "derelict/exception"
6
+ Log4r::Logger["root"] # creates the level constants (INFO, etc).
8
7
 
9
- # Connects to an instance of Vagrant installed via Installer package
8
+ # Main module/entry point for Derelict
9
+ module Derelict
10
+ autoload :Connection, "derelict/connection"
11
+ autoload :Exception, "derelict/exception"
12
+ autoload :Instance, "derelict/instance"
13
+ autoload :Parser, "derelict/parser"
14
+ autoload :Utils, "derelict/utils"
15
+ autoload :VirtualMachine, "derelict/virtual_machine"
16
+
17
+ # Make functions accessible by Derelict.foo and private when included
18
+ module_function
19
+
20
+ # Include "logger" method to get a logger for this class
21
+ extend Utils::Logger
22
+
23
+ # Creates a new Derelict instance for a Vagrant installation
10
24
  #
11
- # path: The path to the location of the Vagrant instance
12
- def self.connect(path)
13
- Instance.new path
25
+ # * path: The path to the Vagrant installation (optional, defaults
26
+ # to Instance::DEFAULT_PATH)
27
+ def instance(path = Instance::DEFAULT_PATH)
28
+ logger.info "Creating and validating new instance for '#{path}'"
29
+ Instance.new(path).validate!
14
30
  end
15
31
 
16
- # Determines if an instance is currently active
17
- def self.active?
18
- Module.const_get("::Vagrant").is_a?(Class)
19
- rescue NameError
20
- false
32
+ # Enables (or disables) Derelict's debug mode
33
+ #
34
+ # When in debug mode, Derelict will log to stderr. The debug level
35
+ # can be controlled as well (which affects the verbosity of the
36
+ # logging).
37
+ #
38
+ # Valid (symbol) keys for the options hash include:
39
+ #
40
+ # * enabled: Whether debug mode should be enabled (defaults to true)
41
+ # * level: Allows setting a custom log level (defaults to INFO)
42
+ def debug!(options = {})
43
+ options = debug_options_defaults.merge options
44
+ logger.level = options[:enabled] ? options[:level] : Log4r::OFF
45
+
46
+ if options[:enabled]
47
+ logger.add stderr unless logger.outputters.include? stderr
48
+ logger.info "enabling debug mode"
49
+ else
50
+ logger.info "disabling debug mode"
51
+ logger.remove "stderr"
52
+ end
53
+
54
+ self
21
55
  end
56
+
57
+ private
58
+ # Retrieves the default values for the options hash for #debug!
59
+ def self.debug_options_defaults
60
+ {
61
+ :enabled => true,
62
+ :level => Log4r::INFO,
63
+ }
64
+ end
65
+
66
+ def self.stderr
67
+ Log4r::Outputter.stderr
68
+ end
22
69
  end
@@ -0,0 +1,16 @@
1
+ if ENV['TRAVIS']
2
+ # Running on Travis CI: initialize Coveralls to submit coverage data
3
+ require "coveralls"
4
+ Coveralls.wear!
5
+ else
6
+ # Not running on Travis CI: Run SimpleCov locally for coverage data
7
+ # Since SimpleCov requires Ruby 1.9+, only include it if we're
8
+ # running on a compatible version.
9
+ version_major = RbConfig::CONFIG["MAJOR"].to_i
10
+ version_minor = RbConfig::CONFIG["MINOR"].to_i
11
+ if version_major >= 1 and version_minor >= 9
12
+ require "simplecov"
13
+ SimpleCov.start
14
+ end
15
+ end
16
+
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Connection::Invalid do
4
+ it "is autoloaded" do
5
+ should be_a Derelict::Connection::Invalid
6
+ end
7
+
8
+ context "when using default reason" do
9
+ its(:message) { should eq "Invalid Derelict connection" }
10
+ end
11
+
12
+ context "when using custom reason" do
13
+ subject { Derelict::Connection::Invalid.new "reason" }
14
+ its(:message) { should eq "Invalid Derelict connection: reason" }
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Connection::NotFound do
4
+ subject { Derelict::Connection::NotFound.new "/foo/bar" }
5
+
6
+ it "is autoloaded" do
7
+ should be_a Derelict::Connection::NotFound
8
+ end
9
+
10
+ its(:message) {
11
+ should eq "Invalid Derelict connection: Vagrantfile not found for /foo/bar"
12
+ }
13
+ end