xorm/dialects/ydb_test.go

439 lines
8.3 KiB
Go

package dialects
import (
"context"
"fmt"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseYDBConnString(t *testing.T) {
type result struct {
dbType string
host string
port string
dbName string
userName string
password string
}
tests := []struct {
connString string
expected result
valid bool
}{
{
connString: "grpc://localhost:2136/local",
expected: result{
dbType: "ydb",
host: "localhost",
port: "2136",
dbName: "/local",
userName: "",
password: "",
},
valid: true,
},
{
connString: "grpcs://localhost:2135/local",
expected: result{
dbType: "ydb",
host: "localhost",
port: "2135",
dbName: "/local",
userName: "",
password: "",
},
valid: true,
},
{
connString: "grpcs://ydb.serverless.yandexcloud.net:2135/ru-central1/b1g8skpblkos03malf3s/etn01q5ko6sh271beftr",
expected: result{
dbType: "ydb",
host: "ydb.serverless.yandexcloud.net",
port: "2135",
dbName: "/ru-central1/b1g8skpblkos03malf3s/etn01q5ko6sh271beftr",
userName: "",
password: "",
},
valid: true,
},
{
connString: "https://localhost:2135/local",
expected: result{},
valid: false,
},
{
connString: "grpcs://localhost:2135/local?query_mode=data&go_query_bind=table_path_prefix(/local/test),numeric,declare",
expected: result{
dbType: "ydb",
host: "localhost",
port: "2135",
dbName: "/local",
userName: "",
password: "",
},
valid: true,
},
{
connString: "grpcs://user:password@localhost:2135/local",
expected: result{
dbType: "ydb",
host: "localhost",
port: "2135",
dbName: "/local",
userName: "user",
password: "password",
},
valid: true,
},
{
connString: "grpcs://lb.etn03r9df42nb631unbv.ydb.mdb.yandexcloud.net:2135/ru-central1/b1g8skpblkos03malf3s/etn03r9df42nb631unbv",
expected: result{
dbType: "ydb",
host: "lb.etn03r9df42nb631unbv.ydb.mdb.yandexcloud.net",
port: "2135",
dbName: "/ru-central1/b1g8skpblkos03malf3s/etn03r9df42nb631unbv",
userName: "",
password: "",
},
valid: true,
},
}
driver := QueryDriver("ydb")
for _, test := range tests {
t.Run(test.connString, func(t *testing.T) {
info, err := driver.Parse("ydb", test.connString)
if err != nil && test.valid {
t.Errorf("%q got unexpected error: %s", test.connString, err)
} else if err == nil {
expected := test.expected
actual := result{}
if test.valid {
actual = result{
dbType: string(info.DBType),
host: info.Host,
port: info.Port,
dbName: info.DBName,
userName: info.User,
password: info.Passwd,
}
}
if !reflect.DeepEqual(expected, actual) {
t.Errorf("%q got: %+v want: %+v", test.connString, actual, expected)
}
}
})
}
}
// error object for testing `IsRetryable()` method of YDB.
type mockError struct {
code int32
name string
}
func (merr mockError) Error() string {
return fmt.Sprintf("%d/%s", merr.code, merr.name)
}
func (merr mockError) Code() int32 {
return merr.code
}
func (merr mockError) Name() string {
return merr.name
}
func TestIsRetryableYDB(t *testing.T) {
ydbDialect := QueryDialect("ydb") // get ydb dialect
for _, curErr := range []struct {
retryable bool
err error
}{
{
retryable: false,
err: fmt.Errorf("unknown error"),
},
{
retryable: false,
err: fmt.Errorf("errors.As() failed"),
},
{
retryable: false,
err: context.DeadlineExceeded,
},
{
retryable: false,
err: context.Canceled,
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_Unknown),
name: "grpc unknown",
},
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_InvalidArgument),
name: "grpc invalid argument",
},
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_DeadlineExceeded),
name: "grpc deadline exceeded",
},
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_NotFound),
name: "grpc not found",
},
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_AlreadyExists),
name: "grpc already exists",
},
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_PermissionDenied),
name: "grpc permission denied",
},
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_FailedPrecondition),
name: "grpc failed precondition",
},
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_OutOfRange),
name: "grpc out of range",
},
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_Unimplemented),
name: "grpc unimplemented",
},
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_DataLoss),
name: "grpc data loss",
},
},
{
retryable: false,
err: mockError{
code: int32(ydb_grpc_Unauthenticated),
name: "grpc unauthenticated",
},
},
{
retryable: true,
err: mockError{
code: int32(ydb_grpc_Canceled),
name: "grpc canceled",
},
},
{
retryable: true,
err: mockError{
code: int32(ydb_grpc_ResourceExhausted),
name: "grpc resource exhauseed",
},
},
{
retryable: true,
err: mockError{
code: int32(ydb_grpc_Aborted),
name: "grpc aborted",
},
},
{
retryable: true,
err: mockError{
code: int32(ydb_grpc_Internal),
name: "grpc internal",
},
},
{
retryable: true,
err: mockError{
code: int32(ydb_grpc_Unavailable),
name: "grpc unavailable",
},
},
{
retryable: false,
err: mockError{
code: ydb_STATUS_CODE_UNSPECIFIED,
name: "ydb status code unspecified",
},
},
{
retryable: false,
err: mockError{
code: ydb_BAD_REQUEST,
name: "ydb bad request",
},
},
{
retryable: false,
err: mockError{
code: ydb_UNAUTHORIZED,
name: "ydb unauthorized",
},
},
{
retryable: false,
err: mockError{
code: ydb_INTERNAL_ERROR,
name: "ydb internal error",
},
},
{
retryable: false,
err: mockError{
code: ydb_SCHEME_ERROR,
name: "ydb scheme error",
},
},
{
retryable: false,
err: mockError{
code: ydb_GENERIC_ERROR,
name: "ydb generic error",
},
},
{
retryable: false,
err: mockError{
code: ydb_TIMEOUT,
name: "ydb timeout",
},
},
{
retryable: false,
err: mockError{
code: ydb_PRECONDITION_FAILED,
name: "ydb precondition failed",
},
},
{
retryable: false,
err: mockError{
code: ydb_ALREADY_EXISTS,
name: "ydb already exists",
},
},
{
retryable: false,
err: mockError{
code: ydb_NOT_FOUND,
name: "ydb not found",
},
},
{
retryable: false,
err: mockError{
code: ydb_SESSION_EXPIRED,
name: "ydb session expired",
},
},
{
retryable: false,
err: mockError{
code: ydb_CANCELLED,
name: "ydb cancelled",
},
},
{
retryable: false,
err: mockError{
code: ydb_UNSUPPORTED,
name: "ydb unsupported",
},
},
{
retryable: true,
err: mockError{
code: ydb_ABORTED,
name: "ydb aborted",
},
},
{
retryable: true,
err: mockError{
code: ydb_UNAVAILABLE,
name: "ydb unavailable",
},
},
{
retryable: true,
err: mockError{
code: ydb_OVERLOADED,
name: "ydb overloaded",
},
},
{
retryable: true,
err: mockError{
code: ydb_BAD_SESSION,
name: "ydb bad session",
},
},
{
retryable: true,
err: mockError{
code: ydb_UNDETERMINED,
name: "ydb undetermined",
},
},
{
retryable: true,
err: mockError{
code: ydb_SESSION_BUSY,
name: "ydb session busy",
},
},
{
retryable: false,
err: fmt.Errorf("wrap error: %w", mockError{code: int32(ydb_grpc_Unknown), name: "wrap grpc unknown"}),
},
{
retryable: true,
err: fmt.Errorf("wrap error: %w", mockError{code: int32(ydb_UNAVAILABLE), name: "wrap ydb unavailable"}),
},
{
retryable: false,
err: fmt.Errorf("wrap error: %w", mockError{code: -1, name: "unknown error"}),
},
} {
t.Run(curErr.err.Error(), func(t *testing.T) {
retryable := ydbDialect.IsRetryable(curErr.err)
assert.EqualValues(t, curErr.retryable, retryable)
})
}
}