auth

Paddy 2015-07-15 Parent:8ecb60d29b0d

178:0a2c3d677161 Go to Latest

auth/profile_test.go

Update to use a generic event emitter. Rather can creating a purpose-built event emitter for each and every event we need to emit (I'm looking at you, login verification event) which is _downright silly_, we're now using a generic event publisher that's based on saying "HEY A MODEL UPDATED". This means we need to change all our setup code in authd to use events.NewNSQPublisher or events.NewStdoutPublisher instead of our homegrown solutions. Which also means updating our config to take an events.Publisher instead of our LoginVerificationNotifier (blergh). Our Context also now uses an events.Publisher instead of a LoginVerificationNotifier. Party all around! We also replaced our SendLoginVerification helper method on Context with a SendModelEvent helper method on Context, which is just a light wrapper around events.PublishModelEvent. Of course, all this means we need to update our email_verification listener to listen to the correct channel (based on the model we want updates about) and filter down to a Created action or our new custom action for "the customer wants their verification resent", which I'm OK making a special case and not generic, because c'mon. But we had a subtle change to all our constants, some of which are unofficial constants now. I'm unsure how I feel about this. We also updated our email_verification listener so that we're unmarshalling to a custom loginEvent, which is just an events.Event that overwrites the Data property to be an auth.Login instance. This is to make sure we don't need to wrangle a map[string]interface{}, which is no fun. I'm also OK with special-casing like this, because it's 1) a tiny amount of code, 2) properly utilising composition, and 3) the only way I can think of to cleanly accomplish what I want. I also added a note about GetLogin's deficient handling of logins, namely that it doesn't recognise admins and return Verification codes to them, which would be a useful property for internal tools to take advantage of. Ah well. I updated the Profile and Login implementations so they're now event.Model instances, mainly by just exporting some strings from them through getters that will let us automatically build an Event from them. This lets us use the PublishModelEvent helper. I updated our CreateProfileHandler to properly mangle the login Verification property, and to fire off the ActionCreated events for the new Login and the new Profile. I updated our GetLoginHandler and UpdateLoginHandler to properly mangle the loginVerification property. God that's annoying. :-/ You'll note I didn't start publishing the events.ActionUpdated or events.ActionDeleted events for Profiles or Logins yet, and didn't bother publishing any events for literally any other type. That's because I'm a lazy piece of crap and will end up publishing them when I absolutely have to. Part of that is because if a channel isn't created/being read for a topic, the messages will just stack up in NSQ, and I don't want that. But mostly I'm lazy. Finally, I got to delete the entire profile_verification.go file, because we're no longer special-casing that. Hooray!

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