Source

qemu-toolkit / spec / lib / qemu-toolkit / vm_spec.rb

Full commit
require 'spec_helper'

require 'qemu-toolkit/vm'

require 'support/backend_fake'

describe QemuToolkit::VM do
  let(:backend) { BackendFake.new(
    /dladm show-vnic/ => '') }
  let(:vm) { described_class.new(backend) }
  before(:each) { 
    vm.name = 'test_vm'
    vm.add_disk '/dev/null' 
  }
  
  describe '.each' do
    it "enumerates all virtual machines" do
      QemuToolkit::VM.all(backend).map(&:name).should include('vm1')
    end 
  end
  describe '.[name]' do
    it "returns just one vm" do
      QemuToolkit::VM['vm1', backend].name.should == 'vm1'
    end 
  end
  
  describe 'keyboard layout' do
    let(:all) { QemuToolkit::VM['all', backend] }

    # Turn off disk configuration.
    before(:each) { flexmock(all, disk_options: []) }
    
    subject { all.command }
    
    it { should include('-k de-ch') }
  end
  describe 'network configuration' do
    describe 'basic sample (nic.rb)' do
      let(:nic) { QemuToolkit::VM['nic', backend] }
      
      subject { nic.command }

      describe 'manual nic configuration' do
        it { should include("-net vnic,vlan=2,name=vm1,ifname=vm1,macaddr=01:08:20:52:a6:7e") }
        it { should include("-net nic,vlan=2,name=vm1,model=virtio,macaddr=01:08:20:52:a6:7e") }
      end
      describe 'automatic vnic configuration' do
        it { should include(
          "-device virtio-net-pci,mac=02:08:20:52:a6:7e,tx=timer,x-txtimer=200000,x-txburst=128,vlan=0")}
        it { should include(
          "-net vnic,vlan=0,name=eth0,ifname=nic_1") }
      end
      describe 'DHCP server configuration' do
        it { should include(
          "-net vnic,ip=10.0.0.2,netmask=255.255.255.0,gateway_ip=10.0.0.1,hostname=foobar,dns_ip=8.8.8.8,8.8.4.4,vlan=1,name=eth2,ifname=nic_1") }
        it { should include(
          "-net nic,vlan=1,name=eth2,model=e1000g,macaddr=00:24:81:67:93:99")}
      end
    end
  end
  describe 'iscsi disk configuration' do
    let(:iscsi) { QemuToolkit::VM['iscsi', backend] }
    let(:command) { iscsi.command }
    let(:target) { flexmock('target', 
      :ensure_exists => nil,
      :disks => %w(
        /dev/rdsk/c4t600144F0503CC9000000503201B00001d0p0
        /dev/rdsk/c4t600144F0503CC9000000503201B00001d0p1
      )) }
    before(:each) { flexmock(iscsi, :produce_target => target) }
    
    it "includes all LUNs as hard disk" do
      command.should include('-drive file=/dev/rdsk/c4t600144F0503CC9000000503201B00001d0p0,if=virtio,index=0,media=disk,cache=none,boot=on')
      command.should include('-drive file=/dev/rdsk/c4t600144F0503CC9000000503201B00001d0p1,if=virtio,index=1,media=disk,cache=none')
    end 
  end
  describe 'device disk configuration' do
    before(:each) { 
      vm.instance_variable_set '@disks', []
      vm.add_disk '/path/to/disk' 
      vm.add_disk '/path/to/disk' }

    it 'adds a drive option' do
      vm.command.should include(
        "-drive file=/path/to/disk,if=virtio,index=0,media=disk,boot=on")
    end
    it 'adds a second option that isn\'t bootable' do
      vm.command.should include(
        "-drive file=/path/to/disk,if=virtio,index=1,media=disk")
    end
  end
  describe 'manual disk configuration' do
    before(:each) { 
      vm.add_drive if: 'floppy', file: 'foo.dsk', cache: 'writeback' }
      
    it "adds a drive option" do
      vm.command.should include(
        "-drive if=floppy,file=foo.dsk,cache=writeback,index=1")
    end 
  end
  describe 'cpus and ram' do
    let(:cpuram) { QemuToolkit::VM['cpuram', backend] }
    let(:command) { cpuram.command }
    
    it "sets the proper amount of smp cpus and ram" do
      command.should include("-m 2048")
      command.should include("-smp 4")
    end 
  end
  describe 'vnc display configuration' do
    it "allows configuring a VNC port" do
      vm.vnc_display = 0
      vm.command.should include("-vnc 0")
    end
    it "allows configuring a VNC host & port" do
      vm.vnc_display = 'host:port'
      vm.command.should include("-vnc host:port")
    end 
  end
  describe 'devices' do
    let(:device) { QemuToolkit::VM['device', backend] }
    let(:command) { device.command }
    
    it "includes a device parameter" do
      command.should include('-device driver,a=test,b=test,c_d=test,x-txtimer=foo,x-txburst=bar')
    end     
  end
  describe 'extra arguments' do
    it "allows appending extra arguments" do
      vm.add_extra_arg '-foo'
      vm.add_extra_arg '-bar'
      
      vm.command.should include('-foo')
      vm.command.should include('-bar')
    end 
  end
  describe "boot order" do
    let(:vm) { QemuToolkit::VM['bootorder', backend] }

    it "should issue a -boot directive" do
      vm.command.should include('-boot order=cd,once=dc,menu=on')
    end
  end

  describe '#target(host, port)' do
    it "returns an ISCSITarget instance" do
      target = vm.produce_target('iqn', 'address')
      target.should be_kind_of(QemuToolkit::ISCSITarget)
      target.iqn.should == 'iqn'
      target.address.should == 'address'
    end 
  end
  describe '#start' do
    it "outputs command on dryrun" do
      flexmock(vm).
        should_receive(:puts).once
      vm.start(true)
    end 
    it "calls backend qemu" do
      arguments = vm.command.join(' ')
      flexmock(backend).should_receive(:qemu).with('vm<test_vm>', Array).once
      
      vm.start(false)
    end 
  end
  describe '#connect' do
    it "executes a socat to the given socket" do
      flexmock(vm).
        should_receive(:exec).
        with('socat stdio unix-connect:/Users/kschiess/git/own/qemu-toolkit/spec'+
             '/fixture/test_vm/vm.foobar').
        once
      vm.connect(:foobar)
    end 
  end
  describe '#kill' do
    it "runs kill on the socket" do
      flexmock(vm).
        should_receive(:pid => 1234).
        should_receive(:run_cmd).with('kill 1234').once
      
      vm.kill
    end
  end
  describe '#shutdown' do
    let(:path) { '/tmp/qemu-toolkit_specs'}
    
    it "enters the monitor socket and sends a system_powerdown" do
      flexmock(vm).
        should_receive(:monitor_cmd).with('system_powerdown').once
      
      vm.shutdown
    end 
  end

  describe '#monitor_cmd' do
    let(:path) { '/tmp/sock' }
    before(:each) { flexmock(vm, :monitor_path => path) }
    after(:each) { FileUtils.rm path }
    
    it "sends the command through the socket" do
      UNIXServer.open(path) do |serv|
        vm.send :monitor_cmd, 'foobar'
        conn = serv.accept
        conn.gets.should == "foobar\n"
        conn.close
      end
    end 
  end
end