nwc_test.go raw

   1  package nwc_test
   2  
   3  import (
   4  	"context"
   5  	"testing"
   6  	"time"
   7  
   8  	"next.orly.dev/pkg/protocol/nwc"
   9  	"next.orly.dev/pkg/nostr/ws"
  10  )
  11  
  12  func TestNWCClientCreation(t *testing.T) {
  13  	uri := "nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b?relay=wss://relay.getalby.com/v1&secret=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
  14  
  15  	c, err := nwc.NewClient(uri)
  16  	if err != nil {
  17  		t.Fatal(err)
  18  	}
  19  
  20  	if c == nil {
  21  		t.Fatal("client should not be nil")
  22  	}
  23  }
  24  
  25  func TestNWCInvalidURI(t *testing.T) {
  26  	invalidURIs := []string{
  27  		"invalid://test",
  28  		"nostr+walletconnect://",
  29  		"nostr+walletconnect://invalid",
  30  		"nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b",
  31  		"nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b?relay=invalid",
  32  	}
  33  
  34  	for _, uri := range invalidURIs {
  35  		_, err := nwc.NewClient(uri)
  36  		if err == nil {
  37  			t.Fatalf("expected error for invalid URI: %s", uri)
  38  		}
  39  	}
  40  }
  41  
  42  func TestNWCRelayConnection(t *testing.T) {
  43  	ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
  44  	defer cancel()
  45  
  46  	rc, err := ws.RelayConnect(ctx, "wss://relay.getalby.com/v1")
  47  	if err != nil {
  48  		t.Fatalf("relay connection failed: %v", err)
  49  	}
  50  	defer rc.Close()
  51  
  52  	t.Log("relay connection successful")
  53  }
  54  
  55  func TestNWCRequestTimeout(t *testing.T) {
  56  	uri := "nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b?relay=wss://relay.getalby.com/v1&secret=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
  57  
  58  	c, err := nwc.NewClient(uri)
  59  	if err != nil {
  60  		t.Fatal(err)
  61  	}
  62  
  63  	ctx, cancel := context.WithTimeout(context.TODO(), 2*time.Second)
  64  	defer cancel()
  65  
  66  	var r map[string]any
  67  	err = c.Request(ctx, "get_info", nil, &r)
  68  
  69  	if err == nil {
  70  		t.Log("wallet responded")
  71  		return
  72  	}
  73  
  74  	expectedErrors := []string{
  75  		"no response from wallet",
  76  		"subscription closed",
  77  		"timeout waiting for response",
  78  		"context deadline exceeded",
  79  	}
  80  
  81  	errorFound := false
  82  	for _, expected := range expectedErrors {
  83  		if contains(err.Error(), expected) {
  84  			errorFound = true
  85  			break
  86  		}
  87  	}
  88  
  89  	if !errorFound {
  90  		t.Fatalf("unexpected error: %v", err)
  91  	}
  92  
  93  	t.Logf("proper timeout handling: %v", err)
  94  }
  95  
  96  func contains(s, substr string) bool {
  97  	return len(s) >= len(substr) && (s == substr || (len(s) > len(substr) &&
  98  		(s[:len(substr)] == substr || s[len(s)-len(substr):] == substr ||
  99  			findInString(s, substr))))
 100  }
 101  
 102  func findInString(s, substr string) bool {
 103  	for i := 0; i <= len(s)-len(substr); i++ {
 104  		if s[i:i+len(substr)] == substr {
 105  			return true
 106  		}
 107  	}
 108  	return false
 109  }
 110  
 111  func TestNWCEncryption(t *testing.T) {
 112  	uri := "nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b?relay=wss://relay.getalby.com/v1&secret=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
 113  
 114  	c, err := nwc.NewClient(uri)
 115  	if err != nil {
 116  		t.Fatal(err)
 117  	}
 118  
 119  	// We can't directly access private fields, but we can test the client creation
 120  	// check conversation key generation
 121  	if c == nil {
 122  		t.Fatal("client creation should succeed with valid URI")
 123  	}
 124  
 125  	// Test passed
 126  }
 127  
 128  func TestNWCEventFormat(t *testing.T) {
 129  	uri := "nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b?relay=wss://relay.getalby.com/v1&secret=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
 130  
 131  	c, err := nwc.NewClient(uri)
 132  	if err != nil {
 133  		t.Fatal(err)
 134  	}
 135  
 136  	// Test client creation
 137  	// The Request method will create proper NWC events with:
 138  	// - Kind 23194 for requests
 139  	// - Proper encryption tag
 140  	// - Signed with client key
 141  
 142  	ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second)
 143  	defer cancel()
 144  
 145  	var r map[string]any
 146  	err = c.Request(ctx, "get_info", nil, &r)
 147  
 148  	// We expect this to fail due to inactive connection, but it should fail
 149  	// after creating and sending NWC event
 150  	if err == nil {
 151  		t.Log("wallet responded")
 152  		return
 153  	}
 154  
 155  	// Verify it failed for the right reason (connection/response issue, not formatting)
 156  	validFailures := []string{
 157  		"subscription closed",
 158  		"no response from wallet",
 159  		"context deadline exceeded",
 160  		"timeout waiting for response",
 161  	}
 162  
 163  	validFailure := false
 164  	for _, failure := range validFailures {
 165  		if contains(err.Error(), failure) {
 166  			validFailure = true
 167  			break
 168  		}
 169  	}
 170  
 171  	if !validFailure {
 172  		t.Fatalf("unexpected error type (suggests formatting issue): %v", err)
 173  	}
 174  
 175  	// Test passed
 176  }
 177