virtualbox 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. data/Gemfile +16 -3
  2. data/Rakefile +4 -48
  3. data/Readme.md +2 -3
  4. data/VERSION +1 -1
  5. data/features/README.md +33 -0
  6. data/features/global.feature +19 -0
  7. data/features/global_extra_data.feature +27 -0
  8. data/features/step_definitions/abstract_model_steps.rb +35 -0
  9. data/features/step_definitions/extra_data_steps.rb +36 -0
  10. data/features/step_definitions/global_steps.rb +29 -0
  11. data/features/step_definitions/network_adapter_steps.rb +38 -0
  12. data/features/step_definitions/shared_folder_steps.rb +57 -0
  13. data/features/step_definitions/storage_controller_steps.rb +16 -0
  14. data/features/step_definitions/virtualbox_steps.rb +17 -0
  15. data/features/step_definitions/vm_steps.rb +50 -0
  16. data/features/support/env.rb +56 -0
  17. data/features/support/helpers.rb +23 -0
  18. data/features/support/hooks.rb +30 -0
  19. data/features/support/vboxmanage.rb +110 -0
  20. data/features/version.feature +16 -0
  21. data/features/vm.feature +13 -0
  22. data/features/vm_bios.feature +29 -0
  23. data/features/vm_cpu.feature +29 -0
  24. data/features/vm_extra_data.feature +35 -0
  25. data/features/vm_hw_virt.feature +29 -0
  26. data/features/vm_network_adapters.feature +27 -0
  27. data/features/vm_shared_folders.feature +29 -0
  28. data/features/vm_storage_controllers.feature +11 -0
  29. data/lib/virtualbox/abstract_model/version_matcher.rb +2 -0
  30. data/lib/virtualbox/version.rb +1 -1
  31. data/lib/virtualbox/vm.rb +0 -2
  32. data/tasks/cucumber.task +13 -0
  33. data/tasks/jeweler.task +21 -0
  34. data/tasks/rcov.task +15 -0
  35. data/tasks/test.task +10 -0
  36. data/tasks/yard.task +9 -0
  37. data/test/virtualbox/abstract_model/version_matcher_test.rb +4 -0
  38. data/test/virtualbox/version_test.rb +2 -3
  39. data/virtualbox.gemspec +31 -2
  40. metadata +32 -3
data/Gemfile CHANGED
@@ -3,10 +3,23 @@ source :gemcutter
3
3
  # External Dependencies
4
4
  gem "ffi"
5
5
 
6
- # Gems required for testing only.
7
- group :test do
6
+ # Gems required for development only.
7
+ group :development do
8
+ # Gem and docs
9
+ gem "jeweler"
10
+ gem "yard"
11
+
12
+ # Unit tests
8
13
  gem "contest", ">= 0.1.2"
9
14
  gem "mocha"
15
+ gem "rcov"
16
+
17
+ # Integration tests
18
+ gem "cucumber", "~> 0.8.0"
19
+ gem "aruba", "~> 0.1.9"
20
+ gem "rspec"
21
+
22
+ # Generally good to have
10
23
  gem "ruby-debug", ">= 0.10.3" if RUBY_VERSION < '1.9'
11
24
  gem "ruby-debug19", ">= 0.11.6" if RUBY_VERSION >= '1.9'
12
- end
25
+ end
data/Rakefile CHANGED
@@ -1,49 +1,5 @@
1
- begin
2
- require 'jeweler'
3
- Jeweler::Tasks.new do |gemspec|
4
- gemspec.name = "virtualbox"
5
- gemspec.summary = "Create and modify virtual machines in VirtualBox using pure ruby."
6
- gemspec.description = "Create and modify virtual machines in VirtualBox using pure ruby."
7
- gemspec.email = "mitchell.hashimoto@gmail.com"
8
- gemspec.homepage = "http://github.com/mitchellh/virtualbox"
9
- gemspec.authors = ["Mitchell Hashimoto"]
10
- gemspec.executables = []
11
-
12
- gemspec.add_dependency('ffi', '>= 0.6.3')
13
- end
14
- Jeweler::GemcutterTasks.new
15
- rescue LoadError
16
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
1
+ # Tests are placed into *.task files in the tasks/ directory since
2
+ # the Rakefile was getting quite large and intimidating to approach.
3
+ Dir[File.join(File.dirname(__FILE__), "tasks", "**", "*.task")].each do |f|
4
+ load f
17
5
  end
