testmain_test.go raw

   1  package database
   2  
   3  import (
   4  	"bufio"
   5  	"bytes"
   6  	"context"
   7  	"io"
   8  	"os"
   9  	"sort"
  10  	"sync"
  11  	"testing"
  12  
  13  	"next.orly.dev/pkg/nostr/encoders/event"
  14  	"next.orly.dev/pkg/nostr/encoders/event/examples"
  15  	"next.orly.dev/pkg/lol"
  16  	"next.orly.dev/pkg/lol/log"
  17  )
  18  
  19  // Shared test fixtures - initialized once in TestMain
  20  var (
  21  	sharedDB         *D
  22  	sharedDBDir      string
  23  	sharedDBCtx      context.Context
  24  	sharedDBCancel   context.CancelFunc
  25  	sharedDBOnce     sync.Once
  26  	sharedEvents     []*event.E // Events that were successfully saved
  27  	sharedSetupError error
  28  )
  29  
  30  // initSharedDB initializes the shared test database with seeded data.
  31  // This is called once and shared across all tests that need seeded data.
  32  func initSharedDB() {
  33  	sharedDBOnce.Do(func() {
  34  		var err error
  35  
  36  		// Create a temporary directory for the shared database
  37  		sharedDBDir, err = os.MkdirTemp("", "shared-test-db-*")
  38  		if err != nil {
  39  			sharedSetupError = err
  40  			return
  41  		}
  42  
  43  		// Create a context for the database
  44  		sharedDBCtx, sharedDBCancel = context.WithCancel(context.Background())
  45  
  46  		// Initialize the database
  47  		sharedDB, err = New(sharedDBCtx, sharedDBCancel, sharedDBDir, "info")
  48  		if err != nil {
  49  			sharedSetupError = err
  50  			return
  51  		}
  52  
  53  		// Seed the database with events from examples.Cache
  54  		scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache))
  55  		scanner.Buffer(make([]byte, 0, 1_000_000_000), 1_000_000_000)
  56  
  57  		var events []*event.E
  58  		for scanner.Scan() {
  59  			b := scanner.Bytes()
  60  			ev := event.New()
  61  			if _, err = ev.Unmarshal(b); err != nil {
  62  				continue
  63  			}
  64  			events = append(events, ev)
  65  		}
  66  
  67  		// Sort events by CreatedAt for consistent processing
  68  		sort.Slice(events, func(i, j int) bool {
  69  			return events[i].CreatedAt < events[j].CreatedAt
  70  		})
  71  
  72  		// Save events to the database
  73  		for _, ev := range events {
  74  			if _, err = sharedDB.SaveEvent(sharedDBCtx, ev); err != nil {
  75  				continue // Skip invalid events
  76  			}
  77  			sharedEvents = append(sharedEvents, ev)
  78  		}
  79  	})
  80  }
  81  
  82  // GetSharedDB returns the shared test database.
  83  // Returns nil if testing.Short() is set or if setup failed.
  84  func GetSharedDB(t *testing.T) (*D, context.Context) {
  85  	if testing.Short() {
  86  		t.Skip("skipping test that requires seeded database in short mode")
  87  	}
  88  
  89  	initSharedDB()
  90  
  91  	if sharedSetupError != nil {
  92  		t.Fatalf("Failed to initialize shared database: %v", sharedSetupError)
  93  	}
  94  
  95  	return sharedDB, sharedDBCtx
  96  }
  97  
  98  // GetSharedEvents returns the events that were successfully saved to the shared database.
  99  func GetSharedEvents(t *testing.T) []*event.E {
 100  	if testing.Short() {
 101  		t.Skip("skipping test that requires seeded events in short mode")
 102  	}
 103  
 104  	initSharedDB()
 105  
 106  	if sharedSetupError != nil {
 107  		t.Fatalf("Failed to initialize shared database: %v", sharedSetupError)
 108  	}
 109  
 110  	return sharedEvents
 111  }
 112  
 113  // findEventWithTag finds an event with a single-character tag key and at least 2 elements.
 114  // Returns nil if no suitable event is found.
 115  func findEventWithTag(events []*event.E) *event.E {
 116  	for _, ev := range events {
 117  		if ev.Tags != nil && ev.Tags.Len() > 0 {
 118  			for _, tg := range *ev.Tags {
 119  				if tg.Len() >= 2 && len(tg.Key()) == 1 {
 120  					return ev
 121  				}
 122  			}
 123  		}
 124  	}
 125  	return nil
 126  }
 127  
 128  func TestMain(m *testing.M) {
 129  	// Disable all logging during tests unless explicitly enabled
 130  	if os.Getenv("TEST_LOG") == "" {
 131  		// Set log level to Off to suppress all logs
 132  		lol.SetLogLevel("off")
 133  		// Also redirect output to discard
 134  		lol.Writer = io.Discard
 135  		// Disable all log printers
 136  		log.T = lol.GetNullPrinter()
 137  		log.D = lol.GetNullPrinter()
 138  		log.I = lol.GetNullPrinter()
 139  		log.W = lol.GetNullPrinter()
 140  		log.E = lol.GetNullPrinter()
 141  		log.F = lol.GetNullPrinter()
 142  
 143  		// Also suppress badger logs
 144  		os.Setenv("BADGER_LOG_LEVEL", "CRITICAL")
 145  	}
 146  
 147  	// Run tests
 148  	code := m.Run()
 149  
 150  	// Cleanup shared database
 151  	if sharedDBCancel != nil {
 152  		sharedDBCancel()
 153  	}
 154  	if sharedDB != nil {
 155  		sharedDB.Close()
 156  	}
 157  	if sharedDBDir != "" {
 158  		os.RemoveAll(sharedDBDir)
 159  	}
 160  
 161  	os.Exit(code)
 162  }
 163