github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/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/hashicorp/packer/packer"
    12  	"github.com/hashicorp/packer/provisioner/file"
    13  	"github.com/hashicorp/packer/provisioner/shell"
    14  	"github.com/hashicorp/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  			ProvisionerTypes: []string{"", ""},
    75  		},
    76  	}
    77  	hook := &packer.DispatchHook{Mapping: hooks}
    78  
    79  	// Run things
    80  	artifact, err := builder.Run(ui, hook, cache)
    81  	if err != nil {
    82  		t.Fatalf("Error running build %s", err)
    83  	}
    84  	// Preemptive cleanup
    85  	defer artifact.Destroy()
    86  
    87  	// Verify that the thing we downloaded is the same thing we sent up.
    88  	// Complain loudly if it isn't.
    89  	inputFile, err := ioutil.ReadFile("test-fixtures/onecakes/strawberry")
    90  	if err != nil {
    91  		t.Fatalf("Unable to read input file: %s", err)
    92  	}
    93  	outputFile, err := ioutil.ReadFile("my-strawberry-cake")
    94  	if err != nil {
    95  		t.Fatalf("Unable to read output file: %s", err)
    96  	}
    97  	if sha256.Sum256(inputFile) != sha256.Sum256(outputFile) {
    98  		t.Fatalf("Input and output files do not match\n"+
    99  			"Input:\n%s\nOutput:\n%s\n", inputFile, outputFile)
   100  	}
   101  }
   102  
   103  // TestLargeDownload verifies that files are the appropriate size after being
   104  // downloaded. This is to identify and fix the race condition in #2793. You may
   105  // need to use github.com/cbednarski/rerun to verify since this problem occurs
   106  // only intermittently.
   107  func TestLargeDownload(t *testing.T) {
   108  	ui := packer.TestUi(t)
   109  	cache := &packer.FileCache{CacheDir: os.TempDir()}
   110  
   111  	tpl, err := template.Parse(strings.NewReader(dockerLargeBuilderConfig))
   112  	if err != nil {
   113  		t.Fatalf("Unable to parse config: %s", err)
   114  	}
   115  
   116  	if os.Getenv("PACKER_ACC") == "" {
   117  		t.Skip("This test is only run with PACKER_ACC=1")
   118  	}
   119  	cmd := exec.Command("docker", "-v")
   120  	cmd.Run()
   121  	if !cmd.ProcessState.Success() {
   122  		t.Error("docker command not found; please make sure docker is installed")
   123  	}
   124  
   125  	// Setup the builder
   126  	builder := &Builder{}
   127  	warnings, err := builder.Prepare(tpl.Builders["docker"].Config)
   128  	if err != nil {
   129  		t.Fatalf("Error preparing configuration %s", err)
   130  	}
   131  	if len(warnings) > 0 {
   132  		t.Fatal("Encountered configuration warnings; aborting")
   133  	}
   134  
   135  	// Setup the provisioners
   136  	shell := &shell.Provisioner{}
   137  	err = shell.Prepare(tpl.Provisioners[0].Config)
   138  	if err != nil {
   139  		t.Fatalf("Error preparing shell provisioner: %s", err)
   140  	}
   141  	downloadCupcake := &file.Provisioner{}
   142  	err = downloadCupcake.Prepare(tpl.Provisioners[1].Config)
   143  	if err != nil {
   144  		t.Fatalf("Error preparing downloadCupcake: %s", err)
   145  	}
   146  	downloadBigcake := &file.Provisioner{}
   147  	err = downloadBigcake.Prepare(tpl.Provisioners[2].Config)
   148  	if err != nil {
   149  		t.Fatalf("Error preparing downloadBigcake: %s", err)
   150  	}
   151  
   152  	// Preemptive cleanup.
   153  	defer os.Remove("cupcake")
   154  	defer os.Remove("bigcake")
   155  
   156  	// Add hooks so the provisioners run during the build
   157  	hooks := map[string][]packer.Hook{}
   158  	hooks[packer.HookProvision] = []packer.Hook{
   159  		&packer.ProvisionHook{
   160  			Provisioners: []packer.Provisioner{
   161  				shell,
   162  				downloadCupcake,
   163  				downloadBigcake,
   164  			},
   165  			ProvisionerTypes: []string{"", "", ""},
   166  		},
   167  	}
   168  	hook := &packer.DispatchHook{Mapping: hooks}
   169  
   170  	// Run things
   171  	artifact, err := builder.Run(ui, hook, cache)
   172  	if err != nil {
   173  		t.Fatalf("Error running build %s", err)
   174  	}
   175  	// Preemptive cleanup
   176  	defer artifact.Destroy()
   177  
   178  	// Verify that the things we downloaded are the right size. Complain loudly
   179  	// if they are not.
   180  	//
   181  	// cupcake should be 2097152 bytes
   182  	// bigcake should be 104857600 bytes
   183  	cupcake, err := os.Stat("cupcake")
   184  	if err != nil {
   185  		t.Fatalf("Unable to stat cupcake file: %s", err)
   186  	}
   187  	cupcakeExpected := int64(2097152)
   188  	if cupcake.Size() != cupcakeExpected {
   189  		t.Errorf("Expected cupcake to be %d bytes; found %d", cupcakeExpected, cupcake.Size())
   190  	}
   191  
   192  	bigcake, err := os.Stat("bigcake")
   193  	if err != nil {
   194  		t.Fatalf("Unable to stat bigcake file: %s", err)
   195  	}
   196  	bigcakeExpected := int64(104857600)
   197  	if bigcake.Size() != bigcakeExpected {
   198  		t.Errorf("Expected bigcake to be %d bytes; found %d", bigcakeExpected, bigcake.Size())
   199  	}
   200  
   201  	// TODO if we can, calculate a sha inside the container and compare to the
   202  	// one we get after we pull it down. We will probably have to parse the log
   203  	// or ui output to do this because we use /dev/urandom to create the file.
   204  
   205  	// if sha256.Sum256(inputFile) != sha256.Sum256(outputFile) {
   206  	// 	t.Fatalf("Input and output files do not match\n"+
   207  	// 		"Input:\n%s\nOutput:\n%s\n", inputFile, outputFile)
   208  	// }
   209  
   210  }
   211  
   212  const dockerBuilderConfig = `
   213  {
   214    "builders": [
   215      {
   216        "type": "docker",
   217        "image": "ubuntu",
   218        "discard": true,
   219        "run_command": ["-d", "-i", "-t", "{{.Image}}", "/bin/sh"]
   220      }
   221    ],
   222    "provisioners": [
   223      {
   224        "type": "file",
   225        "source": "test-fixtures/onecakes/strawberry",
   226        "destination": "/strawberry-cake"
   227      },
   228      {
   229        "type": "file",
   230        "source": "/strawberry-cake",
   231        "destination": "my-strawberry-cake",
   232        "direction": "download"
   233      }
   234    ]
   235  }
   236  `
   237  
   238  const dockerLargeBuilderConfig = `
   239  {
   240    "builders": [
   241      {
   242        "type": "docker",
   243        "image": "ubuntu",
   244        "discard": true
   245      }
   246    ],
   247    "provisioners": [
   248      {
   249        "type": "shell",
   250        "inline": [
   251          "dd if=/dev/urandom of=/tmp/cupcake bs=1M count=2",
   252          "dd if=/dev/urandom of=/tmp/bigcake bs=1M count=100",
   253          "sync",
   254          "md5sum /tmp/cupcake /tmp/bigcake"
   255        ]
   256      },
   257      {
   258        "type": "file",
   259        "source": "/tmp/cupcake",
   260        "destination": "cupcake",
   261        "direction": "download"
   262      },
   263      {
   264        "type": "file",
   265        "source": "/tmp/bigcake",
   266        "destination": "bigcake",
   267        "direction": "download"
   268      }
   269    ]
   270  }
   271  `