github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/auth/token/spec/token_store.go (about)

     1  package spec
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/google/go-cmp/cmp"
    10  	testkeys "github.com/qri-io/qri/auth/key/test"
    11  	"github.com/qri-io/qri/auth/token"
    12  	"github.com/qri-io/qri/profile"
    13  )
    14  
    15  // AssertTokenStoreSpec ensures an token.TokenStore implementation behaves as
    16  // expected
    17  func AssertTokenStoreSpec(t *testing.T, newTokenStore func(context.Context) token.Store) {
    18  	prevTs := token.Timestamp
    19  	token.Timestamp = func() time.Time { return time.Time{} }
    20  	defer func() { token.Timestamp = prevTs }()
    21  
    22  	ctx, cancel := context.WithCancel(context.Background())
    23  	defer cancel()
    24  
    25  	pk := testkeys.GetKeyData(0).PrivKey
    26  	tokens, err := token.NewPrivKeySource(pk)
    27  	if err != nil {
    28  		t.Fatalf("creating local tokens: %q", err)
    29  	}
    30  	store := newTokenStore(ctx)
    31  
    32  	results, err := store.ListTokens(ctx, 0, -1)
    33  	if err != nil {
    34  		t.Errorf("listing all tokens of an empty store shouldn't error. got: %q ", err)
    35  	}
    36  	if len(results) > 0 {
    37  		t.Errorf("new store should return no results. got: %d", len(results))
    38  	}
    39  
    40  	_, err = store.RawToken(ctx, "this doesn't exist")
    41  	if !errors.Is(err, token.ErrTokenNotFound) {
    42  		t.Errorf("expected store.RawToken(nonexistent key) to return a wrap of token.ErrTokenNotFound. got: %q", err)
    43  	}
    44  	err = store.DeleteToken(ctx, "this also doesn't exist")
    45  	if !errors.Is(err, token.ErrTokenNotFound) {
    46  		t.Errorf("expected store.D key to return a wrap of token.ErrTokenNotFound. got: %q", err)
    47  	}
    48  	if err := store.PutToken(ctx, "_bad_key", "not.a.key"); err == nil {
    49  		t.Errorf("putting an invalid json web token should error. got nil")
    50  	}
    51  
    52  	p1 := &profile.Profile{
    53  		ID:       profile.IDB58DecodeOrEmpty(testkeys.GetKeyData(1).EncodedPeerID),
    54  		Peername: "local_user",
    55  	}
    56  	t1Raw, err := tokens.CreateToken(p1, 0)
    57  	if err != nil {
    58  		t.Fatalf("creating token: %q", err)
    59  	}
    60  
    61  	if err := store.PutToken(ctx, "_root", t1Raw); err != nil {
    62  		t.Errorf("putting root key shouldn't error. got: %q", err)
    63  	}
    64  
    65  	results, err = store.ListTokens(ctx, 0, -1)
    66  	if err != nil {
    67  		t.Errorf("listing all tokens of an empty store shouldn't error. got: %q ", err)
    68  	}
    69  	if len(results) != 1 {
    70  		t.Errorf("result length mismatch listing keys after adding `root` key. expected 1, got: %d", len(results))
    71  	}
    72  
    73  	p2 := &profile.Profile{
    74  		ID:       profile.IDB58DecodeOrEmpty(testkeys.GetKeyData(2).EncodedPeerID),
    75  		Peername: "user_2",
    76  	}
    77  	t2Raw, err := tokens.CreateToken(p2, time.Millisecond*10)
    78  	if err != nil {
    79  		t.Fatalf("creating token: %q", err)
    80  	}
    81  
    82  	secondKey := "http://registry.qri.cloud"
    83  	if err := store.PutToken(ctx, secondKey, t2Raw); err != nil {
    84  		t.Errorf("putting a second token with key=%q shouldn't error. got: %q", secondKey, err)
    85  	}
    86  
    87  	results, err = store.ListTokens(ctx, 0, -1)
    88  	if err != nil {
    89  		t.Errorf("listing all tokens of an empty store shouldn't error. got: %q ", err)
    90  	}
    91  	if len(results) != 2 {
    92  		t.Errorf("result length mismatch listing keys after adding second key. expected 2, got: %d", len(results))
    93  	}
    94  
    95  	expect := []token.RawToken{
    96  		{
    97  			Key: "_root",
    98  			Raw: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJRbVdZZ0Q0OXI5SG51WEVwcFFFcTFhN1NVVXJ5amE0UU5zOUU2WENIMlBheUNEIiwic3ViIjoiUW1XWWdENDlyOUhudVhFcHBRRXExYTdTVVVyeWphNFFOczlFNlhDSDJQYXlDRCIsImNsaWVudFR5cGUiOiJ1c2VyIn0.OatuPGP9SCYMevcOWP29bHe5R-vMLgmtVEsVjIp1VN8oF-qZDLxDrMFJpqBVRAMrv4BLtILS_6qQS4VhKVedEoCrXA7Wt78Tg0JQZTawmbQNi0Z280hiM7sJjoaqIBTeq00x6NPuFAQ8hBflslqzN0cjdSkt7wnYFGUG9p_9RLiiW2r7fv4VYxZ4fJX3G8rr3YWEzcZVkpgKHR95kPe77-oT69KPqAb4CxPmhoZ7nF69qX9-tPgtC0LqQSzYYtJkxgRTrVZhE7hndAxNJZM2z_Dkd4saiya4x8lNChfh7OkacbUFbjYRRp3v2Sh5JwUbBffl8axjz-NhbKo_kBa_HQ",
    99  		},
   100  		{
   101  			Key: secondKey,
   102  			Raw: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOi02MjEzNTU5NjgwMCwiaXNzIjoiUW1QZUZUTkhjWkRyM1pGRWZGZmVweFM1UHFIQW1mQlJHUU5QSjM4OUN3aDFhcyIsInN1YiI6IlFtUGVGVE5IY1pEcjNaRkVmRmZlcHhTNVBxSEFtZkJSR1FOUEozODlDd2gxYXMiLCJjbGllbnRUeXBlIjoidXNlciJ9.YozNjhC9gAk6jzSz4d2v1sdtiNIxB_LuFNxFtQTaUQvwhlQAm-vRq2Eb-8R-Y7cz_akkqvxzF0MY-cFV_80V8XxY8_oqYgULxi-HM81LkMwUcx6XzVeO6OxHssLnhz-9yiphElQNdn6u61Z-YLbdbS9Tjr1sjTh4biyRkUKdOba8fKn8VVZ1spUVfV-jUgDk69hxjIs0BBmrElX-GlkW9NLhuAvZzPqYVI6t7l9m2rvJedu-S9ZdMhEMzI_ZhbWwtmcLO_U_NPRJxjYujo5Uq4gr_UYEvEH9rvEw4L9Pcic2dPSnHJuOyrZa76KDKJj5xClZr9lKXeNV8YOypGu8sQ",
   103  		},
   104  	}
   105  
   106  	if diff := cmp.Diff(expect, results); diff != "" {
   107  		t.Log(results)
   108  		t.Errorf("mistmatched list keys results. (-want +got):\n%s", diff)
   109  	}
   110  
   111  	results, err = store.ListTokens(ctx, 1, 1)
   112  	if err != nil {
   113  		t.Errorf("listing all tokens of an empty store shouldn't error. got: %q ", err)
   114  	}
   115  	if len(results) != 1 {
   116  		t.Errorf("result length mismatch listing keys after adding `root` key. expected 1, got: %d", len(results))
   117  	}
   118  
   119  	if diff := cmp.Diff(expect[1:], results); diff != "" {
   120  		t.Errorf("mistmatched list keys with offset=1, limit=1. results. (-want +got):\n%s", diff)
   121  	}
   122  
   123  	if err := store.DeleteToken(ctx, secondKey); err != nil {
   124  		t.Errorf("store.DeleteToken shouldn't error for existing key. got: %q", err)
   125  	}
   126  
   127  	_, err = store.RawToken(ctx, secondKey)
   128  	if !errors.Is(err, token.ErrTokenNotFound) {
   129  		t.Errorf("store.RawToken() for a just-deleted key must return a wrap of token.ErrTokenNotFound. got: %q", err)
   130  	}
   131  }