auth

Paddy 2015-02-20 Child:e090a69e711f

134:d103a598548c Go to Latest

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.

History
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/scope_test.go	Fri Feb 20 22:34:43 2015 -0500
     1.3 @@ -0,0 +1,197 @@
     1.4 +package auth
     1.5 +
     1.6 +import "testing"
     1.7 +
     1.8 +var scopeStores = []scopeStore{NewMemstore()}
     1.9 +
    1.10 +func compareScopes(scope1, scope2 Scope) (success bool, field string, val1, val2 interface{}) {
    1.11 +	if scope1.ID != scope2.ID {
    1.12 +		return false, "ID", scope1.ID, scope2.ID
    1.13 +	}
    1.14 +	if scope1.Name != scope2.Name {
    1.15 +		return false, "Name", scope1.Name, scope2.Name
    1.16 +	}
    1.17 +	if scope1.Description != scope2.Description {
    1.18 +		return false, "Description", scope1.Description, scope2.Description
    1.19 +	}
    1.20 +	return true, "", nil, nil
    1.21 +}
    1.22 +
    1.23 +func TestScopeInScopeStore(t *testing.T) {
    1.24 +	scope := Scope{
    1.25 +		ID:          "testscope",
    1.26 +		Name:        "Test Scope",
    1.27 +		Description: "Access to testing data.",
    1.28 +	}
    1.29 +	scope2 := Scope{
    1.30 +		ID:          "testscope2",
    1.31 +		Name:        "Test Scope 2",
    1.32 +		Description: "Access to minions.",
    1.33 +	}
    1.34 +	scope3 := Scope{
    1.35 +		ID:          "testscope3",
    1.36 +		Name:        "Test Scope 3",
    1.37 +		Description: "Access to bananas.",
    1.38 +	}
    1.39 +	updatedName := "Updated Scope"
    1.40 +	updatedDescription := "An updated scope."
    1.41 +	update := ScopeChange{
    1.42 +		ID:   scope.ID,
    1.43 +		Name: &updatedName,
    1.44 +	}
    1.45 +	update2 := ScopeChange{
    1.46 +		ID:          scope2.ID,
    1.47 +		Description: &updatedDescription,
    1.48 +	}
    1.49 +	update3 := ScopeChange{
    1.50 +		ID:          scope3.ID,
    1.51 +		Name:        &updatedName,
    1.52 +		Description: &updatedDescription,
    1.53 +	}
    1.54 +	for _, store := range scopeStores {
    1.55 +		context := Context{scopes: store}
    1.56 +		retrieved, err := context.GetScopes([]string{scope.ID})
    1.57 +		if len(retrieved) != 0 {
    1.58 +			t.Logf("%+v", retrieved)
    1.59 +			t.Errorf("Expected %d results, got %d from %T", 0, len(retrieved), store)
    1.60 +		}
    1.61 +		if e, ok := err.(ErrScopeNotFound); !ok {
    1.62 +			t.Errorf("Expected ErrScopeNotFound, got %+v instead for %T", err, store)
    1.63 +		} else {
    1.64 +			if e.Pos != 0 {
    1.65 +				t.Errorf("Expected the error to be in position %d, got position %d from %T", 0, e.Pos, store)
    1.66 +			}
    1.67 +			if e.ID != scope.ID {
    1.68 +				t.Errorf("Expected the error to be with scope %s, got %s from %T", scope.ID, e.ID, store)
    1.69 +			}
    1.70 +		}
    1.71 +		err = context.CreateScopes([]Scope{scope})
    1.72 +		if err != nil {
    1.73 +			t.Errorf("Error saving scope to %T: %s", store, err)
    1.74 +		}
    1.75 +		err = context.CreateScopes([]Scope{scope})
    1.76 +		if e, ok := err.(ErrScopeAlreadyExists); !ok {
    1.77 +			t.Errorf("Expected ErrScopeAlreadyExists, got %s instead for %T", err, store)
    1.78 +		} else {
    1.79 +			if e.Pos != 0 {
    1.80 +				t.Errorf("Expected the error to be in position %d, got position %d from %T", 0, e.Pos, store)
    1.81 +			}
    1.82 +			if e.ID != scope.ID {
    1.83 +				t.Errorf("Expected the error to be for ID %s, got %s from %T", scope.ID, e.ID, store)
    1.84 +			}
    1.85 +		}
    1.86 +		retrieved, err = context.GetScopes([]string{scope.ID})
    1.87 +		if err != nil {
    1.88 +			t.Errorf("Unexpected error retrieving scopes from %T: %+v", store, err)
    1.89 +		}
    1.90 +		if len(retrieved) != 1 {
    1.91 +			t.Logf("%+v", retrieved)
    1.92 +			t.Errorf("Expected %d results, got %d from %T", 1, len(retrieved), store)
    1.93 +		}
    1.94 +		success, field, val1, val2 := compareScopes(scope, retrieved[0])
    1.95 +		if !success {
    1.96 +			t.Errorf("Expected %s to be %+v, got %+v from %T", field, val1, val2, store)
    1.97 +		}
    1.98 +		err = context.CreateScopes([]Scope{scope2, scope3})
    1.99 +		if err != nil {
   1.100 +			t.Errorf("Unexpected error trying to create scope2 and scope3 in %T: %+v", store, err)
   1.101 +		}
   1.102 +		retrieved, err = context.GetScopes([]string{scope.ID, scope2.ID, scope3.ID})
   1.103 +		if err != nil {
   1.104 +			t.Errorf("Unexpected error retrieving scopes from  %T: %+v", store, err)
   1.105 +		}
   1.106 +		if len(retrieved) != 3 {
   1.107 +			t.Logf("%+v", retrieved)
   1.108 +			t.Errorf("Expected %d results, got %d from %T", 3, len(retrieved), store)
   1.109 +		}
   1.110 +		for pos, s := range []Scope{scope, scope2, scope3} {
   1.111 +			success, field, val1, val2 = compareScopes(s, retrieved[pos])
   1.112 +			if !success {
   1.113 +				t.Errorf("Expected %s to be %+v for scope %s, got %+v from %T", field, val1, s.ID, val2, store)
   1.114 +			}
   1.115 +		}
   1.116 +		updated, err := context.UpdateScopes([]ScopeChange{update, update2, update3})
   1.117 +		if err != nil {
   1.118 +			t.Errorf("Unexpected error updating scopes in %T: %+v", store, err)
   1.119 +		}
   1.120 +		if len(updated) != 3 {
   1.121 +			t.Logf("%+v", updated)
   1.122 +			t.Errorf("Expected %d results, got %d from %T", 3, len(updated), store)
   1.123 +		}
   1.124 +		scope.ApplyChange(update)
   1.125 +		scope2.ApplyChange(update2)
   1.126 +		scope3.ApplyChange(update3)
   1.127 +		for pos, s := range []Scope{scope, scope2, scope3} {
   1.128 +			success, field, val1, val2 = compareScopes(s, updated[pos])
   1.129 +			if !success {
   1.130 +				t.Errorf("Expected %s to be %+v for scope %s, got %+v from %T", field, val1, s.ID, val2, store)
   1.131 +			}
   1.132 +		}
   1.133 +		retrieved, err = context.ListScopes()
   1.134 +		if err != nil {
   1.135 +			t.Errorf("Unexpected error retrieving scopes from %T: %+v", store, err)
   1.136 +		}
   1.137 +		if len(retrieved) != 3 {
   1.138 +			t.Logf("%+v", retrieved)
   1.139 +			t.Errorf("Expected %d results, got %d from %T", 3, len(retrieved), store)
   1.140 +		}
   1.141 +		for pos, s := range []Scope{scope, scope2, scope3} {
   1.142 +			success, field, val1, val2 = compareScopes(s, retrieved[pos])
   1.143 +			if !success {
   1.144 +				t.Errorf("Expected %s to be %+v for scope %s, got $+v from %T", field, val1, s.ID, val2, store)
   1.145 +			}
   1.146 +		}
   1.147 +		err = context.RemoveScopes([]string{scope.ID, scope2.ID, scope3.ID})
   1.148 +		if err != nil {
   1.149 +			t.Errorf("Unexpected error removing scopes from %T: %+v", store, err)
   1.150 +		}
   1.151 +		retrieved, err = context.ListScopes()
   1.152 +		if err != nil {
   1.153 +			t.Errorf("Unexpected error retrieving scopes from %T: %+v", store, err)
   1.154 +		}
   1.155 +		if len(retrieved) != 0 {
   1.156 +			t.Logf("%+v", retrieved)
   1.157 +			t.Errorf("Expected %d results, got %d from %T", 0, len(retrieved), store)
   1.158 +		}
   1.159 +		err = context.RemoveScopes([]string{scope.ID})
   1.160 +		if err == nil {
   1.161 +			t.Errorf("No error returned removing non-existent scopes from %T", store)
   1.162 +		}
   1.163 +		if e, ok := err.(ErrScopeNotFound); !ok {
   1.164 +			t.Errorf("Unexpected error removing non-existent scopes from %T: %+v", store, err)
   1.165 +		} else {
   1.166 +			if e.Pos != 0 {
   1.167 +				t.Errorf("Expected error to be for scope ID in pos %d, but got %d from %T", 0, e.Pos, store)
   1.168 +			}
   1.169 +			if e.ID != scope.ID {
   1.170 +				t.Errorf("Expected error to be for scope ID %s, but got %s from %T", scope.ID, e.ID, store)
   1.171 +			}
   1.172 +		}
   1.173 +		updated, err = context.UpdateScopes([]ScopeChange{update})
   1.174 +		if err == nil {
   1.175 +			t.Errorf("No error returned updating non-existent scopes from %T", store)
   1.176 +		}
   1.177 +		if e, ok := err.(ErrScopeNotFound); !ok {
   1.178 +			t.Errorf("Unexpected error updating non-existent scopes from %T: %+v", store, err)
   1.179 +		} else {
   1.180 +			if e.Pos != 0 {
   1.181 +				t.Errorf("Expected error to be for scope ID in pos %d, but got %d from %T", 0, e.Pos, store)
   1.182 +			}
   1.183 +			if e.ID != scope.ID {
   1.184 +				t.Errorf("Expected error to be for scope ID %s, but got %s from %T", scope.ID, e.ID, store)
   1.185 +			}
   1.186 +		}
   1.187 +	}
   1.188 +}
   1.189 +
   1.190 +func TestScopeErrors(t *testing.T) {
   1.191 +	errors := map[string]error{
   1.192 +		"scope test couldn't be found": ErrScopeNotFound{ID: "test", Pos: 0},
   1.193 +		"scope test already exists":    ErrScopeAlreadyExists{ID: "test", Pos: 0},
   1.194 +	}
   1.195 +	for expectation, e := range errors {
   1.196 +		if e.Error() != expectation {
   1.197 +			t.Errorf("Expected %+v to produce '%s', produced '%s'", e, expectation, e.Error())
   1.198 +		}
   1.199 +	}
   1.200 +}