Barazo AppView backend
barazo.forum
1import { describe, expect, it, vi } from 'vitest'
2
3import { createPluginContext } from '../../../../src/lib/plugins/context.js'
4import type { PluginContextOptions } from '../../../../src/lib/plugins/context.js'
5
6function makeLogger() {
7 return {
8 info: vi.fn(),
9 warn: vi.fn(),
10 error: vi.fn(),
11 debug: vi.fn(),
12 trace: vi.fn(),
13 fatal: vi.fn(),
14 child: vi.fn().mockReturnThis(),
15 level: 'info',
16 } as unknown as PluginContextOptions['logger']
17}
18
19function makeCacheAdapter() {
20 return {
21 get: vi.fn().mockResolvedValue(null),
22 set: vi.fn().mockResolvedValue(undefined),
23 del: vi.fn().mockResolvedValue(undefined),
24 }
25}
26
27const BASE_OPTIONS: PluginContextOptions = {
28 pluginName: '@barazo/plugin-signatures',
29 pluginVersion: '1.2.0',
30 permissions: ['db:write:plugin_signatures'],
31 settings: { maxLength: 200, prefix: '--' },
32 db: {},
33 cache: null,
34 oauthClient: null,
35 logger: makeLogger(),
36 communityDid: 'did:plc:testcommunity123',
37}
38
39describe('createPluginContext', () => {
40 it('creates context with correct pluginName, pluginVersion, and communityDid', () => {
41 const ctx = createPluginContext({ ...BASE_OPTIONS, logger: makeLogger() })
42
43 expect(ctx.pluginName).toBe('@barazo/plugin-signatures')
44 expect(ctx.pluginVersion).toBe('1.2.0')
45 expect(ctx.communityDid).toBe('did:plc:testcommunity123')
46 })
47
48 it('settings.get() returns values and undefined for missing keys', () => {
49 const ctx = createPluginContext({ ...BASE_OPTIONS, logger: makeLogger() })
50
51 expect(ctx.settings.get('maxLength')).toBe(200)
52 expect(ctx.settings.get('prefix')).toBe('--')
53 expect(ctx.settings.get('nonexistent')).toBeUndefined()
54 })
55
56 it('settings.getAll() returns a copy of settings', () => {
57 const ctx = createPluginContext({ ...BASE_OPTIONS, logger: makeLogger() })
58 const all = ctx.settings.getAll()
59
60 expect(all).toEqual({ maxLength: 200, prefix: '--' })
61 // Verify it is a copy, not the original reference
62 all['maxLength'] = 999
63 expect(ctx.settings.get('maxLength')).toBe(200)
64 })
65
66 it('scoped cache prefixes keys with plugin:<name>: for get/set/del', async () => {
67 const adapter = makeCacheAdapter()
68 const logger = makeLogger()
69 const ctx = createPluginContext({
70 ...BASE_OPTIONS,
71 permissions: ['cache:read', 'cache:write'],
72 cache: adapter,
73 logger,
74 })
75
76 const cache = ctx.cache
77 expect(cache).toBeDefined()
78 if (!cache) throw new Error('Expected cache to be defined')
79
80 await cache.get('mykey')
81 expect(adapter.get).toHaveBeenCalledWith('plugin:@barazo/plugin-signatures:mykey')
82
83 await cache.set('mykey', 'val', 60)
84 expect(adapter.set).toHaveBeenCalledWith('plugin:@barazo/plugin-signatures:mykey', 'val', 60)
85
86 await cache.del('mykey')
87 expect(adapter.del).toHaveBeenCalledWith('plugin:@barazo/plugin-signatures:mykey')
88 })
89
90 it('does not provide cache when no cache permissions', () => {
91 const adapter = makeCacheAdapter()
92 const ctx = createPluginContext({
93 ...BASE_OPTIONS,
94 permissions: ['db:write:plugin_signatures'],
95 cache: adapter,
96 logger: makeLogger(),
97 })
98
99 expect(ctx.cache).toBeUndefined()
100 })
101
102 it('provides cache when cache:read is in permissions', () => {
103 const adapter = makeCacheAdapter()
104 const ctx = createPluginContext({
105 ...BASE_OPTIONS,
106 permissions: ['cache:read'],
107 cache: adapter,
108 logger: makeLogger(),
109 })
110
111 expect(ctx.cache).toBeDefined()
112 })
113
114 it('provides cache when cache:write is in permissions', () => {
115 const adapter = makeCacheAdapter()
116 const ctx = createPluginContext({
117 ...BASE_OPTIONS,
118 permissions: ['cache:write'],
119 cache: adapter,
120 logger: makeLogger(),
121 })
122
123 expect(ctx.cache).toBeDefined()
124 })
125
126 it('creates a child logger with plugin name', () => {
127 const childFn = vi.fn().mockReturnThis()
128 const logger = { ...makeLogger(), child: childFn } as unknown as PluginContextOptions['logger']
129 createPluginContext({ ...BASE_OPTIONS, logger })
130
131 expect(childFn).toHaveBeenCalledWith({ plugin: '@barazo/plugin-signatures' })
132 })
133})
134
135describe('ScopedAtProto', () => {
136 it('provides atproto when pds:read permission is present', () => {
137 const ctx = createPluginContext({
138 ...BASE_OPTIONS,
139 permissions: ['pds:read'],
140 oauthClient: {} as never,
141 logger: makeLogger(),
142 })
143 expect(ctx.atproto).toBeDefined()
144 })
145
146 it('provides atproto when pds:write permission is present', () => {
147 const ctx = createPluginContext({
148 ...BASE_OPTIONS,
149 permissions: ['pds:write'],
150 oauthClient: {} as never,
151 logger: makeLogger(),
152 })
153 expect(ctx.atproto).toBeDefined()
154 })
155
156 it('does not provide atproto without pds permissions', () => {
157 const ctx = createPluginContext({
158 ...BASE_OPTIONS,
159 permissions: ['db:write:plugin_signatures'],
160 oauthClient: null,
161 logger: makeLogger(),
162 })
163 expect(ctx.atproto).toBeUndefined()
164 })
165
166 it('does not provide atproto when no oauthClient even with permissions', () => {
167 const ctx = createPluginContext({
168 ...BASE_OPTIONS,
169 permissions: ['pds:read', 'pds:write'],
170 oauthClient: null,
171 logger: makeLogger(),
172 })
173 expect(ctx.atproto).toBeUndefined()
174 })
175})