storage/conformance: add tests for transactional guarantees
This commit is contained in:
		| @@ -20,22 +20,12 @@ import ( | ||||
| // ensure that values being tested on never expire. | ||||
| var neverExpire = time.Now().UTC().Add(time.Hour * 24 * 365 * 100) | ||||
|  | ||||
| // RunTests runs a set of conformance tests against a storage. newStorage should | ||||
| // return an initialized but empty storage. The storage will be closed at the | ||||
| // end of each test run. | ||||
| func RunTests(t *testing.T, newStorage func() storage.Storage) { | ||||
| 	tests := []struct { | ||||
| 		name string | ||||
| 		run  func(t *testing.T, s storage.Storage) | ||||
| 	}{ | ||||
| 		{"AuthCodeCRUD", testAuthCodeCRUD}, | ||||
| 		{"AuthRequestCRUD", testAuthRequestCRUD}, | ||||
| 		{"ClientCRUD", testClientCRUD}, | ||||
| 		{"RefreshTokenCRUD", testRefreshTokenCRUD}, | ||||
| 		{"PasswordCRUD", testPasswordCRUD}, | ||||
| 		{"KeysCRUD", testKeysCRUD}, | ||||
| 		{"GarbageCollection", testGC}, | ||||
| 	} | ||||
| type subTest struct { | ||||
| 	name string | ||||
| 	run  func(t *testing.T, s storage.Storage) | ||||
| } | ||||
|  | ||||
| func runTests(t *testing.T, newStorage func() storage.Storage, tests []subTest) { | ||||
| 	for _, test := range tests { | ||||
| 		t.Run(test.name, func(t *testing.T) { | ||||
| 			s := newStorage() | ||||
| @@ -45,6 +35,21 @@ func RunTests(t *testing.T, newStorage func() storage.Storage) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // RunTests runs a set of conformance tests against a storage. newStorage should | ||||
| // return an initialized but empty storage. The storage will be closed at the | ||||
| // end of each test run. | ||||
| func RunTests(t *testing.T, newStorage func() storage.Storage) { | ||||
| 	runTests(t, newStorage, []subTest{ | ||||
| 		{"AuthCodeCRUD", testAuthCodeCRUD}, | ||||
| 		{"AuthRequestCRUD", testAuthRequestCRUD}, | ||||
| 		{"ClientCRUD", testClientCRUD}, | ||||
| 		{"RefreshTokenCRUD", testRefreshTokenCRUD}, | ||||
| 		{"PasswordCRUD", testPasswordCRUD}, | ||||
| 		{"KeysCRUD", testKeysCRUD}, | ||||
| 		{"GarbageCollection", testGC}, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func mustLoadJWK(b string) *jose.JSONWebKey { | ||||
| 	var jwt jose.JSONWebKey | ||||
| 	if err := jwt.UnmarshalJSON([]byte(b)); err != nil { | ||||
|   | ||||
							
								
								
									
										54
									
								
								storage/conformance/transactions.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								storage/conformance/transactions.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| // +build go1.7 | ||||
|  | ||||
| package conformance | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/coreos/dex/storage" | ||||
| ) | ||||
|  | ||||
| // RunTransactionTests runs a test suite aimed a verifying the transaction | ||||
| // guarantees of the storage interface. Atomic updates, deletes, etc. The | ||||
| // storage returned by newStorage will be closed at the end of each test run. | ||||
| // | ||||
| // This call is separate from RunTests because some storage perform extremely | ||||
| // poorly under deadlocks, such as SQLite3, while others may be working towards | ||||
| // conformance. | ||||
| func RunTransactionTests(t *testing.T, newStorage func() storage.Storage) { | ||||
| 	runTests(t, newStorage, []subTest{ | ||||
| 		{"ClientConcurrentUpdate", testClientConcurrentUpdate}, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func testClientConcurrentUpdate(t *testing.T, s storage.Storage) { | ||||
| 	c := storage.Client{ | ||||
| 		ID:           storage.NewID(), | ||||
| 		Secret:       "foobar", | ||||
| 		RedirectURIs: []string{"foo://bar.com/", "https://auth.example.com"}, | ||||
| 		Name:         "dex client", | ||||
| 		LogoURL:      "https://goo.gl/JIyzIC", | ||||
| 	} | ||||
|  | ||||
| 	if err := s.CreateClient(c); err != nil { | ||||
| 		t.Fatalf("create client: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	var err1, err2 error | ||||
|  | ||||
| 	err1 = s.UpdateClient(c.ID, func(old storage.Client) (storage.Client, error) { | ||||
| 		old.Secret = "new secret 1" | ||||
| 		err2 = s.UpdateClient(c.ID, func(old storage.Client) (storage.Client, error) { | ||||
| 			old.Secret = "new secret 2" | ||||
| 			return old, nil | ||||
| 		}) | ||||
| 		return old, nil | ||||
| 	}) | ||||
|  | ||||
| 	t.Logf("update1: %v", err1) | ||||
| 	t.Logf("update2: %v", err2) | ||||
|  | ||||
| 	if err1 == nil && err2 == nil { | ||||
| 		t.Errorf("update client: concurrent updates both returned no error") | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user