snapshot of https://github.com/ory/keto.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
CI / Run lints and checks (push) Failing after 47s
CI / Run tests (push) Failing after 1s
CI / Run race tests (push) Failing after 5s
CI / Build CLI docs (push) Has been skipped
CI / Run buf actions (push) Failing after 5s
CodeQL / Analyze (go) (push) Failing after 3s
CodeQL / Analyze (javascript) (push) Failing after 2s
Docker Image Scanners / scanners (push) Failing after 3s
Format / format (push) Failing after 3s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Draft newsletter (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
Some checks failed
CI / Run lints and checks (push) Failing after 47s
CI / Run tests (push) Failing after 1s
CI / Run race tests (push) Failing after 5s
CI / Build CLI docs (push) Has been skipped
CI / Run buf actions (push) Failing after 5s
CodeQL / Analyze (go) (push) Failing after 3s
CodeQL / Analyze (javascript) (push) Failing after 2s
Docker Image Scanners / scanners (push) Failing after 3s
Format / format (push) Failing after 3s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Draft newsletter (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
This commit is contained in:
182
internal/driver/daemon_test.go
Normal file
182
internal/driver/daemon_test.go
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
ioprometheusclient "github.com/prometheus/client_model/go"
|
||||
"github.com/prometheus/common/expfmt"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
grpcHealthV1 "google.golang.org/grpc/health/grpc_health_v1"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
prometheus "github.com/ory/x/prometheusx"
|
||||
|
||||
rts "github.com/ory/keto/gen/go/ory/keto/relation_tuples/v1alpha2"
|
||||
)
|
||||
|
||||
func TestScrapingEndpoint(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := NewSqliteTestRegistry(t)
|
||||
getAddr := UseDynamicPorts(t, r)
|
||||
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
|
||||
eg := errgroup.Group{}
|
||||
doneShutdown := make(chan struct{})
|
||||
eg.Go(r.serveRead(ctx, doneShutdown))
|
||||
eg.Go(r.serveMetrics(ctx, doneShutdown))
|
||||
|
||||
_, readPort, _ := getAddr(t, "read")
|
||||
_, metricsPort, _ := getAddr(t, "metrics")
|
||||
|
||||
t.Logf("write port: %s, metrics port: %s", readPort, metricsPort)
|
||||
|
||||
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
||||
conn, err := grpc.NewClient(fmt.Sprintf("127.0.0.1:%s", readPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, conn.Close()) }()
|
||||
|
||||
cl := grpcHealthV1.NewHealthClient(conn)
|
||||
resp, err := cl.Check(ctx, &grpcHealthV1.HealthCheckRequest{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, grpcHealthV1.HealthCheckResponse_SERVING, resp.Status)
|
||||
}, 2*time.Second, 10*time.Millisecond)
|
||||
|
||||
conn, err := grpc.NewClient(fmt.Sprintf("127.0.0.1:%s", readPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, conn.Close()) }()
|
||||
|
||||
cl := rts.NewReadServiceClient(conn)
|
||||
resp, err := cl.ListRelationTuples(ctx, &rts.ListRelationTuplesRequest{RelationQuery: &rts.RelationQuery{}})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, resp.RelationTuples, 0)
|
||||
|
||||
// A dedicated transport keeps httptest.Server.Close in parallel tests from
|
||||
// breaking these requests via http.DefaultTransport.CloseIdleConnections.
|
||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
t.Cleanup(transport.CloseIdleConnections)
|
||||
hc := &http.Client{Transport: transport}
|
||||
|
||||
respx, err := hc.Get(fmt.Sprintf("http://127.0.0.1:%s/relation-tuples", readPort))
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { _ = respx.Body.Close() })
|
||||
require.EqualValues(t, http.StatusOK, respx.StatusCode)
|
||||
body, err := io.ReadAll(respx.Body)
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, string(body), `"relation_tuples":[]`)
|
||||
|
||||
promresp, err := hc.Get(fmt.Sprintf("http://127.0.0.1:%s%s", metricsPort, prometheus.MetricsPrometheusPath))
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { _ = promresp.Body.Close() })
|
||||
require.EqualValues(t, http.StatusOK, promresp.StatusCode)
|
||||
promrespBody, err := io.ReadAll(promresp.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
textParser := expfmt.NewTextParser(model.UTF8Validation)
|
||||
text, err := textParser.TextToMetricFamilies(bytes.NewReader(promrespBody))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.EqualValuesf(t, "http_requests_total", *text["http_requests_total"].Name, "%s", promrespBody)
|
||||
require.ElementsMatch(t,
|
||||
[]string{"/grpc.health.v1.Health/", "/ory.keto.relation_tuples.v1alpha2.ReadService/ListRelationTuples", "/relation-tuples"},
|
||||
getLabelValues("endpoint", text["http_requests_total"].Metric),
|
||||
)
|
||||
|
||||
cancel()
|
||||
<-doneShutdown
|
||||
<-doneShutdown
|
||||
require.NoError(t, eg.Wait())
|
||||
}
|
||||
|
||||
type panicInterceptor struct{}
|
||||
|
||||
func (panicInterceptor) WrapUnary(connect.UnaryFunc) connect.UnaryFunc {
|
||||
return func(context.Context, connect.AnyRequest) (connect.AnyResponse, error) { panic("test panic") }
|
||||
}
|
||||
func (panicInterceptor) WrapStreamingClient(connect.StreamingClientFunc) connect.StreamingClientFunc {
|
||||
return func(context.Context, connect.Spec) connect.StreamingClientConn { panic("test panic") }
|
||||
}
|
||||
func (panicInterceptor) WrapStreamingHandler(connect.StreamingHandlerFunc) connect.StreamingHandlerFunc {
|
||||
return func(context.Context, connect.StreamingHandlerConn) error { panic("test panic") }
|
||||
}
|
||||
|
||||
var _ connect.Interceptor = (*panicInterceptor)(nil)
|
||||
|
||||
func TestPanicRecovery(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := NewSqliteTestRegistry(t, WithHandlerOptions(connect.WithInterceptors(panicInterceptor{})))
|
||||
getAddr := UseDynamicPorts(t, r)
|
||||
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
|
||||
eg := errgroup.Group{}
|
||||
doneShutdown := make(chan struct{})
|
||||
eg.Go(r.serveWrite(ctx, doneShutdown))
|
||||
|
||||
_, port, _ := getAddr(t, "write")
|
||||
|
||||
conn, err := grpc.NewClient(fmt.Sprintf("127.0.0.1:%s", port), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
require.NoError(t, err)
|
||||
defer func() { require.NoError(t, conn.Close()) }()
|
||||
|
||||
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
||||
cl := grpcHealthV1.NewHealthClient(conn)
|
||||
|
||||
watcher, err := cl.Watch(ctx, &grpcHealthV1.HealthCheckRequest{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, watcher.CloseSend())
|
||||
for err := status.Error(codes.Unavailable, "init"); status.Code(err) != codes.Unavailable; _, err = watcher.Recv() {
|
||||
}
|
||||
}, 2*time.Second, 10*time.Millisecond)
|
||||
|
||||
cl := grpcHealthV1.NewHealthClient(conn)
|
||||
// we want to ensure the server is still running after the panic
|
||||
for range 10 {
|
||||
// Unary call
|
||||
resp, err := cl.Check(ctx, &grpcHealthV1.HealthCheckRequest{})
|
||||
require.Errorf(t, err, "%+v", resp)
|
||||
assert.Equal(t, codes.Internal, status.Code(err))
|
||||
|
||||
// Streaming call
|
||||
wResp, err := cl.Watch(ctx, &grpcHealthV1.HealthCheckRequest{})
|
||||
require.NoError(t, err)
|
||||
err = wResp.RecvMsg(nil)
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, codes.Internal, status.Code(err))
|
||||
}
|
||||
|
||||
cancel()
|
||||
<-doneShutdown
|
||||
require.NoError(t, eg.Wait())
|
||||
}
|
||||
|
||||
func getLabelValues(name string, metric []*ioprometheusclient.Metric) (vals []string) {
|
||||
for _, m := range metric {
|
||||
for _, label := range m.Label {
|
||||
if *label.Name == name {
|
||||
vals = append(vals, *label.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return vals
|
||||
}
|
||||
Reference in New Issue
Block a user