Skip to content
Snippets Groups Projects
store_test.go 12.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Christian Pointner's avatar
    Christian Pointner committed
    //
    //  tank
    //
    //  Import and Playlist Daemon for autoradio project
    //
    //
    
    //  Copyright (C) 2017-2018 Christian Pointner <equinox@helsinki.at>
    
    Christian Pointner's avatar
    Christian Pointner committed
    //
    //  This file is part of tank.
    //
    //  tank is free software: you can redistribute it and/or modify
    //  it under the terms of the GNU General Public License as published by
    //  the Free Software Foundation, either version 3 of the License, or
    //  any later version.
    //
    //  tank is distributed in the hope that it will be useful,
    //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    //  GNU General Public License for more details.
    //
    //  You should have received a copy of the GNU General Public License
    //  along with tank. If not, see <http://www.gnu.org/licenses/>.
    //
    
    package store
    
    import (
    	"fmt"
    	"os"
    	"os/user"
    	"testing"
    
    
    	"github.com/jinzhu/gorm"
    
    	testBasePath     = "run/aura-tank_testing"
    	testDBType       = "mysql"
    	testDBConnection = "tank:aura@tcp(127.0.0.1:3306)/tank?charset=utf8&parseTime=True&loc=Local"
    	// testDBType       = "postgres"
    	// testDBConnection = "host=127.0.0.1 port=5432 user=tank dbname=tank password=aura sslmode=disable"
    	testGroup1 = "test1"
    	testGroup2 = "test2"
    	testUser1  = "user1"
    	testUser2  = "user2"
    
    Christian Pointner's avatar
    Christian Pointner committed
    func stringInSlice(slice []string, search string) bool {
    	for _, element := range slice {
    		if element == search {
    			return true
    		}
    	}
    	return false
    }
    
    
    Christian Pointner's avatar
    Christian Pointner committed
    func TestMain(m *testing.M) {
    	u, err := user.Current()
    	if err != nil {
    		os.Exit(-1)
    	}
    
    	testBasePath = fmt.Sprintf("/run/user/%s/aura-tank_testing", u.Uid)
    
    	//	testDBConnection = filepath.Join(testBasePath, ".db.sqlite")
    
    Christian Pointner's avatar
    Christian Pointner committed
    	os.Exit(m.Run())
    }
    
    //
    // Testing
    //
    
    
    func TestOpen(t *testing.T) {
    	// base-path is non-existing directory
    	cfg := &Config{}
    	cfg.BasePath = "/nonexistend/"
    	cfg.DB.Type = testDBType
    	cfg.DB.Connection = testDBConnection
    	if _, err := NewStore(cfg); err == nil {
    		t.Fatalf("opening store in nonexisting directory should throw an error")
    	}
    	cfg.BasePath = testBasePath
    
    	if err := os.MkdirAll(testBasePath, 0700); err != nil {
    		t.Fatalf("unexpected error: %v", err)
    	}
    
    	/// exisiting but non-database file (only possible with sqlite...)
    
    	// if f, err := os.Create(testDBConnection); err != nil {
    	// 	t.Fatalf("unexpected error: %v", err)
    	// } else {
    	// 	io.WriteString(f, "this is not a sqlite db.")
    	// 	f.Close()
    	// }
    	// if _, err := NewStore(cfg); err == nil {
    	// 	t.Fatalf("opening store using a invalid database should throw an error")
    	// }
    
    	/// create new db and reopen it
    	// os.Remove(testDBConnection)
    
    	store, err := NewStore(cfg)
    	if err != nil {
    		t.Fatalf("creating new store failed: %v", err)
    	}
    	store.Close()
    
    	store, err = NewStore(cfg)
    	if err != nil {
    		t.Fatalf("re-opening existing store failed: %v", err)
    	}
    	store.Close()
    }
    
    func TestMigrations(t *testing.T) {
    	cfg := &Config{}
    	cfg.BasePath = testBasePath
    	cfg.DB.Type = testDBType
    	cfg.DB.Connection = testDBConnection
    
    	// os.Remove(testDBConnection)
    
    	store, err := NewStore(cfg)
    	if err != nil {
    		t.Fatalf("creating new store failed: %v", err)
    	}
    	// TODO: This is only true for now!!
    
    	if store.GetRevision() != "201806161853" {
    		t.Fatalf("for now new databases should have revision %q: got %q", "201806161853", store.GetRevision())
    
    	}
    	store.Close()
    	// TODO: needs more testing!!!!
    }
    
    //// Arrrrgh!!!!!
    ////  both database/sql and gorm are incredibly stupid!!!!
    ////  using database/sql alone it is needlessly hard to write portable sql queries:
    ////     postgres: db.Exec("INSERT INTO groups (name) VALUES ($1)", testGroup1)
    ////     mysql:    db.Exec("INSERT INTO groups (name) VALUES (?)", testGroup1)
    ////
    ////  using gorm db.Exec() will deal with that but i couldn't find a good way to get
    ////     the last inserted id without using the model code of gorm and we specifically
    ////     don't want to use the model code since is not clear whether the constraints
    ////     are actually enforced by the DBMS or by some gorm callbacks...
    ////
    // func TestDBConstraints(t *testing.T) {
    // 	// we don't want to use the model but hand written SQL commands here since we want to check
    // 	// whether the constraints are really enforced by the DBMS and not by some magic bullshit in gorm!
    //  // This is even worse since gorm.AutoUpdate will not deal with foreign key constraints and we
    //  // need do it ourselves at the migration scripts. It would be really nice to be able to check
    //  // whether the migrations do the right thing!!!
    
    // 	db, err := gorm.Open(testDBType, testDBConnection)
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    // 	if err = db.DB().Ping(); err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	res := db.Exec("INSERT INTO groups (name) VALUES (?)", testGroup1)
    // 	if res.Error != nil {
    // 		t.Fatalf("adding group '%s' shouldn't fail: %v", testGroup1, res.Error)
    // 	}
    // 	if res = db.Exec("INSERT INTO groups (name) VALUES (?)", testGroup1); res.Error == nil {
    // 		t.Fatalf("re-adding the same group should fail")
    // 	}
    
    // 	if res = db.Exec("INSERT INTO files (group_name, size) VALUES (?, ?)", testGroup1, 500); res.Error != nil {
    // 		t.Fatalf("re-adding the same group should fail")
    // 	}
    // }
    
    Christian Pointner's avatar
    Christian Pointner committed
    // // Groups
    // //
    
    // func TestGroups(t *testing.T) {
    // 	os.Remove(testDBPath)
    // 	store, err := NewStore(&Config{testBasePath})
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	groups, err := store.ListGroups()
    // 	if err != nil {
    // 		t.Fatalf("listing groups failed: %v", err)
    // 	}
    // 	if len(groups) != 1 && groups[0] != publicGroupBn {
    // 		t.Fatalf("a newly created store should contain a single group '%s' but ListGroups returned: %q", publicGroupBn, groups)
    // 	}
    
    // 	if err = store.createGroup(testGroup1); err != nil {
    // 		t.Fatalf("creating group failed: %v", err)
    // 	}
    // 	groups, err = store.ListGroups()
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    // 	groupsSorted := sort.StringSlice(groups)
    // 	groupsSorted.Sort()
    
    // 	groupsExpected := sort.StringSlice([]string{publicGroupBn, testGroup1})
    // 	groupsExpected.Sort()
    
    // 	if !reflect.DeepEqual(groupsSorted, groupsExpected) {
    // 		t.Fatalf("store should contain groups %q but ListGroups returned: %q", groupsExpected, groupsSorted)
    // 	}
    
    // 	if err = store.createGroup(testGroup2); err != nil {
    // 		t.Fatalf("creating group failed: %v", err)
    // 	}
    // 	groups, err = store.ListGroups()
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    // 	groupsSorted = sort.StringSlice(groups)
    // 	groupsSorted.Sort()
    
    // 	groupsExpected = sort.StringSlice([]string{publicGroupBn, testGroup1, testGroup2})
    // 	groupsExpected.Sort()
    
    // 	if !reflect.DeepEqual(groupsSorted, groupsExpected) {
    // 		t.Fatalf("store should contain groups %q but ListGroups returned: %q", groupsExpected, groupsSorted)
    // 	}
    // }
    
    // // Files
    // //
    
    // func TestFilesListAndCreate(t *testing.T) {
    // 	os.Remove(testDBPath)
    // 	store, err := NewStore(&Config{testBasePath})
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	files, err := store.ListFiles(publicGroupBn)
    // 	if err != nil {
    // 		t.Fatalf("listing files of public group failed: %v", err)
    // 	}
    // 	if len(files) != 0 {
    // 		t.Fatalf("a newly created store should contain no files in public group but ListFiles returned: %v", files)
    // 	}
    
    // 	files, err = store.ListFiles("notexistend")
    // 	if err != nil {
    // 		t.Fatalf("listing files of not existing group shouldn't throw an error but returned: %v", err)
    // 	}
    // 	if len(files) != 0 {
    // 		t.Fatalf("listing files of not existing group should return and empty list but ListFiles returned: %v", files)
    // 	}
    
    // 	_, err = store.CreateFile(publicGroupBn, File{})
    // 	if err != nil {
    // 		t.Fatalf("creating file in public group failed: %v", err)
    // 	}
    
    // 	files, err = store.ListFiles(publicGroupBn)
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    // 	if len(files) != 1 {
    // 		t.Fatalf("ListFiles should return a single file but returned: %v", files)
    // 	}
    
    // 	_, err = store.CreateFile(testGroup1, File{})
    // 	if err != nil {
    // 		t.Fatalf("creating file in not existing group shouldn't throw an error but CreateFile returned: %v", err)
    // 	}
    
    // 	groups, err := store.ListGroups()
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    // 	if !stringInSlice(groups, testGroup1) {
    // 		t.Fatalf("creating file in not existing group '%s' should create that group but ListGroups returned : %q", testGroup1, groups)
    // 	}
    // }
    
    // func TestNewAndChangedFile(t *testing.T) {
    // 	file := NewFile(testUser1)
    // 	if file.Created.User != testUser1 {
    // 		t.Fatalf("new file should be created by user '%s' but is: '%s'", testUser1, file.Created.User)
    // 	}
    // 	age := time.Since(file.Created.Timestamp)
    // 	if age < 0 || age > 3*time.Second {
    // 		t.Fatalf("new file timestamp is off: %s", file.Created.Timestamp)
    // 	}
    // 	if file.LastChanged.User != "" || !file.LastChanged.Timestamp.IsZero() {
    // 		t.Fatalf("new file's changed value should be empty but is: %+v", file.LastChanged)
    // 	}
    
    // 	orig := *file
    
    // 	file.Changed(testUser2)
    // 	if file.Created.User != orig.Created.User {
    // 		t.Fatalf("marking file as changed shouldn't change Created.User or Created.Timestamp, was '%+v' but is now '%+v'", orig.Created, file.Created)
    // 	}
    // 	if file.LastChanged.User != testUser2 {
    // 		t.Fatalf("changed file should have changed by user '%s' but is: '%s'", testUser2, file.LastChanged.User)
    // 	}
    // 	age = time.Since(file.LastChanged.Timestamp)
    // 	if age < 0 || age > 3*time.Second {
    // 		t.Fatalf("changed file timestamp is off: %s", file.LastChanged.Timestamp)
    // 	}
    // }
    
    // func TestFilesCreateAndGet(t *testing.T) {
    // 	os.Remove(testDBPath)
    // 	store, err := NewStore(&Config{testBasePath})
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	_, err = store.GetFile(testGroup1, InvalidID)
    // 	if err != ErrNotFound {
    // 		t.Fatalf("getting file in not-existing group should return ErrNotFound, but GetFile returned: %v", err)
    // 	}
    
    // 	expected := NewFile(testUser1)
    // 	fileID, err := store.CreateFile(testGroup1, *expected)
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	_, err = store.GetFile(testGroup1, fileID)
    // 	//file, err := store.GetFile(testGroup1, fileID)
    // 	if err != nil {
    // 		t.Fatalf("getting existing file from store shouldn't return an error, but GetFile returned: %v", err)
    // 	}
    // 	// This does not work because DeepEqual does not use time.Equal when comparing timestamps...
    // 	// if !reflect.DeepEqual(expected, file) {
    // 	// 	t.Fatalf("GetFile returned different file than expected. Got %v, expected %v", file, expected)
    // 	// }
    
    // 	_, err = store.GetFile(testGroup1, InvalidID)
    // 	if err != ErrNotFound {
    // 		t.Fatalf("getting not-existing file in existing group should return ErrNotFound, but GetFile returned: %v", err)
    // 	}
    // }
    
    // func TestFilesUpdate(t *testing.T) {
    // 	os.Remove(testDBPath)
    // 	store, err := NewStore(&Config{testBasePath})
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	err = store.UpdateFile(testGroup1, InvalidID, File{})
    // 	if err != ErrNotFound {
    // 		t.Fatalf("updateing not-existing file should return ErrNotFound, but UpdateFile returned: %v", err)
    // 	}
    
    // 	orig := NewFile(testUser1)
    // 	fileID, err := store.CreateFile(testGroup1, *orig)
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	updated := *orig
    // 	updated.Changed(testUser2)
    
    // 	err = store.UpdateFile(testGroup1, fileID, updated)
    // 	if err != nil {
    // 		t.Fatalf("updating file failed, UpdateFile returned: %v", err)
    // 	}
    
    // 	// TODO: check if file was successfully updated
    // }
    
    // func TestFilesDelete(t *testing.T) {
    // 	os.Remove(testDBPath)
    // 	store, err := NewStore(&Config{testBasePath})
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	err = store.DeleteFile(testGroup1, InvalidID)
    // 	if err != ErrNotFound {
    // 		t.Fatalf("deleting not-existing file should return ErrNotFound, but DeleteFile returned: %v", err)
    // 	}
    
    // 	file := NewFile(testUser1)
    // 	fileID, err := store.CreateFile(testGroup1, *file)
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	err = store.DeleteFile(testGroup1, fileID)
    // 	if err != nil {
    // 		t.Fatalf("deleting file failed, UpdateFile returned: %v", err)
    // 	}
    
    // 	err = store.DeleteFile(testGroup1, fileID)
    // 	if err != ErrNotFound {
    // 		t.Fatalf("repeated deletion of file should return ErrNotFound, but UpdateFile returned: %v", err)
    // 	}
    
    // 	// test file usage
    // 	fileID, err = store.CreateFile(testGroup1, *file)
    // 	if err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	file.UsedBy = []uint64{42}
    // 	file.Changed(testUser1)
    // 	if err = store.UpdateFile(testGroup1, fileID, *file); err != nil {
    // 		t.Fatalf("unexpected error: %v", err)
    // 	}
    
    // 	err = store.DeleteFile(testGroup1, fileID)
    // 	if err != ErrFileInUse {
    // 		t.Fatalf("deleting  file should return ErrFileInUse, but DeleteFile returned: %v", err)
    // 	}
    // }