virtualbox 0.2.0 → 0.3.0
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/.yardopts +1 -0
- data/TODO +0 -1
- data/VERSION +1 -1
- data/docs/WhatsNew.md +41 -0
- data/lib/virtualbox.rb +1 -0
- data/lib/virtualbox/abstract_model.rb +31 -0
- data/lib/virtualbox/abstract_model/validatable.rb +44 -0
- data/lib/virtualbox/attached_device.rb +15 -3
- data/lib/virtualbox/exceptions.rb +1 -2
- data/lib/virtualbox/hard_drive.rb +13 -0
- data/lib/virtualbox/shared_folder.rb +243 -0
- data/lib/virtualbox/vm.rb +2 -0
- data/test/virtualbox/abstract_model/validatable_test.rb +125 -0
- data/test/virtualbox/abstract_model_test.rb +49 -0
- data/test/virtualbox/attached_device_test.rb +44 -10
- data/test/virtualbox/hard_drive_test.rb +36 -0
- data/test/virtualbox/shared_folder_test.rb +231 -0
- data/test/virtualbox/vm_test.rb +12 -1
- data/virtualbox.gemspec +9 -2
- metadata +9 -2
data/.yardopts
CHANGED
data/TODO
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/docs/WhatsNew.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# What's New in 0.3.x?
|
2
|
+
|
3
|
+
## Shared Folders
|
4
|
+
|
5
|
+
Shared folders are a great feature of VirtualBox which allows the host system
|
6
|
+
to share data with guest systems easily using the native filesystem. Attaching,
|
7
|
+
modifying, and removing these shared folders are now supported. A quick example
|
8
|
+
below:
|
9
|
+
|
10
|
+
vm = VirtualBox::VM.find("FooVM")
|
11
|
+
folder = VirtualBox::SharedFolder.new
|
12
|
+
folder.name = "hosthome"
|
13
|
+
folder.hostpath = "/home/username"
|
14
|
+
vm.shared_folders << folder
|
15
|
+
vm.save
|
16
|
+
|
17
|
+
For full documentation on this new feature, read about them at
|
18
|
+
{VirtualBox::SharedFolder}.
|
19
|
+
|
20
|
+
## Validations
|
21
|
+
|
22
|
+
Many of the models for the virtualbox library now come complete with data
|
23
|
+
validations. These validations are performed within the library itself prior to
|
24
|
+
calling the virtualbox commands. They work very much the same was as ActiveRecord
|
25
|
+
validations:
|
26
|
+
|
27
|
+
sf = VirtualBox::SharedFolder.new(hash_of_values)
|
28
|
+
if !sf.valid?
|
29
|
+
puts "#{sf.errors.length} errors with the folder"
|
30
|
+
else
|
31
|
+
sf.save
|
32
|
+
end
|
33
|
+
|
34
|
+
In addition to `valid?` there is `errors` which returns a hash of all the errors,
|
35
|
+
including errors on relationships. There is also the `validate` method which
|
36
|
+
runs the validations, but you really shouldn't have the need to call that directly.
|
37
|
+
|
38
|
+
All validations are run automatically on `save`, which will return `false` if
|
39
|
+
they fail. If you choose to raise errors on the save, a `ValidationFailedException`
|
40
|
+
will be raised (in contrast to a `CommandFailedException`, which serves its own
|
41
|
+
role).
|
data/lib/virtualbox.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'virtualbox/abstract_model/attributable'
|
2
2
|
require 'virtualbox/abstract_model/dirty'
|
3
3
|
require 'virtualbox/abstract_model/relatable'
|
4
|
+
require 'virtualbox/abstract_model/validatable'
|
4
5
|
|
5
6
|
module VirtualBox
|
6
7
|
# AbstractModel is the base class used for most of virtualbox's classes.
|
@@ -11,6 +12,7 @@ module VirtualBox
|
|
11
12
|
include Attributable
|
12
13
|
include Dirty
|
13
14
|
include Relatable
|
15
|
+
include Validatable
|
14
16
|
|
15
17
|
# Returns a boolean denoting if the record is new or existing. This
|
16
18
|
# method is provided for subclasses to use to differentiate between
|
@@ -36,6 +38,35 @@ module VirtualBox
|
|
36
38
|
@new_record = false
|
37
39
|
end
|
38
40
|
|
41
|
+
# Returns the errors for a model.
|
42
|
+
def errors
|
43
|
+
error_hash = super
|
44
|
+
|
45
|
+
self.class.relationships.each do |name, options|
|
46
|
+
next unless options && options[:klass].respond_to?(:errors_for_relationship)
|
47
|
+
relationship_errors = options[:klass].errors_for_relationship(self, relationship_data[name])
|
48
|
+
|
49
|
+
error_hash.merge!({ :foos => relationship_errors }) if relationship_errors.length > 0
|
50
|
+
end
|
51
|
+
|
52
|
+
error_hash
|
53
|
+
end
|
54
|
+
|
55
|
+
# Validates the model and relationships.
|
56
|
+
def validate(*args)
|
57
|
+
# First clear all previous errors
|
58
|
+
clear_errors
|
59
|
+
|
60
|
+
# Then do the validations
|
61
|
+
failed = false
|
62
|
+
self.class.relationships.each do |name, options|
|
63
|
+
next unless options && options[:klass].respond_to?(:validate_relationship)
|
64
|
+
failed = true if !options[:klass].validate_relationship(self, relationship_data[name], *args)
|
65
|
+
end
|
66
|
+
|
67
|
+
return !failed
|
68
|
+
end
|
69
|
+
|
39
70
|
# Saves the model attributes and relationships.
|
40
71
|
#
|
41
72
|
# The method can be passed any arbitrary arguments, which are
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module VirtualBox
|
2
|
+
class AbstractModel
|
3
|
+
# Provides validation methods for a class. Unlike ActiveRecord,
|
4
|
+
# validations are instance-level rather than class-level.
|
5
|
+
module Validatable
|
6
|
+
def errors
|
7
|
+
@errors ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_error(field, error)
|
11
|
+
errors[field] ||= []
|
12
|
+
errors[field].push(error)
|
13
|
+
end
|
14
|
+
|
15
|
+
def clear_errors
|
16
|
+
@errors = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid?
|
20
|
+
validate
|
21
|
+
errors.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
# Subclasses should override this method.
|
25
|
+
def validate
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def validates_presence_of(field)
|
30
|
+
if field.is_a?(Array)
|
31
|
+
field.map { |v| validates_presence_of(v) }.all? { |v| v == true }
|
32
|
+
else
|
33
|
+
value = send(field)
|
34
|
+
if value.nil? || value == ""
|
35
|
+
add_error(field, "must not be blank.")
|
36
|
+
return false
|
37
|
+
else
|
38
|
+
return true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -140,16 +140,28 @@ module VirtualBox
|
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
143
|
+
# Validates an attached device.
|
144
|
+
def validate
|
145
|
+
super
|
146
|
+
|
147
|
+
validates_presence_of :parent
|
148
|
+
validates_presence_of :image
|
149
|
+
validates_presence_of :port
|
150
|
+
end
|
151
|
+
|
143
152
|
# Saves or creates an attached device.
|
144
153
|
#
|
145
154
|
# @param [Boolean] raise_errors If true, {Exceptions::CommandFailedException}
|
146
155
|
# will be raised if the command failed.
|
147
156
|
# @return [Boolean] True if command was successful, false otherwise.
|
148
|
-
def save(raise_errors=false)
|
149
|
-
raise Exceptions::NoParentException.new if parent.nil?
|
150
|
-
raise Exceptions::InvalidObjectException.new("Image must be set") if image.nil?
|
157
|
+
def save(raise_errors=false)
|
151
158
|
return true unless changed?
|
152
159
|
|
160
|
+
if !valid?
|
161
|
+
raise Exceptions::ValidationFailedException.new(errors) if raise_errors
|
162
|
+
return false
|
163
|
+
end
|
164
|
+
|
153
165
|
# If the port changed, we have to destroy the old one, then create
|
154
166
|
# a new one
|
155
167
|
destroy({:port => port_was}, raise_errors) if port_changed? && !port_was.nil?
|
@@ -5,9 +5,8 @@ module VirtualBox
|
|
5
5
|
class Exception < ::Exception; end
|
6
6
|
|
7
7
|
class CommandFailedException < Exception; end
|
8
|
-
class InvalidObjectException < Exception; end
|
9
8
|
class InvalidRelationshipObjectException < Exception; end
|
10
9
|
class NonSettableRelationshipException < Exception; end
|
11
|
-
class
|
10
|
+
class ValidationFailedException < Exception; end
|
12
11
|
end
|
13
12
|
end
|
@@ -138,6 +138,14 @@ module VirtualBox
|
|
138
138
|
"hdd"
|
139
139
|
end
|
140
140
|
|
141
|
+
# Validates a hard drive.
|
142
|
+
def validate
|
143
|
+
super
|
144
|
+
|
145
|
+
validates_presence_of :format
|
146
|
+
validates_presence_of :size
|
147
|
+
end
|
148
|
+
|
141
149
|
# Creates a new hard drive.
|
142
150
|
#
|
143
151
|
# **This method should NEVER be called. Call {#save} instead.**
|
@@ -146,6 +154,11 @@ module VirtualBox
|
|
146
154
|
# will be raised if the command failed.
|
147
155
|
# @return [Boolean] True if command was successful, false otherwise.
|
148
156
|
def create(raise_errors=false)
|
157
|
+
if !valid?
|
158
|
+
raise Exceptions::ValidationFailedException.new(errors) if raise_errors
|
159
|
+
return false
|
160
|
+
end
|
161
|
+
|
149
162
|
raw = Command.vboxmanage("createhd --filename #{location} --size #{size} --format #{read_attribute(:format)} --remember")
|
150
163
|
return nil unless raw =~ /UUID: (.+?)$/
|
151
164
|
|
@@ -0,0 +1,243 @@
|
|
1
|
+
module VirtualBox
|
2
|
+
# Represents a shared folder in VirtualBox. In VirtualBox, shared folders are a
|
3
|
+
# method for basically "symlinking" a folder on the guest system to a folder which
|
4
|
+
# exists on the host system. This allows for sharing of files across the virtual
|
5
|
+
# machine.
|
6
|
+
#
|
7
|
+
# **Note:** Whenever modifying shared folders on a VM, the changes won't take
|
8
|
+
# effect until a _cold reboot_ occurs. This means actually closing the virtual
|
9
|
+
# machine _completely_, then restarting it. You can't just hit "Start > Restart"
|
10
|
+
# or do a `sudo reboot`. It doesn't work that way!
|
11
|
+
#
|
12
|
+
# # Getting Shared Folders
|
13
|
+
#
|
14
|
+
# All shared folders are attached to a {VM} object, by definition. Therefore, to
|
15
|
+
# get a list of the shared folders, first {VM.find find} the VM you need, then
|
16
|
+
# use the `shared_folders` relationship to access an array of the shared folders.
|
17
|
+
# With this array, you can create, modify, update, and delete the shared folders
|
18
|
+
# for that virtual machine.
|
19
|
+
#
|
20
|
+
# # Creating a Shared Folder
|
21
|
+
#
|
22
|
+
# **This whole section will assume you already looked up a {VM} and assigned it to
|
23
|
+
# a local variable named `vm`.**
|
24
|
+
#
|
25
|
+
# With a VM found, creating a shared folder is just a few lines of code:
|
26
|
+
#
|
27
|
+
# folder = VirtualBox::SharedFolder.new
|
28
|
+
# folder.name = "desktop-images"
|
29
|
+
# folder.hostpath = File.expand_path("~/Desktop/images")
|
30
|
+
# vm.shared_folders << folder
|
31
|
+
# folder.save # Or you can call vm.save, which works too!
|
32
|
+
#
|
33
|
+
# # Modifying an Existing Shared Folder
|
34
|
+
#
|
35
|
+
# **This whole section will assume you already looked up a {VM} and assigned it to
|
36
|
+
# a local variable named `vm`.**
|
37
|
+
#
|
38
|
+
# Nothing tricky here: You treat existing shared folder objects just as if they
|
39
|
+
# were new ones. Assign a new name and/or a new path, then save.
|
40
|
+
#
|
41
|
+
# folder = vm.shared_folders.first
|
42
|
+
# folder.name = "rufus"
|
43
|
+
# folder.save # Or vm.save
|
44
|
+
#
|
45
|
+
# **Note**: The VirtualBox-saavy will know that VirtualBox doesn't actually
|
46
|
+
# expose a way to edit shared folders. Under the hood, the virtualbox ruby
|
47
|
+
# library is actually deleting the old shared folder, then creating a new
|
48
|
+
# one with the new details. This shouldn't affect the way anything works for
|
49
|
+
# the VM itself.
|
50
|
+
#
|
51
|
+
# # Deleting a Shared Folder
|
52
|
+
#
|
53
|
+
# **This whole section will assume you already looked up a {VM} and assigned it to
|
54
|
+
# a local variable named `vm`.**
|
55
|
+
#
|
56
|
+
# folder = vm.shared_folder.first
|
57
|
+
# folder.destroy
|
58
|
+
#
|
59
|
+
# Poof! It'll be gone. This is usually the place where I warn you about this
|
60
|
+
# being non-reversable, but since no _data_ was actually destroyed, this is
|
61
|
+
# not too risky. You could always just recreate the shared folder with the
|
62
|
+
# same name and path and it'll be like nothing happened.
|
63
|
+
#
|
64
|
+
# # Attributes and Relationships
|
65
|
+
#
|
66
|
+
# Properties of the model are exposed using standard ruby instance
|
67
|
+
# methods which are generated on the fly. Because of this, they are not listed
|
68
|
+
# below as available instance methods.
|
69
|
+
#
|
70
|
+
# These attributes can be accessed and modified via standard ruby-style
|
71
|
+
# `instance.attribute` and `instance.attribute=` methods. The attributes are
|
72
|
+
# listed below.
|
73
|
+
#
|
74
|
+
# Relationships are also accessed like attributes but can't be set. Instead,
|
75
|
+
# they are typically references to other objects such as an {AttachedDevice} which
|
76
|
+
# in turn have their own attributes which can be modified.
|
77
|
+
#
|
78
|
+
# ## Attributes
|
79
|
+
#
|
80
|
+
# This is copied directly from the class header, but lists all available
|
81
|
+
# attributes. If you don't understand what this means, read {Attributable}.
|
82
|
+
#
|
83
|
+
# attribute :parent, :readonly => :readonly
|
84
|
+
# attribute :name
|
85
|
+
# attribute :hostpath
|
86
|
+
#
|
87
|
+
class SharedFolder < AbstractModel
|
88
|
+
attribute :parent, :readonly => :readonly
|
89
|
+
attribute :name, :populate_key => "SharedFolderNameMachineMapping"
|
90
|
+
attribute :hostpath, :populate_key => "SharedFolderPathMachineMapping"
|
91
|
+
|
92
|
+
class <<self
|
93
|
+
# Populates the shared folder relationship for anything which is related to it.
|
94
|
+
#
|
95
|
+
# **This method typically won't be used except internally.**
|
96
|
+
#
|
97
|
+
# @return [Array<SharedFolder>]
|
98
|
+
def populate_relationship(caller, data)
|
99
|
+
relation = []
|
100
|
+
|
101
|
+
counter = 1
|
102
|
+
loop do
|
103
|
+
break unless data["SharedFolderNameMachineMapping#{counter}".downcase.to_sym]
|
104
|
+
|
105
|
+
folder = new(counter, caller, data)
|
106
|
+
relation.push(folder)
|
107
|
+
counter += 1
|
108
|
+
end
|
109
|
+
|
110
|
+
relation
|
111
|
+
end
|
112
|
+
|
113
|
+
# Saves the relationship. This simply calls {#save} on every
|
114
|
+
# member of the relationship.
|
115
|
+
#
|
116
|
+
# **This method typically won't be used except internally.**
|
117
|
+
def save_relationship(caller, data)
|
118
|
+
# Just call save on each folder with the VM
|
119
|
+
data.each do |sf|
|
120
|
+
sf.save
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# @overload initialize(data={})
|
126
|
+
# Creates a new SharedFolder which is a new record. This
|
127
|
+
# should be attached to a VM and saved.
|
128
|
+
# @param [Hash] data (optional) A hash which contains initial attribute
|
129
|
+
# values for the SharedFolder.
|
130
|
+
# @overload initialize(index, caller, data)
|
131
|
+
# Creates an SharedFolder for a relationship. **This should
|
132
|
+
# never be called except internally.**
|
133
|
+
# @param [Integer] index Index of the shared folder
|
134
|
+
# @param [Object] caller The parent
|
135
|
+
# @param [Hash] data A hash of data which must be used
|
136
|
+
# to extract the relationship data.
|
137
|
+
def initialize(*args)
|
138
|
+
super()
|
139
|
+
|
140
|
+
if args.length == 3
|
141
|
+
initialize_for_relationship(*args)
|
142
|
+
elsif args.length == 1
|
143
|
+
initialize_for_data(*args)
|
144
|
+
elsif args.length == 0
|
145
|
+
return
|
146
|
+
else
|
147
|
+
raise NoMethodError.new
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Initializes the record for use in a relationship. This
|
152
|
+
# is automatically called by {#initialize} if it has three
|
153
|
+
# parameters.
|
154
|
+
#
|
155
|
+
# **This method typically won't be used except internally.**
|
156
|
+
def initialize_for_relationship(index, caller, data)
|
157
|
+
# Setup the index specific attributes
|
158
|
+
populate_data = {}
|
159
|
+
self.class.attributes.each do |name, options|
|
160
|
+
key = options[:populate_key] || name
|
161
|
+
value = data["#{key}#{index}".downcase.to_sym]
|
162
|
+
populate_data[key] = value
|
163
|
+
end
|
164
|
+
|
165
|
+
populate_attributes(populate_data.merge({
|
166
|
+
:parent => caller
|
167
|
+
}))
|
168
|
+
end
|
169
|
+
|
170
|
+
# Initializes a record with initial data but keeping it a "new
|
171
|
+
# record." This is called automatically if {#initialize} is given
|
172
|
+
# only a single parameter. View {#initialize} for documentation.
|
173
|
+
def initialize_for_data(data)
|
174
|
+
self.class.attributes.each do |name, options|
|
175
|
+
data[options[:populate_key]] = data[name]
|
176
|
+
end
|
177
|
+
|
178
|
+
populate_attributes(data)
|
179
|
+
new_record!
|
180
|
+
end
|
181
|
+
|
182
|
+
# Validates a shared folder.
|
183
|
+
def validate
|
184
|
+
super
|
185
|
+
|
186
|
+
validates_presence_of :parent
|
187
|
+
validates_presence_of :name
|
188
|
+
validates_presence_of :hostpath
|
189
|
+
end
|
190
|
+
|
191
|
+
# Saves or creates a shared folder.
|
192
|
+
#
|
193
|
+
# @param [Boolean] raise_errors If true, {Exceptions::CommandFailedException}
|
194
|
+
# will be raised if the command failed.
|
195
|
+
# @return [Boolean] True if command was successful, false otherwise.
|
196
|
+
def save(raise_errors=false)
|
197
|
+
return true unless changed?
|
198
|
+
|
199
|
+
if !valid?
|
200
|
+
raise Exceptions::ValidationFailedException.new(errors) if raise_errors
|
201
|
+
return false
|
202
|
+
end
|
203
|
+
|
204
|
+
# If this isn't a new record, we destroy it first
|
205
|
+
destroy(raise_errors) if !new_record?
|
206
|
+
|
207
|
+
Command.vboxmanage("sharedfolder add #{Command.shell_escape(parent.name)} --name #{Command.shell_escape(name)} --hostpath #{Command.shell_escape(hostpath)}")
|
208
|
+
existing_record!
|
209
|
+
clear_dirty!
|
210
|
+
|
211
|
+
true
|
212
|
+
rescue Exceptions::CommandFailedException
|
213
|
+
raise if raise_errors
|
214
|
+
false
|
215
|
+
end
|
216
|
+
|
217
|
+
# Relationship callback when added to a collection. This is automatically
|
218
|
+
# called by any relationship collection when this object is added.
|
219
|
+
def added_to_relationship(parent)
|
220
|
+
write_attribute(:parent, parent)
|
221
|
+
end
|
222
|
+
|
223
|
+
# Destroys the shared folder. This doesn't actually delete the folder
|
224
|
+
# from the host system. Instead, it simply removes the mapping to the
|
225
|
+
# virtual machine, meaning it will no longer be possible to mount it
|
226
|
+
# from within the virtual machine.
|
227
|
+
#
|
228
|
+
# @param [Boolean] raise_errors If true, {Exceptions::CommandFailedException}
|
229
|
+
# will be raised if the command failed.
|
230
|
+
# @return [Boolean] True if command was successful, false otherwise.
|
231
|
+
def destroy(raise_errors=false)
|
232
|
+
# If the name changed, we have to be sure to use the previous
|
233
|
+
# one.
|
234
|
+
name_value = name_changed? ? name_was : name
|
235
|
+
|
236
|
+
Command.vboxmanage("sharedfolder remove #{Command.shell_escape(parent.name)} --name #{Command.shell_escape(name_value)}")
|
237
|
+
true
|
238
|
+
rescue Exceptions::CommandFailedException
|
239
|
+
raise if raise_errors
|
240
|
+
false
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
data/lib/virtualbox/vm.rb
CHANGED
@@ -74,6 +74,7 @@ module VirtualBox
|
|
74
74
|
#
|
75
75
|
# relationship :nics, Nic
|
76
76
|
# relationship :storage_controllers, StorageController, :dependent => :destroy
|
77
|
+
# relationship :shared_folders, SharedFolder
|
77
78
|
#
|
78
79
|
class VM < AbstractModel
|
79
80
|
attribute :uuid, :readonly => true
|
@@ -104,6 +105,7 @@ module VirtualBox
|
|
104
105
|
attribute :state, :populate_key => :vmstate, :readonly => true
|
105
106
|
relationship :nics, Nic
|
106
107
|
relationship :storage_controllers, StorageController, :dependent => :destroy
|
108
|
+
relationship :shared_folders, SharedFolder
|
107
109
|
|
108
110
|
class <<self
|
109
111
|
# Returns an array of all available VMs.
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
2
|
+
|
3
|
+
class ValidatableTest < Test::Unit::TestCase
|
4
|
+
class ValidatableModel
|
5
|
+
include VirtualBox::AbstractModel::Validatable
|
6
|
+
|
7
|
+
attr_accessor :foos
|
8
|
+
attr_accessor :bars
|
9
|
+
end
|
10
|
+
|
11
|
+
context "errors" do
|
12
|
+
setup do
|
13
|
+
@model = ValidatableModel.new
|
14
|
+
end
|
15
|
+
|
16
|
+
should "have no errors by default" do
|
17
|
+
assert @model.errors.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
should "be able to add errors" do
|
21
|
+
@model.add_error(:foo, "is blank")
|
22
|
+
assert !@model.errors.empty?
|
23
|
+
assert !@model.errors[:foo].nil?
|
24
|
+
assert_equal "is blank", @model.errors[:foo].first
|
25
|
+
end
|
26
|
+
|
27
|
+
should "be able to add multiple errors" do
|
28
|
+
@model.add_error(:foo, "foo")
|
29
|
+
@model.add_error(:foo, "bar")
|
30
|
+
assert !@model.errors.empty?
|
31
|
+
assert !@model.errors[:foo].nil?
|
32
|
+
assert_equal 2, @model.errors[:foo].length
|
33
|
+
end
|
34
|
+
|
35
|
+
should "be able to clear errors" do
|
36
|
+
@model.add_error(:foo, "foo")
|
37
|
+
assert !@model.errors.empty?
|
38
|
+
@model.clear_errors
|
39
|
+
assert @model.errors.empty?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "validity" do
|
44
|
+
setup do
|
45
|
+
@model = ValidatableModel.new
|
46
|
+
end
|
47
|
+
|
48
|
+
should "call validate on valid?" do
|
49
|
+
@model.expects(:validate)
|
50
|
+
assert @model.valid?
|
51
|
+
end
|
52
|
+
|
53
|
+
should "be valid if there are no errors" do
|
54
|
+
assert @model.valid?
|
55
|
+
end
|
56
|
+
|
57
|
+
should "be invalid if there are any errors" do
|
58
|
+
@model.add_error(:foo, "foo")
|
59
|
+
assert !@model.valid?
|
60
|
+
end
|
61
|
+
|
62
|
+
should "have a validate method by default which returns true" do
|
63
|
+
assert @model.validate
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "specific validations" do
|
68
|
+
setup do
|
69
|
+
@model = ValidatableModel.new
|
70
|
+
end
|
71
|
+
|
72
|
+
context "validates_presence_of" do
|
73
|
+
setup do
|
74
|
+
@model.foos = "foo"
|
75
|
+
@model.bars = "bar"
|
76
|
+
end
|
77
|
+
|
78
|
+
should "not add an error if not blank" do
|
79
|
+
@model.validates_presence_of(:foos)
|
80
|
+
assert @model.valid?
|
81
|
+
end
|
82
|
+
|
83
|
+
should "add an error if blank field" do
|
84
|
+
@model.foos = ""
|
85
|
+
@model.validates_presence_of(:foos)
|
86
|
+
assert !@model.valid?
|
87
|
+
end
|
88
|
+
|
89
|
+
should "add an error for a nil field" do
|
90
|
+
@model.foos = nil
|
91
|
+
@model.validates_presence_of(:foos)
|
92
|
+
assert !@model.valid?
|
93
|
+
end
|
94
|
+
|
95
|
+
should "validate multiple fields" do
|
96
|
+
@model.bars = nil
|
97
|
+
@model.validates_presence_of([:foos, :bars])
|
98
|
+
|
99
|
+
assert !@model.valid?
|
100
|
+
assert @model.errors[:bars]
|
101
|
+
end
|
102
|
+
|
103
|
+
should "return false on invalid" do
|
104
|
+
@model.bars = nil
|
105
|
+
assert !@model.validates_presence_of(:bars)
|
106
|
+
end
|
107
|
+
|
108
|
+
should "return true on valid" do
|
109
|
+
@model.bars = "foo"
|
110
|
+
assert @model.validates_presence_of(:bars)
|
111
|
+
end
|
112
|
+
|
113
|
+
should "return false if any are invalid on multiple fields" do
|
114
|
+
@model.bars = nil
|
115
|
+
assert !@model.validates_presence_of([:foos, :bars])
|
116
|
+
end
|
117
|
+
|
118
|
+
should "return true if all fields are valid" do
|
119
|
+
@model.foos = "foo"
|
120
|
+
@model.bars = "bar"
|
121
|
+
assert @model.validates_presence_of([:foos, :bars])
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -5,6 +5,9 @@ class AbstractModelTest < Test::Unit::TestCase
|
|
5
5
|
def self.set_relationship(caller, old_value, new_value)
|
6
6
|
new_value
|
7
7
|
end
|
8
|
+
|
9
|
+
def self.validate_relationship(caller, data)
|
10
|
+
end
|
8
11
|
end
|
9
12
|
|
10
13
|
class Bar; end
|
@@ -16,6 +19,52 @@ class AbstractModelTest < Test::Unit::TestCase
|
|
16
19
|
relationship :bars, Bar, :dependent => :destroy
|
17
20
|
end
|
18
21
|
|
22
|
+
context "validation" do
|
23
|
+
setup do
|
24
|
+
@model = FakeModel.new
|
25
|
+
end
|
26
|
+
|
27
|
+
should "clear all previous errors" do
|
28
|
+
@model.expects(:clear_errors).once
|
29
|
+
@model.validate
|
30
|
+
end
|
31
|
+
|
32
|
+
should "call validate_relationship on each relationship class" do
|
33
|
+
Foo.expects(:validate_relationship).once.with(@model, nil)
|
34
|
+
@model.validate
|
35
|
+
end
|
36
|
+
|
37
|
+
should "forward arguments to validate_relationship" do
|
38
|
+
Foo.expects(:validate_relationship).once.with(@model, nil, "HELLO")
|
39
|
+
@model.validate("HELLO")
|
40
|
+
end
|
41
|
+
|
42
|
+
should "succeed if all relationships succeeded" do
|
43
|
+
Foo.expects(:validate_relationship).returns(true)
|
44
|
+
assert @model.validate
|
45
|
+
end
|
46
|
+
|
47
|
+
should "fail if one relationship failed to validate" do
|
48
|
+
Foo.expects(:validate_relationship).returns(true)
|
49
|
+
Bar.expects(:validate_relationship).returns(false)
|
50
|
+
assert !@model.validate
|
51
|
+
end
|
52
|
+
|
53
|
+
context "errors" do
|
54
|
+
should "return the errors of the relationships, as well as the model itself" do
|
55
|
+
@model.foo = nil
|
56
|
+
assert !@model.validate
|
57
|
+
|
58
|
+
@model.validates_presence_of(:foo)
|
59
|
+
Foo.expects(:errors_for_relationship).with(@model, nil).returns("BAD")
|
60
|
+
errors = @model.errors
|
61
|
+
assert errors.has_key?(:foos)
|
62
|
+
assert_equal "BAD", errors[:foos]
|
63
|
+
assert errors.has_key?(:foo)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
19
68
|
context "new/existing records" do
|
20
69
|
setup do
|
21
70
|
@model = FakeModel.new
|
@@ -19,6 +19,34 @@ class AttachedDeviceTest < Test::Unit::TestCase
|
|
19
19
|
VirtualBox::Command.stubs(:execute).returns('')
|
20
20
|
end
|
21
21
|
|
22
|
+
context "validations" do
|
23
|
+
setup do
|
24
|
+
@ad = VirtualBox::AttachedDevice.new
|
25
|
+
@ad.image = VirtualBox::DVD.empty_drive
|
26
|
+
@ad.port = 7
|
27
|
+
@ad.added_to_relationship(@caller)
|
28
|
+
end
|
29
|
+
|
30
|
+
should "be valid with all fields" do
|
31
|
+
assert @ad.valid?
|
32
|
+
end
|
33
|
+
|
34
|
+
should "be invalid with no image" do
|
35
|
+
@ad.image = nil
|
36
|
+
assert !@ad.valid?
|
37
|
+
end
|
38
|
+
|
39
|
+
should "be invalid with no port" do
|
40
|
+
@ad.port = nil
|
41
|
+
assert !@ad.valid?
|
42
|
+
end
|
43
|
+
|
44
|
+
should "be invalid if not in a relationship" do
|
45
|
+
@ad.write_attribute(:parent, nil)
|
46
|
+
assert !@ad.valid?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
22
50
|
context "medium" do
|
23
51
|
setup do
|
24
52
|
@ad = VirtualBox::AttachedDevice.new
|
@@ -62,6 +90,12 @@ class AttachedDeviceTest < Test::Unit::TestCase
|
|
62
90
|
@value.save
|
63
91
|
end
|
64
92
|
|
93
|
+
should "return false and not call vboxmanage if invalid" do
|
94
|
+
VirtualBox::Command.expects(:vboxmanage).never
|
95
|
+
@value.expects(:valid?).returns(false)
|
96
|
+
assert !@value.save
|
97
|
+
end
|
98
|
+
|
65
99
|
should "not call destroy if the port didn't change" do
|
66
100
|
@value.expects(:destroy).never
|
67
101
|
assert !@value.port_changed?
|
@@ -90,9 +124,16 @@ class AttachedDeviceTest < Test::Unit::TestCase
|
|
90
124
|
@ad.port = 3
|
91
125
|
end
|
92
126
|
|
93
|
-
should "
|
94
|
-
|
95
|
-
|
127
|
+
should "return false and not call vboxmanage if invalid" do
|
128
|
+
VirtualBox::Command.expects(:vboxmanage).never
|
129
|
+
@ad.expects(:valid?).returns(false)
|
130
|
+
assert !@ad.save
|
131
|
+
end
|
132
|
+
|
133
|
+
should "raise a ValidationFailedException if invalid and raise_errors is true" do
|
134
|
+
@ad.expects(:valid?).returns(false)
|
135
|
+
assert_raises(VirtualBox::Exceptions::ValidationFailedException) {
|
136
|
+
@ad.save(true)
|
96
137
|
}
|
97
138
|
end
|
98
139
|
|
@@ -106,13 +147,6 @@ class AttachedDeviceTest < Test::Unit::TestCase
|
|
106
147
|
@ad.expects(:destroy).never
|
107
148
|
assert @ad.save
|
108
149
|
end
|
109
|
-
|
110
|
-
should "not raise an InvalidObjectException if no image is set" do
|
111
|
-
@ad.image = nil
|
112
|
-
assert_raises(VirtualBox::Exceptions::InvalidObjectException) {
|
113
|
-
@ad.save
|
114
|
-
}
|
115
|
-
end
|
116
150
|
|
117
151
|
should "call the proper vboxcommand" do
|
118
152
|
VirtualBox::Command.expects(:vboxmanage).with("storageattach #{@vm.name} --storagectl #{VirtualBox::Command.shell_escape(@caller.name)} --port #{@ad.port} --device 0 --type #{@image.image_type} --medium #{@ad.medium}")
|
@@ -23,6 +23,29 @@ raw
|
|
23
23
|
VirtualBox::Command.stubs(:vboxmanage).with("showhdinfo #{@name}").returns(@find_raw)
|
24
24
|
end
|
25
25
|
|
26
|
+
context "validations" do
|
27
|
+
setup do
|
28
|
+
@hd = VirtualBox::HardDrive.new
|
29
|
+
@hd.size = 2000
|
30
|
+
end
|
31
|
+
|
32
|
+
should "be valid with a size and format" do
|
33
|
+
assert @hd.valid?
|
34
|
+
end
|
35
|
+
|
36
|
+
should "be invalid if size is nil" do
|
37
|
+
@hd.size = nil
|
38
|
+
assert !@hd.valid?
|
39
|
+
end
|
40
|
+
|
41
|
+
should "clear validations when rechecking" do
|
42
|
+
@hd.size = nil
|
43
|
+
assert !@hd.valid?
|
44
|
+
@hd.size = 700
|
45
|
+
assert @hd.valid?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
26
49
|
context "destroying a hard drive" do
|
27
50
|
setup do
|
28
51
|
@hd = VirtualBox::HardDrive.find(@name)
|
@@ -136,6 +159,19 @@ raw
|
|
136
159
|
@hd.save(true)
|
137
160
|
}
|
138
161
|
end
|
162
|
+
|
163
|
+
should "not run if invalid" do
|
164
|
+
@hd.expects(:valid?).returns(false)
|
165
|
+
VirtualBox::Command.expects(:vboxmanage).never
|
166
|
+
assert !@hd.save
|
167
|
+
end
|
168
|
+
|
169
|
+
should "raise a ValidationFailedException if invalid and raise_errors is true" do
|
170
|
+
@hd.expects(:valid?).returns(false)
|
171
|
+
assert_raises(VirtualBox::Exceptions::ValidationFailedException) {
|
172
|
+
@hd.save(true)
|
173
|
+
}
|
174
|
+
end
|
139
175
|
end
|
140
176
|
|
141
177
|
context "finding a single hard drive" do
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class SharedFolderTest < Test::Unit::TestCase
|
4
|
+
setup do
|
5
|
+
@data = {
|
6
|
+
:sharedfoldernamemachinemapping1 => "foofolder",
|
7
|
+
:sharedfolderpathmachinemapping1 => "/foo",
|
8
|
+
:sharedfoldernamemachinemapping2 => "barfolder",
|
9
|
+
:sharedfolderpathmachinemapping2 => "/bar"
|
10
|
+
}
|
11
|
+
|
12
|
+
@caller = mock("caller")
|
13
|
+
@caller.stubs(:name).returns("foo")
|
14
|
+
|
15
|
+
VirtualBox::Command.stubs(:execute)
|
16
|
+
end
|
17
|
+
|
18
|
+
context "validations" do
|
19
|
+
setup do
|
20
|
+
@sf = VirtualBox::SharedFolder.new
|
21
|
+
@sf.name = "foo"
|
22
|
+
@sf.hostpath = "bar"
|
23
|
+
@sf.added_to_relationship(@caller)
|
24
|
+
end
|
25
|
+
|
26
|
+
should "be valid with all fields" do
|
27
|
+
assert @sf.valid?
|
28
|
+
end
|
29
|
+
|
30
|
+
should "be invalid with no name" do
|
31
|
+
@sf.name = nil
|
32
|
+
assert !@sf.valid?
|
33
|
+
end
|
34
|
+
|
35
|
+
should "be invalid with no hostpath" do
|
36
|
+
@sf.hostpath = nil
|
37
|
+
assert !@sf.valid?
|
38
|
+
end
|
39
|
+
|
40
|
+
should "be invalid if not in a relationship" do
|
41
|
+
@sf.write_attribute(:parent, nil)
|
42
|
+
assert !@sf.valid?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "saving an existing shared folder" do
|
47
|
+
setup do
|
48
|
+
@value = VirtualBox::SharedFolder.populate_relationship(@caller, @data)
|
49
|
+
@value = @value[0]
|
50
|
+
@value.name = "different"
|
51
|
+
assert @value.changed?
|
52
|
+
end
|
53
|
+
|
54
|
+
should "first destroy the shared folder then recreate it" do
|
55
|
+
seq = sequence("create_seq")
|
56
|
+
@value.expects(:destroy).in_sequence(seq)
|
57
|
+
VirtualBox::Command.expects(:vboxmanage).in_sequence(seq)
|
58
|
+
assert @value.save
|
59
|
+
end
|
60
|
+
|
61
|
+
should "call destroy with raise errors if set" do
|
62
|
+
@value.expects(:destroy).with(true).once
|
63
|
+
assert @value.save(true)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "creating a new shared folder" do
|
68
|
+
setup do
|
69
|
+
@sf = VirtualBox::SharedFolder.new
|
70
|
+
@sf.name = "foo"
|
71
|
+
@sf.hostpath = "bar"
|
72
|
+
end
|
73
|
+
|
74
|
+
should "return false and not call vboxmanage if invalid" do
|
75
|
+
VirtualBox::Command.expects(:vboxmanage).never
|
76
|
+
@sf.expects(:valid?).returns(false)
|
77
|
+
assert !@sf.save
|
78
|
+
end
|
79
|
+
|
80
|
+
should "raise a ValidationFailedException if invalid and raise_errors is true" do
|
81
|
+
@sf.expects(:valid?).returns(false)
|
82
|
+
assert_raises(VirtualBox::Exceptions::ValidationFailedException) {
|
83
|
+
@sf.save(true)
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
context "has a parent" do
|
88
|
+
setup do
|
89
|
+
@sf.added_to_relationship(@caller)
|
90
|
+
VirtualBox::Command.stubs(:vboxmanage)
|
91
|
+
end
|
92
|
+
|
93
|
+
should "not call destroy since its a new record" do
|
94
|
+
@sf.expects(:destroy).never
|
95
|
+
assert @sf.save
|
96
|
+
end
|
97
|
+
|
98
|
+
should "call the proper vboxcommand" do
|
99
|
+
VirtualBox::Command.expects(:vboxmanage).with("sharedfolder add #{@caller.name} --name #{@sf.name} --hostpath #{@sf.hostpath}")
|
100
|
+
assert @sf.save
|
101
|
+
end
|
102
|
+
|
103
|
+
should "return false if the command failed" do
|
104
|
+
VirtualBox::Command.stubs(:vboxmanage).raises(VirtualBox::Exceptions::CommandFailedException)
|
105
|
+
assert !@sf.save
|
106
|
+
end
|
107
|
+
|
108
|
+
should "return true if the command was a success" do
|
109
|
+
assert @sf.save
|
110
|
+
end
|
111
|
+
|
112
|
+
should "raise an exception if true sent to save and error occured" do
|
113
|
+
VirtualBox::Command.stubs(:vboxmanage).raises(VirtualBox::Exceptions::CommandFailedException)
|
114
|
+
assert_raises(VirtualBox::Exceptions::CommandFailedException) {
|
115
|
+
@sf.save(true)
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
should "not be a new record after saving" do
|
120
|
+
assert @sf.new_record?
|
121
|
+
assert @sf.save
|
122
|
+
assert !@sf.new_record?
|
123
|
+
end
|
124
|
+
|
125
|
+
should "not be changed after saving" do
|
126
|
+
assert @sf.changed?
|
127
|
+
assert @sf.save
|
128
|
+
assert !@sf.changed?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "constructor" do
|
134
|
+
should "call initialize_for_relationship if 3 args are given" do
|
135
|
+
VirtualBox::SharedFolder.any_instance.expects(:initialize_for_relationship).with(1,2,3).once
|
136
|
+
VirtualBox::SharedFolder.new(1,2,3)
|
137
|
+
end
|
138
|
+
|
139
|
+
should "raise a NoMethodError if anything other than 0,1,or 3 arguments" do
|
140
|
+
2.upto(9) do |i|
|
141
|
+
next if i == 3
|
142
|
+
args = Array.new(i, "A")
|
143
|
+
|
144
|
+
assert_raises(NoMethodError) {
|
145
|
+
VirtualBox::SharedFolder.new(*args)
|
146
|
+
}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
should "populate from a hash if one argument is given" do
|
151
|
+
VirtualBox::SharedFolder.any_instance.expects(:initialize_for_data).with("HI").once
|
152
|
+
VirtualBox::SharedFolder.new("HI")
|
153
|
+
end
|
154
|
+
|
155
|
+
context "initializing from data" do
|
156
|
+
setup do
|
157
|
+
@sf = VirtualBox::SharedFolder.new({:name => "foo", :hostpath => "bar"})
|
158
|
+
end
|
159
|
+
|
160
|
+
should "allow the use of :name and :hostpath in the hash" do
|
161
|
+
assert_equal "foo", @sf.name
|
162
|
+
assert_equal "bar", @sf.hostpath
|
163
|
+
end
|
164
|
+
|
165
|
+
should "keep the record new" do
|
166
|
+
assert @sf.new_record?
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "destroying" do
|
172
|
+
setup do
|
173
|
+
@value = VirtualBox::SharedFolder.populate_relationship(@caller, @data)
|
174
|
+
@value = @value[0]
|
175
|
+
end
|
176
|
+
|
177
|
+
should "call the proper command" do
|
178
|
+
VirtualBox::Command.expects(:vboxmanage).with("sharedfolder remove #{@caller.name} --name #{@value.name}").once
|
179
|
+
assert @value.destroy
|
180
|
+
end
|
181
|
+
|
182
|
+
should "shell escape VM name and storage controller name" do
|
183
|
+
shell_seq = sequence("shell_seq")
|
184
|
+
VirtualBox::Command.expects(:shell_escape).with(@caller.name).in_sequence(shell_seq)
|
185
|
+
VirtualBox::Command.expects(:shell_escape).with(@value.name).in_sequence(shell_seq)
|
186
|
+
VirtualBox::Command.expects(:vboxmanage).in_sequence(shell_seq)
|
187
|
+
assert @value.destroy
|
188
|
+
end
|
189
|
+
|
190
|
+
should "return false if destroy failed" do
|
191
|
+
VirtualBox::Command.stubs(:vboxmanage).raises(VirtualBox::Exceptions::CommandFailedException)
|
192
|
+
assert !@value.destroy
|
193
|
+
end
|
194
|
+
|
195
|
+
should "raise an exception if destroy failed and an error occured" do
|
196
|
+
VirtualBox::Command.stubs(:vboxmanage).raises(VirtualBox::Exceptions::CommandFailedException)
|
197
|
+
assert_raises(VirtualBox::Exceptions::CommandFailedException) {
|
198
|
+
@value.destroy(true)
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
should "use the old name if it was changed" do
|
203
|
+
@value.name = "DIFFERENT"
|
204
|
+
shell_seq = sequence("shell_seq")
|
205
|
+
VirtualBox::Command.expects(:shell_escape).with(@caller.name).in_sequence(shell_seq)
|
206
|
+
VirtualBox::Command.expects(:shell_escape).with(@value.name_was).in_sequence(shell_seq)
|
207
|
+
VirtualBox::Command.expects(:vboxmanage).in_sequence(shell_seq)
|
208
|
+
assert @value.destroy
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
context "populating relationships" do
|
213
|
+
setup do
|
214
|
+
@value = VirtualBox::SharedFolder.populate_relationship(@caller, @data)
|
215
|
+
end
|
216
|
+
|
217
|
+
should "create the correct amount of objects" do
|
218
|
+
assert_equal 2, @value.length
|
219
|
+
end
|
220
|
+
|
221
|
+
should "parse the proper data" do
|
222
|
+
value = @value[0]
|
223
|
+
assert_equal "foofolder", value.name
|
224
|
+
assert_equal "/foo", value.hostpath
|
225
|
+
|
226
|
+
value = @value[1]
|
227
|
+
assert_equal "barfolder", value.name
|
228
|
+
assert_equal "/bar", value.hostpath
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
data/test/virtualbox/vm_test.rb
CHANGED
@@ -71,7 +71,11 @@ uart2="off"
|
|
71
71
|
audio="none"
|
72
72
|
clipboard="bidirectional"
|
73
73
|
vrdp="off"
|
74
|
-
usb="off"
|
74
|
+
usb="off"
|
75
|
+
SharedFolderNameMachineMapping1="mysharedfolder"
|
76
|
+
SharedFolderPathMachineMapping1="/virtualbox"
|
77
|
+
SharedFolderNameMachineMapping2="otherfolder"
|
78
|
+
SharedFolderPathMachineMapping2="/virtualbox/lib"
|
75
79
|
showvminfo
|
76
80
|
|
77
81
|
@name = "foo"
|
@@ -354,6 +358,7 @@ raw
|
|
354
358
|
should "save the relationships as well" do
|
355
359
|
VirtualBox::Nic.expects(:save_relationship).once
|
356
360
|
VirtualBox::StorageController.expects(:save_relationship).once
|
361
|
+
VirtualBox::SharedFolder.expects(:save_relationship).once
|
357
362
|
assert @vm.save
|
358
363
|
end
|
359
364
|
end
|
@@ -391,6 +396,12 @@ raw
|
|
391
396
|
assert @vm.storage_controllers.is_a?(Array)
|
392
397
|
assert_equal 2, @vm.storage_controllers.length
|
393
398
|
end
|
399
|
+
|
400
|
+
should "properly load shared folder relationship" do
|
401
|
+
assert @vm.shared_folders
|
402
|
+
assert @vm.shared_folders.is_a?(Array)
|
403
|
+
assert_equal 2, @vm.shared_folders.length
|
404
|
+
end
|
394
405
|
end
|
395
406
|
|
396
407
|
context "parsing the showvminfo output" do
|
data/virtualbox.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{virtualbox}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Mitchell Hashimoto"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-28}
|
13
13
|
s.description = %q{Create and modify virtual machines in VirtualBox using pure ruby.}
|
14
14
|
s.email = %q{mitchell.hashimoto@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -24,11 +24,13 @@ Gem::Specification.new do |s|
|
|
24
24
|
"TODO",
|
25
25
|
"VERSION",
|
26
26
|
"docs/GettingStarted.md",
|
27
|
+
"docs/WhatsNew.md",
|
27
28
|
"lib/virtualbox.rb",
|
28
29
|
"lib/virtualbox/abstract_model.rb",
|
29
30
|
"lib/virtualbox/abstract_model/attributable.rb",
|
30
31
|
"lib/virtualbox/abstract_model/dirty.rb",
|
31
32
|
"lib/virtualbox/abstract_model/relatable.rb",
|
33
|
+
"lib/virtualbox/abstract_model/validatable.rb",
|
32
34
|
"lib/virtualbox/attached_device.rb",
|
33
35
|
"lib/virtualbox/command.rb",
|
34
36
|
"lib/virtualbox/dvd.rb",
|
@@ -38,12 +40,14 @@ Gem::Specification.new do |s|
|
|
38
40
|
"lib/virtualbox/image.rb",
|
39
41
|
"lib/virtualbox/nic.rb",
|
40
42
|
"lib/virtualbox/proxies/collection.rb",
|
43
|
+
"lib/virtualbox/shared_folder.rb",
|
41
44
|
"lib/virtualbox/storage_controller.rb",
|
42
45
|
"lib/virtualbox/vm.rb",
|
43
46
|
"test/test_helper.rb",
|
44
47
|
"test/virtualbox/abstract_model/attributable_test.rb",
|
45
48
|
"test/virtualbox/abstract_model/dirty_test.rb",
|
46
49
|
"test/virtualbox/abstract_model/relatable_test.rb",
|
50
|
+
"test/virtualbox/abstract_model/validatable_test.rb",
|
47
51
|
"test/virtualbox/abstract_model_test.rb",
|
48
52
|
"test/virtualbox/attached_device_test.rb",
|
49
53
|
"test/virtualbox/command_test.rb",
|
@@ -53,6 +57,7 @@ Gem::Specification.new do |s|
|
|
53
57
|
"test/virtualbox/image_test.rb",
|
54
58
|
"test/virtualbox/nic_test.rb",
|
55
59
|
"test/virtualbox/proxies/collection_test.rb",
|
60
|
+
"test/virtualbox/shared_folder_test.rb",
|
56
61
|
"test/virtualbox/storage_controller_test.rb",
|
57
62
|
"test/virtualbox/vm_test.rb",
|
58
63
|
"virtualbox.gemspec"
|
@@ -67,6 +72,7 @@ Gem::Specification.new do |s|
|
|
67
72
|
"test/virtualbox/abstract_model/attributable_test.rb",
|
68
73
|
"test/virtualbox/abstract_model/dirty_test.rb",
|
69
74
|
"test/virtualbox/abstract_model/relatable_test.rb",
|
75
|
+
"test/virtualbox/abstract_model/validatable_test.rb",
|
70
76
|
"test/virtualbox/abstract_model_test.rb",
|
71
77
|
"test/virtualbox/attached_device_test.rb",
|
72
78
|
"test/virtualbox/command_test.rb",
|
@@ -76,6 +82,7 @@ Gem::Specification.new do |s|
|
|
76
82
|
"test/virtualbox/image_test.rb",
|
77
83
|
"test/virtualbox/nic_test.rb",
|
78
84
|
"test/virtualbox/proxies/collection_test.rb",
|
85
|
+
"test/virtualbox/shared_folder_test.rb",
|
79
86
|
"test/virtualbox/storage_controller_test.rb",
|
80
87
|
"test/virtualbox/vm_test.rb"
|
81
88
|
]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: virtualbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mitchell Hashimoto
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-28 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -30,11 +30,13 @@ files:
|
|
30
30
|
- TODO
|
31
31
|
- VERSION
|
32
32
|
- docs/GettingStarted.md
|
33
|
+
- docs/WhatsNew.md
|
33
34
|
- lib/virtualbox.rb
|
34
35
|
- lib/virtualbox/abstract_model.rb
|
35
36
|
- lib/virtualbox/abstract_model/attributable.rb
|
36
37
|
- lib/virtualbox/abstract_model/dirty.rb
|
37
38
|
- lib/virtualbox/abstract_model/relatable.rb
|
39
|
+
- lib/virtualbox/abstract_model/validatable.rb
|
38
40
|
- lib/virtualbox/attached_device.rb
|
39
41
|
- lib/virtualbox/command.rb
|
40
42
|
- lib/virtualbox/dvd.rb
|
@@ -44,12 +46,14 @@ files:
|
|
44
46
|
- lib/virtualbox/image.rb
|
45
47
|
- lib/virtualbox/nic.rb
|
46
48
|
- lib/virtualbox/proxies/collection.rb
|
49
|
+
- lib/virtualbox/shared_folder.rb
|
47
50
|
- lib/virtualbox/storage_controller.rb
|
48
51
|
- lib/virtualbox/vm.rb
|
49
52
|
- test/test_helper.rb
|
50
53
|
- test/virtualbox/abstract_model/attributable_test.rb
|
51
54
|
- test/virtualbox/abstract_model/dirty_test.rb
|
52
55
|
- test/virtualbox/abstract_model/relatable_test.rb
|
56
|
+
- test/virtualbox/abstract_model/validatable_test.rb
|
53
57
|
- test/virtualbox/abstract_model_test.rb
|
54
58
|
- test/virtualbox/attached_device_test.rb
|
55
59
|
- test/virtualbox/command_test.rb
|
@@ -59,6 +63,7 @@ files:
|
|
59
63
|
- test/virtualbox/image_test.rb
|
60
64
|
- test/virtualbox/nic_test.rb
|
61
65
|
- test/virtualbox/proxies/collection_test.rb
|
66
|
+
- test/virtualbox/shared_folder_test.rb
|
62
67
|
- test/virtualbox/storage_controller_test.rb
|
63
68
|
- test/virtualbox/vm_test.rb
|
64
69
|
- virtualbox.gemspec
|
@@ -95,6 +100,7 @@ test_files:
|
|
95
100
|
- test/virtualbox/abstract_model/attributable_test.rb
|
96
101
|
- test/virtualbox/abstract_model/dirty_test.rb
|
97
102
|
- test/virtualbox/abstract_model/relatable_test.rb
|
103
|
+
- test/virtualbox/abstract_model/validatable_test.rb
|
98
104
|
- test/virtualbox/abstract_model_test.rb
|
99
105
|
- test/virtualbox/attached_device_test.rb
|
100
106
|
- test/virtualbox/command_test.rb
|
@@ -104,5 +110,6 @@ test_files:
|
|
104
110
|
- test/virtualbox/image_test.rb
|
105
111
|
- test/virtualbox/nic_test.rb
|
106
112
|
- test/virtualbox/proxies/collection_test.rb
|
113
|
+
- test/virtualbox/shared_folder_test.rb
|
107
114
|
- test/virtualbox/storage_controller_test.rb
|
108
115
|
- test/virtualbox/vm_test.rb
|