diff --git a/lib/vagrant-lxc/machine_state.rb b/lib/vagrant-lxc/machine_state.rb new file mode 100644 index 0000000..3d9bea5 --- /dev/null +++ b/lib/vagrant-lxc/machine_state.rb @@ -0,0 +1,63 @@ +module Vagrant + module LXC + class MachineState < Vagrant::MachineState + CONTAINER_STATE_FILE_PATH = '/tmp/vagrant-lxc-container-state-%s' + CREATED_STATES = %w( running poweroff ).map!(&:to_sym) + + def initialize(machine) + @machine = machine + end + + def id + @id ||= + begin + state_id = nil + state_id = :not_created if !@machine.id + # TODO: Grab the real machine state here + state_id = read_state_from_file if !state_id + state_id = :unknown if !state_id + state_id + end + end + + def short_description + @short ||= self.id.to_s.gsub("_", " ") + end + + def long_description + @long ||= I18n.t("vagrant.commands.status.#{self.id}") + end + + def created? + CREATED_STATES.include?(self.id) + end + + def off? + self.id == :poweroff + end + + def running? + self.id == :running + end + + def update!(state) + return File.delete(state_file_path) if state.to_sym == :not_created + File.open(state_file_path, 'w') { |f| f.print state } + end + + def read_state_from_file + if File.exists?(state_file_path) + File.read(state_file_path).to_sym + elsif @machine.id + :unknown + end + end + private :read_state_from_file + + def state_file_path + @path ||= CONTAINER_STATE_FILE_PATH % {id: @machine.id} + end + private :state_file_path + end + end +end diff --git a/spec/unit/machine_state_spec.rb b/spec/unit/machine_state_spec.rb new file mode 100644 index 0000000..a18bf69 --- /dev/null +++ b/spec/unit/machine_state_spec.rb @@ -0,0 +1,87 @@ +require 'unit_helper' +require 'vagrant-lxc/machine_state' + +describe Vagrant::LXC::MachineState do + let(:machine) { mocked_machine } + let(:state_file_path) { subject.send(:state_file_path) } + + subject { described_class.new(machine) } + + after { File.delete state_file_path if File.exists? state_file_path } + + # Yeah, I know, this test is not really useful, but vagrant will complain + # if the state is not a Vagrant::MachineState: + # https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/machine.rb#L300 + it { should be_a Vagrant::MachineState } + + describe 'state id' do + context 'when machine id is not present' do + let(:machine) { mocked_machine(id: nil) } + + its(:id) { should == :not_created } + end + + context 'when machine id is present' do + let(:machine) { mocked_machine(id: 'machine-id') } + + context 'and state file exists' do + before { File.stub(read: 'running', exists?: true) } + after { File.unstub!(:exists?) } + + it 'reads it from file' do + subject.id.should == :running + end + end + + context 'and state file does not exist' do + it 'returns :unknown' do + subject.id.should == :unknown + end + end + end + end + + describe 'short description' do + before { subject.stub(id: :not_created) } + + it 'is a humanized version of state id' do + subject.short_description.should == 'not created' + end + end + + describe 'long description' do + before do + subject.stub(id: 'short') + I18n.stub(t: 'some really long description') + end + + it 'is a localized version of the state id' do + subject.long_description.should == 'some really long description' + end + + it 'uses the status locale "namespace"' do + I18n.should have_received(:t).with('vagrant.commands.status.short') + end + end + + context 'when state id is :running' do + before { subject.stub(id: :running) } + + it { should be_created } + it { should be_running } + it { should_not be_off } + end + + context 'when state id is :poweroff' do + before { subject.stub(id: :poweroff) } + + it { should be_created } + it { should be_off } + it { should_not be_running } + end + + MACHINE_DEFAULTS = {id: nil} + def mocked_machine(stubbed_methods = {}) + fire_double('Vagrant::Machine', MACHINE_DEFAULTS.merge(stubbed_methods)) + end +end