Skip to content

Commit eb1ccdf

Browse files
committed
feat: more ups updates
1 parent d3a4f8d commit eb1ccdf

File tree

7 files changed

+501
-238
lines changed

7 files changed

+501
-238
lines changed

.claude/settings.local.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
"Bash(mv:*)",
1515
"Bash(ls:*)",
1616
"mcp__ide__getDiagnostics",
17-
"Bash(pnpm --filter \"*connect*\" test connect-status-writer.service.spec)"
17+
"Bash(pnpm --filter \"*connect*\" test connect-status-writer.service.spec)",
18+
"WebFetch(domain:github.com)",
19+
"Bash(pnpm --filter ./api test src/unraid-api/graph/resolvers/ups)",
20+
"Bash(pnpm --filter @unraid/api test src/unraid-api/graph/resolvers/ups)",
21+
"Bash(pnpm --filter @unraid/api lint)"
1822
]
1923
},
2024
"enableAllProjectMcpServers": false

api/src/unraid-api/graph/resolvers/ups/ups.inputs.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,33 @@ import { Field, InputType, Int } from '@nestjs/graphql';
22

33
@InputType()
44
export class UPSConfigInput {
5-
@Field()
6-
SERVICE: string;
5+
@Field()
6+
SERVICE!: string;
77

8-
@Field()
9-
UPSCABLE: string;
8+
@Field()
9+
UPSCABLE!: string;
1010

11-
@Field({ nullable: true })
12-
CUSTOMUPSCABLE?: string;
11+
@Field({ nullable: true })
12+
CUSTOMUPSCABLE?: string;
1313

14-
@Field()
15-
UPSTYPE: string;
14+
@Field()
15+
UPSTYPE!: string;
1616

17-
@Field({ nullable: true })
18-
DEVICE?: string;
17+
@Field({ nullable: true })
18+
DEVICE?: string;
1919

20-
@Field(() => Int, { nullable: true })
21-
OVERRIDE_UPS_CAPACITY?: number;
20+
@Field(() => Int, { nullable: true })
21+
OVERRIDE_UPS_CAPACITY?: number;
2222

23-
@Field(() => Int)
24-
BATTERYLEVEL: number;
23+
@Field(() => Int)
24+
BATTERYLEVEL!: number;
2525

26-
@Field(() => Int)
27-
MINUTES: number;
26+
@Field(() => Int)
27+
MINUTES!: number;
2828

29-
@Field(() => Int)
30-
TIMEOUT: number;
29+
@Field(() => Int)
30+
TIMEOUT!: number;
3131

32-
@Field()
33-
KILLUPS: string;
32+
@Field()
33+
KILLUPS!: string;
3434
}
Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,91 @@
1-
import { Field, ObjectType, ID, Int, Float } from '@nestjs/graphql';
1+
import { Field, Float, ID, Int, ObjectType } from '@nestjs/graphql';
22

33
@ObjectType()
44
export class UPSBattery {
5-
@Field(() => Int)
6-
chargeLevel: number;
5+
@Field(() => Int)
6+
chargeLevel!: number;
77

8-
@Field(() => Int)
9-
estimatedRuntime: number;
8+
@Field(() => Int)
9+
estimatedRuntime!: number;
1010

11-
@Field()
12-
health: string;
11+
@Field()
12+
health!: string;
1313
}
1414

1515
@ObjectType()
1616
export class UPSPower {
17-
@Field(() => Float)
18-
inputVoltage: number;
17+
@Field(() => Float)
18+
inputVoltage!: number;
1919

20-
@Field(() => Float)
21-
outputVoltage: number;
20+
@Field(() => Float)
21+
outputVoltage!: number;
2222

23-
@Field(() => Int)
24-
loadPercentage: number;
23+
@Field(() => Int)
24+
loadPercentage!: number;
2525
}
2626

