You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
6.9 KiB
Go
292 lines
6.9 KiB
Go
package integration
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"sync"
|
|
"testing"
|
|
|
|
internalplugin "github.com/noahlann/nnet/internal/plugin"
|
|
"github.com/noahlann/nnet/pkg/config"
|
|
"github.com/noahlann/nnet/pkg/nnet"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// testPlugin 测试插件实现
|
|
type testPlugin struct {
|
|
name string
|
|
version string
|
|
initCalled bool
|
|
startCalled bool
|
|
stopCalled bool
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
func (p *testPlugin) Name() string {
|
|
return p.name
|
|
}
|
|
|
|
func (p *testPlugin) Version() string {
|
|
return p.version
|
|
}
|
|
|
|
func (p *testPlugin) Init(cfg *config.Config) error {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.initCalled = true
|
|
return nil
|
|
}
|
|
|
|
func (p *testPlugin) Start(ctx context.Context) error {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.startCalled = true
|
|
return nil
|
|
}
|
|
|
|
func (p *testPlugin) Stop(ctx context.Context) error {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.stopCalled = true
|
|
return nil
|
|
}
|
|
|
|
func (p *testPlugin) IsInitCalled() bool {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
return p.initCalled
|
|
}
|
|
|
|
func (p *testPlugin) IsStartCalled() bool {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
return p.startCalled
|
|
}
|
|
|
|
func (p *testPlugin) IsStopCalled() bool {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
return p.stopCalled
|
|
}
|
|
|
|
// testServerPlugin 测试服务器插件
|
|
type testServerPlugin struct {
|
|
*testPlugin
|
|
onServerStartCalled bool
|
|
onServerStopCalled bool
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
func (p *testServerPlugin) OnServerStart(ctx context.Context) error {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.onServerStartCalled = true
|
|
return nil
|
|
}
|
|
|
|
func (p *testServerPlugin) OnServerStop(ctx context.Context) error {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
p.onServerStopCalled = true
|
|
return nil
|
|
}
|
|
|
|
func (p *testServerPlugin) IsOnServerStartCalled() bool {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
return p.onServerStartCalled
|
|
}
|
|
|
|
func (p *testServerPlugin) IsOnServerStopCalled() bool {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
return p.onServerStopCalled
|
|
}
|
|
|
|
// TestPluginManager 测试插件管理器
|
|
func TestPluginManager(t *testing.T) {
|
|
// 创建插件管理器
|
|
manager := internalplugin.NewManager()
|
|
|
|
// 创建测试插件
|
|
plugin1 := &testPlugin{
|
|
name: "test-plugin-1",
|
|
version: "1.0.0",
|
|
}
|
|
|
|
plugin2 := &testPlugin{
|
|
name: "test-plugin-2",
|
|
version: "2.0.0",
|
|
}
|
|
|
|
// 注册插件
|
|
err := manager.Register(plugin1)
|
|
require.NoError(t, err, "Should register plugin1")
|
|
|
|
err = manager.Register(plugin2)
|
|
require.NoError(t, err, "Should register plugin2")
|
|
|
|
// 尝试注册同名插件(应该失败)
|
|
err = manager.Register(plugin1)
|
|
assert.Error(t, err, "Should fail to register duplicate plugin")
|
|
|
|
// 获取插件
|
|
retrievedPlugin, err := manager.Get("test-plugin-1")
|
|
require.NoError(t, err, "Should get plugin1")
|
|
require.NotNil(t, retrievedPlugin, "Plugin should not be nil")
|
|
assert.Equal(t, "test-plugin-1", retrievedPlugin.Name(), "Plugin name should match")
|
|
|
|
// 列出所有插件
|
|
plugins := manager.List()
|
|
assert.Len(t, plugins, 2, "Should have 2 plugins")
|
|
|
|
// 初始化所有插件
|
|
cfg := config.DefaultConfig()
|
|
err = manager.InitAll(cfg)
|
|
require.NoError(t, err, "Should init all plugins")
|
|
assert.True(t, plugin1.IsInitCalled(), "Plugin1 should be initialized")
|
|
assert.True(t, plugin2.IsInitCalled(), "Plugin2 should be initialized")
|
|
|
|
// 启动所有插件
|
|
ctx := context.Background()
|
|
err = manager.StartAll(ctx)
|
|
require.NoError(t, err, "Should start all plugins")
|
|
assert.True(t, plugin1.IsStartCalled(), "Plugin1 should be started")
|
|
assert.True(t, plugin2.IsStartCalled(), "Plugin2 should be started")
|
|
|
|
// 停止所有插件
|
|
err = manager.StopAll(ctx)
|
|
require.NoError(t, err, "Should stop all plugins")
|
|
assert.True(t, plugin1.IsStopCalled(), "Plugin1 should be stopped")
|
|
assert.True(t, plugin2.IsStopCalled(), "Plugin2 should be stopped")
|
|
|
|
// 取消注册插件
|
|
err = manager.Unregister("test-plugin-1")
|
|
require.NoError(t, err, "Should unregister plugin1")
|
|
|
|
// 验证插件已取消注册
|
|
_, err = manager.Get("test-plugin-1")
|
|
assert.Error(t, err, "Should fail to get unregistered plugin")
|
|
}
|
|
|
|
// TestServerPlugin 测试服务器插件
|
|
func TestServerPlugin(t *testing.T) {
|
|
// 创建插件管理器
|
|
manager := internalplugin.NewManager()
|
|
|
|
// 创建服务器插件
|
|
serverPlugin := &testServerPlugin{
|
|
testPlugin: &testPlugin{
|
|
name: "server-plugin",
|
|
version: "1.0.0",
|
|
},
|
|
}
|
|
|
|
// 注册插件
|
|
err := manager.Register(serverPlugin)
|
|
require.NoError(t, err, "Should register server plugin")
|
|
|
|
// 初始化插件
|
|
cfg := config.DefaultConfig()
|
|
err = manager.InitAll(cfg)
|
|
require.NoError(t, err, "Should init plugin")
|
|
|
|
// 启动插件
|
|
ctx := context.Background()
|
|
err = manager.StartAll(ctx)
|
|
require.NoError(t, err, "Should start plugin")
|
|
|
|
// 调用OnServerStart
|
|
err = serverPlugin.OnServerStart(ctx)
|
|
require.NoError(t, err, "Should call OnServerStart")
|
|
assert.True(t, serverPlugin.IsOnServerStartCalled(), "OnServerStart should be called")
|
|
|
|
// 调用OnServerStop
|
|
err = serverPlugin.OnServerStop(ctx)
|
|
require.NoError(t, err, "Should call OnServerStop")
|
|
assert.True(t, serverPlugin.IsOnServerStopCalled(), "OnServerStop should be called")
|
|
|
|
// 停止插件
|
|
err = manager.StopAll(ctx)
|
|
require.NoError(t, err, "Should stop plugin")
|
|
}
|
|
|
|
// TestPluginWithServer 测试插件与服务器集成
|
|
func TestPluginWithServer(t *testing.T) {
|
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
require.NoError(t, err)
|
|
port := listener.Addr().(*net.TCPAddr).Port
|
|
listener.Close()
|
|
|
|
// 创建插件管理器
|
|
manager := internalplugin.NewManager()
|
|
|
|
// 创建消息计数插件
|
|
var messageCount int
|
|
var mu sync.Mutex
|
|
messagePlugin := &testMessagePlugin{
|
|
testPlugin: &testPlugin{
|
|
name: "message-counter",
|
|
version: "1.0.0",
|
|
},
|
|
onMessage: func(data []byte) ([]byte, error) {
|
|
mu.Lock()
|
|
messageCount++
|
|
mu.Unlock()
|
|
return data, nil
|
|
},
|
|
}
|
|
|
|
// 注册插件
|
|
err = manager.Register(messagePlugin)
|
|
require.NoError(t, err, "Should register message plugin")
|
|
|
|
cfg := &nnet.Config{
|
|
Addr: fmt.Sprintf("tcp://127.0.0.1:%d", port),
|
|
Codec: &nnet.CodecConfig{
|
|
DefaultCodec: "json",
|
|
},
|
|
}
|
|
|
|
ts := StartTestServerWithRoutes(t, cfg, func(srv nnet.Server) {
|
|
srv.Router().RegisterString("test", func(ctx nnet.Context) error {
|
|
return ctx.Response().Write(map[string]any{
|
|
"status": "ok",
|
|
})
|
|
})
|
|
})
|
|
defer CleanupTestServer(t, ts)
|
|
|
|
// 初始化并启动插件
|
|
initCfg := config.DefaultConfig()
|
|
err = manager.InitAll(initCfg)
|
|
require.NoError(t, err, "Should init plugins")
|
|
|
|
ctx := context.Background()
|
|
err = manager.StartAll(ctx)
|
|
require.NoError(t, err, "Should start plugins")
|
|
|
|
// 注意:这里只是测试插件管理器的基本功能
|
|
// 实际的插件集成需要通过服务器内部实现
|
|
_ = messageCount
|
|
|
|
// 清理
|
|
manager.StopAll(ctx)
|
|
}
|
|
|
|
// testMessagePlugin 测试消息插件
|
|
type testMessagePlugin struct {
|
|
*testPlugin
|
|
onMessage func([]byte) ([]byte, error)
|
|
}
|
|
|
|
func (p *testMessagePlugin) OnMessage(ctx context.Context, data []byte) ([]byte, error) {
|
|
if p.onMessage != nil {
|
|
return p.onMessage(data)
|
|
}
|
|
return data, nil
|
|
}
|
|
|