Skip to content

Commit

Permalink
refactoring http generator
Browse files Browse the repository at this point in the history
f7e62dcd9d04a17ee2aa95787799b40b9804aefa
  • Loading branch information
oke11o committed Mar 11, 2024
1 parent a0052dd commit 7985a66
Show file tree
Hide file tree
Showing 21 changed files with 449 additions and 188 deletions.
9 changes: 8 additions & 1 deletion .mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@
"components/guns/http/client.go":"load/projects/pandora/components/guns/http/client.go",
"components/guns/http/connect.go":"load/projects/pandora/components/guns/http/connect.go",
"components/guns/http/connect_test.go":"load/projects/pandora/components/guns/http/connect_test.go",
"components/guns/http/core.go":"load/projects/pandora/components/guns/http/core.go",
"components/guns/http/doc.go":"load/projects/pandora/components/guns/http/doc.go",
"components/guns/http/http.go":"load/projects/pandora/components/guns/http/http.go",
"components/guns/http/http_test.go":"load/projects/pandora/components/guns/http/http_test.go",
"components/guns/http/mock_client_test.go":"load/projects/pandora/components/guns/http/mock_client_test.go",
"components/guns/http/mocks/ammo.go":"load/projects/pandora/components/guns/http/mocks/ammo.go",
"components/guns/http/trace.go":"load/projects/pandora/components/guns/http/trace.go",
"components/guns/http/wrapper.go":"load/projects/pandora/components/guns/http/wrapper.go",
"components/guns/http_scenario/ammo.go":"load/projects/pandora/components/guns/http_scenario/ammo.go",
"components/guns/http_scenario/client.go":"load/projects/pandora/components/guns/http_scenario/client.go",
"components/guns/http_scenario/gun.go":"load/projects/pandora/components/guns/http_scenario/gun.go",
Expand Down Expand Up @@ -358,8 +358,15 @@
"script/coverage.sh":"load/projects/pandora/script/coverage.sh",
"tests/acceptance/common.go":"load/projects/pandora/tests/acceptance/common.go",
"tests/acceptance/config_model.go":"load/projects/pandora/tests/acceptance/config_model.go",
"tests/acceptance/connect_test.go":"load/projects/pandora/tests/acceptance/connect_test.go",
"tests/acceptance/grpc_test.go":"load/projects/pandora/tests/acceptance/grpc_test.go",
"tests/acceptance/http_test.go":"load/projects/pandora/tests/acceptance/http_test.go",
"tests/acceptance/testdata/connect/connect-check-limit.yaml":"load/projects/pandora/tests/acceptance/testdata/connect/connect-check-limit.yaml",
"tests/acceptance/testdata/connect/connect-check-passes.yaml":"load/projects/pandora/tests/acceptance/testdata/connect/connect-check-passes.yaml",
"tests/acceptance/testdata/connect/connect-ssl.yaml":"load/projects/pandora/tests/acceptance/testdata/connect/connect-ssl.yaml",
"tests/acceptance/testdata/connect/connect.yaml":"load/projects/pandora/tests/acceptance/testdata/connect/connect.yaml",
"tests/acceptance/testdata/connect/payload.uri":"load/projects/pandora/tests/acceptance/testdata/connect/payload.uri",
"tests/acceptance/testdata/connect/payload5.uri":"load/projects/pandora/tests/acceptance/testdata/connect/payload5.uri",
"tests/acceptance/testdata/grpc/base.yaml":"load/projects/pandora/tests/acceptance/testdata/grpc/base.yaml",
"tests/acceptance/testdata/grpc/grpc.payload":"load/projects/pandora/tests/acceptance/testdata/grpc/grpc.payload",
"tests/acceptance/testdata/http/http-check-limit.yaml":"load/projects/pandora/tests/acceptance/testdata/http/http-check-limit.yaml",
Expand Down
26 changes: 18 additions & 8 deletions components/guns/http/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/pkg/errors"
"github.com/yandex/pandora/core"
"github.com/yandex/pandora/core/aggregator/netsample"
"github.com/yandex/pandora/core/warmup"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -48,17 +49,17 @@ type HTTPTraceConfig struct {

func DefaultBaseGunConfig() BaseGunConfig {
return BaseGunConfig{
AutoTagConfig{
AutoTag: AutoTagConfig{
Enabled: false,
URIElements: 2,
NoTagOnly: true,
},
AnswLogConfig{
AnswLog: AnswLogConfig{
Enabled: false,
Path: "answ.log",
Filter: "error",
},
HTTPTraceConfig{
HTTPTrace: HTTPTraceConfig{
DumpEnabled: false,
TraceEnabled: false,
},
Expand All @@ -68,17 +69,26 @@ func DefaultBaseGunConfig() BaseGunConfig {
type BaseGun struct {
DebugLog bool // Automaticaly set in Bind if Log accepts debug messages.
Config BaseGunConfig
Do func(r *http.Request) (*http.Response, error) // Required.
Connect func(ctx context.Context) error // Optional hook.
OnClose func() error // Optional. Called on Close().
Aggregator netsample.Aggregator // Lazy set via BindResultTo.
Connect func(ctx context.Context) error // Optional hook.
OnClose func() error // Optional. Called on Close().
Aggregator netsample.Aggregator // Lazy set via BindResultTo.
AnswLog *zap.Logger

scheme string
hostname string
targetResolved string
client Client

core.GunDeps
}

var _ Gun = (*BaseGun)(nil)
var _ io.Closer = (*BaseGun)(nil)

func (b *BaseGun) WarmUp(_ *warmup.Options) (any, error) {
return nil, nil
}

func (b *BaseGun) Bind(aggregator netsample.Aggregator, deps core.GunDeps) error {
log := deps.Log
if ent := log.Check(zap.DebugLevel, "Gun bind"); ent != nil {
Expand Down Expand Up @@ -157,7 +167,7 @@ func (b *BaseGun) Shoot(ammo Ammo) {
}
}
var res *http.Response
res, err = b.Do(req)
res, err = b.client.Do(req)
if b.Config.HTTPTrace.TraceEnabled && timings != nil {
sample.SetReceiveTime(timings.GetReceiveTime())
}
Expand Down
55 changes: 46 additions & 9 deletions components/guns/http/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,38 @@ func (a *ammoMock) IsInvalid() bool {
return false
}

type testDecoratedClient struct {
client Client
t *testing.T
before func(req *http.Request)
after func(req *http.Request, res *http.Response, err error)
returnRes *http.Response
returnErr error
}

func (c *testDecoratedClient) Do(req *http.Request) (*http.Response, error) {
if c.before != nil {
c.before(req)
}
if c.client == nil {
return c.returnRes, c.returnErr
}
res, err := c.client.Do(req)
if c.after != nil {
c.after(req, res, err)
}
return res, err
}

func (c *testDecoratedClient) CloseIdleConnections() {
c.client.CloseIdleConnections()
}

func (s *BaseGunSuite) Test_Shoot_BeforeBindPanics() {
s.base.Do = func(*http.Request) (_ *http.Response, _ error) {
panic("should not be called")
s.base.client = &testDecoratedClient{
client: s.base.client,
before: func(req *http.Request) { panic("should not be called\"") },
after: nil,
}
am := &ammoMock{}

Expand Down Expand Up @@ -152,9 +181,15 @@ func (s *BaseGunSuite) Test_Shoot() {
beforeEachDoOk := func() {
body = ioutil.NopCloser(strings.NewReader("aaaaaaa"))
s.base.AnswLog = zap.NewNop()
s.base.Do = func(doReq *http.Request) (*http.Response, error) {
s.Require().Equal(req, doReq)
return res, nil
s.base.client = &testDecoratedClient{
before: func(doReq *http.Request) {
s.Require().Equal(req, doReq)
},
returnRes: &http.Response{
StatusCode: http.StatusNotFound,
Body: ioutil.NopCloser(body),
Request: req,
},
}
}
s.Run("ammo sample sent to results", func() {
Expand Down Expand Up @@ -232,10 +267,12 @@ func (s *BaseGunSuite) Test_Shoot() {
connectCalled = true
return nil
}
oldDo := s.base.Do
s.base.Do = func(r *http.Request) (*http.Response, error) {
doCalled = true
return oldDo(r)

s.base.client = &testDecoratedClient{
client: s.base.client,
before: func(doReq *http.Request) {
doCalled = true
},
}
}
s.Run("Connect called", func() {
Expand Down
32 changes: 29 additions & 3 deletions components/guns/http/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ type Client interface {
}

type ClientConfig struct {
Redirect bool // When true, follow HTTP redirects.
Dialer DialerConfig `config:"dial"`
Transport TransportConfig `config:",squash"`
Redirect bool // When true, follow HTTP redirects.
Dialer DialerConfig `config:"dial"`
Transport TransportConfig `config:",squash"`
ConnectSSL bool `config:"connect-ssl"` // Defines if tunnel encrypted.
}

type clientConstructor func(clientConfig ClientConfig, target string) Client

func DefaultClientConfig() ClientConfig {
return ClientConfig{
Transport: DefaultTransportConfig(),
Expand Down Expand Up @@ -170,6 +173,29 @@ func (c *panicOnHTTP1Client) Do(req *http.Request) (*http.Response, error) {
return res, nil
}

type httpDecoratedClient struct {
client Client
scheme string
hostname string
targetResolved string
}

func (c *httpDecoratedClient) Do(req *http.Request) (*http.Response, error) {
if req.Host == "" {
req.Host = c.hostname
}

if c.targetResolved != "" {
req.URL.Host = c.targetResolved
}
req.URL.Scheme = c.scheme
return c.client.Do(req)
}

func (c *httpDecoratedClient) CloseIdleConnections() {
c.client.CloseIdleConnections()
}

func checkHTTP2(state *tls.ConnectionState) error {
if state == nil {
return errors.New("http2: non TLS connection")
Expand Down
79 changes: 31 additions & 48 deletions components/guns/http/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,68 +14,51 @@ import (
"go.uber.org/zap"
)

type ConnectGunConfig struct {
Target string `validate:"endpoint,required"`
ConnectSSL bool `config:"connect-ssl"` // Defines if tunnel encrypted.
SSL bool // As in HTTP gun, defines scheme for http requests.
Client ClientConfig `config:",squash"`
BaseGunConfig `config:",squash"`
}

func NewConnectGun(conf ConnectGunConfig, answLog *zap.Logger) *ConnectGun {
func NewConnectGun(cfg HTTPGunConfig, answLog *zap.Logger) *BaseGun {
scheme := "http"
if conf.SSL {
if cfg.SSL {
scheme = "https"
}
client := newConnectClient(conf)
var g ConnectGun
g = ConnectGun{
BaseGun: BaseGun{
Config: conf.BaseGunConfig,
Do: g.Do,
OnClose: func() error {
client.CloseIdleConnections()
return nil
},
AnswLog: answLog,
client := newConnectClient(cfg.Client, cfg.Target)
wrappedClient := &httpDecoratedClient{
client: client,
scheme: scheme,
hostname: "",
targetResolved: cfg.Target,
}
return &BaseGun{
Config: cfg.Base,
OnClose: func() error {
client.CloseIdleConnections()
return nil
},
scheme: scheme,
client: client,
AnswLog: answLog,
client: wrappedClient,
}
return &g
}

type ConnectGun struct {
BaseGun
scheme string
client Client
}

var _ Gun = (*ConnectGun)(nil)

func (g *ConnectGun) Do(req *http.Request) (*http.Response, error) {
req.URL.Scheme = g.scheme
return g.client.Do(req)
}

func DefaultConnectGunConfig() ConnectGunConfig {
return ConnectGunConfig{
SSL: false,
ConnectSSL: false,
Client: DefaultClientConfig(),
func DefaultConnectGunConfig() HTTPGunConfig {
return HTTPGunConfig{
SSL: false,
Client: DefaultClientConfig(),
Base: DefaultBaseGunConfig(),
}
}

func newConnectClient(conf ConnectGunConfig) Client {
transport := NewTransport(conf.Client.Transport,
func newConnectClient(conf ClientConfig, target string) Client {
transport := NewTransport(
conf.Transport,
newConnectDialFunc(
conf.Target,
target,
conf.ConnectSSL,
NewDialer(conf.Client.Dialer),
), conf.Target)
return newClient(transport, conf.Client.Redirect)
NewDialer(conf.Dialer),
),
target)
return newClient(transport, conf.Redirect)
}

var _ clientConstructor = newConnectClient

func newConnectDialFunc(target string, connectSSL bool, dialer netutil.Dialer) netutil.DialerFunc {
return func(ctx context.Context, network, address string) (conn net.Conn, err error) {
// TODO(skipor): make connect sample.
Expand Down
16 changes: 9 additions & 7 deletions components/guns/http/connect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import (
"go.uber.org/zap"
)

var tunnelHandler = func(t *testing.T, originURL string) http.Handler {
var tunnelHandler = func(t *testing.T, originURL string, compareURI bool) http.Handler {
u, err := url.Parse(originURL)
require.NoError(t, err)
originHost := u.Host
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, originHost, r.RequestURI)
if compareURI {
require.Equal(t, originHost, r.RequestURI)
}

toOrigin, err := net.Dial("tcp", originHost)
require.NoError(t, err)
Expand Down Expand Up @@ -60,24 +62,24 @@ func TestDo(t *testing.T) {

var proxy *httptest.Server
if tunnelSSL {
proxy = httptest.NewTLSServer(tunnelHandler(t, origin.URL))
proxy = httptest.NewTLSServer(tunnelHandler(t, origin.URL, true))
} else {
proxy = httptest.NewServer(tunnelHandler(t, origin.URL))
proxy = httptest.NewServer(tunnelHandler(t, origin.URL, true))
}
defer proxy.Close()

req, err := http.NewRequest("GET", origin.URL, nil)
require.NoError(t, err)

conf := DefaultConnectGunConfig()
conf.ConnectSSL = tunnelSSL
conf.Client.ConnectSSL = tunnelSSL
scheme := "http://"
if tunnelSSL {
scheme = "https://"
}
conf.Target = strings.TrimPrefix(proxy.URL, scheme)

client := newConnectClient(conf)
client := newConnectClient(conf.Client, conf.Target)

res, err := client.Do(req)
require.NoError(t, err)
Expand All @@ -91,7 +93,7 @@ func TestNewConnectGun(t *testing.T) {
rw.WriteHeader(http.StatusOK)
}))
defer origin.Close()
proxy := httptest.NewServer(tunnelHandler(t, origin.URL))
proxy := httptest.NewServer(tunnelHandler(t, origin.URL, false))
defer proxy.Close()

log := zap.NewNop()
Expand Down
Loading

0 comments on commit 7985a66

Please sign in to comment.