1package command
2
3import (
4	"fmt"
5	"io/ioutil"
6	"os"
7	"strings"
8	"testing"
9
10	"github.com/hashicorp/nomad/testutil"
11	"github.com/mitchellh/cli"
12)
13
14func TestRunCommand_Implements(t *testing.T) {
15	t.Parallel()
16	var _ cli.Command = &JobRunCommand{}
17}
18
19func TestRunCommand_Output_Json(t *testing.T) {
20	t.Parallel()
21	ui := new(cli.MockUi)
22	cmd := &JobRunCommand{Meta: Meta{Ui: ui}}
23
24	fh, err := ioutil.TempFile("", "nomad")
25	if err != nil {
26		t.Fatalf("err: %s", err)
27	}
28	defer os.Remove(fh.Name())
29	_, err = fh.WriteString(`
30job "job1" {
31	type = "service"
32	datacenters = [ "dc1" ]
33	group "group1" {
34		count = 1
35		task "task1" {
36			driver = "exec"
37			resources = {
38				cpu = 1000
39				memory = 512
40			}
41		}
42	}
43}`)
44	if err != nil {
45		t.Fatalf("err: %s", err)
46	}
47	if code := cmd.Run([]string{"-output", fh.Name()}); code != 0 {
48		t.Fatalf("expected exit code 0, got: %d", code)
49	}
50	if out := ui.OutputWriter.String(); !strings.Contains(out, `"Type": "service",`) {
51		t.Fatalf("Expected JSON output: %v", out)
52	}
53}
54
55func TestRunCommand_Fails(t *testing.T) {
56	t.Parallel()
57	ui := new(cli.MockUi)
58	cmd := &JobRunCommand{Meta: Meta{Ui: ui}}
59
60	// Create a server
61	s := testutil.NewTestServer(t, nil)
62	defer s.Stop()
63	os.Setenv("NOMAD_ADDR", fmt.Sprintf("http://%s", s.HTTPAddr))
64
65	// Fails on misuse
66	if code := cmd.Run([]string{"some", "bad", "args"}); code != 1 {
67		t.Fatalf("expected exit code 1, got: %d", code)
68	}
69	if out := ui.ErrorWriter.String(); !strings.Contains(out, commandErrorText(cmd)) {
70		t.Fatalf("expected help output, got: %s", out)
71	}
72	ui.ErrorWriter.Reset()
73
74	// Fails when specified file does not exist
75	if code := cmd.Run([]string{"/unicorns/leprechauns"}); code != 1 {
76		t.Fatalf("expect exit 1, got: %d", code)
77	}
78	if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error getting job struct") {
79		t.Fatalf("expect getting job struct error, got: %s", out)
80	}
81	ui.ErrorWriter.Reset()
82
83	// Fails on invalid HCL
84	fh1, err := ioutil.TempFile("", "nomad")
85	if err != nil {
86		t.Fatalf("err: %s", err)
87	}
88	defer os.Remove(fh1.Name())
89	if _, err := fh1.WriteString("nope"); err != nil {
90		t.Fatalf("err: %s", err)
91	}
92	if code := cmd.Run([]string{fh1.Name()}); code != 1 {
93		t.Fatalf("expect exit 1, got: %d", code)
94	}
95	if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error getting job struct") {
96		t.Fatalf("expect parsing error, got: %s", out)
97	}
98	ui.ErrorWriter.Reset()
99
100	// Fails on invalid job spec
101	fh2, err := ioutil.TempFile("", "nomad")
102	if err != nil {
103		t.Fatalf("err: %s", err)
104	}
105	defer os.Remove(fh2.Name())
106	if _, err := fh2.WriteString(`job "job1" {}`); err != nil {
107		t.Fatalf("err: %s", err)
108	}
109	if code := cmd.Run([]string{fh2.Name()}); code != 1 {
110		t.Fatalf("expect exit 1, got: %d", code)
111	}
112	if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error submitting job") {
113		t.Fatalf("expect validation error, got: %s", out)
114	}
115	ui.ErrorWriter.Reset()
116
117	// Fails on connection failure (requires a valid job)
118	fh3, err := ioutil.TempFile("", "nomad")
119	if err != nil {
120		t.Fatalf("err: %s", err)
121	}
122	defer os.Remove(fh3.Name())
123	_, err = fh3.WriteString(`
124job "job1" {
125	type = "service"
126	datacenters = [ "dc1" ]
127	group "group1" {
128		count = 1
129		task "task1" {
130			driver = "exec"
131			resources = {
132				cpu = 1000
133				memory = 512
134			}
135		}
136	}
137}`)
138	if err != nil {
139		t.Fatalf("err: %s", err)
140	}
141	if code := cmd.Run([]string{"-address=nope", fh3.Name()}); code != 1 {
142		t.Fatalf("expected exit code 1, got: %d", code)
143	}
144	if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error submitting job") {
145		t.Fatalf("expected failed query error, got: %s", out)
146	}
147
148	// Fails on invalid check-index (requires a valid job)
149	if code := cmd.Run([]string{"-check-index=bad", fh3.Name()}); code != 1 {
150		t.Fatalf("expected exit code 1, got: %d", code)
151	}
152	if out := ui.ErrorWriter.String(); !strings.Contains(out, "parsing check-index") {
153		t.Fatalf("expected parse error, got: %s", out)
154	}
155	ui.ErrorWriter.Reset()
156
157}
158
159func TestRunCommand_From_STDIN(t *testing.T) {
160	t.Parallel()
161	stdinR, stdinW, err := os.Pipe()
162	if err != nil {
163		t.Fatalf("err: %s", err)
164	}
165
166	ui := new(cli.MockUi)
167	cmd := &JobRunCommand{
168		Meta:      Meta{Ui: ui},
169		JobGetter: JobGetter{testStdin: stdinR},
170	}
171
172	go func() {
173		stdinW.WriteString(`
174job "job1" {
175  type = "service"
176  datacenters = [ "dc1" ]
177  group "group1" {
178		count = 1
179		task "task1" {
180			driver = "exec"
181			resources = {
182				cpu = 1000
183				memory = 512
184			}
185		}
186	}
187}`)
188		stdinW.Close()
189	}()
190
191	args := []string{"-address=nope", "-"}
192	if code := cmd.Run(args); code != 1 {
193		t.Fatalf("expected exit code 1, got %d: %q", code, ui.ErrorWriter.String())
194	}
195
196	if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error submitting job") {
197		t.Fatalf("expected submission error, got: %s", out)
198	}
199	ui.ErrorWriter.Reset()
200}
201
202func TestRunCommand_From_URL(t *testing.T) {
203	t.Parallel()
204	ui := new(cli.MockUi)
205	cmd := &JobRunCommand{
206		Meta: Meta{Ui: ui},
207	}
208
209	args := []string{"https://example.com/foo/bar"}
210	if code := cmd.Run(args); code != 1 {
211		t.Fatalf("expected exit code 1, got %d: %q", code, ui.ErrorWriter.String())
212	}
213
214	if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error getting jobfile") {
215		t.Fatalf("expected error getting jobfile, got: %s", out)
216	}
217}
218