18
-
19
- require 'rake/testtask'
20
-
21
- task :default => :test
22
-
23
- Rake::TestTask.new do |t|
24
- t.libs << "test"
25
- t.pattern = 'test/**/*_test.rb'
26
- end
27
-
28
- begin
29
- require 'yard'
30
- YARD::Rake::YardocTask.new do |t|
31
- t.options = ['--main', 'Readme.md', '--markup', 'markdown']
32
- t.options += ['--title', 'VirtualBox Ruby Library Documentation']
33
- end
34
- rescue LoadError
35
- puts "Yard not available. Install it with: gem install yard bluecloth"
36
- end
37
-
38
- begin
39
- require 'rcov/rcovtask'
40
- Rcov::RcovTask.new do |t|
41
- t.libs << "test"
42
- t.test_files = FileList["test/**/*_test.rb"]
43
- t.output_dir = "test/coverage"
44
- t.verbose = true
45
- end
46
- rescue LoadError
47
- puts "Rcov not available. Coverage data tasks not available."
48
- puts "Install it with: gem install rcov"
49
- end
data/Readme.md CHANGED
@@ -56,8 +56,7 @@ If you'd like to contribute to VirtualBox, the first step to developing is to
56
56
  clone this repo, get [bundler](http://github.com/carlhuda/bundler) if you
57
57
  don't have it already, and do the following:
58
58
 
59
- bundle install
60
- bundle lock
59
+ bundle install --relock
61
60
  rake
62
61
 
63
62
  This will run the test suite, which should come back all green! Then you're good to go!
@@ -68,4 +67,4 @@ These folks went above and beyond with contributions to the virtualbox gem, and
68
67
  for that, I have to say "thanks!"
69
68
 
70
69
  * [Kieran Pilkington](http://github.com/KieranP)
71
- * [Aleksey Palazhchenko](http://github.com/AlekSi)
70
+ * [Aleksey Palazhchenko](http://github.com/AlekSi)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.2
1
+ 0.7.3
@@ -0,0 +1,33 @@
1
+ # VirtualBox Gem Feature Tests
2
+
3
+ **Warning: These tests actually hit the real VirtualBox software!**
4
+
5
+ The tests in this directory are _not_ meant as a replacement
6
+ for the unit tests in the `test/` directory. Instead, these
7
+ features are meant to test the actual integration of the
8
+ virtualbox gem with an actual VirtualBox installation.
9
+
10
+ Whereas the unit tests try to test every branch of the code in a
11
+ very prescribed, isolated environment, the feature tests do not
12
+ test specific branches of code, but test behavior of the gem.
13
+ The reasoning for both tests is that the unit tests test proper
14
+ behavior _within the library itself_ whereas these feature tests
15
+ test proper behavior _with the outside world_.
16
+
17
+ ## Running Feature Tests
18
+
19
+ The easiest way to run these feature tests is via `rake` or the
20
+ `cucumber` binary. `rake` shown below:
21
+
22
+ rake test:integration
23
+
24
+ ## Feature Coverage
25
+
26
+ The test coverage of the features are purposefully not trying to
27
+ reach 100% branch coverage. They test the basic functionality (and
28
+ as much as the functionality as possible) to verify the library is
29
+ functional. If a bug is found, then a feature should be added to
30
+ reproduce and verify the bug no longer exists, but I'm not concerned
31
+ with getting 100% branch coverage right away.
32
+
33
+ For 100% branch coverage, see the unit tests, which do this.
@@ -0,0 +1,19 @@
1
+ Feature: Global Data
2
+ As a virtualbox library user
3
+ I want to access information about the global state of VirtualBox
4
+ In order to get information about my environment
5
+
6
+ Scenario: Reading the VMs
7
+ Given the global object
8
+ When I read the "vms"
9
+ Then I should get a matching length for "vms"
10
+
11
+ Scenario: Reading the hard drives
12
+ Given the global object
13
+ When I read the media "hard drives"
14
+ Then I should get a matching length of media items
15
+
16
+ Scenario: Reading the dvds
17
+ Given the global object
18
+ When I read the media "dvds"
19
+ Then I should get a matching length of media items
@@ -0,0 +1,27 @@
1
+ Feature: Global Extra Data
2
+ As a virtualbox library user
3
+ I want to access and update global extra data
4
+
5
+ Background:
6
+ Given the global object
7
+ And I delete the "global" extra data "VirtualBoxGemTest/Key"
8
+ And the "extra_data" relationship
9
+
10
+ Scenario: Reading extra data
11
+ When I get the extra data of "global"
12
+ Then all the extra data should match
13
+
14
+ @unsafe
15
+ Scenario: Writing extra data
16
+ When I set the extra data "VirtualBoxGemTest/Key" to "Value"
17
+ And I save the relationship
18
+ And I get the extra data of "global"
19
+ Then the extra data should include "VirtualBoxGemTest/Key" as "Value"
20
+
21
+ @unsafe
22
+ Scenario: Deleting extra data
23
+ When I set the extra data "VirtualBoxGemTest/Key" to "Value"
24
+ And I save the relationship
25
+ And I delete the extra data "VirtualBoxGemTest/Key"
26
+ And I get the extra data of "global"
27
+ Then the extra data should not include "VirtualBoxGemTest/Key"
@@ -0,0 +1,35 @@
1
+ Given /the "(.+?)" relationship/ do |relationship|
2
+ @relationship = @model.send(relationship)
3
+ end
4
+
5
+ Given /I reload the model/ do
6
+ @model.reload
7
+ end
8
+
9
+ When /I read the "(.+?)"/ do |property|
10
+ @value = @model.send(property)
11
+ end
12
+
13
+ When /I set the property "(.+?)" to "(.+?)"/ do |key, value|
14
+ value = value == "true" if %W[true false].include?(value)
15
+ @model.send("#{key}=", value)
16
+ end
17
+
18
+ When /I set the relationship property "(.+?)" to "(.+?)"/ do |key, value|
19
+ old = @model
20
+ @model = @relationship
21
+ When %Q[I set the property "#{key}" to "#{value}"]
22
+ @model = old
23
+ end
24
+
25
+ When /I add the new record to the relationship/ do
26
+ @relationship << @new_record
27
+ end
28
+
29
+ When /I save the relationship/ do
30
+ @relationship.save
31
+ end
32
+
33
+ When /I save the model/ do
34
+ @model.save
35
+ end
@@ -0,0 +1,36 @@
1
+ Given /I set the "(.+?)" extra data "(.+?)" to "(.*?)"/ do |name, key, value|
2
+ name = @name if name == "VM"
3
+ VBoxManage.execute("setextradata", name, key, value)
4
+ end
5
+
6
+ Given /I delete the "(.+?)" extra data "(.+?)"/ do |name, key|
7
+ # Same as setting to empty
8
+ Given %Q[I set the "#{name}" extra data "#{key}" to ""]
9
+ end
10
+
11
+ When /I get the extra data of "(.+?)"/ do |name|
12
+ @extra_data = VBoxManage.extra_data(name)
13
+ end
14
+
15
+ When /I set the extra data "(.+?)" to "(.+?)"/ do |key, value|
16
+ @relationship[key] = value
17
+ end
18
+
19
+ When /I delete the extra data "(.+?)"/ do |key|
20
+ @relationship.delete(key)
21
+ end
22
+
23
+ Then /all the extra data should match/ do
24
+ @relationship.length.should == @extra_data.length
25
+ @extra_data.each do |k,v|
26
+ @relationship[k].should == v
27
+ end
28
+ end
29
+
30
+ Then /the extra data should include "(.+?)" as "(.+?)"/ do |key, value|
31
+ @extra_data[key].should == value
32
+ end
33
+
34
+ Then /the extra data should not include "(.+?)"/ do |key|
35
+ @extra_data.should_not have_key(key)
36
+ end
@@ -0,0 +1,29 @@
1
+ Given /the global object/ do
2
+ @model = VirtualBox::Global.global(true)
3
+ end
4
+
5
+ When /I read the media "(.+?)"/ do |property|
6
+ @media = property.gsub(" ", "_").to_sym
7
+ @value = @model.media.send(@media)
8
+ end
9
+
10
+ Then /I should get a matching length for "vms"/ do
11
+ output = VBoxManage.execute("list", "vms")
12
+ @value.length.should == output.split("\n").length
13
+ end
14
+
15
+ Then /I should get a matching length of media items/ do
16
+ mapping = {
17
+ :hard_drives => "hdds",
18
+ :dvds => "dvds",
19
+ :floppies => "floppies"
20
+ }
21
+
22
+ output = VBoxManage.execute("list", mapping[@media])
23
+ count = output.split("\n").inject(0) do |acc, line|
24
+ acc += 1 if line =~ /^UUID:/
25
+ acc
26
+ end
27
+
28
+ @value.length.should == count
29
+ end
@@ -0,0 +1,38 @@
1
+ Given /the adapters are reset/ do
2
+ VBoxManage.network_adapters(@output).each_with_index do |obj, i|
3
+ VBoxManage.execute("modifyvm", @name, "--nic#{i+1}", "none")
4
+ end
5
+ end
6
+
7
+ Given /the adapter in slot "(.+?)" is type "(.+?)"/ do |slot, type|
8
+ VBoxManage.execute("modifyvm", @name, "--nic#{slot}", type)
9
+ end
10
+
11
+ Given /the following adapters are set:/ do |table|
12
+ table.hashes.each do |hash|
13
+ Given %Q[the adapter in slot "#{hash["slot"]}" is type "#{hash["type"]}"]
14
+ end
15
+ end
16
+
17
+ When /I update the adapter in slot "(.+?)"/ do |slot|
18
+ adapter = @relationship.find { |na| na.slot == (slot.to_i - 1) }
19
+ adapter.should_not be_nil
20
+
21
+ @model = adapter
22
+ end
23
+
24
+ Then /the network adapter properties should match/ do
25
+ adapters = VBoxManage.network_adapters(@output)
26
+ @relationship.length.should == adapters.length
27
+
28
+ @relationship.each do |na|
29
+ adapter = adapters[na.slot + 1]
30
+ adapter.should_not be_nil
31
+
32
+ if na.enabled?
33
+ test_mappings(NETWORK_ADAPTER_MAPPINGS, na, adapter)
34
+ else
35
+ adapter[:type].should == "none"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,57 @@
1
+ Given /I add a shared folder "(.+?)" with path "(.+?)" via VBoxManage/ do |name,hostpath|
2
+ VBoxManage.execute("sharedfolder", "add", @name,
3
+ "--name", name,
4
+ "--hostpath", hostpath)
5
+ end
6
+
7
+ Given /I delete the shared folder "(.+?)" via VBoxManage/ do |name|
8
+ VBoxManage.execute("sharedfolder", "remove", @name,
9
+ "--name", name)
10
+ end
11
+
12
+ Given /a shared folder "(.+?)" exists/ do |name|
13
+ folders = VBoxManage.shared_folders(@output)
14
+
15
+ if !folders.keys.include?(name)
16
+ Given %Q[I add a shared folder "#{name}" with path "/#{name}" via VBoxManage]
17
+ Given %Q[I reload the VM]
18
+ Given %Q[the "shared_folders" relationship]
19
+ end
20
+ end
21
+
22
+ Given /no shared folder "(.+?)" exists/ do |name|
23
+ folders = VBoxManage.shared_folders(@output)
24
+
25
+ if folders.keys.include?(name)
26
+ Given %Q[I delete the shared folder "#{name}" via VBoxManage]
27
+ Given %Q[I reload the VM]
28
+ Given %Q[the "shared_folders" relationship]
29
+ end
30
+ end
31
+
32
+ When /I create a new shared folder "(.+?)" with path "(.+?)"/ do |name,hostpath|
33
+ @new_record = VirtualBox::SharedFolder.new
34
+ @new_record.name = name
35
+ @new_record.host_path = hostpath
36
+ end
37
+
38
+ When /I delete the shared folder "(.+?)"$/ do |name|
39
+ @relationship.each do |sf|
40
+ sf.destroy if sf.name == name
41
+ end
42
+ end
43
+
44
+ Then /the shared folder "(.+?)" should not exist/ do |name|
45
+ VBoxManage.shared_folders(@output).keys.should_not include(name)
46
+ end
47
+
48
+ Then /the shared folder properties should match/ do
49
+ folders = VBoxManage.shared_folders(@output)
50
+
51
+ @relationship.length.should == folders.length
52
+
53
+ @relationship.each do |sf|
54
+ folder = folders[sf.name]
55
+ test_mappings(SHARED_FOLDER_MAPPINGS, sf, folder)
56
+ end
57
+ end
@@ -0,0 +1,16 @@
1
+ Then /the number of storage controllers should match/ do
2
+ @relationship.length.should == VBoxManage.storage_controllers(@output).length
3
+ end
4
+
5
+ Then /the storage controller properties should match/ do
6
+ controllers = VBoxManage.storage_controllers(@output)
7
+
8
+ @relationship.each do |sc|
9
+ controller = controllers[sc.name]
10
+ controller.should_not be_nil
11
+
12
+ test_mappings(STORAGE_MAPPINGS, sc, controller) do |value, output|
13
+ [value.to_s.downcase.gsub("_",""), output.downcase]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # Testing VBoxManage -v output
2
+ When /I try to read the virtualbox "(.+?)"/ do |item|
3
+ @key = item.to_sym
4
+ @result = VirtualBox.send(item)
5
+ end
6
+
7
+ Then /the result should match version output/ do
8
+ data = VBoxManage.execute("-v").split("r")
9
+ results = {
10
+ :version => data[0],
11
+ :revision => data[1],
12
+ :supported? => !!data
13
+ }
14
+
15
+ @result.should == results[@key]
16
+ end
17
+
@@ -0,0 +1,50 @@
1
+ Given /I set the VM "(.+?)" to "(.+?)"/ do |key, value|
2
+ VBoxManage.execute("modifyvm", @name, "--#{key}", value)
3
+ end
4
+
5
+ Given /I set the VM properties:/ do |properties|
6
+ properties.hashes.each do |hash|
7
+ Given %Q[I set the VM "#{hash["name"]}" to "#{hash["value"]}"]
8
+ end
9
+ end
10
+
11
+ Given /I reload the VM$/ do
12
+ Given %Q[I find a VM identified by "#{@name}"]
13
+ end
14
+
15
+ When /I find a VM identified by "(.+?)"/ do |name|
16
+ @name = name
17
+ @output = VBoxManage.vm_info(name)
18
+ @vm = VirtualBox::VM.find(name)
19
+ @model = @vm
20
+ end
21
+
22
+ When /I reload the VM info$/ do
23
+ @output = VBoxManage.vm_info(@name)
24
+ end
25
+
26
+ When /I save the VM/ do
27
+ @vm.save
28
+ end
29
+
30
+ Then /the VM should not exist/ do
31
+ @output.should be_empty
32
+ @vm.should be_nil
33
+ end
34
+
35
+ Then /the VM should exist/ do
36
+ @output.should have_key("UUID")
37
+ @vm.should_not be_nil
38
+ end
39
+
40
+ Then /the "(.+?)" properties should match/ do |type|
41
+ map = {
42
+ "BIOS" => BIOS_MAPPINGS,
43
+ "CPU" => CPU_MAPPINGS,
44
+ "HW virt" => HWVIRT_MAPPINGS,
45
+ "VM" => VM_MAPPINGS
46
+ }
47
+
48
+ object = type == "VM" ? @vm : @relationship
49
+ test_mappings(map[type], object, @output)
50
+ end
@@ -0,0 +1,56 @@
1
+ # Before everything, load virtualbox, of course
2
+ require 'spec'
3
+ require 'aruba'
4
+ require File.join(File.dirname(__FILE__), %W[.. .. lib virtualbox])
5
+
6
+ # Configuration settings/info
7
+ IntegrationInfo = {
8
+ :test_unsafe => !!ENV["TEST_UNSAFE"],
9
+ :vm_name => "test_vm"
10
+ }
11
+
12
+ # Mapping of VirtualBox::VM property keys to attributes in the
13
+ # `showvminfo` output.
14
+ VM_MAPPINGS = {
15
+ :uuid => "UUID",
16
+ :name => "name",
17
+ :os_type_id => "ostype",
18
+ :memory_size => "memory",
19
+ :vram_size => "vram",
20
+ :cpu_count => "cpus",
21
+ :accelerate_3d_enabled => "accelerate3d",
22
+ :accelerate_2d_video_enabled => "accelerate2dvideo",
23
+ :clipboard_mode => "clipboard",
24
+ :monitor_count => "monitorcount"
25
+ }
26
+
27
+ BIOS_MAPPINGS = {
28
+ :acpi_enabled => "acpi",
29
+ :io_apic_enabled => "ioapic"
30
+ }
31
+
32
+ HWVIRT_MAPPINGS = {
33
+ :enabled => "hwvirtex",
34
+ :exclusive => "hwvirtexexcl",
35
+ :nested_paging => "nestedpaging",
36
+ :vpid => "vtxvpid"
37
+ }
38
+
39
+ CPU_MAPPINGS = {
40
+ :pae => "pae",
41
+ :synthetic => "synthcpu"
42
+ }
43
+
44
+ STORAGE_MAPPINGS = {
45
+ :port_count => "portcount",
46
+ :controller_type => "type"
47
+ }
48
+
49
+ SHARED_FOLDER_MAPPINGS = {
50
+ :host_path => "path"
51
+ }
52
+
53
+ NETWORK_ADAPTER_MAPPINGS = {
54
+ :mac_address => "macaddress",
55
+ :cable_connected => "cableconnected"
56
+ }
@@ -0,0 +1,23 @@
1
+ module VirtualBox
2
+ module IntegrationHelpers
3
+ # Tests that given a mappings hash (see `VM_MAPPINGS` in env.rb),
4
+ # a model, and an output hash (string to string), that all the
5
+ # mappings from model match output.
6
+ def test_mappings(mappings, model, output, match=true)
7
+ mappings.each do |model_key, output_key|
8
+ value = model.send(model_key)
9
+
10
+ if [TrueClass, FalseClass].include?(value.class)
11
+ # Convert true/false to VirtualBox-style string boolean values
12
+ value = value ? "on" : "off"
13
+ end
14
+
15
+ output_value = output[output_key.to_sym] || output[output_key]
16
+ value, output_value = yield value, output_value if block_given?
17
+ value.to_s.should == output_value
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ World(VirtualBox::IntegrationHelpers)
@@ -0,0 +1,30 @@
1
+ #------------------------------------------------------------
2
+ # Hooks
3
+ #------------------------------------------------------------
4
+ # Unsafe tags specify that a test modifies (writes or deletes)
5
+ # actual data in VirtualBox.
6
+ Around('@unsafe') do |scenario, block|
7
+ block.call if IntegrationInfo[:test_unsafe]
8
+ end
9
+
10
+ Around('@pending') do |scenario, block|
11
+ # Don't run the block
12
+ end
13
+
14
+ #------------------------------------------------------------
15
+ # Warning/Info messages about settings.
16
+ #------------------------------------------------------------
17
+ if !IntegrationInfo[:test_unsafe]
18
+ puts <<-MSG
19
+ ========================================================================
20
+
21
+ For your own safety, unsafe tests (tests which modify actual VirtualBox
22
+ data), are disabled unless the environmental variable TEST_UNSAFE is
23
+ set. To enable unsafe tests, the easiest way is to do the following:
24
+
25
+ TEST_UNSAFE=yes rake test:integration
26
+
27
+ ========================================================================
28
+ MSG
29
+ end
30
+
@@ -0,0 +1,110 @@
1
+ class VBoxManage
2
+ class << self
3
+ def command(*args)
4
+ args = args.dup.flatten
5
+ args.unshift("-q")
6
+ "VBoxManage #{args.join(" ")}"
7
+ end
8
+
9
+ def execute(*args)
10
+ cmd = command(*args)
11
+ result = `#{cmd}`.chomp
12
+ raise Exception.new("Failed command: #{cmd}") if $?.exitstatus != 0
13
+ result
14
+ end
15
+
16
+ # Gets the extra data for a VM of the given ID and returns it in
17
+ # hash format.
18
+ def extra_data(name)
19
+ output = execute("getextradata", name, "enumerate")
20
+
21
+ output.split("\n").inject({}) do |acc, line|
22
+ acc[$1.to_s] = $2.to_s if line =~ /^Key: (.+?), Value: (.+?)$/
23
+ acc
24
+ end
25
+ end
26
+
27
+ # Gets the info for a VM and returns it in hash format.
28
+ def vm_info(name)
29
+ output = begin
30
+ execute("showvminfo", name, "--machinereadable")
31
+ rescue Exception
32
+ ""
33
+ end
34
+
35
+ output.split("\n").inject({}) do |acc, line|
36
+ if line =~ /^"?(.+?)"?=(.+?)$/
37
+ key = $1.to_s
38
+ value = $2.to_s
39
+ value = $1.to_s if value =~ /^"(.*?)"$/
40
+ acc[key] = value
41
+ end
42
+
43
+ acc
44
+ end
45
+ end
46
+
47
+ # Parses the storage controllers out of VM info output and returns
48
+ # it in a programmer-friendly hash.
49
+ def storage_controllers(info)
50
+ raw = info.inject({}) do |acc, data|
51
+ k,v = data
52
+
53
+ if k =~ /^storagecontroller(.+?)(\d+)$/
54
+ subkey = $2.to_s
55
+ acc[subkey] ||= {}
56
+ acc[subkey][$1.to_s.to_sym] = v
57
+ end
58
+
59
+ acc
60
+ end
61
+
62
+ raw.inject({}) do |acc, data|
63
+ k,v = data
64
+ acc[v.delete(:name)] = v
65
+ acc
66
+ end
67
+ end
68
+
69
+ # Parses the shared folders out of the VM info output and returns
70
+ # it in a programmer-friendly hash.
71
+ def shared_folders(info)
72
+ raw = info.inject({}) do |acc, data|
73
+ k,v = data
74
+
75
+ if k =~ /^SharedFolder(.+?)MachineMapping(\d+)$/
76
+ subkey = $2.to_s
77
+ acc[subkey] ||= {}
78
+ acc[subkey][$1.to_s.downcase.to_sym] = v
79
+ end
80
+
81
+ acc
82
+ end
83
+
84
+ raw.inject({}) do |acc, data|
85
+ k,v = data
86
+ acc[v.delete(:name)] = v
87
+ acc
88
+ end
89
+ end
90
+
91
+ # Parses the network adapters out of the VM info output and
92
+ # returns it in a hash.
93
+ def network_adapters(info)
94
+ valid_keys = %W[natnet macaddress cableconnected hostonlyadapter]
95
+
96
+ info.inject({}) do |acc, data|
97
+ k,v = data
98
+ if k =~ /^nic(\d+)$/
99
+ acc[$1.to_i] ||= {}
100
+ acc[$1.to_i][:type] = v
101
+ elsif k=~ /^(.+?)(\d+)$/ && valid_keys.include?($1.to_s)
102
+ acc[$2.to_i] ||= {}
103
+ acc[$2.to_i][$1.to_s.to_sym] = v
104
+ end
105
+
106
+ acc
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,16 @@
1
+ Feature: VirtualBox version information
2
+ As a virtualbox library user
3
+ I want to access information about the installed version
4
+ In order to determine if I support this version of VirtualBox
5
+
6
+ Scenario: Reading the version
7
+ When I try to read the virtualbox "version"
8
+ Then the result should match version output
9
+
10
+ Scenario: Reading the revision
11
+ When I try to read the virtualbox "revision"
12
+ Then the result should match version output
13
+
14
+ Scenario: Checking if VirtualBox supported
15
+ When I try to read the virtualbox "supported?"
16
+ Then the result should match version output
@@ -0,0 +1,13 @@
1
+ Feature: Virtual Machine
2
+ As a virtualbox library user
3
+ I want to access information about specific virtual machines
4
+ In order to get information about VMs in VirtualBox
5
+
6
+ Scenario: Finding a non-existent VM
7
+ When I find a VM identified by "this_should_never_exist1234"
8
+ Then the VM should not exist
9
+
10
+ Scenario: Finding a VM
11
+ When I find a VM identified by "test_vm_A"
12
+ Then the VM should exist
13
+ And the "VM" properties should match
@@ -0,0 +1,29 @@
1
+ Feature: Virtual Machine BIOS Settings
2
+ As a virtualbox library user
3
+ I want to read and update VM BIOS
4
+
5
+ Background:
6
+ Given I find a VM identified by "test_vm_A"
7
+ And I set the VM properties:
8
+ | name | value |
9
+ | acpi | off |
10
+ | ioapic | off |
11
+ And I reload the VM
12
+ And the "bios" relationship
13
+
14
+ Scenario: Reading BIOS
15
+ Then the "BIOS" properties should match
16
+
17
+ @unsafe
18
+ Scenario: Updating the BIOS
19
+ When I set the relationship property "acpi_enabled" to "true"
20
+ And I save the relationship
21
+ And I reload the VM info
22
+ Then the "BIOS" properties should match
23
+
24
+ @unsafe
25
+ Scenario: Updating the BIOS via the VM
26
+ When I set the relationship property "io_apic_enabled" to "true"
27
+ And I save the model
28
+ And I reload the VM info
29
+ Then the "BIOS" properties should match
@@ -0,0 +1,29 @@
1
+ Feature: Virtual Machine CPU Settings
2
+ As a virtualbox library user
3
+ I want to read and update VM CPU settings
4
+
5
+ Background:
6
+ Given I find a VM identified by "test_vm_A"
7
+ And I set the VM properties:
8
+ | name | value |
9
+ | pae | off |
10
+ | synthcpu | off |
11
+ And I reload the VM
12
+ And the "cpu" relationship
13
+
14
+ Scenario: Reading CPU settings
15
+ Then the "CPU" properties should match
16
+
17
+ @unsafe
18
+ Scenario: Updating the CPU settings
19
+ When I set the relationship property "pae" to "true"
20
+ And I save the relationship
21
+ And I reload the VM info
22
+ Then the "CPU" properties should match
23
+
24
+ @unsafe
25
+ Scenario: Updating the CPU settings via the VM
26
+ When I set the relationship property "synthetic" to "true"
27
+ And I save the model
28
+ And I reload the VM info
29
+ Then the "CPU" properties should match
@@ -0,0 +1,35 @@
1
+ Feature: VM Extra Data
2
+ As a virtualbox library user
3
+ I want to access and update VM extra data
4
+
5
+ Background:
6
+ Given I find a VM identified by "test_vm_A"
7
+ And I delete the "VM" extra data "VirtualBoxGemTest/Key"
8
+ And I reload the VM
9
+ And the "extra_data" relationship
10
+
11
+ Scenario: Reading extra data
12
+ When I get the extra data of "test_vm_A"
13
+ Then all the extra data should match
14
+
15
+ @unsafe
16
+ Scenario: Writing extra data
17
+ When I set the extra data "VirtualBoxGemTest/Key" to "Value"
18
+ And I save the relationship
19
+ And I get the extra data of "test_vm_A"
20
+ Then the extra data should include "VirtualBoxGemTest/Key" as "Value"
21
+
22
+ @unsafe
23
+ Scenario: Deleting extra data
24
+ When I set the extra data "VirtualBoxGemTest/Key" to "Value"
25
+ And I save the relationship
26
+ And I delete the extra data "VirtualBoxGemTest/Key"
27
+ And I get the extra data of "test_vm_A"
28
+ Then the extra data should not include "VirtualBoxGemTest/Key"
29
+
30
+ @unsafe
31
+ Scenario: Writing extra data and saving VM
32
+ When I set the extra data "VirtualBoxGemTest/Key" to "Value"
33
+ And I save the model
34
+ And I get the extra data of "test_vm_A"
35
+ Then the extra data should include "VirtualBoxGemTest/Key" as "Value"
@@ -0,0 +1,29 @@
1
+ Feature: Virtual Machine HW Virtualization
2
+ As a virtualbox library user
3
+ I want to read and update HW Virtualization settings
4
+
5
+ Background:
6
+ Given I find a VM identified by "test_vm_A"
7
+ And I set the VM properties:
8
+ | name | value |
9
+ | hwvirtex | on |
10
+ | nestedpaging | on |
11
+ And I reload the VM
12
+ And the "hw_virt" relationship
13
+
14
+ Scenario: Reading
15
+ Then the "HW virt" properties should match
16
+
17
+ @unsafe
18
+ Scenario: Updating
19
+ When I set the relationship property "enabled" to "false"
20
+ And I save the relationship
21
+ And I reload the VM info
22
+ Then the "HW virt" properties should match
23
+
24
+ @unsafe
25
+ Scenario: Updating and saving via VM
26
+ When I set the relationship property "nested_paging" to "false"
27
+ And I save the model
28
+ And I reload the VM info
29
+ Then the "HW virt" properties should match
@@ -0,0 +1,27 @@
1
+ Feature: Virtual Machine Network Adapters
2
+ As a virtualbox library user
3
+ I want to read and update network adapters
4
+
5
+ Background:
6
+ Given I find a VM identified by "test_vm_A"
7
+ And the "network_adapters" relationship
8
+
9
+ @unsafe
10
+ Scenario: Reading adapters
11
+ Given the adapters are reset
12
+ And the following adapters are set:
13
+ | slot | type |
14
+ | 1 | nat |
15
+ Then the network adapter properties should match
16
+
17
+ @unsafe
18
+ Scenario: Updating adapters
19
+ Given the adapters are reset
20
+ And the following adapters are set:
21
+ | slot | type |
22
+ | 1 | nat |
23
+ When I update the adapter in slot "1"
24
+ And I set the property "cable_connected" to "false"
25
+ And I save the VM
26
+ And I reload the VM info
27
+ Then the network adapter properties should match
@@ -0,0 +1,29 @@
1
+ Feature: Virtual Machine Shared Folders
2
+ As a virtualbox library user
3
+ I want to read and update shared folders
4
+
5
+ Background:
6
+ Given I find a VM identified by "test_vm_A"
7
+ And the "shared_folders" relationship
8
+
9
+ @unsafe
10
+ Scenario: Reading Shared Folders
11
+ Given a shared folder "foo" exists
12
+ Then the shared folder properties should match
13
+
14
+ @unsafe
15
+ Scenario: Creating Shared Folders
16
+ Given no shared folder "bar" exists
17
+ When I create a new shared folder "bar" with path "/baz"
18
+ And I add the new record to the relationship
19
+ And I save the model
20
+ And I reload the VM info
21
+ Then the shared folder properties should match
22
+
23
+ @unsafe
24
+ Scenario: Deleting Shared Folders
25
+ Given a shared folder "foo" exists
26
+ When I delete the shared folder "foo"
27
+ And I reload the VM info
28
+ Then the shared folder "foo" should not exist
29
+ Then the shared folder properties should match
@@ -0,0 +1,11 @@
1
+ Feature: Virtual Machine Storage Controllers
2
+ As a virtualbox library user
3
+ I want to read and update storage controllers on a VM
4
+
5
+ Background:
6
+ Given I find a VM identified by "test_vm_A"
7
+ And the "storage_controllers" relationship
8
+
9
+ Scenario: Reading Storage Controllers
10
+ Then the number of storage controllers should match
11
+ And the storage controller properties should match
@@ -26,6 +26,8 @@ module VirtualBox
26
26
  # @return [Array]
27
27
  def split_version(version)
28
28
  version.split(/\./)[0,2]
29
+ rescue Exception
30
+ []
29
31
  end
30
32
  end
31
33
  end
@@ -20,7 +20,7 @@ module VirtualBox
20
20
 
21
21
  # Returns the revision string of the VirtualBox installed, ex. "51742"
22
22
  def revision
23
- Lib.lib.virtualbox.revision
23
+ Lib.lib.virtualbox.revision.to_s
24
24
  end
25
25
  end
26
26
  end
@@ -295,8 +295,6 @@ module VirtualBox
295
295
  validates_numericality_of :memory_balloon_size, :monitor_count
296
296
  validates_inclusion_of :accelerate_3d_enabled, :accelerate_2d_video_enabled, :teleporter_enabled, :in => [true, false]
297
297
 
298
- validates_format_of :name, :with => /^[\w\d\s-]+$/, :message => 'must only contain letters, numbers, spaces, underscores, and dashes.'
299
-
300
298
  if !errors_on(:name)
301
299
  # Only validate the name if the name has no errors already
302
300
  vms_of_same_name = self.class.find(name)
@@ -0,0 +1,13 @@
1
+ begin
2
+ require 'cucumber'
3
+ require 'cucumber/rake/task'
4
+
5
+ namespace :test do
6
+ Cucumber::Rake::Task.new(:integration) do |t|
7
+ t.cucumber_opts = "features --format pretty"
8
+ end
9
+ end
10
+ rescue LoadError
11
+ puts "Cucumber not available. Feature testing not available."
12
+ puts "Install it with: gem install cucumber"
13
+ end
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'jeweler'
3
+
4
+ namespace :gem do
5
+ Jeweler::Tasks.new do |gemspec|
6
+ gemspec.name = "virtualbox"
7
+ gemspec.summary = "Create and modify virtual machines in VirtualBox using pure ruby."
8
+ gemspec.description = "Create and modify virtual machines in VirtualBox using pure ruby."
9
+ gemspec.email = "mitchell.hashimoto@gmail.com"
10
+ gemspec.homepage = "http://github.com/mitchellh/virtualbox"
11
+ gemspec.authors = ["Mitchell Hashimoto"]
12
+ gemspec.executables = []
13
+
14
+ gemspec.add_dependency('ffi', '>= 0.6.3')
15
+ end
16
+
17
+ Jeweler::GemcutterTasks.new
18
+ end
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
@@ -0,0 +1,15 @@
1
+ begin
2
+ require 'rcov/rcovtask'
3
+
4
+ namespace :test do
5
+ Rcov::RcovTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ t.output_dir = "test/coverage"
9
+ t.verbose = true
10
+ end
11
+ end
12
+ rescue LoadError
13
+ puts "Rcov not available. Coverage data tasks not available."
14
+ puts "Install it with: gem install rcov"
15
+ end
@@ -0,0 +1,10 @@
1
+ require 'rake/testtask'
2
+
3
+ task :default => "test:units"
4
+
5
+ namespace :test do
6
+ Rake::TestTask.new(:units) do |t|
7
+ t.libs << "test"
8
+ t.pattern = 'test/**/*_test.rb'
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ begin
2
+ require 'yard'
3
+ YARD::Rake::YardocTask.new do |t|
4
+ t.options = ['--main', 'Readme.md', '--markup', 'markdown']
5
+ t.options += ['--title', 'VirtualBox Ruby Library Documentation']
6
+ end
7
+ rescue LoadError
8
+ puts "Yard not available. Install it with: gem install yard bluecloth"
9
+ end
@@ -33,5 +33,9 @@ class VersionMatcherTest < Test::Unit::TestCase
33
33
  assert_equal %W[3 2], @klass.split_version("3.2.0")
34
34
  assert_equal %W[3 1], @klass.split_version("3.1.1.1.1")
35
35
  end
36
+
37
+ should "return an empty array if it can't split" do
38
+ assert_equal [], @klass.split_version(nil)
39
+ end
36
40
  end
37
41
  end
@@ -39,8 +39,7 @@ class VersionTest < Test::Unit::TestCase
39
39
  end
40
40
 
41
41
  should "return the revision" do
42
- revision = mock("revision")
43
- @vbox.expects(:revision).returns(revision)
44
- assert_equal revision, @module.revision
42
+ @vbox.expects(:revision).returns(7)
43
+ assert_equal "7", @module.revision
45
44
  end
46
45
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{virtualbox}
8
- s.version = "0.7.2"
8
+ s.version = "0.7.3"
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-06-17}
12
+ s.date = %q{2010-06-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 = [
@@ -25,6 +25,30 @@ Gem::Specification.new do |s|
25
25
  "VERSION",
26
26
  "docs/GettingStarted.md",
27
27
  "docs/WhatsNew.md",
28
+ "features/README.md",
29
+ "features/global.feature",
30
+ "features/global_extra_data.feature",
31
+ "features/step_definitions/abstract_model_steps.rb",
32
+ "features/step_definitions/extra_data_steps.rb",
33
+ "features/step_definitions/global_steps.rb",
34
+ "features/step_definitions/network_adapter_steps.rb",
35
+ "features/step_definitions/shared_folder_steps.rb",
36
+ "features/step_definitions/storage_controller_steps.rb",
37
+ "features/step_definitions/virtualbox_steps.rb",
38
+ "features/step_definitions/vm_steps.rb",
39
+ "features/support/env.rb",
40
+ "features/support/helpers.rb",
41
+ "features/support/hooks.rb",
42
+ "features/support/vboxmanage.rb",
43
+ "features/version.feature",
44
+ "features/vm.feature",
45
+ "features/vm_bios.feature",
46
+ "features/vm_cpu.feature",
47
+ "features/vm_extra_data.feature",
48
+ "features/vm_hw_virt.feature",
49
+ "features/vm_network_adapters.feature",
50
+ "features/vm_shared_folders.feature",
51
+ "features/vm_storage_controllers.feature",
28
52
  "lib/virtualbox.rb",
29
53
  "lib/virtualbox/abstract_model.rb",
30
54
  "lib/virtualbox/abstract_model/attributable.rb",
@@ -211,6 +235,11 @@ Gem::Specification.new do |s|
211
235
  "lib/virtualbox/virtual_system_description.rb",
212
236
  "lib/virtualbox/vm.rb",
213
237
  "lib/virtualbox/vrdp_server.rb",
238
+ "tasks/cucumber.task",
239
+ "tasks/jeweler.task",
240
+ "tasks/rcov.task",
241
+ "tasks/test.task",
242
+ "tasks/yard.task",
214
243
  "test/test_helper.rb",
215
244
  "test/virtualbox/abstract_model/attributable_test.rb",
216
245
  "test/virtualbox/abstract_model/dirty_test.rb",
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 7
8
- - 2
9
- version: 0.7.2
8
+ - 3
9
+ version: 0.7.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mitchell Hashimoto
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-17 00:00:00 -07:00
17
+ date: 2010-06-28 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -49,6 +49,30 @@ files:
49
49
  - VERSION
50
50
  - docs/GettingStarted.md
51
51
  - docs/WhatsNew.md
52
+ - features/README.md
53
+ - features/global.feature
54
+ - features/global_extra_data.feature
55
+ - features/step_definitions/abstract_model_steps.rb
56
+ - features/step_definitions/extra_data_steps.rb
57
+ - features/step_definitions/global_steps.rb
58
+ - features/step_definitions/network_adapter_steps.rb
59
+ - features/step_definitions/shared_folder_steps.rb
60
+ - features/step_definitions/storage_controller_steps.rb
61
+ - features/step_definitions/virtualbox_steps.rb
62
+ - features/step_definitions/vm_steps.rb
63
+ - features/support/env.rb
64
+ - features/support/helpers.rb
65
+ - features/support/hooks.rb
66
+ - features/support/vboxmanage.rb
67
+ - features/version.feature
68
+ - features/vm.feature
69
+ - features/vm_bios.feature
70
+ - features/vm_cpu.feature
71
+ - features/vm_extra_data.feature
72
+ - features/vm_hw_virt.feature
73
+ - features/vm_network_adapters.feature
74
+ - features/vm_shared_folders.feature
75
+ - features/vm_storage_controllers.feature
52
76
  - lib/virtualbox.rb
53
77
  - lib/virtualbox/abstract_model.rb
54
78
  - lib/virtualbox/abstract_model/attributable.rb
@@ -235,6 +259,11 @@ files:
235
259
  - lib/virtualbox/virtual_system_description.rb
236
260
  - lib/virtualbox/vm.rb
237
261
  - lib/virtualbox/vrdp_server.rb
262
+ - tasks/cucumber.task
263
+ - tasks/jeweler.task
264
+ - tasks/rcov.task
265
+ - tasks/test.task
266
+ - tasks/yard.task
238
267
  - test/test_helper.rb
239
268
  - test/virtualbox/abstract_model/attributable_test.rb
240
269
  - test/virtualbox/abstract_model/dirty_test.rb