Remove subscription_stability_test.go and improve test variable naming
Some checks failed
Go / build-and-release (push) Has been cancelled

Deleted `subscription_stability_test.go` to clean up unused or redundant code. Updated naming in test files for improved readability, replacing `tag` with `tg` for consistency. Also updated the `github.com/klauspost/compress` dependency to v1.18.2.
This commit is contained in:
2025-12-01 18:47:15 +00:00
parent 869006c4c3
commit 2166ff7013
12 changed files with 81 additions and 547 deletions

View File

@@ -1,466 +0,0 @@
package app
import (
"context"
"encoding/json"
"fmt"
"net"
"net/http/httptest"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
"git.mleku.dev/mleku/nostr/encoders/event"
"git.mleku.dev/mleku/nostr/encoders/tag"
"git.mleku.dev/mleku/nostr/interfaces/signer/p8k"
"github.com/gorilla/websocket"
"next.o
"next.orly.dev/pkg/protocol/publish"
)
// createSignedTestEvent creates a properly signed test event for use in tests
func createSignedTestEvent(t *testing.T, kind uint16, content string, tags ...*tag.T) *event.E {
t.Helper()
// Create a signer
signer, err := p8k.New()
if err != nil {
t.Fatalf("Failed to create signer: %v", err)
}
defer signer.Zero()
// Generate a keypair
if err := signer.Generate(); err != nil {
t.Fatalf("Failed to generate keypair: %v", err)
}
// Create event
ev := &event.E{
Kind: kind,
Content: []byte(content),
CreatedAt: time.Now().Unix(),
Tags: &tag.S{},
}
// Add any provided tags
for _, tg := range tags {
*ev.Tags = append(*ev.Tags, tg)
}
// Kind 3 (follow list) events must have at least one p tag
// Add a dummy p tag if none provided
if kind == 3 {
hasPTag := false
for _, tg := range tags {
if tg != nil && tg.Len() >= 1 && string(tg.Key()) == "p" {
hasPTag = true
break
}
}
if !hasPTag {
// Use the signer's own pubkey as the follow target
pubkeyHex := signer.Pub()
pTag := tag.NewFromBytesSlice([]byte("p"), pubkeyHex)
*ev.Tags = append(*ev.Tags, pTag)
}
}
// Sign the event (this sets Pubkey, ID, and Sig)
if err := ev.Sign(signer); err != nil {
t.Fatalf("Failed to sign event: %v", err)
}
return ev
}
// TestLongRunningSubscriptionStability verifies that subscriptions remain active
// for extended periods and correctly receive real-time events without dropping.
func TestLongRunningSubscriptionStability(t *testing.T) {
// Create test server
server, cleanup := setupTestServer(t)
defer cleanup()
// Start HTTP test server
httpServer := httptest.NewServer(server)
defer httpServer.Close()
// Convert HTTP URL to WebSocket URL
wsURL := strings.Replace(httpServer.URL, "http://", "ws://", 1)
// Connect WebSocket client
conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
if err != nil {
t.Fatalf("Failed to connect WebSocket: %v", err)
}
defer conn.Close()
// Subscribe to kind 1 events
subID := "test-long-running"
reqMsg := fmt.Sprintf(`["REQ","%s",{"kinds":[1]}]`, subID)
if err := conn.WriteMessage(websocket.TextMessage, []byte(reqMsg)); err != nil {
t.Fatalf("Failed to send REQ: %v", err)
}
// Read until EOSE
gotEOSE := false
for !gotEOSE {
_, msg, err := conn.ReadMessage()
if err != nil {
t.Fatalf("Failed to read message: %v", err)
}
if strings.Contains(string(msg), `"EOSE"`) && strings.Contains(string(msg), subID) {
gotEOSE = true
t.Logf("Received EOSE for subscription %s", subID)
}
}
// Set up event counter
var receivedCount atomic.Int64
var mu sync.Mutex
receivedEvents := make(map[string]bool)
// Start goroutine to read events
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
readDone := make(chan struct{})
go func() {
defer close(readDone)
defer func() {
// Recover from any panic in read goroutine
if r := recover(); r != nil {
t.Logf("Read goroutine panic (recovered): %v", r)
}
}()
for {
// Check context first before attempting any read
select {
case <-ctx.Done():
return
default:
}
// Use a longer deadline and check context more frequently
conn.SetReadDeadline(time.Now().Add(2 * time.Second))
_, msg, err := conn.ReadMessage()
if err != nil {
// Immediately check if context is done - if so, just exit without continuing
if ctx.Err() != nil {
return
}
// Check for normal close
if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
return
}
// Check if this is a timeout error - those are recoverable
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
// Double-check context before continuing
if ctx.Err() != nil {
return
}
continue
}
// Any other error means connection is broken, exit
t.Logf("Read error (non-timeout): %v", err)
return
}
// Parse message to check if it's an EVENT for our subscription
var envelope []interface{}
if err := json.Unmarshal(msg, &envelope); err != nil {
continue
}
if len(envelope) >= 3 && envelope[0] == "EVENT" && envelope[1] == subID {
// Extract event ID
eventMap, ok := envelope[2].(map[string]interface{})
if !ok {
continue
}
eventID, ok := eventMap["id"].(string)
if !ok {
continue
}
mu.Lock()
if !receivedEvents[eventID] {
receivedEvents[eventID] = true
receivedCount.Add(1)
t.Logf("Received event %s (total: %d)", eventID[:8], receivedCount.Load())
}
mu.Unlock()
}
}
}()
// Publish events at regular intervals over 30 seconds
const numEvents = 30
const publishInterval = 1 * time.Second
publishCtx, publishCancel := context.WithTimeout(context.Background(), 35*time.Second)
defer publishCancel()
for i := 0; i < numEvents; i++ {
select {
case <-publishCtx.Done():
t.Fatalf("Publish timeout exceeded")
default:
}
// Create and sign test event
ev := createSignedTestEvent(t, 1, fmt.Sprintf("Test event %d for long-running subscription", i))
// Save event to database
if _, err := server.DB.SaveEvent(context.Background(), ev); err != nil {
t.Errorf("Failed to save event %d: %v", i, err)
continue
}
// Manually trigger publisher to deliver event to subscriptions
server.publishers.Deliver(ev)
t.Logf("Published event %d", i)
// Wait before next publish
if i < numEvents-1 {
time.Sleep(publishInterval)
}
}
// Wait a bit more for all events to be delivered
time.Sleep(3 * time.Second)
// Cancel context and wait for reader to finish
cancel()
<-readDone
// Check results
received := receivedCount.Load()
t.Logf("Test complete: published %d events, received %d events", numEvents, received)
// We should receive at least 90% of events (allowing for some timing edge cases)
minExpected := int64(float64(numEvents) * 0.9)
if received < minExpected {
t.Errorf("Subscription stability issue: expected at least %d events, got %d", minExpected, received)
}
// Close subscription
closeMsg := fmt.Sprintf(`["CLOSE","%s"]`, subID)
if err := conn.WriteMessage(websocket.TextMessage, []byte(closeMsg)); err != nil {
t.Errorf("Failed to send CLOSE: %v", err)
}
t.Logf("Long-running subscription test PASSED: %d/%d events delivered", received, numEvents)
}
// TestMultipleConcurrentSubscriptions verifies that multiple subscriptions
// can coexist on the same connection without interfering with each other.
func TestMultipleConcurrentSubscriptions(t *testing.T) {
// Create test server
server, cleanup := setupTestServer(t)
defer cleanup()
// Start HTTP test server
httpServer := httptest.NewServer(server)
defer httpServer.Close()
// Convert HTTP URL to WebSocket URL
wsURL := strings.Replace(httpServer.URL, "http://", "ws://", 1)
// Connect WebSocket client
conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
if err != nil {
t.Fatalf("Failed to connect WebSocket: %v", err)
}
defer conn.Close()
// Create 3 subscriptions for different kinds
subscriptions := []struct {
id string
kind int
}{
{"sub1", 1},
{"sub2", 3},
{"sub3", 7},
}
// Subscribe to all
for _, sub := range subscriptions {
reqMsg := fmt.Sprintf(`["REQ","%s",{"kinds":[%d]}]`, sub.id, sub.kind)
if err := conn.WriteMessage(websocket.TextMessage, []byte(reqMsg)); err != nil {
t.Fatalf("Failed to send REQ for %s: %v", sub.id, err)
}
}
// Read until we get EOSE for all subscriptions
eoseCount := 0
for eoseCount < len(subscriptions) {
_, msg, err := conn.ReadMessage()
if err != nil {
t.Fatalf("Failed to read message: %v", err)
}
if strings.Contains(string(msg), `"EOSE"`) {
eoseCount++
t.Logf("Received EOSE %d/%d", eoseCount, len(subscriptions))
}
}
// Track received events per subscription
var mu sync.Mutex
receivedByKind := make(map[int]int)
// Start reader goroutine
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
readDone := make(chan struct{})
go func() {
defer close(readDone)
defer func() {
// Recover from any panic in read goroutine
if r := recover(); r != nil {
t.Logf("Read goroutine panic (recovered): %v", r)
}
}()
for {
// Check context first before attempting any read
select {
case <-ctx.Done():
return
default:
}
conn.SetReadDeadline(time.Now().Add(2 * time.Second))
_, msg, err := conn.ReadMessage()
if err != nil {
// Immediately check if context is done - if so, just exit without continuing
if ctx.Err() != nil {
return
}
// Check for normal close
if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
return
}
// Check if this is a timeout error - those are recoverable
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
// Double-check context before continuing
if ctx.Err() != nil {
return
}
continue
}
// Any other error means connection is broken, exit
t.Logf("Read error (non-timeout): %v", err)
return
}
// Parse message
var envelope []interface{}
if err := json.Unmarshal(msg, &envelope); err != nil {
continue
}
if len(envelope) >= 3 && envelope[0] == "EVENT" {
eventMap, ok := envelope[2].(map[string]interface{})
if !ok {
continue
}
kindFloat, ok := eventMap["kind"].(float64)
if !ok {
continue
}
kind := int(kindFloat)
mu.Lock()
receivedByKind[kind]++
t.Logf("Received event for kind %d (count: %d)", kind, receivedByKind[kind])
mu.Unlock()
}
}
}()
// Publish events for each kind
for _, sub := range subscriptions {
for i := 0; i < 5; i++ {
// Create and sign test event
ev := createSignedTestEvent(t, uint16(sub.kind), fmt.Sprintf("Test for kind %d event %d", sub.kind, i))
if _, err := server.DB.SaveEvent(context.Background(), ev); err != nil {
t.Errorf("Failed to save event: %v", err)
}
// Manually trigger publisher to deliver event to subscriptions
server.publishers.Deliver(ev)
time.Sleep(100 * time.Millisecond)
}
}
// Wait for events to be delivered
time.Sleep(2 * time.Second)
// Cancel and cleanup
cancel()
<-readDone
// Verify each subscription received its events
mu.Lock()
defer mu.Unlock()
for _, sub := range subscriptions {
count := receivedByKind[sub.kind]
if count < 4 { // Allow for some timing issues, expect at least 4/5
t.Errorf("Subscription %s (kind %d) only received %d/5 events", sub.id, sub.kind, count)
}
}
t.Logf("Multiple concurrent subscriptions test PASSED")
}
// setupTestServer creates a test relay server for subscription testing
func setupTestServer(t *testing.T) (*Server, func()) {
// Setup test database
ctx, cancel := context.WithCancel(context.Background())
// Use a temporary directory for the test database
tmpDir := t.TempDir()
db, err := database.New(ctx, cancel, tmpDir, "test.db")
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
// Setup basic config
cfg := &config.C{
AuthRequired: false,
Owners: []string{},
Admins: []string{},
ACLMode: "none",
}
// Setup server
server := &Server{
Config: cfg,
DB: db,
Ctx: ctx,
publishers: publish.New(NewPublisher(ctx)),
Admins: [][]byte{},
Owners: [][]byte{},
challenges: make(map[string][]byte),
}
// Cleanup function
cleanup := func() {
db.Close()
cancel()
}
return server, cleanup
}

