incident-tools.test.ts220 lines · main
1import { beforeEach, describe, expect, it, vi } from 'vitest'
2
3import { getIncidentTools } from './incident-tools'
4
5// Mock IS_PLATFORM
6vi.mock('common', () => ({
7 IS_PLATFORM: true,
8}))
9
10describe('ai/tools/incident-tools', () => {
11 let mockFetch: ReturnType<typeof vi.fn>
12 let mockAbortSignal: AbortSignal
13
14 beforeEach(() => {
15 vi.clearAllMocks()
16 mockFetch = vi.fn()
17 global.fetch = mockFetch as typeof fetch
18
19 // Mock AbortSignal.timeout
20 mockAbortSignal = new AbortController().signal
21 if (!AbortSignal.timeout) {
22 AbortSignal.timeout = vi.fn(() => mockAbortSignal) as any
23 }
24 })
25
26 describe('getIncidentTools', () => {
27 it('should return an object with get_active_incidents tool', () => {
28 const tools = getIncidentTools({ baseUrl: 'https://supabase.com/dashboard' })
29
30 expect(tools).toBeDefined()
31 expect(tools.get_active_incidents).toBeDefined()
32 })
33
34 it('should have correct description for get_active_incidents', () => {
35 const tools = getIncidentTools({ baseUrl: 'https://supabase.com/dashboard' })
36
37 expect(tools.get_active_incidents.description).toContain('Check for active incidents')
38 expect(tools.get_active_incidents.description).toContain('Briven service')
39 })
40
41 it('should have empty input schema', () => {
42 const tools = getIncidentTools({ baseUrl: 'https://supabase.com/dashboard' })
43 const schema = tools.get_active_incidents.inputSchema
44
45 // The schema is a Zod object that accepts empty object
46 expect(schema).toBeDefined()
47 expect((schema as any)._def.typeName).toBe('ZodObject')
48 })
49
50 describe('execute function', () => {
51 it('should return empty incidents when not on platform', async () => {
52 const common = await import('common')
53 vi.spyOn(common, 'IS_PLATFORM', 'get').mockReturnValue(false)
54
55 const tools = getIncidentTools({ baseUrl: 'https://supabase.com/dashboard' })
56 const result = await (tools.get_active_incidents.execute as any)({})
57
58 expect(result).toEqual({
59 incidents: [],
60 message: 'Incident checking is only available on Briven platform.',
61 })
62 expect(mockFetch).not.toHaveBeenCalled()
63 })
64
65 it('should fetch incidents from correct URL', async () => {
66 const common = await import('common')
67 vi.spyOn(common, 'IS_PLATFORM', 'get').mockReturnValue(true)
68
69 mockFetch.mockResolvedValue({
70 ok: true,
71 json: async () => [],
72 })
73
74 const tools = getIncidentTools({ baseUrl: 'https://example.com/dashboard' })
75 if (!tools.get_active_incidents.execute) throw new Error('execute is undefined')
76 await tools.get_active_incidents.execute({}, { toolCallId: 'test', messages: [] })
77
78 expect(mockFetch).toHaveBeenCalledWith(
79 'https://example.com/dashboard/api/incident-status',
80 {
81 signal: expect.any(AbortSignal),
82 }
83 )
84 })
85
86 it('should return message when no incidents', async () => {
87 const common = await import('common')
88 vi.spyOn(common, 'IS_PLATFORM', 'get').mockReturnValue(true)
89
90 mockFetch.mockResolvedValue({
91 ok: true,
92 json: async () => [],
93 })
94
95 const tools = getIncidentTools({ baseUrl: 'https://supabase.com/dashboard' })
96 const result = await (tools.get_active_incidents.execute as any)({})
97
98 expect(result).toEqual({
99 incidents: [],
100 message: expect.stringContaining('No active incidents'),
101 })
102 })
103
104 it('should return incident summaries when incidents exist', async () => {
105 const common = await import('common')
106 vi.spyOn(common, 'IS_PLATFORM', 'get').mockReturnValue(true)
107
108 const mockIncidents = [
109 {
110 name: 'Database slowness',
111 status: 'investigating',
112 impact: 'minor',
113 active_since: '2024-01-01T10:00:00Z',
114 extra_field: 'should be filtered',
115 },
116 ]
117
118 mockFetch.mockResolvedValue({
119 ok: true,
120 json: async () => mockIncidents,
121 })
122
123 const tools = getIncidentTools({ baseUrl: 'https://supabase.com/dashboard' })
124 const result = await (tools.get_active_incidents.execute as any)({})
125
126 expect((result as any).incidents).toEqual([
127 {
128 name: 'Database slowness',
129 status: 'investigating',
130 impact: 'minor',
131 active_since: '2024-01-01T10:00:00Z',
132 },
133 ])
134 expect((result as any).message).toContain('1 active incident')
135 expect((result as any).message).toContain('status.supabase.com')
136 })
137
138 it('should handle multiple incidents', async () => {
139 const common = await import('common')
140 vi.spyOn(common, 'IS_PLATFORM', 'get').mockReturnValue(true)
141
142 const mockIncidents = [
143 {
144 name: 'Database issue',
145 status: 'investigating',
146 impact: 'major',
147 active_since: '2024-01-01T10:00:00Z',
148 },
149 {
150 name: 'Storage issue',
151 status: 'identified',
152 impact: 'minor',
153 active_since: '2024-01-01T11:00:00Z',
154 },
155 ]
156
157 mockFetch.mockResolvedValue({
158 ok: true,
159 json: async () => mockIncidents,
160 })
161
162 const tools = getIncidentTools({ baseUrl: 'https://supabase.com/dashboard' })
163 const result = await (tools.get_active_incidents.execute as any)({})
164
165 expect((result as any).incidents).toHaveLength(2)
166 expect((result as any).message).toContain('2 active incidents')
167 })
168
169 it('should handle fetch errors', async () => {
170 const common = await import('common')
171 vi.spyOn(common, 'IS_PLATFORM', 'get').mockReturnValue(true)
172
173 mockFetch.mockRejectedValue(new Error('Network error'))
174
175 const tools = getIncidentTools({ baseUrl: 'https://supabase.com/dashboard' })
176 const result = await (tools.get_active_incidents.execute as any)({})
177
178 expect(result).toEqual({
179 incidents: [],
180 error: 'Unable to check incident status at this time.',
181 })
182 })
183
184 it('should handle non-ok responses', async () => {
185 const common = await import('common')
186 vi.spyOn(common, 'IS_PLATFORM', 'get').mockReturnValue(true)
187
188 mockFetch.mockResolvedValue({
189 ok: false,
190 status: 500,
191 })
192
193 const tools = getIncidentTools({ baseUrl: 'https://supabase.com/dashboard' })
194 const result = await (tools.get_active_incidents.execute as any)({})
195
196 expect(result).toEqual({
197 incidents: [],
198 error: 'Unable to check incident status at this time.',
199 })
200 })
201
202 it('should use timeout signal', async () => {
203 const common = await import('common')
204 vi.spyOn(common, 'IS_PLATFORM', 'get').mockReturnValue(true)
205
206 mockFetch.mockResolvedValue({
207 ok: true,
208 json: async () => [],
209 })
210
211 const tools = getIncidentTools({ baseUrl: 'https://supabase.com/dashboard' })
212 if (!tools.get_active_incidents.execute) throw new Error('execute is undefined')
213 await tools.get_active_incidents.execute({}, { toolCallId: 'test', messages: [] })
214
215 const callArgs = mockFetch.mock.calls[0]
216 expect(callArgs[1].signal).toBeInstanceOf(AbortSignal)
217 })
218 })
219 })
220})