From a1c8fb79b23330878431da1b2b4d2e09306a9f6b Mon Sep 17 00:00:00 2001 From: Artsiom Koltun Date: Fri, 24 Mar 2023 12:55:34 +0100 Subject: [PATCH] Move test environment creation into utils. Frontend, middleend and backend used the same procedures to prepare test environment. In this patch, this test environment creation is moved into utils.go file which can be used by other packages. Signed-off-by: Artsiom Koltun --- pkg/backend/backend_test.go | 87 ++++++-------------------- pkg/frontend/frontend_test.go | 86 ++++++-------------------- pkg/middleend/middleend_test.go | 79 ++++++------------------ pkg/server/utils.go | 104 ++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 201 deletions(-) diff --git a/pkg/backend/backend_test.go b/pkg/backend/backend_test.go index fbea8e51..5a06fc28 100644 --- a/pkg/backend/backend_test.go +++ b/pkg/backend/backend_test.go @@ -7,85 +7,32 @@ package backend import ( "context" - "log" - "net" - "os" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/test/bufconn" pb "github.com/opiproject/opi-api/storage/v1alpha1/gen/go" "github.com/opiproject/opi-spdk-bridge/pkg/server" ) -// TODO: move test infrastructure code to a separate (test/server) package to avoid duplication - -type backendClient struct { - pb.NVMfRemoteControllerServiceClient - pb.NullDebugServiceClient - pb.AioControllerServiceClient -} - type testEnv struct { + *server.TestEnv opiSpdkServer *Server - client *backendClient - ln net.Listener - testSocket string + client *server.TestOpiClient ctx context.Context - conn *grpc.ClientConn - jsonRPC server.JSONRPC -} - -func (e *testEnv) Close() { - server.CloseListener(e.ln) - if err := os.RemoveAll(e.testSocket); err != nil { - log.Fatal(err) - } - server.CloseGrpcConnection(e.conn) } func createTestEnvironment(startSpdkServer bool, spdkResponses []string) *testEnv { - env := &testEnv{} - env.testSocket = server.GenerateSocketName("backend") - env.ln, env.jsonRPC = server.CreateTestSpdkServer(env.testSocket, startSpdkServer, spdkResponses) - env.opiSpdkServer = NewServer(env.jsonRPC) - - ctx := context.Background() - conn, err := grpc.DialContext(ctx, - "", - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithContextDialer(dialer(env.opiSpdkServer))) - if err != nil { - log.Fatal(err) - } - - env.ctx = ctx - env.conn = conn - - env.client = &backendClient{ - pb.NewNVMfRemoteControllerServiceClient(env.conn), - pb.NewNullDebugServiceClient(env.conn), - pb.NewAioControllerServiceClient(env.conn), - } - - return env -} - -func dialer(opiSpdkServer *Server) func(context.Context, string) (net.Conn, error) { - listener := bufconn.Listen(1024 * 1024) - server := grpc.NewServer() - pb.RegisterNVMfRemoteControllerServiceServer(server, opiSpdkServer) - pb.RegisterNullDebugServiceServer(server, opiSpdkServer) - pb.RegisterAioControllerServiceServer(server, opiSpdkServer) - - go func() { - if err := server.Serve(listener); err != nil { - log.Fatal(err) - } - }() - - return func(context.Context, string) (net.Conn, error) { - return listener.Dial() - } + var opiSpdkServer *Server + env := server.CreateTestEnvironment(startSpdkServer, spdkResponses, + func(jsonRPC server.JSONRPC) server.TestOpiServer { + opiSpdkServer = NewServer(jsonRPC) + return server.TestOpiServer{ + FrontendNvmeServiceServer: &pb.UnimplementedFrontendNvmeServiceServer{}, + FrontendVirtioBlkServiceServer: &pb.UnimplementedFrontendVirtioBlkServiceServer{}, + FrontendVirtioScsiServiceServer: &pb.UnimplementedFrontendVirtioScsiServiceServer{}, + MiddleendServiceServer: &pb.UnimplementedMiddleendServiceServer{}, + AioControllerServiceServer: opiSpdkServer, + NullDebugServiceServer: opiSpdkServer, + NVMfRemoteControllerServiceServer: opiSpdkServer, + } + }) + return &testEnv{env, opiSpdkServer, env.Client, env.Ctx} } diff --git a/pkg/frontend/frontend_test.go b/pkg/frontend/frontend_test.go index 9a362da9..2da60ef4 100644 --- a/pkg/frontend/frontend_test.go +++ b/pkg/frontend/frontend_test.go @@ -7,84 +7,32 @@ package frontend import ( "context" - "log" - "net" - "os" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/test/bufconn" pb "github.com/opiproject/opi-api/storage/v1alpha1/gen/go" "github.com/opiproject/opi-spdk-bridge/pkg/server" ) -// TODO: move test infrastructure code to a separate (test/server) package to avoid duplication - -type frontendClient struct { - pb.FrontendNvmeServiceClient - pb.FrontendVirtioBlkServiceClient - pb.FrontendVirtioScsiServiceClient -} - type testEnv struct { + *server.TestEnv opiSpdkServer *Server - client *frontendClient - ln net.Listener - testSocket string + client *server.TestOpiClient ctx context.Context - conn *grpc.ClientConn - jsonRPC server.JSONRPC -} - -func (e *testEnv) Close() { - server.CloseListener(e.ln) - server.CloseGrpcConnection(e.conn) - if err := os.RemoveAll(e.testSocket); err != nil { - log.Fatal(err) - } } func createTestEnvironment(startSpdkServer bool, spdkResponses []string) *testEnv { - env := &testEnv{} - env.testSocket = server.GenerateSocketName("frontend") - env.ln, env.jsonRPC = server.CreateTestSpdkServer(env.testSocket, startSpdkServer, spdkResponses) - env.opiSpdkServer = NewServer(env.jsonRPC) - - ctx := context.Background() - conn, err := grpc.DialContext(ctx, - "", - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithContextDialer(dialer(env.opiSpdkServer))) - if err != nil { - log.Fatal(err) - } - env.ctx = ctx - env.conn = conn - - env.client = &frontendClient{ - pb.NewFrontendNvmeServiceClient(env.conn), - pb.NewFrontendVirtioBlkServiceClient(env.conn), - pb.NewFrontendVirtioScsiServiceClient(env.conn), - } - - return env -} - -func dialer(opiSpdkServer *Server) func(context.Context, string) (net.Conn, error) { - listener := bufconn.Listen(1024 * 1024) - server := grpc.NewServer() - pb.RegisterFrontendNvmeServiceServer(server, opiSpdkServer) - pb.RegisterFrontendVirtioBlkServiceServer(server, opiSpdkServer) - pb.RegisterFrontendVirtioScsiServiceServer(server, opiSpdkServer) - - go func() { - if err := server.Serve(listener); err != nil { - log.Fatal(err) - } - }() - - return func(context.Context, string) (net.Conn, error) { - return listener.Dial() - } + var opiSpdkServer *Server + env := server.CreateTestEnvironment(startSpdkServer, spdkResponses, + func(jsonRPC server.JSONRPC) server.TestOpiServer { + opiSpdkServer = NewServer(jsonRPC) + return server.TestOpiServer{ + FrontendNvmeServiceServer: opiSpdkServer, + FrontendVirtioBlkServiceServer: opiSpdkServer, + FrontendVirtioScsiServiceServer: opiSpdkServer, + MiddleendServiceServer: &pb.UnimplementedMiddleendServiceServer{}, + AioControllerServiceServer: &pb.UnimplementedAioControllerServiceServer{}, + NullDebugServiceServer: &pb.UnimplementedNullDebugServiceServer{}, + NVMfRemoteControllerServiceServer: &pb.UnimplementedNVMfRemoteControllerServiceServer{}, + } + }) + return &testEnv{env, opiSpdkServer, env.Client, env.Ctx} } diff --git a/pkg/middleend/middleend_test.go b/pkg/middleend/middleend_test.go index 61da72d2..5f1c2425 100644 --- a/pkg/middleend/middleend_test.go +++ b/pkg/middleend/middleend_test.go @@ -9,17 +9,11 @@ import ( "bytes" "context" "fmt" - "log" - "net" - "os" "reflect" "testing" - "google.golang.org/grpc" "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" - "google.golang.org/grpc/test/bufconn" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" @@ -29,68 +23,29 @@ import ( "github.com/opiproject/opi-spdk-bridge/pkg/server" ) -// TODO: move test infrastructure code to a separate (test/server) package to avoid duplication - -type middleendClient struct { - pb.MiddleendServiceClient -} - type testEnv struct { + *server.TestEnv opiSpdkServer *Server - client *middleendClient - ln net.Listener - testSocket string + client *server.TestOpiClient ctx context.Context - conn *grpc.ClientConn - jsonRPC server.JSONRPC -} - -func (e *testEnv) Close() { - server.CloseListener(e.ln) - if err := os.RemoveAll(e.testSocket); err != nil { - log.Fatal(err) - } - server.CloseGrpcConnection(e.conn) } func createTestEnvironment(startSpdkServer bool, spdkResponses []string) *testEnv { - env := &testEnv{} - env.testSocket = server.GenerateSocketName("middleend") - env.ln, env.jsonRPC = server.CreateTestSpdkServer(env.testSocket, startSpdkServer, spdkResponses) - env.opiSpdkServer = NewServer(env.jsonRPC) - - ctx := context.Background() - conn, err := grpc.DialContext(ctx, - "", - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithContextDialer(dialer(env.opiSpdkServer))) - if err != nil { - log.Fatal(err) - } - env.ctx = ctx - env.conn = conn - - env.client = &middleendClient{ - pb.NewMiddleendServiceClient(env.conn), - } - - return env -} - -func dialer(opiSpdkServer *Server) func(context.Context, string) (net.Conn, error) { - listener := bufconn.Listen(1024 * 1024) - server := grpc.NewServer() - pb.RegisterMiddleendServiceServer(server, opiSpdkServer) - - go func() { - if err := server.Serve(listener); err != nil { - log.Fatal(err) - } - }() - - return func(context.Context, string) (net.Conn, error) { - return listener.Dial() - } + var opiSpdkServer *Server + env := server.CreateTestEnvironment(startSpdkServer, spdkResponses, + func(jsonRPC server.JSONRPC) server.TestOpiServer { + opiSpdkServer = NewServer(jsonRPC) + return server.TestOpiServer{ + FrontendNvmeServiceServer: &pb.UnimplementedFrontendNvmeServiceServer{}, + FrontendVirtioBlkServiceServer: &pb.UnimplementedFrontendVirtioBlkServiceServer{}, + FrontendVirtioScsiServiceServer: &pb.UnimplementedFrontendVirtioScsiServiceServer{}, + MiddleendServiceServer: opiSpdkServer, + AioControllerServiceServer: &pb.UnimplementedAioControllerServiceServer{}, + NullDebugServiceServer: &pb.UnimplementedNullDebugServiceServer{}, + NVMfRemoteControllerServiceServer: &pb.UnimplementedNVMfRemoteControllerServiceServer{}, + } + }) + return &testEnv{env, opiSpdkServer, env.Client, env.Ctx} } var ( diff --git a/pkg/server/utils.go b/pkg/server/utils.go index 28457371..3d754ef2 100644 --- a/pkg/server/utils.go +++ b/pkg/server/utils.go @@ -6,6 +6,7 @@ package server import ( + "context" "crypto/rand" "fmt" "log" @@ -16,8 +17,111 @@ import ( "strings" "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/test/bufconn" + + pb "github.com/opiproject/opi-api/storage/v1alpha1/gen/go" ) +// TestOpiClient represents a client which is able to perform all OPI requests +type TestOpiClient struct { + pb.FrontendNvmeServiceClient + pb.FrontendVirtioBlkServiceClient + pb.FrontendVirtioScsiServiceClient + + pb.MiddleendServiceClient + + pb.AioControllerServiceClient + pb.NullDebugServiceClient + pb.NVMfRemoteControllerServiceClient +} + +// TestOpiServer represents a test server which implements all OPI calls +type TestOpiServer struct { + pb.FrontendNvmeServiceServer + pb.FrontendVirtioBlkServiceServer + pb.FrontendVirtioScsiServiceServer + + pb.MiddleendServiceServer + + pb.AioControllerServiceServer + pb.NullDebugServiceServer + pb.NVMfRemoteControllerServiceServer +} + +// TestEnv represents a testing environment with all required objects for testing +type TestEnv struct { + OpiSpdkServer TestOpiServer + Client *TestOpiClient + Ctx context.Context + + ln net.Listener + testSocket string + conn *grpc.ClientConn + jsonRPC JSONRPC +} + +// Close used to close all created resources for testing +func (e *TestEnv) Close() { + CloseListener(e.ln) + CloseGrpcConnection(e.conn) + if err := os.RemoveAll(e.testSocket); err != nil { + log.Fatal(err) + } +} + +// CreateTestEnvironment creates an instance of TestEnv +func CreateTestEnvironment(startSpdkServer bool, spdkResponses []string, serverCreator func(JSONRPC) TestOpiServer) *TestEnv { + env := &TestEnv{} + env.testSocket = GenerateSocketName("opi-unit-test") + env.ln, env.jsonRPC = CreateTestSpdkServer(env.testSocket, startSpdkServer, spdkResponses) + env.OpiSpdkServer = serverCreator(env.jsonRPC) + + env.Ctx = context.Background() + conn, err := grpc.DialContext(env.Ctx, + "", + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithContextDialer(dialer(env.OpiSpdkServer))) + if err != nil { + log.Fatal(err) + } + env.conn = conn + + env.Client = &TestOpiClient{ + pb.NewFrontendNvmeServiceClient(env.conn), + pb.NewFrontendVirtioBlkServiceClient(env.conn), + pb.NewFrontendVirtioScsiServiceClient(env.conn), + pb.NewMiddleendServiceClient(env.conn), + pb.NewAioControllerServiceClient(env.conn), + pb.NewNullDebugServiceClient(env.conn), + pb.NewNVMfRemoteControllerServiceClient(env.conn), + } + + return env +} + +func dialer(opiSpdkServer TestOpiServer) func(context.Context, string) (net.Conn, error) { + listener := bufconn.Listen(1024 * 1024) + server := grpc.NewServer() + pb.RegisterFrontendNvmeServiceServer(server, opiSpdkServer) + pb.RegisterFrontendVirtioBlkServiceServer(server, opiSpdkServer) + pb.RegisterFrontendVirtioScsiServiceServer(server, opiSpdkServer) + pb.RegisterMiddleendServiceServer(server, opiSpdkServer) + pb.RegisterAioControllerServiceServer(server, opiSpdkServer) + pb.RegisterNullDebugServiceServer(server, opiSpdkServer) + pb.RegisterNVMfRemoteControllerServiceServer(server, opiSpdkServer) + + go func() { + if err := server.Serve(listener); err != nil { + log.Fatal(err) + } + }() + + return func(context.Context, string) (net.Conn, error) { + return listener.Dial() + } +} + // CreateTestSpdkServer creates a mock spdk server for testing func CreateTestSpdkServer(socket string, startSpdkServer bool, spdkResponses []string) (net.Listener, JSONRPC) { jsonRPC := NewSpdkJSONRPC(socket).(*spdkJSONRPC)