| package engine |
| |
| import ( |
| "bytes" |
| "strings" |
| "testing" |
| |
| "github.com/docker/docker/pkg/ioutils" |
| ) |
| |
| func TestRegister(t *testing.T) { |
| if err := Register("dummy1", nil); err != nil { |
| t.Fatal(err) |
| } |
| |
| if err := Register("dummy1", nil); err == nil { |
| t.Fatalf("Expecting error, got none") |
| } |
| // Register is global so let's cleanup to avoid conflicts |
| defer unregister("dummy1") |
| |
| eng := New() |
| |
| //Should fail because global handlers are copied |
| //at the engine creation |
| if err := eng.Register("dummy1", nil); err == nil { |
| t.Fatalf("Expecting error, got none") |
| } |
| |
| if err := eng.Register("dummy2", nil); err != nil { |
| t.Fatal(err) |
| } |
| |
| if err := eng.Register("dummy2", nil); err == nil { |
| t.Fatalf("Expecting error, got none") |
| } |
| defer unregister("dummy2") |
| } |
| |
| func TestJob(t *testing.T) { |
| eng := New() |
| job1 := eng.Job("dummy1", "--level=awesome") |
| |
| if job1.handler != nil { |
| t.Fatalf("job1.handler should be empty") |
| } |
| |
| h := func(j *Job) Status { |
| j.Printf("%s\n", j.Name) |
| return 42 |
| } |
| |
| eng.Register("dummy2", h) |
| defer unregister("dummy2") |
| job2 := eng.Job("dummy2", "--level=awesome") |
| |
| if job2.handler == nil { |
| t.Fatalf("job2.handler shouldn't be nil") |
| } |
| |
| if job2.handler(job2) != 42 { |
| t.Fatalf("handler dummy2 was not found in job2") |
| } |
| } |
| |
| func TestEngineShutdown(t *testing.T) { |
| eng := New() |
| if eng.IsShutdown() { |
| t.Fatalf("Engine should not show as shutdown") |
| } |
| eng.Shutdown() |
| if !eng.IsShutdown() { |
| t.Fatalf("Engine should show as shutdown") |
| } |
| } |
| |
| func TestEngineCommands(t *testing.T) { |
| eng := New() |
| handler := func(job *Job) Status { return StatusOK } |
| eng.Register("foo", handler) |
| eng.Register("bar", handler) |
| eng.Register("echo", handler) |
| eng.Register("die", handler) |
| var output bytes.Buffer |
| commands := eng.Job("commands") |
| commands.Stdout.Add(&output) |
| commands.Run() |
| expected := "bar\ncommands\ndie\necho\nfoo\n" |
| if result := output.String(); result != expected { |
| t.Fatalf("Unexpected output:\nExpected = %v\nResult = %v\n", expected, result) |
| } |
| } |
| |
| func TestEngineString(t *testing.T) { |
| eng1 := New() |
| eng2 := New() |
| s1 := eng1.String() |
| s2 := eng2.String() |
| if eng1 == eng2 { |
| t.Fatalf("Different engines should have different names (%v == %v)", s1, s2) |
| } |
| } |
| |
| func TestParseJob(t *testing.T) { |
| eng := New() |
| // Verify that the resulting job calls to the right place |
| var called bool |
| eng.Register("echo", func(job *Job) Status { |
| called = true |
| return StatusOK |
| }) |
| input := "echo DEBUG=1 hello world VERBOSITY=42" |
| job, err := eng.ParseJob(input) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if job.Name != "echo" { |
| t.Fatalf("Invalid job name: %v", job.Name) |
| } |
| if strings.Join(job.Args, ":::") != "hello:::world" { |
| t.Fatalf("Invalid job args: %v", job.Args) |
| } |
| if job.Env().Get("DEBUG") != "1" { |
| t.Fatalf("Invalid job env: %v", job.Env) |
| } |
| if job.Env().Get("VERBOSITY") != "42" { |
| t.Fatalf("Invalid job env: %v", job.Env) |
| } |
| if len(job.Env().Map()) != 2 { |
| t.Fatalf("Invalid job env: %v", job.Env) |
| } |
| if err := job.Run(); err != nil { |
| t.Fatal(err) |
| } |
| if !called { |
| t.Fatalf("Job was not called") |
| } |
| } |
| |
| func TestCatchallEmptyName(t *testing.T) { |
| eng := New() |
| var called bool |
| eng.RegisterCatchall(func(job *Job) Status { |
| called = true |
| return StatusOK |
| }) |
| err := eng.Job("").Run() |
| if err == nil { |
| t.Fatalf("Engine.Job(\"\").Run() should return an error") |
| } |
| if called { |
| t.Fatalf("Engine.Job(\"\").Run() should return an error") |
| } |
| } |
| |
| // Ensure that a job within a job both using the same underlying standard |
| // output writer does not close the output of the outer job when the inner |
| // job's stdout is wrapped with a NopCloser. When not wrapped, it should |
| // close the outer job's output. |
| func TestNestedJobSharedOutput(t *testing.T) { |
| var ( |
| outerHandler Handler |
| innerHandler Handler |
| wrapOutput bool |
| ) |
| |
| outerHandler = func(job *Job) Status { |
| job.Stdout.Write([]byte("outer1")) |
| |
| innerJob := job.Eng.Job("innerJob") |
| |
| if wrapOutput { |
| innerJob.Stdout.Add(ioutils.NopWriteCloser(job.Stdout)) |
| } else { |
| innerJob.Stdout.Add(job.Stdout) |
| } |
| |
| if err := innerJob.Run(); err != nil { |
| t.Fatal(err) |
| } |
| |
| // If wrapOutput was *false* this write will do nothing. |
| // FIXME (jlhawn): It should cause an error to write to |
| // closed output. |
| job.Stdout.Write([]byte(" outer2")) |
| |
| return StatusOK |
| } |
| |
| innerHandler = func(job *Job) Status { |
| job.Stdout.Write([]byte(" inner")) |
| |
| return StatusOK |
| } |
| |
| eng := New() |
| eng.Register("outerJob", outerHandler) |
| eng.Register("innerJob", innerHandler) |
| |
| // wrapOutput starts *false* so the expected |
| // output of running the outer job will be: |
| // |
| // "outer1 inner" |
| // |
| outBuf := new(bytes.Buffer) |
| outerJob := eng.Job("outerJob") |
| outerJob.Stdout.Add(outBuf) |
| |
| if err := outerJob.Run(); err != nil { |
| t.Fatal(err) |
| } |
| |
| expectedOutput := "outer1 inner" |
| if outBuf.String() != expectedOutput { |
| t.Fatalf("expected job output to be %q, got %q", expectedOutput, outBuf.String()) |
| } |
| |
| // Set wrapOutput to true so that the expected |
| // output of running the outer job will be: |
| // |
| // "outer1 inner outer2" |
| // |
| wrapOutput = true |
| outBuf.Reset() |
| outerJob = eng.Job("outerJob") |
| outerJob.Stdout.Add(outBuf) |
| |
| if err := outerJob.Run(); err != nil { |
| t.Fatal(err) |
| } |
| |
| expectedOutput = "outer1 inner outer2" |
| if outBuf.String() != expectedOutput { |
| t.Fatalf("expected job output to be %q, got %q", expectedOutput, outBuf.String()) |
| } |
| } |