diff --git a/app/id/rpc/id.go b/app/id/rpc/id.go index 01e5f86..2472dc2 100644 --- a/app/id/rpc/id.go +++ b/app/id/rpc/id.go @@ -12,18 +12,15 @@ import ( "google.golang.org/grpc" ) -var getConfig = loadConfigByFile - -func loadConfigByFile(filename string) config.Config { - var c config.Config - conf.MustLoad(filename, &c) - return c -} +var ( + configFile = "etc/id.yaml" +) func main() { - cfg := getConfig("etc/id.yaml") - ctx := svc.NewServiceContext(cfg) + var c config.Config + conf.MustLoad(configFile, &c) + ctx := svc.NewServiceContext(c) s := zrpc.MustNewServer( ctx.Config.RpcServerConf, func(grpcServer *grpc.Server) { diff --git a/app/id/rpc/id_test.go b/app/id/rpc/id_test.go index bf2bd49..fc1a940 100644 --- a/app/id/rpc/id_test.go +++ b/app/id/rpc/id_test.go @@ -6,28 +6,13 @@ import ( "os" "testing" + "github.com/samber/lo" "github.com/seth-shi/go-zero-testing-example/app/id/rpc/id" - "github.com/seth-shi/go-zero-testing-example/app/id/rpc/internal/config" "github.com/seth-shi/go-zero-testing-example/pkg" "github.com/stretchr/testify/require" "github.com/zeromicro/go-zero/zrpc" ) -func Test_loadConfigByFile(t *testing.T) { - remove, tmp, err := pkg.CreateTempFile( - ".yaml", ` -Name: id.rpc -ListenOn: 0.0.0.0:9502 -`, - ) - require.NoError(t, err) - defer remove() - - svcCtx := loadConfigByFile(tmp) - require.NoError(t, err) - require.Equal(t, "id.rpc", svcCtx.Name) -} - func Test_get(t *testing.T) { var ( ctx = context.Background() @@ -47,14 +32,15 @@ var ( func TestMain(m *testing.M) { testListenOn = fmt.Sprintf(":%d", pkg.GetAvailablePort()) - - getConfig = func(filename string) config.Config { - return config.Config{ - RpcServerConf: zrpc.RpcServerConf{ - ListenOn: testListenOn, - }, - } - } + data := fmt.Sprintf( + ` +Name: id.rpc +ListenOn: %s +`, testListenOn, + ) + remove, tmp := lo.Must2(pkg.CreateTempFile(".yaml", data)) + defer remove() + configFile = tmp go main() diff --git a/app/post/rpc/internal/faker/db.go b/app/post/rpc/internal/faker/db.go index 01ba8d2..9f50864 100644 --- a/app/post/rpc/internal/faker/db.go +++ b/app/post/rpc/internal/faker/db.go @@ -1,10 +1,13 @@ package faker import ( + "context" + "github.com/samber/lo" + "github.com/seth-shi/go-zero-testing-example/app/id/rpc/id" "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/model/entity" "github.com/zeromicro/go-zero/core/logx" - "gorm.io/driver/mysql" + "google.golang.org/grpc" "gorm.io/gorm" ) @@ -12,18 +15,13 @@ type fakerModels struct { PostModel *entity.Post } -func makeDatabase(dsn string, gen *idGenerator) *fakerModels { - - db, err := gorm.Open( - mysql.Open(dsn), - ) - logx.Must(err) +func makeDatabase(db *gorm.DB) *fakerModels { // 创建表结构 logx.Must(db.Migrator().CreateTable(&entity.Post{})) // 插入测试数据 - entity.SetIdGenerator(gen) + entity.SetIdGenerator(&databaseSeeder{}) postModel := &entity.Post{ Title: lo.ToPtr("test"), Content: lo.ToPtr("content"), @@ -33,3 +31,12 @@ func makeDatabase(dsn string, gen *idGenerator) *fakerModels { return &fakerModels{PostModel: postModel} } + +type databaseSeeder struct { + id uint64 +} + +func (d *databaseSeeder) Get(ctx context.Context, in *id.IdRequest, opts ...grpc.CallOption) (*id.IdResponse, error) { + d.id++ + return &id.IdResponse{Id: d.id}, nil +} diff --git a/app/post/rpc/internal/faker/id.go b/app/post/rpc/internal/faker/id.go deleted file mode 100644 index dfb9a6b..0000000 --- a/app/post/rpc/internal/faker/id.go +++ /dev/null @@ -1,27 +0,0 @@ -package faker - -import ( - "context" - "sync" - - "github.com/seth-shi/go-zero-testing-example/app/id/rpc/id" - "google.golang.org/grpc" -) - -type idGenerator struct { - startId uint64 - locker sync.Locker -} - -func (m *idGenerator) Get(ctx context.Context, in *id.IdRequest, opts ...grpc.CallOption) (*id.IdResponse, error) { - - m.locker.Lock() - defer m.locker.Unlock() - - m.startId++ - - return &id.IdResponse{ - Id: m.startId, - Node: 1, - }, nil -} diff --git a/app/post/rpc/internal/faker/idserver.go b/app/post/rpc/internal/faker/idserver.go new file mode 100644 index 0000000..b6ac5b2 --- /dev/null +++ b/app/post/rpc/internal/faker/idserver.go @@ -0,0 +1,74 @@ +package faker + +import ( + "context" + "math/rand" + "net" + "sync" + "time" + + "github.com/samber/lo" + "github.com/seth-shi/go-zero-testing-example/app/id/rpc/id" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/test/bufconn" +) + +type idServer struct { + id.UnimplementedIdServer + id uint64 + locker sync.Locker + conn *bufconn.Listener + srv *grpc.Server +} + +func (r *idServer) Get(ctx context.Context, request *id.IdRequest) (*id.IdResponse, error) { + r.locker.Lock() + defer r.locker.Unlock() + + r.id++ + + return &id.IdResponse{ + Id: r.id, + Node: 1, + }, nil +} + +const ( + buffSize = 1024 * 1024 +) + +func newIdServer() *idServer { + service := &idServer{ + conn: bufconn.Listen(buffSize), + srv: grpc.NewServer(), + id: uint64(rand.Int() + startId), + locker: &sync.RWMutex{}, + } + id.RegisterIdServer(service.srv, service) + go service.Serve() + time.Sleep(time.Second) + + return service +} + +func (r *idServer) Serve() { + lo.Must0(r.srv.Serve(r.conn)) + +} + +func (r *idServer) Connect() *grpc.ClientConn { + + // Create the dialer + dialer := func(context.Context, string) (net.Conn, error) { + return r.conn.Dial() + } + + var opts []grpc.DialOption + opts = append(opts, grpc.WithContextDialer(dialer)) + // Disable transport security + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + + // Connect https://stackoverflow.com/questions/78485578/how-to-use-the-bufconn-package-with-grpc-newclient + return lo.Must(grpc.NewClient("passthrough://bufnet", opts...)) +} diff --git a/app/post/rpc/internal/faker/value.go b/app/post/rpc/internal/faker/value.go index fe65c5b..8a6a430 100644 --- a/app/post/rpc/internal/faker/value.go +++ b/app/post/rpc/internal/faker/value.go @@ -2,49 +2,69 @@ package faker import ( "fmt" - "math/rand" "sync" "github.com/alicebob/miniredis/v2" + "github.com/redis/go-redis/v9" + "github.com/samber/lo" + "github.com/seth-shi/go-zero-testing-example/app/id/rpc/id" + "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/config" + "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/model/do" + "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/svc" "github.com/seth-shi/go-zero-testing-example/pkg" - "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/service" + "github.com/zeromicro/go-zero/zrpc" "gorm.io/driver/mysql" "gorm.io/gorm" ) +const ( + startId = 100000 +) + type value struct { - IdServer *idGenerator + IdServer *idServer Redis *miniredis.Miniredis Models *fakerModels Gorm *gorm.DB + DatabaseDsn string RedisAddr string RpcListen string - DatabaseDsn string + SvcCtx *svc.ServiceContext } var GetValue = sync.OnceValue( func() value { - redis, redisAddr := pkg.FakerRedisServer() - dsn := pkg.FakerDatabaseServer() - rpcPort := pkg.GetAvailablePort() + redisMock, redisAddr := pkg.FakerRedisServer() + mysqlDsn := pkg.FakerDatabaseServer() + dbConn := lo.Must(gorm.Open(mysql.Open(mysqlDsn))) - conn, err := gorm.Open(mysql.Open(dsn)) - logx.Must(err) + testIdServer := newIdServer() + listenOn := fmt.Sprintf(":%d", rpcPort) - idGen := &idGenerator{ - startId: uint64(rand.Int() + 1), - locker: &sync.RWMutex{}, - } return value{ - IdServer: idGen, - Redis: redis, + IdServer: testIdServer, + Redis: redisMock, RedisAddr: redisAddr, - DatabaseDsn: dsn, - Models: makeDatabase(dsn, idGen), - RpcListen: fmt.Sprintf(":%d", rpcPort), - Gorm: conn, + Models: makeDatabase(dbConn), + RpcListen: listenOn, + DatabaseDsn: mysqlDsn, + Gorm: dbConn, + SvcCtx: &svc.ServiceContext{ + Config: config.Config{ + RpcServerConf: zrpc.RpcServerConf{ + ListenOn: listenOn, + ServiceConf: service.ServiceConf{ + Mode: service.TestMode, + }, + }, + }, + Redis: redis.NewClient(&redis.Options{Addr: redisAddr}), + IdRpc: id.NewIdClient(testIdServer.Connect()), + Query: do.Use(dbConn), + }, } }, ) diff --git a/app/post/rpc/internal/svc/servicecontext.go b/app/post/rpc/internal/svc/servicecontext.go index 620fbea..84a983f 100644 --- a/app/post/rpc/internal/svc/servicecontext.go +++ b/app/post/rpc/internal/svc/servicecontext.go @@ -25,9 +25,6 @@ func NewServiceContext(c config.Config) *ServiceContext { conn, err := gorm.Open(mysql.Open(c.DataSource)) logx.Must(err) - idClient := id.NewIdClient(zrpc.MustNewClient(c.IdRpc).Conn()) - entity.SetIdGenerator(idClient) - rdb := redis.NewClient( &redis.Options{ Addr: c.RedisConf.Host, @@ -36,6 +33,9 @@ func NewServiceContext(c config.Config) *ServiceContext { }, ) + idClient := id.NewIdClient(zrpc.MustNewClient(c.IdRpc).Conn()) + entity.SetIdGenerator(idClient) + return &ServiceContext{ Config: c, Redis: rdb, diff --git a/app/post/rpc/internal/svc/servicecontext_test.go b/app/post/rpc/internal/svc/servicecontext_test.go new file mode 100644 index 0000000..1ba3af8 --- /dev/null +++ b/app/post/rpc/internal/svc/servicecontext_test.go @@ -0,0 +1,31 @@ +package svc + +import ( + "testing" + + "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/config" + "github.com/seth-shi/go-zero-testing-example/pkg" + "github.com/stretchr/testify/require" + "github.com/zeromicro/go-zero/core/stores/redis" + "github.com/zeromicro/go-zero/zrpc" +) + +func TestNewServiceContext(t *testing.T) { + var ( + dsn = pkg.FakerDatabaseServer() + _, redisAddr = pkg.FakerRedisServer() + c = config.Config{ + RpcServerConf: zrpc.RpcServerConf{}, + DataSource: dsn, + RedisConf: redis.RedisConf{ + Host: redisAddr, + }, + IdRpc: zrpc.RpcClientConf{ + Target: "127.0.0.1:3000", + NonBlock: true, + }, + } + ) + ctx := NewServiceContext(c) + require.NotNil(t, ctx) +} diff --git a/app/post/rpc/post.go b/app/post/rpc/post.go index 97f8f0e..9633ef6 100644 --- a/app/post/rpc/post.go +++ b/app/post/rpc/post.go @@ -1,7 +1,6 @@ package main import ( - "flag" "fmt" "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/config" @@ -9,29 +8,20 @@ import ( "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/svc" "github.com/seth-shi/go-zero-testing-example/app/post/rpc/post" "github.com/zeromicro/go-zero/core/conf" - "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/service" "github.com/zeromicro/go-zero/zrpc" "google.golang.org/grpc" "google.golang.org/grpc/reflection" ) -var svcCtxGet = getCtxByConfigFile - -func getCtxByConfigFile() (*svc.ServiceContext, error) { - flag.Parse() - var c config.Config - if err := conf.Load("etc/post.yaml", &c); err != nil { - return nil, err - } - - return svc.NewServiceContext(c), nil -} +var configFile = "etc/post.yaml" +var svcCtxGet = svc.NewServiceContext func main() { - ctx, err := svcCtxGet() - logx.Must(err) + var c config.Config + conf.MustLoad(configFile, &c) + ctx := svcCtxGet(c) s := zrpc.MustNewServer( ctx.Config.RpcServerConf, func(grpcServer *grpc.Server) { post.RegisterPostServer(grpcServer, server.NewPostServer(ctx)) diff --git a/app/post/rpc/post_test.go b/app/post/rpc/post_test.go index 6128577..6641104 100644 --- a/app/post/rpc/post_test.go +++ b/app/post/rpc/post_test.go @@ -5,11 +5,9 @@ import ( "os" "testing" - "github.com/redis/go-redis/v9" "github.com/samber/lo" "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/config" "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/faker" - "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/model/do" "github.com/seth-shi/go-zero-testing-example/app/post/rpc/internal/svc" "github.com/seth-shi/go-zero-testing-example/app/post/rpc/post" "github.com/stretchr/testify/require" @@ -19,24 +17,8 @@ import ( func TestMain(m *testing.M) { // 使用默认配置 - svcCtxGet = func() (*svc.ServiceContext, error) { - - fakerVal := faker.GetValue() - return &svc.ServiceContext{ - Config: config.Config{ - RpcServerConf: zrpc.RpcServerConf{ - ListenOn: fakerVal.RpcListen, - }, - }, - Redis: redis.NewClient( - &redis.Options{ - Addr: fakerVal.RedisAddr, - DB: 0, - }, - ), - IdRpc: fakerVal.IdServer, - Query: do.Use(fakerVal.Gorm), - }, nil + svcCtxGet = func(c config.Config) *svc.ServiceContext { + return faker.GetValue().SvcCtx } go main()