/*
	Checks round-trip hash consistency for the input and output halves of a transmat system.

	- Creates a fixture filesystem
	- Scans it with the output system
	- Places it in a new filesystem with the input system and the scanned hash
	- Checks the new filesystem matches the original
*/
func CheckRoundTrip(kind integrity.TransmatKind, transmatFabFn integrity.TransmatFactory, bounceURI string, addtnlDesc ...string) {
	Convey("SPEC: Round-trip scanning and remaking a filesystem should agree on hash and content"+testutil.AdditionalDescription(addtnlDesc...), testutil.Requires(
		testutil.RequiresRoot,
		func() {
			transmat := transmatFabFn("./workdir")
			for _, fixture := range filefixture.All {
				Convey(fmt.Sprintf("- Fixture %q", fixture.Name), FailureContinues, func() {
					uris := []integrity.SiloURI{integrity.SiloURI(bounceURI)}
					// setup fixture
					fixture.Create("./fixture")
					// scan it with the transmat
					dataHash := transmat.Scan(kind, "./fixture", uris)
					// materialize what we just scanned (along the way, requires hash match)
					arena := transmat.Materialize(kind, dataHash, uris, integrity.AcceptHashMismatch)
					// assert hash match
					// (normally survival would attest this, but we used the `AcceptHashMismatch` to supress panics in the name of letting the test see more after failures.)
					So(arena.Hash(), ShouldEqual, dataHash)
					// check filesystem to match original fixture
					// (do this check even if the input raised a hash mismatch, because it can help show why)
					rescan := filefixture.Scan(arena.Path())
					comparisonLevel := filefixture.CompareDefaults &^ filefixture.CompareSubsecond
					So(rescan.Describe(comparisonLevel), ShouldEqual, fixture.Describe(comparisonLevel))
				})
			}
		},
	))
}
Exemple #2
0
func TestTarOutputCompat(t *testing.T) {
	Convey("Output should produce a tar recognizable to gnu tar", t,
		testutil.Requires(
			testutil.RequiresRoot,
			testutil.WithTmpdir(func() {
				for _, fixture := range filefixture.All {
					Convey(fmt.Sprintf("- Fixture %q", fixture.Name), func() {
						// create fixture
						fixture.Create("./data")

						// scan it
						transmat := New("./workdir")
						transmat.Scan(
							Kind,
							"./data",
							[]integrity.SiloURI{
								integrity.SiloURI("file://output.tar"),
							},
						)

						// sanity check that there's a file.
						So("./output.tar", testutil.ShouldBeFile, os.FileMode(0))

						// now exec tar, and check that it doesn't barf outright.
						// this is not well isolated from the host; consider improving that a todo.
						os.Mkdir("./untar", 0755)
						tarProc := gosh.Gosh(
							"tar",
							"-xf", "./output.tar",
							"-C", "./untar",
							gosh.NullIO,
						).RunAndReport()
						So(tarProc.GetExitCode(), ShouldEqual, 0)

						// should look roughly the same again even bounced through
						// some third-party tar implementation, one would hope.
						rescan := filefixture.Scan("./untar")
						comparisonLevel := filefixture.CompareDefaults &^ filefixture.CompareSubsecond
						So(rescan.Describe(comparisonLevel), ShouldEqual, fixture.Describe(comparisonLevel))
					})
				}
			}),
		),
	)
}
Exemple #3
0
func CheckAssemblerIsolatesSource(assemblerFn integrity.Assembler) {
	Convey("Writing to a placement should not alter the source",
		testutil.Requires(
			testutil.RequiresRoot,
			testutil.WithTmpdir(func() {
				filefixture.Alpha.Create("./material/alpha")
				assembly := assemblerFn("./assembled", []integrity.AssemblyPart{
					{TargetPath: "/", SourcePath: "./material/alpha", Writable: true},
				})
				defer assembly.Teardown()
				f, err := os.OpenFile("./assembled/newfile", os.O_CREATE, 0644)
				defer f.Close()
				So(err, ShouldBeNil)
				scan := filefixture.Scan("./material/alpha")
				So(scan.Describe(filefixture.CompareDefaults), ShouldEqual, filefixture.Alpha.Describe(filefixture.CompareDefaults))
			}),
		),
	)
}
Exemple #4
0
func assembleAndScan(assemblerFn integrity.Assembler, parts []integrity.AssemblyPart, expected filefixture.Fixture) {
	Convey("Assembly should not blow up", FailureContinues, func() {
		var assembly integrity.Assembly
		So(func() {
			assembly = assemblerFn("./assembled", parts)
		}, ShouldNotPanic)
		Reset(func() {
			if assembly != nil {
				// conditional only because we may have continued moving after an error earlier.
				assembly.Teardown()
			}
		})

		Convey("Filesystem should scan as the expected union", func() {
			scan := filefixture.Scan("./assembled")
			So(scan.Describe(filefixture.CompareDefaults), ShouldEqual, expected.Describe(filefixture.CompareDefaults))
		})
	})
}
Exemple #5
0
func CheckScanWithoutMutation(kind integrity.TransmatKind, transmatFabFn integrity.TransmatFactory) {
	Convey("SPEC: Scanning a filesystem shouldn't change it", testutil.Requires(
		testutil.RequiresRoot,
		func() {
			for _, fixture := range filefixture.All {
				transmat := transmatFabFn("./workdir")
				Convey(fmt.Sprintf("- Fixture %q", fixture.Name), func() {
					// set up fixture
					fixture.Create("./data")
					// scan it with the transmat
					transmat.Scan(kind, "./data", nil)
					// rescan it with the test system
					rescan := filefixture.Scan("./data")
					// should be unchanged
					So(rescan.Describe(filefixture.CompareDefaults), ShouldEqual, fixture.Describe(filefixture.CompareDefaults))
				})
			}
		},
	))
}
Exemple #6
0
func TestTarInputCompat(t *testing.T) {
	projPath, _ := os.Getwd()
	projPath = filepath.Dir(filepath.Dir(filepath.Dir(projPath)))

	Convey("Unpacking tars should match exec untar", t,
		testutil.Requires(testutil.RequiresRoot, testutil.WithTmpdir(func() {
			checkEquivalence := func(hash, filename string, paveBase bool) {
				transmat := New("./workdir/tar")

				// apply it; hope it doesn't blow up
				arena := transmat.Materialize(
					integrity.TransmatKind("tar"),
					integrity.CommitID(hash),
					[]integrity.SiloURI{
						integrity.SiloURI("file://" + filename),
					},
				)
				defer arena.Teardown()

				// do a native untar; since we don't have an upfront fixture
				//  for this thing, we'll compare the two as filesystems.
				// this is not well isolated from the host; consider improving that a todo.
				os.Mkdir("./untar", 0755)
				tarProc := gosh.Gosh(
					"tar",
					"-xf", filename,
					"-C", "./untar",
					gosh.NullIO,
				).RunAndReport()
				So(tarProc.GetExitCode(), ShouldEqual, 0)
				// native untar may or may not have an opinion about the base dir, depending on how it was formed.
				// but our scans do, so, if the `paveBase` flag was set to warn us that the tar was missing an "./" entry, flatten that here.
				if paveBase {
					So(fspatch.LUtimesNano("./untar", def.Epochwhen, def.Epochwhen), ShouldBeNil)
				}

				// scan and compare
				scan1 := filefixture.Scan(arena.Path())
				scan2 := filefixture.Scan("./untar")
				// boy, that's entertaining though: gnu tar does all the same stuff,
				//  except it doesn't honor our nanosecond timings.
				// also exclude bodies because they're *big*.
				comparisonLevel := filefixture.CompareDefaults &^ filefixture.CompareSubsecond &^ filefixture.CompareBody
				So(scan1.Describe(comparisonLevel), ShouldEqual, scan2.Describe(comparisonLevel))
			}

			Convey("Given a fixture tarball complete with base dir", func() {
				checkEquivalence(
					"BX0jm4jRNCg1KMbZfv4zp7ZaShx9SUXKaDrO-Xy6mWIoWOCFP5VnDHDDR3nU4PrR",
					filepath.Join(projPath, "data/fixture/tar_withBase.tgz"),
					false,
				)
			})

			Convey("Given a fixture tarball lacking base dir", func() {
				checkEquivalence(
					"ZdV3xhCGWeJmsfeHpDF4nF9stwvdskYwcepKMcOf7a2ziax1YGjQvGTJjRWFkvG1",
					filepath.Join(projPath, "data/fixture/tar_sansBase.tgz"),
					true,
				)
			})

			Convey("Given a fixture tarball containing ubuntu",
				testutil.Requires(testutil.RequiresLongRun, func() {
					checkEquivalence(
						ubuntuTarballHash,
						filepath.Join(projPath, "assets/ubuntu.tar.gz"),
						true,
					)
				}),
			)
		})),
	)

	Convey("Bouncing unusual tars should match hash", t,
		// where really all "unusual" means is "valid tar, but not from our own cannonical output".
		testutil.Requires(
			testutil.RequiresRoot,
			testutil.WithTmpdir(func() {
				checkBounce := func(hash, filename string) {
					transmat := New("./workdir/tar")

					// apply it; hope it doesn't blow up
					arena := transmat.Materialize(
						integrity.TransmatKind("tar"),
						integrity.CommitID(hash),
						[]integrity.SiloURI{
							integrity.SiloURI("file://" + filename),
						},
					)
					defer arena.Teardown()

					// scan and compare
					commitID := transmat.Scan(integrity.TransmatKind("tar"), arena.Path(), nil)
					// debug: gosh.Sh("tar", "--utc", "-xOvf", filename)
					So(commitID, ShouldEqual, integrity.CommitID(hash))

				}

				Convey("Given a fixture tarball complete with base dir", func() {
					checkBounce(
						"BX0jm4jRNCg1KMbZfv4zp7ZaShx9SUXKaDrO-Xy6mWIoWOCFP5VnDHDDR3nU4PrR",
						filepath.Join(projPath, "data/fixture/tar_withBase.tgz"),
					)
				})

				Convey("Given a fixture tarball lacking base dir", func() {
					checkBounce(
						"ZdV3xhCGWeJmsfeHpDF4nF9stwvdskYwcepKMcOf7a2ziax1YGjQvGTJjRWFkvG1",
						filepath.Join(projPath, "data/fixture/tar_sansBase.tgz"),
					)
				})

				// this won't fly until we support hardlinks; the original asset uses them.
				//	Convey("Given a fixture tarball containing ubuntu",
				//		testutil.Requires(testutil.RequiresLongRun, func() {
				//			checkBounce(
				//				ubuntuTarballHash,
				//				filepath.Join(projPath, "assets/ubuntu.tar.gz"),
				//			)
				//		}),
				//	)
			}),
		),
	)
}