auth

Paddy 2014-10-26 Parent:d78418fb9f56 Child:42bc3e44f4fe

57:e45bfa2abc00 Go to Latest

auth/profile_test.go

The great documentation and exported interface cleanup. Modify all our *Store interfaces to be unexported, as there's no real good reason they need to be exported, especially as they can be implemented without being exported. The interfaces shouldn't matter to 99% of users of the package, so let's not pollute our package API. Further, all methods of the interfaces are now unexported, for pretty much the same reasoning. Add a doc.go file with documentation explaining the choices the package is making and what it provides. Implement documentation on all our exported types and methods and functions, which makes golint happy. The only remaining golint warning is about NewMemstore, which will stay the way it is. The memstore type is useful outside tests for things like standing up a server quickly when we don't care about the storage, and because the type is unexported, we _need_ a New function to create an instance that can be passed to the Context.

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