go-micro.dev/v5@v5.12.0/store/nats-js-kv/helpers_test.go (about)

     1  package natsjskv
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net"
     7  	"os"
     8  	"path/filepath"
     9  	"strconv"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  
    14  	nserver "github.com/nats-io/nats-server/v2/server"
    15  	"github.com/pkg/errors"
    16  	"github.com/test-go/testify/require"
    17  	"go-micro.dev/v5/store"
    18  )
    19  
    20  func testSetup(ctx context.Context, t *testing.T, opts ...store.Option) store.Store {
    21  	t.Helper()
    22  
    23  	var err error
    24  	var s store.Store
    25  	for i := 0; i < 5; i++ {
    26  		nCtx, cancel := context.WithCancel(ctx)
    27  		addr := startNatsServer(nCtx, t)
    28  
    29  		opts = append(opts, store.Nodes(addr), EncodeKeys())
    30  		s = NewStore(opts...)
    31  
    32  		err = s.Init()
    33  		if err != nil {
    34  			t.Log(errors.Wrap(err, "Error: Server initialization failed, restarting server"))
    35  			cancel()
    36  			if err = s.Close(); err != nil {
    37  				t.Logf("Failed to close store: %v", err)
    38  			}
    39  			time.Sleep(time.Second)
    40  			continue
    41  		}
    42  
    43  		go func() {
    44  			<-ctx.Done()
    45  			cancel()
    46  			if err = s.Close(); err != nil {
    47  				t.Logf("Failed to close store: %v", err)
    48  			}
    49  		}()
    50  
    51  		return s
    52  	}
    53  	t.Error(errors.Wrap(err, "Store initialization failed"))
    54  	return s
    55  }
    56  
    57  func startNatsServer(ctx context.Context, t *testing.T) string {
    58  	t.Helper()
    59  	natsAddr := getFreeLocalhostAddress()
    60  	natsPort, err := strconv.Atoi(strings.Split(natsAddr, ":")[1])
    61  	if err != nil {
    62  		t.Logf("Failed to parse port from address: %v", err)
    63  	}
    64  
    65  	clusterName := "gomicro-store-test-cluster"
    66  
    67  	// start the NATS with JetStream server
    68  	go natsServer(ctx,
    69  		t,
    70  		&nserver.Options{
    71  			Host: strings.Split(natsAddr, ":")[0],
    72  			Port: natsPort,
    73  			Cluster: nserver.ClusterOpts{
    74  				Name: clusterName,
    75  			},
    76  		},
    77  	)
    78  
    79  	time.Sleep(2 * time.Second)
    80  
    81  	return natsAddr
    82  }
    83  
    84  func getFreeLocalhostAddress() string {
    85  	l, err := net.Listen("tcp", "127.0.0.1:0")
    86  	if err != nil {
    87  		return ""
    88  	}
    89  
    90  	addr := l.Addr().String()
    91  	if err := l.Close(); err != nil {
    92  		return addr
    93  	}
    94  	return addr
    95  }
    96  
    97  func natsServer(ctx context.Context, t *testing.T, opts *nserver.Options) {
    98  	t.Helper()
    99  
   100  	opts.TLSTimeout = 180
   101  	server, err := nserver.NewServer(
   102  		opts,
   103  	)
   104  	require.NoError(t, err)
   105  	if err != nil {
   106  		return
   107  	}
   108  	defer server.Shutdown()
   109  
   110  	server.SetLoggerV2(
   111  		NewLogWrapper(),
   112  		false, false, false,
   113  	)
   114  
   115  	tmpdir := t.TempDir()
   116  	natsdir := filepath.Join(tmpdir, "nats-js")
   117  	jsConf := &nserver.JetStreamConfig{
   118  		StoreDir: natsdir,
   119  	}
   120  
   121  	// first start NATS
   122  	go server.Start()
   123  	time.Sleep(time.Second)
   124  
   125  	// second start JetStream
   126  	err = server.EnableJetStream(jsConf)
   127  	require.NoError(t, err)
   128  	if err != nil {
   129  		return
   130  	}
   131  
   132  	// This fixes some issues where tests fail because directory cleanup fails
   133  	t.Cleanup(func() {
   134  		contents, err := filepath.Glob(natsdir + "/*")
   135  		if err != nil {
   136  			t.Logf("Failed to glob directory: %v", err)
   137  		}
   138  		for _, item := range contents {
   139  			if err := os.RemoveAll(item); err != nil {
   140  				t.Logf("Failed to remove file: %v", err)
   141  			}
   142  		}
   143  		if err := os.RemoveAll(natsdir); err != nil {
   144  			t.Logf("Failed to remove directory: %v", err)
   145  		}
   146  	})
   147  
   148  	<-ctx.Done()
   149  }
   150  
   151  func NewLogWrapper() *LogWrapper {
   152  	return &LogWrapper{}
   153  }
   154  
   155  type LogWrapper struct {
   156  }
   157  
   158  // Noticef logs a notice statement.
   159  func (l *LogWrapper) Noticef(_ string, _ ...interface{}) {
   160  }
   161  
   162  // Warnf logs a warning statement.
   163  func (l *LogWrapper) Warnf(format string, v ...interface{}) {
   164  	fmt.Printf(format+"\n", v...)
   165  }
   166  
   167  // Fatalf logs a fatal statement.
   168  func (l *LogWrapper) Fatalf(format string, v ...interface{}) {
   169  	fmt.Printf(format+"\n", v...)
   170  }
   171  
   172  // Errorf logs an error statement.
   173  func (l *LogWrapper) Errorf(format string, v ...interface{}) {
   174  	fmt.Printf(format+"\n", v...)
   175  }
   176  
   177  // Debugf logs a debug statement.
   178  func (l *LogWrapper) Debugf(_ string, _ ...interface{}) {
   179  }
   180  
   181  // Tracef logs a trace statement.
   182  func (l *LogWrapper) Tracef(format string, v ...interface{}) {
   183  	fmt.Printf(format+"\n", v...)
   184  }