sq/libsq/source/internal_test.go
Neil O'Toole f07edef14d
Add flag --src.schema (#326)
* Support for --src.schema in commands "slq", "sql", and "inspect"
2023-11-18 17:05:48 -07:00

229 lines
6.0 KiB
Go

package source
import (
"context"
"io"
"runtime"
"testing"
"github.com/neilotoole/sq/libsq/core/lg"
"github.com/neilotoole/sq/testh/tutil"
"github.com/neilotoole/slogt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/neilotoole/sq/testh/proj"
"github.com/neilotoole/sq/testh/sakila"
"github.com/neilotoole/sq/testh/testsrc"
)
// Export for testing.
var (
FilesDetectTypeFn = func(fs *Files, ctx context.Context, loc string) (typ DriverType, ok bool, err error) {
return fs.detectType(ctx, loc)
}
GroupsFilterOnlyDirectChildren = groupsFilterOnlyDirectChildren
)
func TestFiles_Open(t *testing.T) {
ctx := lg.NewContext(context.Background(), slogt.New(t))
fs, err := NewFiles(ctx)
require.NoError(t, err)
t.Cleanup(func() { assert.NoError(t, fs.Close()) })
src1 := &Source{
Location: proj.Abs(testsrc.PathXLSXTestHeader),
}
f, err := fs.openLocation(src1.Location)
require.NoError(t, err)
t.Cleanup(func() { assert.NoError(t, f.Close()) })
require.Equal(t, src1.Location, f.Name())
src2 := &Source{
Location: sakila.URLActorCSV,
}
f2, err := fs.openLocation(src2.Location)
require.NoError(t, err)
t.Cleanup(func() { assert.NoError(t, f2.Close()) })
b, err := io.ReadAll(f2)
require.NoError(t, err)
require.Equal(t, proj.ReadFile(sakila.PathCSVActor), b)
}
func TestParseLoc(t *testing.T) {
const (
dbuser = "sakila"
dbpass = "p_ssW0rd"
)
testCases := []struct {
loc string
want parsedLoc
wantErr bool
windows bool
}{
{
loc: "/path/to/sakila.xlsx",
want: parsedLoc{name: "sakila", ext: ".xlsx"},
},
{
loc: "relative/path/to/sakila.xlsx",
want: parsedLoc{name: "sakila", ext: ".xlsx"},
},
{
loc: "./relative/path/to/sakila.xlsx",
want: parsedLoc{name: "sakila", ext: ".xlsx"},
},
{
loc: "https://server:8080/path/to/sakila.xlsx",
want: parsedLoc{scheme: "https", hostname: "server", port: 8080, name: "sakila", ext: ".xlsx"},
},
{
loc: "http://server/path/to/sakila.xlsx?param=val&param2=val2",
want: parsedLoc{scheme: "http", hostname: "server", name: "sakila", ext: ".xlsx"},
},
{
loc: "sqlite3:/path/to/sakila.db",
wantErr: true,
}, // the scheme is malformed (should be "sqlite3://...")
{
loc: "sqlite3:///path/to/sakila.sqlite",
want: parsedLoc{
typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".sqlite",
dsn: "/path/to/sakila.sqlite",
},
},
{
loc: `sqlite3://C:\path\to\sakila.sqlite`,
windows: true,
want: parsedLoc{
typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".sqlite",
dsn: `C:\path\to\sakila.sqlite`,
},
},
{
loc: `sqlite3://C:\path\to\sakila.sqlite?param=val`,
windows: true,
want: parsedLoc{
typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".sqlite",
dsn: `C:\path\to\sakila.sqlite?param=val`,
},
},
{
loc: "sqlite3:///path/to/sakila",
want: parsedLoc{
typ: typeSL3, scheme: "sqlite3", name: "sakila", dsn: "/path/to/sakila",
},
},
{
loc: "sqlite3://path/to/sakila.db",
want: parsedLoc{
typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".db", dsn: "path/to/sakila.db",
},
},
{
loc: "sqlite3:///path/to/sakila.db",
want: parsedLoc{
typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".db", dsn: "/path/to/sakila.db",
},
},
{
loc: "sqlserver://sakila:p_ssW0rd@localhost?database=sakila",
want: parsedLoc{
typ: typeMS, scheme: "sqlserver", user: dbuser, pass: dbpass, hostname: "localhost",
name: "sakila", dsn: "sqlserver://sakila:p_ssW0rd@localhost?database=sakila",
},
},
{
loc: "sqlserver://sakila:p_ssW0rd@server:1433?database=sakila",
want: parsedLoc{
typ: typeMS, scheme: "sqlserver", user: dbuser, pass: dbpass, hostname: "server",
port: 1433, name: "sakila",
dsn: "sqlserver://sakila:p_ssW0rd@server:1433?database=sakila",
},
},
{
loc: "postgres://sakila:p_ssW0rd@localhost/sakila?sslmode=disable",
want: parsedLoc{
typ: typePg, scheme: "postgres", user: dbuser, pass: dbpass, hostname: "localhost",
name: "sakila", dsn: "dbname=sakila host=localhost password=p_ssW0rd sslmode=disable user=sakila",
},
},
{
loc: "postgres://sakila:p_ssW0rd@server:5432/sakila?sslmode=disable",
want: parsedLoc{
typ: typePg, scheme: "postgres", user: dbuser, pass: dbpass, hostname: "server", port: 5432,
name: "sakila",
dsn: "dbname=sakila host=server password=p_ssW0rd port=5432 sslmode=disable user=sakila",
},
},
{
loc: "mysql://sakila:p_ssW0rd@localhost/sakila",
want: parsedLoc{
typ: typeMy, scheme: "mysql", user: dbuser, pass: dbpass, hostname: "localhost",
name: "sakila", dsn: "sakila:p_ssW0rd@tcp(localhost:3306)/sakila",
},
},
{
loc: "mysql://sakila:p_ssW0rd@server:3306/sakila",
want: parsedLoc{
typ: typeMy, scheme: "mysql", user: dbuser, pass: dbpass, hostname: "server", port: 3306,
name: "sakila", dsn: "sakila:p_ssW0rd@tcp(server:3306)/sakila",
},
},
}
for _, tc := range testCases {
tc := tc
t.Run(tutil.Name(1, RedactLocation(tc.loc)), func(t *testing.T) {
if tc.windows && runtime.GOOS != "windows" {
return
}
tc.want.loc = tc.loc // set this here rather than verbosely in the setup
got, gotErr := parseLoc(tc.loc)
if tc.wantErr {
require.Error(t, gotErr)
require.Nil(t, got)
return
}
require.NoError(t, gotErr)
require.Equal(t, tc.want, *got)
})
}
}
func TestGroupsFilterOnlyDirectChildren(t *testing.T) {
testCases := []struct {
parent string
groups []string
want []string
}{
{
parent: "/",
groups: []string{"/", "prod", "prod/customer", "staging"},
want: []string{"prod", "staging"},
},
{
parent: "prod",
groups: []string{"/", "prod", "prod/customer", "prod/backup", "staging"},
want: []string{"prod/customer", "prod/backup"},
},
}
for i, tc := range testCases {
tc := tc
t.Run(tutil.Name(i, tc.want), func(t *testing.T) {
got := GroupsFilterOnlyDirectChildren(tc.parent, tc.groups)
require.EqualValues(t, tc.want, got)
})
}
}