github.com/yandex/pandora@v0.5.32/tests/grpc_scenario/main_test.go (about)

     1  package grpcscenario
     2  
     3  import (
     4  	"context"
     5  	"log/slog"
     6  	"net"
     7  	"os"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/spf13/afero"
    13  	"github.com/stretchr/testify/require"
    14  	"github.com/stretchr/testify/suite"
    15  	grpcscenario "github.com/yandex/pandora/components/guns/grpc/scenario"
    16  	"github.com/yandex/pandora/components/providers/scenario"
    17  	ammo "github.com/yandex/pandora/components/providers/scenario/grpc"
    18  	"github.com/yandex/pandora/components/providers/scenario/grpc/postprocessor"
    19  	_import "github.com/yandex/pandora/components/providers/scenario/import"
    20  	"github.com/yandex/pandora/core"
    21  	"github.com/yandex/pandora/core/plugin/pluginconfig"
    22  	"github.com/yandex/pandora/core/warmup"
    23  	"github.com/yandex/pandora/examples/grpc/server"
    24  	"go.uber.org/zap"
    25  	"google.golang.org/grpc"
    26  	"google.golang.org/grpc/reflection"
    27  )
    28  
    29  var testOnce = &sync.Once{}
    30  
    31  func TestGunSuite(t *testing.T) {
    32  	suite.Run(t, new(GunSuite))
    33  }
    34  
    35  type GunSuite struct {
    36  	suite.Suite
    37  	grpcServer  *grpc.Server
    38  	grpcAddress string
    39  	fs          afero.Fs
    40  	srv         *server.GRPCServer
    41  }
    42  
    43  func (s *GunSuite) SetupSuite() {
    44  	s.fs = afero.NewOsFs()
    45  	_import.Import(s.fs)
    46  	testOnce.Do(func() {
    47  		pluginconfig.AddHooks()
    48  	})
    49  	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
    50  	port := os.Getenv("PORT") // TODO: how to set free port in CI?
    51  	if port == "" {
    52  		port = "8884"
    53  	}
    54  
    55  	s.grpcServer = grpc.NewServer()
    56  	s.srv = server.NewServer(logger, time.Now().UnixNano())
    57  	server.RegisterTargetServiceServer(s.grpcServer, s.srv)
    58  
    59  	reflection.Register(s.grpcServer)
    60  	s.grpcAddress = ":" + port
    61  	l, err := net.Listen("tcp", s.grpcAddress)
    62  	s.NoError(err)
    63  
    64  	go func() {
    65  		err = s.grpcServer.Serve(l)
    66  		s.NoError(err)
    67  	}()
    68  }
    69  
    70  func (s *GunSuite) SetupTest() {
    71  	_, err := s.srv.Reset(context.Background(), nil)
    72  	s.NoError(err)
    73  }
    74  
    75  func (s *GunSuite) TearDownSuite() {
    76  	s.grpcServer.Stop()
    77  }
    78  
    79  func (s *GunSuite) Test_Scenario() {
    80  	ctx := context.Background()
    81  	log := zap.NewNop()
    82  	cfg := grpcscenario.GunConfig{
    83  		Target:      s.grpcAddress,
    84  		Timeout:     0,
    85  		TLS:         false,
    86  		DialOptions: grpcscenario.GrpcDialOptions{},
    87  		AnswLog:     grpcscenario.AnswLogConfig{},
    88  	}
    89  	g := grpcscenario.NewGun(cfg)
    90  
    91  	sharedDeps, err := g.WarmUp(&warmup.Options{Log: log, Ctx: ctx})
    92  	s.NoError(err)
    93  
    94  	gunDeps := core.GunDeps{Ctx: ctx, Log: log, PoolID: "test", InstanceID: 1, Shared: sharedDeps}
    95  	aggr := &Aggregator{}
    96  	err = g.Bind(aggr, gunDeps)
    97  	s.NoError(err)
    98  
    99  	am := &grpcscenario.Scenario{
   100  		Name: "",
   101  		Calls: []grpcscenario.Call{
   102  			{
   103  				Name:           "auth",
   104  				Preprocessors:  nil,
   105  				Postprocessors: nil,
   106  				Tag:            "auth",
   107  				Call:           "target.TargetService.Auth",
   108  				Metadata:       map[string]string{"metadata": "server.proto"},
   109  				Payload:        []byte(`{"login": "1", "pass": "1"}`),
   110  				Sleep:          0,
   111  			},
   112  			{
   113  				Name:           "list",
   114  				Preprocessors:  nil,
   115  				Postprocessors: nil,
   116  				Tag:            "list",
   117  				Call:           "target.TargetService.List",
   118  				Metadata:       map[string]string{"metadata": "server.proto"},
   119  				Payload:        []byte(`{"user_id": {{.request.auth.postprocessor.userId}}, "token": "{{.request.auth.postprocessor.token}}"}`),
   120  				Sleep:          0,
   121  			},
   122  			{
   123  				Name:           "order",
   124  				Preprocessors:  nil,
   125  				Postprocessors: nil,
   126  				Tag:            "order",
   127  				Call:           "target.TargetService.Order",
   128  				Metadata:       map[string]string{"metadata": "server.proto"},
   129  				Payload:        []byte(`{"user_id": {{.request.auth.postprocessor.userId}}, "item_id": 1098, "token": "{{.request.auth.postprocessor.token}}"}`),
   130  				Sleep:          0,
   131  			},
   132  		},
   133  	}
   134  
   135  	g.Shoot(am)
   136  	s.Len(aggr.samples, 3)
   137  }
   138  
   139  func (s *GunSuite) Test_FullScenario() {
   140  	ctx := context.Background()
   141  	log := zap.NewNop()
   142  	gunConfig := grpcscenario.GunConfig{
   143  		Target:      s.grpcAddress,
   144  		Timeout:     0,
   145  		TLS:         false,
   146  		DialOptions: grpcscenario.GrpcDialOptions{},
   147  		AnswLog:     grpcscenario.AnswLogConfig{},
   148  	}
   149  	g := grpcscenario.NewGun(gunConfig)
   150  
   151  	sharedDeps, err := g.WarmUp(&warmup.Options{Log: log, Ctx: ctx})
   152  	s.NoError(err)
   153  
   154  	gunDeps := core.GunDeps{Ctx: ctx, Log: log, PoolID: "pool_id", InstanceID: 1, Shared: sharedDeps}
   155  	aggr := &Aggregator{}
   156  	err = g.Bind(aggr, gunDeps)
   157  	s.NoError(err)
   158  
   159  	pr, err := ammo.NewProvider(s.fs, scenario.ProviderConfig{File: "testdata/grpc_payload.hcl"})
   160  	require.NoError(s.T(), err)
   161  	go func() {
   162  		_ = pr.Run(ctx, core.ProviderDeps{Log: log, PoolID: "pool_id"})
   163  	}()
   164  
   165  	for i := 0; i < 3; i++ {
   166  		am, ok := pr.Acquire()
   167  		s.True(ok)
   168  		g.Shoot(am)
   169  	}
   170  	s.Len(aggr.samples, 15)
   171  	stats, err := s.srv.Stats(context.Background(), nil)
   172  	require.NoError(s.T(), err)
   173  
   174  	s.Assert().Equal(map[int64]uint64{1: 1, 2: 1, 3: 1}, stats.Auth.Code200)
   175  	s.Assert().Equal(uint64(0), stats.Auth.Code400)
   176  	s.Assert().Equal(uint64(0), stats.Auth.Code500)
   177  	s.Assert().Equal(map[int64]uint64{1: 1, 2: 1, 3: 1}, stats.List.Code200)
   178  	s.Assert().Equal(uint64(0), stats.List.Code400)
   179  	s.Assert().Equal(uint64(0), stats.List.Code500)
   180  	s.Assert().Equal(map[int64]uint64{1: 3, 2: 3, 3: 3}, stats.Order.Code200)
   181  	s.Assert().Equal(uint64(0), stats.Order.Code400)
   182  	s.Assert().Equal(uint64(0), stats.Order.Code500)
   183  
   184  }
   185  
   186  func (s *GunSuite) Test_ErrorScenario() {
   187  	ctx := context.Background()
   188  	log := zap.NewNop()
   189  	cfg := grpcscenario.GunConfig{
   190  		Target:      s.grpcAddress,
   191  		Timeout:     0,
   192  		TLS:         false,
   193  		DialOptions: grpcscenario.GrpcDialOptions{},
   194  		AnswLog:     grpcscenario.AnswLogConfig{},
   195  	}
   196  	g := grpcscenario.NewGun(cfg)
   197  
   198  	sharedDeps, err := g.WarmUp(&warmup.Options{Log: log, Ctx: ctx})
   199  	s.NoError(err)
   200  
   201  	gunDeps := core.GunDeps{Ctx: ctx, Log: log, PoolID: "test", InstanceID: 1, Shared: sharedDeps}
   202  	aggr := &Aggregator{}
   203  	err = g.Bind(aggr, gunDeps)
   204  	s.NoError(err)
   205  
   206  	am := &grpcscenario.Scenario{
   207  		Name: "",
   208  		Calls: []grpcscenario.Call{
   209  			{
   210  				Name:          "auth",
   211  				Preprocessors: nil,
   212  				Postprocessors: []grpcscenario.Postprocessor{&postprocessor.AssertResponse{
   213  					Payload:    nil,
   214  					StatusCode: 200,
   215  				}},
   216  				Tag:      "auth",
   217  				Call:     "target.TargetService.Auth",
   218  				Metadata: map[string]string{"metadata": "server.proto"},
   219  				Payload:  []byte(`{"login": "1", "pass": "2"}`), // invalid pass
   220  				Sleep:    0,
   221  			},
   222  			{
   223  				Name:           "list",
   224  				Preprocessors:  nil,
   225  				Postprocessors: nil,
   226  				Tag:            "list",
   227  				Call:           "target.TargetService.List",
   228  				Metadata:       map[string]string{"metadata": "server.proto"},
   229  				Payload:        []byte(`{"user_id": {{.request.auth.postprocessor.userId}}, "token": "{{.request.auth.postprocessor.token}}"}`),
   230  				Sleep:          0,
   231  			},
   232  			{
   233  				Name:           "order",
   234  				Preprocessors:  nil,
   235  				Postprocessors: nil,
   236  				Tag:            "order",
   237  				Call:           "target.TargetService.Order",
   238  				Metadata:       map[string]string{"metadata": "server.proto"},
   239  				Payload:        []byte(`{"user_id": {{.request.auth.postprocessor.userId}}, "item_id": 1098, "token": "{{.request.auth.postprocessor.token}}"}`),
   240  				Sleep:          0,
   241  			},
   242  		},
   243  	}
   244  
   245  	g.Shoot(am)
   246  	s.Len(aggr.samples, 1)
   247  }
   248  
   249  type Aggregator struct {
   250  	samples []core.Sample
   251  }
   252  
   253  func (a *Aggregator) Run(ctx context.Context, deps core.AggregatorDeps) error {
   254  	return nil
   255  }
   256  
   257  func (a *Aggregator) Report(s core.Sample) {
   258  	a.samples = append(a.samples, s)
   259  }