auth

Paddy 2015-04-11 Parent:3e8964a914ef Child:849f3820b164

159:cf6c1f05eb21 Go to Latest

auth/profile_test.go

Enable terminating sessions through the API. Add a terminateSession method to the sessionStore that sets the Active property of the Session to false. Create a Context.TerminateSession wrapper for the terminateSession method on the sessionStore. Add a Sessions property to our response type so we can return a []Session in API responses. Use the URL-safe encoding when base64 encoding our session ID and CSRFToken, so the ID can be passed in the URL and so our encodings are consistent. Add a TerminateSessionHandler function that will extract a Session ID from the request URL, authenticate the user, check that the authenticated user owns the session in question, and terminate the session. Add implementations for our new terminateSession method for the memstore and postgres types. Test both the memstore and postgres implementation of our terminateSession helper in session_test.go.

History
paddy@38 1 package auth
paddy@38 2
paddy@38 3 import (
paddy@38 4 "fmt"
paddy@153 5 "os"
paddy@38 6 "testing"
paddy@38 7 "time"
paddy@38 8
paddy@107 9 "code.secondbit.org/uuid.hg"
paddy@38 10 )
paddy@38 11
paddy@38 12 const (
paddy@38 13 profileChangeName = 1 << iota
paddy@38 14 profileChangePassphrase
paddy@38 15 profileChangeIterations
paddy@38 16 profileChangeSalt
paddy@38 17 profileChangePassphraseScheme
paddy@38 18 profileChangeCompromised
paddy@38 19 profileChangeLockedUntil
paddy@38 20 profileChangePassphraseReset
paddy@38 21 profileChangePassphraseResetCreated
paddy@38 22 profileChangeLastSeen
paddy@38 23 )
paddy@38 24
paddy@149 25 func init() {
paddy@153 26 if os.Getenv("PG_TEST_DB") != "" {
paddy@153 27 p, err := NewPostgres(os.Getenv("PG_TEST_DB"))
paddy@153 28 if err != nil {
paddy@153 29 panic(err)
paddy@153 30 }
paddy@149 31 profileStores = append(profileStores, &p)
paddy@149 32 }
paddy@149 33 }
paddy@149 34
paddy@57 35 var profileStores = []profileStore{NewMemstore()}
paddy@38 36
paddy@38 37 func compareProfiles(profile1, profile2 Profile) (success bool, field string, val1, val2 interface{}) {
paddy@38 38 if !profile1.ID.Equal(profile2.ID) {
paddy@38 39 return false, "ID", profile1.ID, profile2.ID
paddy@38 40 }
paddy@38 41 if profile1.Name != profile2.Name {
paddy@38 42 return false, "name", profile1.Name, profile2.Name
paddy@38 43 }
paddy@38 44 if profile1.Passphrase != profile2.Passphrase {
paddy@38 45 return false, "passphrase", profile1.Passphrase, profile2.Passphrase
paddy@38 46 }
paddy@38 47 if profile1.Iterations != profile2.Iterations {
paddy@38 48 return false, "iterations", profile1.Iterations, profile2.Iterations
paddy@38 49 }
paddy@38 50 if profile1.Salt != profile2.Salt {
paddy@38 51 return false, "salt", profile1.Salt, profile2.Salt
paddy@38 52 }
paddy@38 53 if profile1.PassphraseScheme != profile2.PassphraseScheme {
paddy@38 54 return false, "passphrase scheme", profile1.PassphraseScheme, profile2.PassphraseScheme
paddy@38 55 }
paddy@38 56 if profile1.Compromised != profile2.Compromised {
paddy@38 57 return false, "compromised", profile1.Compromised, profile2.Compromised
paddy@38 58 }
paddy@38 59 if !profile1.LockedUntil.Equal(profile2.LockedUntil) {
paddy@38 60 return false, "locked until", profile1.LockedUntil, profile2.LockedUntil
paddy@38 61 }
paddy@38 62 if profile1.PassphraseReset != profile2.PassphraseReset {
paddy@38 63 return false, "passphrase reset", profile1.PassphraseReset, profile2.PassphraseReset
paddy@38 64 }
paddy@38 65 if !profile1.PassphraseResetCreated.Equal(profile2.PassphraseResetCreated) {
paddy@38 66 return false, "passphrase reset created", profile1.PassphraseResetCreated, profile2.PassphraseResetCreated
paddy@38 67 }
paddy@38 68 if !profile1.Created.Equal(profile2.Created) {
paddy@38 69 return false, "created", profile1.Created, profile2.Created
paddy@38 70 }
paddy@38 71 if !profile1.LastSeen.Equal(profile2.LastSeen) {
paddy@38 72 return false, "last seen", profile1.LastSeen, profile2.LastSeen
paddy@38 73 }
paddy@148 74 if profile1.Deleted != profile2.Deleted {
paddy@148 75 return false, "deleted", profile1.Deleted, profile2.Deleted
paddy@148 76 }
paddy@38 77 return true, "", nil, nil
paddy@38 78 }
paddy@38 79
paddy@46 80 func compareLogins(login1, login2 Login) (success bool, field string, val1, val2 interface{}) {
paddy@46 81 if login1.Type != login2.Type {
paddy@46 82 return false, "Type", login1.Type, login2.Type
paddy@46 83 }
paddy@46 84 if login1.Value != login2.Value {
paddy@46 85 return false, "Value", login1.Value, login2.Value
paddy@46 86 }
paddy@46 87 if !login1.ProfileID.Equal(login2.ProfileID) {
paddy@46 88 return false, "ProfileID", login1.ProfileID, login2.ProfileID
paddy@46 89 }
paddy@46 90 if !login1.Created.Equal(login2.Created) {
paddy@46 91 return false, "Created", login1.Created, login2.Created
paddy@46 92 }
paddy@46 93 if !login1.LastUsed.Equal(login2.LastUsed) {
paddy@46 94 return false, "LastUsed", login1.LastUsed, login2.LastUsed
paddy@46 95 }
paddy@46 96 return true, "", nil, nil
paddy@46 97 }
paddy@46 98
paddy@38 99 func TestProfileStoreSuccess(t *testing.T) {
paddy@38 100 t.Parallel()
paddy@38 101 profile := Profile{
paddy@38 102 ID: uuid.NewID(),
paddy@38 103 Name: "name",
paddy@38 104 Passphrase: "passphrase",
paddy@38 105 Iterations: 10000,
paddy@38 106 Salt: "salt",
paddy@38 107 PassphraseScheme: 1,
paddy@38 108 Compromised: false,
paddy@149 109 LockedUntil: time.Now().Add(time.Hour).Round(time.Millisecond),
paddy@38 110 PassphraseReset: "passphrase reset",
paddy@149 111 PassphraseResetCreated: time.Now().Round(time.Millisecond),
paddy@149 112 Created: time.Now().Round(time.Millisecond),
paddy@149 113 LastSeen: time.Now().Round(time.Millisecond),
paddy@38 114 }
paddy@38 115 for _, store := range profileStores {
paddy@116 116 context := Context{profiles: store}
paddy@116 117 err := context.SaveProfile(profile)
paddy@38 118 if err != nil {
paddy@38 119 t.Errorf("Error saving profile to %T: %s", store, err)
paddy@38 120 }
paddy@116 121 err = context.SaveProfile(profile)
paddy@38 122 if err != ErrProfileAlreadyExists {
paddy@38 123 t.Errorf("Expected ErrProfileAlreadyExists from %T, got %+v", store, err)
paddy@38 124 }
paddy@116 125 retrieved, err := context.GetProfileByID(profile.ID)
paddy@38 126 if err != nil {
paddy@38 127 t.Errorf("Error retrieving profile from %T: %s", store, err)
paddy@38 128 }
paddy@38 129 match, field, expectation, result := compareProfiles(profile, retrieved)
paddy@38 130 if !match {
paddy@38 131 t.Errorf("Expected `%v` in the `%s` field of profile retrieved from %T, got `%v`", expectation, field, store, result)
paddy@38 132 }
paddy@148 133 deleted := true
paddy@148 134 err = context.UpdateProfile(profile.ID, ProfileChange{Deleted: &deleted})
paddy@38 135 if err != nil {
paddy@38 136 t.Errorf("Error removing profile from %T: %s", store, err)
paddy@38 137 }
paddy@116 138 retrieved, err = context.GetProfileByID(profile.ID)
paddy@38 139 if err != ErrProfileNotFound {
paddy@38 140 t.Errorf("Expected ErrProfileNotFound from %T, got %+v and %+v", store, retrieved, err)
paddy@38 141 }
paddy@38 142 }
paddy@38 143 }
paddy@38 144
paddy@38 145 func TestProfileUpdates(t *testing.T) {
paddy@38 146 t.Parallel()
paddy@38 147 variations := 1 << 10
paddy@38 148 profile := Profile{
paddy@38 149 ID: uuid.NewID(),
paddy@38 150 Name: "name",
paddy@38 151 Passphrase: "passphrase",
paddy@38 152 Iterations: 10000,
paddy@38 153 Salt: "salt",
paddy@38 154 PassphraseScheme: 1,
paddy@38 155 Compromised: false,
paddy@149 156 LockedUntil: time.Now().Add(time.Hour).Round(time.Millisecond),
paddy@38 157 PassphraseReset: "passphrase reset",
paddy@149 158 PassphraseResetCreated: time.Now().Round(time.Millisecond),
paddy@149 159 Created: time.Now().Round(time.Millisecond),
paddy@149 160 LastSeen: time.Now().Round(time.Millisecond),
paddy@38 161 }
paddy@38 162 for i := 0; i < variations; i++ {
paddy@38 163 var name, passphrase, salt, passphraseReset string
paddy@69 164 var iterations int
paddy@38 165 var lockedUntil, passphraseResetCreated, lastSeen time.Time
paddy@38 166 var passphraseScheme int
paddy@38 167 var compromised bool
paddy@38 168
paddy@148 169 profile.ID = uuid.NewID()
paddy@38 170 change := ProfileChange{}
paddy@38 171 expectation := profile
paddy@38 172 result := profile
paddy@38 173 if i&profileChangeName != 0 {
paddy@38 174 name = fmt.Sprintf("name-%d", i)
paddy@38 175 change.Name = &name
paddy@38 176 expectation.Name = name
paddy@38 177 }
paddy@38 178 if i&profileChangePassphrase != 0 {
paddy@38 179 passphrase = fmt.Sprintf("passphrase-%d", i)
paddy@38 180 change.Passphrase = &passphrase
paddy@38 181 expectation.Passphrase = passphrase
paddy@38 182 }
paddy@38 183 if i&profileChangeIterations != 0 {
paddy@69 184 iterations = i
paddy@38 185 change.Iterations = &iterations
paddy@38 186 expectation.Iterations = iterations
paddy@38 187 }
paddy@38 188 if i&profileChangeSalt != 0 {
paddy@38 189 salt = fmt.Sprintf("salt-%d", i)
paddy@38 190 change.Salt = &salt
paddy@38 191 expectation.Salt = salt
paddy@38 192 }
paddy@38 193 if i&profileChangePassphraseScheme != 0 {
paddy@38 194 passphraseScheme = i
paddy@38 195 change.PassphraseScheme = &passphraseScheme
paddy@38 196 expectation.PassphraseScheme = passphraseScheme
paddy@38 197 }
paddy@38 198 if i&profileChangeCompromised != 0 {
paddy@38 199 compromised = i%2 != 0
paddy@38 200 change.Compromised = &compromised
paddy@38 201 expectation.Compromised = compromised
paddy@38 202 }
paddy@38 203 if i&profileChangeLockedUntil != 0 {
paddy@149 204 lockedUntil = time.Now().Round(time.Millisecond)
paddy@38 205 change.LockedUntil = &lockedUntil
paddy@38 206 expectation.LockedUntil = lockedUntil
paddy@38 207 }
paddy@38 208 if i&profileChangePassphraseReset != 0 {
paddy@38 209 passphraseReset = fmt.Sprintf("passphraseReset-%d", i)
paddy@38 210 change.PassphraseReset = &passphraseReset
paddy@38 211 expectation.PassphraseReset = passphraseReset
paddy@38 212 }
paddy@38 213 if i&profileChangePassphraseResetCreated != 0 {
paddy@149 214 passphraseResetCreated = time.Now().Round(time.Millisecond)
paddy@38 215 change.PassphraseResetCreated = &passphraseResetCreated
paddy@38 216 expectation.PassphraseResetCreated = passphraseResetCreated
paddy@38 217 }
paddy@38 218 if i&profileChangeLastSeen != 0 {
paddy@149 219 lastSeen = time.Now().Round(time.Millisecond)
paddy@38 220 change.LastSeen = &lastSeen
paddy@38 221 expectation.LastSeen = lastSeen
paddy@38 222 }
paddy@38 223 result.ApplyChange(change)
paddy@38 224 match, field, expected, got := compareProfiles(expectation, result)
paddy@38 225 if !match {
paddy@38 226 t.Errorf("Expected field `%s` to be `%v`, got `%v`", field, expected, got)
paddy@38 227 }
paddy@38 228 for _, store := range profileStores {
paddy@116 229 context := Context{profiles: store}
paddy@116 230 err := context.SaveProfile(profile)
paddy@38 231 if err != nil {
paddy@38 232 t.Errorf("Error saving profile in %T: %s", store, err)
paddy@38 233 }
paddy@116 234 err = context.UpdateProfile(profile.ID, change)
paddy@38 235 if err != nil {
paddy@38 236 t.Errorf("Error updating profile in %T: %s", store, err)
paddy@38 237 }
paddy@116 238 retrieved, err := context.GetProfileByID(profile.ID)
paddy@38 239 if err != nil {
paddy@38 240 t.Errorf("Error getting profile from %T: %s", store, err)
paddy@38 241 }
paddy@38 242 match, field, expected, got = compareProfiles(expectation, retrieved)
paddy@38 243 if !match {
paddy@38 244 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T", field, expected, got, store)
paddy@38 245 }
paddy@38 246 }
paddy@38 247 }
paddy@38 248 }
paddy@45 249
paddy@45 250 func TestProfilesUpdates(t *testing.T) {
paddy@45 251 profile1 := Profile{
paddy@45 252 ID: uuid.NewID(),
paddy@45 253 }
paddy@45 254 profile2 := Profile{
paddy@45 255 ID: uuid.NewID(),
paddy@45 256 }
paddy@45 257 profile3 := Profile{
paddy@45 258 ID: uuid.NewID(),
paddy@45 259 }
paddy@45 260 truth := true
paddy@45 261 change := BulkProfileChange{
paddy@45 262 Compromised: &truth,
paddy@45 263 }
paddy@45 264 for _, store := range profileStores {
paddy@116 265 context := Context{profiles: store}
paddy@116 266 err := context.SaveProfile(profile1)
paddy@45 267 if err != nil {
paddy@45 268 t.Errorf("Error saving profile in %T: %s", store, err)
paddy@45 269 }
paddy@116 270 err = context.SaveProfile(profile2)
paddy@45 271 if err != nil {
paddy@45 272 t.Errorf("Error saving profile in %T: %s", store, err)
paddy@45 273 }
paddy@116 274 err = context.SaveProfile(profile3)
paddy@45 275 if err != nil {
paddy@45 276 t.Errorf("Error saving profile in %T: %s", store, err)
paddy@45 277 }
paddy@116 278 err = context.UpdateProfiles([]uuid.ID{profile1.ID, profile3.ID}, change)
paddy@45 279 if err != nil {
paddy@45 280 t.Errorf("Error updating profile in %T: %s", store, err)
paddy@45 281 }
paddy@45 282 profile1.Compromised = truth
paddy@45 283 profile3.Compromised = truth
paddy@116 284 retrieved, err := context.GetProfileByID(profile1.ID)
paddy@45 285 if err != nil {
paddy@45 286 t.Errorf("Error getting profile from %T: %s", store, err)
paddy@45 287 }
paddy@45 288 match, field, expected, got := compareProfiles(profile1, retrieved)
paddy@45 289 if !match {
paddy@45 290 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T", field, expected, got, store)
paddy@45 291 }
paddy@116 292 retrieved, err = context.GetProfileByID(profile2.ID)
paddy@45 293 if err != nil {
paddy@45 294 t.Errorf("Error getting profile from %T: %s", store, err)
paddy@45 295 }
paddy@45 296 match, field, expected, got = compareProfiles(profile2, retrieved)
paddy@45 297 if !match {
paddy@45 298 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T", field, expected, got, store)
paddy@45 299 }
paddy@116 300 retrieved, err = context.GetProfileByID(profile3.ID)
paddy@45 301 if err != nil {
paddy@45 302 t.Errorf("Error getting profile from %T: %s", store, err)
paddy@45 303 }
paddy@45 304 match, field, expected, got = compareProfiles(profile3, retrieved)
paddy@45 305 if !match {
paddy@45 306 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T", field, expected, got, store)
paddy@45 307 }
paddy@45 308 }
paddy@45 309 }
paddy@46 310
paddy@46 311 func TestProfileStoreLoginSuccess(t *testing.T) {
paddy@46 312 t.Parallel()
paddy@46 313 login := Login{
paddy@46 314 Type: "type",
paddy@46 315 Value: "value",
paddy@46 316 ProfileID: uuid.NewID(),
paddy@149 317 Created: time.Now().Add(-1 * time.Hour).Round(time.Millisecond),
paddy@149 318 LastUsed: time.Now().Add(-1 * time.Minute).Round(time.Millisecond),
paddy@46 319 }
paddy@46 320 for _, store := range profileStores {
paddy@116 321 context := Context{profiles: store}
paddy@116 322 err := context.AddLogin(login)
paddy@46 323 if err != nil {
paddy@46 324 t.Errorf("Error adding login to %T: %s", store, err)
paddy@46 325 }
paddy@116 326 err = context.AddLogin(login)
paddy@46 327 if err != ErrLoginAlreadyExists {
paddy@46 328 t.Errorf("Expected ErrLoginAlreadyExists from %T, got %+v", store, err)
paddy@46 329 }
paddy@116 330 retrieved, err := context.ListLogins(login.ProfileID, 10, 0)
paddy@46 331 if err != nil {
paddy@46 332 t.Errorf("Error retrieving logins from %T: %s", store, err)
paddy@46 333 }
paddy@46 334 if len(retrieved) != 1 {
paddy@46 335 t.Errorf("Expected 1 login result from %T, got %d", store, len(retrieved))
paddy@46 336 }
paddy@46 337 match, field, expectation, result := compareLogins(login, retrieved[0])
paddy@46 338 if !match {
paddy@46 339 t.Errorf("Expected `%v` in the `%s` field of login retrieved from %T, got `%v`", expectation, field, store, result)
paddy@46 340 }
paddy@149 341 lastUsed := time.Now().Round(time.Millisecond)
paddy@116 342 err = context.RecordLoginUse(login.Value, lastUsed)
paddy@46 343 if err != nil {
paddy@46 344 t.Errorf("Error recording use of login to %T: %s", store, err)
paddy@46 345 }
paddy@46 346 login.LastUsed = lastUsed
paddy@116 347 retrieved, err = context.ListLogins(login.ProfileID, 10, 0)
paddy@46 348 if err != nil {
paddy@46 349 t.Errorf("Error retrieving logins from %T: %s", store, err)
paddy@46 350 }
paddy@46 351 if len(retrieved) != 1 {
paddy@46 352 t.Errorf("Expected 1 login result from %T, got %d", store, len(retrieved))
paddy@46 353 }
paddy@46 354 match, field, expectation, result = compareLogins(login, retrieved[0])
paddy@46 355 if !match {
paddy@46 356 t.Errorf("Expected `%v` in the `%s` field of login retrieved from %T, got `%v`", expectation, field, store, result)
paddy@46 357 }
paddy@116 358 err = context.RemoveLogin(login.Value, login.ProfileID)
paddy@46 359 if err != nil {
paddy@46 360 t.Errorf("Error removing login from %T: %s", store, err)
paddy@46 361 }
paddy@116 362 retrieved, err = context.ListLogins(login.ProfileID, 10, 0)
paddy@46 363 if len(retrieved) != 0 {
paddy@46 364 t.Errorf("Expected 0 login results from %T, got %d: %+v", store, len(retrieved), retrieved)
paddy@46 365 }
paddy@116 366 err = context.RemoveLogin(login.Value, login.ProfileID)
paddy@46 367 if err != ErrLoginNotFound {
paddy@46 368 t.Errorf("Expected ErrLoginNotFound from %T, got %+v", store, err)
paddy@46 369 }
paddy@46 370 }
paddy@46 371 }
paddy@47 372
paddy@47 373 func TestProfileStoreLoginRetrieval(t *testing.T) {
paddy@47 374 t.Parallel()
paddy@47 375 profile := Profile{
paddy@47 376 ID: uuid.NewID(),
paddy@47 377 Name: "name",
paddy@47 378 Passphrase: "passphrase",
paddy@47 379 Iterations: 10000,
paddy@47 380 Salt: "salt",
paddy@47 381 PassphraseScheme: 1,
paddy@47 382 Compromised: false,
paddy@149 383 LockedUntil: time.Now().Add(time.Hour).Round(time.Millisecond),
paddy@47 384 PassphraseReset: "passphrase reset",
paddy@149 385 PassphraseResetCreated: time.Now().Round(time.Millisecond),
paddy@149 386 Created: time.Now().Round(time.Millisecond),
paddy@149 387 LastSeen: time.Now().Round(time.Millisecond),
paddy@47 388 }
paddy@47 389 login := Login{
paddy@47 390 Type: "type",
paddy@47 391 Value: "value",
paddy@47 392 ProfileID: profile.ID,
paddy@149 393 Created: time.Now().Add(-1 * time.Hour).Round(time.Millisecond),
paddy@149 394 LastUsed: time.Now().Add(-1 * time.Minute).Round(time.Millisecond),
paddy@47 395 }
paddy@47 396 for _, store := range profileStores {
paddy@116 397 context := Context{profiles: store}
paddy@116 398 err := context.SaveProfile(profile)
paddy@47 399 if err != nil {
paddy@47 400 t.Errorf("Error saving profile in %T: %s", store, err)
paddy@47 401 }
paddy@116 402 err = context.AddLogin(login)
paddy@47 403 if err != nil {
paddy@47 404 t.Errorf("Error storing login in %T: %s", store, err)
paddy@47 405 }
paddy@116 406 retrieved, err := context.GetProfileByLogin(login.Value)
paddy@47 407 if err != nil {
paddy@47 408 t.Errorf("Error retrieving profile by login from %T: %s", store, err)
paddy@47 409 }
paddy@47 410 match, field, expectation, result := compareProfiles(profile, retrieved)
paddy@47 411 if !match {
paddy@47 412 t.Errorf("Expected `%v` in the `%s` field of profile retrieved from %T, got `%v`", expectation, field, store, result)
paddy@47 413 }
paddy@47 414 }
paddy@47 415 }
paddy@48 416
paddy@48 417 func TestProfileChangeValidation(t *testing.T) {
paddy@48 418 t.Parallel()
paddy@48 419 passphraseScheme := 1
paddy@48 420 passphraseReset := "reset"
paddy@48 421 salt := "salt"
paddy@69 422 iterations := 100
paddy@48 423 emptyName := ""
paddy@48 424 enteredName := "Paddy"
paddy@48 425 okPassphrase := "this is a decent passphrase"
paddy@48 426 compromised := true
paddy@149 427 lockedUntil := time.Now().Round(time.Millisecond)
paddy@149 428 resetCreated := time.Now().Round(time.Millisecond)
paddy@149 429 lastSeen := time.Now().Round(time.Millisecond)
paddy@48 430 changes := map[*ProfileChange]error{
paddy@48 431 &ProfileChange{}: ErrEmptyChange,
paddy@48 432 &ProfileChange{PassphraseScheme: &passphraseScheme}: ErrMissingPassphrase,
paddy@48 433 &ProfileChange{PassphraseScheme: &passphraseScheme, Passphrase: &okPassphrase}: nil,
paddy@48 434 &ProfileChange{PassphraseReset: &passphraseReset}: ErrMissingPassphraseResetCreated,
paddy@48 435 &ProfileChange{PassphraseReset: &passphraseReset, PassphraseResetCreated: &resetCreated}: nil,
paddy@48 436 &ProfileChange{Salt: &salt}: ErrMissingPassphrase,
paddy@48 437 &ProfileChange{Salt: &salt, Passphrase: &okPassphrase}: nil,
paddy@48 438 &ProfileChange{Iterations: &iterations}: ErrMissingPassphrase,
paddy@48 439 &ProfileChange{Iterations: &iterations, Passphrase: &okPassphrase}: nil,
paddy@48 440 &ProfileChange{Passphrase: &okPassphrase}: nil,
paddy@48 441 &ProfileChange{Name: &emptyName}: nil,
paddy@48 442 &ProfileChange{Name: &enteredName}: nil,
paddy@48 443 &ProfileChange{Compromised: &compromised}: nil,
paddy@48 444 &ProfileChange{LockedUntil: &lockedUntil}: nil,
paddy@48 445 &ProfileChange{LastSeen: &lastSeen}: nil,
paddy@48 446 &ProfileChange{PassphraseResetCreated: &resetCreated}: ErrMissingPassphraseReset,
paddy@48 447 }
paddy@48 448 for change, expectedErr := range changes {
paddy@48 449 if err := change.Validate(); err != expectedErr {
paddy@48 450 t.Errorf("Expected %+v to give an error of %v, gave %v", change, expectedErr, err)
paddy@48 451 }
paddy@48 452 }
paddy@48 453 }
paddy@48 454
paddy@48 455 func TestBulkProfileChangeValidation(t *testing.T) {
paddy@48 456 t.Parallel()
paddy@48 457 compromised := true
paddy@48 458 changes := map[*BulkProfileChange]error{
paddy@48 459 &BulkProfileChange{}: ErrEmptyChange,
paddy@48 460 &BulkProfileChange{Compromised: &compromised}: nil,
paddy@48 461 }
paddy@48 462 for change, expectedErr := range changes {
paddy@48 463 if err := change.Validate(); err != expectedErr {
paddy@48 464 t.Errorf("Expected %+v to give an error of %v, gave %v", change, expectedErr, err)
paddy@48 465 }
paddy@48 466 }
paddy@48 467 }
paddy@128 468
paddy@128 469 // BUG(paddy): We need to test the validateNewProfileRequest helper.
paddy@128 470 // BUG(paddy): We need to test the CreateProfileHandler.
paddy@148 471 // BUG(paddy): We need to test that deleting works as we expect.