github.com/rothwerx/packer@v0.9.0/builder/docker/communicator_test.go (about)

     1  package docker
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"io/ioutil"
     6  	"os"
     7  	"os/exec"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/mitchellh/packer/packer"
    12  	"github.com/mitchellh/packer/provisioner/file"
    13  	"github.com/mitchellh/packer/provisioner/shell"
    14  	"github.com/mitchellh/packer/template"
    15  )
    16  
    17  func TestCommunicator_impl(t *testing.T) {
    18  	var _ packer.Communicator = new(Communicator)
    19  }
    20  
    21  // TestUploadDownload verifies that basic upload / download functionality works
    22  func TestUploadDownload(t *testing.T) {
    23  	ui := packer.TestUi(t)
    24  	cache := &packer.FileCache{CacheDir: os.TempDir()}
    25  
    26  	tpl, err := template.Parse(strings.NewReader(dockerBuilderConfig))
    27  	if err != nil {
    28  		t.Fatalf("Unable to parse config: %s", err)
    29  	}
    30  
    31  	if os.Getenv("PACKER_ACC") == "" {
    32  		t.Skip("This test is only run with PACKER_ACC=1")
    33  	}
    34  	cmd := exec.Command("docker", "-v")
    35  	cmd.Run()
    36  	if !cmd.ProcessState.Success() {
    37  		t.Error("docker command not found; please make sure docker is installed")
    38  	}
    39  
    40  	// Setup the builder
    41  	builder := &Builder{}
    42  	warnings, err := builder.Prepare(tpl.Builders["docker"].Config)
    43  	if err != nil {
    44  		t.Fatalf("Error preparing configuration %s", err)
    45  	}
    46  	if len(warnings) > 0 {
    47  		t.Fatal("Encountered configuration warnings; aborting")
    48  	}
    49  
    50  	// Setup the provisioners
    51  	upload := &file.Provisioner{}
    52  	err = upload.Prepare(tpl.Provisioners[0].Config)
    53  	if err != nil {
    54  		t.Fatalf("Error preparing upload: %s", err)
    55  	}
    56  	download := &file.Provisioner{}
    57  	err = download.Prepare(tpl.Provisioners[1].Config)
    58  	if err != nil {
    59  		t.Fatalf("Error preparing download: %s", err)
    60  	}
    61  	// Preemptive cleanup. Honestly I don't know why you would want to get rid
    62  	// of my strawberry cake. It's so tasty! Do you not like cake? Are you a
    63  	// cake-hater? Or are you keeping all the cake all for yourself? So selfish!
    64  	defer os.Remove("my-strawberry-cake")
    65  
    66  	// Add hooks so the provisioners run during the build
    67  	hooks := map[string][]packer.Hook{}
    68  	hooks[packer.HookProvision] = []packer.Hook{
    69  		&packer.ProvisionHook{
    70  			Provisioners: []packer.Provisioner{
    71  				upload,
    72  				download,
    73  			},
    74  		},
    75  	}
    76  	hook := &packer.DispatchHook{Mapping: hooks}
    77  
    78  	// Run things
    79  	artifact, err := builder.Run(ui, hook, cache)
    80  	if err != nil {
    81  		t.Fatalf("Error running build %s", err)
    82  	}
    83  	// Preemptive cleanup
    84  	defer artifact.Destroy()
    85  
    86  	// Verify that the thing we downloaded is the same thing we sent up.
    87  	// Complain loudly if it isn't.
    88  	inputFile, err := ioutil.ReadFile("test-fixtures/onecakes/strawberry")
    89  	if err != nil {
    90  		t.Fatalf("Unable to read input file: %s", err)
    91  	}
    92  	outputFile, err := ioutil.ReadFile("my-strawberry-cake")
    93  	if err != nil {
    94  		t.Fatalf("Unable to read output file: %s", err)
    95  	}
    96  	if sha256.Sum256(inputFile) != sha256.Sum256(outputFile) {
    97  		t.Fatalf("Input and output files do not match\n"+
    98  			"Input:\n%s\nOutput:\n%s\n", inputFile, outputFile)
    99  	}
   100  }
   101  
   102  // TestLargeDownload verifies that files are the apporpriate size after being
   103  // downloaded. This is to identify and fix the race condition in #2793. You may
   104  // need to use github.com/cbednarski/rerun to verify since this problem occurs
   105  // only intermittently.
   106  func TestLargeDownload(t *testing.T) {
   107  	ui := packer.TestUi(t)
   108  	cache := &packer.FileCache{CacheDir: os.TempDir()}
   109  
   110  	tpl, err := template.Parse(strings.NewReader(dockerLargeBuilderConfig))
   111  	if err != nil {
   112  		t.Fatalf("Unable to parse config: %s", err)
   113  	}
   114  
   115  	if os.Getenv("PACKER_ACC") == "" {
   116  		t.Skip("This test is only run with PACKER_ACC=1")
   117  	}
   118  	cmd := exec.Command("docker", "-v")
   119  	cmd.Run()
   120  	if !cmd.ProcessState.Success() {
   121  		t.Error("docker command not found; please make sure docker is installed")
   122  	}
   123  
   124  	// Setup the builder
   125  	builder := &Builder{}
   126  	warnings, err := builder.Prepare(tpl.Builders["docker"].Config)
   127  	if err != nil {
   128  		t.Fatalf("Error preparing configuration %s", err)
   129  	}
   130  	if len(warnings) > 0 {
   131  		t.Fatal("Encountered configuration warnings; aborting")
   132  	}
   133  
   134  	// Setup the provisioners
   135  	shell := &shell.Provisioner{}
   136  	err = shell.Prepare(tpl.Provisioners[0].Config)
   137  	if err != nil {
   138  		t.Fatalf("Error preparing shell provisioner: %s", err)
   139  	}
   140  	downloadCupcake := &file.Provisioner{}
   141  	err = downloadCupcake.Prepare(tpl.Provisioners[1].Config)
   142  	if err != nil {
   143  		t.Fatalf("Error preparing downloadCupcake: %s", err)
   144  	}
   145  	downloadBigcake := &file.Provisioner{}
   146  	err = downloadBigcake.Prepare(tpl.Provisioners[2].Config)
   147  	if err != nil {
   148  		t.Fatalf("Error preparing downloadBigcake: %s", err)
   149  	}
   150  
   151  	// Preemptive cleanup.
   152  	defer os.Remove("cupcake")
   153  	defer os.Remove("bigcake")
   154  
   155  	// Add hooks so the provisioners run during the build
   156  	hooks := map[string][]packer.Hook{}
   157  	hooks[packer.HookProvision] = []packer.Hook{
   158  		&packer.ProvisionHook{
   159  			Provisioners: []packer.Provisioner{
   160  				shell,
   161  				downloadCupcake,
   162  				downloadBigcake,
   163  			},
   164  		},
   165  	}
   166  	hook := &packer.DispatchHook{Mapping: hooks}
   167  
   168  	// Run things
   169  	artifact, err := builder.Run(ui, hook, cache)
   170  	if err != nil {
   171  		t.Fatalf("Error running build %s", err)
   172  	}
   173  	// Preemptive cleanup
   174  	defer artifact.Destroy()
   175  
   176  	// Verify that the things we downloaded are the right size. Complain loudly
   177  	// if they are not.
   178  	//
   179  	// cupcake should be 2097152 bytes
   180  	// bigcake should be 104857600 bytes
   181  	cupcake, err := os.Stat("cupcake")
   182  	if err != nil {
   183  		t.Fatalf("Unable to stat cupcake file: %s", err)
   184  	}
   185  	cupcakeExpected := int64(2097152)
   186  	if cupcake.Size() != cupcakeExpected {
   187  		t.Errorf("Expected cupcake to be %d bytes; found %d", cupcakeExpected, cupcake.Size())
   188  	}
   189  
   190  	bigcake, err := os.Stat("bigcake")
   191  	if err != nil {
   192  		t.Fatalf("Unable to stat bigcake file: %s", err)
   193  	}
   194  	bigcakeExpected := int64(104857600)
   195  	if bigcake.Size() != bigcakeExpected {
   196  		t.Errorf("Expected bigcake to be %d bytes; found %d", bigcakeExpected, bigcake.Size())
   197  	}
   198  
   199  	// TODO if we can, calculate a sha inside the container and compare to the
   200  	// one we get after we pull it down. We will probably have to parse the log
   201  	// or ui output to do this because we use /dev/urandom to create the file.
   202  
   203  	// if sha256.Sum256(inputFile) != sha256.Sum256(outputFile) {
   204  	// 	t.Fatalf("Input and output files do not match\n"+
   205  	// 		"Input:\n%s\nOutput:\n%s\n", inputFile, outputFile)
   206  	// }
   207  
   208  }
   209  
   210  const dockerBuilderConfig = `
   211  {
   212    "builders": [
   213      {
   214        "type": "docker",
   215        "image": "ubuntu",
   216        "discard": true,
   217        "run_command": ["-d", "-i", "-t", "{{.Image}}", "/bin/sh"]
   218      }
   219    ],
   220    "provisioners": [
   221      {
   222        "type": "file",
   223        "source": "test-fixtures/onecakes/strawberry",
   224        "destination": "/strawberry-cake"
   225      },
   226      {
   227        "type": "file",
   228        "source": "/strawberry-cake",
   229        "destination": "my-strawberry-cake",
   230        "direction": "download"
   231      }
   232    ]
   233  }
   234  `
   235  
   236  const dockerLargeBuilderConfig = `
   237  {
   238    "builders": [
   239      {
   240        "type": "docker",
   241        "image": "ubuntu",
   242        "discard": true
   243      }
   244    ],
   245    "provisioners": [
   246      {
   247        "type": "shell",
   248        "inline": [
   249          "dd if=/dev/urandom of=/tmp/cupcake bs=1M count=2",
   250          "dd if=/dev/urandom of=/tmp/bigcake bs=1M count=100",
   251          "sync",
   252          "md5sum /tmp/cupcake /tmp/bigcake"
   253        ]
   254      },
   255      {
   256        "type": "file",
   257        "source": "/tmp/cupcake",
   258        "destination": "cupcake",
   259        "direction": "download"
   260      },
   261      {
   262        "type": "file",
   263        "source": "/tmp/bigcake",
   264        "destination": "bigcake",
   265        "direction": "download"
   266      }
   267    ]
   268  }
   269  `