From 7ce0297ffa7b28adbcd6ecc50cd3189bb7159c90 Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 15 Jul 2022 21:04:13 +0200 Subject: [PATCH] Add tests for default vehicle and vehicle defaults (#3860) --- core/loadpoint.go | 9 ++- core/loadpoint_test.go | 130 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 132 insertions(+), 7 deletions(-) diff --git a/core/loadpoint.go b/core/loadpoint.go index 75322276a..2230a8c55 100644 --- a/core/loadpoint.go +++ b/core/loadpoint.go @@ -244,8 +244,7 @@ func NewLoadPointFromConfig(log *util.Logger, cp configProvider, other map[strin lp.log.WARN.Printf("locking phase config to %dp for switchable charger", lp.DefaultPhases) } - // allow target charge handler to access loadpoint - lp.socTimer = soc.NewTimer(lp.log, &adapter{LoadPoint: lp}) + // validate thresholds if lp.Enable.Threshold > lp.Disable.Threshold { lp.log.WARN.Printf("PV mode enable threshold (%.0fW) is larger than disable threshold (%.0fW)", lp.Enable.Threshold, lp.Disable.Threshold) } else if lp.Enable.Threshold > 0 { @@ -277,6 +276,9 @@ func NewLoadPoint(log *util.Logger) *LoadPoint { tasks: aq.New(), } + // allow target charge handler to access loadpoint + lp.socTimer = soc.NewTimer(lp.log, &adapter{LoadPoint: lp}) + return lp } @@ -443,12 +445,13 @@ func (lp *LoadPoint) evVehicleDisconnectHandler() { // remove active vehicle if not default if lp.vehicle != lp.defaultVehicle { - lp.setActiveVehicle(nil) + lp.setActiveVehicle(lp.defaultVehicle) lp.unpublishVehicle() } // set default mode on disconnect if lp.ResetOnDisconnect { + // TODO respect defaultVehicle lp.applyAction(lp.onDisconnect) } diff --git a/core/loadpoint_test.go b/core/loadpoint_test.go index 13c6ac574..e72a86cb3 100644 --- a/core/loadpoint_test.go +++ b/core/loadpoint_test.go @@ -33,9 +33,7 @@ func (n *Null) ChargingTime() (time.Duration, error) { return 0, nil } -func attachListeners(t *testing.T, lp *LoadPoint) { - Voltage = 230 // V - +func createChannels(t *testing.T) (chan util.Param, chan push.Event, chan *LoadPoint) { uiChan := make(chan util.Param) pushChan := make(chan push.Event) lpChan := make(chan *LoadPoint) @@ -60,11 +58,24 @@ func attachListeners(t *testing.T, lp *LoadPoint) { } }() + return uiChan, pushChan, lpChan +} + +func attachChannels(lp *LoadPoint, uiChan chan util.Param, pushChan chan push.Event, lpChan chan *LoadPoint) { + lp.uiChan = uiChan + lp.pushChan = pushChan + lp.lpChan = lpChan +} + +func attachListeners(t *testing.T, lp *LoadPoint) { + Voltage = 230 // V + if charger, ok := lp.charger.(*mock.MockCharger); ok && charger != nil { charger.EXPECT().Enabled().Return(true, nil) charger.EXPECT().MaxCurrent(int64(lp.MinCurrent)).Return(nil) } + uiChan, pushChan, lpChan := createChannels(t) lp.Prepare(uiChan, pushChan, lpChan) } @@ -287,7 +298,6 @@ func TestPVHysteresis(t *testing.T) { } for _, status := range []api.ChargeStatus{api.StatusB, api.StatusC} { - for _, tc := range tc { t.Log(tc) @@ -823,3 +833,115 @@ func TestVehicleDetectByID(t *testing.T) { } } } + +func TestDefaultVehicle(t *testing.T) { + ctrl := gomock.NewController(t) + + dflt := mock.NewMockVehicle(ctrl) + dflt.EXPECT().Title().Return("default").AnyTimes() + dflt.EXPECT().Capacity().AnyTimes() + dflt.EXPECT().Phases().AnyTimes() + dflt.EXPECT().OnIdentified().AnyTimes() + + vehicle := mock.NewMockVehicle(ctrl) + vehicle.EXPECT().Title().Return("target").AnyTimes() + vehicle.EXPECT().Capacity().AnyTimes() + vehicle.EXPECT().Phases().AnyTimes() + vehicle.EXPECT().OnIdentified().AnyTimes() + + lp := NewLoadPoint(util.NewLogger("foo")) + lp.defaultVehicle = dflt + + // populate channels + x, y, z := createChannels(t) + attachChannels(lp, x, y, z) + + title := func(v api.Vehicle) string { + if v == nil { + return "" + } + return v.Title() + } + + // non-default vehicle identified + lp.setActiveVehicle(vehicle) + if lp.vehicle != vehicle { + t.Errorf("expected %v, got %v", title(vehicle), title(lp.vehicle)) + } + + // non-default vehicle disconnected + lp.evVehicleDisconnectHandler() + if lp.vehicle != dflt { + t.Errorf("expected %v, got %v", title(dflt), title(lp.vehicle)) + } + + // default vehicle disconnected + lp.evVehicleDisconnectHandler() + if lp.vehicle != dflt { + t.Errorf("expected %v, got %v", title(dflt), title(lp.vehicle)) + } + + // guest connected + lp.setActiveVehicle(nil) + if lp.vehicle != nil { + t.Errorf("expected %v, got %v", nil, title(lp.vehicle)) + } +} + +func TestApplyVehicleDefaults(t *testing.T) { + ctrl := gomock.NewController(t) + + newConfig := func(mode api.ChargeMode, minCurrent, maxCurrent float64, minSoC, targetSoC int) api.ActionConfig { + return api.ActionConfig{ + Mode: &mode, + MinCurrent: &minCurrent, + MaxCurrent: &maxCurrent, + MinSoC: &minSoC, + TargetSoC: &targetSoC, + } + } + + assertConfig := func(lp *LoadPoint, conf api.ActionConfig) { + if lp.Mode != *conf.Mode { + t.Errorf("expected mode %v, got %v", *conf.Mode, lp.Mode) + } + if lp.MinCurrent != *conf.MinCurrent { + t.Errorf("expected minCurrent %v, got %v", *conf.MinCurrent, lp.MinCurrent) + } + if lp.MaxCurrent != *conf.MaxCurrent { + t.Errorf("expected maxCurrent %v, got %v", *conf.MaxCurrent, lp.MaxCurrent) + } + if lp.SoC.Min != *conf.MinSoC { + t.Errorf("expected minSoC %v, got %v", *conf.MinSoC, lp.SoC.Min) + } + if lp.SoC.Target != *conf.TargetSoC { + t.Errorf("expected targetSoC %v, got %v", *conf.TargetSoC, lp.SoC.Target) + } + } + + oi := newConfig(api.ModePV, 7, 17, 1, 99) + od := newConfig(api.ModeOff, 5, 15, 2, 98) + + vehicle := mock.NewMockVehicle(ctrl) + vehicle.EXPECT().Title().AnyTimes() + vehicle.EXPECT().Capacity().AnyTimes() + vehicle.EXPECT().OnIdentified().Return(oi) + + lp := NewLoadPoint(util.NewLogger("foo")) + + // populate channels + x, y, z := createChannels(t) + attachChannels(lp, x, y, z) + + lp.onDisconnect = od + lp.ResetOnDisconnect = true + + // vehicle identified + lp.setActiveVehicle(vehicle) + assertConfig(lp, oi) + + // vehicle disconnected + vehicle.EXPECT().Phases().AnyTimes() + lp.evVehicleDisconnectHandler() + assertConfig(lp, od) +}