virtualbox 0.7.2 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
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