blob: 62dc931edfdd54863822181e1dbdb1c13cf1c334 [file] [log] [blame]
Bogdan Capritac87a9142014-07-21 10:38:13 -07001package impl_test
2
3import (
4 "fmt"
Bogdan Capritad2b9f032014-10-10 17:43:29 -07005 "io/ioutil"
Bogdan Capritac87a9142014-07-21 10:38:13 -07006 "os"
Bogdan Capritad2b9f032014-10-10 17:43:29 -07007 "path/filepath"
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -07008 "reflect"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07009 "runtime"
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -070010 "sort"
Shyam Jayaramandbae76b2014-11-17 12:51:29 -080011 "strings"
Bogdan Capritac87a9142014-07-21 10:38:13 -070012 "testing"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070013 "time"
Bogdan Capritac87a9142014-07-21 10:38:13 -070014
Jiri Simsa519c5072014-09-17 21:37:57 -070015 "veyron.io/veyron/veyron2"
16 "veyron.io/veyron/veyron2/ipc"
17 "veyron.io/veyron/veyron2/naming"
18 "veyron.io/veyron/veyron2/rt"
Bogdan Caprita26929102014-11-07 11:56:56 -080019 "veyron.io/veyron/veyron2/security"
Jiri Simsa519c5072014-09-17 21:37:57 -070020 "veyron.io/veyron/veyron2/services/mgmt/node"
21 "veyron.io/veyron/veyron2/verror"
22 "veyron.io/veyron/veyron2/vlog"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -070023
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070024 "veyron.io/veyron/veyron/lib/expect"
Asim Shankar95910b62014-10-31 22:02:29 -070025 "veyron.io/veyron/veyron/lib/flags/consts"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070026 "veyron.io/veyron/veyron/lib/modules"
27 "veyron.io/veyron/veyron/lib/modules/core"
Bogdan Caprita26929102014-11-07 11:56:56 -080028 tsecurity "veyron.io/veyron/veyron/lib/testutil/security"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070029 "veyron.io/veyron/veyron/profiles/static"
30 "veyron.io/veyron/veyron/services/mgmt/node/impl"
31 "veyron.io/veyron/veyron2/services/mgmt/application"
Bogdan Capritac87a9142014-07-21 10:38:13 -070032)
33
Bogdan Capritad2b9f032014-10-10 17:43:29 -070034// Setting this environment variable to any non-empty value avoids removing the
35// node manager's workspace for successful test runs (for failed test runs, this
36// is already the case). This is useful when developing test cases.
37const preserveNMWorkspaceEnv = "VEYRON_TEST_PRESERVE_NM_WORKSPACE"
38
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070039func loc(d int) string {
40 _, file, line, _ := runtime.Caller(d + 1)
41 return fmt.Sprintf("%s:%d", filepath.Base(file), line)
Bogdan Capritac87a9142014-07-21 10:38:13 -070042}
43
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070044func startRootMT(t *testing.T, sh *modules.Shell) (string, modules.Handle, *expect.Session) {
Cosmos Nicolaou612ad382014-10-29 19:41:35 -070045 h, err := sh.Start(core.RootMTCommand, nil, "--", "--veyron.tcp.address=127.0.0.1:0")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070046 if err != nil {
47 t.Fatalf("failed to start root mount table: %s", err)
48 }
49 s := expect.NewSession(t, h.Stdout(), time.Minute)
50 rootName := s.ExpectVar("MT_NAME")
51 if t.Failed() {
52 t.Fatalf("failed to read mt name: %s", s.Error())
53 }
54 return rootName, h, s
Bogdan Capritab9501d12014-10-10 15:02:03 -070055}
56
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070057func credentialsForChild(blessing string) (string, []string) {
Bogdan Caprita26929102014-11-07 11:56:56 -080058 creds := tsecurity.NewVeyronCredentials(rt.R().Principal(), blessing)
Asim Shankar95910b62014-10-31 22:02:29 -070059 return creds, []string{consts.VeyronCredentials + "=" + creds}
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070060}
61
62func createShellAndMountTable(t *testing.T) (*modules.Shell, func()) {
63 sh := core.NewShell()
64 // The shell, will, by default share credentials with its children.
Asim Shankar95910b62014-10-31 22:02:29 -070065 sh.ClearVar(consts.VeyronCredentials)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070066
67 mtName, mtHandle, _ := startRootMT(t, sh)
68 // Make sure the root mount table is the last process to be shutdown
69 // since the others will likely want to communicate with it during
70 // their shutdown process
71 sh.Forget(mtHandle)
72
73 fn := func() {
74 vlog.VI(1).Info("------------ CLEANUP ------------")
75 vlog.VI(1).Info("---------------------------------")
76 sh.Cleanup(nil, os.Stderr)
77 mtHandle.Shutdown(nil, os.Stderr)
Cosmos Nicolaou612ad382014-10-29 19:41:35 -070078 sh.Start(core.SetNamespaceRootsCommand, nil, "")
Bogdan Capritac87a9142014-07-21 10:38:13 -070079 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070080
Cosmos Nicolaou612ad382014-10-29 19:41:35 -070081 if _, err := sh.Start(core.SetNamespaceRootsCommand, nil, mtName); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070082 t.Fatalf("%s: unexpected error: %s", loc(1), err)
83 }
Asim Shankar95910b62014-10-31 22:02:29 -070084 sh.SetVar(consts.NamespaceRootPrefix, mtName)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070085 return sh, fn
86}
87
88func runShellCommand(t *testing.T, sh *modules.Shell, env []string, cmd string, args ...string) (modules.Handle, *expect.Session) {
Cosmos Nicolaou612ad382014-10-29 19:41:35 -070089 h, err := sh.Start(cmd, env, args...)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070090 if err != nil {
91 t.Fatalf("%s: failed to start %q: %s", loc(1), cmd, err)
92 return nil, nil
93 }
94 s := expect.NewSession(t, h.Stdout(), 10*time.Second)
95 s.SetVerbosity(testing.Verbose())
96 return h, s
97}
98
99func envelopeFromShell(sh *modules.Shell, env []string, cmd, title string, args ...string) application.Envelope {
100 args, nenv := sh.CommandEnvelope(cmd, env, args...)
101 return application.Envelope{
102 Title: title,
103 Args: args[1:],
104 // TODO(caprita): revisit how the environment is sanitized for arbirary
105 // apps.
106 Env: impl.VeyronEnvironment(nenv),
107 Binary: mockBinaryRepoName,
Bogdan Capritac87a9142014-07-21 10:38:13 -0700108 }
109}
110
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700111// setupRootDir sets up and returns the local filesystem location that the node
112// manager is told to use, as well as a cleanup function.
113func setupRootDir(t *testing.T) (string, func()) {
114 rootDir, err := ioutil.TempDir("", "nodemanager")
115 if err != nil {
116 t.Fatalf("Failed to set up temporary dir for test: %v", err)
117 }
118 // On some operating systems (e.g. darwin) os.TempDir() can return a
119 // symlink. To avoid having to account for this eventuality later,
120 // evaluate the symlink.
121 rootDir, err = filepath.EvalSymlinks(rootDir)
122 if err != nil {
123 vlog.Fatalf("EvalSymlinks(%v) failed: %v", rootDir, err)
124 }
125 return rootDir, func() {
126 if t.Failed() || os.Getenv(preserveNMWorkspaceEnv) != "" {
127 t.Logf("You can examine the node manager workspace at %v", rootDir)
128 } else {
129 os.RemoveAll(rootDir)
130 }
131 }
132}
133
Bogdan Capritac87a9142014-07-21 10:38:13 -0700134func newServer() (ipc.Server, string) {
135 server, err := rt.R().NewServer()
136 if err != nil {
137 vlog.Fatalf("NewServer() failed: %v", err)
138 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700139 spec := static.ListenSpec
140 spec.Address = "127.0.0.1:0"
141 endpoint, err := server.Listen(spec)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700142 if err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700143 vlog.Fatalf("Listen(%s) failed: %v", static.ListenSpec, err)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700144 }
145 return server, endpoint.String()
146}
147
148// resolveExpectError verifies that the given name is not in the mounttable.
Bogdan Capritabce0a632014-09-03 16:15:26 -0700149func resolveExpectNotFound(t *testing.T, name string) {
Bogdan Capritac87a9142014-07-21 10:38:13 -0700150 if results, err := rt.R().Namespace().Resolve(rt.R().NewContext(), name); err == nil {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700151 t.Fatalf("Resolve(%v) succeeded with results %v when it was expected to fail", name, results)
Benjamin Prosnitzb8178d32014-11-04 10:24:12 -0800152 } else if expectErr := naming.ErrNoSuchName.ID; !verror.Is(err, expectErr) {
Tilak Sharma492e8e92014-09-18 10:58:14 -0700153 t.Fatalf("Resolve(%v) failed with error %v, expected error ID %v", name, err, expectErr)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700154 }
155}
156
157// resolve looks up the given name in the mounttable.
Bogdan Capritabce0a632014-09-03 16:15:26 -0700158func resolve(t *testing.T, name string, replicas int) []string {
Bogdan Capritac87a9142014-07-21 10:38:13 -0700159 results, err := rt.R().Namespace().Resolve(rt.R().NewContext(), name)
160 if err != nil {
161 t.Fatalf("Resolve(%v) failed: %v", name, err)
162 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800163
164 filteredResults := []string{}
165 for _, r := range results {
166 if strings.Index(r, "@tcp") != -1 {
167 filteredResults = append(filteredResults, r)
168 }
169 }
170 // We are going to get a websocket and a tcp endpoint for each replica.
171 if want, got := replicas, len(filteredResults); want != got {
Bogdan Capritac87a9142014-07-21 10:38:13 -0700172 t.Fatalf("Resolve(%v) expected %d result(s), got %d instead", name, want, got)
173 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800174 return filteredResults
Bogdan Capritac87a9142014-07-21 10:38:13 -0700175}
176
177// The following set of functions are convenience wrappers around Update and
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700178// Revert for node manager.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700179
Todd Wang702385a2014-11-07 01:54:08 -0800180func nodeStub(name string) node.NodeClientMethods {
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700181 nodeName := naming.Join(name, "nm")
Todd Wang702385a2014-11-07 01:54:08 -0800182 return node.NodeClient(nodeName)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700183}
184
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700185func updateNodeExpectError(t *testing.T, name string, errID verror.ID) {
Todd Wang702385a2014-11-07 01:54:08 -0800186 if err := nodeStub(name).Update(rt.R().NewContext()); !verror.Is(err, errID) {
Benjamin Prosnitzb8178d32014-11-04 10:24:12 -0800187 if errID == naming.ErrNoSuchName.ID && err.Error() == "no different version available" {
188 // TODO(bprosnitz) Remove this check when errUpdateNoOp is updated to verror2
189 return
190 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700191 t.Fatalf("%s: Update(%v) expected to fail with %v, got %v instead", loc(1), name, errID, err)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700192 }
193}
194
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700195func updateNode(t *testing.T, name string) {
Todd Wang702385a2014-11-07 01:54:08 -0800196 if err := nodeStub(name).Update(rt.R().NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700197 t.Fatalf("%s: Update(%v) failed: %v", loc(1), name, err)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700198 }
199}
200
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700201func revertNodeExpectError(t *testing.T, name string, errID verror.ID) {
Todd Wang702385a2014-11-07 01:54:08 -0800202 if err := nodeStub(name).Revert(rt.R().NewContext()); !verror.Is(err, errID) {
Benjamin Prosnitzb8178d32014-11-04 10:24:12 -0800203 if errID == naming.ErrNoSuchName.ID && err.Error() == "no different version available" {
204 // TODO(bprosnitz) Remove this check when errUpdateNoOp is updated to verror2
205 return
206 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700207 t.Fatalf("%s: Revert(%v) expected to fail with %v, got %v instead", loc(1), name, errID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700208 }
209}
210
211func revertNode(t *testing.T, name string) {
Todd Wang702385a2014-11-07 01:54:08 -0800212 if err := nodeStub(name).Revert(rt.R().NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700213 t.Fatalf("%s: Revert(%v) failed: %v", loc(1), name, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700214 }
215}
216
217// The following set of functions are convenience wrappers around various app
218// management methods.
219
Robert Kroeger362ff892014-09-29 14:23:47 -0700220func ort(opt []veyron2.Runtime) veyron2.Runtime {
221 if len(opt) > 0 {
222 return opt[0]
223 } else {
224 return rt.R()
225 }
226}
227
Todd Wang702385a2014-11-07 01:54:08 -0800228func appStub(nameComponents ...string) node.ApplicationClientMethods {
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700229 appsName := "nm//apps"
230 appName := naming.Join(append([]string{appsName}, nameComponents...)...)
Todd Wang702385a2014-11-07 01:54:08 -0800231 return node.ApplicationClient(appName)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700232}
233
Robert Kroeger362ff892014-09-29 14:23:47 -0700234func installApp(t *testing.T, opt ...veyron2.Runtime) string {
Todd Wang702385a2014-11-07 01:54:08 -0800235 appID, err := appStub().Install(ort(opt).NewContext(), mockApplicationRepoName)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700236 if err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700237 t.Fatalf("%s: Install failed: %v", loc(1), err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700238 }
239 return appID
240}
241
Bogdan Caprita26929102014-11-07 11:56:56 -0800242type granter struct {
243 ipc.CallOpt
244 p security.Principal
245 extension string
246}
247
248func (g *granter) Grant(other security.Blessings) (security.Blessings, error) {
249 return g.p.Bless(other.PublicKey(), g.p.BlessingStore().Default(), g.extension, security.UnconstrainedUse())
250}
251
Bogdan Caprita730bde12014-11-08 15:35:43 -0800252func startAppImpl(t *testing.T, appID, grant string, opt ...veyron2.Runtime) (string, error) {
253 var opts []ipc.CallOpt
254 if grant != "" {
255 opts = append(opts, &granter{p: ort(opt).Principal(), extension: grant})
256 }
257 if instanceIDs, err := appStub(appID).Start(ort(opt).NewContext(), opts...); err != nil {
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700258 return "", err
259 } else {
260 if want, got := 1, len(instanceIDs); want != got {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700261 t.Fatalf("%s: Start(%v): expected %v instance ids, got %v instead", loc(1), appID, want, got)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700262 }
263 return instanceIDs[0], nil
264 }
265}
266
Robert Kroeger362ff892014-09-29 14:23:47 -0700267func startApp(t *testing.T, appID string, opt ...veyron2.Runtime) string {
Bogdan Caprita730bde12014-11-08 15:35:43 -0800268 instanceID, err := startAppImpl(t, appID, "forapp", opt...)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700269 if err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700270 t.Fatalf("%s: Start(%v) failed: %v", loc(1), appID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700271 }
272 return instanceID
273}
274
Robert Kroeger362ff892014-09-29 14:23:47 -0700275func startAppExpectError(t *testing.T, appID string, expectedError verror.ID, opt ...veyron2.Runtime) {
Bogdan Caprita730bde12014-11-08 15:35:43 -0800276 if _, err := startAppImpl(t, appID, "forapp", opt...); err == nil || !verror.Is(err, expectedError) {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700277 t.Fatalf("%s: Start(%v) expected to fail with %v, got %v instead", loc(1), appID, expectedError, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700278 }
279}
280
Robert Kroeger362ff892014-09-29 14:23:47 -0700281func stopApp(t *testing.T, appID, instanceID string, opt ...veyron2.Runtime) {
Todd Wang702385a2014-11-07 01:54:08 -0800282 if err := appStub(appID, instanceID).Stop(ort(opt).NewContext(), 5); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700283 t.Fatalf("%s: Stop(%v/%v) failed: %v", loc(1), appID, instanceID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700284 }
285}
286
Robert Kroeger362ff892014-09-29 14:23:47 -0700287func suspendApp(t *testing.T, appID, instanceID string, opt ...veyron2.Runtime) {
Todd Wang702385a2014-11-07 01:54:08 -0800288 if err := appStub(appID, instanceID).Suspend(ort(opt).NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700289 t.Fatalf("%s: Suspend(%v/%v) failed: %v", loc(1), appID, instanceID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700290 }
291}
292
Robert Kroeger362ff892014-09-29 14:23:47 -0700293func resumeApp(t *testing.T, appID, instanceID string, opt ...veyron2.Runtime) {
Todd Wang702385a2014-11-07 01:54:08 -0800294 if err := appStub(appID, instanceID).Resume(ort(opt).NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700295 t.Fatalf("%s: Resume(%v/%v) failed: %v", loc(1), appID, instanceID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700296 }
297}
298
Robert Kroeger1ce0bd72014-10-22 13:57:14 -0700299func resumeAppExpectError(t *testing.T, appID, instanceID string, expectedError verror.ID, opt ...veyron2.Runtime) {
Todd Wang702385a2014-11-07 01:54:08 -0800300 if err := appStub(appID, instanceID).Resume(ort(opt).NewContext()); err == nil || !verror.Is(err, expectedError) {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700301 t.Fatalf("%s: Resume(%v/%v) expected to fail with %v, got %v instead", loc(1), appID, instanceID, expectedError, err)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -0700302 }
303}
304
Robert Kroeger362ff892014-09-29 14:23:47 -0700305func updateApp(t *testing.T, appID string, opt ...veyron2.Runtime) {
Todd Wang702385a2014-11-07 01:54:08 -0800306 if err := appStub(appID).Update(ort(opt).NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700307 t.Fatalf("%s: Update(%v) failed: %v", loc(1), appID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700308 }
309}
310
311func updateAppExpectError(t *testing.T, appID string, expectedError verror.ID) {
Todd Wang702385a2014-11-07 01:54:08 -0800312 if err := appStub(appID).Update(rt.R().NewContext()); err == nil || !verror.Is(err, expectedError) {
Benjamin Prosnitzb8178d32014-11-04 10:24:12 -0800313 if expectedError == naming.ErrNoSuchName.ID && err.Error() == "no different version available" {
314 // TODO(bprosnitz) Remove this check when errUpdateNoOp is updated to verror2
315 return
316 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700317 t.Fatalf("%s: Update(%v) expected to fail with %v, got %v instead", loc(1), appID, expectedError, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700318 }
319}
320
321func revertApp(t *testing.T, appID string) {
Todd Wang702385a2014-11-07 01:54:08 -0800322 if err := appStub(appID).Revert(rt.R().NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700323 t.Fatalf("%s: Revert(%v) failed: %v", loc(1), appID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700324 }
325}
326
327func revertAppExpectError(t *testing.T, appID string, expectedError verror.ID) {
Todd Wang702385a2014-11-07 01:54:08 -0800328 if err := appStub(appID).Revert(rt.R().NewContext()); err == nil || !verror.Is(err, expectedError) {
Benjamin Prosnitzb8178d32014-11-04 10:24:12 -0800329 if expectedError == naming.ErrNoSuchName.ID && err.Error() == "no different version available" {
330 // TODO(bprosnitz) Remove this check when errUpdateNoOp is updated to verror2
331 return
332 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700333 t.Fatalf("%s: Revert(%v) expected to fail with %v, got %v instead", loc(1), appID, expectedError, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700334 }
335}
336
337func uninstallApp(t *testing.T, appID string) {
Todd Wang702385a2014-11-07 01:54:08 -0800338 if err := appStub(appID).Uninstall(rt.R().NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700339 t.Fatalf("%s: Uninstall(%v) failed: %v", loc(1), appID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700340 }
Bogdan Capritac87a9142014-07-21 10:38:13 -0700341}
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700342
343// Code to make Association lists sortable.
344type byIdentity []node.Association
345
346func (a byIdentity) Len() int { return len(a) }
347func (a byIdentity) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
348func (a byIdentity) Less(i, j int) bool { return a[i].IdentityName < a[j].IdentityName }
349
350func compareAssociations(t *testing.T, got, expected []node.Association) {
351 sort.Sort(byIdentity(got))
352 sort.Sort(byIdentity(expected))
353 if !reflect.DeepEqual(got, expected) {
354 t.Fatalf("ListAssociations() got %v, expected %v", got, expected)
355 }
356}
Robert Kroeger94ec7562014-10-28 17:58:44 -0700357
358// generateSuidHelperScript builds a script to execute the test target as
359// a suidhelper instance and returns the path to the script.
360func generateSuidHelperScript(t *testing.T, root string) string {
361 output := "#!/bin/bash\n"
362 output += "VEYRON_SUIDHELPER_TEST=1"
363 output += " "
364 output += "exec" + " " + os.Args[0] + " " + "-minuid=1" + " " + "-test.run=TestSuidHelper $*"
365 output += "\n"
366
367 vlog.VI(1).Infof("script\n%s", output)
368
369 if err := os.MkdirAll(root, 0755); err != nil {
370 t.Fatalf("MkdirAll failed: %v", err)
371 }
372 // Helper does not need to live under the node manager's root dir, but
373 // we put it there for convenience.
374 path := filepath.Join(root, "helper.sh")
375 if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil {
376 t.Fatalf("WriteFile(%v) failed: %v", path, err)
377 }
378 return path
379}