From 0053b12a388c5e8e2b2a11904e1eb93f71ff1816 Mon Sep 17 00:00:00 2001 From: wtks <30363887+wtks@users.noreply.github.com> Date: Sat, 7 Dec 2024 11:43:02 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=E3=83=87=E3=83=BC=E3=82=BF=E3=82=92?= =?UTF-8?q?=E5=8F=97=E3=81=91=E5=8F=96=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scenario/worldclient/worldclient.go | 37 ++++++++++++++++--- bench/benchmarker/world/notification.go | 31 ++++++++++++++++ 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/bench/benchmarker/scenario/worldclient/worldclient.go b/bench/benchmarker/scenario/worldclient/worldclient.go index c897314a..c6b2b24a 100644 --- a/bench/benchmarker/scenario/worldclient/worldclient.go +++ b/bench/benchmarker/scenario/worldclient/worldclient.go @@ -441,28 +441,53 @@ func (c *userClient) ConnectUserNotificationStream(ctx *world.Context, user *wor if r.Data.Valid { data := r.Data.V var event world.NotificationEvent + userNotificationEvent := world.UserNotificationEvent{ + Pickup: world.C(data.PickupCoordinate.Latitude, data.PickupCoordinate.Longitude), + Destination: world.C(data.DestinationCoordinate.Latitude, data.DestinationCoordinate.Longitude), + Fare: data.Fare, + Chair: nil, + } + if data.Chair.Set { + userNotificationEvent.Chair = &world.UserNotificationEventChairPayload{ + ID: data.Chair.Value.ID, + Name: data.Chair.Value.Name, + Model: data.Chair.Value.Model, + Stats: world.UserNotificationEventChairStatsPayload{ + TotalRidesCount: data.Chair.Value.Stats.TotalRidesCount, + TotalEvaluationAvg: data.Chair.Value.Stats.TotalEvaluationAvg, + }, + } + } switch data.Status { case api.RideStatusMATCHING: - // event = &world.UserNotificationEventMatching{} + event = &world.UserNotificationEventMatching{ + ServerRequestID: data.RideID, + UserNotificationEvent: userNotificationEvent, + } case api.RideStatusENROUTE: event = &world.UserNotificationEventDispatching{ - ServerRequestID: data.RideID, + ServerRequestID: data.RideID, + UserNotificationEvent: userNotificationEvent, } case api.RideStatusPICKUP: event = &world.UserNotificationEventDispatched{ - ServerRequestID: data.RideID, + ServerRequestID: data.RideID, + UserNotificationEvent: userNotificationEvent, } case api.RideStatusCARRYING: event = &world.UserNotificationEventCarrying{ - ServerRequestID: data.RideID, + ServerRequestID: data.RideID, + UserNotificationEvent: userNotificationEvent, } case api.RideStatusARRIVED: event = &world.UserNotificationEventArrived{ - ServerRequestID: data.RideID, + ServerRequestID: data.RideID, + UserNotificationEvent: userNotificationEvent, } case api.RideStatusCOMPLETED: event = &world.UserNotificationEventCompleted{ - ServerRequestID: data.RideID, + ServerRequestID: data.RideID, + UserNotificationEvent: userNotificationEvent, } } if event == nil { diff --git a/bench/benchmarker/world/notification.go b/bench/benchmarker/world/notification.go index 2494b84d..22d7a8f0 100644 --- a/bench/benchmarker/world/notification.go +++ b/bench/benchmarker/world/notification.go @@ -33,32 +33,63 @@ type ChairNotificationEventUserPayload struct { Name string } +type UserNotificationEventMatching struct { + ServerRequestID string + UserNotificationEvent + + unimplementedNotificationEvent +} + type UserNotificationEventDispatching struct { ServerRequestID string + UserNotificationEvent unimplementedNotificationEvent } type UserNotificationEventDispatched struct { ServerRequestID string + UserNotificationEvent unimplementedNotificationEvent } type UserNotificationEventCarrying struct { ServerRequestID string + UserNotificationEvent unimplementedNotificationEvent } type UserNotificationEventArrived struct { ServerRequestID string + UserNotificationEvent unimplementedNotificationEvent } type UserNotificationEventCompleted struct { ServerRequestID string + UserNotificationEvent unimplementedNotificationEvent } + +type UserNotificationEvent struct { + Pickup Coordinate + Destination Coordinate + Fare int + Chair *UserNotificationEventChairPayload +} + +type UserNotificationEventChairPayload struct { + ID string + Name string + Model string + Stats UserNotificationEventChairStatsPayload +} + +type UserNotificationEventChairStatsPayload struct { + TotalRidesCount int + TotalEvaluationAvg float64 +} From 4d04ef29938a8e9aa57c25e31404698af00b4491 Mon Sep 17 00:00:00 2001 From: wtks <30363887+wtks@users.noreply.github.com> Date: Sat, 7 Dec 2024 12:23:29 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC?= =?UTF-8?q?=E3=81=AEEnroute=E9=80=9A=E7=9F=A5=E3=81=AE=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E3=82=92=E3=83=90=E3=83=AA=E3=83=87=E3=83=BC=E3=82=B7=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench/benchmarker/world/errors.go | 3 + bench/benchmarker/world/user.go | 130 ++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 6 deletions(-) diff --git a/bench/benchmarker/world/errors.go b/bench/benchmarker/world/errors.go index ea516a3e..000612a3 100644 --- a/bench/benchmarker/world/errors.go +++ b/bench/benchmarker/world/errors.go @@ -75,6 +75,8 @@ const ( ErrorCodeLackOfNearbyChairs // ErrorCodeMatchingTimeout マッチングに時間がかかりすぎです ErrorCodeMatchingTimeout + // ErrorCodeUserReceivedDataIsWrong ユーザーが通知から受け取ったデータが想定と異なります + ErrorCodeUserReceivedDataIsWrong ) var CriticalErrorCodes = map[ErrorCode]bool{ @@ -117,6 +119,7 @@ var ErrorTexts = map[ErrorCode]string{ ErrorCodeWrongNearbyChairs: "取得した付近の椅子情報に不備があります", ErrorCodeLackOfNearbyChairs: "付近の椅子情報が想定よりも3つ以上足りていません", ErrorCodeMatchingTimeout: "ライドが長時間マッチングされませんでした", + ErrorCodeUserReceivedDataIsWrong: "ユーザーが受け取った通知の内容が想定と異なります", } type codeError struct { diff --git a/bench/benchmarker/world/user.go b/bench/benchmarker/world/user.go index 670214fc..7fb78a8a 100644 --- a/bench/benchmarker/world/user.go +++ b/bench/benchmarker/world/user.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "log/slog" + "math" "math/rand/v2" "slices" "sync" @@ -63,6 +64,8 @@ type User struct { notificationConn NotificationStream // notificationQueue 通知キュー。毎Tickで最初に処理される notificationQueue chan NotificationEvent + // validatedRideNotificationEvent 最新のバリデーション済みの通知イベント情報 + validatedRideNotificationEvent *UserNotificationEvent } type RegisteredUserData struct { @@ -364,7 +367,7 @@ func (u *User) CreateRequest(ctx *Context) error { return nil } -func (u *User) ChangeRequestStatus(status RequestStatus, serverRequestID string) error { +func (u *User) ChangeRequestStatus(status RequestStatus, serverRequestID string, validator func() error) error { request := u.Request if request == nil { if status == RequestStatusCompleted { @@ -401,6 +404,13 @@ func (u *User) ChangeRequestStatus(status RequestStatus, serverRequestID string) return WrapCodeError(ErrorCodeUnexpectedUserRequestStatusTransitionOccurred, fmt.Errorf("ride_id: %v, expect: %v, got: %v (current: %v)", request.ServerID, request.Statuses.Desired, status, request.Statuses.User)) } } + + if validator != nil { + if err := validator(); err != nil { + return WrapCodeError(ErrorCodeUserReceivedDataIsWrong, err) + } + } + request.Statuses.User = status return nil } @@ -408,30 +418,138 @@ func (u *User) ChangeRequestStatus(status RequestStatus, serverRequestID string) func (u *User) HandleNotification(event NotificationEvent) error { switch data := event.(type) { case *UserNotificationEventDispatching: - err := u.ChangeRequestStatus(RequestStatusDispatching, data.ServerRequestID) + err := u.ChangeRequestStatus(RequestStatusDispatching, data.ServerRequestID, func() error { + if err := u.ValidateNotificationEvent(data.ServerRequestID, data.UserNotificationEvent); err != nil { + return err + } + u.validatedRideNotificationEvent = &data.UserNotificationEvent + return nil + }) if err != nil { return err } case *UserNotificationEventDispatched: - err := u.ChangeRequestStatus(RequestStatusDispatched, data.ServerRequestID) + err := u.ChangeRequestStatus(RequestStatusDispatched, data.ServerRequestID, nil) if err != nil { return err } case *UserNotificationEventCarrying: - err := u.ChangeRequestStatus(RequestStatusCarrying, data.ServerRequestID) + err := u.ChangeRequestStatus(RequestStatusCarrying, data.ServerRequestID, nil) if err != nil { return err } case *UserNotificationEventArrived: - err := u.ChangeRequestStatus(RequestStatusArrived, data.ServerRequestID) + err := u.ChangeRequestStatus(RequestStatusArrived, data.ServerRequestID, nil) if err != nil { return err } case *UserNotificationEventCompleted: - err := u.ChangeRequestStatus(RequestStatusCompleted, data.ServerRequestID) + err := u.ChangeRequestStatus(RequestStatusCompleted, data.ServerRequestID, nil) if err != nil { return err } } return nil } + +func (u *User) ValidateNotificationEvent(rideID string, serverSide UserNotificationEvent) error { + if !serverSide.Pickup.Equals(u.Request.PickupPoint) { + return fmt.Errorf("配車位置が一致しません。(ride_id: %s, got: %s, want: %s)", rideID, serverSide.Pickup, u.Request.PickupPoint) + } + if !serverSide.Destination.Equals(u.Request.DestinationPoint) { + return fmt.Errorf("目的地が一致しません。(ride_id: %s, got: %s, want: %s)", rideID, serverSide.Destination, u.Request.DestinationPoint) + } + + if serverSide.Fare != u.Request.Fare() { + return fmt.Errorf("運賃が一致しません。(ride_id: %s, got: %d, want: %d)", rideID, serverSide.Fare, u.Request.Fare()) + } + + if serverSide.Chair == nil { + return fmt.Errorf("椅子情報がありません。(ride_id: %s)", rideID) + } + + serverSideChair := serverSide.Chair + chair := u.World.ChairDB.GetByServerID(serverSideChair.ID) + if chair == nil { + return fmt.Errorf("想定していない椅子が返却されました。(ride_id: %s, chair_id: %s)", rideID, serverSide.Chair.ID) + } + + if serverSideChair.Name != chair.RegisteredData.Name { + return fmt.Errorf("椅子の名前が一致しません。(ride_id: %s, chair_id: %s, got: %s, want: %s)", rideID, serverSide.Chair.ID, serverSide.Chair.Name, u.Request.Chair.RegisteredData.Name) + } + if serverSideChair.Model != chair.Model.Name { + return fmt.Errorf("椅子のモデルが一致しません。(ride_id: %s, chair_id: %s, got: %s, want: %s)", rideID, serverSide.Chair.ID, serverSide.Chair.Model, u.Request.Chair.Model) + } + + totalRideCount := 0 + totalEvaluation := 0 + for _, r := range chair.RequestHistory.Iter() { + if r.Evaluated.Load() { + totalRideCount++ + totalEvaluation += r.CalculateEvaluation().Score() + } + } + + if serverSideChair.Stats.TotalRidesCount != totalRideCount { + return fmt.Errorf("椅子の総乗車回数が一致しません。(ride_id: %s, chair_id: %s, got: %d, want: %d)", rideID, serverSide.Chair.ID, serverSide.Chair.Stats.TotalRidesCount, totalRideCount) + } + if totalRideCount > 0 { + if !almostEqual(serverSideChair.Stats.TotalEvaluationAvg, float64(totalEvaluation)/float64(totalRideCount), 0.01) { + return fmt.Errorf("椅子の評価の平均が一致しません。(ride_id: %s, chair_id: %s, got: %f, want: %f)", rideID, serverSide.Chair.ID, serverSide.Chair.Stats.TotalEvaluationAvg, float64(totalEvaluation)/float64(totalRideCount)) + } + } else { + if serverSideChair.Stats.TotalEvaluationAvg != 0 { + return fmt.Errorf("椅子の評価の平均が一致しません。(ride_id: %s, chair_id: %s, got: %f, want: %f)", rideID, serverSide.Chair.ID, serverSide.Chair.Stats.TotalEvaluationAvg, 0.0) + } + } + + return nil +} + +// compareUserNotificationEvent validation済みのUserNotificationEventと比較して、一致しない場合はエラーを返す +func compareUserNotificationEvent(rideID string, old, new UserNotificationEvent) error { + if !new.Pickup.Equals(old.Pickup) { + return fmt.Errorf("配車位置が一致しません。(ride_id: %s, got: %s, want: %s)", rideID, new.Pickup, old.Pickup) + } + if !new.Destination.Equals(old.Destination) { + return fmt.Errorf("目的地が一致しません。(ride_id: %s, got: %s, want: %s)", rideID, new.Destination, old.Destination) + } + + if new.Fare != old.Fare { + return fmt.Errorf("運賃が一致しません。(ride_id: %s, got: %d, want: %d)", rideID, new.Fare, old.Fare) + } + + if new.Chair == nil { + return fmt.Errorf("椅子情報がありません。(ride_id: %s)", rideID) + } + + if new.Chair.ID != old.Chair.ID { + return fmt.Errorf("椅子のIDが一致しません。(ride_id: %s, got: %s, want: %s)", rideID, new.Chair.ID, old.Chair.ID) + } + if new.Chair.Name != old.Chair.Name { + return fmt.Errorf("椅子の名前が一致しません。(ride_id: %s, chair_id: %s, got: %s, want: %s)", rideID, new.Chair.ID, new.Chair.Name, old.Chair.Name) + } + if new.Chair.Model != old.Chair.Model { + return fmt.Errorf("椅子のモデルが一致しません。(ride_id: %s, chair_id: %s, got: %s, want: %s)", rideID, new.Chair.ID, new.Chair.Model, old.Chair.Model) + } + + if new.Chair.Stats.TotalRidesCount != old.Chair.Stats.TotalRidesCount { + return fmt.Errorf("椅子の総乗車回数が一致しません。(ride_id: %s, chair_id: %s, got: %d, want: %d)", rideID, new.Chair.ID, new.Chair.Stats.TotalRidesCount, old.Chair.Stats.TotalRidesCount) + } + if new.Chair.Stats.TotalEvaluationAvg != old.Chair.Stats.TotalEvaluationAvg { + return fmt.Errorf("椅子の評価の平均が一致しません。(ride_id: %s, chair_id: %s, got: %f, want: %f)", rideID, new.Chair.ID, new.Chair.Stats.TotalEvaluationAvg, old.Chair.Stats.TotalEvaluationAvg) + } + + return nil +} + +func almostEqual(a, b, epsilon float64) bool { + // 絶対誤差と相対誤差を組み合わせて比較 + absDiff := math.Abs(a - b) + if absDiff <= epsilon { + return true + } + // 相対誤差の比較 + maxAbs := math.Max(math.Abs(a), math.Abs(b)) + return absDiff <= epsilon*maxAbs +} From b9f72a36b9c2f838f1f56de22ad9ee8e3b7d4660 Mon Sep 17 00:00:00 2001 From: wtks <30363887+wtks@users.noreply.github.com> Date: Sat, 7 Dec 2024 12:29:23 +0900 Subject: [PATCH 3/3] fix --- bench/benchmarker/world/user.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/benchmarker/world/user.go b/bench/benchmarker/world/user.go index 7fb78a8a..9a2f9d97 100644 --- a/bench/benchmarker/world/user.go +++ b/bench/benchmarker/world/user.go @@ -478,7 +478,7 @@ func (u *User) ValidateNotificationEvent(rideID string, serverSide UserNotificat return fmt.Errorf("椅子の名前が一致しません。(ride_id: %s, chair_id: %s, got: %s, want: %s)", rideID, serverSide.Chair.ID, serverSide.Chair.Name, u.Request.Chair.RegisteredData.Name) } if serverSideChair.Model != chair.Model.Name { - return fmt.Errorf("椅子のモデルが一致しません。(ride_id: %s, chair_id: %s, got: %s, want: %s)", rideID, serverSide.Chair.ID, serverSide.Chair.Model, u.Request.Chair.Model) + return fmt.Errorf("椅子のモデルが一致しません。(ride_id: %s, chair_id: %s, got: %s, want: %s)", rideID, serverSide.Chair.ID, serverSide.Chair.Model, u.Request.Chair.Model.Name) } totalRideCount := 0