Skip to content
Snippets Groups Projects
Commit 8ddf1dd2 authored by Yordan Kinkov's avatar Yordan Kinkov
Browse files

#8 Accept HTTP header with cache TTL for policy result

parent 00470524
No related branches found
No related tags found
No related merge requests found
...@@ -29,6 +29,9 @@ var _ = Service("policy", func() { ...@@ -29,6 +29,9 @@ var _ = Service("policy", func() {
Header("evaluationID:x-evaluation-id", String, "EvaluationID allows overwriting the randomly generated evaluationID", func() { Header("evaluationID:x-evaluation-id", String, "EvaluationID allows overwriting the randomly generated evaluationID", func() {
Example("did:web:example.com") Example("did:web:example.com")
}) })
Header("ttl:x-cache-ttl", Int, "Policy result cache TTL in seconds", func() {
Example(60)
})
Body("input") Body("input")
Response(StatusOK, func() { Response(StatusOK, func() {
Body("result") Body("result")
......
...@@ -15,6 +15,7 @@ var EvaluateRequest = Type("EvaluateRequest", func() { ...@@ -15,6 +15,7 @@ var EvaluateRequest = Type("EvaluateRequest", func() {
}) })
Field(4, "input", Any, "Input data passed to the policy execution runtime.") Field(4, "input", Any, "Input data passed to the policy execution runtime.")
Field(5, "evaluationID", String, "Identifier created by external system and passed as parameter to overwrite the randomly generated evaluationID.") Field(5, "evaluationID", String, "Identifier created by external system and passed as parameter to overwrite the randomly generated evaluationID.")
Field(6, "ttl", Int, "TTL for storing policy result in cache")
Required("group", "policyName", "version") Required("group", "policyName", "version")
}) })
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"strconv"
"gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors" "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors"
) )
...@@ -29,7 +30,7 @@ func New(addr string, opts ...Option) *Client { ...@@ -29,7 +30,7 @@ func New(addr string, opts ...Option) *Client {
return c return c
} }
func (c *Client) Set(ctx context.Context, key, namespace, scope string, value []byte) error { func (c *Client) Set(ctx context.Context, key, namespace, scope string, value []byte, ttl int) error {
req, err := http.NewRequestWithContext(ctx, "POST", c.addr+"/v1/cache", bytes.NewReader(value)) req, err := http.NewRequestWithContext(ctx, "POST", c.addr+"/v1/cache", bytes.NewReader(value))
if err != nil { if err != nil {
return err return err
...@@ -40,6 +41,9 @@ func (c *Client) Set(ctx context.Context, key, namespace, scope string, value [] ...@@ -40,6 +41,9 @@ func (c *Client) Set(ctx context.Context, key, namespace, scope string, value []
"x-cache-namespace": []string{namespace}, "x-cache-namespace": []string{namespace},
"x-cache-scope": []string{scope}, "x-cache-scope": []string{scope},
} }
if ttl != 0 {
req.Header.Add("x-cache-ttl", strconv.Itoa(ttl))
}
resp, err := c.httpClient.Do(req) resp, err := c.httpClient.Do(req)
if err != nil { if err != nil {
......
...@@ -25,7 +25,7 @@ type FakeCache struct { ...@@ -25,7 +25,7 @@ type FakeCache struct {
result1 []byte result1 []byte
result2 error result2 error
} }
SetStub func(context.Context, string, string, string, []byte) error SetStub func(context.Context, string, string, string, []byte, int) error
setMutex sync.RWMutex setMutex sync.RWMutex
setArgsForCall []struct { setArgsForCall []struct {
arg1 context.Context arg1 context.Context
...@@ -33,6 +33,7 @@ type FakeCache struct { ...@@ -33,6 +33,7 @@ type FakeCache struct {
arg3 string arg3 string
arg4 string arg4 string
arg5 []byte arg5 []byte
arg6 int
} }
setReturns struct { setReturns struct {
result1 error result1 error
...@@ -111,7 +112,7 @@ func (fake *FakeCache) GetReturnsOnCall(i int, result1 []byte, result2 error) { ...@@ -111,7 +112,7 @@ func (fake *FakeCache) GetReturnsOnCall(i int, result1 []byte, result2 error) {
}{result1, result2} }{result1, result2}
} }
func (fake *FakeCache) Set(arg1 context.Context, arg2 string, arg3 string, arg4 string, arg5 []byte) error { func (fake *FakeCache) Set(arg1 context.Context, arg2 string, arg3 string, arg4 string, arg5 []byte, arg6 int) error {
var arg5Copy []byte var arg5Copy []byte
if arg5 != nil { if arg5 != nil {
arg5Copy = make([]byte, len(arg5)) arg5Copy = make([]byte, len(arg5))
...@@ -125,13 +126,14 @@ func (fake *FakeCache) Set(arg1 context.Context, arg2 string, arg3 string, arg4 ...@@ -125,13 +126,14 @@ func (fake *FakeCache) Set(arg1 context.Context, arg2 string, arg3 string, arg4
arg3 string arg3 string
arg4 string arg4 string
arg5 []byte arg5 []byte
}{arg1, arg2, arg3, arg4, arg5Copy}) arg6 int
}{arg1, arg2, arg3, arg4, arg5Copy, arg6})
stub := fake.SetStub stub := fake.SetStub
fakeReturns := fake.setReturns fakeReturns := fake.setReturns
fake.recordInvocation("Set", []interface{}{arg1, arg2, arg3, arg4, arg5Copy}) fake.recordInvocation("Set", []interface{}{arg1, arg2, arg3, arg4, arg5Copy, arg6})
fake.setMutex.Unlock() fake.setMutex.Unlock()
if stub != nil { if stub != nil {
return stub(arg1, arg2, arg3, arg4, arg5) return stub(arg1, arg2, arg3, arg4, arg5, arg6)
} }
if specificReturn { if specificReturn {
return ret.result1 return ret.result1
...@@ -145,17 +147,17 @@ func (fake *FakeCache) SetCallCount() int { ...@@ -145,17 +147,17 @@ func (fake *FakeCache) SetCallCount() int {
return len(fake.setArgsForCall) return len(fake.setArgsForCall)
} }
func (fake *FakeCache) SetCalls(stub func(context.Context, string, string, string, []byte) error) { func (fake *FakeCache) SetCalls(stub func(context.Context, string, string, string, []byte, int) error) {
fake.setMutex.Lock() fake.setMutex.Lock()
defer fake.setMutex.Unlock() defer fake.setMutex.Unlock()
fake.SetStub = stub fake.SetStub = stub
} }
func (fake *FakeCache) SetArgsForCall(i int) (context.Context, string, string, string, []byte) { func (fake *FakeCache) SetArgsForCall(i int) (context.Context, string, string, string, []byte, int) {
fake.setMutex.RLock() fake.setMutex.RLock()
defer fake.setMutex.RUnlock() defer fake.setMutex.RUnlock()
argsForCall := fake.setArgsForCall[i] argsForCall := fake.setArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5 return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5, argsForCall.arg6
} }
func (fake *FakeCache) SetReturns(result1 error) { func (fake *FakeCache) SetReturns(result1 error) {
......
...@@ -21,7 +21,7 @@ import ( ...@@ -21,7 +21,7 @@ import (
//go:generate counterfeiter . RegoCache //go:generate counterfeiter . RegoCache
type Cache interface { type Cache interface {
Set(ctx context.Context, key, namespace, scope string, value []byte) error Set(ctx context.Context, key, namespace, scope string, value []byte, ttl int) error
Get(ctx context.Context, key, namespace, scope string) ([]byte, error) Get(ctx context.Context, key, namespace, scope string) ([]byte, error)
} }
...@@ -116,7 +116,11 @@ func (s *Service) Evaluate(ctx context.Context, req *policy.EvaluateRequest) (*p ...@@ -116,7 +116,11 @@ func (s *Service) Evaluate(ctx context.Context, req *policy.EvaluateRequest) (*p
return nil, errors.New("error encoding result to json") return nil, errors.New("error encoding result to json")
} }
if err := s.cache.Set(ctx, evaluationID, "", "", jsonValue); err != nil { var ttl int
if req.TTL != nil {
ttl = *req.TTL
}
if err := s.cache.Set(ctx, evaluationID, "", "", jsonValue, ttl); err != nil {
logger.Error("error storing policy result in cache", zap.Error(err)) logger.Error("error storing policy result in cache", zap.Error(err))
return nil, errors.New("error storing policy result in cache") return nil, errors.New("error storing policy result in cache")
} }
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors" "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors"
"gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/ptr"
goapolicy "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/policy/gen/policy" goapolicy "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/policy/gen/policy"
"gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/policy/internal/service/policy" "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/policy/internal/service/policy"
"gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/policy/internal/service/policy/policyfakes" "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/policy/internal/service/policy/policyfakes"
...@@ -72,7 +73,7 @@ func TestService_Evaluate(t *testing.T) { ...@@ -72,7 +73,7 @@ func TestService_Evaluate(t *testing.T) {
}, },
}, },
cache: &policyfakes.FakeCache{ cache: &policyfakes.FakeCache{
SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte) error { SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte, i int) error {
return nil return nil
}, },
}, },
...@@ -152,7 +153,7 @@ func TestService_Evaluate(t *testing.T) { ...@@ -152,7 +153,7 @@ func TestService_Evaluate(t *testing.T) {
}, },
}, },
cache: &policyfakes.FakeCache{ cache: &policyfakes.FakeCache{
SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte) error { SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte, i int) error {
return nil return nil
}, },
}, },
...@@ -181,7 +182,7 @@ func TestService_Evaluate(t *testing.T) { ...@@ -181,7 +182,7 @@ func TestService_Evaluate(t *testing.T) {
}, },
}, },
cache: &policyfakes.FakeCache{ cache: &policyfakes.FakeCache{
SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte) error { SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte, i int) error {
return errors.New("some error") return errors.New("some error")
}, },
}, },
...@@ -209,7 +210,42 @@ func TestService_Evaluate(t *testing.T) { ...@@ -209,7 +210,42 @@ func TestService_Evaluate(t *testing.T) {
}, },
}, },
cache: &policyfakes.FakeCache{ cache: &policyfakes.FakeCache{
SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte) error { SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte, i int) error {
return nil
},
},
res: &goapolicy.EvaluateResult{
Result: map[string]interface{}{"hello": "world"},
},
},
{
name: "policy is evaluated successfully with TTL sent in the request headers",
req: &goapolicy.EvaluateRequest{
Group: "testgroup",
PolicyName: "example",
Version: "1.0",
Input: map[string]interface{}{"msg": "yes"},
TTL: ptr.Int(30),
},
regocache: &policyfakes.FakeRegoCache{
GetStub: func(key string) (*rego.PreparedEvalQuery, bool) {
return nil, false
},
},
storage: &policyfakes.FakeStorage{
PolicyStub: func(ctx context.Context, s string, s2 string, s3 string) (*storage.Policy, error) {
return &storage.Policy{
Name: "example",
Group: "testgroup",
Version: "1.0",
Rego: testPolicyBlankAssignment,
Locked: false,
LastUpdate: time.Now(),
}, nil
},
},
cache: &policyfakes.FakeCache{
SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte, i int) error {
return nil return nil
}, },
}, },
...@@ -239,7 +275,7 @@ func TestService_Evaluate(t *testing.T) { ...@@ -239,7 +275,7 @@ func TestService_Evaluate(t *testing.T) {
}, },
}, },
cache: &policyfakes.FakeCache{ cache: &policyfakes.FakeCache{
SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte) error { SetStub: func(ctx context.Context, s string, s2 string, s3 string, bytes []byte, i int) error {
return nil return nil
}, },
}, },
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment