diff --git a/go.mod b/go.mod index a2c2f51..548f718 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Interhyp/metadata-service -go 1.21 +go 1.21.4 // exclude actually unused dependencies (mostly of pact-go, which is testing only anyway) // because our scanner fails to understand they are not in use @@ -80,6 +80,8 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/Roshick/go-autumn-kafka v0.3.1 // indirect + github.com/Roshick/go-autumn-synchronisation v0.2.0 // indirect github.com/StephanHCB/go-autumn-acorn-registry v0.3.1 // indirect github.com/StephanHCB/go-autumn-web-swagger-ui v0.2.3 // indirect github.com/acomagu/bufpipe v1.0.4 // indirect @@ -90,6 +92,7 @@ require ( github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/elastic/go-sysinfo v1.7.1 // indirect github.com/elastic/go-windows v1.0.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect @@ -116,6 +119,7 @@ require ( github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect + github.com/redis/go-redis/v9 v9.3.0 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect @@ -129,10 +133,10 @@ require ( go.elastic.co/apm/module/apmhttp/v2 v2.4.5 // indirect go.elastic.co/apm/v2 v2.4.5 // indirect go.elastic.co/fastjson v1.1.0 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.15.0 // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/net v0.18.0 // indirect + golang.org/x/sys v0.14.0 // indirect golang.org/x/tools v0.13.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 1d44c67..85215cd 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,10 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/Roshick/go-autumn-kafka v0.3.1 h1:wnIxUEM/2nzjUsjonrF19sYuBiBYl7L6SnuRegMwZtU= +github.com/Roshick/go-autumn-kafka v0.3.1/go.mod h1:D0MfJsHTD+2qgebdnu2BFG5BKrWrLpz20kEAQMz6g28= +github.com/Roshick/go-autumn-synchronisation v0.2.0 h1:K+uKM33SWWrBaJcCbVQ3kySmcHacXOPdTbJsaXDkoZ4= +github.com/Roshick/go-autumn-synchronisation v0.2.0/go.mod h1:Escd6Ri5m/ppyFilE2C9DcVB3A6EzqO7JOFz8p8WThQ= github.com/StephanHCB/go-autumn-acorn-registry v0.3.1 h1:rAJlEsrSTJArQZHOt4Q6Gkc4NgL2ObSQGvxW0chiRiM= github.com/StephanHCB/go-autumn-acorn-registry v0.3.1/go.mod h1:KB7wPWOEy2n8VGNw75H4w7wBSWSrgwNNJNmet/F+9RI= github.com/StephanHCB/go-autumn-config-api v0.2.1 h1:t2EeTsdFpLM2xH2T7QFQtbFYI8hG5I9S+Q2o3KT6mlk= @@ -53,6 +57,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/elastic/go-sysinfo v1.7.1 h1:Wx4DSARcKLllpKT2TnFVdSUJOsybqMYCNQZq1/wO+s0= github.com/elastic/go-sysinfo v1.7.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= @@ -151,6 +157,8 @@ github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/redis/go-redis/v9 v9.3.0 h1:RiVDjmig62jIWp7Kk4XVLs0hzV6pI3PyTnnL0cnn0u0= +github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= @@ -210,6 +218,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -222,6 +232,8 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -251,6 +263,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -259,6 +273,7 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -268,6 +283,7 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= diff --git a/internal/acorn/service/cacheint.go b/internal/acorn/service/cacheint.go index 9d06220..4d59991 100644 --- a/internal/acorn/service/cacheint.go +++ b/internal/acorn/service/cacheint.go @@ -14,15 +14,15 @@ type Cache interface { // --- owner cache --- // SetOwnerListTimestamp lets you set or update the timestamp for the last full scan of the list of aliases. - SetOwnerListTimestamp(ctx context.Context, timestamp string) + SetOwnerListTimestamp(ctx context.Context, timestamp string) error // GetOwnerListTimestamp gives you the timestamp of the last full scan of the list of aliases. - GetOwnerListTimestamp(ctx context.Context) string + GetOwnerListTimestamp(ctx context.Context) (string, error) // GetSortedOwnerAliases gives you a time snapshot copy of the slice of sorted owner names. // // This means you won't mess up the cache if you work with it in any way. - GetSortedOwnerAliases(ctx context.Context) []string + GetSortedOwnerAliases(ctx context.Context) ([]string, error) // GetOwner gives you a time snapshot deep copy of the owner information. // @@ -34,25 +34,25 @@ type Cache interface { // PutOwner creates or replaces the owner cache entry. // // This is an atomic operation. - PutOwner(ctx context.Context, alias string, entry openapi.OwnerDto) + PutOwner(ctx context.Context, alias string, entry openapi.OwnerDto) error // DeleteOwner deletes the owner cache entry. // // This is an atomic operation. - DeleteOwner(ctx context.Context, alias string) + DeleteOwner(ctx context.Context, alias string) error // --- service cache --- // SetServiceListTimestamp lets you set or update the timestamp for the last full scan of the list of names. - SetServiceListTimestamp(ctx context.Context, timestamp string) + SetServiceListTimestamp(ctx context.Context, timestamp string) error // GetServiceListTimestamp gives you the timestamp of the last full scan of the list of names. - GetServiceListTimestamp(ctx context.Context) string + GetServiceListTimestamp(ctx context.Context) (string, error) // GetSortedServiceNames gives you a time snapshot copy of the slice of sorted service names. // // This means you won't mess up the cache if you work with it in any way. - GetSortedServiceNames(ctx context.Context) []string + GetSortedServiceNames(ctx context.Context) ([]string, error) // GetService gives you a time snapshot deep copy of the service information. // @@ -64,25 +64,25 @@ type Cache interface { // PutService creates or replaces the service cache entry. // // This is an atomic operation. - PutService(ctx context.Context, name string, entry openapi.ServiceDto) + PutService(ctx context.Context, name string, entry openapi.ServiceDto) error // DeleteService deletes the service cache entry. // // This is an atomic operation. - DeleteService(ctx context.Context, name string) + DeleteService(ctx context.Context, name string) error // --- repository cache --- // SetRepositoryListTimestamp lets you set or update the timestamp for the last full scan of the list of keys. - SetRepositoryListTimestamp(ctx context.Context, timestamp string) + SetRepositoryListTimestamp(ctx context.Context, timestamp string) error // GetRepositoryListTimestamp gives you the timestamp of the last full scan of the list of keys. - GetRepositoryListTimestamp(ctx context.Context) string + GetRepositoryListTimestamp(ctx context.Context) (string, error) // GetSortedRepositoryKeys gives you a time snapshot copy of the slice of sorted repository names. // // This means you won't mess up the cache if you work with it in any way. - GetSortedRepositoryKeys(ctx context.Context) []string + GetSortedRepositoryKeys(ctx context.Context) ([]string, error) // GetRepository gives you a time snapshot deep copy of the repository information. // @@ -94,10 +94,10 @@ type Cache interface { // PutRepository creates or replaces the repository cache entry. // // This is an atomic operation. - PutRepository(ctx context.Context, key string, entry openapi.RepositoryDto) + PutRepository(ctx context.Context, key string, entry openapi.RepositoryDto) error // DeleteRepository deletes the repository cache entry. // // This is an atomic operation. - DeleteRepository(ctx context.Context, key string) + DeleteRepository(ctx context.Context, key string) error } diff --git a/internal/acorn/service/updaterint.go b/internal/acorn/service/updaterint.go index 50be7cd..bece532 100644 --- a/internal/acorn/service/updaterint.go +++ b/internal/acorn/service/updaterint.go @@ -87,5 +87,5 @@ type Updater interface { // CanMoveOrDeleteRepository checks that no service still references the repository key. // // Expects a current cache and you must be holding the lock. - CanMoveOrDeleteRepository(ctx context.Context, key string) bool + CanMoveOrDeleteRepository(ctx context.Context, key string) (bool, error) } diff --git a/internal/service/cache/cache.go b/internal/service/cache/cache.go index f0bea90..064aee9 100644 --- a/internal/service/cache/cache.go +++ b/internal/service/cache/cache.go @@ -2,20 +2,25 @@ package cache import ( "context" + openapi "github.com/Interhyp/metadata-service/api" "github.com/Interhyp/metadata-service/internal/acorn/service" - "github.com/Interhyp/metadata-service/internal/service/cache/cacheable" + libcache "github.com/Roshick/go-autumn-synchronisation/pkg/aucache" auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" + "time" ) +var cacheRetention = 30 * 24 * time.Hour + type Impl struct { Configuration librepo.Configuration Logging librepo.Logging Timestamp librepo.Timestamp - OwnerCache cacheable.Cacheable - ServiceCache cacheable.Cacheable - RepositoryCache cacheable.Cacheable + OwnerCache libcache.Cache[openapi.OwnerDto] + ServiceCache libcache.Cache[openapi.ServiceDto] + RepositoryCache libcache.Cache[openapi.RepositoryDto] + TimestampCache libcache.Cache[string] } func New( @@ -47,15 +52,20 @@ func (s *Impl) Setup() error { } func (s *Impl) SetupCache(_ context.Context) error { + // TODO create redis instances based on configuration + // idempotent to allow mocking if s.OwnerCache == nil { - s.OwnerCache = cacheable.New() + s.OwnerCache = libcache.NewMemoryCache[openapi.OwnerDto]() } if s.ServiceCache == nil { - s.ServiceCache = cacheable.New() + s.ServiceCache = libcache.NewMemoryCache[openapi.ServiceDto]() } if s.RepositoryCache == nil { - s.RepositoryCache = cacheable.New() + s.RepositoryCache = libcache.NewMemoryCache[openapi.RepositoryDto]() + } + if s.TimestampCache == nil { + s.TimestampCache = libcache.NewMemoryCache[string]() } return nil } diff --git a/internal/service/cache/cacheable/cacheable.go b/internal/service/cache/cacheable/cacheable.go deleted file mode 100644 index aa4f975..0000000 --- a/internal/service/cache/cacheable/cacheable.go +++ /dev/null @@ -1,82 +0,0 @@ -package cacheable - -import ( - "sort" - "sync" -) - -type Impl struct { - mu sync.Mutex - - timestamp string - sortedKeysCache *[]string - values map[string]*interface{} -} - -func New() Cacheable { - c := &Impl{ - values: make(map[string]*interface{}), - } - // during initial creation we don't need to lock - c.buildKeysCacheMustHaveLock() - return c -} - -func (c *Impl) buildKeysCacheMustHaveLock() { - keys := make([]string, 0, len(c.values)) - for k := range c.values { - keys = append(keys, k) - } - sort.Strings(keys) - - c.sortedKeysCache = &keys -} - -func (c *Impl) GetTimestamp() string { - return c.timestamp -} - -func (c *Impl) SetTimestamp(timestamp string) { - c.timestamp = timestamp -} - -func (c *Impl) GetSortedKeys() *[]string { - c.mu.Lock() - defer c.mu.Unlock() - return c.sortedKeysCache -} - -func (c *Impl) GetEntryRef(key string) *interface{} { - c.mu.Lock() - defer c.mu.Unlock() - ref, ok := c.values[key] - if ok { - return ref - } else { - // this is actually the same as the ok branch, because the zero value of a pointer is nil, - // but writing it down for clarity's sake - return nil - } -} - -func (c *Impl) UpdateEntryRef(key string, newRef *interface{}) { - c.mu.Lock() - defer c.mu.Unlock() - _, ok := c.values[key] - if ok { - if newRef != nil { - // update existing - c.values[key] = newRef - } else { - // delete - delete(c.values, key) - c.buildKeysCacheMustHaveLock() - } - } else { - if newRef != nil { - // insert new - c.values[key] = newRef - c.buildKeysCacheMustHaveLock() - } - } -} diff --git a/internal/service/cache/cacheable/cacheableint.go b/internal/service/cache/cacheable/cacheableint.go deleted file mode 100644 index 7cbea1c..0000000 --- a/internal/service/cache/cacheable/cacheableint.go +++ /dev/null @@ -1,20 +0,0 @@ -package cacheable - -// Cacheable implements a synchronized in-memory cache for references to arbitrary data structures -// -// Update the timestamp whenever you do a full rescan. -type Cacheable interface { - GetTimestamp() string - SetTimestamp(timestamp string) - - GetSortedKeys() *[]string - - // GetEntryRef obtains the reference to the current entry, or nil if the key isn't present. - GetEntryRef(key string) *interface{} - - // UpdateEntryRef will create the key if it doesn't exist - // if newRef is nil, will remove the key if present - // - // key changes lead to re-creating the sorted keys cache - UpdateEntryRef(key string, newRef *interface{}) -} diff --git a/internal/service/cache/deepcopy.go b/internal/service/cache/deepcopy.go deleted file mode 100644 index 66e60e9..0000000 --- a/internal/service/cache/deepcopy.go +++ /dev/null @@ -1,27 +0,0 @@ -package cache - -import ( - "encoding/json" -) - -// deepCopyStruct creates a copy of a struct by serializing and deserializing to JSON. -// Beware: Unexported fields are not copied. -func deepCopyStruct[T any](source T, targetPointer *T) error { - jsonBytes, err := json.Marshal(source) - if err != nil { - return err - } - err = json.Unmarshal(jsonBytes, targetPointer) - return err -} - -func deepCopyStringSlice(original []string) []string { - // the slice pointers returned by Cacheable already are a snapshot in time because - // the Cacheable switches the pointer and doesn't ever change existing values - - // now prevent users from inadvertently updating the slice from the outside by making a copy of its values - result := make([]string, len(original)) - // for strings, which are immutable in go, this _is_ a deep copy - copy(result, original) - return result -} diff --git a/internal/service/cache/deepcopy_test.go b/internal/service/cache/deepcopy_test.go deleted file mode 100644 index 957f569..0000000 --- a/internal/service/cache/deepcopy_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package cache - -import ( - "github.com/stretchr/testify/require" - "testing" -) - -func TestDeepCopyStringSlice(t *testing.T) { - input := []string{"first", "WORLD", "problems"} - copyResult := deepCopyStringSlice(input) - require.Equal(t, input, copyResult, "Deep copied slices do not contain same elements.") - // Compare addresses of first slice elements to determine reference equality. - // We may not use require.NotEqual as it compares pointer values and not addresses. - // See https://stackoverflow.com/a/53010178 - require.False(t, &input[0] == ©Result[0], "Deep copied slices are identical.") -} - -func TestDeepCopyStruct(t *testing.T) { - type deepCopyTestStruct struct { - SomeString string - SomeInt int - SomeBool bool - SomeSlice []string - SomeMap map[string]string - SomePointer *string - SomeNilPointer *string - somePrivateField string - SomeInBetweenStruct struct { - SomeInBetweenString string - SomeInnerStruct struct { - SomeInnerString string - } - } - } - - mapField := make(map[string]string) - mapField["key"] = "value" - pointerValue := "pointer" - input := deepCopyTestStruct{ - SomeString: "SomeString", - SomeInt: 51324, - SomeBool: true, - SomeSlice: []string{"first", "second"}, - SomeMap: mapField, - SomePointer: &pointerValue, - SomeNilPointer: nil, - somePrivateField: "private", - SomeInBetweenStruct: struct { - SomeInBetweenString string - SomeInnerStruct struct { - SomeInnerString string - } - }{ - SomeInBetweenString: "inBetweenString", - SomeInnerStruct: struct { - SomeInnerString string - }{ - SomeInnerString: "innerString", - }, - }, - } - - result := deepCopyTestStruct{} - err := deepCopyStruct(input, &result) - - require.Nil(t, err) - require.Empty(t, result.somePrivateField) - require.EqualExportedValues(t, input, result) - require.False(t, &input == &result, "Structs are equal by reference.") -} - -func TestDeepCopyStruct_MarshalErrorIsReturned(t *testing.T) { - type errorStruct struct{ SomeFunction func(int) int } - input := errorStruct{ - SomeFunction: func(i int) int { - return i - }, - } - result := errorStruct{} - err := deepCopyStruct(input, &result) - require.ErrorContains(t, err, "unsupported type") -} - -func TestDeepCopyStruct_UnmarshalErrorIsReturned(t *testing.T) { - type someStruct struct{ SomeString string } - input := someStruct{ - SomeString: "someString", - } - err := deepCopyStruct(input, nil) - require.ErrorContains(t, err, "json: Unmarshal(nil") -} diff --git a/internal/service/cache/lowlevel.go b/internal/service/cache/lowlevel.go new file mode 100644 index 0000000..abdca74 --- /dev/null +++ b/internal/service/cache/lowlevel.go @@ -0,0 +1,96 @@ +package cache + +import ( + "context" + "fmt" + libcache "github.com/Roshick/go-autumn-synchronisation/pkg/aucache" + "github.com/StephanHCB/go-backend-service-common/api/apierrors" + "sort" +) + +const ( + ownerTimestampKey = "ownertimestamp" + serviceTimestampKey = "servicetimestamp" + repositoryTimestampKey = "repositorytimestamp" +) + +var notFoundTimestamp = "1970-01-01T00:00:00Z" + +func (s *Impl) setTimestamp(ctx context.Context, what string, key string, timestamp string) error { + err := s.TimestampCache.Set(ctx, key, timestamp, cacheRetention) + if err != nil { + messageKey := fmt.Sprintf("cache.%s.error", what) + details := fmt.Sprintf("error writing %s timestamp to cache", what) + s.Logging.Logger().Ctx(ctx).Info().WithErr(err).Printf("%s: %s", details, err.Error()) + return apierrors.NewBadGatewayError(messageKey, details, err, s.Timestamp.Now()) + } + return nil +} + +func (s *Impl) getTimestamp(ctx context.Context, what string, key string) (string, error) { + valPtr, err := s.TimestampCache.Get(ctx, key) + if err != nil { + messageKey := fmt.Sprintf("cache.%s.error", what) + details := fmt.Sprintf("error reading %s timestamp from cache", what) + s.Logging.Logger().Ctx(ctx).Info().Printf("%s: %s", details, err.Error()) + return notFoundTimestamp, apierrors.NewBadGatewayError(messageKey, details, err, s.Timestamp.Now()) + } + if valPtr == nil { + return notFoundTimestamp, err + } + return *valPtr, nil +} + +func getSortedKeys[E any](ctx context.Context, what string, s *Impl, cache libcache.Cache[E]) ([]string, error) { + keys, err := cache.Keys(ctx) + if err != nil { + messageKey := fmt.Sprintf("cache.%s.error", what) + details := fmt.Sprintf("error reading %s keys from cache", what) + s.Logging.Logger().Ctx(ctx).Warn().WithErr(err).Printf("%s: %s", details, err.Error()) + return []string{}, apierrors.NewBadGatewayError(messageKey, details, err, s.Timestamp.Now()) + } + sort.Strings(keys) + return keys, nil +} + +func getEntry[E any](ctx context.Context, what string, s *Impl, cache libcache.Cache[E], key string) (E, error) { + copiedEntryPtr, err := cache.Get(ctx, key) + if err != nil { + var empty E + messageKey := fmt.Sprintf("cache.%s.error", what) + details := fmt.Sprintf("error reading %s %s from cache", what, key) + s.Logging.Logger().Ctx(ctx).Warn().WithErr(err).Printf("%s: %s", details, err.Error()) + return empty, apierrors.NewBadGatewayError(messageKey, details, err, s.Timestamp.Now()) + } + if copiedEntryPtr == nil { + var empty E + messageKey := fmt.Sprintf("%s.notfound", what) + details := fmt.Sprintf("%s %s not found", what, key) + s.Logging.Logger().Ctx(ctx).Info().Print(details) + return empty, apierrors.NewNotFoundError(messageKey, details, nil, s.Timestamp.Now()) + } else { + return *copiedEntryPtr, nil + } +} + +func putEntry[E any](ctx context.Context, what string, s *Impl, cache libcache.Cache[E], key string, entry E) error { + err := cache.Set(ctx, key, entry, cacheRetention) + if err != nil { + messageKey := fmt.Sprintf("cache.%s.error", what) + details := fmt.Sprintf("error writing %s %s to cache", what, key) + s.Logging.Logger().Ctx(ctx).Warn().WithErr(err).Printf("%s: %s", details, err.Error()) + return apierrors.NewBadGatewayError(messageKey, details, err, s.Timestamp.Now()) + } + return nil +} + +func removeEntry[E any](ctx context.Context, what string, s *Impl, cache libcache.Cache[E], key string) error { + err := cache.Remove(ctx, key) + if err != nil { + messageKey := fmt.Sprintf("cache.%s.error", what) + details := fmt.Sprintf("error removing %s %s from cache", what, key) + s.Logging.Logger().Ctx(ctx).Warn().WithErr(err).Printf("%s: %s", details, err.Error()) + return apierrors.NewBadGatewayError(messageKey, details, err, s.Timestamp.Now()) + } + return nil +} diff --git a/internal/service/cache/ownercache.go b/internal/service/cache/ownercache.go index d5992e1..58d6c14 100644 --- a/internal/service/cache/ownercache.go +++ b/internal/service/cache/ownercache.go @@ -2,48 +2,31 @@ package cache import ( "context" - "fmt" "github.com/Interhyp/metadata-service/api" - "github.com/StephanHCB/go-backend-service-common/api/apierrors" ) -func (s *Impl) SetOwnerListTimestamp(_ context.Context, timestamp string) { - s.OwnerCache.SetTimestamp(timestamp) +const ownerWhat = "owner" + +func (s *Impl) SetOwnerListTimestamp(ctx context.Context, timestamp string) error { + return s.setTimestamp(ctx, ownerWhat, ownerTimestampKey, timestamp) } -func (s *Impl) GetOwnerListTimestamp(_ context.Context) string { - return s.OwnerCache.GetTimestamp() +func (s *Impl) GetOwnerListTimestamp(ctx context.Context) (string, error) { + return s.getTimestamp(ctx, ownerWhat, ownerTimestampKey) } -func (s *Impl) GetSortedOwnerAliases(_ context.Context) []string { - keysPtr := s.OwnerCache.GetSortedKeys() - return deepCopyStringSlice(*keysPtr) +func (s *Impl) GetSortedOwnerAliases(ctx context.Context) ([]string, error) { + return getSortedKeys(ctx, ownerWhat, s, s.OwnerCache) } func (s *Impl) GetOwner(ctx context.Context, alias string) (openapi.OwnerDto, error) { - immutableOwnerPtr := s.OwnerCache.GetEntryRef(alias) - if immutableOwnerPtr == nil { - s.Logging.Logger().Ctx(ctx).Info().Printf("owner %v not found", alias) - return openapi.OwnerDto{}, apierrors.NewNotFoundError("owner.notfound", fmt.Sprintf("owner %s not found", alias), nil, s.Timestamp.Now()) - } else { - ownerCopy := openapi.OwnerDto{} - owner := (*immutableOwnerPtr).(openapi.OwnerDto) - err := deepCopyStruct(owner, &ownerCopy) - return ownerCopy, err - } + return getEntry(ctx, ownerWhat, s, s.OwnerCache, alias) } -func (s *Impl) PutOwner(_ context.Context, alias string, entry openapi.OwnerDto) { - var e interface{} - e = entry - - s.OwnerCache.UpdateEntryRef(alias, &e) +func (s *Impl) PutOwner(ctx context.Context, alias string, entry openapi.OwnerDto) error { + return putEntry(ctx, ownerWhat, s, s.OwnerCache, alias, entry) } -func (s *Impl) DeleteOwner(_ context.Context, alias string) { - s.OwnerCache.UpdateEntryRef(alias, nil) - // TODO since this may come in from reading a manually made git commit, in this lowlevel cache we cascade - // - // s.scDeleteOwner(alias) - // s.rcDeleteOwner(alias) +func (s *Impl) DeleteOwner(ctx context.Context, alias string) error { + return removeEntry(ctx, ownerWhat, s, s.OwnerCache, alias) } diff --git a/internal/service/cache/repositorycache.go b/internal/service/cache/repositorycache.go index bcc6373..1819745 100644 --- a/internal/service/cache/repositorycache.go +++ b/internal/service/cache/repositorycache.go @@ -2,44 +2,31 @@ package cache import ( "context" - "fmt" "github.com/Interhyp/metadata-service/api" - "github.com/StephanHCB/go-backend-service-common/api/apierrors" ) -func (s *Impl) SetRepositoryListTimestamp(_ context.Context, timestamp string) { - s.RepositoryCache.SetTimestamp(timestamp) +const repositoryWhat = "repository" + +func (s *Impl) SetRepositoryListTimestamp(ctx context.Context, timestamp string) error { + return s.setTimestamp(ctx, repositoryWhat, repositoryTimestampKey, timestamp) } -func (s *Impl) GetRepositoryListTimestamp(_ context.Context) string { - return s.RepositoryCache.GetTimestamp() +func (s *Impl) GetRepositoryListTimestamp(ctx context.Context) (string, error) { + return s.getTimestamp(ctx, repositoryWhat, repositoryTimestampKey) } -func (s *Impl) GetSortedRepositoryKeys(_ context.Context) []string { - keysPtr := s.RepositoryCache.GetSortedKeys() - return deepCopyStringSlice(*keysPtr) +func (s *Impl) GetSortedRepositoryKeys(ctx context.Context) ([]string, error) { + return getSortedKeys(ctx, repositoryWhat, s, s.RepositoryCache) } func (s *Impl) GetRepository(ctx context.Context, key string) (openapi.RepositoryDto, error) { - immutableRepositoryPtr := s.RepositoryCache.GetEntryRef(key) - if immutableRepositoryPtr == nil { - s.Logging.Logger().Ctx(ctx).Info().Printf("repository %v not found", key) - return openapi.RepositoryDto{}, apierrors.NewNotFoundError("repository.notfound", fmt.Sprintf("repository %s not found", key), nil, s.Timestamp.Now()) - } else { - repoCopy := openapi.RepositoryDto{} - repo := (*immutableRepositoryPtr).(openapi.RepositoryDto) - err := deepCopyStruct(repo, &repoCopy) - return repoCopy, err - } + return getEntry(ctx, repositoryWhat, s, s.RepositoryCache, key) } -func (s *Impl) PutRepository(_ context.Context, key string, entry openapi.RepositoryDto) { - var e interface{} - e = entry - - s.RepositoryCache.UpdateEntryRef(key, &e) +func (s *Impl) PutRepository(ctx context.Context, key string, entry openapi.RepositoryDto) error { + return putEntry(ctx, repositoryWhat, s, s.RepositoryCache, key, entry) } -func (s *Impl) DeleteRepository(_ context.Context, key string) { - s.RepositoryCache.UpdateEntryRef(key, nil) +func (s *Impl) DeleteRepository(ctx context.Context, key string) error { + return removeEntry(ctx, repositoryWhat, s, s.RepositoryCache, key) } diff --git a/internal/service/cache/servicecache.go b/internal/service/cache/servicecache.go index 23ead4d..0ba35fa 100644 --- a/internal/service/cache/servicecache.go +++ b/internal/service/cache/servicecache.go @@ -2,43 +2,31 @@ package cache import ( "context" - "fmt" "github.com/Interhyp/metadata-service/api" - "github.com/StephanHCB/go-backend-service-common/api/apierrors" ) -func (s *Impl) SetServiceListTimestamp(_ context.Context, timestamp string) { - s.ServiceCache.SetTimestamp(timestamp) +const serviceWhat = "service" + +func (s *Impl) SetServiceListTimestamp(ctx context.Context, timestamp string) error { + return s.setTimestamp(ctx, serviceWhat, serviceTimestampKey, timestamp) } -func (s *Impl) GetServiceListTimestamp(_ context.Context) string { - return s.ServiceCache.GetTimestamp() +func (s *Impl) GetServiceListTimestamp(ctx context.Context) (string, error) { + return s.getTimestamp(ctx, serviceWhat, serviceTimestampKey) } -func (s *Impl) GetSortedServiceNames(_ context.Context) []string { - keysPtr := s.ServiceCache.GetSortedKeys() - return deepCopyStringSlice(*keysPtr) +func (s *Impl) GetSortedServiceNames(ctx context.Context) ([]string, error) { + return getSortedKeys(ctx, serviceWhat, s, s.ServiceCache) } func (s *Impl) GetService(ctx context.Context, name string) (openapi.ServiceDto, error) { - immutableServicePtr := s.ServiceCache.GetEntryRef(name) - if immutableServicePtr == nil { - return openapi.ServiceDto{}, apierrors.NewNotFoundError("service.notfound", fmt.Sprintf("service %s not found", name), nil, s.Timestamp.Now()) - } else { - serviceCopy := openapi.ServiceDto{} - service := (*immutableServicePtr).(openapi.ServiceDto) - err := deepCopyStruct(service, &serviceCopy) - return serviceCopy, err - } + return getEntry(ctx, serviceWhat, s, s.ServiceCache, name) } -func (s *Impl) PutService(_ context.Context, name string, entry openapi.ServiceDto) { - var e interface{} - e = entry - - s.ServiceCache.UpdateEntryRef(name, &e) +func (s *Impl) PutService(ctx context.Context, name string, entry openapi.ServiceDto) error { + return putEntry(ctx, serviceWhat, s, s.ServiceCache, name, entry) } -func (s *Impl) DeleteService(_ context.Context, name string) { - s.ServiceCache.UpdateEntryRef(name, nil) +func (s *Impl) DeleteService(ctx context.Context, name string) error { + return removeEntry(ctx, serviceWhat, s, s.ServiceCache, name) } diff --git a/internal/service/owners/owners.go b/internal/service/owners/owners.go index 4531365..4ccf84d 100644 --- a/internal/service/owners/owners.go +++ b/internal/service/owners/owners.go @@ -51,10 +51,20 @@ func (s *Impl) Setup() error { func (s *Impl) GetOwners(ctx context.Context) (openapi.OwnerListDto, error) { result := openapi.OwnerListDto{ - Owners: make(map[string]openapi.OwnerDto), - TimeStamp: s.Cache.GetOwnerListTimestamp(ctx), + Owners: make(map[string]openapi.OwnerDto), } - for _, name := range s.Cache.GetSortedOwnerAliases(ctx) { + + stamp, err := s.Cache.GetOwnerListTimestamp(ctx) + if err != nil { + return result, err + } + result.TimeStamp = stamp + + names, err := s.Cache.GetSortedOwnerAliases(ctx) + if err != nil { + return result, err + } + for _, name := range names { owner, err := s.GetOwner(ctx, name) if err != nil { // owner not found errors are ok, the cache may have been changed concurrently, just drop the entry diff --git a/internal/service/repositories/repositories.go b/internal/service/repositories/repositories.go index b9cca73..2fb455e 100644 --- a/internal/service/repositories/repositories.go +++ b/internal/service/repositories/repositories.go @@ -94,9 +94,14 @@ func (s *Impl) GetRepositories(ctx context.Context, ) (openapi.RepositoryListDto, error) { result := openapi.RepositoryListDto{ Repositories: make(map[string]openapi.RepositoryDto), - TimeStamp: s.Cache.GetRepositoryListTimestamp(ctx), } + stamp, err := s.Cache.GetRepositoryListTimestamp(ctx) + if err != nil { + return result, err + } + result.TimeStamp = stamp + useReferencedRepositoriesMap := false referencedRepositoriesMap := make(map[string]bool, 0) if serviceNameFilter != "" { @@ -110,7 +115,11 @@ func (s *Impl) GetRepositories(ctx context.Context, } } - for _, key := range s.Cache.GetSortedRepositoryKeys(ctx) { + keys, err := s.Cache.GetSortedRepositoryKeys(ctx) + if err != nil { + return openapi.RepositoryListDto{}, err + } + for _, key := range keys { if !useReferencedRepositoriesMap || referencedRepositoriesMap[key] { repository, err := s.GetRepository(ctx, key) if err != nil { @@ -583,7 +592,10 @@ func (s *Impl) DeleteRepository(ctx context.Context, key string, deletionInfo op return err } - allowed := s.Updater.CanMoveOrDeleteRepository(subCtx, key) + allowed, err := s.Updater.CanMoveOrDeleteRepository(subCtx, key) + if err != nil { + return err + } if !allowed { s.Logging.Logger().Ctx(ctx).Info().Printf("tried to delete repository %v, which is still referenced by its service", key) return apierrors.NewConflictError("repository.conflict.referenced", "this repository is still being referenced by a service and cannot be deleted", nil, s.Timestamp.Now()) diff --git a/internal/service/services/services.go b/internal/service/services/services.go index bb85e3d..b423ada 100644 --- a/internal/service/services/services.go +++ b/internal/service/services/services.go @@ -61,11 +61,19 @@ func (s *Impl) Setup() error { var initialServiceLifecycle = "experimental" func (s *Impl) GetServices(ctx context.Context, ownerAliasFilter string) (openapi.ServiceListDto, error) { + stamp, err := s.Cache.GetServiceListTimestamp(ctx) + if err != nil { + return openapi.ServiceListDto{}, err + } result := openapi.ServiceListDto{ Services: make(map[string]openapi.ServiceDto), - TimeStamp: s.Cache.GetServiceListTimestamp(ctx), + TimeStamp: stamp, + } + names, err := s.Cache.GetSortedServiceNames(ctx) + if err != nil { + return openapi.ServiceListDto{}, err } - for _, name := range s.Cache.GetSortedServiceNames(ctx) { + for _, name := range names { theService, err := s.GetService(ctx, name) if err != nil { // service not found errors are ok, the cache may have been changed concurrently, just drop the entry @@ -477,7 +485,11 @@ func (s *Impl) validateDeletionDto(ctx context.Context, deletionInfo openapi.Del } func (s *Impl) addAllProductOwners(ctx context.Context, resultSet map[string]bool) error { - for _, alias := range s.Cache.GetSortedOwnerAliases(ctx) { + names, err := s.Cache.GetSortedOwnerAliases(ctx) + if err != nil { + return err + } + for _, alias := range names { owner, err := s.Cache.GetOwner(ctx, alias) if err != nil { // owner not found errors are ok, the cache may have been changed concurrently, just drop the entry diff --git a/internal/service/updater/owners.go b/internal/service/updater/owners.go index 98ab2ce..db9dbaa 100644 --- a/internal/service/updater/owners.go +++ b/internal/service/updater/owners.go @@ -106,7 +106,10 @@ func (s *Impl) updateOwners(ctx context.Context) error { } func (s *Impl) decideOwnersToAddUpdateOrRemove(ctx context.Context) (map[string]int8, error) { - cachedOwnerAliases := s.Cache.GetSortedOwnerAliases(ctx) + cachedOwnerAliases, err := s.Cache.GetSortedOwnerAliases(ctx) + if err != nil { + return nil, err + } currentOwnerAliases, err := s.Mapper.GetSortedOwnerAliases(ctx) if err != nil { diff --git a/internal/service/updater/repositories.go b/internal/service/updater/repositories.go index c153c5b..3df1c64 100644 --- a/internal/service/updater/repositories.go +++ b/internal/service/updater/repositories.go @@ -19,7 +19,10 @@ func (s *Impl) WriteRepository(ctx context.Context, key string, repository opena current, err := s.Cache.GetRepository(ctx, key) if err == nil && current.Owner != repository.Owner { - allowed := s.CanMoveOrDeleteRepository(subCtx, key) + allowed, err := s.CanMoveOrDeleteRepository(subCtx, key) + if err != nil { + return err + } if !allowed { s.Logging.Logger().Ctx(ctx).Info().Printf("tried to move repository %v, which is still referenced by its service", key) return apierrors.NewConflictError("repository.conflict.referenced", "this repository is being referenced in a service, you cannot change its owner directly - you can change the owner of the service and this will move it along", nil, s.Timestamp.Now()) @@ -128,7 +131,10 @@ func (s *Impl) updateRepositories(ctx context.Context) error { } func (s *Impl) decideRepositoriesToAddUpdateOrRemove(ctx context.Context) (map[string]int8, error) { - cachedRepositoryKeys := s.Cache.GetSortedRepositoryKeys(ctx) + cachedRepositoryKeys, err := s.Cache.GetSortedRepositoryKeys(ctx) + if err != nil { + return nil, err + } currentRepositoryKeys, err := s.Mapper.GetSortedRepositoryKeys(ctx) if err != nil { @@ -219,14 +225,18 @@ func (s *Impl) updateIndividualRepository(ctx context.Context, key string, isNew return nil } -func (s *Impl) CanMoveOrDeleteRepository(ctx context.Context, key string) bool { - for _, name := range s.Cache.GetSortedServiceNames(ctx) { +func (s *Impl) CanMoveOrDeleteRepository(ctx context.Context, key string) (bool, error) { + names, err := s.Cache.GetSortedServiceNames(ctx) + if err != nil { + return false, err + } + for _, name := range names { svc, _ := s.Cache.GetService(ctx, name) for _, candidateKey := range svc.Repositories { if key == candidateKey { - return false + return false, nil } } } - return true + return true, nil } diff --git a/internal/service/updater/services.go b/internal/service/updater/services.go index c57d573..4c82732 100644 --- a/internal/service/updater/services.go +++ b/internal/service/updater/services.go @@ -143,7 +143,10 @@ func (s *Impl) updateServices(ctx context.Context) error { } func (s *Impl) decideServicesToAddUpdateOrRemove(ctx context.Context) (map[string]int8, error) { - cachedServiceNames := s.Cache.GetSortedServiceNames(ctx) + cachedServiceNames, err := s.Cache.GetSortedServiceNames(ctx) + if err != nil { + return nil, err + } currentServiceNames, err := s.Mapper.GetSortedServiceNames(ctx) if err != nil { diff --git a/test/mock/cachemock/cachemock.go b/test/mock/cachemock/cachemock.go index 928d45c..4334549 100644 --- a/test/mock/cachemock/cachemock.go +++ b/test/mock/cachemock/cachemock.go @@ -16,16 +16,16 @@ func (s *Mock) Setup() error { return nil } -func (s *Mock) SetOwnerListTimestamp(ctx context.Context, timestamp string) { - +func (s *Mock) SetOwnerListTimestamp(ctx context.Context, timestamp string) error { + return nil } -func (s *Mock) GetOwnerListTimestamp(ctx context.Context) string { - return "" +func (s *Mock) GetOwnerListTimestamp(ctx context.Context) (string, error) { + return "", nil } -func (s *Mock) GetSortedOwnerAliases(ctx context.Context) []string { - return nil +func (s *Mock) GetSortedOwnerAliases(ctx context.Context) ([]string, error) { + return nil, nil } func (s *Mock) GetOwner(ctx context.Context, alias string) (openapi.OwnerDto, error) { @@ -37,52 +37,58 @@ func (s *Mock) GetOwner(ctx context.Context, alias string) (openapi.OwnerDto, er return openapi.OwnerDto{}, nil } -func (s *Mock) PutOwner(ctx context.Context, alias string, entry openapi.OwnerDto) { - +func (s *Mock) PutOwner(ctx context.Context, alias string, entry openapi.OwnerDto) error { + return nil } -func (s *Mock) DeleteOwner(ctx context.Context, alias string) {} +func (s *Mock) DeleteOwner(ctx context.Context, alias string) error { + return nil +} -func (s *Mock) SetServiceListTimestamp(ctx context.Context, timestamp string) {} +func (s *Mock) SetServiceListTimestamp(ctx context.Context, timestamp string) error { + return nil +} -func (s *Mock) GetServiceListTimestamp(ctx context.Context) string { - return "" +func (s *Mock) GetServiceListTimestamp(ctx context.Context) (string, error) { + return "", nil } -func (s *Mock) GetSortedServiceNames(ctx context.Context) []string { - return nil +func (s *Mock) GetSortedServiceNames(ctx context.Context) ([]string, error) { + return nil, nil } func (s *Mock) GetService(ctx context.Context, name string) (openapi.ServiceDto, error) { return openapi.ServiceDto{}, nil } -func (s *Mock) PutService(ctx context.Context, name string, entry openapi.ServiceDto) {} - -func (s *Mock) DeleteService(ctx context.Context, name string) { - +func (s *Mock) PutService(ctx context.Context, name string, entry openapi.ServiceDto) error { + return nil } -func (s *Mock) SetRepositoryListTimestamp(ctx context.Context, timestamp string) { +func (s *Mock) DeleteService(ctx context.Context, name string) error { + return nil +} +func (s *Mock) SetRepositoryListTimestamp(ctx context.Context, timestamp string) error { + return nil } -func (s *Mock) GetRepositoryListTimestamp(ctx context.Context) string { - return "" +func (s *Mock) GetRepositoryListTimestamp(ctx context.Context) (string, error) { + return "", nil } -func (s *Mock) GetSortedRepositoryKeys(ctx context.Context) []string { - return nil +func (s *Mock) GetSortedRepositoryKeys(ctx context.Context) ([]string, error) { + return nil, nil } func (s *Mock) GetRepository(ctx context.Context, key string) (openapi.RepositoryDto, error) { return openapi.RepositoryDto{}, nil } -func (s *Mock) PutRepository(ctx context.Context, key string, entry openapi.RepositoryDto) { - +func (s *Mock) PutRepository(ctx context.Context, key string, entry openapi.RepositoryDto) error { + return nil } -func (s *Mock) DeleteRepository(ctx context.Context, key string) { - +func (s *Mock) DeleteRepository(ctx context.Context, key string) error { + return nil }