require 'spec_helper' require Vagrant.source_root.join('plugins/communicators/ssh/communicator') require 'vocker/docker_client' describe VagrantPlugins::Vocker::DockerClient do verify_contract(:docker_client) fake(:communicator, test: true) { VagrantPlugins::CommunicatorSSH::Communicator } let(:machine) { fake(:machine, communicate: communicator) } subject { described_class.new(machine) } it 'pulls configured images' do subject.pull_images 'base', 'mysql' expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /docker pull base/}) expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /docker pull mysql/}) end it 'verifies if the docker daemon is running' do stub(communicator).test(with{|cmd| cmd == 'test -f /var/run/docker.pid'}) { true } expect(subject.daemon_running?).to be_true stub(communicator).test(any_args) { false } expect(subject.daemon_running?).to be_false end context 'running containers' do let(:containers) { {'mysql' => {image: 'mysql'}} } it 'ensures container ids folder exists' do subject.run containers expect(communicator).to have_received.sudo('mkdir -p /var/lib/vocker/cids') end context 'parameters' do let(:containers) { { 'my-db' => { image: 'mysql', cidfile: '/foo/bla', dns: '127.0.0.1', volumes: ['/host/path:/guest/path', '/container-volume'], ports: ['1:2', ':3'], links: ['other:db', 'foo:bar'], additional_run_args: 'some parameter' } } } before do stub(communicator).test(with{|cmd| cmd =~ /docker ps/}) { false } subject.run containers end it 'automatically assigns a digest of the image name as the cidfile if not specified' do stub(Digest::SHA1).hexdigest('my-db') { 'digest' } containers['my-db'][:cidfile] = nil subject.run containers expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /-cidfile=\/var\/lib\/vocker\/cids\/digest/}) end it 'allows cidfile to be specified' do expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /-cidfile=\/foo\/bla/}) end it 'allows a dns to be specified' do expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /-dns=127\.0\.0\.1/}) end it 'allows an array of ports to be specified' do expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /-p 1:2 -p :3/}) end it 'allows an array of volumes to be specified' do expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /-v \/host\/path:\/guest\/path -v \/container-volume/}) end it 'allows an array of links to be specified' do expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /-link other:db -link foo:bar/}) end it 'provides the container name to the docker command' do expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /-name=my-db/}) end it 'allows additional params to be passed to the run command' do expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /some parameter/}) end end context 'when the container already exists' do before do stub(communicator).test(with{|cmd| cmd =~ /docker ps -a -q/}) { true } end it 'starts the container if it is stopped' do stub(communicator).test(with{|cmd| cmd =~ /docker ps -q/}) { false } subject.run containers expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /docker start/}) end it 'noops if container is already running' do stub(communicator).test(with{|cmd| cmd =~ /docker ps -q/}) { true } subject.run containers expect(communicator).to_not have_received.sudo(with{|cmd| cmd =~ /docker start/}) end end context 'when the container does not exist' do before do stub(communicator).test(with{|cmd| cmd =~ /docker ps/}) { false } subject.run containers end it 'creates a new container' do expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /docker run/}) end end context 'bind mounts' do before do containers['mysql'][:volumes] = '/guest/path:/container/path' stub(communicator).test(with{|cmd| cmd =~ /docker ps/}) { false } subject.run containers end it 'ensures the guest VM path exists' do expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /mkdir -p \/guest\/path/}) end end context 'data volumes' do before do containers['mysql'][:volumes] = ['/container/path'] subject.run containers end it 'does not try to create a guest path it' do expect(communicator).to_not have_received.sudo(with{|cmd| cmd =~ /mkdir -p \/container\/path/}) end end end end