package service import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" ) func TestKetoService_CheckPermission(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/relation-tuples/check", r.URL.Path) assert.Equal(t, "user1", r.URL.Query().Get("subject_id")) assert.Equal(t, "tenants", r.URL.Query().Get("namespace")) assert.Equal(t, "tenant1", r.URL.Query().Get("object")) assert.Equal(t, "admin", r.URL.Query().Get("relation")) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(checkResponse{Allowed: true}) })) defer server.Close() s := &ketoService{ readURL: server.URL, client: &http.Client{}, } allowed, err := s.CheckPermission(context.Background(), "user1", "tenants", "tenant1", "admin") assert.NoError(t, err) assert.True(t, allowed) } func TestKetoService_CreateRelation(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/admin/relation-tuples", r.URL.Path) assert.Equal(t, "PUT", r.Method) var body map[string]interface{} json.NewDecoder(r.Body).Decode(&body) assert.Equal(t, "tenants", body["namespace"]) assert.Equal(t, "tenant1", body["object"]) assert.Equal(t, "admin", body["relation"]) assert.Equal(t, "user1", body["subject_id"]) w.WriteHeader(http.StatusCreated) })) defer server.Close() s := &ketoService{ writeURL: server.URL, client: &http.Client{}, } err := s.CreateRelation(context.Background(), "tenants", "tenant1", "admin", "user1") assert.NoError(t, err) } func TestKetoService_DeleteRelation(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/relation-tuples", r.URL.Path) assert.Equal(t, "DELETE", r.Method) assert.Equal(t, "user1", r.URL.Query().Get("subject_id")) w.WriteHeader(http.StatusNoContent) })) defer server.Close() s := &ketoService{ writeURL: server.URL, client: &http.Client{}, } err := s.DeleteRelation(context.Background(), "tenants", "tenant1", "admin", "user1") assert.NoError(t, err) } func TestKetoService_ListRelations(t *testing.T) { tuples := []RelationTuple{ {Namespace: "tenants", Object: "tenant1", Relation: "admin", SubjectID: "user1"}, } server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/relation-tuples", r.URL.Path) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(relationTuplesResponse{RelationTuples: tuples}) })) defer server.Close() s := &ketoService{ readURL: server.URL, client: &http.Client{}, } result, err := s.ListRelations(context.Background(), "tenants", "tenant1", "admin", "user1") assert.NoError(t, err) assert.Equal(t, tuples, result) } func TestKetoService_ErrorHandling(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("internal error")) })) defer server.Close() s := &ketoService{ readURL: server.URL, writeURL: server.URL, client: &http.Client{}, } _, err := s.CheckPermission(context.Background(), "u", "n", "o", "r") assert.Error(t, err) err = s.DeleteRelation(context.Background(), "n", "o", "r", "s") assert.Error(t, err) _, err = s.ListRelations(context.Background(), "n", "o", "r", "s") assert.Error(t, err) } func TestKetoService_CheckPermission_Forbidden(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusForbidden) })) defer server.Close() s := &ketoService{readURL: server.URL, client: &http.Client{}} allowed, err := s.CheckPermission(context.Background(), "u", "n", "o", "r") assert.NoError(t, err) assert.False(t, allowed) } func TestKetoService_CreateRelation_Retry(t *testing.T) { attempts := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { attempts++ if attempts < 2 { w.WriteHeader(http.StatusInternalServerError) return } w.WriteHeader(http.StatusCreated) })) defer server.Close() s := &ketoService{ writeURL: server.URL, client: &http.Client{}, } err := s.CreateRelation(context.Background(), "n", "o", "r", "s") assert.NoError(t, err) assert.Equal(t, 2, attempts) }