diff --git a/packer/communicator.go b/packer/communicator.go
index 27360b63a13ac043ddd8738117b0dea767fad3b6..00df95811cfc4ece8b4481c66bee57e55ce04740 100644
--- a/packer/communicator.go
+++ b/packer/communicator.go
@@ -59,6 +59,11 @@ type Communicator interface {
 	// it completes.
 	Upload(string, io.Reader) error
 
+	// UploadDir uploads the contents of a directory recursively to
+	// the remote path. It also takes an optional slice of paths to
+	// ignore when uploading.
+	UploadDir(string, string, []string) error
+
 	// Download downloads a file from the machine from the given remote path
 	// with the contents writing to the given writer. This method will
 	// block until it completes.
diff --git a/packer/communicator_mock.go b/packer/communicator_mock.go
new file mode 100644
index 0000000000000000000000000000000000000000..e8c6e111e274cb84df9cc40a4a3f8844e4c6f6a9
--- /dev/null
+++ b/packer/communicator_mock.go
@@ -0,0 +1,41 @@
+package packer
+
+import (
+	"io"
+)
+
+// MockCommunicator is a valid Communicator implementation that can be
+// used for tests.
+type MockCommunicator struct {
+	Stderr io.Reader
+	Stdout io.Reader
+}
+
+func (c *MockCommunicator) Start(rc *RemoteCmd) error {
+	go func() {
+		rc.Lock()
+		defer rc.Unlock()
+
+		if rc.Stdout != nil && c.Stdout != nil {
+			io.Copy(rc.Stdout, c.Stdout)
+		}
+
+		if rc.Stderr != nil && c.Stderr != nil {
+			io.Copy(rc.Stderr, c.Stderr)
+		}
+	}()
+
+	return nil
+}
+
+func (c *MockCommunicator) Upload(string, io.Reader) error {
+	return nil
+}
+
+func (c *MockCommunicator) UploadDir(string, string, []string) error {
+	return nil
+}
+
+func (c *MockCommunicator) Download(string, io.Writer) error {
+	return nil
+}
diff --git a/packer/communicator_mock_test.go b/packer/communicator_mock_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..7aa92b070c6d0aafc10002bebd67580654b25eb6
--- /dev/null
+++ b/packer/communicator_mock_test.go
@@ -0,0 +1,13 @@
+package packer
+
+import (
+	"testing"
+)
+
+func TestMockCommunicator_impl(t *testing.T) {
+	var raw interface{}
+	raw = new(MockCommunicator)
+	if _, ok := raw.(Communicator); !ok {
+		t.Fatal("should be a communicator")
+	}
+}
diff --git a/packer/communicator_test.go b/packer/communicator_test.go
index 05c387ec182267fb29908e1278080701f8067cb4..432f60e8e22e9e596a068afd0e144422403d406c 100644
--- a/packer/communicator_test.go
+++ b/packer/communicator_test.go
@@ -2,42 +2,11 @@ package packer
 
 import (
 	"bytes"
-	"io"
 	"strings"
 	"testing"
 	"time"
 )
 
-type TestCommunicator struct {
-	Stderr io.Reader
-	Stdout io.Reader
-}
-
-func (c *TestCommunicator) Start(rc *RemoteCmd) error {
-	go func() {
-		rc.Lock()
-		defer rc.Unlock()
-
-		if rc.Stdout != nil && c.Stdout != nil {
-			io.Copy(rc.Stdout, c.Stdout)
-		}
-
-		if rc.Stderr != nil && c.Stderr != nil {
-			io.Copy(rc.Stderr, c.Stderr)
-		}
-	}()
-
-	return nil
-}
-
-func (c *TestCommunicator) Upload(string, io.Reader) error {
-	return nil
-}
-
-func (c *TestCommunicator) Download(string, io.Writer) error {
-	return nil
-}
-
 func TestRemoteCmd_StartWithUi(t *testing.T) {
 	data := "hello\nworld\nthere"
 
@@ -46,7 +15,7 @@ func TestRemoteCmd_StartWithUi(t *testing.T) {
 	uiOutput := new(bytes.Buffer)
 	rcOutput.WriteString(data)
 
-	testComm := &TestCommunicator{
+	testComm := &MockCommunicator{
 		Stdout: rcOutput,
 	}