github.com/kubri/kubri@v0.5.1-0.20240317001612-bda2aaef967e/internal/test/target.go (about)

     1  package test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"io"
     7  	"io/fs"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/google/go-cmp/cmp"
    12  
    13  	"github.com/kubri/kubri/target"
    14  )
    15  
    16  type targetOptions struct {
    17  	delay                time.Duration
    18  	ignoreRemoveNotFound bool
    19  }
    20  
    21  type TargetOption func(*targetOptions)
    22  
    23  // WithDelay adds a delay between writing, updating & reading, to allow for
    24  // services where the changes aren't available instantly.
    25  func WithDelay(d time.Duration) TargetOption {
    26  	return func(opts *targetOptions) {
    27  		opts.delay = d
    28  	}
    29  }
    30  
    31  // WithIgnoreRemoveNotFound disables testing if removing a non-existent file
    32  // returns an error.
    33  func WithIgnoreRemoveNotFound() TargetOption {
    34  	return func(opts *targetOptions) {
    35  		opts.ignoreRemoveNotFound = true
    36  	}
    37  }
    38  
    39  //nolint:funlen,gocognit
    40  func Target(t *testing.T, tgt target.Target, makeURL func(string) string, opt ...TargetOption) {
    41  	t.Helper()
    42  
    43  	opts := &targetOptions{}
    44  	for _, o := range opt {
    45  		o(opts)
    46  	}
    47  
    48  	ctx := context.Background()
    49  	data := []byte("test")
    50  
    51  	t.Run("NewWriter_Create", func(t *testing.T) {
    52  		t.Helper()
    53  
    54  		w, err := tgt.NewWriter(ctx, "path/to/file")
    55  		if err != nil {
    56  			t.Fatal(err)
    57  		}
    58  
    59  		if _, err = w.Write([]byte("foo")); err != nil {
    60  			t.Fatal(err)
    61  		}
    62  
    63  		if err = w.Close(); err != nil {
    64  			t.Fatal(err)
    65  		}
    66  	})
    67  
    68  	time.Sleep(opts.delay)
    69  
    70  	t.Run("NewWriter_Update", func(t *testing.T) {
    71  		t.Helper()
    72  
    73  		w, err := tgt.NewWriter(ctx, "path/to/file")
    74  		if err != nil {
    75  			t.Fatal(err)
    76  		}
    77  
    78  		if _, err = w.Write(data); err != nil {
    79  			t.Fatal(err)
    80  		}
    81  
    82  		if err = w.Close(); err != nil {
    83  			t.Fatal(err)
    84  		}
    85  	})
    86  
    87  	time.Sleep(opts.delay)
    88  
    89  	t.Run("NewReader", func(t *testing.T) {
    90  		t.Helper()
    91  
    92  		r, err := tgt.NewReader(ctx, "path/to/file")
    93  		if err != nil {
    94  			t.Fatal(err)
    95  		}
    96  
    97  		got, err := io.ReadAll(r)
    98  		if err != nil {
    99  			t.Fatal(err)
   100  		}
   101  
   102  		if err = r.Close(); err != nil {
   103  			t.Fatal(err)
   104  		}
   105  
   106  		if diff := cmp.Diff(data, got); diff != "" {
   107  			t.Fatal(diff)
   108  		}
   109  
   110  		_, err = tgt.NewReader(ctx, "does/not/exist")
   111  		if !errors.Is(err, fs.ErrNotExist) {
   112  			t.Fatalf("Should return %q - got %q", fs.ErrNotExist, err)
   113  		}
   114  	})
   115  
   116  	t.Run("Sub", func(t *testing.T) {
   117  		t.Helper()
   118  
   119  		sub := tgt.Sub("path/to")
   120  
   121  		r, err := sub.NewReader(ctx, "file")
   122  		if err != nil {
   123  			t.Fatal(err)
   124  		} else {
   125  			r.Close()
   126  		}
   127  	})
   128  
   129  	t.Run("URL", func(t *testing.T) {
   130  		t.Helper()
   131  
   132  		url, err := tgt.URL(ctx, "path/to/file")
   133  		if err != nil {
   134  			t.Fatal(err)
   135  		}
   136  
   137  		if diff := cmp.Diff(makeURL("path/to/file"), url); diff != "" {
   138  			t.Fatal(diff)
   139  		}
   140  	})
   141  
   142  	t.Run("Remove", func(t *testing.T) {
   143  		t.Helper()
   144  
   145  		err := tgt.Remove(ctx, "path/to/file")
   146  		if err != nil {
   147  			t.Fatal(err)
   148  		}
   149  
   150  		time.Sleep(opts.delay)
   151  
   152  		r, err := tgt.NewReader(ctx, "path/to/file")
   153  		if err == nil {
   154  			r.Close()
   155  		}
   156  		if !errors.Is(err, fs.ErrNotExist) {
   157  			t.Fatalf("Read should return %q - got %q", fs.ErrNotExist, err)
   158  		}
   159  
   160  		if !opts.ignoreRemoveNotFound {
   161  			err = tgt.Remove(ctx, "does/not/exist")
   162  			if !errors.Is(err, fs.ErrNotExist) {
   163  				t.Fatalf("Remove should return %q - got %q", fs.ErrNotExist, err)
   164  			}
   165  		}
   166  	})
   167  }