vaguerent/test/unit/vagrant/machine_index_test.rb

381 lines
9.8 KiB
Ruby

# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
require "json"
require "pathname"
require "tempfile"
require File.expand_path("../../base", __FILE__)
require "vagrant/machine_index"
describe Vagrant::MachineIndex do
include_context "unit"
let(:data_dir) { Pathname.new(Dir.mktmpdir("vagrant-test-machine-index-data-dir")) }
let(:entry_klass) { Vagrant::MachineIndex::Entry }
let(:new_entry) do
entry_klass.new.tap do |e|
e.name = "foo"
e.vagrantfile_path = "/bar"
end
end
subject { described_class.new(data_dir) }
after do
FileUtils.rm_rf(data_dir)
end
it "raises an exception if the data file is corrupt" do
data_dir.join("index").open("w") do |f|
f.write(JSON.dump({}))
end
expect { subject }.
to raise_error(Vagrant::Errors::CorruptMachineIndex)
end
it "raises an exception if the JSON is invalid" do
data_dir.join("index").open("w") do |f|
f.write("foo")
end
expect { subject }.
to raise_error(Vagrant::Errors::CorruptMachineIndex)
end
describe "#each" do
before do
5.times do |i|
e = entry_klass.new
e.name = "entry-#{i}"
e.vagrantfile_path = "/foo"
subject.release(subject.set(e))
end
end
it "should iterate over all the elements" do
items = []
subject = described_class.new(data_dir)
subject.each do |entry|
items << entry.name
end
items.sort!
expect(items).to eq([
"entry-0",
"entry-1",
"entry-2",
"entry-3",
"entry-4",
])
end
end
describe "#get and #release" do
before do
data = {
"version" => 1,
"machines" => {
"bar" => {
"name" => "default",
"provider" => "vmware",
"local_data_path" => "/foo",
"vagrantfile_path" => "/foo/bar/baz",
"state" => "running",
"updated_at" => "foo",
},
"baz" => {
"name" => "default",
"provider" => "vmware",
"vagrantfile_path" => "/foo/bar/baz",
"state" => "running",
"updated_at" => "foo",
"extra_data" => {
"foo" => "bar",
},
},
}
}
data_dir.join("index").open("w") do |f|
f.write(JSON.dump(data))
end
end
it "returns nil if the machine doesn't exist" do
expect(subject.get("foo")).to be_nil
expect(subject.get(nil)).to be_nil
end
it "returns nil if the machine doesn't exist (is an empty string)" do
expect(subject.get("")).to be_nil
expect(subject.get(nil)).to be_nil
end
it "returns a valid entry if the machine exists" do
result = subject.get("bar")
expect(result.id).to eq("bar")
expect(result.name).to eq("default")
expect(result.provider).to eq("vmware")
expect(result.local_data_path).to eq(Pathname.new("/foo"))
expect(result.vagrantfile_path).to eq(Pathname.new("/foo/bar/baz"))
expect(result.state).to eq("running")
expect(result.updated_at).to eq("foo")
expect(result.extra_data).to eq({})
end
it "returns a valid entry with extra data" do
result = subject.get("baz")
expect(result.id).to eq("baz")
expect(result.extra_data).to eq({
"foo" => "bar",
})
end
it "returns a valid entry by unique prefix" do
result = subject.get("b")
expect(result).to_not be_nil
expect(result.id).to eq("bar")
end
it "should include? by prefix" do
expect(subject.include?("b")).to be(true)
end
it "should return false if given nil input" do
expect(subject.include?(nil)).to be(false)
end
it "locks the entry so subsequent gets fail" do
result = subject.get("bar")
expect(result).to_not be_nil
expect { subject.get("bar") }.
to raise_error(Vagrant::Errors::MachineLocked)
end
it "can unlock a machine" do
result = subject.get("bar")
expect(result).to_not be_nil
subject.release(result)
result = subject.get("bar")
expect(result).to_not be_nil
end
end
describe "#include" do
it "should not include non-existent things" do
expect(subject.include?("foo")).to be(false)
end
it "should include created entries" do
result = subject.set(new_entry)
expect(result.id).to_not be_empty
subject.release(result)
subject = described_class.new(data_dir)
expect(subject.include?(result.id)).to be(true)
end
end
describe "#set and #get and #delete" do
it "adds a new entry" do
result = subject.set(new_entry)
expect(result.id).to_not be_empty
# It should be locked
expect { subject.get(result.id) }.
to raise_error(Vagrant::Errors::MachineLocked)
# Get it froma new class and check the results
subject.release(result)
subject = described_class.new(data_dir)
entry = subject.get(result.id)
expect(entry).to_not be_nil
expect(entry.name).to eq("foo")
# TODO: test that updated_at is set
end
it "can delete an entry" do
result = subject.set(new_entry)
expect(result.id).to_not be_empty
subject.delete(result)
# Get it from a new class and check the results
subject = described_class.new(data_dir)
entry = subject.get(result.id)
expect(entry).to be_nil
end
it "can delete an entry that doesn't exist" do
e = entry_klass.new
expect(subject.delete(e)).to be(true)
end
it "updates an existing entry" do
entry = entry_klass.new
entry.name = "foo"
entry.vagrantfile_path = "/bar"
result = subject.set(entry)
expect(result.id).to_not be_empty
result.name = "bar"
result.extra_data["foo"] = "bar"
nextresult = subject.set(result)
expect(nextresult.id).to eq(result.id)
# Release it so we can test the contents
subject.release(nextresult)
# Get it froma new class and check the results
subject = described_class.new(data_dir)
entry = subject.get(result.id)
expect(entry).to_not be_nil
expect(entry.name).to eq("bar")
expect(entry.extra_data).to eq({
"foo" => "bar",
})
end
it "updates an existing directory if the name, provider, and path are the same" do
entry = entry_klass.new
entry.name = "foo"
entry.provider = "bar"
entry.vagrantfile_path = "/bar"
entry.state = "foo"
result = subject.set(entry)
expect(result.id).to_not be_empty
# Release it so we can modify it
subject.release(result)
entry2 = entry_klass.new
entry2.name = entry.name
entry2.provider = entry.provider
entry2.vagrantfile_path = entry.vagrantfile_path
entry2.state = "bar"
expect(entry2.id).to be_nil
nextresult = subject.set(entry2)
expect(nextresult.id).to eq(result.id)
# Release it so we can test the contents
subject.release(nextresult)
# Get it from a new class and check the results
subject = described_class.new(data_dir)
entry = subject.get(result.id)
expect(entry).to_not be_nil
expect(entry.name).to eq(entry2.name)
expect(entry.state).to eq(entry2.state)
end
end
describe "#recover" do
it "recovers an entry if not in the index" do
result = subject.recover(new_entry)
expect(result.id).to_not be_empty
expect { subject.get(result.id) }.to raise_error(Vagrant::Errors::MachineLocked)
end
it "returns an entry if in the index" do
test_entry = entry_klass.new()
entry = subject.set(test_entry)
subject.release(entry)
new_test_entry = entry_klass.new(id=entry.id, {})
result = subject.recover(new_test_entry)
expect(result.id).to eq(entry.id)
end
end
end
describe Vagrant::MachineIndex::Entry do
include_context "unit"
let(:env) {
iso_env = isolated_environment
iso_env.vagrantfile(vagrantfile)
iso_env.create_vagrant_env
}
let(:vagrantfile) { "" }
describe "#valid?" do
let(:machine) { env.machine(:default, :dummy) }
subject do
described_class.new.tap do |e|
e.name = "default"
e.provider = "dummy"
e.vagrantfile_path = env.root_path
end
end
it "should be valid with a valid entry" do
machine.id = "foo"
expect(subject).to be_valid(env.home_path)
end
it "should be invalid if no Vagrantfile path is set" do
subject.vagrantfile_path = nil
expect(subject).to_not be_valid(env.home_path)
end
it "should be invalid if the Vagrantfile path does not exist" do
subject.vagrantfile_path = Pathname.new("/i/should/not/exist")
expect(subject).to_not be_valid(env.home_path)
end
it "should be invalid if the machine is inactive" do
machine.id = nil
expect(subject).to_not be_valid(env.home_path)
end
it "should be invalid if machine is not created" do
machine.id = "foo"
machine.provider.state = Vagrant::MachineState::NOT_CREATED_ID
expect(subject).to_not be_valid(env.home_path)
end
context "with another active machine" do
let(:vagrantfile) do
<<-VF
Vagrant.configure("2") do |config|
config.vm.define "web"
config.vm.define "db"
end
VF
end
it "should be invalid if the wrong machine is active only" do
m = env.machine(:web, :dummy)
m.id = "foo"
subject.name = "db"
expect(subject).to_not be_valid(env.home_path)
end
it "should be valid if the correct machine is active" do
env.machine(:web, :dummy).id = "foo"
env.machine(:db, :dummy).id = "foo"
subject.name = "db"
expect(subject).to be_valid(env.home_path)
end
end
end
end