Files
substrate/cmd/ateapi/internal/controlapi/workflow_delete_test.go
T
Julian Gutierrez Oschmann 4c1bd9d36b Add status fields to Substrate resources (#1025)
Add `status` fields to all Substrate resources that need it. Move
server-owned fields under it.

Fixes #1006 .
2026-08-18 11:58:31 -07:00

121 lines
3.7 KiB
Go

// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controlapi
import (
"context"
"testing"
"github.com/agent-substrate/substrate/cmd/ateapi/internal/store/storetest"
"github.com/agent-substrate/substrate/internal/resources"
"github.com/agent-substrate/substrate/pkg/proto/ateapipb"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func TestDeleteActorWorkflow_ExecutionPaths(t *testing.T) {
tests := []struct {
name string
seedState ateapipb.ActorState
wantErr bool
wantCode codes.Code
}{
{
name: "delete suspended actor succeeds",
seedState: ateapipb.ActorState_ACTOR_STATE_SUSPENDED,
wantErr: false,
},
{
name: "delete crashed actor succeeds",
seedState: ateapipb.ActorState_ACTOR_STATE_CRASHED,
wantErr: false,
},
{
name: "delete deleting actor succeeds",
seedState: ateapipb.ActorState_ACTOR_STATE_DELETING,
wantErr: false,
},
{
name: "delete running actor rejected",
seedState: ateapipb.ActorState_ACTOR_STATE_RUNNING,
wantErr: true,
wantCode: codes.FailedPrecondition,
},
{
name: "delete paused actor rejected",
seedState: ateapipb.ActorState_ACTOR_STATE_PAUSED,
wantErr: true,
wantCode: codes.FailedPrecondition,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
ctx := context.Background()
st, cleanup := storetest.SetupTestStore(t)
defer cleanup()
w := newTestActorWorkflow(t, st, "ns", "tmpl1")
actorRef := resources.ActorRef{Atespace: "team-a", Name: "id1"}
seedWorkflowActor(t, ctx, st, actorRef, "ns", "tmpl1", tc.seedState)
deleted, err := w.DeleteActor(ctx, actorRef)
if tc.wantErr {
if got := status.Code(err); got != tc.wantCode {
t.Fatalf("status.Code(err) = %v, want %v (err: %v)", got, tc.wantCode, err)
}
} else {
if err != nil {
t.Fatalf("DeleteActor failed: %v", err)
}
if deleted == nil {
t.Fatalf("expected non-nil deleted actor")
}
if _, err := st.GetActor(ctx, actorRef); err == nil {
t.Errorf("expected actor to be deleted from store, but it still exists")
}
}
})
}
}
func TestEnsureMarkedDeleting_StateMatrix(t *testing.T) {
allowed := map[ateapipb.ActorState]bool{
ateapipb.ActorState_ACTOR_STATE_SUSPENDED: true,
ateapipb.ActorState_ACTOR_STATE_CRASHED: true,
ateapipb.ActorState_ACTOR_STATE_DELETING: true, // skipped, not re-marked
}
for _, seedState := range allActorStates {
ctx := context.Background()
st, cleanup := storetest.SetupTestStore(t)
w := newTestActorWorkflow(t, st, "ns", "tmpl1")
actorRef := resources.ActorRef{Atespace: "team-a", Name: "id1"}
seedWorkflowActor(t, ctx, st, actorRef, "ns", "tmpl1", seedState)
actor, err := st.GetActor(ctx, actorRef)
if err != nil {
t.Fatalf("state %v: get seeded actor: %v", seedState, err)
}
updated, err := w.ensureMarkedDeleting(ctx, actorRef, actor)
assertPrerequisiteResult(t, seedState, err, allowed[seedState])
if err == nil && updated.GetStatus().GetState() != ateapipb.ActorState_ACTOR_STATE_DELETING {
t.Errorf("state %v: ensureMarkedDeleting returned actor in %v, want DELETING", seedState, updated.GetStatus().GetState())
}
cleanup()
}
}