test(utils): 添加事件驱动模型测试

- 在 sqrt_test.go 中添加了 fastSqr1 测试函数,用于测试事件驱动模型
- 新增了 Event 和 Uint32AsyncEvent 类型用于测试
- 更新了 go.work、go.mod 和
This commit is contained in:
2025-08-05 16:10:18 +08:00
parent bbbec5dff0
commit cd7583ba05
32 changed files with 1789 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
package cart
import (
"context"
"fmt"
"strings"
"github.com/badu/bus"
"github.com/badu/bus/test_scenarios/factory-request-reply/events"
"github.com/badu/bus/test_scenarios/factory-request-reply/inventory"
"github.com/badu/bus/test_scenarios/factory-request-reply/prices"
)
type ServiceImpl struct {
sb *strings.Builder
}
func NewService(sb *strings.Builder) ServiceImpl {
result := ServiceImpl{sb: sb}
return result
}
func (s *ServiceImpl) AddProductToCart(ctx context.Context, productID string) error {
inventoryClientRequest := events.NewInventoryGRPCClientRequestEvent()
bus.Pub(inventoryClientRequest)
inventoryClientRequest.WaitReply()
pricesClientRequest := events.NewPricesGRPCClientRequestEvent()
bus.Pub(pricesClientRequest)
pricesClientRequest.WaitReply()
defer inventoryClientRequest.Conn.Close() // close GRPC connection when done
stockResponse, err := inventoryClientRequest.Client.GetStockForProduct(ctx, &inventory.ProductIDRequest{ID: productID})
if err != nil {
return err
}
defer pricesClientRequest.Conn.Close() // close GRPC connection when done
priceResponse, err := pricesClientRequest.Client.GetPricesForProduct(ctx, &prices.ProductIDRequest{ID: productID})
if err != nil {
return err
}
s.sb.WriteString(fmt.Sprintf("stock %0.2fpcs @ price %0.2f$\n", stockResponse.Stock, priceResponse.Price))
return nil
}

View File

@@ -0,0 +1,56 @@
package events
import (
"sync"
"github.com/badu/bus/test_scenarios/factory-request-reply/inventory"
"github.com/badu/bus/test_scenarios/factory-request-reply/prices"
)
type InventoryGRPCClientRequestEvent struct {
wg sync.WaitGroup
Conn Closer // should be *grpc.ClientConn, but we're avoiding the import
Client inventory.ServiceClient
}
func NewInventoryGRPCClientRequestEvent() *InventoryGRPCClientRequestEvent {
result := InventoryGRPCClientRequestEvent{}
result.wg.Add(1)
return &result
}
func (i *InventoryGRPCClientRequestEvent) Async() bool {
return true // this one is async
}
func (i *InventoryGRPCClientRequestEvent) WaitReply() {
i.wg.Wait()
}
func (i *InventoryGRPCClientRequestEvent) Reply() {
i.wg.Done()
}
type PricesGRPCClientRequestEvent struct {
wg sync.WaitGroup
Conn Closer // should be *grpc.ClientConn, but we're avoiding the import
Client prices.ServiceClient
}
func NewPricesGRPCClientRequestEvent() *PricesGRPCClientRequestEvent {
result := PricesGRPCClientRequestEvent{}
result.wg.Add(1)
return &result
}
func (p *PricesGRPCClientRequestEvent) WaitReply() {
p.wg.Wait()
}
func (p *PricesGRPCClientRequestEvent) Reply() {
p.wg.Done()
}
type Closer interface {
Close() error
}

View File

@@ -0,0 +1,17 @@
package inventory
import (
"context"
)
type ServiceClient interface {
GetStockForProduct(ctx context.Context, in *ProductIDRequest) (*ProductStockResponse, error) // , opts ...grpc.CallOption) (*ProductStockResponse, error)
}
type ProductIDRequest struct {
ID string
}
type ProductStockResponse struct {
Stock float64
}

View File

@@ -0,0 +1,18 @@
package inventory
import (
"context"
)
type ServiceImpl struct {
}
func NewService() ServiceImpl {
result := ServiceImpl{}
return result
}
func (s *ServiceImpl) GetStockForProduct(ctx context.Context, productID string) {
}

View File

@@ -0,0 +1,81 @@
package factory_request_reply
import (
"context"
"strings"
"testing"
"time"
"github.com/badu/bus"
"github.com/badu/bus/test_scenarios/factory-request-reply/cart"
"github.com/badu/bus/test_scenarios/factory-request-reply/events"
"github.com/badu/bus/test_scenarios/factory-request-reply/inventory"
"github.com/badu/bus/test_scenarios/factory-request-reply/prices"
)
var sb strings.Builder
type pricesClientStub struct{}
func (s *pricesClientStub) GetPricesForProduct(ctx context.Context, in *prices.ProductIDRequest) (*prices.ProductPriceResponse, error) {
return &prices.ProductPriceResponse{Price: 10.30}, nil
}
type fakeCloser struct {
}
func (f *fakeCloser) Close() error {
return nil
}
func OnPricesGRPCClientStubRequest(e *events.PricesGRPCClientRequestEvent) {
sb.WriteString("OnPricesGRPCClientStubRequest\n")
e.Client = &pricesClientStub{}
e.Conn = &fakeCloser{}
<-time.After(300 * time.Millisecond)
e.Reply()
}
type inventoryClientStub struct{}
func (s *inventoryClientStub) GetStockForProduct(ctx context.Context, in *inventory.ProductIDRequest) (*inventory.ProductStockResponse, error) {
return &inventory.ProductStockResponse{Stock: 200}, nil
}
func OnInventoryGRPCClientStubRequest(e *events.InventoryGRPCClientRequestEvent) {
sb.WriteString("OnInventoryGRPCClientStubRequest\n")
e.Client = &inventoryClientStub{}
e.Conn = &fakeCloser{}
<-time.After(300 * time.Millisecond)
e.Reply()
}
func TestGRPCClientStub(t *testing.T) {
cartSvc := cart.NewService(&sb)
bus.Sub(OnInventoryGRPCClientStubRequest)
bus.Sub(OnPricesGRPCClientStubRequest)
err := cartSvc.AddProductToCart(context.Background(), "1")
if err != nil {
t.Fatalf("error adding product to cart : %#v", err)
}
err = cartSvc.AddProductToCart(context.Background(), "2")
if err != nil {
t.Fatalf("error adding product to cart : %#v", err)
}
const expecting = "OnInventoryGRPCClientStubRequest\n" +
"OnPricesGRPCClientStubRequest\n" +
"stock 200.00pcs @ price 10.30$\n" +
"OnInventoryGRPCClientStubRequest\n" +
"OnPricesGRPCClientStubRequest\n" +
"stock 200.00pcs @ price 10.30$\n"
got := sb.String()
if got != expecting {
t.Fatalf("expecting :\n%s but got : \n%s", expecting, got)
}
}

View File

@@ -0,0 +1,17 @@
package prices
import (
"context"
)
type ServiceClient interface {
GetPricesForProduct(ctx context.Context, in *ProductIDRequest) (*ProductPriceResponse, error) // , opts ...grpc.CallOption) (*ProductPriceResponse, error)
}
type ProductIDRequest struct {
ID string
}
type ProductPriceResponse struct {
Price float64
}

View File

@@ -0,0 +1,18 @@
package prices
import (
"context"
)
type ServiceImpl struct {
}
func NewService() ServiceImpl {
result := ServiceImpl{}
return result
}
func (s *ServiceImpl) GetPricesForProduct(ctx context.Context, productID string) {
}