1 Star 0 Fork 0

lxq1586746679/pitaya-notes

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
app_test.go 19.28 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
// Copyright (c) nano Author and TFG Co. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package pitaya
import (
"context"
"errors"
"fmt"
"net"
"os"
"reflect"
"testing"
"time"
"github.com/coreos/etcd/integration"
"github.com/google/uuid"
opentracing "github.com/opentracing/opentracing-go"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/topfreegames/pitaya/acceptor"
"github.com/topfreegames/pitaya/cluster"
"github.com/topfreegames/pitaya/conn/codec"
"github.com/topfreegames/pitaya/conn/message"
"github.com/topfreegames/pitaya/constants"
e "github.com/topfreegames/pitaya/errors"
"github.com/topfreegames/pitaya/groups"
"github.com/topfreegames/pitaya/helpers"
"github.com/topfreegames/pitaya/logger"
"github.com/topfreegames/pitaya/metrics"
"github.com/topfreegames/pitaya/route"
"github.com/topfreegames/pitaya/router"
"github.com/topfreegames/pitaya/serialize/json"
"github.com/topfreegames/pitaya/session"
"github.com/topfreegames/pitaya/timer"
)
var (
tables = []struct {
isFrontend bool
serverType string
serverMode ServerMode
serverMetadata map[string]string
cfg *viper.Viper
}{
{true, "sv1", Cluster, map[string]string{"name": "bla"}, viper.New()},
{false, "sv2", Standalone, map[string]string{}, viper.New()},
}
typeOfetcdSD reflect.Type
typeOfNatsRPCServer reflect.Type
typeOfNatsRPCClient reflect.Type
)
func TestMain(m *testing.M) {
setup()
exit := m.Run()
os.Exit(exit)
}
func setup() {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
etcdSD, err := cluster.NewEtcdServiceDiscovery(app.config, app.server, app.dieChan)
if err != nil {
panic(err)
}
typeOfetcdSD = reflect.TypeOf(etcdSD)
natsRPCServer, err := cluster.NewNatsRPCServer(app.config, app.server, nil, app.dieChan)
if err != nil {
panic(err)
}
typeOfNatsRPCServer = reflect.TypeOf(natsRPCServer)
natsRPCClient, err := cluster.NewNatsRPCClient(app.config, app.server, nil, app.dieChan)
if err != nil {
panic(err)
}
typeOfNatsRPCClient = reflect.TypeOf(natsRPCClient)
c := integration.NewClusterV3(nil, &integration.ClusterConfig{Size: 1})
cli := c.RandClient()
gsi, err := groups.NewEtcdGroupService(app.config, cli)
if err != nil {
panic(err)
}
InitGroups(gsi)
}
func initApp() {
app = &App{
server: &cluster.Server{
ID: uuid.New().String(),
Type: "game",
Metadata: map[string]string{},
Frontend: true,
},
debug: false,
startAt: time.Now(),
dieChan: make(chan bool),
acceptors: []acceptor.Acceptor{},
packetDecoder: codec.NewPomeloPacketDecoder(),
packetEncoder: codec.NewPomeloPacketEncoder(),
serverMode: Standalone,
serializer: json.NewSerializer(),
configured: false,
running: false,
router: router.New(),
}
}
func TestConfigure(t *testing.T) {
for _, table := range tables {
t.Run(table.serverType, func(t *testing.T) {
initApp()
Configure(table.isFrontend, table.serverType, table.serverMode, table.serverMetadata, table.cfg)
assert.Equal(t, table.isFrontend, app.server.Frontend)
assert.Equal(t, table.serverType, app.server.Type)
assert.Equal(t, table.serverMode, app.serverMode)
assert.Equal(t, table.serverMetadata, app.server.Metadata)
assert.Equal(t, true, app.configured)
})
}
}
func TestAddAcceptor(t *testing.T) {
acc := acceptor.NewTCPAcceptor("0.0.0.0:0")
for _, table := range tables {
t.Run(table.serverType, func(t *testing.T) {
initApp()
Configure(table.isFrontend, table.serverType, table.serverMode, table.serverMetadata, table.cfg)
AddAcceptor(acc)
if table.isFrontend {
assert.Equal(t, acc, app.acceptors[0])
} else {
assert.Equal(t, 0, len(app.acceptors))
}
})
}
}
func TestSetDebug(t *testing.T) {
SetDebug(true)
assert.Equal(t, true, app.debug)
SetDebug(false)
assert.Equal(t, false, app.debug)
}
func TestSetLogger(t *testing.T) {
l := logrus.New()
SetLogger(l)
assert.Equal(t, l, logger.Log)
}
func TestSetPacketDecoder(t *testing.T) {
d := codec.NewPomeloPacketDecoder()
SetPacketDecoder(d)
assert.Equal(t, d, app.packetDecoder)
}
func TestSetPacketEncoder(t *testing.T) {
e := codec.NewPomeloPacketEncoder()
SetPacketEncoder(e)
assert.Equal(t, e, app.packetEncoder)
}
func TestGetDieChan(t *testing.T) {
assert.Equal(t, app.dieChan, GetDieChan())
}
func TestGetConfig(t *testing.T) {
assert.Equal(t, app.config, GetConfig())
}
func TestGetSerializer(t *testing.T) {
assert.Equal(t, app.serializer, GetSerializer())
}
func TestGetSever(t *testing.T) {
assert.Equal(t, app.server, GetServer())
}
func TestGetMetricsReporters(t *testing.T) {
assert.Equal(t, app.metricsReporters, GetMetricsReporters())
}
func TestGetServerByID(t *testing.T) {
r, err := cluster.NewEtcdServiceDiscovery(app.config, app.server, app.dieChan)
assert.NoError(t, err)
assert.NotNil(t, r)
SetServiceDiscoveryClient(r)
s, err := GetServerByID("id")
assert.Nil(t, s)
assert.EqualError(t, constants.ErrNoServerWithID, err.Error())
}
func TestGetServersByType(t *testing.T) {
r, err := cluster.NewEtcdServiceDiscovery(app.config, app.server, app.dieChan)
assert.NoError(t, err)
assert.NotNil(t, r)
SetServiceDiscoveryClient(r)
s, err := GetServersByType("id")
assert.Nil(t, s)
assert.EqualError(t, constants.ErrNoServersAvailableOfType, err.Error())
}
func TestSetHeartbeatInterval(t *testing.T) {
inter := 35 * time.Millisecond
SetHeartbeatTime(inter)
assert.Equal(t, inter, app.heartbeat)
}
func TestSetRPCServer(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
r, err := cluster.NewNatsRPCServer(app.config, app.server, nil, nil)
assert.NoError(t, err)
assert.NotNil(t, r)
SetRPCServer(r)
assert.Equal(t, r, app.rpcServer)
}
func TestSetRPCClient(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
r, err := cluster.NewNatsRPCClient(app.config, app.server, nil, nil)
assert.NoError(t, err)
assert.NotNil(t, r)
SetRPCClient(r)
assert.Equal(t, r, app.rpcClient)
}
func TestSetServiceDiscovery(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
r, err := cluster.NewEtcdServiceDiscovery(app.config, app.server, app.dieChan)
assert.NoError(t, err)
assert.NotNil(t, r)
SetServiceDiscoveryClient(r)
assert.Equal(t, r, app.serviceDiscovery)
}
func TestAddMetricsReporter(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
r, err := metrics.NewStatsdReporter(app.config, app.server.Type, map[string]string{
"tag1": "value1",
})
assert.NoError(t, err)
assert.NotNil(t, r)
AddMetricsReporter(r)
assert.Contains(t, app.metricsReporters, r)
}
func TestSetSerializer(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
r := json.NewSerializer()
assert.NotNil(t, r)
SetSerializer(r)
assert.Equal(t, r, app.serializer)
}
func TestInitSysRemotes(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
initSysRemotes()
assert.NotNil(t, remoteComp[0])
}
func TestSetDictionary(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
dict := map[string]uint16{"someroute": 12}
err := SetDictionary(dict)
assert.NoError(t, err)
assert.Equal(t, dict, message.GetDictionary())
app.running = true
err = SetDictionary(dict)
assert.EqualError(t, constants.ErrChangeDictionaryWhileRunning, err.Error())
}
func TestAddRoute(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
app.router = nil
err := AddRoute("somesv", func(ctx context.Context, route *route.Route, payload []byte, servers map[string]*cluster.Server) (*cluster.Server, error) {
return nil, nil
})
assert.EqualError(t, constants.ErrRouterNotInitialized, err.Error())
app.router = router.New()
err = AddRoute("somesv", func(ctx context.Context, route *route.Route, payload []byte, servers map[string]*cluster.Server) (*cluster.Server, error) {
return nil, nil
})
assert.NoError(t, err)
app.running = true
err = AddRoute("somesv", func(ctx context.Context, route *route.Route, payload []byte, servers map[string]*cluster.Server) (*cluster.Server, error) {
return nil, nil
})
assert.EqualError(t, constants.ErrChangeRouteWhileRunning, err.Error())
}
func TestShutdown(t *testing.T) {
initApp()
go func() {
Shutdown()
}()
<-app.dieChan
}
func TestConfigureDefaultMetricsReporter(t *testing.T) {
tables := []struct {
enabled bool
}{
{true},
{false},
}
for _, table := range tables {
t.Run(fmt.Sprintf("%t", table.enabled), func(t *testing.T) {
initApp()
cfg := viper.New()
cfg.Set("pitaya.metrics.prometheus.enabled", table.enabled)
cfg.Set("pitaya.metrics.statsd.enabled", table.enabled)
Configure(true, "testtype", Cluster, map[string]string{}, cfg)
// if statsd is enabled there are 2 metricsReporters, prometheus and statsd
assert.Equal(t, table.enabled, len(app.metricsReporters) == 2)
})
}
}
func TestStartDefaultSD(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
startDefaultSD()
assert.NotNil(t, app.serviceDiscovery)
assert.Equal(t, typeOfetcdSD, reflect.TypeOf(app.serviceDiscovery))
}
func TestStartDefaultRPCServer(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
startDefaultRPCServer()
assert.NotNil(t, app.rpcServer)
assert.Equal(t, typeOfNatsRPCServer, reflect.TypeOf(app.rpcServer))
}
func TestStartDefaultRPCClient(t *testing.T) {
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, viper.New())
startDefaultRPCClient()
assert.NotNil(t, app.rpcClient)
assert.Equal(t, typeOfNatsRPCClient, reflect.TypeOf(app.rpcClient))
}
func TestStartAndListenStandalone(t *testing.T) {
initApp()
Configure(true, "testtype", Standalone, map[string]string{}, viper.New())
acc := acceptor.NewTCPAcceptor("0.0.0.0:0")
AddAcceptor(acc)
go func() {
Start()
}()
helpers.ShouldEventuallyReturn(t, func() bool {
return app.running
}, true)
assert.NotNil(t, handlerService)
assert.NotNil(t, timer.GlobalTicker)
// should be listening
assert.NotEmpty(t, acc.GetAddr())
helpers.ShouldEventuallyReturn(t, func() error {
n, err := net.Dial("tcp", acc.GetAddr())
defer n.Close()
return err
}, nil, 10*time.Millisecond, 100*time.Millisecond)
}
func ConfigureClusterApp() {
}
func TestStartAndListenCluster(t *testing.T) {
es, cli := helpers.GetTestEtcd(t)
defer es.Terminate(t)
ns := helpers.GetTestNatsServer(t)
nsAddr := ns.Addr().String()
cfg := viper.New()
cfg.Set("pitaya.cluster.rpc.client.nats.connect", fmt.Sprintf("nats://%s", nsAddr))
cfg.Set("pitaya.cluster.rpc.server.nats.connect", fmt.Sprintf("nats://%s", nsAddr))
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, cfg)
etcdSD, err := cluster.NewEtcdServiceDiscovery(app.config, app.server, app.dieChan, cli)
assert.NoError(t, err)
SetServiceDiscoveryClient(etcdSD)
acc := acceptor.NewTCPAcceptor("0.0.0.0:0")
assert.Nil(t, err)
AddAcceptor(acc)
go func() {
Start()
}()
helpers.ShouldEventuallyReturn(t, func() bool {
return app.running
}, true)
assert.NotNil(t, handlerService)
assert.NotNil(t, timer.GlobalTicker)
// should be listening
assert.NotEmpty(t, acc.GetAddr())
helpers.ShouldEventuallyReturn(t, func() error {
n, err := net.Dial("tcp", acc.GetAddr())
defer n.Close()
return err
}, nil, 10*time.Millisecond, 100*time.Millisecond)
}
func TestError(t *testing.T) {
t.Parallel()
tables := []struct {
name string
err error
code string
metadata map[string]string
}{
{"nil_metadata", errors.New(uuid.New().String()), uuid.New().String(), nil},
{"empty_metadata", errors.New(uuid.New().String()), uuid.New().String(), map[string]string{}},
{"non_empty_metadata", errors.New(uuid.New().String()), uuid.New().String(), map[string]string{"key": uuid.New().String()}},
}
for _, table := range tables {
t.Run(table.name, func(t *testing.T) {
var err *e.Error
if table.metadata != nil {
err = Error(table.err, table.code, table.metadata)
} else {
err = Error(table.err, table.code)
}
assert.NotNil(t, err)
assert.Equal(t, table.code, err.Code)
assert.Equal(t, table.err.Error(), err.Message)
assert.Equal(t, table.metadata, err.Metadata)
})
}
}
func TestGetSessionFromCtx(t *testing.T) {
ss := &session.Session{}
ctx := context.WithValue(context.Background(), constants.SessionCtxKey, ss)
s := GetSessionFromCtx(ctx)
assert.Equal(t, ss, s)
}
func TestAddMetricTagsToPropagateCtx(t *testing.T) {
ctx := AddMetricTagsToPropagateCtx(context.Background(), map[string]string{
"key": "value",
})
val := ctx.Value(constants.PropagateCtxKey)
assert.Equal(t, map[string]interface{}{
constants.MetricTagsKey: map[string]string{
"key": "value",
},
}, val)
}
func TestAddToPropagateCtx(t *testing.T) {
ctx := AddToPropagateCtx(context.Background(), "key", "val")
val := ctx.Value(constants.PropagateCtxKey)
assert.Equal(t, map[string]interface{}{"key": "val"}, val)
}
func TestGetFromPropagateCtx(t *testing.T) {
ctx := AddToPropagateCtx(context.Background(), "key", "val")
val := GetFromPropagateCtx(ctx, "key")
assert.Equal(t, "val", val)
}
func TestExtractSpan(t *testing.T) {
span := opentracing.StartSpan("op", opentracing.ChildOf(nil))
ctx := opentracing.ContextWithSpan(context.Background(), span)
spanCtx, err := ExtractSpan(ctx)
assert.NoError(t, err)
assert.Equal(t, span.Context(), spanCtx)
}
func TestDescriptor(t *testing.T) {
bts, err := Descriptor("kick.proto")
assert.NoError(t, err)
assert.NotNil(t, bts)
bts, err = Descriptor("not_exists.proto")
assert.Nil(t, bts)
assert.EqualError(t, constants.ErrProtodescriptor, err.Error())
}
func TestDocumentation(t *testing.T) {
doc, err := Documentation(false)
assert.NoError(t, err)
assert.Equal(t, map[string]interface{}{
"handlers": map[string]interface{}{},
"remotes": map[string]interface{}{
"testtype.sys.bindsession": map[string]interface{}{
"input": map[string]interface{}{
"uid": "string",
"data": "[]byte",
"id": "int64",
},
"output": []interface{}{
map[string]interface{}{
"error": map[string]interface{}{
"msg": "string",
"code": "string",
"metadata": "map[string]string",
},
"data": "[]byte",
},
"error",
},
},
"testtype.sys.kick": map[string]interface{}{
"input": map[string]interface{}{
"userId": "string",
},
"output": []interface{}{
map[string]interface{}{
"kicked": "bool",
},
"error",
},
},
"testtype.sys.pushsession": map[string]interface{}{
"input": map[string]interface{}{
"data": "[]byte",
"id": "int64",
"uid": "string",
},
"output": []interface{}{
map[string]interface{}{
"error": map[string]interface{}{
"code": "string",
"metadata": "map[string]string",
"msg": "string",
},
"data": "[]byte",
},
"error",
},
},
},
}, doc)
}
func TestDocumentationTrue(t *testing.T) {
doc, err := Documentation(true)
assert.NoError(t, err)
assert.Equal(t, map[string]interface{}{
"remotes": map[string]interface{}{
"testtype.sys.bindsession": map[string]interface{}{
"input": map[string]interface{}{
"*protos.Session": map[string]interface{}{
"data": "[]byte",
"id": "int64",
"uid": "string",
},
},
"output": []interface{}{map[string]interface{}{
"*protos.Response": map[string]interface{}{
"data": "[]byte",
"error": map[string]interface{}{
"*protos.Error": map[string]interface{}{
"code": "string",
"metadata": "map[string]string",
"msg": "string",
},
},
},
},
"error",
},
},
"testtype.sys.kick": map[string]interface{}{
"input": map[string]interface{}{
"*protos.KickMsg": map[string]interface{}{
"userId": "string",
},
},
"output": []interface{}{map[string]interface{}{
"*protos.KickAnswer": map[string]interface{}{
"kicked": "bool",
},
},
"error",
},
},
"testtype.sys.pushsession": map[string]interface{}{
"input": map[string]interface{}{
"*protos.Session": map[string]interface{}{
"data": "[]byte",
"id": "int64",
"uid": "string",
},
},
"output": []interface{}{map[string]interface{}{
"*protos.Response": map[string]interface{}{
"data": "[]byte",
"error": map[string]interface{}{
"*protos.Error": map[string]interface{}{
"code": "string",
"metadata": "map[string]string",
"msg": "string",
},
},
},
},
"error",
},
},
},
"handlers": map[string]interface{}{},
}, doc)
}
func TestAddGRPCInfoToMetadata(t *testing.T) {
t.Parallel()
metadata := map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}
metadata = AddGRPCInfoToMetadata(metadata, "region", "host", "port", "external-host", "external-port")
assert.Equal(t, map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
constants.GRPCHostKey: "host",
constants.GRPCPortKey: "port",
constants.GRPCExternalHostKey: "external-host",
constants.GRPCExternalPortKey: "external-port",
constants.RegionKey: "region",
}, metadata)
}
func TestStartWorker(t *testing.T) {
cfg := viper.New()
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, cfg)
err := StartWorker(GetConfig())
assert.NoError(t, err)
assert.True(t, app.worker.Started())
}
func TestRegisterRPCJob(t *testing.T) {
t.Run("register_once", func(t *testing.T) {
cfg := viper.New()
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, cfg)
err := StartWorker(GetConfig())
assert.NoError(t, err)
err = RegisterRPCJob(nil)
assert.NoError(t, err)
})
t.Run("register_twice", func(t *testing.T) {
cfg := viper.New()
initApp()
Configure(true, "testtype", Cluster, map[string]string{}, cfg)
err := StartWorker(GetConfig())
assert.NoError(t, err)
err = RegisterRPCJob(nil)
assert.NoError(t, err)
err = RegisterRPCJob(nil)
assert.Equal(t, constants.ErrRPCJobAlreadyRegistered, err)
})
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/lxq1586746679/pitaya-notes.git
git@gitee.com:lxq1586746679/pitaya-notes.git
lxq1586746679
pitaya-notes
pitaya-notes
master

搜索帮助