Files
stats-gateway/internal/service/recordspeedtest_test.go
T

110 lines
3.3 KiB
Go

package service
import (
"context"
"path/filepath"
"testing"
"time"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
statsv1 "github.com/bergabruh/stats-gateway/gen/stats/v1"
"github.com/bergabruh/stats-gateway/internal/auth"
"github.com/bergabruh/stats-gateway/internal/storage"
)
// authedCtx returns a context with a valid Bearer JWT for the given subject.
// Uses the same secret as newTestServer ("test-secret") and scope "tunnel"
// (the only scope accepted by *auth.Verifier.Verify).
func authedCtx(t *testing.T, sub string) context.Context {
t.Helper()
tok, err := auth.Issue([]byte("test-secret"), sub, "tunnel", time.Minute)
if err != nil {
t.Fatalf("issue token: %v", err)
}
return metadata.AppendToOutgoingContext(context.Background(), "authorization", "Bearer "+tok)
}
func newRecordSpeedTestClient(t *testing.T) (statsv1.SpeedStatusClient, func()) {
t.Helper()
dir := t.TempDir()
st, err := storage.Open(filepath.Join(dir, "test.db"))
if err != nil {
t.Fatalf("storage.Open: %v", err)
}
client, cleanup := newTestServer(t, st)
return client, func() { cleanup(); st.Close() }
}
func TestRecordSpeedTest_HappyPath(t *testing.T) {
client, cleanup := newRecordSpeedTestClient(t)
defer cleanup()
ctx := authedCtx(t, "fl-speedtest-sync")
resp, err := client.RecordSpeedTest(ctx, &statsv1.RecordSpeedTestRequest{
Timestamp: time.Now().Unix(),
Node: "fl",
Country: "RU",
DlMbps: 100, UlMbps: 20, PingMs: 35, JitterMs: 2,
})
if err != nil {
t.Fatalf("RecordSpeedTest: %v", err)
}
if resp.Id <= 0 {
t.Fatalf("expected id>0, got %d", resp.Id)
}
}
func TestRecordSpeedTest_RejectsBadNode(t *testing.T) {
client, cleanup := newRecordSpeedTestClient(t)
defer cleanup()
ctx := authedCtx(t, "fl-speedtest-sync")
_, err := client.RecordSpeedTest(ctx, &statsv1.RecordSpeedTestRequest{
Timestamp: time.Now().Unix(),
Node: "moon", Country: "RU",
DlMbps: 1, UlMbps: 1, PingMs: 1, JitterMs: 1,
})
if err == nil {
t.Fatalf("expected InvalidArgument for bad node, got nil")
}
if st, ok := status.FromError(err); !ok || st.Code() != codes.InvalidArgument {
t.Fatalf("expected InvalidArgument, got %v", err)
}
}
func TestRecordSpeedTest_RejectsNegativeMbps(t *testing.T) {
client, cleanup := newRecordSpeedTestClient(t)
defer cleanup()
ctx := authedCtx(t, "fl-speedtest-sync")
_, err := client.RecordSpeedTest(ctx, &statsv1.RecordSpeedTestRequest{
Timestamp: time.Now().Unix(), Node: "fl", Country: "RU",
DlMbps: -1, UlMbps: 1, PingMs: 1, JitterMs: 1,
})
if err == nil {
t.Fatalf("expected InvalidArgument for negative dl_mbps, got nil")
}
if st, ok := status.FromError(err); !ok || st.Code() != codes.InvalidArgument {
t.Fatalf("expected InvalidArgument, got %v", err)
}
}
func TestRecordSpeedTest_RequiresAuth(t *testing.T) {
client, cleanup := newRecordSpeedTestClient(t)
defer cleanup()
_, err := client.RecordSpeedTest(context.Background(), &statsv1.RecordSpeedTestRequest{
Timestamp: time.Now().Unix(), Node: "fl", Country: "RU",
DlMbps: 1, UlMbps: 1, PingMs: 1, JitterMs: 1,
})
if err == nil {
t.Fatalf("expected Unauthenticated, got nil")
}
if st, ok := status.FromError(err); !ok || st.Code() != codes.Unauthenticated {
t.Fatalf("expected Unauthenticated, got %v", err)
}
}