github.com/simonferquel/app@v0.6.1-0.20181012141724-68b7cccf26ac/e2e/commands_test.go (about)

     1  package e2e
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/docker/app/internal"
    12  	"github.com/docker/app/internal/yaml"
    13  	"gotest.tools/assert"
    14  	is "gotest.tools/assert/cmp"
    15  	"gotest.tools/fs"
    16  	"gotest.tools/golden"
    17  	"gotest.tools/icmd"
    18  	"gotest.tools/skip"
    19  )
    20  
    21  const (
    22  	singleFileApp = `version: 0.1.0
    23  name: helloworld
    24  description: "hello world app"
    25  namespace: "foo"
    26  ---
    27  version: '3.5'
    28  services:
    29    hello-world:
    30      image: hello-world
    31  ---
    32  # This section contains the default values for your application settings.`
    33  )
    34  
    35  func TestRenderTemplates(t *testing.T) {
    36  	skip.If(t, !hasExperimental, "experimental mode needed for this test")
    37  	appsPath := filepath.Join("testdata", "templates")
    38  	apps, err := ioutil.ReadDir(appsPath)
    39  	assert.NilError(t, err, "unable to get apps")
    40  	for _, app := range apps {
    41  		appPath := filepath.Join(appsPath, app.Name())
    42  		if !checkRenderers(app.Name(), renderers) {
    43  			t.Log("Required renderer not enabled")
    44  			continue
    45  		}
    46  		t.Run(app.Name(), testRenderApp(appPath, "DOCKERAPP_RENDERERS="+app.Name()))
    47  	}
    48  }
    49  
    50  func TestRender(t *testing.T) {
    51  	appsPath := filepath.Join("testdata", "render")
    52  	apps, err := ioutil.ReadDir(appsPath)
    53  	assert.NilError(t, err, "unable to get apps")
    54  	for _, app := range apps {
    55  		appPath := filepath.Join(appsPath, app.Name())
    56  		t.Run(app.Name(), testRenderApp(appPath))
    57  	}
    58  }
    59  
    60  func testRenderApp(appPath string, env ...string) func(*testing.T) {
    61  	return func(t *testing.T) {
    62  		envSettings := map[string]string{}
    63  		data, err := ioutil.ReadFile(filepath.Join(appPath, "env.yml"))
    64  		assert.NilError(t, err)
    65  		assert.NilError(t, yaml.Unmarshal(data, &envSettings))
    66  		args := []string{dockerApp, "render", filepath.Join(appPath, "my.dockerapp"),
    67  			"-f", filepath.Join(appPath, "settings-0.yml"),
    68  		}
    69  		for k, v := range envSettings {
    70  			args = append(args, "-s", fmt.Sprintf("%s=%s", k, v))
    71  		}
    72  		result := icmd.RunCmd(icmd.Cmd{
    73  			Command: args,
    74  			Env:     env,
    75  		}).Assert(t, icmd.Success)
    76  		assert.Assert(t, is.Equal(readFile(t, filepath.Join(appPath, "expected.txt")), result.Stdout()), "rendering mismatch")
    77  	}
    78  }
    79  
    80  func TestRenderFormatters(t *testing.T) {
    81  	appPath := filepath.Join("testdata", "fork", "simple.dockerapp")
    82  	result := icmd.RunCommand(dockerApp, "render", "--formatter", "json", appPath).Assert(t, icmd.Success)
    83  	assert.Assert(t, golden.String(result.Stdout(), "expected-json-render.golden"))
    84  
    85  	result = icmd.RunCommand(dockerApp, "render", "--formatter", "yaml", appPath).Assert(t, icmd.Success)
    86  	assert.Assert(t, golden.String(result.Stdout(), "expected-yaml-render.golden"))
    87  }
    88  
    89  func TestInit(t *testing.T) {
    90  	composeData := `version: "3.2"
    91  services:
    92    nginx:
    93      image: nginx:${NGINX_VERSION}
    94      command: nginx $NGINX_ARGS
    95  `
    96  	meta := `# Version of the application
    97  version: 0.1.0
    98  # Name of the application
    99  name: app-test
   100  # A short description of the application
   101  description: my cool app
   102  # Namespace to use when pushing to a registry. This is typically your Hub username.
   103  #namespace: myHubUsername
   104  # List of application maintainers with name and email for each
   105  maintainers:
   106    - name: bob
   107      email: 
   108    - name: joe
   109      email: joe@joe.com
   110  `
   111  	envData := "# some comment\nNGINX_VERSION=latest"
   112  	dir := fs.NewDir(t, "app_input",
   113  		fs.WithFile(internal.ComposeFileName, composeData),
   114  		fs.WithFile(".env", envData),
   115  	)
   116  	defer dir.Remove()
   117  
   118  	testAppName := "app-test"
   119  	dirName := internal.DirNameFromAppName(testAppName)
   120  	defer os.RemoveAll(dirName)
   121  
   122  	icmd.RunCommand(dockerApp, "init", testAppName,
   123  		"-c", dir.Join(internal.ComposeFileName),
   124  		"-d", "my cool app",
   125  		"-m", "bob",
   126  		"-m", "joe:joe@joe.com",
   127  	).Assert(t, icmd.Success)
   128  	manifest := fs.Expected(
   129  		t,
   130  		fs.WithMode(0755),
   131  		fs.WithFile(internal.MetadataFileName, meta, fs.WithMode(0644)), // too many variables, cheating
   132  		fs.WithFile(internal.ComposeFileName, composeData, fs.WithMode(0644)),
   133  		fs.WithFile(internal.SettingsFileName, "NGINX_ARGS: FILL ME\nNGINX_VERSION: latest\n", fs.WithMode(0644)),
   134  	)
   135  	assert.Assert(t, fs.Equal(dirName, manifest))
   136  
   137  	// validate metadata with JSON Schema
   138  	icmd.RunCommand(dockerApp, "validate", testAppName).Assert(t, icmd.Success)
   139  
   140  	// test single-file init
   141  	icmd.RunCommand(dockerApp, "init", "tac",
   142  		"-c", dir.Join(internal.ComposeFileName),
   143  		"-d", "my cool app",
   144  		"-m", "bob",
   145  		"-m", "joe:joe@joe.com",
   146  		"-s",
   147  	).Assert(t, icmd.Success)
   148  	defer os.Remove("tac.dockerapp")
   149  	appData, err := ioutil.ReadFile("tac.dockerapp")
   150  	assert.NilError(t, err)
   151  	assert.Assert(t, golden.Bytes(appData, "init-singlefile.dockerapp"))
   152  	// Check various commands work on single-file app package
   153  	icmd.RunCommand(dockerApp, "inspect", "tac").Assert(t, icmd.Success)
   154  	icmd.RunCommand(dockerApp, "render", "tac").Assert(t, icmd.Success)
   155  }
   156  
   157  func TestDetectApp(t *testing.T) {
   158  	// cwd = e2e
   159  	dir := fs.NewDir(t, "detect-app-binary",
   160  		fs.WithDir("helm.dockerapp", fs.FromDir("testdata/helm.dockerapp")),
   161  		fs.WithDir("render",
   162  			fs.WithDir("app1.dockerapp", fs.FromDir("testdata/render/envvariables/my.dockerapp")),
   163  			fs.WithDir("app2.dockerapp", fs.FromDir("testdata/render/envvariables/my.dockerapp")),
   164  		),
   165  	)
   166  	defer dir.Remove()
   167  	icmd.RunCmd(icmd.Cmd{
   168  		Command: []string{dockerApp, "inspect"},
   169  		Dir:     dir.Path(),
   170  	}).Assert(t, icmd.Success)
   171  	icmd.RunCmd(icmd.Cmd{
   172  		Command: []string{dockerApp, "inspect"},
   173  		Dir:     dir.Join("helm.dockerapp"),
   174  	}).Assert(t, icmd.Success)
   175  	icmd.RunCmd(icmd.Cmd{
   176  		Command: []string{dockerApp, "inspect", "."},
   177  		Dir:     dir.Join("helm.dockerapp"),
   178  	}).Assert(t, icmd.Success)
   179  	result := icmd.RunCmd(icmd.Cmd{
   180  		Command: []string{dockerApp, "inspect"},
   181  		Dir:     dir.Join("render"),
   182  	})
   183  	result.Assert(t, icmd.Expected{
   184  		ExitCode: 1,
   185  		Err:      "Error: multiple applications found in current directory, specify the application name on the command line",
   186  	})
   187  }
   188  
   189  func TestPack(t *testing.T) {
   190  	skip.If(t, !hasExperimental, "experimental mode needed for this test")
   191  	tempDir, err := ioutil.TempDir("", "dockerapp")
   192  	assert.NilError(t, err)
   193  	defer os.RemoveAll(tempDir)
   194  	icmd.RunCommand(dockerApp, "pack", "testdata/helm", "-o", filepath.Join(tempDir, "test.dockerapp")).Assert(t, icmd.Success)
   195  	// check that our commands run on the packed version
   196  	icmd.RunCommand(dockerApp, "inspect", filepath.Join(tempDir, "test")).Assert(t, icmd.Expected{
   197  		Out: "myapp",
   198  	})
   199  	icmd.RunCommand(dockerApp, "render", filepath.Join(tempDir, "test")).Assert(t, icmd.Expected{
   200  		Out: "nginx",
   201  	})
   202  	icmd.RunCmd(icmd.Cmd{
   203  		Command: []string{dockerApp, "helm", "test"},
   204  		Dir:     tempDir,
   205  	}).Assert(t, icmd.Success)
   206  	_, err = os.Stat(filepath.Join(tempDir, "test.chart", "Chart.yaml"))
   207  	assert.NilError(t, err)
   208  	assert.NilError(t, os.Mkdir(filepath.Join(tempDir, "output"), 0755))
   209  	icmd.RunCmd(icmd.Cmd{
   210  		Command: []string{dockerApp, "unpack", "test", "-o", "output"},
   211  		Dir:     tempDir,
   212  	}).Assert(t, icmd.Success)
   213  	_, err = os.Stat(filepath.Join(tempDir, "output", "test.dockerapp", "docker-compose.yml"))
   214  	assert.NilError(t, err)
   215  }
   216  
   217  func TestHelm(t *testing.T) {
   218  	t.Run("default", testHelm(""))
   219  	t.Run("v1beta1", testHelm("v1beta1"))
   220  	t.Run("v1beta2", testHelm("v1beta2"))
   221  }
   222  
   223  func testHelm(version string) func(*testing.T) {
   224  	return func(t *testing.T) {
   225  		dir := fs.NewDir(t, "testHelmBinary", fs.FromDir("testdata"))
   226  		defer dir.Remove()
   227  		cmd := []string{dockerApp, "helm", "helm", "-s", "myapp.nginx_version=2"}
   228  		if version != "" {
   229  			cmd = append(cmd, "--stack-version", version)
   230  		}
   231  		icmd.RunCmd(icmd.Cmd{
   232  			Command: cmd,
   233  			Dir:     dir.Path(),
   234  		}).Assert(t, icmd.Success)
   235  
   236  		chart := golden.Get(t, dir.Join("helm.chart/Chart.yaml"))
   237  		values := golden.Get(t, dir.Join("helm.chart/values.yaml"))
   238  		stack := golden.Get(t, dir.Join("helm.chart/templates/stack.yaml"))
   239  		assert.Check(t, golden.String(string(chart), "helm-expected.chart/Chart.yaml"))
   240  		assert.Check(t, golden.String(string(values), "helm-expected.chart/values.yaml"))
   241  		assert.Check(t, golden.String(string(stack), "helm-expected.chart/templates/stack"+version+".yaml"))
   242  	}
   243  }
   244  
   245  func TestHelmInvalidStackVersion(t *testing.T) {
   246  	icmd.RunCommand(dockerApp, "helm", "testdata/helm", "--stack-version", "foobar").Assert(t, icmd.Expected{
   247  		ExitCode: 1,
   248  		Err:      `Error: invalid stack version "foobar" (accepted values: v1beta1, v1beta2)`,
   249  	})
   250  }
   251  
   252  func TestSplitMerge(t *testing.T) {
   253  	icmd.RunCommand(dockerApp, "merge", "testdata/render/envvariables/my.dockerapp", "-o", "remerged.dockerapp").Assert(t, icmd.Success)
   254  	defer os.Remove("remerged.dockerapp")
   255  	// test that inspect works on single-file
   256  	result := icmd.RunCommand(dockerApp, "inspect", "remerged").Assert(t, icmd.Success)
   257  	assert.Assert(t, golden.String(result.Combined(), "envvariables-inspect.golden"))
   258  	// split it
   259  	icmd.RunCommand(dockerApp, "split", "remerged", "-o", "split.dockerapp").Assert(t, icmd.Success)
   260  	defer os.RemoveAll("split.dockerapp")
   261  	result = icmd.RunCommand(dockerApp, "inspect", "remerged").Assert(t, icmd.Success)
   262  	assert.Assert(t, golden.String(result.Combined(), "envvariables-inspect.golden"))
   263  	// test inplace
   264  	icmd.RunCommand(dockerApp, "merge", "split").Assert(t, icmd.Success)
   265  	icmd.RunCommand(dockerApp, "split", "split").Assert(t, icmd.Success)
   266  }
   267  
   268  func TestURL(t *testing.T) {
   269  	url := "https://raw.githubusercontent.com/docker/app/v0.4.1/examples/hello-world/hello-world.dockerapp"
   270  	result := icmd.RunCommand(dockerApp, "inspect", url).Assert(t, icmd.Success)
   271  	assert.Assert(t, golden.String(result.Combined(), "helloworld-inspect.golden"))
   272  }
   273  
   274  func TestWithRegistry(t *testing.T) {
   275  	r := startRegistry(t)
   276  	defer r.Stop(t)
   277  	registry := r.GetAddress(t)
   278  	t.Run("image", testImage(registry))
   279  	t.Run("fork", testFork(registry))
   280  }
   281  
   282  func testImage(registry string) func(*testing.T) {
   283  	return func(t *testing.T) {
   284  		// push to a registry
   285  		icmd.RunCommand(dockerApp, "push", "--namespace", registry+"/myuser", "testdata/render/envvariables/my.dockerapp").Assert(t, icmd.Success)
   286  		icmd.RunCommand(dockerApp, "push", "--namespace", registry+"/myuser", "-t", "latest", "testdata/render/envvariables/my.dockerapp").Assert(t, icmd.Success)
   287  		icmd.RunCommand(dockerApp, "inspect", registry+"/myuser/my.dockerapp:0.1.0").Assert(t, icmd.Success)
   288  		icmd.RunCommand(dockerApp, "inspect", registry+"/myuser/my.dockerapp").Assert(t, icmd.Success)
   289  		icmd.RunCommand(dockerApp, "inspect", registry+"/myuser/my").Assert(t, icmd.Success)
   290  		icmd.RunCommand(dockerApp, "inspect", registry+"/myuser/my:0.1.0").Assert(t, icmd.Success)
   291  		// push a single-file app to a registry
   292  		dir := fs.NewDir(t, "save-prepare-build", fs.WithFile("my.dockerapp", singleFileApp))
   293  		defer dir.Remove()
   294  		icmd.RunCommand(dockerApp, "push", "--namespace", registry+"/myuser", dir.Join("my.dockerapp")).Assert(t, icmd.Success)
   295  
   296  		// push with custom repo name
   297  		icmd.RunCommand(dockerApp, "push", "-t", "marshmallows", "--namespace", registry+"/rainbows", "--repo", "unicorns", "testdata/render/envvariables/my.dockerapp").Assert(t, icmd.Success)
   298  		icmd.RunCommand(dockerApp, "inspect", registry+"/rainbows/unicorns:marshmallows").Assert(t, icmd.Success)
   299  	}
   300  }
   301  
   302  func testFork(registry string) func(*testing.T) {
   303  	return func(t *testing.T) {
   304  		icmd.RunCommand(dockerApp, "push", "--namespace", registry+"/acmecorp", "testdata/fork/simple").Assert(t, icmd.Success)
   305  
   306  		tempDir := fs.NewDir(t, "dockerapptest")
   307  		defer tempDir.Remove()
   308  
   309  		icmd.RunCommand(dockerApp, "fork", registry+"/acmecorp/simple.dockerapp:1.1.0-beta1", "acmecorp/scarlet.devil",
   310  			"-p", tempDir.Path(), "-m", "Remilia Scarlet:remilia@acmecorp.cool").Assert(t, icmd.Success)
   311  		metadata := golden.Get(t, tempDir.Join("scarlet.devil.dockerapp", "metadata.yml"))
   312  		assert.Assert(t, golden.Bytes(metadata, "expected-fork-metadata.golden"))
   313  
   314  		icmd.RunCommand(dockerApp, "fork", registry+"/acmecorp/simple.dockerapp:1.1.0-beta1",
   315  			"-p", tempDir.Path(), "-m", "Remilia Scarlet:remilia@acmecorp.cool").Assert(t, icmd.Success)
   316  		metadata2 := golden.Get(t, tempDir.Join("simple.dockerapp", "metadata.yml"))
   317  		assert.Assert(t, golden.Bytes(metadata2, "expected-fork-metadata-no-rename.golden"))
   318  	}
   319  }
   320  
   321  func TestAttachmentsWithRegistry(t *testing.T) {
   322  	r := startRegistry(t)
   323  	defer r.Stop(t)
   324  	registry := r.GetAddress(t)
   325  
   326  	dir := fs.NewDir(t, "testattachments",
   327  		fs.WithDir("attachments.dockerapp", fs.FromDir("testdata/attachments.dockerapp")),
   328  	)
   329  	defer dir.Remove()
   330  
   331  	icmd.RunCommand(dockerApp, "push", "--namespace", registry+"/acmecorp", dir.Join("attachments.dockerapp")).Assert(t, icmd.Success)
   332  
   333  	// inspect will run the core pull code too
   334  	result := icmd.RunCommand(dockerApp, "inspect", registry+"/acmecorp/attachments.dockerapp:0.1.0")
   335  
   336  	result.Assert(t, icmd.Success)
   337  	resultOutput := result.Combined()
   338  
   339  	assert.Assert(t, strings.Contains(resultOutput, "config.cfg"))
   340  	assert.Assert(t, strings.Contains(resultOutput, "nesteddir/config2.cfg"))
   341  	assert.Assert(t, strings.Contains(resultOutput, "nesteddir/nested2/nested3/config3.cfg"))
   342  
   343  	// Test forking with external files
   344  	tempDir := fs.NewDir(t, "dockerapptest")
   345  	defer tempDir.Remove()
   346  
   347  	icmd.RunCommand(dockerApp, "fork", registry+"/acmecorp/attachments.dockerapp:0.1.0",
   348  		"-p", tempDir.Path()).Assert(t, icmd.Success)
   349  	externalFile := golden.Get(t, tempDir.Join("attachments.dockerapp", "config.cfg"))
   350  	assert.Assert(t, golden.Bytes(externalFile, filepath.Join("attachments.dockerapp", "config.cfg")))
   351  
   352  	nestedAttachment := golden.Get(t, tempDir.Join("attachments.dockerapp", "nesteddir", "config2.cfg"))
   353  	assert.Assert(t, golden.Bytes(nestedAttachment, filepath.Join("attachments.dockerapp", "nesteddir", "config2.cfg")))
   354  }