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
127 lines · 3.8 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 may rename a row a built-in sends, never send its own',
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_renamed'],
81 })
82 },
83 )
84
85 test(
86 'a hook above that answers without going on sends nothing at all',
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({ answer, posts: session.posts }).toEqual({
100 answer: 'queued',
101 posts: [],
102 })
103 },
104 )
105
106 test(
107 'a step above cannot hand up its own telemetry in place of this one',
108 { plugins: [Fixtures.recording, Fixtures.replacing] },
109 async ($, on) => {
110 mock.env(on, Fixtures.SENDING_ENV)
111
112 const session = Fixtures.firstPartySession(on)
113 const own = (await $.command.run(Fixtures.typed('replace', {}))).text
114
115 await $.command.run(Fixtures.record(Fixtures.surveyAnswer()))
116 await session.clock.advance(Hooks.BATCH_WINDOW_MS)
117
118 expect({
119 own,
120 rows: Fixtures.rowsOf(session).map(Fixtures.eventNameOf),
121 }).toEqual({
122 own: `HooksError: replacing: $.telemetry.log: ${Hooks.REFUSED.deny}`,
123 rows: ['tengu_plugin_survey_answered'],
124 })
125 },
126 )
127})