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 }