Skip to content

Commit

Permalink
More tests for web, diag, and grpc servers
Browse files Browse the repository at this point in the history
  • Loading branch information
z4kn4fein committed Mar 7, 2024
1 parent 884a97a commit c514b98
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 23 deletions.
102 changes: 102 additions & 0 deletions diag/server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package diag

import (
"github.com/configcat/configcat-proxy/config"
"github.com/configcat/configcat-proxy/diag/metrics"
"github.com/configcat/configcat-proxy/diag/status"
"github.com/configcat/configcat-proxy/log"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)

func TestNewServer(t *testing.T) {
errChan := make(chan error)
conf := config.DiagConfig{
Port: 5050,
Enabled: true,
Status: config.StatusConfig{Enabled: true},
Metrics: config.MetricsConfig{Enabled: true},
}
srv := NewServer(&conf, status.NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"sdk": {Key: "key"}}}), metrics.NewReporter(), log.NewNullLogger(), errChan)
go srv.Listen()

req, _ := http.NewRequest(http.MethodGet, "http://localhost:5050/status", http.NoBody)
resp, err := http.DefaultClient.Do(req)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)

req, _ = http.NewRequest(http.MethodGet, "http://localhost:5050/metrics", http.NoBody)
resp, err = http.DefaultClient.Do(req)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)

srv.Shutdown()

assert.Nil(t, readFromErrChan(errChan))
}

func TestNewServer_NotEnabled(t *testing.T) {
errChan := make(chan error)
conf := config.DiagConfig{
Port: 5050,
Enabled: true,
Status: config.StatusConfig{Enabled: false},
Metrics: config.MetricsConfig{Enabled: false},
}

srv := NewServer(&conf, status.NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"sdk": {Key: "key"}}}), metrics.NewReporter(), log.NewNullLogger(), errChan)
go srv.Listen()

req, _ := http.NewRequest(http.MethodGet, "http://localhost:5050/status", http.NoBody)
resp, err := http.DefaultClient.Do(req)
assert.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)

req, _ = http.NewRequest(http.MethodGet, "http://localhost:5050/metrics", http.NoBody)
resp, err = http.DefaultClient.Do(req)
assert.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)

srv.Shutdown()

assert.Nil(t, readFromErrChan(errChan))
}

func TestNewServer_NilReporters(t *testing.T) {
errChan := make(chan error)
conf := config.DiagConfig{
Port: 5050,
Enabled: true,
Status: config.StatusConfig{Enabled: true},
Metrics: config.MetricsConfig{Enabled: true},
}
srv := NewServer(&conf, nil, nil, log.NewNullLogger(), errChan)
go srv.Listen()

req, _ := http.NewRequest(http.MethodGet, "http://localhost:5050/status", http.NoBody)
resp, err := http.DefaultClient.Do(req)
assert.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)

req, _ = http.NewRequest(http.MethodGet, "http://localhost:5050/metrics", http.NoBody)
resp, err = http.DefaultClient.Do(req)
assert.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)

srv.Shutdown()

assert.Nil(t, readFromErrChan(errChan))
}

func readFromErrChan(ch chan error) error {
select {
case val, ok := <-ch:
if ok {
return val
}
default:
return nil
}
return nil
}
5 changes: 3 additions & 2 deletions grpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type Server struct {
errorChannel chan error
}

func NewServer(sdkClients map[string]sdk.Client, metrics metrics.Reporter, conf *config.Config, logger log.Logger, errorChan chan error) *Server {
func NewServer(sdkClients map[string]sdk.Client, metrics metrics.Reporter, conf *config.Config, logger log.Logger, errorChan chan error) (*Server, error) {
grpcLog := logger.WithLevel(conf.Grpc.Log.GetLevel()).WithPrefix("grpc")
opts := make([]grpc.ServerOption, 0)
if conf.Tls.Enabled {
Expand All @@ -36,6 +36,7 @@ func NewServer(sdkClients map[string]sdk.Client, metrics metrics.Reporter, conf
t.Certificates = append(t.Certificates, cert)
} else {
grpcLog.Errorf("failed to load the certificate and key pair: %s", err)
return nil, err
}
}
opts = append(opts, grpc.Creds(credentials.NewTLS(t)))
Expand All @@ -53,7 +54,7 @@ func NewServer(sdkClients map[string]sdk.Client, metrics metrics.Reporter, conf
errorChannel: errorChan,
grpcServer: grpcServer,
conf: conf,
}
}, nil
}

