spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

claude-code / mods / telemetry / tests / gate.test.ts
188 lines · 5.3 KBRaw
1import { describe, expect, mock, test, tier } from 'claude-code/testing'
2
3import Hooks from '../hooks'
4import Fixtures from './fixtures'
5
6tier('builtin')
7
8const refusal = `HooksError: reaching: $.telemetry.log: ${Hooks.REFUSED.deny}`
9
10describe('gate', () => {
11 test(
12 'the table an engine.create step is handed serves no one above either',
13 { plugins: [Fixtures.recording, Fixtures.reaching] },
14 async ($, on) => {
15 mock.env(on, Fixtures.SENDING_ENV)
16
17 const session = Fixtures.firstPartySession(on)
18
19 on('tool.call', () => ({ result: 'read' }))
20
21 await $.session.start(Fixtures.STARTED)
22 await session.clock.advance(1)
23 await $.tool.call(Fixtures.READ_TOOL)
24
25 const during = (await $.command.run(Fixtures.typed('reach', {}))).text
26
27 await $.command.run(Fixtures.record(Fixtures.surveyAnswer()))
28 await session.clock.advance(Hooks.BATCH_WINDOW_MS)
29
30 expect({
31 isServedDuringCreate: during === 'served',
32 later: session.lines.filter(line => !line.startsWith('telemetry: ')),
33 rows: Fixtures.rowsOf(session).map(Fixtures.eventNameOf),
34 }).toEqual({
35 isServedDuringCreate: false,
36 later: [`timer: ${refusal}`, `tool: ${refusal}`],
37 rows: ['tengu_plugin_survey_answered'],
38 })
39 },
40 )
41
42 test(
43 'a module that keeps the table to call later never loads',
44 { plugins: [Fixtures.holding] },
45 async ($, on) => {
46 mock.env(on, Fixtures.SENDING_ENV)
47
48 const session = Fixtures.firstPartySession(on)
49
50 const held = await $.command
51 .run(Fixtures.typed('hold', {}))
52 .then(result => result.text, String)
53
54 await session.clock.advance(Hooks.BATCH_WINDOW_MS)
55
56 expect({
57 isLoaded: !String(held).includes('did not load'),
58 posts: session.posts,
59 }).toEqual({ isLoaded: false, posts: [] })
60 },
61 )
62
63 test(
64 "a hook above on the collector's stream renames no row, sends none",
65 { plugins: [Fixtures.recording, Fixtures.meddling] },
66 async ($, on) => {
67 mock.env(on, Fixtures.SENDING_ENV)
68
69 const session = Fixtures.firstPartySession(on)
70 const own = (await $.command.run(Fixtures.typed('meddle', {}))).text
71
72 await $.command.run(Fixtures.record(Fixtures.surveyAnswer()))
73 await session.clock.advance(Hooks.BATCH_WINDOW_MS)
74
75 expect({
76 own,
77 rows: Fixtures.rowsOf(session).map(Fixtures.eventNameOf),
78 }).toEqual({
79 own: `HooksError: meddling: $.telemetry.log: ${Hooks.REFUSED.deny}`,
80 rows: ['tengu_plugin_survey_answered'],
81 })
82 },
83 )
84
85 test(
86 "a hook above that swallows the collector's stream stops no row",
87 { plugins: [Fixtures.recording, Fixtures.swallowing] },
88 async ($, on) => {
89 mock.env(on, Fixtures.SENDING_ENV)
90
91 const session = Fixtures.firstPartySession(on)
92
93 const answer = (
94 await $.command.run(Fixtures.record(Fixtures.surveyAnswer()))
95 ).text
96
97 await session.clock.advance(Hooks.BATCH_WINDOW_MS)
98
99 expect({
100 answer,
101 posts: session.posts.length,
102 rows: Fixtures.rowsOf(session).map(Fixtures.eventNameOf),
103 }).toEqual({
104 answer: 'queued',
105 posts: 1,
106 rows: ['tengu_plugin_survey_answered'],
107 })
108 },
109 )
110
111 test(
112 'a step above cannot hand up its own telemetry in place of this one',
113 { plugins: [Fixtures.recording, Fixtures.replacing] },
114 async ($, on) => {
115 mock.env(on, Fixtures.SENDING_ENV)
116
117 const session = Fixtures.firstPartySession(on)
118 const own = (await $.command.run(Fixtures.typed('replace', {}))).text
119
120 await $.command.run(Fixtures.record(Fixtures.surveyAnswer()))
121 await session.clock.advance(Hooks.BATCH_WINDOW_MS)
122
123 expect({
124 own,
125 rows: Fixtures.rowsOf(session).map(Fixtures.eventNameOf),
126 }).toEqual({
127 own: `HooksError: replacing: $.telemetry.log: ${Hooks.REFUSED.deny}`,
128 rows: ['tengu_plugin_survey_answered'],
129 })
130 },
131 )
132
133 test(
134 'a hook on every event cannot turn a row to the other destination',
135 { plugins: [Fixtures.recording, Fixtures.sweeping] },
136 async ($, on) => {
137 mock.env(on, Fixtures.SENDING_ENV)
138
139 const session = Fixtures.firstPartySession(on)
140
141 await $.session.start(Fixtures.STARTED)
142
143 const answer = (
144 await $.command.run(Fixtures.record(Fixtures.surveyAnswer()))
145 ).text
146
147 await session.clock.advance(Hooks.BATCH_WINDOW_MS)
148
149 expect({
150 answer,
151 posts: session.posts.length,
152 rows: Fixtures.rowsOf(session),
153 }).toEqual({
154 answer: 'queued',
155 posts: 1,
156 rows: [Fixtures.EXPECTED_ROW],
157 })
158 },
159 )
160
161 test(
162 'what a hook on every event adds beside a row never leaves in it',
163 { plugins: [Fixtures.recording, Fixtures.annotating] },
164 async ($, on) => {
165 mock.env(on, Fixtures.SENDING_ENV)
166
167 const session = Fixtures.firstPartySession(on)
168
169 await $.session.start(Fixtures.STARTED)
170
171 const answer = (
172 await $.command.run(Fixtures.record(Fixtures.surveyAnswer()))
173 ).text
174
175 await session.clock.advance(Hooks.BATCH_WINDOW_MS)
176
177 expect({
178 answer,
179 posts: session.posts.length,
180 rows: Fixtures.rowsOf(session),
181 }).toEqual({
182 answer: 'queued',
183 posts: 1,
184 rows: [Fixtures.EXPECTED_ROW],
185 })
186 },
187 )
188})