All checks were successful
CI / changes (push) Successful in 19s
CI / test (push) Successful in 24s
CI / build-ai-gateway (push) Successful in 1m6s
CI / build-ha-gateway (push) Successful in 1m3s
CI / build-discord-bot (push) Successful in 1m4s
CI / build-alexa-bridge (push) Successful in 1m15s
CI / build-tts-gateway (push) Successful in 1m5s
CI / build-tts-sidecar (push) Has been skipped
CI / build-tts-model (push) Has been skipped
- Implemented SetTemperature in ClimateService for setting an absolute target temperature. - Updated ClimateServiceClient and ClimateServiceServer interfaces to include SetTemperature. - Added corresponding handler and tests for SetTemperature in ClimateGRPC. - Modified ClimateApp to handle SetTemperature requests without clamping. - Updated climate.proto to define SetTemperatureRequest message. - Adjusted Dockerfiles to include alexa-bridge dependencies.
110 lines
3.6 KiB
Go
110 lines
3.6 KiB
Go
package entities
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sort"
|
|
"testing"
|
|
|
|
hav1 "gitea.nik4nao.com/nik/home-services/gen/ha/v1"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
type fakeEntityServiceClient struct {
|
|
listStatesFunc func(ctx context.Context, in *hav1.ListStatesRequest) (*hav1.ListStatesResponse, error)
|
|
}
|
|
|
|
func (f *fakeEntityServiceClient) GetState(ctx context.Context, in *hav1.GetStateRequest, _ ...grpc.CallOption) (*hav1.GetStateResponse, error) {
|
|
return &hav1.GetStateResponse{}, nil
|
|
}
|
|
|
|
func (f *fakeEntityServiceClient) ListStates(ctx context.Context, in *hav1.ListStatesRequest, _ ...grpc.CallOption) (*hav1.ListStatesResponse, error) {
|
|
if f.listStatesFunc == nil {
|
|
return &hav1.ListStatesResponse{}, nil
|
|
}
|
|
return f.listStatesFunc(ctx, in)
|
|
}
|
|
|
|
func TestClientFetchAll(t *testing.T) {
|
|
t.Run("fetches per domain and extracts friendly_name", func(t *testing.T) {
|
|
fake := &fakeEntityServiceClient{
|
|
listStatesFunc: func(ctx context.Context, in *hav1.ListStatesRequest) (*hav1.ListStatesResponse, error) {
|
|
switch in.GetDomain() {
|
|
case "light":
|
|
return &hav1.ListStatesResponse{States: []*hav1.EntityState{
|
|
{EntityId: "light.living_room", Attributes: map[string]string{"friendly_name": "Living Room Lamp"}},
|
|
}}, nil
|
|
case "switch":
|
|
return &hav1.ListStatesResponse{States: []*hav1.EntityState{
|
|
{EntityId: "switch.fan", Attributes: map[string]string{"friendly_name": "Fan"}},
|
|
}}, nil
|
|
case "climate":
|
|
return &hav1.ListStatesResponse{States: []*hav1.EntityState{
|
|
{EntityId: "climate.air_conditioner", Attributes: map[string]string{}},
|
|
}}, nil
|
|
}
|
|
t.Fatalf("unexpected domain %q", in.GetDomain())
|
|
return nil, nil
|
|
},
|
|
}
|
|
c := NewClient(fake, []string{"light", "switch", "climate"})
|
|
|
|
got, err := c.FetchAll(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("FetchAll() error = %v", err)
|
|
}
|
|
sort.Slice(got, func(i, j int) bool { return got[i].EntityID < got[j].EntityID })
|
|
|
|
want := []struct {
|
|
entityID, friendlyName, domain string
|
|
}{
|
|
{"climate.air_conditioner", "climate.air_conditioner", "climate"}, // no friendly_name attr -> falls back to entity_id
|
|
{"light.living_room", "Living Room Lamp", "light"},
|
|
{"switch.fan", "Fan", "switch"},
|
|
}
|
|
if len(got) != len(want) {
|
|
t.Fatalf("len(got) = %d, want %d (got=%#v)", len(got), len(want), got)
|
|
}
|
|
for i, w := range want {
|
|
if got[i].EntityID != w.entityID || got[i].FriendlyName != w.friendlyName || got[i].Domain != w.domain {
|
|
t.Fatalf("got[%d] = %#v, want {%s %s %s}", i, got[i], w.entityID, w.friendlyName, w.domain)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("one domain failing fails the whole fetch", func(t *testing.T) {
|
|
wantErr := errors.New("boom")
|
|
fake := &fakeEntityServiceClient{
|
|
listStatesFunc: func(ctx context.Context, in *hav1.ListStatesRequest) (*hav1.ListStatesResponse, error) {
|
|
if in.GetDomain() == "switch" {
|
|
return nil, wantErr
|
|
}
|
|
return &hav1.ListStatesResponse{}, nil
|
|
},
|
|
}
|
|
c := NewClient(fake, []string{"light", "switch", "climate"})
|
|
|
|
got, err := c.FetchAll(context.Background())
|
|
if err == nil {
|
|
t.Fatal("FetchAll() error = nil, want error")
|
|
}
|
|
if !errors.Is(err, wantErr) {
|
|
t.Fatalf("FetchAll() error = %v, want it to wrap %v", err, wantErr)
|
|
}
|
|
if got != nil {
|
|
t.Fatalf("FetchAll() entities = %#v, want nil on partial failure", got)
|
|
}
|
|
})
|
|
|
|
t.Run("empty domain list returns empty result", func(t *testing.T) {
|
|
c := NewClient(&fakeEntityServiceClient{}, nil)
|
|
got, err := c.FetchAll(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("FetchAll() error = %v", err)
|
|
}
|
|
if len(got) != 0 {
|
|
t.Fatalf("FetchAll() = %#v, want empty", got)
|
|
}
|
|
})
|
|
}
|