package acoustid import ( "context" "net/http" "net/http/httptest" "strings" "testing" "time" "github.com/google/uuid" "github.com/stretchr/testify/require" ) type memoryCache map[string][]byte func (m memoryCache) GetMetadataCache(_ context.Context, k string) ([]byte, bool, error) { b, ok := m[k] return b, ok, nil } func (m memoryCache) PutMetadataCache(_ context.Context, k string, b []byte, _ time.Duration) error { m[k] = b return nil } func TestLookupPostsFingerprintCachesAndDeduplicatesRecordings(t *testing.T) { id := uuid.NewString() calls := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { calls++ require.Equal(t, "POST", r.Method) require.Empty(t, r.URL.RawQuery, "key and fingerprint must not appear in URL logs") require.NoError(t, r.ParseForm()) require.Equal(t, "private-key", r.Form.Get("client")) require.Equal(t, "encoded-fingerprint", r.Form.Get("fingerprint")) require.Equal(t, "321", r.Form.Get("duration")) require.Equal(t, "recordingids", r.Form.Get("meta")) _, _ = w.Write([]byte(`{"status":"ok","results":[{"score":0.98,"recordings":[{"id":"` + id + `"}]},{"score":0.95,"recordings":[{"id":"` + id + `"},{"id":"invalid"}]}]}`)) })) defer server.Close() cache := memoryCache{} c := New("private-key", cache) c.endpoint = server.URL c.interval = 0 for range 2 { matches, err := c.Lookup(context.Background(), "encoded-fingerprint", 321) require.NoError(t, err) require.Equal(t, []Match{{id, .98}}, matches) } require.Equal(t, 1, calls) for k := range cache { require.NotContains(t, k, "private-key") require.NotContains(t, k, "encoded-fingerprint") } } func TestLookupRejectsProviderErrorsAndDoesNotCacheThem(t *testing.T) { for _, body := range []string{`{"status":"error","error":{"message":"secret-key"}}`, `invalid`, strings.Repeat("x", (2<<20)+1)} { t.Run(body[:min(20, len(body))], func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(body)) })) defer server.Close() cache := memoryCache{} c := New("secret-key", cache) c.endpoint = server.URL _, err := c.Lookup(context.Background(), "fp", 200) require.Error(t, err) require.NotContains(t, err.Error(), "secret-key") require.Empty(t, cache) }) } } func TestLookupDoesNotForwardKeyOnRedirectAndWaitIsCancelable(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "https://example.com", 307) })) defer server.Close() c := New("key", memoryCache{}) c.endpoint = server.URL _, err := c.Lookup(context.Background(), "fp", 200) require.ErrorContains(t, err, "HTTP 307") c.next = time.Now().Add(time.Hour) ctx, cancel := context.WithCancel(context.Background()) cancel() _, err = c.Lookup(ctx, "fp", 200) require.ErrorIs(t, err, context.Canceled) }