func (s *Server) Listen() {
Expand Down
175 changes: 175 additions & 0 deletions grpc/server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package grpc

import (
"github.com/configcat/configcat-proxy/config"
"github.com/configcat/configcat-proxy/internal/testutils"
"github.com/configcat/configcat-proxy/internal/utils"
"github.com/configcat/configcat-proxy/log"
"github.com/configcat/configcat-proxy/sdk"
"github.com/configcat/go-sdk/v9/configcattest"
"github.com/stretchr/testify/assert"
"net/http/httptest"
"strings"
"sync"
"testing"
"time"
)

func TestNewServer(t *testing.T) {
errChan := make(chan error)

key := configcattest.RandomSDKKey()
var h configcattest.Handler
_ = h.SetFlags(key, map[string]*configcattest.Flag{
"flag": {
Default: "test1",
},
})
sdkSrv := httptest.NewServer(&h)
defer sdkSrv.Close()

ctx := testutils.NewTestSdkContext(&config.SDKConfig{BaseUrl: sdkSrv.URL, Key: key, PollInterval: 1}, nil)
sdkClient := sdk.NewClient(ctx, log.NewNullLogger())
defer sdkClient.Close()

srv, _ := NewServer(map[string]sdk.Client{"test": sdkClient}, nil, &config.Config{Grpc: config.GrpcConfig{Port: 5060}}, log.NewNullLogger(), errChan)

wg := sync.WaitGroup{}
wg.Add(1)
go func() {
srv.Listen()
wg.Done()
}()
time.Sleep(1 * time.Second)
srv.Shutdown()
wg.Wait()

assert.Nil(t, readFromErrChan(errChan))
}

func TestNewServer_TLS(t *testing.T) {
utils.UseTempFile(`
-----BEGIN CERTIFICATE-----
MIICrzCCAZcCFDnpdKF+Pg1smjtIXrNdIgxGYEJfMA0GCSqGSIb3DQEBCwUAMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMzAzMDEyMTA2NThaFw0yNDAyMjkyMTA2
NThaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAOiTDTjfAPvJLDZ2mwNvu0pohSHPRzzfZRc16iVI6+ESl0Dwjdjl
yERFO/ts1GQnhE2ggykvoxH4zUy1OCnjTJ+Mm1ryjy4G5ZIILIF9MfFcyma5/5Xd
oOTcDr3ZDTAwFaabKYKisoVMHAJCphencgoyOToW5/HRHMKOEpTJOQWSyNduXYfY
nsWb3hx7WD9NajliW7/Jjbf7UnDtKY2VM2GZWT3ygIH/7SlBqyuXJNqyZXbqfbrP
6mdZQ5wvYsnSUU4kNMtZg/ns+0H5R7PFmRhIRM0nZvJZTO9oHREdm+e2nnZwHyJF
Z26LxE7Qr1bn8+PQSydyQIqeUdaSX2LuXqECAwEAATANBgkqhkiG9w0BAQsFAAOC
AQEAjRoOTe4W4OQ6YOo5kx5sMAozh0Rg6eifS0s8GuxKwfuBop8FEnM3wAfF6x3J
fsik9MmoM4L11HWjttb46UFq/rP3GsA3DLX8i1yBOES+iyCELd5Ss9q1jfr/Jqo3
cAanE4yl3NNEZoDmMdSj2U11BneKSzHDR+l2hDF9wBifWGI9DQ1ItfA5I6MwnL+0
J03vcwPSwme4bKC/avAT2oDD7jLGLA+kuhMqHvVq7nXRzs46xyFPBBv7fBxXjPPG
c89d0ISafKtZ9kIKaRrzu2HX+b0fzKr0vtHYDLtC1U5oU7GPB12eupERkmWYlhrw
hDL3X7kt3jEZFkzGV1XL1IJx/g==
-----END CERTIFICATE-----`, func(certFile string) {
utils.UseTempFile(`-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDokw043wD7ySw2
dpsDb7tKaIUhz0c832UXNeolSOvhEpdA8I3Y5chERTv7bNRkJ4RNoIMpL6MR+M1M
tTgp40yfjJta8o8uBuWSCCyBfTHxXMpmuf+V3aDk3A692Q0wMBWmmymCorKFTBwC
QqYXp3IKMjk6Fufx0RzCjhKUyTkFksjXbl2H2J7Fm94ce1g/TWo5Ylu/yY23+1Jw
7SmNlTNhmVk98oCB/+0pQasrlyTasmV26n26z+pnWUOcL2LJ0lFOJDTLWYP57PtB
+UezxZkYSETNJ2byWUzvaB0RHZvntp52cB8iRWdui8RO0K9W5/Pj0EsnckCKnlHW
kl9i7l6hAgMBAAECggEBAOMWiqeIH5a6BGCdiJhfZZmu2qd7k8xdOIDkVN7ZB/B5
TZTMDUTGgLggfgPubKfqaeW+H7N8XxZyQEtw+wjzduKm0R6JjsJbW5cuQf6htr08
ZCjP3j5/69TrBb3bjGQL32gRQwPaRsOe4A5Y84JPLivEhFoy+YEFNLbHMF905yeH
IaSeqeK0GNm0a/MU68pa1ODIc8B2zqo+f6I9qekezlDR7Or487FqnlLtNf0yvnLD
sbshzj5rzLdLYgA/RNZ4CkuGddxEYjnDB1IG0NX8m9MrHlsi7jqxa7pHt5oDrRsW
ZxBez6Q70dE29sdl5lnce3qjxweB2NK3Q6Cr2eyizwECgYEA/L/WzgY1yDMWzaCr
SRThg9NWO1EYbvz4uxt7rElfZ+NYAaT08E35Ooo9IeBzp3VoFA1PcNQnKB5pgczO
Mu5W/td5zpx1dzguBZAl4IpKkml08i06R7FxxTqtRM/P7Pna+RagtqAo3JZww3bd
ofIPH2OrobqlcFhOsLqKp5ocDNECgYEA65DJsImeBfW1aZ5ABgPr7NErSv2fKj1r
eGsgC5Za1ZiaG5LWkCpuezsvf6ma4EN3CMl5Fo617qaY6mnL2HlfVtFhHYSeLpna
9ZgqZ1zj2HkqiXOPEkb3d3cC61rXiMK97NpshrpzFx+uMCH8MMu9/CVJEHNKGgAq
6zZQ4LhjaNECgYEA3W4UeprmM2bO64d/iJ9Kk3traLw7c8EdCI+jYeVGOHXsfERQ
ctddKfRCapOBv4wUiry+hFLZm0RJmvYbEHPOs6WDiYd5QeFuMGGBTZ7ahjrtwd3t
2TGUQv6NHmQR/cNIHEG+u0DFi7whPp28vkybAx0HGMG0fyBekGZdY0iYmoECgYEA
3mVOlVYHk9ba1AEsrsErDuSXe/AgQa/E8+YnVek4jqnI7LlfyrHUppFFEcDdUFdB
XVFg+ZP4XXx5p+4EHrbP9NYuWsDm2lY1K2Livb0r+ybBqw0niPjpD6eTYQHdtOcu
ihvZFAWZPL6TJCwhvSvNjOziox5FWnDIFFKuXsqWR9ECgYAfiG1izToF+GX3yUPq
CU+ceTbM2uy3hVnQLvCnraN7hkF02Fa9ZwP6nmnsvhfdaIUP5WLm3A+qMWu/PL0i
F/dUCUF6M/DyihQUnOl+MD9Sg89ZHiftqXSY8jGR14uH4woStyUFHiFbtajmnqV7
MK4Li/LGWcksyoF+hbPNXMFCIA==
-----END PRIVATE KEY-----
`, func(keyFile string) {
errChan := make(chan error)
tlsConf := config.TlsConfig{
Enabled: true,
Certificates: []config.CertConfig{
{Cert: strings.ReplaceAll(certFile, "\\", "/"), Key: strings.ReplaceAll(keyFile, "\\", "/")},
},
}

key := configcattest.RandomSDKKey()
var h configcattest.Handler
_ = h.SetFlags(key, map[string]*configcattest.Flag{
"flag": {
Default: "test1",
},
})
sdkSrv := httptest.NewServer(&h)
defer sdkSrv.Close()

ctx := testutils.NewTestSdkContext(&config.SDKConfig{BaseUrl: sdkSrv.URL, Key: key, PollInterval: 1}, nil)
sdkClient := sdk.NewClient(ctx, log.NewNullLogger())
defer sdkClient.Close()

srv, _ := NewServer(map[string]sdk.Client{"test": sdkClient}, nil, &config.Config{Grpc: config.GrpcConfig{Port: 5060}, Tls: tlsConf}, log.NewNullLogger(), errChan)

wg := sync.WaitGroup{}
wg.Add(1)
go func() {
srv.Listen()
wg.Done()
}()
time.Sleep(1 * time.Second)
srv.Shutdown()
wg.Wait()

assert.Nil(t, readFromErrChan(errChan))
})

})
}

func TestNewServer_TLS_Missing_Cert(t *testing.T) {
errChan := make(chan error)
tlsConf := config.TlsConfig{
Enabled: true,
Certificates: []config.CertConfig{
{Cert: "./non-existing.cert", Key: "./non-existing.key"},
},
}

key := configcattest.RandomSDKKey()
var h configcattest.Handler
_ = h.SetFlags(key, map[string]*configcattest.Flag{
"flag": {
Default: "test1",
},
})
sdkSrv := httptest.NewServer(&h)
defer sdkSrv.Close()

ctx := testutils.NewTestSdkContext(&config.SDKConfig{BaseUrl: sdkSrv.URL, Key: key, PollInterval: 1}, nil)
sdkClient := sdk.NewClient(ctx, log.NewNullLogger())
defer sdkClient.Close()

_, err := NewServer(map[string]sdk.Client{"test": sdkClient}, nil, &config.Config{Grpc: config.GrpcConfig{Port: 5060}, Tls: tlsConf}, log.NewDebugLogger(), errChan)
assert.Error(t, err)
}

func readFromErrChan(ch chan error) error {
select {
case val, ok := <-ch:
if ok {
return val
}
default:
return nil
}
return nil
}
13 changes: 11 additions & 2 deletions internal/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,17 @@ log:
level: "debug"

grpc:
enabled: false
enabled: true
port: 50052

diag:
enabled: false

http:
port: 8090
port: 8090

tls:
enabled: true
certificates:
- cert: "./internal/resources/cert/localhost.crt"
key: "./internal/resources/cert/localhost.key"
23 changes: 17 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import (
"syscall"
)

const (
exitOk = iota
exitFailure
)

func main() {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
Expand All @@ -33,12 +38,12 @@ func run(closeSignal chan os.Signal) int {
conf, err := config.LoadConfigFromFileAndEnvironment(configFile)
if err != nil {
logger.Errorf("%s", err)
return 1
return exitFailure
}
err = conf.Validate()
if err != nil {
logger.Errorf("%s", err)
return 1
return exitFailure
}

logger = logger.WithLevel(conf.Log.GetLevel())
Expand Down Expand Up @@ -76,12 +81,18 @@ func run(closeSignal chan os.Signal) int {
}
router := web.NewRouter(sdkClients, metricsReporter, statusReporter, &conf.Http, logger)

httpServer := web.NewServer(router.Handler(), logger, &conf, errorChan)
httpServer, err := web.NewServer(router.Handler(), logger, &conf, errorChan)
if err != nil {
return exitFailure
}
httpServer.Listen()

var grpcServer *grpc.Server
if conf.Grpc.Enabled {
grpcServer = grpc.NewServer(sdkClients, metricsReporter, &conf, logger, errorChan)
grpcServer, err = grpc.NewServer(sdkClients, metricsReporter, &conf, logger, errorChan)
if err != nil {
return exitFailure
}
grpcServer.Listen()
}

Expand Down Expand Up @@ -119,10 +130,10 @@ func run(closeSignal chan os.Signal) int {
}()
}
wg.Wait()
return 0
return exitOk
case err = <-errorChan:
logger.Errorf("%s", err)
return 1
return exitFailure
}
}
}
2 changes: 1 addition & 1 deletion web/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (s *HttpRouter) setupSSERoutes(conf *config.SseConfig, sdkClients map[strin
s.router.HandlerFunc(endpoint.method, endpoint.path, endpoint.handler)
s.router.HandlerFunc(http.MethodOptions, endpoint.path, endpoint.handler)
}
l.Reportf("SSE enabled, listening on path: /sse/:sdkId/*")
l.Reportf("SSE enabled, accepting requests on path: /sse/:sdkId/*")
}

func (s *HttpRouter) setupWebhookRoutes(conf *config.WebhookConfig, sdkClients map[string]sdk.Client, l log.Logger) {
Expand Down
Loading

0 comments on commit c514b98

Please sign in to comment.