165 lines
3.8 KiB
Go
165 lines
3.8 KiB
Go
package meter
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/evcc-io/evcc/api"
|
|
"github.com/evcc-io/evcc/util"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNewPowerWallFromConfigValidation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config map[string]any
|
|
want string
|
|
}{
|
|
{
|
|
name: "missing usage",
|
|
config: map[string]any{"password": "secret"},
|
|
want: "missing usage",
|
|
},
|
|
{
|
|
name: "missing password",
|
|
config: map[string]any{"usage": "battery"},
|
|
want: "missing password",
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := NewPowerWallFromConfig(tc.config)
|
|
assert.ErrorContains(t, err, tc.want)
|
|
})
|
|
}
|
|
}
|
|
|
|
// decodePowerWallConfig mirrors the decoding done by the meter constructors
|
|
func decodePowerWallConfig(t *testing.T, other map[string]any) powerWallConfig {
|
|
t.Helper()
|
|
|
|
cc := defaultPowerWallConfig()
|
|
require.NoError(t, util.DecodeOther(other, &cc))
|
|
require.NoError(t, cc.validate())
|
|
|
|
return cc
|
|
}
|
|
|
|
func TestPowerWallConfigLegacyUsage(t *testing.T) {
|
|
tests := []struct {
|
|
usage string
|
|
want string
|
|
}{
|
|
{usage: "grid", want: "site"},
|
|
{usage: "pv", want: "solar"},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.usage, func(t *testing.T) {
|
|
cc := decodePowerWallConfig(t, map[string]any{
|
|
"usage": tc.usage,
|
|
"password": "secret",
|
|
})
|
|
assert.Equal(t, tc.want, cc.Usage)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPowerWallConfigDeprecatedParams(t *testing.T) {
|
|
decodePowerWallConfig(t, map[string]any{
|
|
"usage": "battery", "password": "secret",
|
|
"refreshToken": "token", "siteId": 123,
|
|
"maxsoc": 95, "maxchargepower": 4600, "maxdischargepower": 4600,
|
|
})
|
|
}
|
|
|
|
// battery control must fall back to the default reserve, not to zero
|
|
func TestPowerWallFleetReserve(t *testing.T) {
|
|
cc := decodePowerWallConfig(t, map[string]any{"usage": "battery", "password": "secret"})
|
|
limits := batterySocLimits{MinSoc: cc.MinSoc, MaxSoc: 100}
|
|
|
|
var reserve float64
|
|
ctrl := limits.LimitController(
|
|
func() (float64, error) { return 50, nil },
|
|
func(limit float64) error { reserve = limit; return nil },
|
|
)
|
|
|
|
tests := []struct {
|
|
mode api.BatteryMode
|
|
want float64
|
|
}{
|
|
{mode: api.BatteryNormal, want: 20},
|
|
{mode: api.BatteryHold, want: 50},
|
|
{mode: api.BatteryCharge, want: 100},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.mode.String(), func(t *testing.T) {
|
|
require.NoError(t, ctrl(tc.mode))
|
|
assert.Equal(t, tc.want, reserve)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewPowerWallFleetFromConfigValidation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config map[string]any
|
|
want string
|
|
wantSentinel error
|
|
}{
|
|
{
|
|
name: "missing client id",
|
|
config: map[string]any{
|
|
"usage": "battery",
|
|
"password": "secret",
|
|
},
|
|
want: "missing client id",
|
|
},
|
|
{
|
|
name: "missing tokens",
|
|
config: map[string]any{
|
|
"usage": "battery",
|
|
"password": "secret",
|
|
"credentials": map[string]any{
|
|
"id": "client",
|
|
},
|
|
},
|
|
wantSentinel: api.ErrMissingToken,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := NewPowerWallFleetFromConfig(tc.config)
|
|
if tc.wantSentinel != nil {
|
|
assert.ErrorIs(t, err, tc.wantSentinel)
|
|
return
|
|
}
|
|
assert.ErrorContains(t, err, tc.want)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTeslaReserveLimit(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
limit float64
|
|
want uint64
|
|
}{
|
|
{name: "negative", limit: -1, want: 0},
|
|
{name: "below cap", limit: 79.9, want: 79},
|
|
{name: "at cap", limit: 80, want: 80},
|
|
{name: "unsupported range start", limit: 81, want: 80},
|
|
{name: "unsupported range end", limit: 99.9, want: 80},
|
|
{name: "full reserve", limit: 100, want: 100},
|
|
{name: "above full reserve", limit: 101, want: 100},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert.Equal(t, tc.want, teslaReserveLimit(tc.limit))
|
|
})
|
|
}
|
|
}
|