You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2017/01/25 09:58:54 UTC

[2/3] jclouds-labs git commit: Add Vagrant provider

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/main/java/org/jclouds/vagrant/strategy/VagrantDefaultImageCredentials.java
----------------------------------------------------------------------
diff --git a/vagrant/src/main/java/org/jclouds/vagrant/strategy/VagrantDefaultImageCredentials.java b/vagrant/src/main/java/org/jclouds/vagrant/strategy/VagrantDefaultImageCredentials.java
new file mode 100644
index 0000000..97667cf
--- /dev/null
+++ b/vagrant/src/main/java/org/jclouds/vagrant/strategy/VagrantDefaultImageCredentials.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.strategy;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy;
+import org.jclouds.domain.Credentials;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.domain.LoginCredentials.Builder;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.logging.Logger;
+import org.jclouds.vagrant.internal.BoxConfig;
+import org.jclouds.vagrant.reference.VagrantConstants;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.io.Files;
+import com.google.inject.Singleton;
+
+@Singleton
+public class VagrantDefaultImageCredentials implements PopulateDefaultLoginCredentialsForImageStrategy {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   protected final LoginCredentials creds;
+   protected final Map<String, Credentials> credentialStore;
+   protected final BoxConfig.Factory boxConfigFactory;
+
+   @Inject
+   VagrantDefaultImageCredentials(
+         @Nullable @Named("image") LoginCredentials creds,
+         Map<String, Credentials> credentialStore,
+         BoxConfig.Factory boxConfigFactory) {
+      this.creds = creds;
+      this.credentialStore = checkNotNull(credentialStore, "credentialStore");
+      this.boxConfigFactory = checkNotNull(boxConfigFactory, "boxConfigFactory");
+   }
+
+   @Override
+   public LoginCredentials apply(Object resourceToAuthenticate) {
+      checkState(resourceToAuthenticate instanceof Image, "this is only valid for images, not %s",
+            resourceToAuthenticate.getClass().getSimpleName());
+      if (creds != null)
+         return creds;
+      Image image = Image.class.cast(resourceToAuthenticate);
+      if (credentialStore.containsKey("image#" + image.getId())) {
+         return LoginCredentials.fromCredentials(credentialStore.get("image#" + image.getId()));
+      // Skipping osFamilyToCredentials - not applicable to vagrant world
+      } else if (image.getOperatingSystem().getFamily() == OsFamily.WINDOWS) {
+         return parseWinRmBoxCredentials(image);
+      } else {
+         return parseSshBoxCredentials(image);
+      }
+   }
+
+   private LoginCredentials parseWinRmBoxCredentials(Image image) {
+      BoxConfig parser = boxConfigFactory.newInstance(image);
+      String username = parser.getStringKey(VagrantConstants.KEY_WINRM_USERNAME).or(VagrantConstants.DEFAULT_USERNAME);
+      String password = parser.getStringKey(VagrantConstants.KEY_WINRM_PASSWORD).or(VagrantConstants.DEFAULT_PASSWORD);
+      return LoginCredentials.builder()
+            .user(username)
+            .password(password)
+            .noPrivateKey()
+            .build();
+   }
+
+   private LoginCredentials parseSshBoxCredentials(Image image) {
+      BoxConfig parser = boxConfigFactory.newInstance(image);
+      String username = parser.getStringKey(VagrantConstants.KEY_SSH_USERNAME).or(VagrantConstants.DEFAULT_USERNAME);
+      Builder credBuilder = LoginCredentials.builder().user(username);
+      Optional<String> password = parser.getStringKey(VagrantConstants.KEY_SSH_PASSWORD);
+      if (password.isPresent()) {
+         credBuilder.password(password.get());
+      }
+      Optional<String> privateKeyPath = parser.getStringKey(VagrantConstants.KEY_SSH_PRIVATE_KEY_PATH);
+      if (privateKeyPath.isPresent()) {
+         File privateKey = new File(parser.getFolder(), privateKeyPath.get());
+         if (privateKey.exists()) {
+            try {
+               credBuilder.privateKey(Files.toString(privateKey, Charsets.UTF_8));
+            } catch (IOException e) {
+               throw new IllegalStateException("Failure reading private key file " +
+                     privateKey.getAbsolutePath() + " for box " + parser.getFolder().getAbsolutePath());
+            }
+         } else {
+            logger.warn("Private key " + privateKeyPath.get() + " for box " +
+                  parser.getFolder().getAbsolutePath() + " not found at " + privateKey.getAbsolutePath() + ". Ignoring.");
+         }
+      }
+      return credBuilder.build();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/main/java/org/jclouds/vagrant/suppliers/VagrantHardwareSupplier.java
----------------------------------------------------------------------
diff --git a/vagrant/src/main/java/org/jclouds/vagrant/suppliers/VagrantHardwareSupplier.java b/vagrant/src/main/java/org/jclouds/vagrant/suppliers/VagrantHardwareSupplier.java
new file mode 100644
index 0000000..f048b48
--- /dev/null
+++ b/vagrant/src/main/java/org/jclouds/vagrant/suppliers/VagrantHardwareSupplier.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.suppliers;
+
+import java.util.Map;
+
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.domain.Volume.Type;
+import org.jclouds.compute.domain.VolumeBuilder;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+
+public class VagrantHardwareSupplier implements Supplier<Map<String, Hardware>> {
+   private static final Map<String, Hardware> HARDWARE = ImmutableMap.of(
+         "micro", hardware("micro", 512, 1),
+         "small", hardware("small", 1024, 1),
+         "medium", hardware("medium", 2048, 2),
+         "large", hardware("large", 4096, 2),
+         "xlarge", hardware("xlarge", 8192, 4));
+
+   private static Hardware hardware(String name, int ram, int cores) {
+      return new HardwareBuilder()
+            .ids(name)
+            .hypervisor("VirtualBox")
+            .name(name)
+            .processor(new Processor(cores, 1))
+            .ram(ram)
+            .volume(new VolumeBuilder().bootDevice(true).durable(true).type(Type.LOCAL).build())
+            .build();
+   }
+
+   @Override
+   public Map<String, Hardware> get() {
+      return HARDWARE;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/main/java/org/jclouds/vagrant/util/VagrantUtils.java
----------------------------------------------------------------------
diff --git a/vagrant/src/main/java/org/jclouds/vagrant/util/VagrantUtils.java b/vagrant/src/main/java/org/jclouds/vagrant/util/VagrantUtils.java
new file mode 100644
index 0000000..68c6249
--- /dev/null
+++ b/vagrant/src/main/java/org/jclouds/vagrant/util/VagrantUtils.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.jclouds.util.Closeables2;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.ByteStreams;
+
+public class VagrantUtils {
+   public static void deleteFolder(File path) {
+      if (path.isDirectory()) {
+         for (File sub : path.listFiles()) {
+            deleteFolder(sub);
+         }
+      }
+      if (!path.delete()) {
+         throw new IllegalStateException("Can't delete " + path.getAbsolutePath());
+      }
+   }
+
+   public static void write(File file, String value) throws IOException {
+      write(file, new ByteArrayInputStream(value.getBytes(Charsets.UTF_8)));
+   }
+
+   public static void write(File file, InputStream in) throws IOException {
+      OutputStream out = new FileOutputStream(file);
+      try {
+         ByteStreams.copy(in, out);
+      } finally {
+         Closeables2.closeQuietly(out);
+         Closeables2.closeQuietly(in);
+      }
+   }
+
+   public static void deleteFiles(File path, String filePattern) {
+      for (File f : path.listFiles()) {
+         if (f.getName().startsWith(filePattern)) {
+            if (!f.delete()) {
+               throw new IllegalStateException("Failed deleting machine file " + f.getAbsolutePath());
+            }
+         }
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/main/resources/Vagrantfile
----------------------------------------------------------------------
diff --git a/vagrant/src/main/resources/Vagrantfile b/vagrant/src/main/resources/Vagrantfile
new file mode 100644
index 0000000..9912ff1
--- /dev/null
+++ b/vagrant/src/main/resources/Vagrantfile
@@ -0,0 +1,80 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'yaml'
+
+# Because of linked_clone. 1.9+ recommended for Ubuntu Xenial
+Vagrant.require_version ">= 1.8"
+
+Vagrant.configure(2) do |config|
+  Dir.glob('machines/*.yaml') do |machine_file|
+    machine_config = YAML.load_file(machine_file)
+    name = File.basename(machine_file, ".yaml")
+    config.vm.define name do |config|
+      config.vm.box = machine_config["box"]
+      config.vm.box_check_update = false
+      config.vm.network "private_network", type: "dhcp"
+      config.vm.synced_folder '.', '/vagrant', disabled: true
+      config.ssh.username = machine_config["username"] if machine_config.key?("username") 
+      config.ssh.password = machine_config["password"] if machine_config.key?("password")
+      config.ssh.private_key_path = machine_config["private_key_path"] if machine_config.key?("private_key_path")
+
+      isWindows = (machine_config["osFamily"] == "windows");
+      if isWindows
+        # That's a Powershell script.
+        # Go through a temporary file, otherwise getting the following error:
+
+        # out-lineoutput : The OS handle's position is not what FileStream expected. Do n
+        # ot use a handle simultaneously in one FileStream and in Win32 code or another F
+        # ileStream. This may cause data loss.
+        #     + CategoryInfo          : NotSpecified: (:) [out-lineoutput], IOException
+        #     + FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Comma 
+        #     nds.OutLineOutputCommand
+
+        config.vm.provision "shell", inline: <<-EOF
+          $tmp = [System.IO.Path]::GetTempFileName()
+          echo "================= Networks start =================" > $tmp
+          ipconfig | find "IPv4 Address" >> $tmp 2>&1
+          echo "================= Networks end ===================" >> $tmp
+          echo "================= Hostname start ==========================" >> $tmp
+          hostname >> $tmp 2>&1
+          echo "================= Hostname end ============================" >> $tmp
+          type $tmp
+        EOF
+      else
+        config.vm.provision "shell", inline: <<-EOF
+          echo "================= Networks start ================="
+          ip address show | grep 'scope global' 2>&1
+          echo "================= Networks end ==================="
+          echo "================= Hostname start =========================="
+          hostname 2>&1
+          echo "================= Hostname end ============================"
+        EOF
+      end
+
+      config.vm.provider "virtualbox" do |v|
+        v.gui = false
+        v.memory = machine_config["memory"] if machine_config.key?("memory")
+        v.cpus = machine_config["cpus"] if machine_config.key?("cpus")
+        v.linked_clone = true
+        # Windows needs additional drivers for virtio
+        if !isWindows
+          v.customize ["modifyvm", :id, "--nictype1", "virtio"]
+          v.customize ["modifyvm", :id, "--nictype2", "virtio"]
+        end
+      end
+    end
+  end
+end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/compute/BoxConfigLiveTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/compute/BoxConfigLiveTest.java b/vagrant/src/test/java/org/jclouds/vagrant/compute/BoxConfigLiveTest.java
new file mode 100644
index 0000000..3475f43
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/compute/BoxConfigLiveTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.compute;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
+import org.jclouds.vagrant.internal.BoxConfig;
+import org.jclouds.vagrant.reference.VagrantConstants;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+
+@Test(groups = "live", testName = "BoxConfigLiveTest")
+public class BoxConfigLiveTest extends BaseComputeServiceContextLiveTest {
+
+   public BoxConfigLiveTest() {
+      provider = "vagrant";
+   }
+
+   @Test
+   public void testDefaultCredentials() {
+      Image image = view.getComputeService().getImage("ubuntu/trusty64");
+
+      BoxConfig.Factory boxConfigFactory = new BoxConfig.Factory();
+      BoxConfig boxConfig = boxConfigFactory.newInstance(image);
+
+      assertFalse(boxConfig.getStringKey(VagrantConstants.CONFIG_USERNAME).isPresent());
+      assertFalse(boxConfig.getStringKey(VagrantConstants.CONFIG_PASSWORD).isPresent());
+   }
+
+   @Test
+   public void testCustomUsernameAndPassword() {
+      Image image = view.getComputeService().getImage("ubuntu/xenial64");
+
+      BoxConfig.Factory boxConfigFactory = new BoxConfig.Factory();
+      BoxConfig boxConfig = boxConfigFactory.newInstance(image);
+
+      assertEquals(boxConfig.getStringKey(VagrantConstants.CONFIG_USERNAME), Optional.of("ubuntu"));
+      // Password changes on each box update
+      assertTrue(boxConfig.getStringKey(VagrantConstants.CONFIG_PASSWORD).isPresent());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/compute/VagrantComputeServiceAdapterLiveTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/compute/VagrantComputeServiceAdapterLiveTest.java b/vagrant/src/test/java/org/jclouds/vagrant/compute/VagrantComputeServiceAdapterLiveTest.java
new file mode 100644
index 0000000..58580ca
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/compute/VagrantComputeServiceAdapterLiveTest.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.compute;
+
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.internal.BaseComputeServiceLiveTest;
+import org.jclouds.sshj.config.SshjSshClientModule;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+public class VagrantComputeServiceAdapterLiveTest extends BaseComputeServiceLiveTest {
+
+   public VagrantComputeServiceAdapterLiveTest() {
+      provider = "vagrant";
+   }
+
+   @Override
+   protected Module getSshModule() {
+      return new SshjSshClientModule();
+   }
+
+   @Override
+   @Test(enabled = true)
+   public void testCorrectAuthException() throws Exception {
+      // Vagrant doesn't use credential info
+   }
+
+   @Override
+   protected void checkTagsInNodeEquals(NodeMetadata node, ImmutableSet<String> tags) {
+      // Vagrant doesn't support tags
+      // TODO Could store it in the json
+   }
+
+   @Override
+   protected void checkUserMetadataContains(NodeMetadata node, ImmutableMap<String, String> userMetadata) {
+      // Vagrant doesn't support user metadata
+      // TODO Could store it in the json
+   }
+
+   @Override
+   @Test(enabled = true, dependsOnMethods = "testGet")
+   public void testOptionToNotBlock() throws Exception {
+       // LoginCredentials are available only after the machine starts,
+       // so can't return earlier.
+   }
+
+   @Override
+   @Test(enabled = true, dependsOnMethods = { "testCompareSizes" })
+   public void testAScriptExecutionAfterBootWithBasicTemplate() throws Exception {
+      // Fails on CentOS 7. Can't ssh back with user foo because SELinux not configured correctly.
+      // "foo" is created out of the /home folder, /over/ridden is not white listed with the correct context.
+      // Steps needed to configure SELinux before creating the user:
+      //
+      // semanage fcontext -a -e /home /over/ridden
+      // mkdir /over/ridden
+      // restorecon /over/ridden
+      // useradd -d /over/ridden/foo foo
+      //
+      // semanage is not available on a default install - needs "yum install policycoreutils-python"
+
+      Template template = buildTemplate(templateBuilder());
+      if (template.getImage().getOperatingSystem().getFamily() != OsFamily.CENTOS) {
+         super.testAScriptExecutionAfterBootWithBasicTemplate();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/compute/VagrantTemplateBuilderLiveTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/compute/VagrantTemplateBuilderLiveTest.java b/vagrant/src/test/java/org/jclouds/vagrant/compute/VagrantTemplateBuilderLiveTest.java
new file mode 100644
index 0000000..dcb8040
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/compute/VagrantTemplateBuilderLiveTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.compute;
+
+import static org.jclouds.compute.domain.OsFamily.UBUNTU;
+import static org.jclouds.compute.domain.OsFamily.CENTOS;
+import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.Set;
+
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.internal.BaseTemplateBuilderLiveTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+@Test(groups = "live", testName = "VagrantTemplateBuilderLiveTest")
+public class VagrantTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
+
+   public VagrantTemplateBuilderLiveTest() {
+      provider = "vagrant";
+   }
+
+   @Override
+   protected Set<String> getIso3166Codes() {
+      return ImmutableSet.of();
+   }
+
+   @Test
+   @Override
+   public void testDefaultTemplateBuilder() throws IOException {
+      Template defaultTemplate = view.getComputeService().templateBuilder().build();
+      String imageId = defaultTemplate.getImage().getId();
+      if (imageId.startsWith("ubuntu")) {
+         assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), UBUNTU);
+      } else if (imageId.startsWith("centos")) {
+         assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), CENTOS);
+      }
+      assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
+      assertEquals(defaultTemplate.getHardware().getName(), "micro");
+      assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/compute/WindowsLiveTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/compute/WindowsLiveTest.java b/vagrant/src/test/java/org/jclouds/vagrant/compute/WindowsLiveTest.java
new file mode 100644
index 0000000..a8887e7
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/compute/WindowsLiveTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.compute;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.TemplateBuilder;
+import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.vagrant.internal.BoxConfig;
+import org.jclouds.vagrant.reference.VagrantConstants;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+
+/**
+ * Building the image:
+ *   $ git clone https://github.com/boxcutter/windows.git boxcutter-windows
+ *   $ cd boxcutter-windows
+ *   $ make virtualbox/eval-win7x86-enterprise
+ *   $ vagrant box add boxcutter/eval-win7x86-enterprise box/virtualbox/eval-win7x86-enterprise-nocm-1.0.4.box
+ */
+@Test(groups = "live", singleThreaded = true, enabled = true, testName = "WindowsLiveTest")
+public class WindowsLiveTest extends BaseComputeServiceContextLiveTest {
+
+   protected ComputeService client;
+
+   public WindowsLiveTest() {
+      provider = "vagrant";
+   }
+
+   @Override
+   protected void initializeContext() {
+      super.initializeContext();
+      client = view.getComputeService();
+   }
+
+   protected TemplateBuilder templateBuilder() {
+      TemplateBuilder templateBuilder = client.templateBuilder();
+      if (templateBuilderSpec != null) {
+         templateBuilder = templateBuilder.from(templateBuilderSpec);
+      }
+      templateBuilder.imageId(getImageId());
+      return templateBuilder;
+   }
+
+   private String getImageId() {
+      return "boxcutter/eval-win7x86-enterprise";
+   }
+
+   protected Template buildTemplate(TemplateBuilder templateBuilder) {
+      return templateBuilder.build();
+   }
+
+   @Test
+   public void testGet() throws Exception {
+      Set<? extends NodeMetadata> nodes = client.createNodesInGroup("vagrant-win", 1, buildTemplate(templateBuilder()));
+      NodeMetadata node = Iterables.getOnlyElement(nodes);
+      OperatingSystem os = node.getOperatingSystem();
+      LoginCredentials creds = node.getCredentials();
+      assertEquals(os.getFamily(), OsFamily.WINDOWS);
+      assertEquals(creds.getUser(), "vagrant");
+      assertTrue(creds.getOptionalPassword().isPresent(), "password expected");
+      assertEquals(creds.getOptionalPassword().get(), "vagrant");
+      assertFalse(creds.getOptionalPrivateKey().isPresent(), "no private key expected for windows");
+      assertEquals(node.getLoginPort(), 5985);
+      client.destroyNode(node.getId());
+   }
+
+
+   @Test
+   public void testBoxConfig() {
+      Image image = view.getComputeService().getImage(getImageId());
+
+      BoxConfig.Factory boxConfigFactory = new BoxConfig.Factory();
+      BoxConfig boxConfig = boxConfigFactory.newInstance(image);
+
+      assertEquals(boxConfig.getStringKey(".vm.communicator"), Optional.of("winrm"));
+      assertEquals(boxConfig.getKey(VagrantConstants.KEY_VM_GUEST), Optional.of(VagrantConstants.VM_GUEST_WINDOWS));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/functions/BoxToImageTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/functions/BoxToImageTest.java b/vagrant/src/test/java/org/jclouds/vagrant/functions/BoxToImageTest.java
new file mode 100644
index 0000000..ac6307c
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/functions/BoxToImageTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.domain.Image.Status;
+import org.jclouds.vagrant.internal.BoxConfig;
+import org.jclouds.vagrant.reference.VagrantConstants;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+
+import vagrant.api.domain.Box;
+
+public class BoxToImageTest {
+   
+   @DataProvider(name = "boxedProvider")
+   public Object[][] boxesProvider() {
+      return new Object[][] {
+         {new Box("centos/7", "20161226", "virtualbox"), null, OsFamily.CENTOS},
+         {new Box("ubuntu/xenial64", "20161226", "virtualbox"), null, OsFamily.UBUNTU},
+         {new Box("windows-eval", "20161226", "virtualbox"), null, OsFamily.WINDOWS},
+         {new Box("some-random-name", "20161226", "virtualbox"), Optional.of(VagrantConstants.VM_GUEST_WINDOWS), OsFamily.WINDOWS},
+         {new Box("some-random-name", "20161226", "virtualbox"), Optional.absent(), OsFamily.UNRECOGNIZED},
+      };
+   }
+
+   @Test(dataProvider = "boxedProvider")
+   public void testBoxToImage(Box box, Optional<String> guestType, OsFamily osFamilyExpected) {
+      BoxConfig boxConfig = EasyMock.createMock(BoxConfig.class);
+      if (guestType != null) {
+         EasyMock.expect(boxConfig.getKey(VagrantConstants.KEY_VM_GUEST)).andReturn(guestType);
+      }
+
+      BoxConfig.Factory boxConfigFactory = EasyMock.createMock(BoxConfig.Factory.class);
+      EasyMock.expect(boxConfigFactory.newInstance(EasyMock.<Box>anyObject())).andReturn(boxConfig);
+
+      EasyMock.replay(boxConfigFactory, boxConfig);
+
+      BoxToImage boxToImage = new BoxToImage(boxConfigFactory);
+      Image image = boxToImage.apply(box);
+
+      assertEquals(image.getId(), box.getName());
+      assertEquals(image.getProviderId(), box.getName());
+      assertEquals(image.getName(), box.getName());
+      assertEquals(image.getVersion(), box.getVersion());
+      assertEquals(image.getOperatingSystem().getFamily(), osFamilyExpected);
+      assertEquals(image.getOperatingSystem().getName(), box.getName());
+      assertEquals(image.getOperatingSystem().getVersion(), box.getVersion());
+      assertEquals(image.getOperatingSystem().getDescription(), box.getName());
+      assertEquals(image.getStatus(), Status.AVAILABLE);
+      assertEquals(image.getUserMetadata(), ImmutableMap.of(VagrantConstants.USER_META_PROVIDER, box.getProvider()));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/functions/MachineToNodeMetadataTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/functions/MachineToNodeMetadataTest.java b/vagrant/src/test/java/org/jclouds/vagrant/functions/MachineToNodeMetadataTest.java
new file mode 100644
index 0000000..7f5f5f2
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/functions/MachineToNodeMetadataTest.java
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Set;
+
+import org.easymock.EasyMock;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadata.Status;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.domain.Location;
+import org.jclouds.vagrant.domain.VagrantNode;
+import org.jclouds.vagrant.internal.BoxConfig;
+import org.jclouds.vagrant.internal.MachineConfig;
+import org.jclouds.vagrant.reference.VagrantConstants;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import vagrant.api.domain.Box;
+
+public class MachineToNodeMetadataTest {
+   private abstract static class MachineToNodeMetadataFixture {
+      @Test
+      public void doTest() {
+         OperatingSystem os = new OperatingSystem(getOsFamily(), "Jclouds OS", "10", "x64", "Jclouds Test Image", true);
+         Image image = new ImageBuilder()
+               .ids("jclouds/box")
+               .operatingSystem(os)
+               .status(org.jclouds.compute.domain.Image.Status.AVAILABLE)
+               .build();
+
+         ImmutableList<String> networks = ImmutableList.of("172.28.128.3");
+         VagrantNode node = VagrantNode.builder()
+               .setPath(new File("/path/to/machine"))
+               .setId("vagrant/node")
+               .setGroup("vagrant")
+               .setName("node")
+               .setImage(image)
+               .setNetworks(networks)
+               .setHostname("vagrant-node")
+               .build();
+
+         node.setMachineState(Status.RUNNING);
+
+         Location location = EasyMock.createMock(Location.class);
+
+         BoxConfig boxConfig = EasyMock.createMock(BoxConfig.class);
+         expectBoxConfig(boxConfig);
+
+         BoxConfig.Factory boxConfigFactory = EasyMock.createMock(BoxConfig.Factory.class);
+         EasyMock.expect(boxConfigFactory.newInstance((Image)EasyMock.<Box>anyObject())).andReturn(boxConfig);
+
+         MachineConfig machineConfig = EasyMock.createMock(MachineConfig.class);
+         EasyMock.expect(machineConfig.load()).andReturn(getMachineConfig());
+
+         MachineConfig.Factory machineConfigFactory = EasyMock.createMock(MachineConfig.Factory.class);
+         EasyMock.expect(machineConfigFactory.newInstance(node)).andReturn(machineConfig);
+
+         Hardware hardware = new HardwareBuilder().ids(getHardwareId()).ram(100).processor(new Processor(1.0, 1)).build();
+         Supplier<? extends Map<String, Hardware>> hardwareSupplier = Suppliers.ofInstance(ImmutableMap.of(getHardwareId(), hardware));
+
+         EasyMock.replay(location, boxConfig, boxConfigFactory,
+               machineConfig, machineConfigFactory);
+
+         @SuppressWarnings({ "unchecked", "rawtypes" })
+         Supplier<Set<? extends Location>> locations = (Supplier<Set<? extends Location>>)(Supplier)Suppliers.ofInstance(ImmutableSet.of(location));
+
+         MachineToNodeMetadata machineToNodeMetadata = new MachineToNodeMetadata(
+               locations,
+               boxConfigFactory,
+               machineConfigFactory,
+               hardwareSupplier);
+
+         NodeMetadata nodeMetadataActual = machineToNodeMetadata.apply(node);
+
+         NodeMetadataBuilder nodeMetadataBuilder = new NodeMetadataBuilder()
+               .ids("vagrant/node")
+               .name("node")
+               .location(location)
+               .group("vagrant")
+               .imageId("jclouds/box")
+               .operatingSystem(os)
+               .status(Status.RUNNING)
+               .hostname("vagrant-node")
+               .privateAddresses(networks)
+               .hardware(hardware);
+         customizeBuilder(nodeMetadataBuilder);
+         NodeMetadata nodeMetadataExpected = nodeMetadataBuilder
+               .build();
+
+         assertEquals(nodeMetadataActual.toString(), nodeMetadataExpected.toString());
+      }
+
+      protected Map<String, Object> getMachineConfig() {
+         return ImmutableMap.<String, Object>of(VagrantConstants.CONFIG_HARDWARE_ID, getHardwareId());
+      }
+
+      protected abstract void customizeBuilder(NodeMetadataBuilder nodeMetadataBuilder);
+      protected abstract String getHardwareId();
+      protected abstract OsFamily getOsFamily();
+      protected abstract void expectBoxConfig(BoxConfig boxConfig);
+   }
+
+   @Test
+   public void testMiniLinux() {
+      class MachineToNodeMetadataLinuxMini extends MachineToNodeMetadataFixture {
+         protected void customizeBuilder(NodeMetadataBuilder nodeMetadataBuilder) {
+            nodeMetadataBuilder.loginPort(2222);
+         }
+
+         protected String getHardwareId() {
+            return "mini";
+         }
+
+         protected OsFamily getOsFamily() {
+            return OsFamily.LINUX;
+         }
+
+         protected void expectBoxConfig(BoxConfig boxConfig) {
+            EasyMock.expect(boxConfig.getKey(VagrantConstants.KEY_SSH_PORT)).andReturn(Optional.of("2222"));
+         }
+      }
+      new MachineToNodeMetadataLinuxMini().doTest();
+   }
+
+   @Test
+   public void testDefaultSshPort() {
+      class MachineToNodeMetadataLinuxMini extends MachineToNodeMetadataFixture {
+
+         protected OsFamily getOsFamily() {
+            return OsFamily.LINUX;
+         }
+
+         protected void expectBoxConfig(BoxConfig boxConfig) {
+            EasyMock.expect(boxConfig.getKey(VagrantConstants.KEY_SSH_PORT)).andReturn(Optional.<String>absent());
+         }
+
+         protected void customizeBuilder(NodeMetadataBuilder nodeMetadataBuilder) {
+            nodeMetadataBuilder.loginPort(22);
+         }
+
+         protected String getHardwareId() {
+            return "mini";
+         }
+      }
+      new MachineToNodeMetadataLinuxMini().doTest();
+   }
+
+   @Test
+   public void testAutoLinux() {
+      class MachineToNodeMetadataLinuxMini extends MachineToNodeMetadataFixture {
+         protected OsFamily getOsFamily() {
+            return OsFamily.LINUX;
+         }
+
+         protected void expectBoxConfig(BoxConfig boxConfig) {
+            EasyMock.expect(boxConfig.getKey(VagrantConstants.KEY_SSH_PORT)).andReturn(Optional.of("2222"));
+         }
+
+         protected void customizeBuilder(NodeMetadataBuilder nodeMetadataBuilder) {
+            nodeMetadataBuilder.loginPort(2222)
+               .hardware(new HardwareBuilder()
+                  .ids("automatic:cores=2.0;ram=1000")
+                  .processor(new Processor(2.0, 1))
+                  .ram(1000)
+                  .build());
+         }
+
+         @Override
+         protected Map<String, Object> getMachineConfig() {
+            return ImmutableMap.<String, Object>of(
+                  VagrantConstants.CONFIG_HARDWARE_ID, getHardwareId(),
+                  VagrantConstants.CONFIG_CPUS, "2.0",
+                  VagrantConstants.CONFIG_MEMORY, "1000");
+         }
+
+         protected String getHardwareId() {
+            return "automatic";
+         }
+      }
+      new MachineToNodeMetadataLinuxMini().doTest();
+   }
+
+   @Test
+   public void testMiniWin() {
+      class MachineToNodeMetadataLinuxMini extends MachineToNodeMetadataFixture {
+         protected void customizeBuilder(NodeMetadataBuilder nodeMetadataBuilder) {
+            nodeMetadataBuilder.loginPort(8899);
+         }
+
+         protected String getHardwareId() {
+            return "mini";
+         }
+
+         protected OsFamily getOsFamily() {
+            return OsFamily.WINDOWS;
+         }
+
+         protected void expectBoxConfig(BoxConfig boxConfig) {
+            EasyMock.expect(boxConfig.getKey(VagrantConstants.KEY_WINRM_PORT)).andReturn(Optional.of("8899"));
+         }
+      }
+      new MachineToNodeMetadataLinuxMini().doTest();
+   }
+
+   @Test
+   public void testDefaultWinrmPort() {
+      class MachineToNodeMetadataLinuxMini extends MachineToNodeMetadataFixture {
+
+         protected OsFamily getOsFamily() {
+            return OsFamily.WINDOWS;
+         }
+
+         protected void expectBoxConfig(BoxConfig boxConfig) {
+            EasyMock.expect(boxConfig.getKey(VagrantConstants.KEY_WINRM_PORT)).andReturn(Optional.<String>absent());
+         }
+
+         protected void customizeBuilder(NodeMetadataBuilder nodeMetadataBuilder) {
+            nodeMetadataBuilder.loginPort(5985);
+         }
+
+         protected String getHardwareId() {
+            return "mini";
+         }
+      }
+      new MachineToNodeMetadataLinuxMini().doTest();
+   }
+
+   @Test
+   public void testAutoWin() {
+      class MachineToNodeMetadataLinuxMini extends MachineToNodeMetadataFixture {
+         protected OsFamily getOsFamily() {
+            return OsFamily.WINDOWS;
+         }
+
+         protected void expectBoxConfig(BoxConfig boxConfig) {
+            EasyMock.expect(boxConfig.getKey(VagrantConstants.KEY_WINRM_PORT)).andReturn(Optional.of("8899"));
+         }
+
+         protected void customizeBuilder(NodeMetadataBuilder nodeMetadataBuilder) {
+            nodeMetadataBuilder.loginPort(8899)
+               .hardware(new HardwareBuilder()
+                  .ids("automatic:cores=2.0;ram=1000")
+                  .processor(new Processor(2.0, 1))
+                  .ram(1000)
+                  .build());
+         }
+
+         @Override
+         protected Map<String, Object> getMachineConfig() {
+            return ImmutableMap.<String, Object>of(
+                  VagrantConstants.CONFIG_HARDWARE_ID, getHardwareId(),
+                  VagrantConstants.CONFIG_CPUS, "2.0",
+                  VagrantConstants.CONFIG_MEMORY, "1000");
+         }
+
+         protected String getHardwareId() {
+            return "automatic";
+         }
+      }
+      new MachineToNodeMetadataLinuxMini().doTest();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/functions/OutdatedBoxesFilterTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/functions/OutdatedBoxesFilterTest.java b/vagrant/src/test/java/org/jclouds/vagrant/functions/OutdatedBoxesFilterTest.java
new file mode 100644
index 0000000..7cf3f06
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/functions/OutdatedBoxesFilterTest.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Collection;
+import java.util.Set;
+
+import org.testng.annotations.Test;
+import org.testng.collections.Sets;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import vagrant.api.domain.Box;
+
+public class OutdatedBoxesFilterTest {
+   Collection<Box> UNFILTERED = ImmutableList.<Box>builder()
+         .add(new Box("CiscoCloud/microservices-infrastructure", "0.5", "virtualbox"))
+         .add(new Box("boxcutter/eval-win7x86-enterprise", "0", "virtualbox"))
+         .add(new Box("centos/7", "1603.01", "virtualbox"))
+         .add(new Box("centos/7", "1607.01", "virtualbox"))
+         .add(new Box("chef/centos-6.5", "1.0.0", "virtualbox"))
+         .add(new Box("chef/centos-7.0", "1.0.0", "virtualbox"))
+         .add(new Box("debian/jessie64", "8.4.0", "virtualbox"))
+         .add(new Box("debian/jessie64", "8.6.1", "virtualbox"))
+         .add(new Box("debian/wheezy64", "7.10.0", "virtualbox"))
+         .add(new Box("mitchellh/boot2docker", "1.2.0", "virtualbox"))
+         .add(new Box("nrel/CentOS-6.5-x86_64", "1.2.0", "virtualbox"))
+         .add(new Box("orlandohohmeier/toolchain", "0.5.1", "virtualbox"))
+         .add(new Box("playa_mesos_ubuntu_14.04", "0", "virtualbox"))
+         .add(new Box("snappy", "0", "virtualbox"))
+         .add(new Box("ubuntu/precise32", "20161208.0.0", "virtualbox"))
+         .add(new Box("ubuntu/precise64", "12.04.4", "virtualbox"))
+         .add(new Box("ubuntu/trusty64", "14.04", "virtualbox"))
+         .add(new Box("ubuntu/trusty64", "20160822.0.2", "virtualbox"))
+         .add(new Box("ubuntu/ubuntu-15.04-snappy-core-edge-amd64", "15.04.20150424", "virtualbox"))
+         .add(new Box("ubuntu/vivid64", "20150427.0.0", "virtualbox"))
+         .add(new Box("ubuntu/vivid64", "20150611.0.1", "virtualbox"))
+         .add(new Box("ubuntu/wily64", "20151106.0.0", "virtualbox"))
+         .add(new Box("ubuntu/wily64", "20160715.0.0", "virtualbox"))
+         .add(new Box("ubuntu/xenial64", "20160922.0.0", "virtualbox"))
+         .add(new Box("ubuntu/xenial64", "20161119.0.0", "virtualbox"))
+         .add(new Box("ubuntu/xenial64", "20161221.0.0", "virtualbox"))
+         .build();
+
+   Set<Box> FILTERED = ImmutableSet.<Box>builder()
+         .add(new Box("CiscoCloud/microservices-infrastructure", "0.5", "virtualbox"))
+         .add(new Box("boxcutter/eval-win7x86-enterprise", "0", "virtualbox"))
+         .add(new Box("centos/7", "1607.01", "virtualbox"))
+         .add(new Box("chef/centos-6.5", "1.0.0", "virtualbox"))
+         .add(new Box("chef/centos-7.0", "1.0.0", "virtualbox"))
+         .add(new Box("debian/jessie64", "8.6.1", "virtualbox"))
+         .add(new Box("debian/wheezy64", "7.10.0", "virtualbox"))
+         .add(new Box("mitchellh/boot2docker", "1.2.0", "virtualbox"))
+         .add(new Box("nrel/CentOS-6.5-x86_64", "1.2.0", "virtualbox"))
+         .add(new Box("orlandohohmeier/toolchain", "0.5.1", "virtualbox"))
+         .add(new Box("playa_mesos_ubuntu_14.04", "0", "virtualbox"))
+         .add(new Box("snappy", "0", "virtualbox"))
+         .add(new Box("ubuntu/precise32", "20161208.0.0", "virtualbox"))
+         .add(new Box("ubuntu/precise64", "12.04.4", "virtualbox"))
+         .add(new Box("ubuntu/trusty64", "20160822.0.2", "virtualbox"))
+         .add(new Box("ubuntu/ubuntu-15.04-snappy-core-edge-amd64", "15.04.20150424", "virtualbox"))
+         .add(new Box("ubuntu/vivid64", "20150611.0.1", "virtualbox"))
+         .add(new Box("ubuntu/wily64", "20160715.0.0", "virtualbox"))
+         .add(new Box("ubuntu/xenial64", "20161221.0.0", "virtualbox"))
+         .build();
+
+   @Test
+   public void testFilter() {
+      OutdatedBoxesFilter filter = new OutdatedBoxesFilter();
+      Collection<Box> actual = filter.apply(UNFILTERED);
+      assertEquals(Sets.newHashSet(actual), FILTERED, "Actual list: " + actual);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/internal/BoxConfigTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/internal/BoxConfigTest.java b/vagrant/src/test/java/org/jclouds/vagrant/internal/BoxConfigTest.java
new file mode 100644
index 0000000..631d813
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/internal/BoxConfigTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.jclouds.vagrant.reference.VagrantConstants;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+import com.google.common.io.Files;
+import com.google.common.io.Resources;
+
+import vagrant.api.domain.Box;
+
+public class BoxConfigTest {
+
+   private File vagrantHome;
+
+   @BeforeMethod
+   public void setUp() {
+      vagrantHome = new File(System.getProperty("java.io.tmpdir"), "jclouds/vagrant");
+   }
+
+   @Test
+   public void testKeys() throws IOException {
+      File boxFolder = new File(vagrantHome, "boxes/jclouds-VAGRANTSLASH-vagrant/0/virtualbox");
+      boxFolder.mkdirs();
+      File boxPath = new File(boxFolder, VagrantConstants.VAGRANTFILE);
+      Resources.asByteSource(getClass().getResource("/Vagrantfile.boxconfig")).copyTo(Files.asByteSink(boxPath));
+      
+      BoxConfig boxConfig = new BoxConfig.Factory().newInstance(vagrantHome, new Box("jclouds/vagrant", "0", "virtualbox"));
+      assertEquals(boxConfig.getKey(".non.existent"), Optional.absent());
+      assertEquals(boxConfig.getStringKey(".non.existent"), Optional.absent());
+      assertEquals(boxConfig.getKey(VagrantConstants.KEY_VM_GUEST), Optional.of(VagrantConstants.VM_GUEST_WINDOWS));
+      assertEquals(boxConfig.getKey(VagrantConstants.KEY_WINRM_USERNAME), Optional.of("\"jclouds-winrm\""));
+      assertEquals(boxConfig.getStringKey(VagrantConstants.KEY_WINRM_USERNAME), Optional.of("jclouds-winrm"));
+      assertEquals(boxConfig.getStringKey(VagrantConstants.KEY_WINRM_PASSWORD), Optional.of("password-winrm"));
+      assertEquals(boxConfig.getStringKey(VagrantConstants.KEY_WINRM_PORT), Optional.of("8899"));
+      assertEquals(boxConfig.getStringKey(VagrantConstants.KEY_SSH_USERNAME), Optional.of("jclouds-ssh"));
+      assertEquals(boxConfig.getStringKey(VagrantConstants.KEY_SSH_PASSWORD), Optional.of("password-ssh"));
+      assertEquals(boxConfig.getStringKey(VagrantConstants.KEY_SSH_PRIVATE_KEY_PATH), Optional.of("/path/to/private.key"));
+      assertEquals(boxConfig.getStringKey(VagrantConstants.KEY_SSH_PORT), Optional.of("2222"));
+
+      boxPath.delete();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/internal/MachineConfigTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/internal/MachineConfigTest.java b/vagrant/src/test/java/org/jclouds/vagrant/internal/MachineConfigTest.java
new file mode 100644
index 0000000..eb968a6
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/internal/MachineConfigTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+import org.jclouds.JcloudsVersion;
+import org.jclouds.vagrant.reference.VagrantConstants;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.Files;
+import com.google.common.io.Resources;
+
+public class MachineConfigTest {
+   private static final Map<String, Object> CONFIG = ImmutableMap.<String, Object>builder()
+         .put("jcloudsVersion", "0.0.1")
+         .put("box", "jclouds/vagrant")
+         .put("osFamily", "ubuntu")
+         .put("hardwareId", "micro")
+         .put("memory", "512")
+         .put("cpus", "1")
+         .build();
+
+   private File machineFolder;
+   private MachineConfig machineConfig;
+   private File configPath;
+
+   @BeforeMethod
+   public void setUp() throws IOException {
+      File vagrantHome = new File(System.getProperty("java.io.tmpdir"), "jclouds/vagrant");
+      machineFolder = new File(vagrantHome, "jclouds");
+      File configFolder = new File(machineFolder, VagrantConstants.MACHINES_CONFIG_SUBFOLDER);
+      configFolder.mkdirs();
+      configPath = new File(configFolder, "vagrant" + VagrantConstants.MACHINES_CONFIG_EXTENSION);
+      machineConfig = new MachineConfig.Factory().newInstance(machineFolder, "vagrant");
+   }
+
+   @AfterMethod
+   public void tearDown() {
+      configPath.delete();
+   }
+
+   @Test
+   public void testRead() throws IOException {
+      Resources.asByteSource(getClass().getResource("/machine-config.yaml")).copyTo(Files.asByteSink(configPath));
+      assertEquals(machineConfig.load(), CONFIG);
+   }
+
+   @Test
+   public void testWrite() throws IOException {
+      machineConfig.save(CONFIG);
+      ByteArrayOutputStream actualBytes = new ByteArrayOutputStream();
+      Files.asByteSource(configPath).copyTo(actualBytes);
+
+      ByteArrayOutputStream expectedBytes = new ByteArrayOutputStream();
+      Resources.asByteSource(getClass().getResource("/machine-config.yaml")).copyTo(expectedBytes);
+
+      String actual = new String(actualBytes.toByteArray(), Charsets.UTF_8);
+      String expected = new String(expectedBytes.toByteArray(), Charsets.UTF_8);
+      assertEquals(actual, expected
+            .replace("jcloudsVersion: 0.0.1", "jcloudsVersion: " + JcloudsVersion.get().toString())
+            // Strip license headers
+            .replaceAll("(?m)^#.*", "")
+            .trim());
+   }
+
+   @Test
+   public void testUpdatesVersion() throws IOException {
+      machineConfig.save(CONFIG);
+      Map<String, Object> newConfig = machineConfig.load();
+      assertEquals(newConfig.get(VagrantConstants.CONFIG_JCLOUDS_VERSION), JcloudsVersion.get().toString());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantNodeRegistryTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantNodeRegistryTest.java b/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantNodeRegistryTest.java
new file mode 100644
index 0000000..fb4950c
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantNodeRegistryTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.vagrant.domain.VagrantNode;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+
+public class VagrantNodeRegistryTest {
+   private static class TestTimeSupplier implements Supplier<Long> {
+      long time = System.currentTimeMillis();
+
+      @Override
+      public Long get() {
+         return time;
+      }
+
+      public void advanceTime(long add) {
+         time += add;
+      }
+
+   }
+
+   @Test
+   public void testNodeRegistry() {
+      TestTimeSupplier timeSupplier = new TestTimeSupplier();
+      VagrantNodeRegistry registry = new VagrantNodeRegistry(timeSupplier);
+      OperatingSystem os = new OperatingSystem(OsFamily.UNRECOGNIZED, "Jclouds OS", "10", "x64", "Jclouds Test Image", true);
+      Image image = new ImageBuilder()
+            .ids("jclouds/box")
+            .operatingSystem(os)
+            .status(Image.Status.AVAILABLE)
+            .build();
+
+      ImmutableList<String> networks = ImmutableList.of("172.28.128.3");
+      VagrantNode node = VagrantNode.builder()
+            .setPath(new File("/path/to/machine"))
+            .setId("vagrant/node")
+            .setGroup("vagrant")
+            .setName("node")
+            .setImage(image)
+            .setNetworks(networks)
+            .setHostname("vagrant-node")
+            .build();
+
+      assertNull(registry.get(node.id()));
+      registry.add(node);
+      assertEquals(registry.get(node.id()), node);
+      registry.onTerminated(node);
+      assertEquals(registry.get(node.id()), node);
+      timeSupplier.advanceTime(TimeUnit.MINUTES.toMillis(10));
+      assertNull(registry.get(node.id()));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantOutputRecorderTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantOutputRecorderTest.java b/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantOutputRecorderTest.java
new file mode 100644
index 0000000..c74bb54
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantOutputRecorderTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import vagrant.api.CommandIOListener;
+
+public class VagrantOutputRecorderTest {
+   protected static final String INPUT = "vagrant up";
+   protected static final String OUT1 = "1482768916,f99,metadata,provider,virtualbox\n";
+   protected static final String OUT2 = "1482768916,,ui,info,Bringing machine ";
+   protected static final String OUT3 = "'f99' up with 'virtualbox' provider...\n";
+   protected static final String OUT4 = "1482768916,f99,action,up,sta";
+
+   private static CommandIOListener nopIOListener = new CommandIOListener() {
+      @Override
+      public void onInput(String input) {
+      }
+
+      @Override
+      public void onOutput(String output) {
+      }
+   };
+
+   @Test
+   public void testOutputRecorder() {
+      VagrantOutputRecorder outputRecorder = new VagrantOutputRecorder(nopIOListener);
+      outputRecorder.record();
+      assertEquals(outputRecorder.stopRecording(), "");
+      outputRecorder.record();
+      outputRecorder.onInput("vagrant up");
+      assertEquals(outputRecorder.stopRecording(), "");
+      outputRecorder.record();
+      outputRecorder.onOutput(OUT1);
+      outputRecorder.onOutput(OUT2);
+      outputRecorder.onOutput(OUT3 + OUT4);
+      assertEquals(outputRecorder.stopRecording(), OUT1 + OUT2 + OUT3 + OUT4);
+      outputRecorder.onOutput(OUT1);
+      assertEquals(outputRecorder.stopRecording(), "");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantWireLoggerTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantWireLoggerTest.java b/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantWireLoggerTest.java
new file mode 100644
index 0000000..66b89a5
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/internal/VagrantWireLoggerTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.internal;
+
+import java.io.InputStream;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.jclouds.http.internal.HttpWire;
+import org.testng.annotations.Test;
+
+public class VagrantWireLoggerTest {
+   private static final String INPUT = VagrantOutputRecorderTest.INPUT;
+   private static final String OUT1 = VagrantOutputRecorderTest.OUT1;
+   private static final String OUT2 = VagrantOutputRecorderTest.OUT2;
+   private static final String OUT3 = VagrantOutputRecorderTest.OUT3;
+   private static final String OUT4 = VagrantOutputRecorderTest.OUT4;
+
+   @Test
+   public void testWireLogger() {
+      HttpWire httpWire = EasyMock.createMock(HttpWire.class);
+      Capture<InputStream> wireInCapture = new Capture<InputStream>();
+      EasyMock.expect(httpWire.input(EasyMock.capture(wireInCapture))).andReturn(null);
+      EasyMock.expect(httpWire.output(OUT1)).andReturn(OUT1);
+      EasyMock.expect(httpWire.output(OUT2 + OUT3)).andReturn(OUT2 + OUT3);
+      EasyMock.expect(httpWire.output(OUT4)).andReturn(OUT4);
+
+      EasyMock.replay(httpWire);
+
+      VagrantWireLogger wireLogger = new VagrantWireLogger(httpWire);
+      wireLogger.onInput(INPUT);
+      wireLogger.onInput(null);
+      wireLogger.onOutput(OUT1);
+      wireLogger.onOutput(OUT2);
+      wireLogger.onOutput(OUT3 + OUT4);
+      wireLogger.onOutput(null);
+      
+      EasyMock.verify(httpWire);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/java/org/jclouds/vagrant/strategy/VagrantDefaultImageCredentialsTest.java
----------------------------------------------------------------------
diff --git a/vagrant/src/test/java/org/jclouds/vagrant/strategy/VagrantDefaultImageCredentialsTest.java b/vagrant/src/test/java/org/jclouds/vagrant/strategy/VagrantDefaultImageCredentialsTest.java
new file mode 100644
index 0000000..ea29835
--- /dev/null
+++ b/vagrant/src/test/java/org/jclouds/vagrant/strategy/VagrantDefaultImageCredentialsTest.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.vagrant.strategy;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.easymock.EasyMock;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.domain.Credentials;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.vagrant.internal.BoxConfig;
+import org.jclouds.vagrant.reference.VagrantConstants;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+
+public class VagrantDefaultImageCredentialsTest {
+
+   @Test
+   public void testCredentials() {
+      LoginCredentials creds = LoginCredentials.builder()
+            .user("vagrant")
+            .password("vagrant")
+            .noPrivateKey()
+            .build();
+
+      @SuppressWarnings("unchecked")
+      Map<String, Credentials> credentialStore = EasyMock.createMock(Map.class);
+      BoxConfig.Factory boxConfigFactory = EasyMock.createMock(BoxConfig.Factory.class);
+
+      EasyMock.replay(credentialStore, boxConfigFactory);
+
+      VagrantDefaultImageCredentials defaultImageCredentials =
+            new VagrantDefaultImageCredentials(creds, credentialStore, boxConfigFactory);
+
+      OperatingSystem os = new OperatingSystem(OsFamily.LINUX, "Jclouds OS", "10", "x64", "Jclouds Test Image", true);
+      Image image = new ImageBuilder()
+            .ids("jclouds/box")
+            .operatingSystem(os)
+            .status(org.jclouds.compute.domain.Image.Status.AVAILABLE)
+            .build();
+
+      LoginCredentials actualCreds = defaultImageCredentials.apply(image);
+
+      EasyMock.verify(credentialStore, boxConfigFactory);
+
+      assertEquals(actualCreds, creds);
+   }
+
+   @Test
+   public void testCredentialStore() {
+      LoginCredentials creds = LoginCredentials.builder()
+            .user("vagrant")
+            .password("vagrant")
+            .noPrivateKey()
+            .build();
+
+      OperatingSystem os = new OperatingSystem(OsFamily.LINUX, "Jclouds OS", "10", "x64", "Jclouds Test Image", true);
+      Image image = new ImageBuilder()
+            .ids("jclouds/box")
+            .operatingSystem(os)
+            .status(org.jclouds.compute.domain.Image.Status.AVAILABLE)
+            .build();
+
+      @SuppressWarnings("unchecked")
+      Map<String, Credentials> credentialStore = EasyMock.createMock(Map.class);
+      EasyMock.expect(credentialStore.containsKey("image#" + image.getId())).andReturn(Boolean.TRUE);
+      EasyMock.expect(credentialStore.get("image#" + image.getId())).andReturn(creds);
+
+      BoxConfig.Factory boxConfigFactory = EasyMock.createMock(BoxConfig.Factory.class);
+
+      EasyMock.replay(credentialStore, boxConfigFactory);
+
+      VagrantDefaultImageCredentials defaultImageCredentials =
+            new VagrantDefaultImageCredentials(null, credentialStore, boxConfigFactory);
+
+      LoginCredentials actualCreds = defaultImageCredentials.apply(image);
+
+      EasyMock.verify(credentialStore, boxConfigFactory);
+
+      assertEquals(actualCreds, creds);
+   }
+
+   @Test
+   public void testWinrmCredentials() {
+      LoginCredentials creds = LoginCredentials.builder()
+            .user("jclouds-user")
+            .password("jclouds-pass")
+            .noPrivateKey()
+            .build();
+
+      OperatingSystem os = new OperatingSystem(OsFamily.WINDOWS, "Jclouds OS", "10", "x64", "Jclouds Test Image", true);
+      Image image = new ImageBuilder()
+            .ids("jclouds/box")
+            .operatingSystem(os)
+            .status(org.jclouds.compute.domain.Image.Status.AVAILABLE)
+            .build();
+
+      @SuppressWarnings("unchecked")
+      Map<String, Credentials> credentialStore = EasyMock.createMock(Map.class);
+      EasyMock.expect(credentialStore.containsKey("image#" + image.getId())).andReturn(Boolean.FALSE);
+
+      BoxConfig boxConfig = EasyMock.createMock(BoxConfig.class);
+      EasyMock.expect(boxConfig.getStringKey(VagrantConstants.KEY_WINRM_USERNAME)).andReturn(Optional.of(creds.getUser()));
+      EasyMock.expect(boxConfig.getStringKey(VagrantConstants.KEY_WINRM_PASSWORD)).andReturn(Optional.of(creds.getOptionalPassword().get()));
+
+      BoxConfig.Factory boxConfigFactory = EasyMock.createMock(BoxConfig.Factory.class);
+      EasyMock.expect(boxConfigFactory.newInstance(image)).andReturn(boxConfig);
+
+      EasyMock.replay(credentialStore, boxConfig, boxConfigFactory);
+
+      VagrantDefaultImageCredentials defaultImageCredentials =
+            new VagrantDefaultImageCredentials(null, credentialStore, boxConfigFactory);
+
+      LoginCredentials actualCreds = defaultImageCredentials.apply(image);
+
+      EasyMock.verify(credentialStore, boxConfigFactory);
+
+      assertEquals(actualCreds, creds);
+   }
+
+   @Test
+   public void testSshCredentials() {
+      LoginCredentials creds = LoginCredentials.builder()
+            .user("jclouds-user")
+            .password("jclouds-pass")
+            .noPrivateKey()
+            .build();
+
+      OperatingSystem os = new OperatingSystem(OsFamily.LINUX, "Jclouds OS", "10", "x64", "Jclouds Test Image", true);
+      Image image = new ImageBuilder()
+            .ids("jclouds/box")
+            .operatingSystem(os)
+            .status(org.jclouds.compute.domain.Image.Status.AVAILABLE)
+            .build();
+
+      @SuppressWarnings("unchecked")
+      Map<String, Credentials> credentialStore = EasyMock.createMock(Map.class);
+      EasyMock.expect(credentialStore.containsKey("image#" + image.getId())).andReturn(Boolean.FALSE);
+
+      BoxConfig boxConfig = EasyMock.createMock(BoxConfig.class);
+      EasyMock.expect(boxConfig.getStringKey(VagrantConstants.KEY_SSH_USERNAME)).andReturn(Optional.of(creds.getUser()));
+      EasyMock.expect(boxConfig.getStringKey(VagrantConstants.KEY_SSH_PASSWORD)).andReturn(Optional.of(creds.getOptionalPassword().get()));
+      EasyMock.expect(boxConfig.getStringKey(VagrantConstants.KEY_SSH_PRIVATE_KEY_PATH)).andReturn(Optional.<String>absent());
+
+      BoxConfig.Factory boxConfigFactory = EasyMock.createMock(BoxConfig.Factory.class);
+      EasyMock.expect(boxConfigFactory.newInstance(image)).andReturn(boxConfig);
+
+      EasyMock.replay(credentialStore, boxConfig, boxConfigFactory);
+
+      VagrantDefaultImageCredentials defaultImageCredentials =
+            new VagrantDefaultImageCredentials(null, credentialStore, boxConfigFactory);
+
+      LoginCredentials actualCreds = defaultImageCredentials.apply(image);
+
+      EasyMock.verify(credentialStore, boxConfigFactory);
+
+      assertEquals(actualCreds, creds);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/resources/Vagrantfile.boxconfig
----------------------------------------------------------------------
diff --git a/vagrant/src/test/resources/Vagrantfile.boxconfig b/vagrant/src/test/resources/Vagrantfile.boxconfig
new file mode 100644
index 0000000..9f09642
--- /dev/null
+++ b/vagrant/src/test/resources/Vagrantfile.boxconfig
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+Vagrant.configure(2) do |config|
+  config.vm.guest = :windows
+  config.winrm.username = "jclouds-winrm"
+  config.winrm.password = "password-winrm"
+  config.winrm.port = "8899"
+  config.ssh.username = "jclouds-ssh"
+  config.ssh.password = "password-ssh"
+  config.ssh.private_key_path = "/path/to/private.key"
+  config.ssh.port = "2222"
+end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/resources/logback-test.xml
----------------------------------------------------------------------
diff --git a/vagrant/src/test/resources/logback-test.xml b/vagrant/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..72e46d0
--- /dev/null
+++ b/vagrant/src/test/resources/logback-test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<configuration scan="false">
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
+        </encoder>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="console"/>
+    </root>
+
+    <logger name="org.jclouds" level="INFO" />
+    <logger name="org.jclouds.vagrant" level="DEBUG" />
+    <logger name="jclouds.wire" level="DEBUG" />
+    <logger name="jclouds.headers" level="DEBUG" />
+    <logger name="ch.qos.logback" level="WARN" />
+
+</configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/fadcd5d9/vagrant/src/test/resources/machine-config.yaml
----------------------------------------------------------------------
diff --git a/vagrant/src/test/resources/machine-config.yaml b/vagrant/src/test/resources/machine-config.yaml
new file mode 100644
index 0000000..f95642f
--- /dev/null
+++ b/vagrant/src/test/resources/machine-config.yaml
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+jcloudsVersion: 0.0.1
+box: jclouds/vagrant
+osFamily: ubuntu
+hardwareId: micro
+memory: 512
+cpus: 1
\ No newline at end of file