storage/conformance: expand transaction test suite
This commit is contained in:
		| @@ -4,6 +4,9 @@ package conformance | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"golang.org/x/crypto/bcrypt" | ||||
|  | ||||
| 	"github.com/coreos/dex/storage" | ||||
| ) | ||||
| @@ -17,7 +20,10 @@ import ( | ||||
| // conformance. | ||||
| func RunTransactionTests(t *testing.T, newStorage func() storage.Storage) { | ||||
| 	runTests(t, newStorage, []subTest{ | ||||
| 		{"AuthRequestConcurrentUpdate", testAuthRequestConcurrentUpdate}, | ||||
| 		{"ClientConcurrentUpdate", testClientConcurrentUpdate}, | ||||
| 		{"PasswordConcurrentUpdate", testPasswordConcurrentUpdate}, | ||||
| 		{"KeysConcurrentUpdate", testKeysConcurrentUpdate}, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| @@ -45,10 +51,124 @@ func testClientConcurrentUpdate(t *testing.T, s storage.Storage) { | ||||
| 		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") | ||||
| 	if (err1 == nil) == (err2 == nil) { | ||||
| 		t.Errorf("update client:\nupdate1: %v\nupdate2: %v\n", err1, err2) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testAuthRequestConcurrentUpdate(t *testing.T, s storage.Storage) { | ||||
| 	a := storage.AuthRequest{ | ||||
| 		ID:                  storage.NewID(), | ||||
| 		ClientID:            "foobar", | ||||
| 		ResponseTypes:       []string{"code"}, | ||||
| 		Scopes:              []string{"openid", "email"}, | ||||
| 		RedirectURI:         "https://localhost:80/callback", | ||||
| 		Nonce:               "foo", | ||||
| 		State:               "bar", | ||||
| 		ForceApprovalPrompt: true, | ||||
| 		LoggedIn:            true, | ||||
| 		Expiry:              neverExpire, | ||||
| 		ConnectorID:         "ldap", | ||||
| 		ConnectorData:       []byte(`{"some":"data"}`), | ||||
| 		Claims: storage.Claims{ | ||||
| 			UserID:        "1", | ||||
| 			Username:      "jane", | ||||
| 			Email:         "jane.doe@example.com", | ||||
| 			EmailVerified: true, | ||||
| 			Groups:        []string{"a", "b"}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	if err := s.CreateAuthRequest(a); err != nil { | ||||
| 		t.Fatalf("failed creating auth request: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	var err1, err2 error | ||||
|  | ||||
| 	err1 = s.UpdateAuthRequest(a.ID, func(old storage.AuthRequest) (storage.AuthRequest, error) { | ||||
| 		old.State = "state 1" | ||||
| 		err2 = s.UpdateAuthRequest(a.ID, func(old storage.AuthRequest) (storage.AuthRequest, error) { | ||||
| 			old.State = "state 2" | ||||
| 			return old, nil | ||||
| 		}) | ||||
| 		return old, nil | ||||
| 	}) | ||||
|  | ||||
| 	if (err1 == nil) == (err2 == nil) { | ||||
| 		t.Errorf("update auth request:\nupdate1: %v\nupdate2: %v\n", err1, err2) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testPasswordConcurrentUpdate(t *testing.T, s storage.Storage) { | ||||
| 	// Use bcrypt.MinCost to keep the tests short. | ||||
| 	passwordHash, err := bcrypt.GenerateFromPassword([]byte("secret"), bcrypt.MinCost) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	password := storage.Password{ | ||||
| 		Email:    "jane@example.com", | ||||
| 		Hash:     passwordHash, | ||||
| 		Username: "jane", | ||||
| 		UserID:   "foobar", | ||||
| 	} | ||||
| 	if err := s.CreatePassword(password); err != nil { | ||||
| 		t.Fatalf("create password token: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	var err1, err2 error | ||||
|  | ||||
| 	err1 = s.UpdatePassword(password.Email, func(old storage.Password) (storage.Password, error) { | ||||
| 		old.Username = "user 1" | ||||
| 		err2 = s.UpdatePassword(password.Email, func(old storage.Password) (storage.Password, error) { | ||||
| 			old.Username = "user 2" | ||||
| 			return old, nil | ||||
| 		}) | ||||
| 		return old, nil | ||||
| 	}) | ||||
|  | ||||
| 	if (err1 == nil) == (err2 == nil) { | ||||
| 		t.Errorf("update password: concurrent updates both returned no error") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testKeysConcurrentUpdate(t *testing.T, s storage.Storage) { | ||||
| 	// Test twice. Once for a create, once for an update. | ||||
| 	for i := 0; i < 2; i++ { | ||||
| 		n := time.Now().UTC().Round(time.Second) | ||||
| 		keys1 := storage.Keys{ | ||||
| 			SigningKey:    jsonWebKeys[0].Private, | ||||
| 			SigningKeyPub: jsonWebKeys[0].Public, | ||||
| 			NextRotation:  n, | ||||
| 		} | ||||
|  | ||||
| 		keys2 := storage.Keys{ | ||||
| 			SigningKey:    jsonWebKeys[2].Private, | ||||
| 			SigningKeyPub: jsonWebKeys[2].Public, | ||||
| 			NextRotation:  n.Add(time.Hour), | ||||
| 			VerificationKeys: []storage.VerificationKey{ | ||||
| 				{ | ||||
| 					PublicKey: jsonWebKeys[0].Public, | ||||
| 					Expiry:    n.Add(time.Hour), | ||||
| 				}, | ||||
| 				{ | ||||
| 					PublicKey: jsonWebKeys[1].Public, | ||||
| 					Expiry:    n.Add(time.Hour * 2), | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| 		var err1, err2 error | ||||
|  | ||||
| 		err1 = s.UpdateKeys(func(old storage.Keys) (storage.Keys, error) { | ||||
| 			err2 = s.UpdateKeys(func(old storage.Keys) (storage.Keys, error) { | ||||
| 				return keys1, nil | ||||
| 			}) | ||||
| 			return keys2, nil | ||||
| 		}) | ||||
|  | ||||
| 		if (err1 == nil) == (err2 == nil) { | ||||
| 			t.Errorf("update keys: concurrent updates both returned no error") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user