Example #1
0
func TestErrorMetadata(t *testing.T) {
	var checkParseErr = func(path string, expErr string) {
		sc := scanner.Scanner{
			Position: scanner.Position{
				Filename: path,
			},
		}
		f, err := util.Open(path)
		if err != nil {
			t.Errorf("Couldn't open %s", path)
		}
		_, err = parse(*sc.Init(f))
		if err.Error() != expErr {
			t.Errorf("Expected \"%s\"\ngot \"%s\"", expErr, err)
			return
		}
	}
	var checkEvalErr = func(path string, expErr string) {
		sc := scanner.Scanner{
			Position: scanner.Position{
				Filename: path,
			},
		}
		f, err := util.Open(path)
		if err != nil {
			t.Errorf("Couldn't open %s", path)
		}
		parsed, err := parse(*sc.Init(f))
		if err != nil {
			t.Errorf("Unexpected parse error: %s", parsed)
		}

		_, _, err = eval(astRoot(parsed))
		if err.Error() != expErr {
			t.Errorf("Expected \"%s\"\ngot \"%s\"", expErr, err)
			return
		}
	}

	util.AppFs = afero.NewMemMapFs()
	util.WriteFile("paren.spec", []byte(`
// This is a comment.
(define Test "abc"`), 0644)
	checkParseErr("paren.spec", "paren.spec:3: unbalanced Parenthesis")

	util.WriteFile("undefined.spec", []byte(`
(+ 1 b)`), 0644)
	checkEvalErr("undefined.spec", "undefined.spec:2: unassigned variable: b")

	util.WriteFile("bad_type.spec", []byte(`
(define a "1")
(+ 1 a)`), 0644)
	checkEvalErr("bad_type.spec", `bad_type.spec:3: bad arithmetic argument: "1"`)

	// Test that functions which evaluate generated S-expressions still have proper
	// error messages.
	util.WriteFile("generated_sexp.spec", []byte(`(apply + (list 1 "1"))`), 0644)
	checkEvalErr("generated_sexp.spec",
		`generated_sexp.spec:1: bad arithmetic argument: "1"`)
}
Example #2
0
func TestPromptsUser(t *testing.T) {
	oldConfirm := confirm
	defer func() {
		confirm = oldConfirm
	}()

	util.AppFs = afero.NewMemMapFs()
	for _, confirmResp := range []bool{true, false} {
		confirm = func(in io.Reader, prompt string) (bool, error) {
			return confirmResp, nil
		}

		mockGetter := new(testutils.Getter)
		c := &clientMock.Client{
			ClusterReturn: []db.Cluster{
				{
					Spec: `{"old":"spec"}`,
				},
			},
		}
		mockGetter.On("Client", mock.Anything).Return(c, nil)

		util.WriteFile("test.js", []byte(""), 0644)
		runCmd := NewRunCommand()
		runCmd.clientGetter = mockGetter
		runCmd.stitch = "test.js"
		runCmd.Run()
		assert.Equal(t, confirmResp, c.DeployArg != "")
	}
}
Example #3
0
func testCheckSpec(t *testing.T) {
	initVCSFunc()
	os.Setenv("QUILT_PATH", ".")
	util.AppFs = afero.NewMemMapFs()
	util.AppFs.Mkdir("test", 777)
	util.WriteFile("test/noDownload.spec",
		[]byte(`(import "nextimport/nextimport")`), 0644)
	util.AppFs.Mkdir("nextimport", 777)
	util.WriteFile("nextimport/nextimport.spec", []byte("(define dummy 1)"), 0644)
	if err := checkSpec("test/noDownload.spec", nil, nil); err != nil {
		t.Error(err)
	}

	if len(created) != 0 {
		t.Errorf("should not have downloaded, but downloaded %s", created)
	}

	// Verify that call is made to GetSpec
	util.WriteFile("test/toDownload.spec",
		[]byte(`(import "github.com/NetSys/quilt/specs/example")`), 0644)
	expected := "unable to open import github.com/NetSys/quilt/specs/example"
	if err := checkSpec("test/toDownload.spec", nil, nil); err.Error() != expected {
		t.Errorf("expected %s \n but got %s", expected, err.Error())
	}

	if len(created) == 0 {
		t.Error("did not download dependency!")
	}

	expected = "github.com/NetSys/quilt"
	if created[0] != expected {
		t.Errorf("expected to download %s \n but got %s", expected, created[0])
	}
}
Example #4
0
func TestAutoDownload(t *testing.T) {
	util.AppFs = afero.NewMemMapFs()

	repoName := "autodownload"
	importPath := filepath.Join(repoName, "foo")
	util.WriteFile("test.js", []byte(fmt.Sprintf("require(%q);", importPath)), 0644)

	logger := newRepoLogger()
	getter := ImportGetter{
		Path:        ".",
		repoFactory: logger.newRepoFactory(nil),
	}

	expErr := "StitchError: unable to open import autodownload/foo: no loadable file"
	err := getter.checkSpec("test.js", nil, nil)
	if err == nil || err.Error() != expErr {
		t.Errorf("Wrong error, expected %q, got %v", expErr, err)
		return
	}

	assert.Equal(t, map[string][]string{
		importPath: {repoName},
	}, logger.created, "Should autodownload the repo")
	assert.Empty(t, logger.updated, "Shouldn't update any repos")
}
Example #5
0
func Test_filesystemCredentialStore_GetCredentials_SavedCredentialsAreValid_CredentialsAreReturned(t *testing.T) {

	// arrange
	fs := afero.NewMemMapFs()
	credentialFilePath := "/home/user/.dee/credentials.json"

	// create the initial file
	f1, _ := fs.Create(credentialFilePath)
	f1.WriteString(`{"Email":"*****@*****.**","Token":"123456"}`)
	f1.Close()

	credentialStore := filesystemCredentialStore{fs, credentialFilePath}

	// act
	credentials, err := credentialStore.GetCredentials()

	// assert
	if err != nil {
		t.Fail()
		t.Logf("GetCredentials returned an error: %s", err.Error())
	}

	if credentials.Email != "*****@*****.**" || credentials.Token != "123456" {
		t.Fail()
		t.Logf("GetCredentials did not return the correct credentials. Email: %q, Token: %q", credentials.Email, credentials.Token)
	}
}
Example #6
0
func TestCmdExec(t *testing.T) {
	appFs = afero.NewMemMapFs()

	outputPath := "output.log"
	log = logger{
		cmdLogger: fileLogger(outputPath),
	}

	expStdout := "standard out"
	expStderr := "standard error"
	cmd := exec.Command("sh", "-c",
		fmt.Sprintf("echo %s ; echo %s 1>&2", expStdout, expStderr))
	stdout, stderr, err := execCmd(cmd, "PREFIX")

	if err != nil {
		t.Errorf("Unexpected error: %s", err.Error())
		return
	}
	if stdout != expStdout {
		t.Errorf("Stdout didn't match: expected %s, got %s", expStdout, stdout)
	}
	if stderr != expStderr {
		t.Errorf("Stderr didn't match: expected %s, got %s", expStderr, stderr)
	}
}
Example #7
0
func TestUpdateNamespace(t *testing.T) {
	appFs = afero.NewMemMapFs()

	specPath := "/test.spec"
	err := overwrite(specPath, `require("spark");
var deployment = createDeployment({namespace: "replace"});
deployment.deploy(new Machine({}));`)
	if err != nil {
		t.Errorf("Unexpected error: %s", err.Error())
	}
	updateNamespace(specPath, "test-namespace")

	res, err := fileContents(specPath)
	exp := `require("spark");
var deployment = createDeployment({namespace: "replace"});
deployment.deploy(new Machine({}));; deployment.namespace = "test-namespace";`
	if err != nil {
		t.Errorf("Unexpected error: %s", err.Error())
		return
	}
	if res != exp {
		t.Errorf("Namespace didn't properly update, expected %s, got %s",
			exp, res)
	}
}
Example #8
0
func TestDefaultKeys(t *testing.T) {
	util.AppFs = afero.NewMemMapFs()

	// Don't pull in keys from the host OS. Setting this environment variable
	// is safe because it won't affect the parent shell.
	os.Setenv("SSH_AUTH_SOCK", "")

	dir, err := homedir.Dir()
	if err != nil {
		t.Errorf("Failed to get homedir: %q", err.Error())
		return
	}

	sshDir := filepath.Join(dir, ".ssh")
	if err := util.AppFs.MkdirAll(sshDir, 0600); err != nil {
		t.Errorf("Failed to create SSH directory: %q", err.Error())
		return
	}

	for _, key := range []string{"id_rsa", "id_dsa", "ignored"} {
		if err := writeRandomKey(filepath.Join(sshDir, key)); err != nil {
			t.Errorf("Failed to write key: %q", err.Error())
			return
		}
	}

	signers := defaultSigners()
	if len(signers) != 2 {
		t.Errorf("Expected two default signers, but got %v", signers)
	}
}
Example #9
0
func TestCompileAndRun(t *testing.T) {
	var testProgram = "/$/ {}\n"
	store := metrics.NewStore()
	lines := make(chan string)
	w := watcher.NewFakeWatcher()
	fs := afero.NewMemMapFs()
	o := LoaderOptions{store, lines, w, fs, false, false, true}
	l, err := NewLoader(o)
	if err != nil {
		t.Fatalf("couldn't create loader: %s", err)
	}
	if err := l.CompileAndRun("Test", strings.NewReader(testProgram)); err != nil {
		t.Errorf("CompileAndRun returned error: %s", err)
	}
	l.handleMu.Lock()
	if len(l.handles) < 1 {
		t.Errorf("no vm handles: %v", l.handles)
	}
	l.handleMu.Unlock()
	l.handleMu.Lock()
	c := l.handles["Test"].done
	if c == nil {
		t.Errorf("No done channel in handles: %v", l.handles)
	}
	l.handleMu.Unlock()
	close(lines)
	<-c
	{
		l.handleMu.Lock()
		defer l.handleMu.Unlock()
		if len(l.handles) != 0 {
			t.Errorf("some vm handles: %v", l.handles)
		}
	}
}
Example #10
0
func TestMain(t *testing.T) {
	util.AppFs = afero.NewMemMapFs()
	util.WriteFile("test.js", []byte(testStitch), 0644)

	exitCode := Main([]string{"test.js", "graphviz"})

	assert.Zero(t, exitCode)
	res, err := util.ReadFile("test.dot")
	assert.Nil(t, err)
	assert.True(t, isGraphEqual(expGraph, res))
}
Example #11
0
func makeTestTail(t *testing.T) (*Tailer, chan string, *watcher.FakeWatcher, afero.Fs) {
	fs := afero.NewMemMapFs()
	w := watcher.NewFakeWatcher()
	lines := make(chan string, 1)
	o := Options{lines, w, fs}
	ta, err := New(o)
	if err != nil {
		t.Fatal(err)
	}
	return ta, lines, w, fs
}
Example #12
0
func TestSyncKeysError(t *testing.T) {
	util.AppFs = afero.NewMemMapFs()

	conn := db.New()
	err := runOnce(conn)
	assert.EqualError(t, err, "no self minion")

	fs := afero.NewMemMapFs()
	util.AppFs = afero.NewReadOnlyFs(fs)
	conn.Transact(func(view db.Database) error {
		m := view.InsertMinion()
		m.Self = true
		m.AuthorizedKeys = "keys"
		view.Commit(m)
		return nil
	})
	err = runOnce(conn)
	assert.EqualError(t, err, "open /home/quilt/.ssh/authorized_keys: "+
		"file does not exist")

	fs.Create(authorizedKeysFile)
	err = runOnce(conn)
	assert.EqualError(t, err, "operation not permitted")
}
Example #13
0
func Test_filesystemCredentialStore_SaveCredentials_CredentialsAreValid_NoErrorIsReturned(t *testing.T) {

	// arrange
	fs := afero.NewMemMapFs()
	credentialFilePath := "/home/user/.dee/credentials.json"
	credentialStore := filesystemCredentialStore{fs, credentialFilePath}

	// act
	err := credentialStore.SaveCredentials(deens.APICredentials{"*****@*****.**", "123456"})

	// assert
	if err != nil {
		t.Fail()
		t.Logf("SaveCredentials should not return an error (%q)", err.Error())
	}
}
Example #14
0
func Test_filesystemCredentialStore_WithoutSourceFile_DeleteCredentials_credentialsNotFoundErrorIsReturned(t *testing.T) {

	// arrange
	fs := afero.NewMemMapFs()
	credentialFilePath := "/home/user/.dee/credentials.json"
	credentialStore := filesystemCredentialStore{fs, credentialFilePath}

	// act
	err := credentialStore.DeleteCredentials()

	// assert
	if !isNoCredentialsError(err) {
		t.Fail()
		t.Logf("DeleteCredentials should return a noCredentials-error if the credential store has no source file.")
	}
}
Example #15
0
func TestSyncKeys(t *testing.T) {
	tests := []keyTest{
		{
			dbKeys:     "key1\nkey2",
			expKeyFile: "key1\nkey2",
		},
		{
			dbKeys:     "key1\nkey2",
			keyFile:    "key1",
			expKeyFile: "key1\nkey2",
		},
		{
			dbKeys:     "key1\nkey2",
			keyFile:    "key1\nkey2",
			expKeyFile: "key1\nkey2",
		},
		{
			keyFile:    "key1\nkey2",
			expKeyFile: "",
		},
	}
	for _, test := range tests {
		util.AppFs = afero.NewMemMapFs()
		if test.keyFile != "" {
			err := util.WriteFile(
				authorizedKeysFile, []byte(test.keyFile), 0644)
			assert.NoError(t, err)
		}

		conn := db.New()
		conn.Transact(func(view db.Database) error {
			m := view.InsertMinion()
			m.Self = true
			m.AuthorizedKeys = test.dbKeys
			view.Commit(m)
			return nil
		})

		err := runOnce(conn)
		assert.NoError(t, err)

		actual, err := util.ReadFile(authorizedKeysFile)
		assert.NoError(t, err)
		assert.Equal(t, test.expKeyFile, actual)
	}
}
Example #16
0
func Test_filesystemCredentialStore_WithoutFilePath_SaveCredentials_ErrorIsReturned(t *testing.T) {

	// arrange
	filesystem := afero.NewMemMapFs()
	credentialStore := filesystemCredentialStore{
		fs: filesystem,
	}

	// act
	err := credentialStore.SaveCredentials(deens.APICredentials{"*****@*****.**", "123456"})

	// assert
	if err == nil {
		t.Fail()
		t.Logf("SaveCredentials should return an error if the credential store file path configured.")
	}
}
Example #17
0
func Test_filesystemCredentialStore_SaveCredentials_CredentialsAreValid_JSONIsWrittenToFile(t *testing.T) {

	// arrange
	fs := afero.NewMemMapFs()
	credentialFilePath := "/home/user/.dee/credentials.json"
	credentialStore := filesystemCredentialStore{fs, credentialFilePath}

	// act
	credentialStore.SaveCredentials(deens.APICredentials{"*****@*****.**", "123456"})

	// assert
	expectedResult := `{"Email":"*****@*****.**","Token":"123456"}`
	content, _ := afero.ReadFile(fs, credentialFilePath)
	if string(content) != expectedResult {
		t.Fail()
		t.Logf("SaveCredentials should have written the credentials as JSON to %q. Expected: %q, Actual: %q", credentialFilePath, expectedResult, string(content))
	}
}
Example #18
0
func TestImportExists(t *testing.T) {
	util.AppFs = afero.NewMemMapFs()

	util.WriteFile("test.js", []byte(`require("existingImport")`), 0644)
	util.WriteFile("existingImport.js", []byte(""), 0644)

	logger := newRepoLogger()
	getter := ImportGetter{
		Path:        ".",
		repoFactory: logger.newRepoFactory(nil),
	}
	if err := getter.checkSpec("test.js", nil, nil); err != nil {
		t.Error(err)
		return
	}

	assert.Empty(t, logger.created, "Shouldn't create any repos")
	assert.Empty(t, logger.updated, "Shouldn't update any repos")
}
Example #19
0
func TestGetWalk(t *testing.T) {
	util.AppFs = afero.NewMemMapFs()

	quiltPath := "getspecs"

	repoOne := "repoOne"
	importOne := filepath.Join(repoOne, "file")

	repoTwo := "anotherRepo"
	fileTwo := "importTwo"
	importTwo := filepath.Join(repoTwo, fileTwo)

	logger := newRepoLogger()
	getter := ImportGetter{
		Path: quiltPath,
		repoFactory: logger.newRepoFactory(map[string][]file{
			importOne: {
				{
					name:     "foo.js",
					contents: fmt.Sprintf("require(%q);", importTwo),
				},
			},
			importTwo: {
				{
					name: fmt.Sprintf("%s.js", fileTwo),
				},
			},
		}),
	}

	if err := getter.Get(importOne); err != nil {
		t.Error(err)
		return
	}

	assert.Equal(t, map[string][]string{
		importOne: {filepath.Join(quiltPath, repoOne)},
		importTwo: {filepath.Join(quiltPath, repoTwo)},
	}, logger.created, "Should autodownload the imported repo")
	assert.Empty(t, logger.updated, "Shouldn't update any repos")
}
Example #20
0
// getFileWithContent returns an afero.File with the given name and content.
func getFileWithContent(name, content string) (afero.File, error) {
	fs := afero.NewMemMapFs()
	fs.MkdirAll(path.Base(name), 0755)
	f, createFileError := fs.OpenFile(name, os.O_CREATE|os.O_RDWR, 0744)
	if createFileError != nil {
		return nil, createFileError
	}

	_, writeError := f.WriteString(content)
	if writeError != nil {
		return nil, writeError
	}
	f.Close()

	f2, openFileError := fs.OpenFile(name, os.O_CREATE|os.O_RDWR, 0744)
	if openFileError != nil {
		return nil, openFileError
	}

	return f2, nil
}
Example #21
0
func Test_filesystemCredentialStore_SourceFileExists_DeleteCredentials_NoErrorIsReturned(t *testing.T) {

	// arrange
	fs := afero.NewMemMapFs()
	credentialFilePath := "/home/user/.dee/credentials.json"

	// create the initial file
	f1, _ := fs.Create(credentialFilePath)
	f1.WriteString("Some content")

	credentialStore := filesystemCredentialStore{fs, credentialFilePath}

	// act
	err := credentialStore.DeleteCredentials()

	// assert
	if err != nil {
		t.Fail()
		t.Logf("DeleteCredentials should not return an error if the credential file exists and was successfully deleted.")
	}
}
Example #22
0
func Test_filesystemCredentialStore_GetCredentials_SavedCredentialsAreEmpty_ErrorIsReturned(t *testing.T) {

	// arrange
	fs := afero.NewMemMapFs()
	credentialFilePath := "/home/user/.dee/credentials.json"

	// create the initial file
	f1, _ := fs.Create(credentialFilePath)
	f1.WriteString(``)
	f1.Close()

	credentialStore := filesystemCredentialStore{fs, credentialFilePath}

	// act
	_, err := credentialStore.GetCredentials()

	// assert
	if err == nil {
		t.Fail()
		t.Logf("GetCredentials should return an error if the given file is empty.")
	}
}
Example #23
0
func Test_filesystemCredentialStore_GetCredentials_JSONIsInvalid_ErrorIsReturned(t *testing.T) {

	// arrange
	fs := afero.NewMemMapFs()
	credentialFilePath := "/home/user/.dee/credentials.json"

	// create the initial file
	f1, _ := fs.Create(credentialFilePath)
	f1.WriteString("dsakldjasl ---")
	f1.Close()

	credentialStore := filesystemCredentialStore{fs, credentialFilePath}

	// act
	_, err := credentialStore.GetCredentials()

	// assert
	if err == nil {
		t.Fail()
		t.Logf("GetCredentials should return an error if the given file content is invalid.")
	}
}
Example #24
0
func TestGetCreate(t *testing.T) {
	util.AppFs = afero.NewMemMapFs()

	quiltPath := "./getspecs"
	repoName := "github.com/NetSys/quilt"
	importPath := filepath.Join(repoName, "foo")

	logger := newRepoLogger()
	getter := ImportGetter{
		Path:        quiltPath,
		repoFactory: logger.newRepoFactory(nil),
	}

	if err := getter.Get(importPath); err != nil {
		t.Error(err)
		return
	}

	assert.Equal(t, map[string][]string{
		importPath: {filepath.Join(quiltPath, repoName)},
	}, logger.created, "Should download the repo")
	assert.Empty(t, logger.updated, "Shouldn't update any repos")
}
Example #25
0
func Test_filesystemCredentialStore_SourceFileExists_DeleteCredentials_FileIsDeleted(t *testing.T) {

	// arrange
	fs := afero.NewMemMapFs()
	credentialFilePath := "/home/user/.dee/credentials.json"

	// create the initial file
	f1, _ := fs.Create(credentialFilePath)
	f1.WriteString("Some content")

	credentialStore := filesystemCredentialStore{fs, credentialFilePath}

	// act
	credentialStore.DeleteCredentials()

	// assert
	fileInfo, _ := fs.Stat(credentialFilePath)
	fileExists := fileInfo != nil
	if fileExists {
		t.Fail()
		t.Logf("The file %q should be deleted after DeleteCredentials is executed.", credentialFilePath)
	}
}
Example #26
0
// Integration test.
func Test_loginAction_ValidArguments_CredentialFileIsCreated(t *testing.T) {
	// arrange
	filesystem := afero.NewMemMapFs()
	credentialStore := newFilesystemCredentialStore(filesystem, "/home/testuser/.dee/credentials.json")
	arguments := []string{
		"-email",
		"*****@*****.**",
		"-apitoken",
		"123456",
	}

	login := loginAction{credentialStore}

	// act
	login.Execute(arguments)

	// assert
	fileInfo, err := filesystem.Stat("/home/testuser/.dee/credentials.json")
	if fileInfo == nil || err != nil {
		t.Fail()
		t.Logf("login.Execute(%q) create the credential file and should not return an error: %s", arguments, err.Error())
	}
}
Example #27
0
// Due to limitations with git and afero, GetSpec will error at resolveSpecImports.
// Instead, resolveSpecImports is covered above.
func TestGetSpec(t *testing.T) {
	initVCSFunc()
	util.AppFs = afero.NewMemMapFs()
	util.AppFs.Mkdir("getspecs", 777)
	os.Setenv("QUILT_PATH", "./getspecs")
	importPath := "github.com/NetSys/quilt"

	// Clone
	if _, err := getSpec(importPath); err != nil {
		t.Error(err)
	}

	if len(created) == 0 {
		t.Errorf("did not download dependency %s", importPath)
	}

	expected := "getspecs/github.com/NetSys/quilt"
	if created[0] != expected {
		t.Errorf("expected to download %s \n but got %s", expected, created[0])
	}
	fmt.Println(created)
	util.AppFs.Mkdir("getspecs/github.com/NetSys/quilt", 777)

	// Update
	if _, err := getSpec(importPath); err != nil {
		t.Error(err)
	}

	if len(updated) == 0 {
		t.Errorf("did not update dependency %s", importPath)
	}

	expected = "getspecs/github.com/NetSys/quilt"
	if updated[0] != expected {
		t.Errorf("expected to update %s \n but got %s", expected, updated[0])
	}
}
Example #28
0
func Test_filesystemCredentialStore_SaveCredentials_FileExists_FileIsOverridden(t *testing.T) {

	// arrange
	fs := afero.NewMemMapFs()
	credentialFilePath := "/home/user/.dee/credentials.json"

	// create the initial file
	f1, _ := fs.Create(credentialFilePath)
	f1.WriteString(`{"Email":"*****@*****.**","Token":"543"}`)
	f1.Close()

	credentialStore := filesystemCredentialStore{fs, credentialFilePath}

	// act
	credentialStore.SaveCredentials(deens.APICredentials{"*****@*****.**", "123456"})

	// assert
	expectedResult := `{"Email":"*****@*****.**","Token":"123456"}`
	content, _ := afero.ReadFile(fs, credentialFilePath)
	if string(content) != expectedResult {
		t.Fail()
		t.Logf("SaveCredentials should have written the credentials as JSON to %q. Expected: %q, Actual: %q", credentialFilePath, expectedResult, string(content))
	}
}
Example #29
0
func TestNewLoader(t *testing.T) {
	w := watcher.NewFakeWatcher()
	store := metrics.NewStore()
	inLines := make(chan string)
	fs := afero.NewMemMapFs()
	o := LoaderOptions{store, inLines, w, fs, false, false, true}
	l, err := NewLoader(o)
	if err != nil {
		t.Fatalf("couldn't create loader: %s", err)
	}
	done := make(chan struct{})
	outLines := make(chan string)
	handle := &vmHandle{outLines, done}
	l.handleMu.Lock()
	l.handles["test"] = handle
	l.handleMu.Unlock()
	go func() {
		for _ = range outLines {
		}
		close(done)
	}()
	close(inLines)
	<-outLines
}
Example #30
0
func TestProcessEvents(t *testing.T) {
	for _, tt := range testProcessEvents {
		w := watcher.NewFakeWatcher()
		w.Add(".")
		store := metrics.NewStore()
		lines := make(chan string)
		fs := afero.NewMemMapFs()
		o := LoaderOptions{store, lines, w, fs, false, false, true}
		l, err := NewLoader(o)
		if err != nil {
			t.Fatalf("couldn't create loader: %s", err)
		}
		for i := range tt.events {
			e := tt.events[i]
			switch e := e.(type) {
			case watcher.CreateEvent:
				if e.Pathname != "notexist.mtail" {
					_, err := fs.Create(e.Pathname)
					if err != nil {
						t.Fatalf("Create failed for %s: %s", e.Pathname, err)
					}
				}
				w.InjectCreate(e.Pathname)
			case watcher.DeleteEvent:
				err := fs.Remove(e.Pathname)
				if err != nil {
					t.Fatalf("Remove failed for %s: %s", e.Pathname, err)
				}
				w.InjectDelete(e.Pathname)
			case watcher.UpdateEvent:
				if e.Pathname != "notexist.mtail" {
					f, err := fs.Create(e.Pathname)
					if err != nil {
						t.Fatalf("Couldn't open file %s for test: %s", e.Pathname, err)
					}
					_, err = f.WriteString(testProgram)
					if err != nil {
						t.Fatalf("Couldn't write file contents: %s", err)
					}
					if err = f.Close(); err != nil {
						t.Fatalf("Close failed: %s", err)
					}
				}
				w.InjectUpdate(e.Pathname)
			}
		}
		w.Close()
		<-l.watcherDone
		l.handleMu.RLock()
		var programs []string
		for program := range l.handles {
			programs = append(programs, program)
		}
		l.handleMu.RUnlock()
		l.handleMu.RLock()
		if diff := pretty.Compare(tt.expectedPrograms, programs); len(diff) > 0 {
			t.Errorf("%q: loaded programs don't match.\nl.handles: %+#v\n%s", tt.name, l.handles, diff)
		}
		l.handleMu.RUnlock()
		close(lines)

	}
}