2727
@ObjectType()
2828
export class UPSDevice {
29-
@Field(() => ID)
30-
id: string;
29+
@Field(() => ID)
30+
id!: string;
3131

32-
@Field()
33-
name: string;
32+
@Field()
33+
name!: string;
3434

35-
@Field()
36-
model: string;
35+
@Field()
36+
model!: string;
3737

38-
@Field()
39-
status: string;
38+
@Field()
39+
status!: string;
4040

41-
@Field(() => UPSBattery)
42-
battery: UPSBattery;
41+
@Field(() => UPSBattery)
42+
battery!: UPSBattery;
4343

44-
@Field(() => UPSPower)
45-
power: UPSPower;
44+
@Field(() => UPSPower)
45+
power!: UPSPower;
46+
}
47+
48+
@ObjectType()
49+
export class UPSConfiguration {
50+
@Field({ nullable: true })
51+
service?: string;
52+
53+
@Field({ nullable: true })
54+
upsCable?: string;
55+
56+
@Field({ nullable: true })
57+
customUpsCable?: string;
58+
59+
@Field({ nullable: true })
60+
upsType?: string;
61+
62+
@Field({ nullable: true })
63+
device?: string;
64+
65+
@Field(() => Int, { nullable: true })
66+
overrideUpsCapacity?: number;
67+
68+
@Field(() => Int, { nullable: true })
69+
batteryLevel?: number;
70+
71+
@Field(() => Int, { nullable: true })
72+
minutes?: number;
73+
74+
@Field(() => Int, { nullable: true })
75+
timeout?: number;
76+
77+
@Field({ nullable: true })
78+
killUps?: string;
79+
80+
@Field({ nullable: true })
81+
nisIp?: string;
82+
83+
@Field({ nullable: true })
84+
netServer?: string;
85+
86+
@Field({ nullable: true })
87+
upsName?: string;
88+
89+
@Field({ nullable: true })
90+
modelName?: string;
4691
}
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { Module } from '@nestjs/common';
2-
import { UPSResolver } from './ups.resolver.js';
3-
import { UPSService } from './ups.service.js';
2+
43
import { PubSub } from 'graphql-subscriptions';
54

5+
import { UPSResolver } from '@app/unraid-api/graph/resolvers/ups/ups.resolver.js';
6+
import { UPSService } from '@app/unraid-api/graph/resolvers/ups/ups.service.js';
7+
68
@Module({
7-
providers: [UPSResolver, UPSService, { provide: PubSub, useValue: new PubSub() }],
9+
providers: [UPSResolver, UPSService, { provide: PubSub, useValue: new PubSub() }],
810
})
911
export class UPSModule {}
Lines changed: 74 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,89 @@
11
import { Test, TestingModule } from '@nestjs/testing';
2-
import { UPSResolver } from './ups.resolver.js';
3-
import { UPSService, UPSData } from './ups.service.js';
4-
import { describe, it, expect, beforeEach, vi } from 'vitest';
5-
import { UPSConfigInput } from './ups.inputs.js';
2+
63
import { PubSub } from 'graphql-subscriptions';
4+
import { beforeEach, describe, expect, it, vi } from 'vitest';
5+
6+
import { UPSConfigInput } from '@app/unraid-api/graph/resolvers/ups/ups.inputs.js';
7+
import { UPSResolver } from '@app/unraid-api/graph/resolvers/ups/ups.resolver.js';
8+
import { UPSData, UPSService } from '@app/unraid-api/graph/resolvers/ups/ups.service.js';
79

