Example #1
0
func LoadFormulaFromFile(path string) def.Formula {
	filename, _ := filepath.Abs(path)

	content, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(Error.Wrap(fmt.Errorf("Could not read formula file %q: %s", filename, err)))
	}
	content = tab2space(content)

	var raw interface{}
	if err := yaml.Unmarshal(content, &raw); err != nil {
		panic(Error.New("Could not parse formula file %q: %s", filename, err))
	}
	raw = stringifyMapKeys(raw)
	formula := def.Formula{}
	if err := formula.Unmarshal(raw); err != nil {
		panic(Error.New("Could not parse formula file %q: %s", filename, err))
	}

	return formula
}
Example #2
0
/*
	Check the basics of exec:
	  - Does it work at all?
	  - Can we see error codes?
	  - Can we stream stdout?
	  - If there's no rootfs, does it panic?
	  - If the command's not found, does it panic?

	Anything that requires *more than the one rootfs input* or anything
	about outputs belongs in another part of the spec tests.

	If any of these fail, most other parts of the specs will also fail.
*/
func CheckBasicExecution(execEng executor.Executor) {
	Convey("SPEC: Attempting launch with a rootfs that doesn't exist should error", func() {
		formula := def.Formula{
			Inputs: []def.Input{
				{
					Type:     "tar",
					Location: "/",
					// Funny thing is, the URI isn't even necessarily where the buck stops;
					// Remote URIs need not be checked if caches are in play, etc.
					// So the hash needs to be set (and needs to be invalid).
					URI:  "file:///nonexistance/in/its/most/essential/unform.tar.gz",
					Hash: "defnot",
				},
			},
		}

		Convey("We should get an error from the warehouse", func() {
			result := execEng.Start(formula, def.JobID(guid.New()), nil, ioutil.Discard).Wait()
			So(result.Error, testutil.ShouldBeErrorClass, integrity.WarehouseError)
		})

		Convey("The job exit code should clearly indicate failure", FailureContinues, func() {
			formula.Accents = def.Accents{
				Entrypoint: []string{"echo", "echococo"},
			}
			job := execEng.Start(formula, def.JobID(guid.New()), nil, ioutil.Discard)
			So(job, ShouldNotBeNil)
			So(job.Wait().Error, ShouldNotBeNil)
			// Even though one should clearly also check the error status,
			//  zero here could be very confusing, so jobs that error before start should be -1.
			So(job.Wait().ExitCode, ShouldEqual, -1)
		})
	})

	Convey("SPEC: Launching a command with a working rootfs should work", func() {
		formula := getBaseFormula()

		Convey("The executor should be able to invoke echo", FailureContinues, func() {
			formula.Accents = def.Accents{
				Entrypoint: []string{"echo", "echococo"},
			}

			job := execEng.Start(formula, def.JobID(guid.New()), nil, ioutil.Discard)
			So(job, ShouldNotBeNil)
			// note that we can read output concurrently.
			// no need to wait for job done.
			msg, err := ioutil.ReadAll(job.OutputReader())
			So(err, ShouldBeNil)
			So(string(msg), ShouldEqual, "echococo\n")
			So(job.Wait().Error, ShouldBeNil)
			So(job.Wait().ExitCode, ShouldEqual, 0)
		})

		Convey("The executor should be able to check exit codes", func() {
			formula.Accents = def.Accents{
				Entrypoint: []string{"sh", "-c", "exit 14"},
			}

			job := execEng.Start(formula, def.JobID(guid.New()), nil, ioutil.Discard)
			So(job, ShouldNotBeNil)
			So(job.Wait().Error, ShouldBeNil)
			So(job.Wait().ExitCode, ShouldEqual, 14)
		})

		Convey("The executor should report command not found clearly", FailureContinues, func() {
			formula.Accents = def.Accents{
				Entrypoint: []string{"not a command"},
			}

			job := execEng.Start(formula, def.JobID(guid.New()), nil, ioutil.Discard)
			So(job.Wait().Error, testutil.ShouldBeErrorClass, executor.NoSuchCommandError)
			So(job.Wait().ExitCode, ShouldEqual, -1)
			msg, err := ioutil.ReadAll(job.OutputReader())
			So(err, ShouldBeNil)
			So(string(msg), ShouldEqual, "")
		})
	})
}