/
githubmirror
/
ydb-go-sdk
Обзор
Документация
Войти
/
githubmirror
/
ydb-go-sdk
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
testutil/driver.go
372 строки
10 KB
Konstantin Prokopenko
Modernize Go codebase: adopt modern idioms and upgrade CI tooling (#2082)
08 апр 2026, 20:42
Не верифицирован
08 апр 2026, 20:42
f3aeeb1
Код
Авторство
О чём код?
package testutil import ( "context" "fmt" "reflect" "strings" "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Operations" "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "github.com/ydb-platform/ydb-go-sdk/v3/internal/endpoint" "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" ) var ErrNotImplemented = xerrors.Wrap(fmt.Errorf("testutil: not implemented")) type MethodCode uint func (m MethodCode) String() string { if method, ok := codeToString[m]; ok { return method } return "" } type Method string func (m Method) Code() MethodCode { if code, ok := grpcMethodToCode[m]; ok { return code } return UnknownMethod } const ( UnknownMethod MethodCode = iota TableCreateSession TableDeleteSession TableKeepAlive TableCreateTable TableDropTable TableAlterTable TableCopyTable TableDescribeTable TableExplainDataQuery TablePrepareDataQuery TableExecuteDataQuery TableExecuteSchemeQuery TableBeginTransaction TableCommitTransaction TableRollbackTransaction TableDescribeTableOptions TableStreamReadTable TableStreamExecuteScanQuery ) var grpcMethodToCode = map[Method]MethodCode{ "/Ydb.Table.V1.TableService/CreateSession": TableCreateSession, "/Ydb.Table.V1.TableService/DeleteSession": TableDeleteSession, "/Ydb.Table.V1.TableService/KeepAlive": TableKeepAlive, "/Ydb.Table.V1.TableService/CreateTable": TableCreateTable, "/Ydb.Table.V1.TableService/DropTable": TableDropTable, "/Ydb.Table.V1.TableService/AlterTable": TableAlterTable, "/Ydb.Table.V1.TableService/CopyTable": TableCopyTable, "/Ydb.Table.V1.TableService/DescribeTable": TableDescribeTable, "/Ydb.Table.V1.TableService/ExplainDataQuery": TableExplainDataQuery, "/Ydb.Table.V1.TableService/PrepareDataQuery": TablePrepareDataQuery, "/Ydb.Table.V1.TableService/ExecuteDataQuery": TableExecuteDataQuery, "/Ydb.Table.V1.TableService/ExecuteSchemeQuery": TableExecuteSchemeQuery, "/Ydb.Table.V1.TableService/BeginTransaction": TableBeginTransaction, "/Ydb.Table.V1.TableService/CommitTransaction": TableCommitTransaction, "/Ydb.Table.V1.TableService/RollbackTransaction": TableRollbackTransaction, "/Ydb.Table.V1.TableService/DescribeTableOptions": TableDescribeTableOptions, "/Ydb.Table.V1.TableService/StreamReadTable": TableStreamReadTable, "/Ydb.Table.V1.TableService/StreamExecuteScanQuery": TableStreamExecuteScanQuery, } var codeToString = map[MethodCode]string{ TableCreateSession: lastSegment("/Ydb.Table.V1.TableService/CreateSession"), TableDeleteSession: lastSegment("/Ydb.Table.V1.TableService/DeleteSession"), TableKeepAlive: lastSegment("/Ydb.Table.V1.TableService/KeepAlive"), TableCreateTable: lastSegment("/Ydb.Table.V1.TableService/CreateTable"), TableDropTable: lastSegment("/Ydb.Table.V1.TableService/DropTable"), TableAlterTable: lastSegment("/Ydb.Table.V1.TableService/AlterTable"), TableCopyTable: lastSegment("/Ydb.Table.V1.TableService/CopyTable"), TableDescribeTable: lastSegment("/Ydb.Table.V1.TableService/DescribeTable"), TableExplainDataQuery: lastSegment("/Ydb.Table.V1.TableService/ExplainDataQuery"), TablePrepareDataQuery: lastSegment("/Ydb.Table.V1.TableService/PrepareDataQuery"), TableExecuteDataQuery: lastSegment("/Ydb.Table.V1.TableService/ExecuteDataQuery"), TableExecuteSchemeQuery: lastSegment("/Ydb.Table.V1.TableService/ExecuteSchemeQuery"), TableBeginTransaction: lastSegment("/Ydb.Table.V1.TableService/BeginTransaction"), TableCommitTransaction: lastSegment("/Ydb.Table.V1.TableService/CommitTransaction"), TableRollbackTransaction: lastSegment("/Ydb.Table.V1.TableService/RollbackTransaction"), TableDescribeTableOptions: lastSegment("/Ydb.Table.V1.TableService/DescribeTableOptions"), TableStreamReadTable: lastSegment("/Ydb.Table.V1.TableService/StreamReadTable"), TableStreamExecuteScanQuery: lastSegment("/Ydb.Table.V1.TableService/StreamExecuteScanQuery"), } func setField(name string, dst, value any) { x := reflect.ValueOf(dst).Elem() t := x.Type() f, ok := t.FieldByName(name) if !ok { panic(fmt.Sprintf( "struct %s has no field %q", t, name, )) } v := reflect.ValueOf(value) if f.Type.Kind() != v.Type().Kind() { panic(fmt.Sprintf( "struct %s field %q is types of %s, not %s", t, name, f.Type, v.Type(), )) } x.FieldByName(f.Name).Set(v) } type balancerStub struct { onInvoke func( ctx context.Context, method string, args any, reply any, opts ...grpc.CallOption, ) error onNewStream func( ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption, ) (grpc.ClientStream, error) } func (b *balancerStub) Invoke( ctx context.Context, method string, args any, reply any, opts ...grpc.CallOption, ) (err error) { if b.onInvoke == nil { return fmt.Errorf("database.onInvoke() not defined") } return b.onInvoke(ctx, method, args, reply, opts...) } func (b *balancerStub) NewStream( ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption, ) (_ grpc.ClientStream, err error) { if b.onNewStream == nil { return nil, fmt.Errorf("database.onNewStream() not defined") } return b.onNewStream(ctx, desc, method, opts...) } func (b *balancerStub) Get(context.Context) (conn grpc.ClientConnInterface, err error) { cc := &clientConn{ onInvoke: b.onInvoke, onNewStream: b.onNewStream, } return cc, nil } func (b *balancerStub) Name() string { return "testutil.database" } func (b *balancerStub) Close(ctx context.Context) error { return nil } type ( InvokeHandlers map[MethodCode]func(request any) (result proto.Message, err error) NewStreamHandlers map[MethodCode]func(desc *grpc.StreamDesc) (grpc.ClientStream, error) ) type balancerOption func(c *balancerStub) func WithInvokeHandlers(invokeHandlers InvokeHandlers) balancerOption { return func(r *balancerStub) { r.onInvoke = func( ctx context.Context, method string, args any, reply any, opts ...grpc.CallOption, ) (err error) { if handler, ok := invokeHandlers[Method(method).Code()]; ok { var result proto.Message result, err = handler(args) if err != nil { return xerrors.WithStackTrace(err) } var anyResult *anypb.Any anyResult, err = anypb.New(result) if err != nil { return xerrors.WithStackTrace(err) } setField( "Operation", reply, &Ydb_Operations.Operation{ Result: anyResult, }, ) return nil } return fmt.Errorf("method '%s' not implemented", method) } } } func WithNewStreamHandlers(newStreamHandlers NewStreamHandlers) balancerOption { return func(r *balancerStub) { r.onNewStream = func( ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption, ) (_ grpc.ClientStream, err error) { if handler, ok := newStreamHandlers[Method(method).Code()]; ok { return handler(desc) } return nil, fmt.Errorf("method '%s' not implemented", method) } } } func NewBalancer(opts ...balancerOption) *balancerStub { c := &balancerStub{} for _, opt := range opts { if opt != nil { opt(c) } } return c } func (b *balancerStub) OnUpdate(func(context.Context, []endpoint.Info)) { } type clientConn struct { onInvoke func( ctx context.Context, method string, args any, reply any, opts ...grpc.CallOption, ) error onNewStream func( ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption, ) (grpc.ClientStream, error) onAddress func() string } func (c *clientConn) Address() string { if c.onAddress != nil { return c.onAddress() } return "" } func (c *clientConn) Invoke( ctx context.Context, method string, args any, reply any, opts ...grpc.CallOption, ) error { if c.onInvoke == nil { return fmt.Errorf("onInvoke not implemented (method: %s, request: %v, response: %v)", method, args, reply) } return c.onInvoke(ctx, method, args, reply, opts...) } func (c *clientConn) NewStream( ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption, ) (grpc.ClientStream, error) { if c.onNewStream == nil { return nil, fmt.Errorf("onNewStream not implemented (method: %s, desc: %v)", method, desc) } return c.onNewStream(ctx, desc, method, opts...) } type ClientStream struct { OnHeader func() (metadata.MD, error) OnTrailer func() metadata.MD OnCloseSend func() error OnContext func() context.Context OnSendMsg func(m any) error OnRecvMsg func(m any) error } func (s *ClientStream) Header() (metadata.MD, error) { if s.OnHeader == nil { return nil, xerrors.WithStackTrace(ErrNotImplemented) } return s.OnHeader() } func (s *ClientStream) Trailer() metadata.MD { if s.OnTrailer == nil { return nil } return s.OnTrailer() } func (s *ClientStream) CloseSend() error { if s.OnCloseSend == nil { return xerrors.WithStackTrace(ErrNotImplemented) } return s.OnCloseSend() } func (s *ClientStream) Context() context.Context { if s.OnContext == nil { return nil } return s.OnContext() } func (s *ClientStream) SendMsg(m any) error { if s.OnSendMsg == nil { return xerrors.WithStackTrace(ErrNotImplemented) } return s.OnSendMsg(m) } func (s *ClientStream) RecvMsg(m any) error { if s.OnRecvMsg == nil { return xerrors.WithStackTrace(ErrNotImplemented) } return s.OnRecvMsg(m) } func lastSegment(m string) string { s := strings.Split(m, "/") return s[len(s)-1] }