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() {
Header("evaluationID:x-evaluation-id", String, "EvaluationID allows overwriting the randomly generated evaluationID", func() {
Example("did:web:example.com")
})
Header("ttl:x-cache-ttl", Int, "Policy result cache TTL in seconds", func() {
Example(60)
})
Body("input")
Response(StatusOK, func() {
Body("result")
......
......@@ -15,6 +15,7 @@ var EvaluateRequest = Type("EvaluateRequest", func() {
})
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(6, "ttl", Int, "TTL for storing policy result in cache")
Required("group", "policyName", "version")
})
......
......@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
"strconv"
"gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors"
)
......@@ -29,7 +30,7 @@ func New(addr string, opts ...Option) *Client {
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))
if err != nil {
return err
......@@ -40,6 +41,9 @@ func (c *Client) Set(ctx context.Context, key, namespace, scope string, value []
"x-cache-namespace": []string{namespace},
"x-cache-scope": []string{scope},
}
if ttl != 0 {
req.Header.Add("x-cache-ttl", strconv.Itoa(ttl))
}
resp, err := c.httpClient.Do(req)
if err != nil {
......
......@@ -25,7 +25,7 @@ type FakeCache struct {
result1 []byte
result2 error
}
SetStub func(context.Context, string, string, string, []byte) error
SetStub func(context.Context, string, string, string, []byte, int) error
setMutex sync.RWMutex
setArgsForCall []struct {
arg1 context.Context
......@@ -33,6 +33,7 @@ type FakeCache struct {
arg3 string
arg4 string
arg5 []byte
arg6 int
}
setReturns struct {
result1 error
......@@ -111,7 +112,7 @@ func (fake *FakeCache) GetReturnsOnCall(i int, result1 []byte, result2 error) {
}{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
if arg5 != nil {
arg5Copy = make([]byte, len(arg5))
......@@ -125,13 +126,14 @@ func (fake *FakeCache) Set(arg1 context.Context, arg2 string, arg3 string, arg4
arg3 string
arg4 string
arg5 []byte
}{arg1, arg2, arg3, arg4, arg5Copy})
arg6 int
}{arg1, arg2, arg3, arg4, arg5Copy, arg6})
stub := fake.SetStub
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()
if stub != nil {
return stub(arg1, arg2, arg3, arg4, arg5)
return stub(arg1, arg2, arg3, arg4, arg5, arg6)
}
if specificReturn {
return ret.result1
......@@ -145,17 +147,17 @@ func (fake *FakeCache) SetCallCount() int {
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()
defer fake.setMutex.Unlock()
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()
defer fake.setMutex.RUnlock()
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) {
......
......@@ -21,7 +21,7 @@ import (
//go:generate counterfeiter . RegoCache
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)
}
......@@ -116,7 +116,11 @@ func (s *Service) Evaluate(ctx context.Context, req *policy.EvaluateRequest) (*p
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))
return nil, errors.New("error storing policy result in cache")
}
......
......@@ -10,6 +10,7 @@ import (
"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/ptr"
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/policyfakes"
......@@ -72,7 +73,7 @@ func TestService_Evaluate(t *testing.T) {
},
},
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
},
},
......@@ -152,7 +153,7 @@ func TestService_Evaluate(t *testing.T) {
},
},
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
},
},
......@@ -181,7 +182,7 @@ func TestService_Evaluate(t *testing.T) {
},
},
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")
},
},
......@@ -209,7 +210,42 @@ func TestService_Evaluate(t *testing.T) {
},
},
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
},
},
......@@ -239,7 +275,7 @@ func TestService_Evaluate(t *testing.T) {
},
},
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
},
},
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment