fix: api handlers. add tests
This commit is contained in:
		
							parent
							
								
									7c48812057
								
							
						
					
					
						commit
						fb72d4bc8c
					
				@ -25,6 +25,9 @@ type Capabilities struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c Capabilities) String() string {
 | 
					func (c Capabilities) String() string {
 | 
				
			||||||
 | 
						if c.AcceptEncoding == "" {
 | 
				
			||||||
 | 
							return "<nil>"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return fmt.Sprint("accept-encoding: ", c.AcceptEncoding)
 | 
						return fmt.Sprint("accept-encoding: ", c.AcceptEncoding)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -83,30 +86,40 @@ func (a *Addr) Refresh(ctx context.Context) error {
 | 
				
			|||||||
	defer span.End()
 | 
						defer span.End()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	span.AddEvent(fmt.Sprintf("Looking up SRV record for _salty._tcp.%s", a.Domain))
 | 
						span.AddEvent(fmt.Sprintf("Looking up SRV record for _salty._tcp.%s", a.Domain))
 | 
				
			||||||
	if target, _, err := a.dns.LookupSRV(ctx, "salty", "tcp", a.Domain); err == nil {
 | 
						if _, srv, err := a.dns.LookupSRV(ctx, "salty", "tcp", a.Domain); err == nil {
 | 
				
			||||||
		a.discoveredDomain = target
 | 
							if len(srv) > 0 {
 | 
				
			||||||
 | 
								a.discoveredDomain = strings.TrimSuffix(srv[0].Target, ".")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		span.AddEvent(fmt.Sprintf("Discovered salty services %s", a.discoveredDomain))
 | 
							span.AddEvent(fmt.Sprintf("Discovered salty services %s", a.discoveredDomain))
 | 
				
			||||||
	} else if err != nil {
 | 
						} else if err != nil {
 | 
				
			||||||
		span.AddEvent(fmt.Sprintf("error looking up SRV record for _salty._tcp.%s : %s", a.Domain, err))
 | 
							span.RecordError(fmt.Errorf("error looking up SRV record for _salty._tcp.%s : %s", a.Domain, err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, cap, err := fetchConfig(ctx, a.HashURI())
 | 
						config, cap, err := fetchConfig(ctx, a.HashURI())
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		// Fallback to plain user nick
 | 
							// Fallback to plain user nick
 | 
				
			||||||
 | 
							span.RecordError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		config, cap, err = fetchConfig(ctx, a.URI())
 | 
							config, cap, err = fetchConfig(ctx, a.URI())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("error looking up user %s: %w", a, err)
 | 
							err = fmt.Errorf("error looking up user %s: %w", a, err)
 | 
				
			||||||
 | 
							span.RecordError(err)
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	key, err := keys.NewEdX25519PublicKeyFromID(keys.ID(config.Key))
 | 
						key, err := keys.NewEdX25519PublicKeyFromID(keys.ID(config.Key))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("error parsing public key %s: %w", config.Key, err)
 | 
							err = fmt.Errorf("error parsing public key %s: %w", config.Key, err)
 | 
				
			||||||
 | 
							span.RecordError(err)
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	a.key = key
 | 
						a.key = key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u, err := url.Parse(config.Endpoint)
 | 
						u, err := url.Parse(config.Endpoint)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("error parsing endpoint %s: %w", config.Endpoint, err)
 | 
							err = fmt.Errorf("error parsing endpoint %s: %w", config.Endpoint, err)
 | 
				
			||||||
 | 
							span.RecordError(err)
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	a.endpoint = u
 | 
						a.endpoint = u
 | 
				
			||||||
	a.capabilities = cap
 | 
						a.capabilities = cap
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,7 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/keys-pub/keys"
 | 
						"github.com/keys-pub/keys"
 | 
				
			||||||
	"github.com/sour-is/ev/internal/lg"
 | 
						"github.com/sour-is/ev/internal/lg"
 | 
				
			||||||
@ -35,6 +36,7 @@ type service struct {
 | 
				
			|||||||
	m_api_register syncint64.Counter
 | 
						m_api_register syncint64.Counter
 | 
				
			||||||
	m_api_lookup   syncint64.Counter
 | 
						m_api_lookup   syncint64.Counter
 | 
				
			||||||
	m_api_send     syncint64.Counter
 | 
						m_api_send     syncint64.Counter
 | 
				
			||||||
 | 
						m_req_time     syncint64.Histogram
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
type contextKey struct {
 | 
					type contextKey struct {
 | 
				
			||||||
	name string
 | 
						name string
 | 
				
			||||||
@ -81,6 +83,10 @@ func New(ctx context.Context, es *es.EventStore, baseURL string) (*service, erro
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	svc.m_api_send, err = m.SyncInt64().Counter("salty_api_send")
 | 
						svc.m_api_send, err = m.SyncInt64().Counter("salty_api_send")
 | 
				
			||||||
	errs = multierr.Append(errs, err)
 | 
						errs = multierr.Append(errs, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						svc.m_req_time, err = m.SyncInt64().Histogram("salty_request_time")
 | 
				
			||||||
 | 
						errs = multierr.Append(errs, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	span.RecordError(err)
 | 
						span.RecordError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return svc, errs
 | 
						return svc, errs
 | 
				
			||||||
@ -106,6 +112,9 @@ func (s *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
	ctx, span := lg.Span(ctx)
 | 
						ctx, span := lg.Span(ctx)
 | 
				
			||||||
	defer span.End()
 | 
						defer span.End()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						start := time.Now()
 | 
				
			||||||
 | 
						defer s.m_req_time.Record(ctx, int64(time.Since(start)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addr := "saltyuser-" + strings.TrimPrefix(r.URL.Path, "/.well-known/salty/")
 | 
						addr := "saltyuser-" + strings.TrimPrefix(r.URL.Path, "/.well-known/salty/")
 | 
				
			||||||
	addr = strings.TrimSuffix(addr, ".json")
 | 
						addr = strings.TrimSuffix(addr, ".json")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -209,10 +218,14 @@ func (s *service) apiv1(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
	case http.MethodGet:
 | 
						case http.MethodGet:
 | 
				
			||||||
		switch {
 | 
							switch {
 | 
				
			||||||
		case r.URL.Path == "/ping":
 | 
							case r.URL.Path == "/ping":
 | 
				
			||||||
 | 
								s.m_api_ping.Add(ctx, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			w.Header().Set("Content-Type", "application/json")
 | 
								w.Header().Set("Content-Type", "application/json")
 | 
				
			||||||
			_, _ = w.Write([]byte(`{}`))
 | 
								_, _ = w.Write([]byte(`{}`))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case strings.HasPrefix(r.URL.Path, "/lookup/"):
 | 
							case strings.HasPrefix(r.URL.Path, "/lookup/"):
 | 
				
			||||||
 | 
								s.m_api_lookup.Add(ctx, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			addr, err := s.ParseAddr(strings.TrimPrefix(r.URL.Path, "/lookup/"))
 | 
								addr, err := s.ParseAddr(strings.TrimPrefix(r.URL.Path, "/lookup/"))
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				span.RecordError(err)
 | 
									span.RecordError(err)
 | 
				
			||||||
@ -226,7 +239,8 @@ func (s *service) apiv1(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			json.NewEncoder(w).Encode(addr)
 | 
								err = json.NewEncoder(w).Encode(addr)
 | 
				
			||||||
 | 
								span.RecordError(err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
@ -237,8 +251,14 @@ func (s *service) apiv1(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
	case http.MethodPost:
 | 
						case http.MethodPost:
 | 
				
			||||||
		switch r.URL.Path {
 | 
							switch r.URL.Path {
 | 
				
			||||||
		case "/register":
 | 
							case "/register":
 | 
				
			||||||
 | 
								s.m_api_register.Add(ctx, 1)
 | 
				
			||||||
 | 
								notImplemented(w)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case "/send":
 | 
							case "/send":
 | 
				
			||||||
 | 
								s.m_api_send.Add(ctx, 1)
 | 
				
			||||||
 | 
								notImplemented(w)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			w.WriteHeader(http.StatusNotFound)
 | 
								w.WriteHeader(http.StatusNotFound)
 | 
				
			||||||
@ -249,3 +269,7 @@ func (s *service) apiv1(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func notImplemented(w http.ResponseWriter) {
 | 
				
			||||||
 | 
						w.WriteHeader(http.StatusNotImplemented)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/rs/cors"
 | 
						"github.com/rs/cors"
 | 
				
			||||||
@ -17,6 +18,7 @@ func httpMux(fns ...interface{ RegisterHTTP(*http.ServeMux) }) http.Handler {
 | 
				
			|||||||
		fn.RegisterHTTP(mux.ServeMux)
 | 
							fn.RegisterHTTP(mux.ServeMux)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if fn, ok := fn.(interface{ RegisterAPIv1(*http.ServeMux) }); ok {
 | 
							if fn, ok := fn.(interface{ RegisterAPIv1(*http.ServeMux) }); ok {
 | 
				
			||||||
 | 
								log.Printf("register api %T", fn)
 | 
				
			||||||
			fn.RegisterAPIv1(mux.api)
 | 
								fn.RegisterAPIv1(mux.api)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -28,10 +30,7 @@ func newMux() *mux {
 | 
				
			|||||||
		api:      http.NewServeMux(),
 | 
							api:      http.NewServeMux(),
 | 
				
			||||||
		ServeMux: http.NewServeMux(),
 | 
							ServeMux: http.NewServeMux(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mux.Handle("/api/v1/", http.StripPrefix("/api/v1/", mux.api))
 | 
						mux.Handle("/api/v1/", http.StripPrefix("/api/v1", mux.api))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mux
 | 
						return mux
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (m mux) HandleAPIv1(pattern string, handler http.Handler) {
 | 
					 | 
				
			||||||
	m.api.Handle(pattern, handler)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										40
									
								
								httpmux_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								httpmux_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/http/httptest"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/matryer/is"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type mockHTTP struct {
 | 
				
			||||||
 | 
						onServeHTTP func()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *mockHTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
						m.onServeHTTP()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *mockHTTP) RegisterHTTP(mux *http.ServeMux) {
 | 
				
			||||||
 | 
						mux.Handle("/", h)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (h *mockHTTP) RegisterAPIv1(mux *http.ServeMux) {
 | 
				
			||||||
 | 
						mux.Handle("/ping", h)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestHttpMux(t *testing.T) {
 | 
				
			||||||
 | 
						is := is.New(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						called := false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mux := httpMux(&mockHTTP{func() { called = true }})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is.True(mux != nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						w := httptest.NewRecorder()
 | 
				
			||||||
 | 
						r := httptest.NewRequest(http.MethodGet, "/api/v1/ping", nil)
 | 
				
			||||||
 | 
						mux.ServeHTTP(w, r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is.True(called)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -48,7 +48,9 @@ func initMetrics(ctx context.Context, name string) (context.Context, func() erro
 | 
				
			|||||||
		host = h
 | 
							host = h
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config := prometheus.Config{}
 | 
						config := prometheus.Config{
 | 
				
			||||||
 | 
							DefaultHistogramBoundaries: []float64{1, 2, 5, 10, 20, 50},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	cont := controller.New(
 | 
						cont := controller.New(
 | 
				
			||||||
		processor.NewFactory(
 | 
							processor.NewFactory(
 | 
				
			||||||
			selector.NewWithHistogramDistribution(
 | 
								selector.NewWithHistogramDistribution(
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								pkg/cache/cache.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								pkg/cache/cache.go
									
									
									
									
										vendored
									
									
								
							@ -139,7 +139,7 @@ func (c *Cache[K, V]) ContainsOrAdd(ctx context.Context, key K, value V) (ok, ev
 | 
				
			|||||||
// PeekOrAdd checks if a key is in the cache without updating the
 | 
					// PeekOrAdd checks if a key is in the cache without updating the
 | 
				
			||||||
// recent-ness or deleting it for being stale, and if not, adds the value.
 | 
					// recent-ness or deleting it for being stale, and if not, adds the value.
 | 
				
			||||||
// Returns whether found and whether an eviction occurred.
 | 
					// Returns whether found and whether an eviction occurred.
 | 
				
			||||||
func (c *Cache[K, V]) PeekOrAdd(ctx context.Context, key K, value V) (previous interface{}, ok, evicted bool) {
 | 
					func (c *Cache[K, V]) PeekOrAdd(ctx context.Context, key K, value V) (previous *V, ok, evicted bool) {
 | 
				
			||||||
	var k K
 | 
						var k K
 | 
				
			||||||
	var v V
 | 
						var v V
 | 
				
			||||||
	c.lock.Lock()
 | 
						c.lock.Lock()
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										131
									
								
								pkg/cache/cache_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								pkg/cache/cache_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,131 @@
 | 
				
			|||||||
 | 
					package cache_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/matryer/is"
 | 
				
			||||||
 | 
						"github.com/sour-is/ev/pkg/cache"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCache(t *testing.T) {
 | 
				
			||||||
 | 
						is := is.New(t)
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c, err := cache.NewCache[string, int](1)
 | 
				
			||||||
 | 
						is.NoErr(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						evicted := c.Add(ctx, "one", 1)
 | 
				
			||||||
 | 
						is.True(!evicted)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is.True(c.Contains("one"))
 | 
				
			||||||
 | 
						_, ok := c.Peek("one")
 | 
				
			||||||
 | 
						is.True(ok)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ok, evicted = c.ContainsOrAdd(ctx, "two", 2)
 | 
				
			||||||
 | 
						is.True(!ok)
 | 
				
			||||||
 | 
						is.True(evicted)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is.True(!c.Contains("one"))
 | 
				
			||||||
 | 
						is.True(c.Contains("two"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is.Equal(c.Len(), 1)
 | 
				
			||||||
 | 
						is.Equal(c.Keys(), []string{"two"})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v, ok := c.Get("two")
 | 
				
			||||||
 | 
						is.True(ok)
 | 
				
			||||||
 | 
						is.Equal(*v, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						evictCount := c.Resize(ctx, 100)
 | 
				
			||||||
 | 
						is.True(evictCount == 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.Add(ctx, "one", 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prev, ok, evicted := c.PeekOrAdd(ctx, "three", 3)
 | 
				
			||||||
 | 
						is.True(!ok)
 | 
				
			||||||
 | 
						is.True(!evicted)
 | 
				
			||||||
 | 
						is.Equal(prev, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key, value, ok := c.GetOldest()
 | 
				
			||||||
 | 
						is.True(ok)
 | 
				
			||||||
 | 
						is.Equal(*key, "two")
 | 
				
			||||||
 | 
						is.Equal(*value, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key, value, ok = c.RemoveOldest(ctx)
 | 
				
			||||||
 | 
						is.True(ok)
 | 
				
			||||||
 | 
						is.Equal(*key, "two")
 | 
				
			||||||
 | 
						is.Equal(*value, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.Remove(ctx, "one")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.Purge(ctx)
 | 
				
			||||||
 | 
						is.True(!c.Contains("three"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCacheWithEvict(t *testing.T) {
 | 
				
			||||||
 | 
						is := is.New(t)
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						evictions := 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c, err := cache.NewWithEvict(1, func(ctx context.Context, s string, i int) { evictions++ })
 | 
				
			||||||
 | 
						is.NoErr(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key, value, ok := c.GetOldest()
 | 
				
			||||||
 | 
						is.True(!ok)
 | 
				
			||||||
 | 
						is.Equal(key, nil)
 | 
				
			||||||
 | 
						is.Equal(value, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key, value, ok = c.RemoveOldest(ctx)
 | 
				
			||||||
 | 
						is.True(!ok)
 | 
				
			||||||
 | 
						is.Equal(key, nil)
 | 
				
			||||||
 | 
						is.Equal(value, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						evicted := c.Add(ctx, "one", 1)
 | 
				
			||||||
 | 
						is.True(!evicted)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is.True(c.Contains("one"))
 | 
				
			||||||
 | 
						_, ok = c.Peek("one")
 | 
				
			||||||
 | 
						is.True(ok)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ok, evicted = c.ContainsOrAdd(ctx, "two", 2)
 | 
				
			||||||
 | 
						is.True(!ok)
 | 
				
			||||||
 | 
						is.True(evicted)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is.True(!c.Contains("one"))
 | 
				
			||||||
 | 
						is.True(c.Contains("two"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is.Equal(c.Len(), 1)
 | 
				
			||||||
 | 
						is.Equal(c.Keys(), []string{"two"})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v, ok := c.Get("two")
 | 
				
			||||||
 | 
						is.True(ok)
 | 
				
			||||||
 | 
						is.Equal(*v, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						evictCount := c.Resize(ctx, 100)
 | 
				
			||||||
 | 
						is.True(evictCount == 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.Add(ctx, "one", 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prev, ok, evicted := c.PeekOrAdd(ctx, "three", 3)
 | 
				
			||||||
 | 
						is.True(!ok)
 | 
				
			||||||
 | 
						is.True(!evicted)
 | 
				
			||||||
 | 
						is.Equal(prev, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key, value, ok = c.GetOldest()
 | 
				
			||||||
 | 
						is.True(ok)
 | 
				
			||||||
 | 
						is.Equal(*key, "two")
 | 
				
			||||||
 | 
						is.Equal(*value, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key, value, ok = c.RemoveOldest(ctx)
 | 
				
			||||||
 | 
						is.True(ok)
 | 
				
			||||||
 | 
						is.Equal(*key, "two")
 | 
				
			||||||
 | 
						is.Equal(*value, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.Resize(ctx, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.Purge(ctx)
 | 
				
			||||||
 | 
						is.True(!c.Contains("three"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is.Equal(evictions, 4)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								pkg/es/driver/projecter/projector_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/es/driver/projecter/projector_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					package projecter_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/sour-is/ev/pkg/es/driver"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type mockDriver struct {
 | 
				
			||||||
 | 
						onOpen     func()
 | 
				
			||||||
 | 
						onEventLog func()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EventLog implements driver.Driver
 | 
				
			||||||
 | 
					func (*mockDriver) EventLog(ctx context.Context, streamID string) (driver.EventLog, error) {
 | 
				
			||||||
 | 
						panic("unimplemented")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Open implements driver.Driver
 | 
				
			||||||
 | 
					func (*mockDriver) Open(ctx context.Context, dsn string) (driver.Driver, error) {
 | 
				
			||||||
 | 
						panic("unimplemented")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ driver.Driver = (*mockDriver)(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestProjecter(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user