810
describe('UPSResolver', () => {
9-
let resolver: UPSResolver;
10-
let service: UPSService;
11-
let pubSub: PubSub;
11+
let resolver: UPSResolver;
12+
let service: UPSService;
13+
let pubSub: PubSub;
1214

13-
const mockUPSData: UPSData = {
14-
MODEL: 'Test UPS',
15-
STATUS: 'Online',
16-
BCHARGE: '100',
17-
TIMELEFT: '3600',
18-
LINEV: '120.5',
19-
OUTPUTV: '120.5',
20-
LOADPCT: '25',
21-
};
15+
const mockUPSData: UPSData = {
16+
MODEL: 'Test UPS',
17+
STATUS: 'Online',
18+
BCHARGE: '100',
19+
TIMELEFT: '3600',
20+
LINEV: '120.5',
21+
OUTPUTV: '120.5',
22+
LOADPCT: '25',
23+
};
2224

23-
beforeEach(async () => {
24-
const module: TestingModule = await Test.createTestingModule({
25-
providers: [
26-
UPSResolver,
27-
{
28-
provide: UPSService,
29-
useValue: {
30-
getUPSData: vi.fn().mockResolvedValue(mockUPSData),
31-
configureUPS: vi.fn().mockResolvedValue(undefined),
32-
},
33-
},
34-
{
35-
provide: PubSub,
36-
useValue: {
37-
publish: vi.fn(),
38-
asyncIterator: vi.fn(),
39-
},
40-
},
41-
],
42-
}).compile();
25+
beforeEach(async () => {
26+
const module: TestingModule = await Test.createTestingModule({
27+
providers: [
28+
UPSResolver,
29+
{
30+
provide: UPSService,
31+
useValue: {
32+
getUPSData: vi.fn().mockResolvedValue(mockUPSData),
33+
configureUPS: vi.fn().mockResolvedValue(undefined),
34+
getCurrentConfig: vi.fn().mockResolvedValue({}),
35+
},
36+
},
37+
{
38+
provide: PubSub,
39+
useValue: {
40+
publish: vi.fn(),
41+
asyncIterableIterator: vi.fn(),
42+
},
43+
},
44+
],
45+
}).compile();
4346

44-
resolver = module.get<UPSResolver>(UPSResolver);
45-
service = module.get<UPSService>(UPSService);
46-
pubSub = module.get<PubSub>(PubSub);
47-
});
47+
resolver = module.get<UPSResolver>(UPSResolver);
48+
service = module.get<UPSService>(UPSService);
49+
pubSub = module.get<PubSub>(PubSub);
50+
});
4851

49-
it('should be defined', () => {
50-
expect(resolver).toBeDefined();
51-
});
52+
it('should be defined', () => {
53+
expect(resolver).toBeDefined();
54+
});
5255

53-
describe('upsDevices', () => {
54-
it('should return an array of UPS devices', async () => {
55-
const result = await resolver.upsDevices();
56-
expect(result).toBeInstanceOf(Array);
57-
expect(result[0].model).toBe('Test UPS');
58-
expect(service.getUPSData).toHaveBeenCalled();
56+
describe('upsDevices', () => {
57+
it('should return an array of UPS devices', async () => {
58+
const result = await resolver.upsDevices();
59+
expect(result).toBeInstanceOf(Array);
60+
expect(result[0].model).toBe('Test UPS');
61+
expect(service.getUPSData).toHaveBeenCalled();
62+
});
5963
});
60-
});
6164

62-
describe('configureUps', () => {
63-
it('should call the configureUPS service method and return true', async () => {
64-
const config: UPSConfigInput = {
65-
SERVICE: 'enable',
66-
UPSCABLE: 'usb',
67-
UPSTYPE: 'usb',
68-
BATTERYLEVEL: 10,
69-
MINUTES: 5,
70-
TIMEOUT: 0,
71-
KILLUPS: 'no',
72-
};
73-
const result = await resolver.configureUps(config);
74-
expect(result).toBe(true);
75-
expect(service.configureUPS).toHaveBeenCalledWith(config);
76-
expect(pubSub.publish).toHaveBeenCalledWith('upsUpdates', expect.any(Object));
65+
describe('configureUps', () => {
66+
it('should call the configureUPS service method and return true', async () => {
67+
const config: UPSConfigInput = {
68+
SERVICE: 'enable',
69+
UPSCABLE: 'usb',
70+
UPSTYPE: 'usb',
71+
BATTERYLEVEL: 10,
72+
MINUTES: 5,
73+
TIMEOUT: 0,
74+
KILLUPS: 'no',
75+
};
76+
const result = await resolver.configureUps(config);
77+
expect(result).toBe(true);
78+
expect(service.configureUPS).toHaveBeenCalledWith(config);
79+
expect(pubSub.publish).toHaveBeenCalledWith('upsUpdates', expect.any(Object));
80+
});
7781
});
78-
});
7982

80-
describe('upsUpdates', () => {
81-
it('should return an async iterator', () => {
82-
resolver.upsUpdates();
83-
expect(pubSub.asyncIterator).toHaveBeenCalledWith('upsUpdates');
83+
describe('upsUpdates', () => {
84+
it('should return an async iterator', () => {
85+
resolver.upsUpdates();
86+
expect(pubSub.asyncIterableIterator).toHaveBeenCalledWith('upsUpdates');
87+
});
8488
});
85-
});
8689
});

0 commit comments

Comments
 (0)