| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package main_test |
| |
| import ( |
| "bytes" |
| "encoding/json" |
| "fmt" |
| "io/ioutil" |
| "os" |
| "path/filepath" |
| "reflect" |
| "strings" |
| "testing" |
| |
| "v.io/v23/naming" |
| "v.io/v23/security" |
| "v.io/v23/services/application" |
| "v.io/v23/services/device" |
| "v.io/x/lib/cmdline" |
| "v.io/x/ref/lib/v23cmd" |
| "v.io/x/ref/test" |
| |
| cmd_device "v.io/x/ref/services/device/device" |
| ) |
| |
| func createFile(t *testing.T, path string, contents string) { |
| if err := ioutil.WriteFile(path, []byte(contents), 0700); err != nil { |
| t.Fatalf("Failed to create %v: %v", path, err) |
| } |
| } |
| |
| func TestInstallLocalCommand(t *testing.T) { |
| ctx, shutdown := test.InitForTest() |
| defer shutdown() |
| |
| tapes := newTapeMap() |
| server, endpoint, err := startServer(t, ctx, tapes) |
| if err != nil { |
| return |
| } |
| defer stopServer(t, server) |
| // Setup the command-line. |
| cmd := cmd_device.CmdRoot |
| var stdout, stderr bytes.Buffer |
| env := &cmdline.Env{Stdout: &stdout, Stderr: &stderr} |
| deviceName := naming.JoinAddressName(endpoint.String(), "") |
| const appTitle = "Appo di tutti Appi" |
| binary := os.Args[0] |
| fi, err := os.Stat(binary) |
| if err != nil { |
| t.Fatalf("Failed to stat %v: %v", binary, err) |
| } |
| binarySize := fi.Size() |
| rootTape := tapes.forSuffix("") |
| for i, c := range []struct { |
| args []string |
| stderrSubstr string |
| }{ |
| { |
| []string{deviceName}, "incorrect number of arguments", |
| }, |
| { |
| []string{deviceName, appTitle}, "missing binary", |
| }, |
| { |
| []string{deviceName, appTitle, "a=b"}, "missing binary", |
| }, |
| { |
| []string{deviceName, appTitle, "foo"}, "binary foo not found", |
| }, |
| { |
| []string{deviceName, appTitle, binary, "PACKAGES", "foo"}, "foo not found", |
| }, |
| } { |
| c.args = append([]string{"install-local"}, c.args...) |
| if err := v23cmd.ParseAndRun(cmd, ctx, env, c.args); err == nil { |
| t.Fatalf("test case %d: wrongly failed to receive a non-nil error.", i) |
| } else { |
| fmt.Fprintln(&stderr, "ERROR:", err) |
| if want, got := c.stderrSubstr, stderr.String(); !strings.Contains(got, want) { |
| t.Errorf("test case %d: %q not found in stderr: %q", i, want, got) |
| } |
| } |
| if got, expected := len(rootTape.Play()), 0; got != expected { |
| t.Errorf("test case %d: invalid call sequence. Got %v, want %v", i, got, expected) |
| } |
| rootTape.Rewind() |
| stdout.Reset() |
| stderr.Reset() |
| } |
| emptySig := security.Signature{} |
| emptyBlessings := security.Blessings{} |
| cfg := device.Config{"someflag": "somevalue"} |
| |
| testPackagesDir, err := ioutil.TempDir("", "testdir") |
| if err != nil { |
| t.Fatalf("Failed to create temp dir: %v", err) |
| } |
| defer os.RemoveAll(testPackagesDir) |
| pkgFile1 := filepath.Join(testPackagesDir, "file1.txt") |
| createFile(t, pkgFile1, "1234567") |
| pkgFile2 := filepath.Join(testPackagesDir, "file2") |
| createFile(t, pkgFile2, string([]byte{0x01, 0x02, 0x03, 0x04})) |
| pkgDir1 := filepath.Join(testPackagesDir, "dir1") |
| if err := os.Mkdir(pkgDir1, 0700); err != nil { |
| t.Fatalf("Failed to create dir1: %v", err) |
| } |
| createFile(t, filepath.Join(pkgDir1, "f1"), "123") |
| createFile(t, filepath.Join(pkgDir1, "f2"), "456") |
| createFile(t, filepath.Join(pkgDir1, "f3"), "7890") |
| |
| pkgFile3 := filepath.Join(testPackagesDir, "file3") |
| createFile(t, pkgFile3, "12345") |
| pkgFile4 := filepath.Join(testPackagesDir, "file4") |
| createFile(t, pkgFile4, "123") |
| pkgDir2 := filepath.Join(testPackagesDir, "dir2") |
| if err := os.Mkdir(pkgDir2, 0700); err != nil { |
| t.Fatalf("Failed to create dir2: %v", err) |
| } |
| createFile(t, filepath.Join(pkgDir2, "f1"), "123456") |
| createFile(t, filepath.Join(pkgDir2, "f2"), "78") |
| pkg := application.Packages{ |
| "overridepkg1": application.SignedFile{File: pkgFile3}, |
| "overridepkg2": application.SignedFile{File: pkgFile4}, |
| "overridepkg3": application.SignedFile{File: pkgDir2}, |
| } |
| |
| for i, c := range []struct { |
| args []string |
| config device.Config |
| packages application.Packages |
| expectedTape interface{} |
| }{ |
| { |
| []string{deviceName, appTitle, binary}, |
| nil, |
| nil, |
| InstallStimulus{ |
| "Install", |
| appNameAfterFetch, |
| nil, |
| nil, |
| application.Envelope{ |
| Title: appTitle, |
| Binary: application.SignedFile{ |
| File: binaryNameAfterFetch, |
| Signature: emptySig, |
| }, |
| Publisher: emptyBlessings, |
| }, |
| map[string]int64{"binary": binarySize}}, |
| }, |
| { |
| []string{deviceName, appTitle, binary}, |
| cfg, |
| nil, |
| InstallStimulus{ |
| "Install", |
| appNameAfterFetch, |
| cfg, |
| nil, |
| application.Envelope{ |
| Title: appTitle, |
| Binary: application.SignedFile{ |
| File: binaryNameAfterFetch, |
| Signature: emptySig, |
| }, |
| Publisher: emptyBlessings, |
| }, |
| map[string]int64{"binary": binarySize}}, |
| }, |
| { |
| []string{deviceName, appTitle, "ENV1=V1", "ENV2=V2", binary, "FLAG1=V1", "FLAG2=V2"}, |
| nil, |
| nil, |
| InstallStimulus{ |
| "Install", |
| appNameAfterFetch, |
| nil, |
| nil, |
| application.Envelope{ |
| Title: appTitle, |
| Binary: application.SignedFile{ |
| File: binaryNameAfterFetch, |
| Signature: emptySig, |
| }, |
| Publisher: emptyBlessings, |
| Env: []string{"ENV1=V1", "ENV2=V2"}, |
| Args: []string{"FLAG1=V1", "FLAG2=V2"}, |
| }, |
| map[string]int64{"binary": binarySize}}, |
| }, |
| { |
| []string{deviceName, appTitle, "ENV=V", binary, "FLAG=V", "PACKAGES", pkgFile1, pkgFile2, pkgDir1}, |
| nil, |
| pkg, |
| InstallStimulus{"Install", |
| appNameAfterFetch, |
| nil, |
| nil, |
| application.Envelope{ |
| Title: appTitle, |
| Binary: application.SignedFile{ |
| File: binaryNameAfterFetch, |
| Signature: emptySig, |
| }, |
| Publisher: emptyBlessings, |
| Env: []string{"ENV=V"}, |
| Args: []string{"FLAG=V"}, |
| }, |
| map[string]int64{ |
| "binary": binarySize, |
| "packages/file1.txt": 7, |
| "packages/file2": 4, |
| "packages/dir1": 10, |
| "overridepackages/overridepkg1": 5, |
| "overridepackages/overridepkg2": 3, |
| "overridepackages/overridepkg3": 8, |
| }, |
| }, |
| }, |
| } { |
| const appId = "myBestAppID" |
| rootTape.SetResponses([]interface{}{InstallResponse{appId, nil}}) |
| if c.config != nil { |
| jsonConfig, err := json.Marshal(c.config) |
| if err != nil { |
| t.Fatalf("test case %d: Marshal(%v) failed: %v", i, c.config, err) |
| } |
| c.args = append([]string{fmt.Sprintf("--config=%s", string(jsonConfig))}, c.args...) |
| } |
| if c.packages != nil { |
| jsonPackages, err := json.Marshal(c.packages) |
| if err != nil { |
| t.Fatalf("test case %d: Marshal(%v) failed: %v", i, c.packages, err) |
| } |
| c.args = append([]string{fmt.Sprintf("--packages=%s", string(jsonPackages))}, c.args...) |
| } |
| c.args = append([]string{"install-local"}, c.args...) |
| if err := v23cmd.ParseAndRun(cmd, ctx, env, c.args); err != nil { |
| t.Fatalf("test case %d: %v", i, err) |
| } |
| if expected, got := naming.Join(deviceName, appId), strings.TrimSpace(stdout.String()); got != expected { |
| t.Fatalf("test case %d: Unexpected output from Install. Got %q, expected %q", i, got, expected) |
| } |
| if got, expected := rootTape.Play(), []interface{}{c.expectedTape}; !reflect.DeepEqual(expected, got) { |
| t.Errorf("test case %d: Invalid call sequence. Got %#v, want %#v", i, got, expected) |
| } |
| rootTape.Rewind() |
| stdout.Reset() |
| stderr.Reset() |
| } |
| } |