Retry vehicle detection every 3 minutes for 10 minutes (#1254)
This commit is contained in:
parent
2123ae4c61
commit
f127eca315
5 changed files with 349 additions and 74 deletions
|
|
@ -2,7 +2,7 @@ package api
|
|||
|
||||
import "time"
|
||||
|
||||
//go:generate mockgen -package mock -destination ../mock/mock_api.go github.com/andig/evcc/api Charger,Meter,MeterEnergy,Vehicle,ChargeRater
|
||||
//go:generate mockgen -package mock -destination ../mock/mock_api.go github.com/andig/evcc/api Charger,ChargeState,Identifier,Meter,MeterEnergy,Vehicle,ChargeRater
|
||||
|
||||
// ChargeMode are charge modes modeled after OpenWB
|
||||
type ChargeMode string
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ const (
|
|||
evVehicleConnect = "connect" // vehicle connected
|
||||
evVehicleDisconnect = "disconnect" // vehicle disconnected
|
||||
|
||||
minActiveCurrent = 1.0 // minimum current at which a phase is treated as active
|
||||
minActiveCurrent = 1.0 // minimum current at which a phase is treated as active
|
||||
vehicleDetectInterval = 3 * time.Minute
|
||||
vehicleDetectDuration = 10 * time.Minute
|
||||
)
|
||||
|
||||
// PollConfig defines the vehicle polling mode and interval
|
||||
|
|
@ -95,21 +97,22 @@ type LoadPoint struct {
|
|||
MaxCurrent float64 // Max allowed current. Physically ensured by the charger
|
||||
GuardDuration time.Duration // charger enable/disable minimum holding time
|
||||
|
||||
enabled bool // Charger enabled state
|
||||
chargeCurrent float64 // Charger current limit
|
||||
guardUpdated time.Time // Charger enabled/disabled timestamp
|
||||
socUpdated time.Time // SoC updated timestamp (poll: connected)
|
||||
enabled bool // Charger enabled state
|
||||
chargeCurrent float64 // Charger current limit
|
||||
guardUpdated time.Time // Charger enabled/disabled timestamp
|
||||
socUpdated time.Time // SoC updated timestamp (poll: connected)
|
||||
vehicleConnected time.Time // Vehicle connected timestamp
|
||||
vehicleConnectedTicker *clock.Ticker
|
||||
|
||||
charger api.Charger
|
||||
chargeTimer api.ChargeTimer
|
||||
chargeRater api.ChargeRater
|
||||
|
||||
chargeMeter api.Meter // Charger usage meter
|
||||
vehicle api.Vehicle // Currently active vehicle
|
||||
vehicles []api.Vehicle // Assigned vehicles
|
||||
socEstimator *soc.Estimator
|
||||
socTimer *soc.Timer
|
||||
vehicleIdError error // state of last vehicle identification
|
||||
chargeMeter api.Meter // Charger usage meter
|
||||
vehicle api.Vehicle // Currently active vehicle
|
||||
vehicles []api.Vehicle // Assigned vehicles
|
||||
socEstimator *soc.Estimator
|
||||
socTimer *soc.Timer
|
||||
|
||||
// cached state
|
||||
status api.ChargeStatus // Charger status
|
||||
|
|
@ -327,9 +330,11 @@ func (lp *LoadPoint) evVehicleConnectHandler() {
|
|||
}
|
||||
|
||||
// flush all vehicles before updating state
|
||||
lp.log.DEBUG.Println("vehicle api refresh")
|
||||
provider.ResetCached()
|
||||
|
||||
// identify active vehicle
|
||||
lp.startVehicleDetection()
|
||||
lp.findActiveVehicle()
|
||||
|
||||
// immediately allow pv mode activity
|
||||
|
|
@ -348,6 +353,11 @@ func (lp *LoadPoint) evVehicleDisconnectHandler() {
|
|||
|
||||
lp.pushEvent(evVehicleDisconnect)
|
||||
|
||||
// remove active vehicle
|
||||
if len(lp.vehicles) > 1 {
|
||||
lp.setActiveVehicle(nil)
|
||||
}
|
||||
|
||||
// set default mode on disconnect
|
||||
if lp.OnDisconnect.Mode != "" && lp.GetMode() != api.ModeOff {
|
||||
lp.SetMode(lp.OnDisconnect.Mode)
|
||||
|
|
@ -421,7 +431,7 @@ func (lp *LoadPoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even
|
|||
// run during prepare() to ensure cache has been attached
|
||||
if len(lp.vehicles) > 0 {
|
||||
lp.setActiveVehicle(lp.vehicles[0])
|
||||
lp.findActiveVehicle()
|
||||
lp.startVehicleDetection()
|
||||
}
|
||||
|
||||
// read initial charger state to prevent immediately disabling charger
|
||||
|
|
@ -591,35 +601,64 @@ func (lp *LoadPoint) remoteControlled(demand RemoteDemand) bool {
|
|||
|
||||
// setActiveVehicle assigns currently active vehicle and configures soc estimator
|
||||
func (lp *LoadPoint) setActiveVehicle(vehicle api.Vehicle) {
|
||||
if lp.vehicle != nil {
|
||||
lp.log.INFO.Printf("vehicle updated: %s -> %s", lp.vehicle.Title(), vehicle.Title())
|
||||
if lp.vehicle == vehicle {
|
||||
return
|
||||
}
|
||||
|
||||
// update successful
|
||||
lp.vehicleIdError = nil
|
||||
from := "unknown"
|
||||
if lp.vehicle != nil {
|
||||
from = lp.vehicle.Title()
|
||||
}
|
||||
to := "unknown"
|
||||
if vehicle != nil {
|
||||
to = vehicle.Title()
|
||||
}
|
||||
lp.log.INFO.Printf("vehicle updated: %s -> %s", from, to)
|
||||
|
||||
lp.vehicle = vehicle
|
||||
lp.socEstimator = soc.NewEstimator(lp.log, vehicle, lp.SoC.Estimate)
|
||||
if lp.vehicle = vehicle; vehicle != nil {
|
||||
lp.socEstimator = soc.NewEstimator(lp.log, vehicle, lp.SoC.Estimate)
|
||||
|
||||
lp.publish("socTitle", lp.vehicle.Title())
|
||||
lp.publish("socCapacity", lp.vehicle.Capacity())
|
||||
lp.publish("socTitle", lp.vehicle.Title())
|
||||
lp.publish("socCapacity", lp.vehicle.Capacity())
|
||||
} else {
|
||||
lp.socEstimator = nil
|
||||
|
||||
lp.publish("socTitle", "unknown")
|
||||
lp.publish("socCapacity", 0)
|
||||
}
|
||||
}
|
||||
|
||||
// vehicleIdentificationAllowed returns true if active vehicle has not yet been identified
|
||||
// startVehicleDetection resets connection timer and starts api refresh timer
|
||||
func (lp *LoadPoint) startVehicleDetection() {
|
||||
lp.vehicleConnected = lp.clock.Now()
|
||||
lp.vehicleConnectedTicker = lp.clock.Ticker(vehicleDetectInterval)
|
||||
}
|
||||
|
||||
// vehicleIdentificationAllowed checks if loadpoint has multiple vehicles associated and starts discovery period
|
||||
func (lp *LoadPoint) vehicleIdentificationAllowed() bool {
|
||||
return errors.Is(lp.vehicleIdError, api.ErrMustRetry)
|
||||
res := len(lp.vehicles) > 1 && lp.connected() && lp.clock.Since(lp.vehicleConnected) < vehicleDetectDuration
|
||||
|
||||
// request vehicle api refresh while waiting to identify
|
||||
if res {
|
||||
select {
|
||||
case <-lp.vehicleConnectedTicker.C:
|
||||
lp.log.DEBUG.Println("vehicle api refresh")
|
||||
provider.ResetCached()
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// findActiveVehicle validates if the active vehicle is still connected to the loadpoint
|
||||
func (lp *LoadPoint) findActiveVehicle() {
|
||||
// find vehicles by id
|
||||
// find active vehicle by id
|
||||
func (lp *LoadPoint) findActiveVehicleByID() api.Vehicle {
|
||||
if identifier, ok := lp.charger.(api.Identifier); ok {
|
||||
id, err := identifier.Identify()
|
||||
|
||||
if err != nil {
|
||||
lp.vehicleIdError = err
|
||||
lp.log.ERROR.Println("charger vehicle id:", err)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
if id != "" {
|
||||
|
|
@ -628,14 +667,13 @@ func (lp *LoadPoint) findActiveVehicle() {
|
|||
// find exact match
|
||||
for _, vehicle := range lp.vehicles {
|
||||
if vid, err := vehicle.Identify(); err == nil && vid == id {
|
||||
lp.setActiveVehicle(vehicle)
|
||||
return
|
||||
return vehicle
|
||||
}
|
||||
}
|
||||
|
||||
// find placeholder match
|
||||
for _, vehicle := range lp.vehicles {
|
||||
if vid, err := vehicle.Identify(); err == nil {
|
||||
if vid, err := vehicle.Identify(); err == nil && vid != "" {
|
||||
re, err := regexp.Compile(strings.ReplaceAll(vid, "*", ".*?"))
|
||||
if err != nil {
|
||||
lp.log.ERROR.Printf("vehicle identity: %v", err)
|
||||
|
|
@ -643,64 +681,59 @@ func (lp *LoadPoint) findActiveVehicle() {
|
|||
}
|
||||
|
||||
if re.MatchString(id) {
|
||||
lp.setActiveVehicle(vehicle)
|
||||
return
|
||||
return vehicle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO implement removing vehicle
|
||||
// lp.setActiveVehicle(nil)
|
||||
}
|
||||
}
|
||||
|
||||
if len(lp.vehicles) <= 1 {
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// find vehicles by charge state - current vehicle
|
||||
if vs, ok := lp.vehicle.(api.ChargeState); ok {
|
||||
status, err := vs.Status()
|
||||
|
||||
if err != nil {
|
||||
lp.vehicleIdError = err
|
||||
lp.log.ERROR.Println("vehicle charge state:", err)
|
||||
return
|
||||
}
|
||||
|
||||
lp.log.DEBUG.Printf("vehicle status: %s (%s)", status, lp.vehicle.Title())
|
||||
|
||||
// vehicle is plugged or charging, so it should be the right one
|
||||
if status == api.StatusB || status == api.StatusC {
|
||||
lp.vehicleIdError = nil
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// find vehicles by charge state
|
||||
// find active vehicle by charge state
|
||||
func (lp *LoadPoint) findActiveVehicleByStatus() api.Vehicle {
|
||||
for _, vehicle := range lp.vehicles {
|
||||
if vehicle == lp.vehicle {
|
||||
continue
|
||||
}
|
||||
|
||||
if vs, ok := vehicle.(api.ChargeState); ok {
|
||||
status, err := vs.Status()
|
||||
|
||||
if err != nil {
|
||||
lp.vehicleIdError = err
|
||||
lp.log.ERROR.Println("vehicle charge state:", err)
|
||||
return
|
||||
lp.log.ERROR.Println("vehicle status:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
lp.log.DEBUG.Printf("vehicle status: %s (%s)", status, vehicle.Title())
|
||||
|
||||
// vehicle is plugged or charging, so it should be the right one
|
||||
if status == api.StatusB || status == api.StatusC {
|
||||
lp.setActiveVehicle(vehicle)
|
||||
return
|
||||
return vehicle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findActiveVehicle validates if the active vehicle is still connected to the loadpoint
|
||||
func (lp *LoadPoint) findActiveVehicle() {
|
||||
if len(lp.vehicles) <= 1 {
|
||||
return
|
||||
}
|
||||
|
||||
if vehicle := lp.findActiveVehicleByID(); vehicle != nil {
|
||||
lp.setActiveVehicle(vehicle)
|
||||
return
|
||||
}
|
||||
|
||||
if vehicle := lp.findActiveVehicleByStatus(); vehicle != nil {
|
||||
lp.setActiveVehicle(vehicle)
|
||||
return
|
||||
}
|
||||
|
||||
// remove previous vehicle if status was not confirmed
|
||||
if _, ok := lp.vehicle.(api.ChargeState); ok {
|
||||
lp.setActiveVehicle(nil)
|
||||
}
|
||||
}
|
||||
|
||||
// updateChargerStatus updates charger status and detects car connected/disconnected events
|
||||
|
|
@ -762,7 +795,7 @@ func (lp *LoadPoint) effectiveCurrent() float64 {
|
|||
|
||||
// pvDisableTimer puts the pv enable/disable timer into elapsed state
|
||||
func (lp *LoadPoint) pvDisableTimer() {
|
||||
lp.pvTimer = time.Now().Add(-lp.Disable.Delay)
|
||||
lp.pvTimer = lp.clock.Now().Add(-lp.Disable.Delay)
|
||||
}
|
||||
|
||||
// pvMaxCurrent calculates the maximum target current for PV mode
|
||||
|
|
|
|||
|
|
@ -747,3 +747,142 @@ func TestMinSoC(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVehicleDetectByID(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
type charger struct {
|
||||
*mock.MockCharger
|
||||
*mock.MockIdentifier
|
||||
}
|
||||
|
||||
c := &charger{mock.NewMockCharger(ctrl), mock.NewMockIdentifier(ctrl)}
|
||||
|
||||
v1 := mock.NewMockVehicle(ctrl)
|
||||
v2 := mock.NewMockVehicle(ctrl)
|
||||
|
||||
type testcase struct {
|
||||
string
|
||||
id, i1, i2 string
|
||||
res api.Vehicle
|
||||
prepare func(testcase)
|
||||
}
|
||||
tc := []testcase{
|
||||
{"_/_/_->0", "", "", "", nil, func(tc testcase) {
|
||||
c.MockIdentifier.EXPECT().Identify().Return(tc.id, nil)
|
||||
}},
|
||||
{"1/_/_->0", "1", "", "", nil, func(tc testcase) {
|
||||
c.MockIdentifier.EXPECT().Identify().Return(tc.id, nil)
|
||||
v1.EXPECT().Identify().Return(tc.i1, nil)
|
||||
v2.EXPECT().Identify().Return(tc.i2, nil)
|
||||
v1.EXPECT().Identify().Return(tc.i1, nil)
|
||||
v2.EXPECT().Identify().Return(tc.i2, nil)
|
||||
}},
|
||||
{"1/1/2->1", "1", "1", "2", v1, func(tc testcase) {
|
||||
c.MockIdentifier.EXPECT().Identify().Return(tc.id, nil)
|
||||
v1.EXPECT().Identify().Return(tc.i1, nil)
|
||||
}},
|
||||
{"2/1/2->2", "2", "1", "2", v2, func(tc testcase) {
|
||||
c.MockIdentifier.EXPECT().Identify().Return(tc.id, nil)
|
||||
v1.EXPECT().Identify().Return(tc.i1, nil)
|
||||
v2.EXPECT().Identify().Return(tc.i2, nil)
|
||||
}},
|
||||
{"11/1*/2->1", "11", "1*", "2", v1, func(tc testcase) {
|
||||
c.MockIdentifier.EXPECT().Identify().Return(tc.id, nil)
|
||||
v1.EXPECT().Identify().Return(tc.i1, nil)
|
||||
v2.EXPECT().Identify().Return(tc.i2, nil)
|
||||
v1.EXPECT().Identify().Return(tc.i1, nil)
|
||||
// v2.EXPECT().Identify().Return(tc.i2, nil)
|
||||
}},
|
||||
{"22/1*/2*->2", "22", "1*", "2*", v2, func(tc testcase) {
|
||||
c.MockIdentifier.EXPECT().Identify().Return(tc.id, nil)
|
||||
v1.EXPECT().Identify().Return(tc.i1, nil)
|
||||
v2.EXPECT().Identify().Return(tc.i2, nil)
|
||||
v1.EXPECT().Identify().Return(tc.i1, nil)
|
||||
v2.EXPECT().Identify().Return(tc.i2, nil)
|
||||
}},
|
||||
{"2/_/*->2", "2", "", "*", v2, func(tc testcase) {
|
||||
c.MockIdentifier.EXPECT().Identify().Return(tc.id, nil)
|
||||
v1.EXPECT().Identify().Return(tc.i1, nil)
|
||||
v2.EXPECT().Identify().Return(tc.i2, nil)
|
||||
v1.EXPECT().Identify().Return(tc.i1, nil)
|
||||
v2.EXPECT().Identify().Return(tc.i2, nil)
|
||||
}},
|
||||
}
|
||||
|
||||
for _, tc := range tc {
|
||||
t.Logf("%+v", tc)
|
||||
|
||||
lp := &LoadPoint{
|
||||
log: util.NewLogger("foo"),
|
||||
charger: c,
|
||||
vehicles: []api.Vehicle{v1, v2},
|
||||
}
|
||||
|
||||
if tc.prepare != nil {
|
||||
tc.prepare(tc)
|
||||
}
|
||||
|
||||
if res := lp.findActiveVehicleByID(); tc.res != res {
|
||||
t.Errorf("expected %v, got %v", tc.res, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVehicleDetectByStatus(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
type vehicle struct {
|
||||
*mock.MockVehicle
|
||||
*mock.MockChargeState
|
||||
}
|
||||
|
||||
v1 := &vehicle{mock.NewMockVehicle(ctrl), mock.NewMockChargeState(ctrl)}
|
||||
v2 := &vehicle{mock.NewMockVehicle(ctrl), mock.NewMockChargeState(ctrl)}
|
||||
|
||||
type testcase struct {
|
||||
string
|
||||
v1, v2 api.ChargeStatus
|
||||
res api.Vehicle
|
||||
prepare func(testcase)
|
||||
}
|
||||
tc := []testcase{
|
||||
{"A/A->0", api.StatusA, api.StatusA, nil, func(t testcase) {
|
||||
v1.MockChargeState.EXPECT().Status().Return(t.v1, nil)
|
||||
v1.MockVehicle.EXPECT().Title().Return("v1")
|
||||
v2.MockChargeState.EXPECT().Status().Return(t.v2, nil)
|
||||
v2.MockVehicle.EXPECT().Title().Return("v2")
|
||||
}},
|
||||
{"B/A->1", api.StatusB, api.StatusA, v1, func(t testcase) {
|
||||
v1.MockChargeState.EXPECT().Status().Return(t.v1, nil)
|
||||
v1.MockVehicle.EXPECT().Title().Return("v1")
|
||||
}},
|
||||
{"A/B->2", api.StatusA, api.StatusB, v2, func(t testcase) {
|
||||
v1.MockChargeState.EXPECT().Status().Return(t.v1, nil)
|
||||
v1.MockVehicle.EXPECT().Title().Return("v1")
|
||||
v2.MockChargeState.EXPECT().Status().Return(t.v2, nil)
|
||||
v2.MockVehicle.EXPECT().Title().Return("v2")
|
||||
}},
|
||||
{"B/B->1", api.StatusB, api.StatusB, v1, func(t testcase) {
|
||||
v1.MockChargeState.EXPECT().Status().Return(t.v1, nil)
|
||||
v1.MockVehicle.EXPECT().Title().Return("v1")
|
||||
}},
|
||||
}
|
||||
|
||||
for _, tc := range tc {
|
||||
t.Logf("%+v", tc)
|
||||
|
||||
lp := &LoadPoint{
|
||||
log: util.NewLogger("foo"),
|
||||
vehicles: []api.Vehicle{v1, v2},
|
||||
}
|
||||
|
||||
if tc.prepare != nil {
|
||||
tc.prepare(tc)
|
||||
}
|
||||
|
||||
if res := lp.findActiveVehicleByStatus(); tc.res != res {
|
||||
t.Errorf("expected %v, got %v", tc.res, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/andig/evcc/api (interfaces: Charger,Meter,MeterEnergy,Vehicle,ChargeRater)
|
||||
// Source: github.com/andig/evcc/api (interfaces: Charger,ChargeState,Identifier,Meter,MeterEnergy,Vehicle,ChargeRater)
|
||||
|
||||
// Package mock is a generated GoMock package.
|
||||
package mock
|
||||
|
|
@ -92,6 +92,82 @@ func (mr *MockChargerMockRecorder) Status() *gomock.Call {
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockCharger)(nil).Status))
|
||||
}
|
||||
|
||||
// MockChargeState is a mock of ChargeState interface.
|
||||
type MockChargeState struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockChargeStateMockRecorder
|
||||
}
|
||||
|
||||
// MockChargeStateMockRecorder is the mock recorder for MockChargeState.
|
||||
type MockChargeStateMockRecorder struct {
|
||||
mock *MockChargeState
|
||||
}
|
||||
|
||||
// NewMockChargeState creates a new mock instance.
|
||||
func NewMockChargeState(ctrl *gomock.Controller) *MockChargeState {
|
||||
mock := &MockChargeState{ctrl: ctrl}
|
||||
mock.recorder = &MockChargeStateMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockChargeState) EXPECT() *MockChargeStateMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Status mocks base method.
|
||||
func (m *MockChargeState) Status() (api.ChargeStatus, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Status")
|
||||
ret0, _ := ret[0].(api.ChargeStatus)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Status indicates an expected call of Status.
|
||||
func (mr *MockChargeStateMockRecorder) Status() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockChargeState)(nil).Status))
|
||||
}
|
||||
|
||||
// MockIdentifier is a mock of Identifier interface.
|
||||
type MockIdentifier struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockIdentifierMockRecorder
|
||||
}
|
||||
|
||||
// MockIdentifierMockRecorder is the mock recorder for MockIdentifier.
|
||||
type MockIdentifierMockRecorder struct {
|
||||
mock *MockIdentifier
|
||||
}
|
||||
|
||||
// NewMockIdentifier creates a new mock instance.
|
||||
func NewMockIdentifier(ctrl *gomock.Controller) *MockIdentifier {
|
||||
mock := &MockIdentifier{ctrl: ctrl}
|
||||
mock.recorder = &MockIdentifierMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockIdentifier) EXPECT() *MockIdentifierMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Identify mocks base method.
|
||||
func (m *MockIdentifier) Identify() (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Identify")
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Identify indicates an expected call of Identify.
|
||||
func (mr *MockIdentifierMockRecorder) Identify() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Identify", reflect.TypeOf((*MockIdentifier)(nil).Identify))
|
||||
}
|
||||
|
||||
// MockMeter is a mock of Meter interface.
|
||||
type MockMeter struct {
|
||||
ctrl *gomock.Controller
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ func TestCachedGetter(t *testing.T) {
|
|||
|
||||
duration := time.Second
|
||||
c := NewCached(g, duration)
|
||||
clck := clock.NewMock()
|
||||
c.clock = clck
|
||||
clock := clock.NewMock()
|
||||
c.clock = clock
|
||||
getter := c.FloatGetter()
|
||||
|
||||
expect := func(s struct {
|
||||
|
|
@ -45,9 +45,36 @@ func TestCachedGetter(t *testing.T) {
|
|||
expect(cases[0])
|
||||
expect(cases[0])
|
||||
|
||||
clck.Add(2 * duration)
|
||||
clock.Add(2 * duration)
|
||||
expect(cases[1])
|
||||
|
||||
clck.Add(2 * duration)
|
||||
clock.Add(2 * duration)
|
||||
expect(cases[2])
|
||||
}
|
||||
|
||||
func TestCacheReset(t *testing.T) {
|
||||
var i int64
|
||||
g := func() (int64, error) {
|
||||
i++
|
||||
return i, nil
|
||||
}
|
||||
|
||||
c := NewCached(g, 10*time.Minute)
|
||||
clock := clock.NewMock()
|
||||
c.clock = clock
|
||||
|
||||
test := func(exp int64) {
|
||||
v, _ := c.IntGetter()()
|
||||
if exp != v {
|
||||
t.Errorf("expected %d, got %d", exp, v)
|
||||
}
|
||||
}
|
||||
|
||||
test(1)
|
||||
test(1)
|
||||
ResetCached()
|
||||
test(2)
|
||||
test(2)
|
||||
clock.Add(10*time.Minute + 1)
|
||||
test(3)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue