Files
cloud-services/pkg/tmobile/client_simulator.go

157 lines
6.0 KiB
Go

package tmobile
import (
"context"
"math/rand"
"strconv"
"sync"
"time"
"github.com/fiskerinc/cloud-services/pkg/grpc/sms"
)
// Want to make a client simulator that has a delay for each message, along with a chance of failure
// For use with just await sms testing
type tmobileSimulator struct {
messages map[string]fakeMessage
sy sync.Mutex
count int
FailPercentage int // 10 = 10% chance of failure
AVGDeliveryTime time.Duration // lets do two seconds
Deviation float64 // The number of seconds we can deviate by
Rando *rand.Rand // Using a set seed so we can have consistent results with our random messages
filter ICCIDFilter
}
// ChangeDeviceStatus implements TMobClienter.
func (ts *tmobileSimulator) ChangeDeviceStatus(ctx context.Context, cda ChangeDeviceActivation) (err error) {
panic("unimplemented")
}
type fakeMessage struct {
finishTime time.Time
//status string // Set the time that the message will resolve, and then it will return this resolution. If blank, the message is not going to be delivered within 5 seconds
}
// avgDeliveryTime is time in seconds
func newTMboileSimulator() (tms tmobileSimulator) {
tms.messages = make(map[string]fakeMessage)
tms.Rando = rand.New(rand.NewSource(99))
tms.FailPercentage = 5 // 5% chance of a message not being delivered, so 10,000 will have 500 failed
tms.Deviation = 2 // How many seconds, maybe don't use this
tms.AVGDeliveryTime = time.Second * 2 // On average take 2ish seconds to deliver the message
return
}
// AccessToken implements TMobClienter.
func (*tmobileSimulator) AccessToken(ctx context.Context) (out *AccessTokenResponse, err error) {
out = &AccessTokenResponse{}
out.ExpiresIn = 500000
return
}
// ChangeRatePlan implements TMobClienter.
func (*tmobileSimulator) ChangeRatePlan(context.Context, *ChangeRatePlanRequest) (*ChangeRatePlanResponse, error) {
panic("unimplemented")
}
// CustomAttributes implements TMobClienter.
func (*tmobileSimulator) CustomAttributes(context.Context, *CustomAtributesRequest) (*CustomAtributesResponse, error) {
panic("unimplemented")
}
// Details implements TMobClienter.
func (ts *tmobileSimulator) Details(ctx context.Context, ID string) (out *SMSDetailsResponse, err error) {
out = &SMSDetailsResponse{}
msg := ts.messages[ID]
if msg.finishTime.IsZero() {
out.Status = "Pending"
return
}
//-cpuprofile cpu.out
if time.Now().After(msg.finishTime) {
out.Status = "Delivered"
} else {
out.Status = "Pending"
}
time.Sleep(time.Millisecond * 40)
return
}
// DeviceDetails implements TMobClienter.
func (*tmobileSimulator) DeviceDetails(context.Context, *DeviceDetailsRequest) (*DeviceDetailsResponse, error) {
panic("unimplemented")
}
// GetProducts implements TMobClienter.
func (*tmobileSimulator) GetProducts(context.Context, *sms.GetAvailableProductsRequest) (*sms.GetAvailableProductsResponse, error) {
panic("unimplemented")
}
// SendSMS implements TMobClienter.
// Call this synchronously as we are using a non-locking map and non-locked index count
func (ts *tmobileSimulator) SendSMS(ctx context.Context, in *SendSMSRequest) (out *SendSMSResponse, err error) {
ts.sy.Lock()
defer ts.sy.Unlock()
out = &SendSMSResponse{}
ts.messages[strconv.Itoa(ts.count)] = ts.randomDelivery()
out.SmsMessageID = strconv.Itoa(ts.count)
ts.count += 1
return
}
func (ts *tmobileSimulator) randomDelivery() (msg fakeMessage) {
if ts.Rando.Intn(100) <= ts.FailPercentage {
return
}
// 0 -> .99 of deviation
// 0:Deviation Value - 1/2 deviation = -.5 deviation -> .5 deviation
// I think its okay that the time is only going to take longer, no real need for shorter messages
ranomometer := (ts.Rando.Float64() * ts.Deviation)
// Actually don't need the status for this test. We have the pending unless its delivered. WE don't really see the failed to delivery message
msg.finishTime = time.Now().Add(ts.AVGDeliveryTime + time.Duration(ranomometer))
return
}
// SetAccessToken implements TMobClienter.
func (*tmobileSimulator) SetAccessToken(accessToken string) {
}
// SetFilter implements TMobClienter.
func (ts *tmobileSimulator) SetFilter(filter []string) {
ts.filter = ICCIDFilter{
filter: filter,
}
}
var _ TMobClienter = new(tmobileSimulator)
// with the channel instead of default
//BenchmarkSMSWrapper-16 1 5009644871 ns/op 3096536 B/op 45650 allocs/op
// flat flat% sum% cum cum%
// 50ms 31.25% 31.25% 50ms 31.25% runtime.kevent
// 40ms 25.00% 56.25% 40ms 25.00% runtime.pthread_cond_wait
// 20ms 12.50% 68.75% 20ms 12.50% runtime.pthread_cond_signal
// 10ms 6.25% 75.00% 10ms 6.25% runtime.(*mspan).init
// 10ms 6.25% 81.25% 20ms 12.50% runtime.mallocgc
// 10ms 6.25% 87.50% 10ms 6.25% runtime.read
// 10ms 6.25% 93.75% 10ms 6.25% runtime.usleep
// 10ms 6.25% 100% 10ms 6.25% runtime.write1
// 0 0% 100% 20ms 12.50% github.com/fiskerinc/cloud-services/pkg/tmobile.(*SMSClient).SendSMS
// 0 0% 100% 10ms 6.25% github.com/fiskerinc/cloud-services/pkg/tmobile.(*tmobileSimulator).SendSMS
// with default
//BenchmarkSMSWrapper-16 1 5110808221 ns/op 2923960 B/op 43176 allocs/op no major difference
// flat flat% sum% cum cum%
// 50ms 45.45% 45.45% 50ms 45.45% runtime.pthread_cond_wait
// 20ms 18.18% 63.64% 20ms 18.18% runtime.pthread_cond_signal
// 10ms 9.09% 72.73% 10ms 9.09% runtime.arenaIndex (inline)
// 10ms 9.09% 81.82% 10ms 9.09% runtime.kevent
// 10ms 9.09% 90.91% 10ms 9.09% runtime.stackpoolalloc
// 10ms 9.09% 100% 10ms 9.09% runtime.usleep
// 0 0% 100% 10ms 9.09% github.com/fiskerinc/cloud-services/pkg/tmobile.BenchmarkSMSWrapper
// 0 0% 100% 10ms 9.09% runtime.copystack
// 0 0% 100% 10ms 9.09% runtime.findObject
// 0 0% 100% 60ms 54.55% runtime.findRunnable