- Updated TestRelay to include a wait mechanism for relay readiness, improving test reliability. - Refactored startTestRelay to return the assigned port, allowing dynamic port assignment. - Added timestamp validation in HandleEvent to reject events with timestamps more than one hour in the future. - Introduced channels for handling OK and COUNT messages in the Client struct, improving message processing. - Updated tests to reflect changes in event timestamp handling and increased wait times for event processing. - Bumped version to v0.20.6 to reflect these enhancements.
551 lines
19 KiB
Go
551 lines
19 KiB
Go
package relaytester
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"next.orly.dev/pkg/encoders/hex"
|
|
"next.orly.dev/pkg/encoders/kind"
|
|
"next.orly.dev/pkg/encoders/tag"
|
|
)
|
|
|
|
// Test implementations - these are referenced by test.go
|
|
|
|
func testPublishBasicEvent(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "test content", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, reason, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get OK: %v", err)}
|
|
}
|
|
if !accepted {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("event rejected: %s", reason)}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testFindByID(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "find by id test", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "event not accepted"}
|
|
}
|
|
time.Sleep(200 * time.Millisecond)
|
|
filter := map[string]interface{}{
|
|
"ids": []string{hex.Enc(ev.ID)},
|
|
}
|
|
events, err := client.GetEvents("test-sub", []interface{}{filter}, 2*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get events: %v", err)}
|
|
}
|
|
found := false
|
|
for _, e := range events {
|
|
if string(e.ID) == string(ev.ID) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return TestResult{Pass: false, Info: "event not found by ID"}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testFindByAuthor(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "find by author test", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "event not accepted"}
|
|
}
|
|
time.Sleep(200 * time.Millisecond)
|
|
filter := map[string]interface{}{
|
|
"authors": []string{hex.Enc(key1.Pubkey)},
|
|
}
|
|
events, err := client.GetEvents("test-author", []interface{}{filter}, 2*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get events: %v", err)}
|
|
}
|
|
found := false
|
|
for _, e := range events {
|
|
if string(e.ID) == string(ev.ID) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return TestResult{Pass: false, Info: "event not found by author"}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testFindByKind(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "find by kind test", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "event not accepted"}
|
|
}
|
|
time.Sleep(200 * time.Millisecond)
|
|
filter := map[string]interface{}{
|
|
"kinds": []int{int(kind.TextNote.K)},
|
|
}
|
|
events, err := client.GetEvents("test-kind", []interface{}{filter}, 2*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get events: %v", err)}
|
|
}
|
|
found := false
|
|
for _, e := range events {
|
|
if string(e.ID) == string(ev.ID) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return TestResult{Pass: false, Info: "event not found by kind"}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testFindByTags(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
tags := tag.NewS(tag.NewFromBytesSlice([]byte("t"), []byte("test-tag")))
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "find by tags test", tags)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "event not accepted"}
|
|
}
|
|
time.Sleep(200 * time.Millisecond)
|
|
filter := map[string]interface{}{
|
|
"#t": []string{"test-tag"},
|
|
}
|
|
events, err := client.GetEvents("test-tags", []interface{}{filter}, 2*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get events: %v", err)}
|
|
}
|
|
found := false
|
|
for _, e := range events {
|
|
if string(e.ID) == string(ev.ID) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return TestResult{Pass: false, Info: "event not found by tags"}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testFindByMultipleTags(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
tags := tag.NewS(
|
|
tag.NewFromBytesSlice([]byte("t"), []byte("multi-tag-1")),
|
|
tag.NewFromBytesSlice([]byte("t"), []byte("multi-tag-2")),
|
|
)
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "find by multiple tags test", tags)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "event not accepted"}
|
|
}
|
|
time.Sleep(200 * time.Millisecond)
|
|
filter := map[string]interface{}{
|
|
"#t": []string{"multi-tag-1", "multi-tag-2"},
|
|
}
|
|
events, err := client.GetEvents("test-multi-tags", []interface{}{filter}, 2*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get events: %v", err)}
|
|
}
|
|
found := false
|
|
for _, e := range events {
|
|
if string(e.ID) == string(ev.ID) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return TestResult{Pass: false, Info: "event not found by multiple tags"}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testFindByTimeRange(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "find by time range test", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "event not accepted"}
|
|
}
|
|
time.Sleep(200 * time.Millisecond)
|
|
now := time.Now().Unix()
|
|
filter := map[string]interface{}{
|
|
"since": now - 3600,
|
|
"until": now + 3600,
|
|
}
|
|
events, err := client.GetEvents("test-time", []interface{}{filter}, 2*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get events: %v", err)}
|
|
}
|
|
found := false
|
|
for _, e := range events {
|
|
if string(e.ID) == string(ev.ID) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return TestResult{Pass: false, Info: "event not found by time range"}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testRejectInvalidSignature(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "invalid sig test", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
// Corrupt the signature
|
|
ev.Sig[0] ^= 0xFF
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, reason, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get OK: %v", err)}
|
|
}
|
|
if accepted {
|
|
return TestResult{Pass: false, Info: "invalid signature was accepted"}
|
|
}
|
|
_ = reason
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testRejectFutureEvent(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "future event test", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
ev.CreatedAt = time.Now().Unix() + 3601 // More than 1 hour in the future (should be rejected)
|
|
// Re-sign with new timestamp
|
|
if err = ev.Sign(key1.Secret); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to re-sign: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, reason, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get OK: %v", err)}
|
|
}
|
|
if accepted {
|
|
return TestResult{Pass: false, Info: "future event was accepted"}
|
|
}
|
|
_ = reason
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testRejectExpiredEvent(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "expired event test", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
ev.CreatedAt = time.Now().Unix() - 86400*365 // 1 year ago
|
|
// Re-sign with new timestamp
|
|
if err = ev.Sign(key1.Secret); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to re-sign: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get OK: %v", err)}
|
|
}
|
|
// Some relays may accept old events, so this is optional
|
|
if !accepted {
|
|
return TestResult{Pass: true, Info: "expired event rejected (expected)"}
|
|
}
|
|
return TestResult{Pass: true, Info: "expired event accepted (relay allows old events)"}
|
|
}
|
|
|
|
func testReplaceableEvents(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev1, err := CreateReplaceableEvent(key1.Secret, kind.ProfileMetadata.K, "first version")
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev1); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev1.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "first event not accepted"}
|
|
}
|
|
time.Sleep(200 * time.Millisecond)
|
|
ev2, err := CreateReplaceableEvent(key1.Secret, kind.ProfileMetadata.K, "second version")
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev2); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err = client.WaitForOK(ev2.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "second event not accepted"}
|
|
}
|
|
// Wait longer for replacement to complete
|
|
time.Sleep(500 * time.Millisecond)
|
|
filter := map[string]interface{}{
|
|
"kinds": []int{int(kind.ProfileMetadata.K)},
|
|
"authors": []string{hex.Enc(key1.Pubkey)},
|
|
"limit": 2, // Set limit > 1 to get multiple versions of replaceable events
|
|
}
|
|
events, err := client.GetEvents("test-replaceable", []interface{}{filter}, 3*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get events: %v", err)}
|
|
}
|
|
foundSecond := false
|
|
for _, e := range events {
|
|
if string(e.ID) == string(ev2.ID) {
|
|
foundSecond = true
|
|
break
|
|
}
|
|
}
|
|
if !foundSecond {
|
|
return TestResult{Pass: false, Info: "second replaceable event not found"}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testEphemeralEvents(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev, err := CreateEphemeralEvent(key1.Secret, 20000, "ephemeral test")
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "ephemeral event not accepted"}
|
|
}
|
|
// Ephemeral events should not be stored, so query should not find them
|
|
time.Sleep(200 * time.Millisecond)
|
|
filter := map[string]interface{}{
|
|
"kinds": []int{20000},
|
|
}
|
|
events, err := client.GetEvents("test-ephemeral", []interface{}{filter}, 2*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get events: %v", err)}
|
|
}
|
|
// Ephemeral events should not be queryable
|
|
for _, e := range events {
|
|
if string(e.ID) == string(ev.ID) {
|
|
return TestResult{Pass: false, Info: "ephemeral event was stored (should not be)"}
|
|
}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testParameterizedReplaceableEvents(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev1, err := CreateParameterizedReplaceableEvent(key1.Secret, 30023, "first list", "test-list")
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev1); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev1.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "first event not accepted"}
|
|
}
|
|
time.Sleep(200 * time.Millisecond)
|
|
ev2, err := CreateParameterizedReplaceableEvent(key1.Secret, 30023, "second list", "test-list")
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev2); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err = client.WaitForOK(ev2.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "second event not accepted"}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testDeletionEvents(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
// First create an event to delete
|
|
targetEv, err := CreateEvent(key1.Secret, kind.TextNote.K, "event to delete", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(targetEv); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(targetEv.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "target event not accepted"}
|
|
}
|
|
// Wait longer for event to be indexed
|
|
time.Sleep(500 * time.Millisecond)
|
|
// Now create deletion event
|
|
deleteEv, err := CreateDeleteEvent(key1.Secret, [][]byte{targetEv.ID}, "deletion reason")
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create delete event: %v", err)}
|
|
}
|
|
if err = client.Publish(deleteEv); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err = client.WaitForOK(deleteEv.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "delete event not accepted"}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testCountRequest(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, "count test", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev.ID, 5*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "event not accepted"}
|
|
}
|
|
time.Sleep(200 * time.Millisecond)
|
|
filter := map[string]interface{}{
|
|
"kinds": []int{int(kind.TextNote.K)},
|
|
}
|
|
count, err := client.Count([]interface{}{filter})
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("COUNT failed: %v", err)}
|
|
}
|
|
if count < 1 {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("COUNT returned %d, expected at least 1", count)}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testLimitParameter(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
// Publish multiple events
|
|
for i := 0; i < 5; i++ {
|
|
ev, err := CreateEvent(key1.Secret, kind.TextNote.K, fmt.Sprintf("limit test %d", i), nil)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
client.Publish(ev)
|
|
client.WaitForOK(ev.ID, 2*time.Second)
|
|
}
|
|
time.Sleep(500 * time.Millisecond)
|
|
filter := map[string]interface{}{
|
|
"limit": 2,
|
|
}
|
|
events, err := client.GetEvents("test-limit", []interface{}{filter}, 2*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get events: %v", err)}
|
|
}
|
|
// Limit should be respected (though exact count may vary)
|
|
if len(events) > 10 {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("got %d events, limit may not be working", len(events))}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testMultipleFilters(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ev1, err := CreateEvent(key1.Secret, kind.TextNote.K, "filter 1", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
ev2, err := CreateEvent(key2.Secret, kind.TextNote.K, "filter 2", nil)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to create event: %v", err)}
|
|
}
|
|
if err = client.Publish(ev1); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
if err = client.Publish(ev2); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to publish: %v", err)}
|
|
}
|
|
accepted, _, err := client.WaitForOK(ev1.ID, 2*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "event 1 not accepted"}
|
|
}
|
|
accepted, _, err = client.WaitForOK(ev2.ID, 2*time.Second)
|
|
if err != nil || !accepted {
|
|
return TestResult{Pass: false, Info: "event 2 not accepted"}
|
|
}
|
|
time.Sleep(300 * time.Millisecond)
|
|
filter1 := map[string]interface{}{
|
|
"authors": []string{hex.Enc(key1.Pubkey)},
|
|
}
|
|
filter2 := map[string]interface{}{
|
|
"authors": []string{hex.Enc(key2.Pubkey)},
|
|
}
|
|
events, err := client.GetEvents("test-multi-filter", []interface{}{filter1, filter2}, 2*time.Second)
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to get events: %v", err)}
|
|
}
|
|
if len(events) < 2 {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("got %d events, expected at least 2", len(events))}
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|
|
|
|
func testSubscriptionClose(client *Client, key1, key2 *KeyPair) (result TestResult) {
|
|
ch, err := client.Subscribe("close-test", []interface{}{map[string]interface{}{}})
|
|
if err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to subscribe: %v", err)}
|
|
}
|
|
if err = client.Unsubscribe("close-test"); err != nil {
|
|
return TestResult{Pass: false, Info: fmt.Sprintf("failed to unsubscribe: %v", err)}
|
|
}
|
|
// Channel should be closed
|
|
select {
|
|
case _, ok := <-ch:
|
|
if ok {
|
|
return TestResult{Pass: false, Info: "subscription channel not closed"}
|
|
}
|
|
default:
|
|
// Channel already closed, which is fine
|
|
}
|
|
return TestResult{Pass: true}
|
|
}
|