Skip to content

Commit 6a4ba89

Browse files
authored
Merge pull request #42 from gatewayd-io/add-more-tests
Add more tests and a plugin test job
2 parents e1e9913 + 55d91a1 commit 6a4ba89

File tree

10 files changed

+361
-90
lines changed

10 files changed

+361
-90
lines changed

.github/workflows/test.yaml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,71 @@ jobs:
3434
# uses: shogo82148/actions-goveralls@v1
3535
# with:
3636
# path-to-profile: profile.cov
37+
38+
test-plugins:
39+
name: Test GatewayD Plugins
40+
runs-on: ubuntu-latest
41+
services:
42+
postgres:
43+
image: postgres
44+
env:
45+
POSTGRES_HOST: postgres
46+
POSTGRES_USER: postgres
47+
POSTGRES_PASSWORD: postgres
48+
ports:
49+
- 5432:5432
50+
options: >-
51+
--health-cmd pg_isready
52+
--health-interval 10s
53+
--health-timeout 5s
54+
--health-retries 5
55+
steps:
56+
- name: Checkout 🛎️
57+
uses: actions/checkout@v3
58+
with:
59+
fetch-depth: 0
60+
61+
- name: Checkout test plugin 🛎️
62+
uses: actions/checkout@v3
63+
with:
64+
repository: gatewayd-io/gatewayd-plugin-test
65+
path: gatewayd-plugin-test
66+
token: ${{ secrets.GH_PLUGIN_TOKEN }}
67+
68+
- name: Install Go 🧑‍💻
69+
uses: actions/setup-go@v3
70+
with:
71+
go-version: '1.18'
72+
73+
- name: Build test plugin 🏗️
74+
run: |
75+
# Build GatewayD
76+
make build
77+
# Build test plugin
78+
cd gatewayd-plugin-test && make build && cp gatewayd-plugin-test ../gdp-test && cd ..
79+
export SHA256SUM=$(sha256sum gdp-test | awk '{print $1}')
80+
cat <<EOF > gatewayd_plugins.yaml
81+
gatewayd-plugin-test:
82+
enabled: True
83+
localPath: ./gdp-test
84+
checksum: ${SHA256SUM}
85+
EOF
86+
87+
- name: Run GatewayD with test plugin 🚀
88+
run: |
89+
./gatewayd run &
90+
91+
- name: Run a test with PSQL 🧪
92+
run: |
93+
sudo apt-get update
94+
sudo apt-get install --yes --no-install-recommends postgresql-client
95+
psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -c "CREATE DATABASE gatewayd_test;"
96+
psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d ${DBNAME} -c "CREATE TABLE test_table (id serial PRIMARY KEY, name varchar(255));"
97+
psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d ${DBNAME} -c "INSERT INTO test_table (name) VALUES ('test');"
98+
psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d ${DBNAME} -c "SELECT * FROM test_table;" | grep test
99+
env:
100+
DBNAME: gatewayd_test
101+
PGUSER: postgres
102+
PGPASSWORD: postgres
103+
PGHOST: localhost
104+
PGPORT: 15432

