feat: Start adding parameterized tests
This commit is contained in:
2
Makefile
2
Makefile
@@ -33,7 +33,7 @@ $(addprefix run/,$(obj)):
|
|||||||
|
|
||||||
# Test
|
# Test
|
||||||
test:
|
test:
|
||||||
go test ./...
|
go test ./... -parallel $(shell nproc)
|
||||||
|
|
||||||
# Clean
|
# Clean
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
@@ -1,31 +1,151 @@
|
|||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/pojntfx/stfs/internal/logging"
|
"github.com/pojntfx/stfs/examples"
|
||||||
"github.com/pojntfx/stfs/pkg/cache"
|
"github.com/pojntfx/stfs/pkg/cache"
|
||||||
"github.com/pojntfx/stfs/pkg/config"
|
"github.com/pojntfx/stfs/pkg/config"
|
||||||
|
"github.com/pojntfx/stfs/pkg/keys"
|
||||||
"github.com/pojntfx/stfs/pkg/operations"
|
"github.com/pojntfx/stfs/pkg/operations"
|
||||||
"github.com/pojntfx/stfs/pkg/persisters"
|
"github.com/pojntfx/stfs/pkg/persisters"
|
||||||
"github.com/pojntfx/stfs/pkg/tape"
|
"github.com/pojntfx/stfs/pkg/tape"
|
||||||
|
"github.com/pojntfx/stfs/pkg/utility"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createTestFss() (filesystems []afero.Fs, cleanup func() error, err error) {
|
const (
|
||||||
tmp, err := os.MkdirTemp(os.TempDir(), "stfs-test-*")
|
verbose = true
|
||||||
if err != nil {
|
signaturePassword = "testSignaturePassword"
|
||||||
return nil, nil, err
|
encryptionPassword = "testEncryptionPassword"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
recordSizes = []int{20, 60, 120}
|
||||||
|
fileSystemCacheDurations = []time.Duration{time.Minute, time.Hour}
|
||||||
|
stfsConfigs = []stfsConfig{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// TODO: Generate encryption and signature keys here and re-use them
|
||||||
|
// for _, signature := range config.KnownSignatureFormats {
|
||||||
|
// for _, encryption := range config.KnownEncryptionFormats {
|
||||||
|
for _, compression := range config.KnownCompressionFormats {
|
||||||
|
for _, compressionLevel := range config.KnownCompressionLevels {
|
||||||
|
for _, writeCacheType := range config.KnownWriteCacheTypes {
|
||||||
|
for _, fileSystemCacheType := range config.KnownFileSystemCacheTypes {
|
||||||
|
for _, fileSystemCacheDuration := range fileSystemCacheDurations {
|
||||||
|
for _, recordSize := range recordSizes {
|
||||||
|
stfsConfigs = append(stfsConfigs, stfsConfig{
|
||||||
|
recordSize,
|
||||||
|
false,
|
||||||
|
|
||||||
|
config.NoneKey, // encryption,
|
||||||
|
config.NoneKey, // signature,
|
||||||
|
compression,
|
||||||
|
|
||||||
|
compressionLevel,
|
||||||
|
|
||||||
|
writeCacheType,
|
||||||
|
fileSystemCacheType,
|
||||||
|
|
||||||
|
fileSystemCacheDuration,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSTFS(
|
||||||
|
drive string,
|
||||||
|
metadata string,
|
||||||
|
|
||||||
|
recordSize int,
|
||||||
|
readOnly bool,
|
||||||
|
verbose bool,
|
||||||
|
|
||||||
|
signature string,
|
||||||
|
signaturePassword string,
|
||||||
|
|
||||||
|
encryption string,
|
||||||
|
encryptionPassword string,
|
||||||
|
|
||||||
|
compression string,
|
||||||
|
compressionLevel string,
|
||||||
|
|
||||||
|
writeCache string,
|
||||||
|
writeCacheDir string,
|
||||||
|
|
||||||
|
fileSystemCache string,
|
||||||
|
fileSystemCacheDir string,
|
||||||
|
fileSystemCacheDuration time.Duration,
|
||||||
|
) (afero.Fs, error) {
|
||||||
|
signaturePrivkey := []byte{}
|
||||||
|
signaturePubkey := []byte{}
|
||||||
|
|
||||||
|
if signature != config.NoneKey {
|
||||||
|
var err error
|
||||||
|
signaturePrivkey, signaturePubkey, err = utility.Keygen(
|
||||||
|
config.PipeConfig{
|
||||||
|
Signature: signature,
|
||||||
|
Encryption: config.NoneKey,
|
||||||
|
},
|
||||||
|
config.PasswordConfig{
|
||||||
|
Password: signaturePassword,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drive := filepath.Join(tmp, "drive.tar")
|
signatureRecipient, err := keys.ParseSignerRecipient(signature, signaturePubkey)
|
||||||
recordSize := 20
|
if err != nil {
|
||||||
metadata := filepath.Join(tmp, "metadata.sqlite")
|
return nil, err
|
||||||
writeCache := filepath.Join(tmp, "write-cache")
|
}
|
||||||
osfsDir := filepath.Join(tmp, "osfs")
|
|
||||||
|
signatureIdentity, err := keys.ParseSignerIdentity(signature, signaturePrivkey, signaturePassword)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptionPrivkey := []byte{}
|
||||||
|
encryptionPubkey := []byte{}
|
||||||
|
|
||||||
|
if encryption != config.NoneKey {
|
||||||
|
encryptionPrivkey, encryptionPubkey, err = utility.Keygen(
|
||||||
|
config.PipeConfig{
|
||||||
|
Signature: config.NoneKey,
|
||||||
|
Encryption: encryption,
|
||||||
|
},
|
||||||
|
config.PasswordConfig{
|
||||||
|
Password: encryptionPassword,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptionRecipient, err := keys.ParseRecipient(encryption, encryptionPubkey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptionIdentity, err := keys.ParseIdentity(encryption, encryptionPrivkey, encryptionPassword)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
tm := tape.NewTapeManager(
|
tm := tape.NewTapeManager(
|
||||||
drive,
|
drive,
|
||||||
@@ -35,18 +155,20 @@ func createTestFss() (filesystems []afero.Fs, cleanup func() error, err error) {
|
|||||||
|
|
||||||
metadataPersister := persisters.NewMetadataPersister(metadata)
|
metadataPersister := persisters.NewMetadataPersister(metadata)
|
||||||
if err := metadataPersister.Open(); err != nil {
|
if err := metadataPersister.Open(); err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
l := logging.NewJSONLogger(4)
|
jsonLogger := &examples.Logger{
|
||||||
|
Verbose: verbose,
|
||||||
|
}
|
||||||
|
|
||||||
metadataConfig := config.MetadataConfig{
|
metadataConfig := config.MetadataConfig{
|
||||||
Metadata: metadataPersister,
|
Metadata: metadataPersister,
|
||||||
}
|
}
|
||||||
pipeConfig := config.PipeConfig{
|
pipeConfig := config.PipeConfig{
|
||||||
Compression: config.NoneKey,
|
Compression: compression,
|
||||||
Encryption: config.NoneKey,
|
Encryption: encryption,
|
||||||
Signature: config.NoneKey,
|
Signature: signature,
|
||||||
RecordSize: recordSize,
|
RecordSize: recordSize,
|
||||||
}
|
}
|
||||||
backendConfig := config.BackendConfig{
|
backendConfig := config.BackendConfig{
|
||||||
@@ -59,7 +181,11 @@ func createTestFss() (filesystems []afero.Fs, cleanup func() error, err error) {
|
|||||||
GetDrive: tm.GetDrive,
|
GetDrive: tm.GetDrive,
|
||||||
CloseDrive: tm.Close,
|
CloseDrive: tm.Close,
|
||||||
}
|
}
|
||||||
readCryptoConfig := config.CryptoConfig{}
|
readCryptoConfig := config.CryptoConfig{
|
||||||
|
Recipient: signatureRecipient,
|
||||||
|
Identity: encryptionIdentity,
|
||||||
|
Password: encryptionPassword,
|
||||||
|
}
|
||||||
|
|
||||||
readOps := operations.NewOperations(
|
readOps := operations.NewOperations(
|
||||||
backendConfig,
|
backendConfig,
|
||||||
@@ -69,18 +195,23 @@ func createTestFss() (filesystems []afero.Fs, cleanup func() error, err error) {
|
|||||||
readCryptoConfig,
|
readCryptoConfig,
|
||||||
|
|
||||||
func(event *config.HeaderEvent) {
|
func(event *config.HeaderEvent) {
|
||||||
l.Debug("Header read", event)
|
jsonLogger.Debug("Header read", event)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
writeOps := operations.NewOperations(
|
writeOps := operations.NewOperations(
|
||||||
backendConfig,
|
backendConfig,
|
||||||
metadataConfig,
|
metadataConfig,
|
||||||
|
|
||||||
pipeConfig,
|
pipeConfig,
|
||||||
config.CryptoConfig{},
|
config.CryptoConfig{
|
||||||
|
Recipient: encryptionRecipient,
|
||||||
|
Identity: signatureIdentity,
|
||||||
|
Password: signaturePassword,
|
||||||
|
},
|
||||||
|
|
||||||
func(event *config.HeaderEvent) {
|
func(event *config.HeaderEvent) {
|
||||||
l.Debug("Header write", event)
|
jsonLogger.Debug("Header write", event)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -92,88 +223,136 @@ func createTestFss() (filesystems []afero.Fs, cleanup func() error, err error) {
|
|||||||
Metadata: metadataPersister,
|
Metadata: metadataPersister,
|
||||||
},
|
},
|
||||||
|
|
||||||
config.CompressionLevelFastest,
|
compressionLevel,
|
||||||
func() (cache.WriteCache, func() error, error) {
|
func() (cache.WriteCache, func() error, error) {
|
||||||
return cache.NewCacheWrite(
|
return cache.NewCacheWrite(
|
||||||
|
writeCacheDir,
|
||||||
writeCache,
|
writeCache,
|
||||||
config.WriteCacheTypeFile,
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
false,
|
readOnly,
|
||||||
|
|
||||||
func(hdr *config.Header) {
|
func(hdr *config.Header) {
|
||||||
l.Trace("Header transform", hdr)
|
jsonLogger.Trace("Header transform", hdr)
|
||||||
},
|
},
|
||||||
l,
|
jsonLogger,
|
||||||
)
|
)
|
||||||
|
|
||||||
root, err := stfs.Initialize("/", os.ModePerm)
|
root, err := stfs.Initialize("/", os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fs, err := cache.NewCacheFilesystem(
|
return cache.NewCacheFilesystem(
|
||||||
stfs,
|
stfs,
|
||||||
root,
|
root,
|
||||||
config.NoneKey,
|
fileSystemCache,
|
||||||
0,
|
fileSystemCacheDuration,
|
||||||
"",
|
fileSystemCacheDir,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type stfsConfig struct {
|
||||||
|
recordSize int
|
||||||
|
readOnly bool
|
||||||
|
|
||||||
|
signature string
|
||||||
|
encryption string
|
||||||
|
compression string
|
||||||
|
|
||||||
|
compressionLevel string
|
||||||
|
|
||||||
|
writeCache string
|
||||||
|
fileSystemCache string
|
||||||
|
|
||||||
|
fileSystemCacheDuration time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type fsConfig struct {
|
||||||
|
stfsConfig stfsConfig
|
||||||
|
fs afero.Fs
|
||||||
|
}
|
||||||
|
|
||||||
|
func createFss() ([]fsConfig, func() error, error) {
|
||||||
|
fss := []fsConfig{}
|
||||||
|
|
||||||
|
tmp, err := os.MkdirTemp(os.TempDir(), "stfs-test-*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osfsDir := filepath.Join(tmp, "osfs")
|
||||||
|
|
||||||
if err := os.MkdirAll(osfsDir, os.ModePerm); err != nil {
|
if err := os.MkdirAll(osfsDir, os.ModePerm); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return []afero.Fs{
|
fss = append(fss, fsConfig{stfsConfig{}, afero.NewBasePathFs(afero.NewOsFs(), osfsDir)})
|
||||||
fs,
|
|
||||||
afero.NewBasePathFs(afero.NewOsFs(), osfsDir),
|
for _, config := range stfsConfigs {
|
||||||
},
|
tmp, err := os.MkdirTemp(os.TempDir(), "stfs-test-*")
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
drive := filepath.Join(tmp, "drive.tar")
|
||||||
|
metadata := filepath.Join(tmp, "metadata.sqlite")
|
||||||
|
|
||||||
|
writeCacheDir := filepath.Join(tmp, "write-cache")
|
||||||
|
fileSystemCacheDir := filepath.Join(tmp, "filesystem-cache")
|
||||||
|
|
||||||
|
stfs, err := createSTFS(
|
||||||
|
drive,
|
||||||
|
metadata,
|
||||||
|
|
||||||
|
config.recordSize,
|
||||||
|
config.readOnly,
|
||||||
|
verbose,
|
||||||
|
|
||||||
|
config.signature,
|
||||||
|
signaturePassword,
|
||||||
|
|
||||||
|
config.encryption,
|
||||||
|
encryptionPassword,
|
||||||
|
|
||||||
|
config.compression,
|
||||||
|
config.compressionLevel,
|
||||||
|
|
||||||
|
config.writeCache,
|
||||||
|
writeCacheDir,
|
||||||
|
|
||||||
|
config.fileSystemCache,
|
||||||
|
fileSystemCacheDir,
|
||||||
|
config.fileSystemCacheDuration,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fss = append(fss, fsConfig{config, stfs})
|
||||||
|
}
|
||||||
|
|
||||||
|
return fss,
|
||||||
func() error {
|
func() error {
|
||||||
return os.RemoveAll(tmp)
|
return os.RemoveAll(tmp)
|
||||||
},
|
},
|
||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTestNameForFs(testName string, fsName string) string {
|
func runForAllFss(t *testing.T, name string, action func(t *testing.T, fs fsConfig)) {
|
||||||
return testName + " (" + fsName + ")"
|
fss, cleanup, err := createFss()
|
||||||
}
|
|
||||||
|
|
||||||
func TestSTFS_Name(t *testing.T) {
|
|
||||||
filesystems, cleanup, err := createTestFss()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
tests := []struct {
|
for _, fs := range fss {
|
||||||
name string
|
t.Run(fmt.Sprintf(`%v for filesystem with config %v and name %v`, name, fs.stfsConfig, fs.fs.Name()), func(t *testing.T) {
|
||||||
f []afero.Fs
|
t.Parallel()
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"Returns correct file system name",
|
|
||||||
[]afero.Fs{filesystems[1]},
|
|
||||||
"BasePathFs",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Returns correct file system name",
|
|
||||||
[]afero.Fs{filesystems[0]},
|
|
||||||
"STFS",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
action(t, fs)
|
||||||
for _, f := range tt.f {
|
})
|
||||||
t.Run(getTestNameForFs(tt.name, f.Name()), func(t *testing.T) {
|
|
||||||
if got := f.Name(); got != tt.want {
|
|
||||||
t.Errorf("%v.Name() = %v, want %v", f.Name(), got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,41 +385,33 @@ func TestSTFS_Create(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
filesystems, cleanup, err := createTestFss()
|
runForAllFss(t, tt.name, func(t *testing.T, fs fsConfig) {
|
||||||
if err != nil {
|
file, err := fs.fs.Create(tt.args.name)
|
||||||
panic(err)
|
if (err != nil) != tt.wantErr {
|
||||||
}
|
t.Errorf("%v.Create() error = %v, wantErr %v", fs.fs.Name(), err, tt.wantErr)
|
||||||
defer cleanup()
|
|
||||||
|
|
||||||
for _, f := range filesystems {
|
return
|
||||||
t.Run(getTestNameForFs(tt.name, f.Name()), func(t *testing.T) {
|
}
|
||||||
file, err := f.Create(tt.args.name)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("%v.Create() error = %v, wantErr %v", f.Name(), err, tt.wantErr)
|
|
||||||
|
|
||||||
return
|
want, err := fs.fs.Stat(tt.args.name)
|
||||||
}
|
if err != nil {
|
||||||
|
t.Errorf("%v.Stat() error = %v, wantErr %v", fs.fs.Name(), err, tt.wantErr)
|
||||||
|
|
||||||
want, err := f.Stat(tt.args.name)
|
return
|
||||||
if err != nil {
|
}
|
||||||
t.Errorf("%v.Stat() error = %v, wantErr %v", f.Name(), err, tt.wantErr)
|
|
||||||
|
|
||||||
return
|
got, err := fs.fs.Stat(file.Name())
|
||||||
}
|
if err != nil {
|
||||||
|
t.Errorf("%v.Stat() error = %v, wantErr %v", fs.fs.Name(), err, tt.wantErr)
|
||||||
|
|
||||||
got, err := f.Stat(file.Name())
|
return
|
||||||
if err != nil {
|
}
|
||||||
t.Errorf("%v.Stat() error = %v, wantErr %v", f.Name(), err, tt.wantErr)
|
|
||||||
|
|
||||||
return
|
if !reflect.DeepEqual(got, want) {
|
||||||
}
|
t.Errorf("%v.Create().Name() = %v, want %v", fs.fs.Name(), got, want)
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
return
|
||||||
t.Errorf("%v.Create().Name() = %v, want %v", f.Name(), got, want)
|
}
|
||||||
|
})
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user