Skip to content

Commit 32ac52e

Browse files
test: add stable NIP-22 created_at limit coverage
1 parent 32a1ec5 commit 32ac52e

4 files changed

Lines changed: 143 additions & 3 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"nostream": patch
3+
---
4+
5+
Improve NIP-22 `created_at` limit handling coverage and boundary reliability.
6+
7+
This adds integration coverage for accepted and rejected events across configured positive and negative `created_at` deltas, and keeps rejection semantics consistent (`rejected`) for out-of-range timestamps.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@nip-22
2+
Feature: NIP-22 created_at timestamp limits
3+
Scenario: Event with created_at at current time is accepted
4+
Given someone called Alice
5+
And created_at limits are set to maxPositiveDelta 900 and maxNegativeDelta 0
6+
When Alice drafts a text_note event with content "test event" and created_at 0 seconds from now
7+
Then Alice sends their last draft event successfully
8+
When Alice subscribes to author Alice
9+
Then Alice receives a text_note event from Alice with content "test event"
10+
11+
Scenario: Event with created_at above positive delta limit is rejected
12+
Given someone called Alice
13+
And created_at limits are set to maxPositiveDelta 900 and maxNegativeDelta 0
14+
When Alice drafts a text_note event with content "test event" and created_at 910 seconds from now
15+
Then Alice sends their last draft event unsuccessfully with reason containing "rejected"
16+
17+
Scenario: Event older than configured negative delta limit is rejected
18+
Given someone called Alice
19+
And created_at limits are set to maxPositiveDelta 900 and maxNegativeDelta 3600
20+
When Alice drafts a text_note event with content "test event" and created_at -3601 seconds from now
21+
Then Alice sends their last draft event unsuccessfully with reason containing "rejected"
22+
23+
Scenario: Event within configured negative delta limit is accepted
24+
Given someone called Alice
25+
And created_at limits are set to maxPositiveDelta 900 and maxNegativeDelta 3600
26+
When Alice drafts a text_note event with content "test event" and created_at -3590 seconds from now
27+
Then Alice sends their last draft event successfully
28+
When Alice subscribes to author Alice
29+
Then Alice receives a text_note event from Alice with content "test event"
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { After, Before, Given, Then, When } from '@cucumber/cucumber'
2+
import { assocPath, pipe } from 'ramda'
3+
4+
import { CommandResult, MessageType } from '../../../../src/@types/messages'
5+
import { createEvent, sendEvent } from '../helpers'
6+
7+
import { Event } from '../../../../src/@types/event'
8+
import { expect } from 'chai'
9+
import { isDraft } from '../shared'
10+
import { SettingsStatic } from '../../../../src/utils/settings'
11+
import WebSocket from 'ws'
12+
13+
const previousSettingsSnapshot = Symbol('nip22PreviousSettingsSnapshot')
14+
const draftOffsetSeconds = Symbol('nip22DraftOffsetSeconds')
15+
16+
const setCreatedAtLimits = (maxPositiveDelta: number, maxNegativeDelta: number) => {
17+
const settings = SettingsStatic._settings ?? SettingsStatic.createSettings()
18+
19+
SettingsStatic._settings = pipe(
20+
assocPath(['limits', 'event', 'createdAt', 'maxPositiveDelta'], maxPositiveDelta),
21+
assocPath(['limits', 'event', 'createdAt', 'maxNegativeDelta'], maxNegativeDelta),
22+
)(settings) as any
23+
}
24+
25+
Before({ tags: '@nip-22' }, function(this: any) {
26+
this[previousSettingsSnapshot] = SettingsStatic._settings
27+
})
28+
29+
After({ tags: '@nip-22' }, function(this: any) {
30+
SettingsStatic._settings = this[previousSettingsSnapshot]
31+
delete this[previousSettingsSnapshot]
32+
})
33+
34+
Given(/^created_at limits are set to maxPositiveDelta (\d+) and maxNegativeDelta (\d+)$/, function(
35+
maxPositiveDelta: string,
36+
maxNegativeDelta: string,
37+
) {
38+
setCreatedAtLimits(Number(maxPositiveDelta), Number(maxNegativeDelta))
39+
})
40+
41+
When(/^(\w+) drafts a text_note event with content "([^"]+)" and created_at (-?\d+) seconds from now$/, async function(
42+
name: string,
43+
content: string,
44+
offsetSeconds: string,
45+
) {
46+
const { pubkey, privkey } = this.parameters.identities[name]
47+
const createdAt = Math.floor(Date.now() / 1000) + Number(offsetSeconds)
48+
49+
const event: Event = await createEvent(
50+
{
51+
pubkey,
52+
kind: 1,
53+
content,
54+
created_at: createdAt,
55+
},
56+
privkey,
57+
)
58+
59+
const draftEvent = event as any
60+
draftEvent[isDraft] = true
61+
draftEvent[draftOffsetSeconds] = Number(offsetSeconds)
62+
63+
this.parameters.events[name].push(event)
64+
})
65+
66+
Then(/^(\w+) sends their last draft event unsuccessfully with reason containing "([^"]+)"$/, async function(
67+
name: string,
68+
expectedReason: string,
69+
) {
70+
const ws = this.parameters.clients[name] as WebSocket
71+
72+
const event = this.parameters.events[name].findLast((lastEvent: Event) => (lastEvent as any)[isDraft])
73+
if (!event) {
74+
throw new Error(`No draft event found for ${name}`)
75+
}
76+
77+
const draftEvent = event as any
78+
const offsetSeconds = draftEvent[draftOffsetSeconds]
79+
80+
let eventToSend = event
81+
if (typeof offsetSeconds === 'number') {
82+
const { pubkey, privkey } = this.parameters.identities[name]
83+
const createdAt = Math.floor(Date.now() / 1000) + offsetSeconds
84+
85+
eventToSend = await createEvent(
86+
{
87+
pubkey,
88+
kind: event.kind,
89+
content: event.content,
90+
created_at: createdAt,
91+
},
92+
privkey,
93+
)
94+
}
95+
96+
delete draftEvent[isDraft]
97+
delete draftEvent[draftOffsetSeconds]
98+
99+
const command = await sendEvent(ws, eventToSend, false) as CommandResult
100+
101+
expect(command[0]).to.equal(MessageType.OK)
102+
expect(command[2]).to.equal(false)
103+
expect(command[3].toLowerCase()).to.contain(expectedReason.toLowerCase())
104+
})

test/unit/handlers/event-message-handler.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,9 @@ describe('EventMessageHandler', () => {
291291
eventLimits.createdAt.maxPositiveDelta = 100
292292
event.created_at += 101
293293

294-
expect((handler as any).canAcceptEvent(event)).to.equal(
295-
'rejected: created_at is more than 100 seconds in the future',
296-
)
294+
expect(
295+
(handler as any).canAcceptEvent(event)
296+
).to.equal('rejected: created_at is more than 100 seconds in the future')
297297
})
298298
})
299299

0 commit comments

Comments
 (0)