auth
2015-02-20
Child:e090a69e711f
auth/scope_test.go
Introduced scopes. Created a Scope type and a scopeStore interface, along with the memstore methods for the scopeStore. This will allow applications to define access with granularity, so users can grant access to some data, not _all_ data. We're operating on the assumption that there won't be an unreasonable number of scopes defined, so there is no paging operation included for the ListScopes method. This is a decision that may have to be revisited in the future, depending on usecases.
| paddy@134 | 1 package auth |
| paddy@134 | 2 |
| paddy@134 | 3 import "testing" |
| paddy@134 | 4 |
| paddy@134 | 5 var scopeStores = []scopeStore{NewMemstore()} |
| paddy@134 | 6 |
| paddy@134 | 7 func compareScopes(scope1, scope2 Scope) (success bool, field string, val1, val2 interface{}) { |
| paddy@134 | 8 if scope1.ID != scope2.ID { |
| paddy@134 | 9 return false, "ID", scope1.ID, scope2.ID |
| paddy@134 | 10 } |
| paddy@134 | 11 if scope1.Name != scope2.Name { |
| paddy@134 | 12 return false, "Name", scope1.Name, scope2.Name |
| paddy@134 | 13 } |
| paddy@134 | 14 if scope1.Description != scope2.Description { |
| paddy@134 | 15 return false, "Description", scope1.Description, scope2.Description |
| paddy@134 | 16 } |
| paddy@134 | 17 return true, "", nil, nil |
| paddy@134 | 18 } |
| paddy@134 | 19 |
| paddy@134 | 20 func TestScopeInScopeStore(t *testing.T) { |
| paddy@134 | 21 scope := Scope{ |
| paddy@134 | 22 ID: "testscope", |
| paddy@134 | 23 Name: "Test Scope", |
| paddy@134 | 24 Description: "Access to testing data.", |
| paddy@134 | 25 } |
| paddy@134 | 26 scope2 := Scope{ |
| paddy@134 | 27 ID: "testscope2", |
| paddy@134 | 28 Name: "Test Scope 2", |
| paddy@134 | 29 Description: "Access to minions.", |
| paddy@134 | 30 } |
| paddy@134 | 31 scope3 := Scope{ |
| paddy@134 | 32 ID: "testscope3", |
| paddy@134 | 33 Name: "Test Scope 3", |
| paddy@134 | 34 Description: "Access to bananas.", |
| paddy@134 | 35 } |
| paddy@134 | 36 updatedName := "Updated Scope" |
| paddy@134 | 37 updatedDescription := "An updated scope." |
| paddy@134 | 38 update := ScopeChange{ |
| paddy@134 | 39 ID: scope.ID, |
| paddy@134 | 40 Name: &updatedName, |
| paddy@134 | 41 } |
| paddy@134 | 42 update2 := ScopeChange{ |
| paddy@134 | 43 ID: scope2.ID, |
| paddy@134 | 44 Description: &updatedDescription, |
| paddy@134 | 45 } |
| paddy@134 | 46 update3 := ScopeChange{ |
| paddy@134 | 47 ID: scope3.ID, |
| paddy@134 | 48 Name: &updatedName, |
| paddy@134 | 49 Description: &updatedDescription, |
| paddy@134 | 50 } |
| paddy@134 | 51 for _, store := range scopeStores { |
| paddy@134 | 52 context := Context{scopes: store} |
| paddy@134 | 53 retrieved, err := context.GetScopes([]string{scope.ID}) |
| paddy@134 | 54 if len(retrieved) != 0 { |
| paddy@134 | 55 t.Logf("%+v", retrieved) |
| paddy@134 | 56 t.Errorf("Expected %d results, got %d from %T", 0, len(retrieved), store) |
| paddy@134 | 57 } |
| paddy@134 | 58 if e, ok := err.(ErrScopeNotFound); !ok { |
| paddy@134 | 59 t.Errorf("Expected ErrScopeNotFound, got %+v instead for %T", err, store) |
| paddy@134 | 60 } else { |
| paddy@134 | 61 if e.Pos != 0 { |
| paddy@134 | 62 t.Errorf("Expected the error to be in position %d, got position %d from %T", 0, e.Pos, store) |
| paddy@134 | 63 } |
| paddy@134 | 64 if e.ID != scope.ID { |
| paddy@134 | 65 t.Errorf("Expected the error to be with scope %s, got %s from %T", scope.ID, e.ID, store) |
| paddy@134 | 66 } |
| paddy@134 | 67 } |
| paddy@134 | 68 err = context.CreateScopes([]Scope{scope}) |
| paddy@134 | 69 if err != nil { |
| paddy@134 | 70 t.Errorf("Error saving scope to %T: %s", store, err) |
| paddy@134 | 71 } |
| paddy@134 | 72 err = context.CreateScopes([]Scope{scope}) |
| paddy@134 | 73 if e, ok := err.(ErrScopeAlreadyExists); !ok { |
| paddy@134 | 74 t.Errorf("Expected ErrScopeAlreadyExists, got %s instead for %T", err, store) |
| paddy@134 | 75 } else { |
| paddy@134 | 76 if e.Pos != 0 { |
| paddy@134 | 77 t.Errorf("Expected the error to be in position %d, got position %d from %T", 0, e.Pos, store) |
| paddy@134 | 78 } |
| paddy@134 | 79 if e.ID != scope.ID { |
| paddy@134 | 80 t.Errorf("Expected the error to be for ID %s, got %s from %T", scope.ID, e.ID, store) |
| paddy@134 | 81 } |
| paddy@134 | 82 } |
| paddy@134 | 83 retrieved, err = context.GetScopes([]string{scope.ID}) |
| paddy@134 | 84 if err != nil { |
| paddy@134 | 85 t.Errorf("Unexpected error retrieving scopes from %T: %+v", store, err) |
| paddy@134 | 86 } |
| paddy@134 | 87 if len(retrieved) != 1 { |
| paddy@134 | 88 t.Logf("%+v", retrieved) |
| paddy@134 | 89 t.Errorf("Expected %d results, got %d from %T", 1, len(retrieved), store) |
| paddy@134 | 90 } |
| paddy@134 | 91 success, field, val1, val2 := compareScopes(scope, retrieved[0]) |
| paddy@134 | 92 if !success { |
| paddy@134 | 93 t.Errorf("Expected %s to be %+v, got %+v from %T", field, val1, val2, store) |
| paddy@134 | 94 } |
| paddy@134 | 95 err = context.CreateScopes([]Scope{scope2, scope3}) |
| paddy@134 | 96 if err != nil { |
| paddy@134 | 97 t.Errorf("Unexpected error trying to create scope2 and scope3 in %T: %+v", store, err) |
| paddy@134 | 98 } |
| paddy@134 | 99 retrieved, err = context.GetScopes([]string{scope.ID, scope2.ID, scope3.ID}) |
| paddy@134 | 100 if err != nil { |
| paddy@134 | 101 t.Errorf("Unexpected error retrieving scopes from %T: %+v", store, err) |
| paddy@134 | 102 } |
| paddy@134 | 103 if len(retrieved) != 3 { |
| paddy@134 | 104 t.Logf("%+v", retrieved) |
| paddy@134 | 105 t.Errorf("Expected %d results, got %d from %T", 3, len(retrieved), store) |
| paddy@134 | 106 } |
| paddy@134 | 107 for pos, s := range []Scope{scope, scope2, scope3} { |
| paddy@134 | 108 success, field, val1, val2 = compareScopes(s, retrieved[pos]) |
| paddy@134 | 109 if !success { |
| paddy@134 | 110 t.Errorf("Expected %s to be %+v for scope %s, got %+v from %T", field, val1, s.ID, val2, store) |
| paddy@134 | 111 } |
| paddy@134 | 112 } |
| paddy@134 | 113 updated, err := context.UpdateScopes([]ScopeChange{update, update2, update3}) |
| paddy@134 | 114 if err != nil { |
| paddy@134 | 115 t.Errorf("Unexpected error updating scopes in %T: %+v", store, err) |
| paddy@134 | 116 } |
| paddy@134 | 117 if len(updated) != 3 { |
| paddy@134 | 118 t.Logf("%+v", updated) |
| paddy@134 | 119 t.Errorf("Expected %d results, got %d from %T", 3, len(updated), store) |
| paddy@134 | 120 } |
| paddy@134 | 121 scope.ApplyChange(update) |
| paddy@134 | 122 scope2.ApplyChange(update2) |
| paddy@134 | 123 scope3.ApplyChange(update3) |
| paddy@134 | 124 for pos, s := range []Scope{scope, scope2, scope3} { |
| paddy@134 | 125 success, field, val1, val2 = compareScopes(s, updated[pos]) |
| paddy@134 | 126 if !success { |
| paddy@134 | 127 t.Errorf("Expected %s to be %+v for scope %s, got %+v from %T", field, val1, s.ID, val2, store) |
| paddy@134 | 128 } |
| paddy@134 | 129 } |
| paddy@134 | 130 retrieved, err = context.ListScopes() |
| paddy@134 | 131 if err != nil { |
| paddy@134 | 132 t.Errorf("Unexpected error retrieving scopes from %T: %+v", store, err) |
| paddy@134 | 133 } |
| paddy@134 | 134 if len(retrieved) != 3 { |
| paddy@134 | 135 t.Logf("%+v", retrieved) |
| paddy@134 | 136 t.Errorf("Expected %d results, got %d from %T", 3, len(retrieved), store) |
| paddy@134 | 137 } |
| paddy@134 | 138 for pos, s := range []Scope{scope, scope2, scope3} { |
| paddy@134 | 139 success, field, val1, val2 = compareScopes(s, retrieved[pos]) |
| paddy@134 | 140 if !success { |
| paddy@134 | 141 t.Errorf("Expected %s to be %+v for scope %s, got $+v from %T", field, val1, s.ID, val2, store) |
| paddy@134 | 142 } |
| paddy@134 | 143 } |
| paddy@134 | 144 err = context.RemoveScopes([]string{scope.ID, scope2.ID, scope3.ID}) |
| paddy@134 | 145 if err != nil { |
| paddy@134 | 146 t.Errorf("Unexpected error removing scopes from %T: %+v", store, err) |
| paddy@134 | 147 } |
| paddy@134 | 148 retrieved, err = context.ListScopes() |
| paddy@134 | 149 if err != nil { |
| paddy@134 | 150 t.Errorf("Unexpected error retrieving scopes from %T: %+v", store, err) |
| paddy@134 | 151 } |
| paddy@134 | 152 if len(retrieved) != 0 { |
| paddy@134 | 153 t.Logf("%+v", retrieved) |
| paddy@134 | 154 t.Errorf("Expected %d results, got %d from %T", 0, len(retrieved), store) |
| paddy@134 | 155 } |
| paddy@134 | 156 err = context.RemoveScopes([]string{scope.ID}) |
| paddy@134 | 157 if err == nil { |
| paddy@134 | 158 t.Errorf("No error returned removing non-existent scopes from %T", store) |
| paddy@134 | 159 } |
| paddy@134 | 160 if e, ok := err.(ErrScopeNotFound); !ok { |
| paddy@134 | 161 t.Errorf("Unexpected error removing non-existent scopes from %T: %+v", store, err) |
| paddy@134 | 162 } else { |
| paddy@134 | 163 if e.Pos != 0 { |
| paddy@134 | 164 t.Errorf("Expected error to be for scope ID in pos %d, but got %d from %T", 0, e.Pos, store) |
| paddy@134 | 165 } |
| paddy@134 | 166 if e.ID != scope.ID { |
| paddy@134 | 167 t.Errorf("Expected error to be for scope ID %s, but got %s from %T", scope.ID, e.ID, store) |
| paddy@134 | 168 } |
| paddy@134 | 169 } |
| paddy@134 | 170 updated, err = context.UpdateScopes([]ScopeChange{update}) |
| paddy@134 | 171 if err == nil { |
| paddy@134 | 172 t.Errorf("No error returned updating non-existent scopes from %T", store) |
| paddy@134 | 173 } |
| paddy@134 | 174 if e, ok := err.(ErrScopeNotFound); !ok { |
| paddy@134 | 175 t.Errorf("Unexpected error updating non-existent scopes from %T: %+v", store, err) |
| paddy@134 | 176 } else { |
| paddy@134 | 177 if e.Pos != 0 { |
| paddy@134 | 178 t.Errorf("Expected error to be for scope ID in pos %d, but got %d from %T", 0, e.Pos, store) |
| paddy@134 | 179 } |
| paddy@134 | 180 if e.ID != scope.ID { |
| paddy@134 | 181 t.Errorf("Expected error to be for scope ID %s, but got %s from %T", scope.ID, e.ID, store) |
| paddy@134 | 182 } |
| paddy@134 | 183 } |
| paddy@134 | 184 } |
| paddy@134 | 185 } |
| paddy@134 | 186 |
| paddy@134 | 187 func TestScopeErrors(t *testing.T) { |
| paddy@134 | 188 errors := map[string]error{ |
| paddy@134 | 189 "scope test couldn't be found": ErrScopeNotFound{ID: "test", Pos: 0}, |
| paddy@134 | 190 "scope test already exists": ErrScopeAlreadyExists{ID: "test", Pos: 0}, |
| paddy@134 | 191 } |
| paddy@134 | 192 for expectation, e := range errors { |
| paddy@134 | 193 if e.Error() != expectation { |
| paddy@134 | 194 t.Errorf("Expected %+v to produce '%s', produced '%s'", e, expectation, e.Error()) |
| paddy@134 | 195 } |
| paddy@134 | 196 } |
| paddy@134 | 197 } |