Exemplo n.º 1
0
func TestCopySuccessful(test *testing.T) {
	// set-up

	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	fileA, err := store.AddFile("/tmp/a", fingerprint.Fingerprint("abc"), time.Now(), 123, true)
	if err != nil {
		test.Fatal(err)
	}

	fileAB, err := store.AddFile("/tmp/a/b", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	sourceTag, err := store.AddTag("source")
	if err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileA.Id, sourceTag.Id); err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileAB.Id, sourceTag.Id); err != nil {
		test.Fatal(err)
	}

	command := CopyCommand{false}

	// test

	if err := command.Exec(cli.Options{}, []string{"source", "dest"}); err != nil {
		test.Fatal(err)
	}

	// validate

	destTag, err := store.TagByName("dest")
	if err != nil {
		test.Fatal(err)
	}
	if destTag == nil {
		test.Fatal("Destination tag does not exist.")
	}

	expectTags(test, store, fileA, sourceTag, destTag)
	expectTags(test, store, fileAB, sourceTag, destTag)
}
Exemplo n.º 2
0
func TestDupesMultiple(test *testing.T) {
	// set-up
	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	outPath, errPath, err := configureOutput()
	if err != nil {
		test.Fatal(err)
	}
	defer os.Remove(outPath)
	defer os.Remove(errPath)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	_, err = store.AddFile("/tmp/a", fingerprint.Fingerprint("abc"), time.Now(), 123, true)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/a/b", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	_, err = store.AddFile("/tmp/b", fingerprint.Fingerprint("def"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/e/f", fingerprint.Fingerprint("def"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/a/d", fingerprint.Fingerprint("def"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	command := DupesCommand{false}

	// test

	if err := command.Exec(cli.Options{}, []string{}); err != nil {
		test.Fatal(err)
	}

	// validate

	log.Outfile.Seek(0, 0)

	bytes, err := ioutil.ReadAll(log.Outfile)
	compareOutput(test, "Set of 2 duplicates:\n  /tmp/a\n  /tmp/a/b\n\nSet of 3 duplicates:\n  /tmp/a/d\n  /tmp/b\n  /tmp/e/f\n", string(bytes))
}
Exemplo n.º 3
0
func TestFilesAll(test *testing.T) {
	// set-up

	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	outPath, errPath, err := configureOutput()
	if err != nil {
		test.Fatal(err)
	}
	defer os.Remove(outPath)
	defer os.Remove(errPath)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	_, err = store.AddFile("/tmp/d", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	_, err = store.AddFile("/tmp/b/a", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	_, err = store.AddFile("/tmp/b", fingerprint.Fingerprint("abc"), time.Now(), 123, true)
	if err != nil {
		test.Fatal(err)
	}

	command := FilesCommand{}

	// test

	if err := command.Exec(cli.Options{cli.Option{"-a", "--all", "", false, ""}}, []string{}); err != nil {
		test.Fatal(err)
	}

	// validate

	log.Outfile.Seek(0, 0)

	bytes, err := ioutil.ReadAll(log.Outfile)
	compareOutput(test, "/tmp/b\n/tmp/b/a\n/tmp/d\n", string(bytes))
}
Exemplo n.º 4
0
func TestTagsForSingleFile(test *testing.T) {
	// set-up

	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	outPath, errPath, err := configureOutput()
	if err != nil {
		test.Fatal(err)
	}
	defer os.Remove(outPath)
	defer os.Remove(errPath)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	file, err := store.AddFile("/tmp/tmsu/a", fingerprint.Fingerprint("123"), time.Now(), 0, false)
	if err != nil {
		test.Fatal(err)
	}

	appleTag, err := store.AddTag("apple")
	if err != nil {
		test.Fatal(err)
	}

	bananaTag, err := store.AddTag("banana")
	if err != nil {
		test.Fatal(err)
	}

	_, err = store.AddFileTag(file.Id, appleTag.Id)
	if err != nil {
		test.Fatal(err)
	}

	_, err = store.AddFileTag(file.Id, bananaTag.Id)
	if err != nil {
		test.Fatal(err)
	}

	tagsCommand := TagsCommand{false, false}

	// test

	if err := tagsCommand.Exec(cli.Options{}, []string{"/tmp/tmsu/a"}); err != nil {
		test.Fatal(err)
	}

	// verify

	log.Outfile.Seek(0, 0)

	bytes, err := ioutil.ReadAll(log.Outfile)
	compareOutput(test, "apple\nbanana\n", string(bytes))
}
Exemplo n.º 5
0
func (command DupesCommand) findDuplicatesOf(paths []string) error {
	store, err := storage.Open()
	if err != nil {
		return fmt.Errorf("could not open storage: %v", err)
	}
	defer store.Close()

	first := true
	for _, path := range paths {
		if command.verbose {
			log.Infof("%v: identifying duplicate files.\n", path)
		}

		fp, err := fingerprint.Create(path)
		if err != nil {
			return fmt.Errorf("%v: could not create fingerprint: %v", path, err)
		}

		if fp == fingerprint.Fingerprint("") {
			return nil
		}

		files, err := store.FilesByFingerprint(fp)
		if err != nil {
			return fmt.Errorf("%v: could not retrieve files matching fingerprint '%v': %v", path, fp, err)
		}

		absPath, err := filepath.Abs(path)
		if err != nil {
			return fmt.Errorf("%v: could not determine absolute path: %v", path, err)
		}

		// filter out the file we're searching on
		dupes := files.Where(func(file *database.File) bool { return file.Path() != absPath })

		if len(paths) > 1 && len(dupes) > 0 {
			if first {
				first = false
			} else {
				log.Print()
			}

			log.Printf("%v duplicates of %v:", len(dupes), path)

			for _, dupe := range dupes {
				relPath := _path.Rel(dupe.Path())
				log.Printf("  %v", relPath)
			}
		} else {
			for _, dupe := range dupes {
				relPath := _path.Rel(dupe.Path())
				log.Print(relPath)
			}
		}
	}

	return nil
}
Exemplo n.º 6
0
func TestSingleUntag(test *testing.T) {
	// set-up

	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	file, err := store.AddFile("/tmp/tmsu/a", fingerprint.Fingerprint("abc123"), time.Now(), 0, false)
	if err != nil {
		test.Fatal(err)
	}

	appleTag, err := store.AddTag("apple")
	if err != nil {
		test.Fatal(err)
	}

	bananaTag, err := store.AddTag("banana")
	if err != nil {
		test.Fatal(err)
	}

	_, err = store.AddFileTag(file.Id, appleTag.Id)
	if err != nil {
		test.Fatal(err)
	}

	_, err = store.AddFileTag(file.Id, bananaTag.Id)
	if err != nil {
		test.Fatal(err)
	}

	untagCommand := UntagCommand{false, false}

	// test

	if err := untagCommand.Exec(cli.Options{}, []string{"/tmp/tmsu/a", "apple"}); err != nil {
		test.Fatal(err)
	}

	// validate

	fileTags, err := store.FileTags()
	if err != nil {
		test.Fatal(err)
	}
	if len(fileTags) != 1 {
		test.Fatalf("Expected one file-tag but are %v", len(fileTags))
	}
	if fileTags[0].TagId != bananaTag.Id {
		test.Fatalf("Incorrect tag was applied.")
	}
}
Exemplo n.º 7
0
// Retrieves the sets of duplicate files within the database.
func (db *Database) DuplicateFiles() ([]Files, error) {
	sql := `SELECT id, directory, name, fingerprint, mod_time, size, is_dir
            FROM file
            WHERE fingerprint IN (
                SELECT fingerprint
                FROM file
                WHERE fingerprint != ''
                GROUP BY fingerprint
                HAVING count(1) > 1
            )
            ORDER BY fingerprint, directory || '/' || name`

	rows, err := db.connection.Query(sql)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	fileSets := make([]Files, 0, 10)
	var fileSet Files
	var previousFingerprint fingerprint.Fingerprint

	for rows.Next() {
		if rows.Err() != nil {
			return nil, err
		}

		var fileId uint
		var directory, name, fp string
		var modTime time.Time
		var size int64
		var isDir bool
		err = rows.Scan(&fileId, &directory, &name, &fp, &modTime, &size, &isDir)
		if err != nil {
			return nil, err
		}

		fingerprint := fingerprint.Fingerprint(fp)

		if fingerprint != previousFingerprint {
			if fileSet != nil {
				fileSets = append(fileSets, fileSet)
			}
			fileSet = make(Files, 0, 10)
			previousFingerprint = fingerprint
		}

		fileSet = append(fileSet, &File{fileId, directory, name, fingerprint, modTime, size, isDir})
	}

	// ensure last file set is added
	if len(fileSet) > 0 {
		fileSets = append(fileSets, fileSet)
	}

	return fileSets, nil
}
Exemplo n.º 8
0
func readFile(rows *sql.Rows) (*File, error) {
	if !rows.Next() {
		return nil, nil
	}
	if rows.Err() != nil {
		return nil, rows.Err()
	}

	var fileId uint
	var directory, name, fp string
	var modTime time.Time
	var size int64
	var isDir bool
	err := rows.Scan(&fileId, &directory, &name, &fp, &modTime, &size, &isDir)
	if err != nil {
		return nil, err
	}

	return &File{fileId, directory, name, fingerprint.Fingerprint(fp), modTime, size, isDir}, nil
}
Exemplo n.º 9
0
func TestFilesSingleTag(test *testing.T) {
	// set-up

	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	outPath, errPath, err := configureOutput()
	if err != nil {
		test.Fatal(err)
	}
	defer os.Remove(outPath)
	defer os.Remove(errPath)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	fileD, err := store.AddFile("/tmp/d", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	fileBA, err := store.AddFile("/tmp/b/a", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	fileB, err := store.AddFile("/tmp/b", fingerprint.Fingerprint("abc"), time.Now(), 123, true)
	if err != nil {
		test.Fatal(err)
	}

	tagD, err := store.AddTag("d")
	if err != nil {
		test.Fatal(err)
	}

	tagB, err := store.AddTag("b")
	if err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileD.Id, tagD.Id); err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileB.Id, tagB.Id); err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileBA.Id, tagB.Id); err != nil {
		test.Fatal(err)
	}

	command := FilesCommand{}

	// test

	if err := command.Exec(cli.Options{}, []string{"b"}); err != nil {
		test.Fatal(err)
	}

	// validate

	log.Outfile.Seek(0, 0)

	bytes, err := ioutil.ReadAll(log.Outfile)
	compareOutput(test, "/tmp/b\n/tmp/b/a\n", string(bytes))
}
Exemplo n.º 10
0
func TestDupesNoneUntaggedFile(test *testing.T) {
	// set-up
	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	outPath, errPath, err := configureOutput()
	if err != nil {
		test.Fatal(err)
	}
	defer os.Remove(outPath)
	defer os.Remove(errPath)

	path := filepath.Join(os.TempDir(), "tmsu-file")
	_, err = os.Create(path)
	if err != nil {
		test.Fatal(err)
	}
	defer os.Remove(path)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	_, err = store.AddFile("/tmp/a", fingerprint.Fingerprint("abc"), time.Now(), 123, true)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/a/b", fingerprint.Fingerprint("def"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/b", fingerprint.Fingerprint("ghi"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/e/f", fingerprint.Fingerprint("klm"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/a/d", fingerprint.Fingerprint("nop"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	command := DupesCommand{false}

	// test

	if err := command.Exec(cli.Options{}, []string{path}); err != nil {
		test.Fatal(err)
	}

	// validate

	log.Outfile.Seek(0, 0)

	bytes, err := ioutil.ReadAll(log.Outfile)
	compareOutput(test, "", string(bytes))
}
Exemplo n.º 11
0
func TestDupesMultipleUntaggedFile(test *testing.T) {
	// set-up
	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	outPath, errPath, err := configureOutput()
	if err != nil {
		test.Fatal(err)
	}
	defer os.Remove(outPath)
	defer os.Remove(errPath)

	path := filepath.Join(os.TempDir(), "tmsu-file")
	_, err = os.Create(path)
	if err != nil {
		test.Fatal(err)
	}
	defer os.Remove(path)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	_, err = store.AddFile("/tmp/a", fingerprint.Fingerprint("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"), time.Now(), 123, true)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/a/b", fingerprint.Fingerprint("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/b", fingerprint.Fingerprint("xxx"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/e/f", fingerprint.Fingerprint("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}
	_, err = store.AddFile("/tmp/a/d", fingerprint.Fingerprint("xxx"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	command := DupesCommand{false}

	// test

	if err := command.Exec(cli.Options{}, []string{path}); err != nil {
		test.Fatal(err)
	}

	// validate

	log.Outfile.Seek(0, 0)

	bytes, err := ioutil.ReadAll(log.Outfile)
	compareOutput(test, "/tmp/a\n/tmp/a/b\n/tmp/e/f\n", string(bytes))
}
Exemplo n.º 12
0
func TestUntagAll(test *testing.T) {
	// set-up

	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	fileA, err := store.AddFile("/tmp/tmsu/a", fingerprint.Fingerprint("abc123"), time.Now(), 0, false)
	if err != nil {
		test.Fatal(err)
	}

	fileB, err := store.AddFile("/tmp/tmsu/b", fingerprint.Fingerprint("abc123"), time.Now(), 0, false)
	if err != nil {
		test.Fatal(err)
	}

	appleTag, err := store.AddTag("apple")
	if err != nil {
		test.Fatal(err)
	}

	_, err = store.AddFileTag(fileA.Id, appleTag.Id)
	if err != nil {
		test.Fatal(err)
	}

	_, err = store.AddFileTag(fileB.Id, appleTag.Id)
	if err != nil {
		test.Fatal(err)
	}

	untagCommand := UntagCommand{false, false}

	// test

	if err := untagCommand.Exec(cli.Options{cli.Option{"--all", "-a", "", false, ""}}, []string{"/tmp/tmsu/a", "/tmp/tmsu/b"}); err != nil {
		test.Fatal(err)
	}

	// validate

	fileTags, err := store.FileTags()
	if err != nil {
		test.Fatal(err)
	}
	if len(fileTags) != 0 {
		test.Fatalf("Expected no file-tags but are %v", len(fileTags))
	}

	files, err := store.Files()
	if err != nil {
		test.Fatal(err)
	}
	if len(files) != 0 {
		test.Fatalf("Expected no files but are %v", len(files))
	}
}
Exemplo n.º 13
0
func TestDeleteSuccessful(test *testing.T) {
	// set-up

	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	fileD, err := store.AddFile("/tmp/d", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	fileF, err := store.AddFile("/tmp/f", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	fileB, err := store.AddFile("/tmp/b", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	tagDeathrow, err := store.AddTag("deathrow")
	if err != nil {
		test.Fatal(err)
	}

	tagFreeman, err := store.AddTag("freeman")
	if err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileD.Id, tagDeathrow.Id); err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileF.Id, tagFreeman.Id); err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileB.Id, tagDeathrow.Id); err != nil {
		test.Fatal(err)
	}
	if _, err := store.AddFileTag(fileB.Id, tagFreeman.Id); err != nil {
		test.Fatal(err)
	}

	command := DeleteCommand{false}

	// test

	if err := command.Exec(cli.Options{}, []string{"deathrow"}); err != nil {
		test.Fatal(err)
	}

	// validate

	tagDeathrow, err = store.TagByName("deathrow")
	if err != nil {
		test.Fatal(err)
	}
	if tagDeathrow != nil {
		test.Fatal("Deleted tag still exists.")
	}

	fileTagsD, err := store.FileTagsByFileId(fileD.Id)
	if err != nil {
		test.Fatal(err)
	}
	if len(fileTagsD) != 0 {
		test.Fatal("Expected no file-tags for file 'd'.")
	}

	fileTagsF, err := store.FileTagsByFileId(fileF.Id)
	if err != nil {
		test.Fatal(err)
	}
	if len(fileTagsF) != 1 {
		test.Fatal("Expected one file-tag for file 'f'.")
	}
	if fileTagsF[0].TagId != tagFreeman.Id {
		test.Fatal("Expected file-tag for tag 'freeman'.")
	}

	fileTagsB, err := store.FileTagsByFileId(fileB.Id)
	if err != nil {
		test.Fatal(err)
	}
	if len(fileTagsB) != 1 {
		test.Fatal("Expected one file-tag for file 'b'.")
	}
	if fileTagsB[0].TagId != tagFreeman.Id {
		test.Fatal("Expected file-tag for tag 'freeman'.")
	}
}
Exemplo n.º 14
0
func TestMergeSingleTag(test *testing.T) {
	// set-up

	databasePath := configureDatabase()
	defer os.Remove(databasePath)

	store, err := storage.Open()
	if err != nil {
		test.Fatal(err)
	}
	defer store.Close()

	fileA, err := store.AddFile("/tmp/a", fingerprint.Fingerprint("abc"), time.Now(), 123, true)
	if err != nil {
		test.Fatal(err)
	}

	fileA1, err := store.AddFile("/tmp/a/1", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	fileB, err := store.AddFile("/tmp/b", fingerprint.Fingerprint("abc"), time.Now(), 123, true)
	if err != nil {
		test.Fatal(err)
	}

	fileB1, err := store.AddFile("/tmp/b/1", fingerprint.Fingerprint("abc"), time.Now(), 123, false)
	if err != nil {
		test.Fatal(err)
	}

	tagA, err := store.AddTag("a")
	if err != nil {
		test.Fatal(err)
	}

	tagB, err := store.AddTag("b")
	if err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileA.Id, tagA.Id); err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileA1.Id, tagA.Id); err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileB.Id, tagB.Id); err != nil {
		test.Fatal(err)
	}

	if _, err := store.AddFileTag(fileB1.Id, tagB.Id); err != nil {
		test.Fatal(err)
	}

	command := MergeCommand{false}

	// test

	if err := command.Exec(cli.Options{}, []string{"a", "b"}); err != nil {
		test.Fatal(err)
	}

	// validate

	tagA, err = store.TagByName("a")
	if err != nil {
		test.Fatal(err)
	}
	if tagA != nil {
		test.Fatal("Tag 'a' still exists.")
	}

	tagB, err = store.TagByName("b")
	if err != nil {
		test.Fatal(err)
	}
	if tagB == nil {
		test.Fatal("Tag 'b' does not exist.")
	}

	expectTags(test, store, fileA, tagB)
	expectTags(test, store, fileA1, tagB)
	expectTags(test, store, fileB, tagB)
	expectTags(test, store, fileB1, tagB)
}