Skip to content

Commit

Permalink
#297 Add tests for SensorStateService
Browse files Browse the repository at this point in the history
  • Loading branch information
TWilkin committed Jul 30, 2023
1 parent dd7ef61 commit 5669240
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 3 deletions.
6 changes: 5 additions & 1 deletion services/api/src/services/DeviceStateService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ describe("DeviceStateService", () => {
function getConsumer<TConsumer extends Message>(action: string) {
const subscriptions = capture(mockedMqttService.subscribe);

for (let i = 0; i < 3; i++) {
for (let i = 0; ; i++) {
const subscription = subscriptions.byCallIndex(i);
if (!subscription) {
break;
}

if (subscription[2] === action) {
return subscription[3] as MqttConsumer<TConsumer>;
}
Expand Down
189 changes: 189 additions & 0 deletions services/api/src/services/SensorStateService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { Message, MqttConsumer, MqttService } from "@powerpi/common";
import { capture, instance, mock, resetCalls, when } from "ts-mockito";
import ConfigService from "./ConfigService";
import SensorStateService from "./SensorStateService";
import { BatteryMessage } from "./listeners/BatteryStateListener";
import { EventMessage } from "./listeners/SensorStateListener";

const mockedConfigService = mock<ConfigService>();
const mockedMqttService = mock<MqttService>();

describe("SensorStateService", () => {
let subject: SensorStateService | undefined;

function getConsumer<TConsumer extends Message>(action: string) {
const subscriptions = capture(mockedMqttService.subscribe);

for (let i = 0; ; i++) {
const subscription = subscriptions.byCallIndex(i);
if (!subscription) {
break;
}

if (subscription[2] === action) {
return subscription[3] as MqttConsumer<TConsumer>;
}
}

return undefined;
}

beforeEach(async () => {
when(mockedConfigService.sensors).thenReturn([
{
name: "HallwayMotionSensor",
type: "motion",
location: "Hallway",
},
{
name: "BedroomTempSensor",
type: "temperature",
location: "Bedroom",
},
{
name: "Other",
display_name: "Other Sensor",
type: "other",
location: "Atlantis",
entity: "something",
action: "else",
visible: false,
},
]);

resetCalls(mockedMqttService);

subject = new SensorStateService(
instance(mockedConfigService),
instance(mockedMqttService),
);

await subject.$onInit();
});

describe("sensors", () => {
test("some", () => {
const sensors = subject?.sensors;
expect(sensors).toHaveLength(3);

let sensor = sensors![0];
expect(sensor.name).toBe("HallwayMotionSensor");
expect(sensor.display_name).toBe("HallwayMotionSensor");
expect(sensor.type).toBe("motion");
expect(sensor.location).toBe("Hallway");
expect(sensor.entity).toBe("HallwayMotionSensor");
expect(sensor.action).toBe("motion");
expect(sensor.visible).toBeTruthy();

sensor = sensors![2];
expect(sensor.name).toBe("Other");
expect(sensor.display_name).toBe("Other Sensor");
expect(sensor.type).toBe("other");
expect(sensor.location).toBe("Atlantis");
expect(sensor.entity).toBe("something");
expect(sensor.action).toBe("else");
expect(sensor.visible).toBeFalsy();
});

test("none", () => {
subject = new SensorStateService(
instance(mockedConfigService),
instance(mockedMqttService),
);

const sensors = subject?.sensors;
expect(sensors).toHaveLength(0);
});
});

test("$onInit", async () => {
when(mockedConfigService.sensors).thenReturn([]);

subject = new SensorStateService(
instance(mockedConfigService),
instance(mockedMqttService),
);

await subject.$onInit();

const sensors = subject?.sensors;
expect(sensors).toHaveLength(0);
});

describe("onSensorStateMessage", () => {
[undefined, 1234].forEach((timestamp) =>
test(`timestamp: ${timestamp}`, () => {
const consumer = getConsumer<EventMessage>("motion");

const sensor = subject?.sensors.find(
(sensor) => sensor.name == "HallwayMotionSensor",
);
expect(sensor?.state).toBeUndefined();
expect(sensor?.since).toBe(-1);

consumer?.message("event", "HallwayMotionSensor", "motion", {
state: "detected",
timestamp,
});

expect(sensor?.state).toBe("detected");

if (timestamp) {
expect(sensor?.since).toBe(timestamp);
} else {
expect(sensor?.since).toBe(-1);
}
}),
);
});

describe("onSensorDataMessage", () => {
[undefined, 1234].forEach((timestamp) =>
test(`timestamp: ${timestamp}`, () => {
const consumer = getConsumer<EventMessage>("temperature");

const sensor = subject?.sensors.find(
(sensor) => sensor.name == "BedroomTempSensor",
);
expect(sensor?.value).toBeUndefined();
expect(sensor?.unit).toBeUndefined();
expect(sensor?.since).toBe(-1);

consumer?.message("event", "BedroomTempSensor", "temperature", {
value: 100,
unit: "F",
timestamp,
});

expect(sensor?.value).toBe(100);
expect(sensor?.unit).toBe("F");

if (timestamp) {
expect(sensor?.since).toBe(timestamp);
} else {
expect(sensor?.since).toBe(-1);
}
}),
);
});

test("onBatteryMessage", () => {
const consumer = getConsumer<BatteryMessage>("battery");

const sensor = subject?.sensors.find((sensor) => sensor.name == "HallwayMotionSensor");
expect(sensor?.battery).toBeUndefined();
expect(sensor?.batterySince).toBeUndefined();
expect(sensor?.charging).toBeFalsy();

consumer?.message("event", "HallwayMotionSensor", "battery", {
value: 53,
unit: "%",
charging: true,
timestamp: 1234,
});

expect(sensor?.battery).toBe(53);
expect(sensor?.batterySince).toBe(1234);
expect(sensor?.charging).toBeTruthy();
});
});
6 changes: 5 additions & 1 deletion services/api/src/services/SensorStateService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export default class SensorStateService {
public async $onInit() {
this.initialise();

await Promise.all(this._sensors?.map((sensor) => sensor.$onInit()) ?? []);
const promises = this._sensors!.map((sensor) => sensor.$onInit());

if (promises) {
await Promise.all(promises);
}
}

private initialise() {
Expand Down
2 changes: 1 addition & 1 deletion services/api/src/services/listeners/SensorStateListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Sensor } from "@powerpi/common-api";
import MqttService from "../MqttService";
import BatteryStateListener, { BatteryMessage } from "./BatteryStateListener";

interface EventMessage extends Message {
export interface EventMessage extends Message {
state?: string;
value?: number;
unit?: string;
Expand Down

0 comments on commit 5669240

Please sign in to comment.