cmd/run.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,7 @@ var runCmd = &cobra.Command{
9696
// This is a notification hook, so we don't care about the result.
9797
data, err := structpb.NewStruct(map[string]interface{}{
9898
"timeFormat": loggerCfg.TimeFormat,
99-
"level": loggerCfg.Level,
100-
"output": loggerCfg.Output,
99+
"level": loggerCfg.Level.String(),
101100
"noColor": loggerCfg.NoColor,
102101
})
103102
if err != nil {
@@ -179,7 +178,11 @@ var runCmd = &cobra.Command{
179178
proxyCfg, err := structpb.NewStruct(map[string]interface{}{
180179
"elastic": elastic,
181180
"reuseElasticClients": reuseElasticClients,
182-
"clientConfig": elasticClientConfig,
181+
"clientConfig": map[string]interface{}{
182+
"network": elasticClientConfig.Network,
183+
"address": elasticClientConfig.Address,
184+
"receiveBufferSize": elasticClientConfig.ReceiveBufferSize,
185+
},
183186
})
184187
if err != nil {
185188
logger.Error().Err(err).Msg("Failed to convert proxy config to structpb")
@@ -240,19 +243,19 @@ var runCmd = &cobra.Command{
240243
"address": serverConfig.Address,
241244
"softLimit": serverConfig.SoftLimit,
242245
"hardLimit": serverConfig.HardLimit,
243-
"tickInterval": serverConfig.TickInterval,
246+
"tickInterval": serverConfig.TickInterval.Seconds(),
244247
"multiCore": serverConfig.MultiCore,
245248
"lockOSThread": serverConfig.LockOSThread,
246249
"enableTicker": serverConfig.EnableTicker,
247-
"loadBalancer": serverConfig.LoadBalancer,
250+
"loadBalancer": int(serverConfig.LoadBalancer),
248251
"readBufferCap": serverConfig.ReadBufferCap,
249252
"writeBufferCap": serverConfig.WriteBufferCap,
250253
"socketRecvBuffer": serverConfig.SocketRecvBuffer,
251254
"socketSendBuffer": serverConfig.SocketSendBuffer,
252255
"reuseAddress": serverConfig.ReuseAddress,
253256
"reusePort": serverConfig.ReusePort,
254-
"tcpKeepAlive": serverConfig.TCPKeepAlive,
255-
"tcpNoDelay": serverConfig.TCPNoDelay,
257+
"tcpKeepAlive": serverConfig.TCPKeepAlive.Seconds(),
258+
"tcpNoDelay": int(serverConfig.TCPNoDelay),
256259
})
257260
if err != nil {
258261
logger.Error().Err(err).Msg("Failed to convert server config to structpb")
@@ -281,7 +284,8 @@ var runCmd = &cobra.Command{
281284
for _, s := range signals {
282285
if sig != s {
283286
// Notify the hooks that the server is shutting down
284-
signalCfg, err := structpb.NewStruct(map[string]interface{}{"signal": sig})
287+
signalCfg, err := structpb.NewStruct(
288+
map[string]interface{}{"signal": sig.String()})
285289
if err != nil {
286290
logger.Error().Err(err).Msg(
287291
"Failed to convert signal config to structpb")

logging/logging_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package logging
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"testing"
7+
8+
"github.com/rs/zerolog"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestNewLogger(t *testing.T) {
13+
var buffer bytes.Buffer
14+
logger := NewLogger(
15+
LoggerConfig{
16+
Output: &buffer,
17+
Level: zerolog.DebugLevel,
18+
TimeFormat: zerolog.TimeFormatUnix,
19+
NoColor: true,
20+
},
21+
)
22+
assert.NotNil(t, logger)
23+
24+
var msg interface{}
25+
err := json.Unmarshal(buffer.Bytes(), &msg)
26+
assert.NoError(t, err)
27+
28+
if jsonMsg, ok := msg.(map[string]interface{}); ok {
29+
// This is created when the logger is created and
30+
// is used to test that the logger is working.
31+
assert.Equal(t, "Created a new logger", jsonMsg["message"])
32+
assert.Equal(t, "debug", jsonMsg["level"])
33+
} else {
34+
t.Fail()
35+
}
36+
37+
buffer.Reset()
38+
39+
logger.Error().Str("key", "key").Msg("This is an error")
40+
var msg2 interface{}
41+
err = json.Unmarshal(buffer.Bytes(), &msg2)
42+
assert.NoError(t, err)
43+
44+
if jsonMsg, ok := msg2.(map[string]interface{}); ok {
45+
assert.Equal(t, "This is an error", jsonMsg["message"])
46+
assert.Equal(t, "error", jsonMsg["level"])
47+
assert.Equal(t, "key", jsonMsg["key"])
48+
} else {
49+
t.Fail()
50+
}
51+
}

network/server.go

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ func (s *Server) OnBoot(engine gnet.Engine) gnet.Action {
4444
s.logger.Debug().Msg("GatewayD is booting...")
4545

4646
onBootingData, err := structpb.NewStruct(map[string]interface{}{
47-
"server": s,
48-
"engine": engine,
47+
"status": string(s.Status),
4948
})
5049
if err != nil {
5150
s.logger.Error().Err(err).Msg("Failed to create structpb")
@@ -63,8 +62,7 @@ func (s *Server) OnBoot(engine gnet.Engine) gnet.Action {
6362
s.Status = Running
6463

6564
onBootedData, err := structpb.NewStruct(map[string]interface{}{
66-
"server": s,
67-
"engine": engine,
65+
"status": string(s.Status),
6866
})
6967
if err != nil {
7068
s.logger.Error().Err(err).Msg("Failed to create structpb")
@@ -85,8 +83,10 @@ func (s *Server) OnOpen(gconn gnet.Conn) ([]byte, gnet.Action) {
8583
s.logger.Debug().Msgf("GatewayD is opening a connection from %s", gconn.RemoteAddr().String())
8684

8785
onOpeningData, err := structpb.NewStruct(map[string]interface{}{
88-
"server": s,
89-
"gconn": gconn,
86+
"client": map[string]interface{}{
87+
"local": gconn.LocalAddr().String(),
88+
"remote": gconn.RemoteAddr().String(),
89+
},
9090
})
9191
if err != nil {
9292
s.logger.Error().Err(err).Msg("Failed to create structpb")
@@ -117,8 +117,10 @@ func (s *Server) OnOpen(gconn gnet.Conn) ([]byte, gnet.Action) {
117117
}
118118

119119
onOpenedData, err := structpb.NewStruct(map[string]interface{}{
120-
"server": s,
121-
"gconn": gconn,
120+
"client": map[string]interface{}{
121+
"local": gconn.LocalAddr().String(),
122+
"remote": gconn.RemoteAddr().String(),
123+
},
122124
})
123125
if err != nil {
124126
s.logger.Error().Err(err).Msg("Failed to create structpb")
@@ -137,9 +139,11 @@ func (s *Server) OnClose(gconn gnet.Conn, err error) gnet.Action {
137139
s.logger.Debug().Msgf("GatewayD is closing a connection from %s", gconn.RemoteAddr().String())
138140

139141
onClosingData, err := structpb.NewStruct(map[string]interface{}{
140-
"server": s,
141-
"gconn": gconn,
142-
"error": err,
142+
"client": map[string]interface{}{
143+
"local": gconn.LocalAddr().String(),
144+
"remote": gconn.RemoteAddr().String(),
145+
},
146+
"error": err,
143147
})
144148
if err != nil {
145149
s.logger.Error().Err(err).Msg("Failed to create structpb")
@@ -160,9 +164,11 @@ func (s *Server) OnClose(gconn gnet.Conn, err error) gnet.Action {
160164
}
161165

162166
onClosedData, err := structpb.NewStruct(map[string]interface{}{
163-
"server": s,
164-
"gconn": gconn,
165-
"error": err,
167+
"client": map[string]interface{}{
168+
"local": gconn.LocalAddr().String(),
169+
"remote": gconn.RemoteAddr().String(),
170+
},
171+
"error": err,
166172
})
167173
if err != nil {
168174
s.logger.Error().Err(err).Msg("Failed to create structpb")
@@ -179,8 +185,10 @@ func (s *Server) OnClose(gconn gnet.Conn, err error) gnet.Action {
179185

180186
func (s *Server) OnTraffic(gconn gnet.Conn) gnet.Action {
181187
onTrafficData, err := structpb.NewStruct(map[string]interface{}{
182-
"server": s,
183-
"gconn": gconn,
188+
"client": map[string]interface{}{
189+
"local": gconn.LocalAddr().String(),
190+
"remote": gconn.RemoteAddr().String(),
191+
},
184192
})
185193
if err != nil {
186194
s.logger.Error().Err(err).Msg("Failed to create structpb")
@@ -205,8 +213,7 @@ func (s *Server) OnShutdown(engine gnet.Engine) {
205213
s.logger.Debug().Msg("GatewayD is shutting down...")
206214

207215
onShutdownData, err := structpb.NewStruct(map[string]interface{}{
208-
"server": s,
209-
"engine": engine,
216+
"connections": s.engine.CountConnections(),
210217
})
211218
if err != nil {
212219
s.logger.Error().Err(err).Msg("Failed to create structpb")
@@ -227,7 +234,7 @@ func (s *Server) OnTick() (time.Duration, gnet.Action) {
227234
s.logger.Info().Msgf("Active connections: %d", s.engine.CountConnections())
228235

229236
onTickData, err := structpb.NewStruct(map[string]interface{}{
230-
"server": s,
237+
"connections": s.engine.CountConnections(),
231238
})
232239
if err != nil {
233240
s.logger.Error().Err(err).Msg("Failed to create structpb")
@@ -254,7 +261,6 @@ func (s *Server) Run() error {
254261
// Since gnet.Run is blocking, we need to run OnRun before it
255262
//nolint:nestif
256263
if onRunData, err := structpb.NewStruct(map[string]interface{}{
257-
"server": s,
258264
"address": addr,
259265
"error": err,
260266
}); err != nil {

plugin/hooks_test.go

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -77,65 +77,6 @@ func Test_HookConfig_Run(t *testing.T) {
7777
assert.Nil(t, err)
7878
}
7979

80-
func Test_Verify(t *testing.T) {
81-
params, err := structpb.NewStruct(
82-
map[string]interface{}{
83-
"test": "test",
84-
},
85-
)
86-
assert.Nil(t, err)
87-
88-
returnVal, err := structpb.NewStruct(
89-
map[string]interface{}{
90-
"test": "test",
91-
},
92-
)
93-
assert.Nil(t, err)
94-
95-
assert.True(t, Verify(params, returnVal))
96-
}
97-
98-
func Test_Verify_fail(t *testing.T) {
99-
data := [][]map[string]interface{}{
100-
{
101-
{
102-
"test": "test",
103-
},
104-
{
105-
"test": "test",
106-
"test2": "test2",
107-
},
108-
},
109-
{
110-
{
111-
"test": "test",
112-
"test2": "test2",
113-
},
114-
{
115-
"test": "test",
116-
},
117-
},
118-
{
119-
{
120-
"test": "test",
121-
"test2": "test2",
122-
},
123-
{
124-
"test": "test",
125-
"test3": "test3",
126-
},
127-
},
128-
}
129-
130-
for _, d := range data {
131-
params, err := structpb.NewStruct(d[0])
132-
assert.Nil(t, err)
133-
returnVal, err := structpb.NewStruct(d[1])
134-
assert.Nil(t, err)
135-
assert.False(t, Verify(params, returnVal))
136-
}
137-
}
138-
13980
func Test_HookConfig_Run_PassDown(t *testing.T) {
14081
hooks := NewHookConfig()
14182
// The result of the hook will be nil and will be passed down to the next hook.

plugin/registry.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) {
152152
Managed: true,
153153
MinPort: DefaultMinPort,
154154
MaxPort: DefaultMaxPort,
155+
// TODO: Enable GRPC DialOptions
155156
// GRPCDialOptions: []grpc.DialOption{
156157
// grpc.WithInsecure(),
157158
// },
@@ -189,9 +190,14 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) {
189190
&plugin.Hooks); err != nil {
190191
reg.hooksConfig.Logger.Debug().Err(err).Msg("Failed to decode plugin hooks")
191192
}
192-
if err := mapstructure.Decode(metadata.Fields["config"].GetStructValue().AsMap(),
193-
&plugin.Config); err != nil {
194-
reg.hooksConfig.Logger.Debug().Err(err).Msg("Failed to decode plugin config")
193+
194+
plugin.Config = make(map[string]string)
195+
for key, value := range metadata.Fields["config"].GetStructValue().AsMap() {
196+
if val, ok := value.(string); ok {
197+
plugin.Config[key] = val
198+
} else {
199+
reg.hooksConfig.Logger.Debug().Msgf("Failed to decode plugin config: %s", key)
200+
}
195201
}
196202

197203
reg.Add(plugin)

0 commit comments

Comments
 (0)