151 lines
3.5 KiB
Go
151 lines
3.5 KiB
Go
package circuit
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/evcc-io/evcc/api"
|
|
"github.com/evcc-io/evcc/util"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/mock/gomock"
|
|
)
|
|
|
|
type circuitTest struct {
|
|
// current values for parent, circuit 1, circuit 2
|
|
p, c1, c2 float64
|
|
// old/new demand values and allowed result
|
|
old, new, res float64
|
|
}
|
|
|
|
func circuitTests() []circuitTest {
|
|
return []circuitTest{
|
|
// no load
|
|
{0, 0, 0, 0, 0, 0}, // =
|
|
{0, 0, 0, 0, 1, 1}, // +
|
|
{0, 0, 0, 0, 2, 1}, // +
|
|
{0, 0, 0, 1, 1, 1}, // =
|
|
|
|
// circuit 1 loaded
|
|
{0, 1, 0, 0, 0, 0}, // =
|
|
{0, 1, 0, 0, 1, 0}, // +
|
|
{0, 1, 0, 0, 2, 0}, // +
|
|
{0, 1, 0, 1, 1, 1}, // =
|
|
{0, 1, 0, 2, 1, 1}, // -
|
|
|
|
// circuit 1 overloaded
|
|
{0, 2, 0, 0, 0, 0}, // =
|
|
{0, 2, 0, 0, 1, 0}, // +
|
|
{0, 2, 0, 1, 1, 0}, // =
|
|
{0, 2, 0, 2, 2, 1}, // =
|
|
{0, 2, 0, 2, 3, 1}, // +
|
|
{0, 2, 0, 2, 1, 1}, // -
|
|
|
|
{0, 1.1, 0, 2, 1, 1}, // -
|
|
{0, 1.1, 0, 1, 0, 0}, // -
|
|
|
|
// parent loaded
|
|
{1, 0, 0, 0, 0, 0}, // =
|
|
{1, 0, 0, 0, 1, 0}, // +
|
|
{1, 0, 0, 0, 2, 0}, // +
|
|
{1, 0, 0, 1, 1, 1}, // =
|
|
{1, 0, 0, 2, 1, 1}, // -
|
|
|
|
// parent overloaded
|
|
{2, 0, 0, 0, 0, 0}, // =
|
|
{2, 0, 0, 0, 1, 0}, // +
|
|
{2, 0, 0, 1, 1, 0}, // =
|
|
{2, 0, 0, 2, 2, 1}, // =
|
|
{2, 0, 0, 2, 3, 1}, // +
|
|
{2, 0, 0, 2, 1, 1}, // -
|
|
|
|
{1.1, 0, 0, 2, 1, 1}, // -
|
|
{1.1, 0, 0, 1, 0, 0}, // -
|
|
|
|
// negative load
|
|
{-1, -1, 0, 0, 2, 2}, // +
|
|
}
|
|
}
|
|
|
|
func TestCircuitPower(t *testing.T) {
|
|
log := util.NewLogger("foo")
|
|
|
|
circ := func(t *testing.T, ctrl *gomock.Controller, maxP float64) (*Circuit, *api.MockMeter) {
|
|
m := api.NewMockMeter(ctrl)
|
|
c, err := New(log, "foo", 0, maxP, m, 0)
|
|
require.NoError(t, err)
|
|
return c, m
|
|
}
|
|
|
|
for _, tc := range circuitTests() {
|
|
ctrl := gomock.NewController(t)
|
|
|
|
pc, pm := circ(t, ctrl, 1)
|
|
c1, cm1 := circ(t, ctrl, 1)
|
|
c2, cm2 := circ(t, ctrl, 1)
|
|
|
|
c1.setParent(pc)
|
|
c2.setParent(pc)
|
|
|
|
// update meters
|
|
pm.EXPECT().CurrentPower().Return(tc.p, nil)
|
|
cm1.EXPECT().CurrentPower().Return(tc.c1, nil)
|
|
cm2.EXPECT().CurrentPower().Return(tc.c2, nil)
|
|
require.NoError(t, pc.Update(nil))
|
|
|
|
assert.Equal(t, tc.res, c1.ValidatePower(tc.old, tc.new), tc)
|
|
|
|
ctrl.Finish()
|
|
}
|
|
}
|
|
|
|
func TestCircuitCurrents(t *testing.T) {
|
|
log := util.NewLogger("foo")
|
|
|
|
type combined struct {
|
|
*api.MockMeter
|
|
*api.MockPhaseCurrents
|
|
}
|
|
circ := func(t *testing.T, ctrl *gomock.Controller, maxC float64) (*Circuit, combined) {
|
|
m := combined{
|
|
api.NewMockMeter(ctrl),
|
|
api.NewMockPhaseCurrents(ctrl),
|
|
}
|
|
c, err := New(log, "foo", maxC, 0, m, 0)
|
|
require.NoError(t, err)
|
|
return c, m
|
|
}
|
|
|
|
for _, tc := range circuitTests() {
|
|
ctrl := gomock.NewController(t)
|
|
|
|
pc, pm := circ(t, ctrl, 1)
|
|
c1, cm1 := circ(t, ctrl, 1)
|
|
c2, cm2 := circ(t, ctrl, 1)
|
|
|
|
c1.setParent(pc)
|
|
c2.setParent(pc)
|
|
|
|
// update meters
|
|
pm.MockMeter.EXPECT().CurrentPower().AnyTimes().Return(0.0, nil)
|
|
cm1.MockMeter.EXPECT().CurrentPower().AnyTimes().Return(0.0, nil)
|
|
cm2.MockMeter.EXPECT().CurrentPower().AnyTimes().Return(0.0, nil)
|
|
pm.MockPhaseCurrents.EXPECT().Currents().Return(tc.p, tc.p, tc.p, nil)
|
|
cm1.MockPhaseCurrents.EXPECT().Currents().Return(tc.c1, tc.c1, tc.c1, nil)
|
|
cm2.MockPhaseCurrents.EXPECT().Currents().Return(tc.c2, tc.c2, tc.c2, nil)
|
|
require.NoError(t, pc.Update(nil))
|
|
|
|
assert.Equal(t, tc.res, c1.ValidateCurrent(tc.old, tc.new), tc)
|
|
|
|
ctrl.Finish()
|
|
}
|
|
}
|
|
|
|
func TestWrapCycleDetection(t *testing.T) {
|
|
log := util.NewLogger("foo")
|
|
|
|
pc, _ := New(log, "root", 0, 0, nil, 0)
|
|
lpc, _ := New(log, "lpc", 0, 0, nil, 0)
|
|
|
|
require.NoError(t, lpc.setParent(pc))
|
|
require.Error(t, pc.Wrap(lpc))
|
|
}
|