2
go.mod
View File

@@ -9,7 +9,7 @@ require (
github.com/dgraph-io/dgo/v230 v230.0.1
github.com/gorilla/websocket v1.5.3
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
github.com/klauspost/compress v1.18.1
github.com/klauspost/compress v1.18.2
github.com/minio/sha256-simd v1.0.1
github.com/nbd-wtf/go-nostr v0.52.0
github.com/neo4j/neo4j-go-driver/v5 v5.28.4

4
go.sum
View File

@@ -109,8 +109,8 @@ github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uia
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=

View File

@@ -36,12 +36,12 @@ func TestKind3TagRoundTrip(t *testing.T) {
// Verify all tags have key "p"
pTagCount := 0
for _, tag := range *ev1.Tags {
for _, tg := range *ev1.Tags {
if tag != nil && tag.Len() >= 2 {
key := tag.Key()
key := tg.Key()
if len(key) == 1 && key[0] == 'p' {
pTagCount++
t.Logf("Found p tag with value length: %d bytes", len(tag.Value()))
t.Logf("Found p tag with value length: %d bytes", len(tg.Value()))
}
}
}
@@ -62,12 +62,12 @@ func TestKind3TagRoundTrip(t *testing.T) {
// Verify all tags still have key "p"
pTagCount2 := 0
for _, tag := range *ev2.Tags {
for _, tg := range *ev2.Tags {
if tag != nil && tag.Len() >= 2 {
key := tag.Key()
key := tg.Key()
if len(key) == 1 && key[0] == 'p' {
pTagCount2++
t.Logf("Found p tag after round-trip with value length: %d bytes", len(tag.Value()))
t.Logf("Found p tag after round-trip with value length: %d bytes", len(tg.Value()))
}
}
}

View File

@@ -581,8 +581,8 @@ func TestQueryEventsByTag(t *testing.T) {
for _, ev := range events {
if ev.Tags != nil && ev.Tags.Len() > 0 {
// Find a tag with at least 2 elements and first element of length 1
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testTagEvent = ev
break
}
@@ -600,9 +600,9 @@ func TestQueryEventsByTag(t *testing.T) {
// Get the first tag with at least 2 elements and first element of length 1
var testTag *tag.T
for _, tag := range *testTagEvent.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
testTag = tag
for _, tg := range *testTagEvent.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testTag = tg
break
}
}
@@ -627,10 +627,10 @@ func TestQueryEventsByTag(t *testing.T) {
// Verify all events have the tag
for i, ev := range evs {
var hasTag bool
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
if utils.FastEqual(tag.Key(), testTag.Key()) &&
utils.FastEqual(tag.Value(), testTag.Value()) {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
if utils.FastEqual(tg.Key(), testTag.Key()) &&
utils.FastEqual(tg.Value(), testTag.Value()) {
hasTag = true
break
}

View File

@@ -97,8 +97,8 @@ func TestQueryForAuthorsTags(t *testing.T) {
if ev.Tags != nil && ev.Tags.Len() > 0 {
// Find a tag with at least 2 elements and the first element of
// length 1
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testEvent = ev
break
}
@@ -115,9 +115,9 @@ func TestQueryForAuthorsTags(t *testing.T) {
// Get the first tag with at least 2 elements and first element of length 1
var testTag *tag.T
for _, tag := range *testEvent.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
testTag = tag
for _, tg := range *testEvent.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testTag = tg
break
}
}
@@ -163,11 +163,11 @@ func TestQueryForAuthorsTags(t *testing.T) {
// Check if the event has the tag we're looking for
var hasTag bool
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
if utils.FastEqual(
tag.Key(), testTag.Key(),
) && utils.FastEqual(tag.Value(), testTag.Value()) {
tg.Key(), testTag.Key(),
) && utils.FastEqual(tg.Value(), testTag.Value()) {
hasTag = true
break
}

View File

@@ -172,8 +172,8 @@ func TestQueryForIds(t *testing.T) {
for _, ev := range events {
if ev.Tags != nil && ev.Tags.Len() > 0 {
// Find a tag with at least 2 elements and first element of length 1
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testEvent = ev
break
}
@@ -187,9 +187,9 @@ func TestQueryForIds(t *testing.T) {
if testEvent != nil {
// Get the first tag with at least 2 elements and first element of length 1
var testTag *tag.T
for _, tag := range *testEvent.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
testTag = tag
for _, tg := range *testEvent.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testTag = tg
break
}
}
@@ -221,11 +221,11 @@ func TestQueryForIds(t *testing.T) {
// Check if the event has the tag we're looking for
var hasTag bool
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
if utils.FastEqual(
tag.Key(), testTag.Key(),
) && utils.FastEqual(tag.Value(), testTag.Value()) {
tg.Key(), testTag.Key(),
) && utils.FastEqual(tg.Value(), testTag.Value()) {
hasTag = true
break
}
@@ -325,11 +325,11 @@ func TestQueryForIds(t *testing.T) {
// Check if the event has the tag we're looking for
var hasTag bool
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
if utils.FastEqual(
tag.Key(), testTag.Key(),
) && utils.FastEqual(tag.Value(), testTag.Value()) {
tg.Key(), testTag.Key(),
) && utils.FastEqual(tg.Value(), testTag.Value()) {
hasTag = true
break
}
@@ -393,11 +393,11 @@ func TestQueryForIds(t *testing.T) {
// Check if the event has the tag we're looking for
var hasTag bool
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
if utils.FastEqual(
tag.Key(), testTag.Key(),
) && utils.FastEqual(tag.Value(), testTag.Value()) {
tg.Key(), testTag.Key(),
) && utils.FastEqual(tg.Value(), testTag.Value()) {
hasTag = true
break
}
@@ -454,11 +454,11 @@ func TestQueryForIds(t *testing.T) {
// Check if the event has the tag we're looking for
var hasTag bool
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
if utils.FastEqual(
tag.Key(), testTag.Key(),
) && utils.FastEqual(tag.Value(), testTag.Value()) {
tg.Key(), testTag.Key(),
) && utils.FastEqual(tg.Value(), testTag.Value()) {
hasTag = true
break
}

View File

@@ -97,8 +97,8 @@ func TestQueryForKindsAuthorsTags(t *testing.T) {
for _, ev := range events {
if ev.Tags != nil && ev.Tags.Len() > 0 {
// Find a tag with at least 2 elements and first element of length 1
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testEvent = ev
break
}
@@ -115,9 +115,9 @@ func TestQueryForKindsAuthorsTags(t *testing.T) {
// Get the first tag with at least 2 elements and first element of length 1
var testTag *tag.T
for _, tag := range *testEvent.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
testTag = tag
for _, tg := range *testEvent.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testTag = tg
break
}
}
@@ -174,11 +174,11 @@ func TestQueryForKindsAuthorsTags(t *testing.T) {
// Check if the event has the tag we're looking for
var hasTag bool
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
if utils.FastEqual(
tag.Key(), testTag.Key(),
) && utils.FastEqual(tag.Value(), testTag.Value()) {
tg.Key(), testTag.Key(),
) && utils.FastEqual(tg.Value(), testTag.Value()) {
hasTag = true
break
}

View File

@@ -97,8 +97,8 @@ func TestQueryForKindsTags(t *testing.T) {
for _, ev := range events {
if ev.Tags != nil && ev.Tags.Len() > 0 {
// Find a tag with at least 2 elements and first element of length 1
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testEvent = ev
break
}
@@ -115,9 +115,9 @@ func TestQueryForKindsTags(t *testing.T) {
// Get the first tag with at least 2 elements and first element of length 1
var testTag *tag.T
for _, tag := range *testEvent.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
testTag = tag
for _, tg := range *testEvent.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testTag = tg
break
}
}
@@ -163,11 +163,11 @@ func TestQueryForKindsTags(t *testing.T) {
// Check if the event has the tag we're looking for
var hasTag bool
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
if utils.FastEqual(
tag.Key(), testTag.Key(),
) && utils.FastEqual(tag.Value(), testTag.Value()) {
tg.Key(), testTag.Key(),
) && utils.FastEqual(tg.Value(), testTag.Value()) {
hasTag = true
break
}

View File

@@ -92,8 +92,8 @@ func TestQueryForTags(t *testing.T) {
for _, ev := range events {
if ev.Tags != nil && ev.Tags.Len() > 0 {
// Find a tag with at least 2 elements and first element of length 1
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testEvent = ev
break
}
@@ -110,9 +110,9 @@ func TestQueryForTags(t *testing.T) {
// Get the first tag with at least 2 elements and first element of length 1
var testTag *tag.T
for _, tag := range *testEvent.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
testTag = tag
for _, tg := range *testEvent.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
testTag = tg
break
}
}
@@ -147,11 +147,11 @@ func TestQueryForTags(t *testing.T) {
// Check if the event has the tag we're looking for
var hasTag bool
for _, tag := range *ev.Tags {
if tag.Len() >= 2 && len(tag.Key()) == 1 {
for _, tg := range *ev.Tags {
if tg.Len() >= 2 && len(tg.Key()) == 1 {
if utils.FastEqual(
tag.Key(), testTag.Key(),
) && utils.FastEqual(tag.Value(), testTag.Value()) {
tg.Key(), testTag.Key(),
) && utils.FastEqual(tg.Value(), testTag.Value()) {
hasTag = true
break
}

View File

@@ -896,7 +896,7 @@ func TestFollowsWhitelistAdminsWithWriteAllow(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
// Generate if needed
if tt.signer.Pub() == nil {
tt.signer.Generate()
_ = tt.signer.Generate()
}
ev := createTestEventForNewFields(t, tt.signer, "test", 1)

View File

@@ -87,7 +87,7 @@ type Rule struct {
ReadDeny []string `json:"read_deny,omitempty"`
// MaxExpiry is the maximum expiry time in seconds for events written to the relay. If 0, there is no maximum expiry. Events must have an expiry time if this is set, and it must be no more than this value in the future compared to the event's created_at time.
// Deprecated: Use MaxExpiryDuration instead for human-readable duration strings.
MaxExpiry *int64 `json:"max_expiry,omitempty"`
MaxExpiry *int64 `json:"max_expiry,omitempty"` //nolint:staticcheck // Intentional backward compatibility
// MaxExpiryDuration is the maximum expiry time in ISO-8601 duration format.
// Format: P[n]Y[n]M[n]W[n]DT[n]H[n]M[n]S (e.g., "P7D" for 7 days, "PT1H" for 1 hour, "P1DT12H" for 1 day 12 hours).
// Parsed into maxExpirySeconds at load time.
@@ -152,7 +152,7 @@ func (r *Rule) hasAnyRules() bool {
len(r.readAllowBin) > 0 || len(r.readDenyBin) > 0 ||
r.SizeLimit != nil || r.ContentLimit != nil ||
r.MaxAgeOfEvent != nil || r.MaxAgeEventInFuture != nil ||
r.MaxExpiry != nil || r.MaxExpiryDuration != "" || r.maxExpirySeconds != nil ||
r.MaxExpiry != nil || r.MaxExpiryDuration != "" || r.maxExpirySeconds != nil || //nolint:staticcheck // Backward compat
len(r.MustHaveTags) > 0 ||
r.Script != "" || r.Privileged ||
r.WriteAllowFollows || len(r.FollowsWhitelistAdmins) > 0 ||
@@ -226,9 +226,9 @@ func (r *Rule) populateBinaryCache() error {
} else {
r.maxExpirySeconds = &seconds
}
} else if r.MaxExpiry != nil {
} else if r.MaxExpiry != nil { //nolint:staticcheck // Backward compatibility
// Fall back to MaxExpiry (raw seconds) if MaxExpiryDuration not set
r.maxExpirySeconds = r.MaxExpiry
r.maxExpirySeconds = r.MaxExpiry //nolint:staticcheck // Backward compatibility
}
// Compile IdentifierRegex pattern
@@ -956,7 +956,7 @@ func (sr *ScriptRunner) readResponses() {
}
// logOutput logs the output from stderr
func (sr *ScriptRunner) logOutput(stdout, stderr io.ReadCloser) {
func (sr *ScriptRunner) logOutput(_ /* stdout */, stderr io.ReadCloser) {
defer stderr.Close()
// Only log stderr, stdout is used by readResponses