Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d2cd4c5
docs(plans): cloud-SDK extraction design — workflow core → strict-con…
intel352 May 14, 2026
98448d5
docs(plans): cloud-SDK extraction design — adversarial review cycle 1…
intel352 May 14, 2026
18534e8
docs(plans): cloud-SDK extraction design — adversarial review cycle 2…
intel352 May 14, 2026
5fb2000
docs(plans): fix stale Phase A/B refs + Status line post-cycle-2
intel352 May 14, 2026
39a3b43
docs(plans): cloud-SDK extraction design — adversarial review cycle 3…
intel352 May 14, 2026
a6d6396
docs(plans): cloud-SDK extraction design — adversarial review cycle 4…
intel352 May 14, 2026
e71fa10
docs(plans): cloud-SDK extraction design — adversarial review cycle 5…
intel352 May 14, 2026
ac10b67
docs(plans): cloud-SDK extraction design — adversarial review cycle 6…
intel352 May 14, 2026
808ec51
docs(plans): cloud-SDK extraction design — adversarial review cycle 7…
intel352 May 14, 2026
337d0e0
docs(plans): cloud-SDK extraction design — cycle-8 re-baseline agains…
intel352 May 14, 2026
b9facf5
docs(plans): cloud-SDK extraction design — cycle-9 re-baseline + audi…
intel352 May 14, 2026
264791b
docs(plans): cloud-SDK extraction design — cycle-10 re-baseline, AWS …
intel352 May 14, 2026
1b8fb38
docs(plans): cloud-SDK extraction design — cycle-11 PASS, minor cleanups
intel352 May 14, 2026
a81f0b6
fix(scripts): audit-cloud-symbols single-line-import grep poisoned th…
intel352 May 14, 2026
02fe621
docs(plans): cloud-SDK extraction implementation plan (Phase 0 + Phas…
intel352 May 14, 2026
3499c8b
docs(plans): cloud-SDK extraction plan — address plan-phase adversari…
intel352 May 14, 2026
e34be7c
docs(plans): cloud-SDK extraction plan — plan-review cycle 2 fixes
intel352 May 14, 2026
bdf0de8
docs(plans): cloud-SDK extraction plan — plan-review cycle 3 PASS + m…
intel352 May 14, 2026
e67757c
chore: lock scope for cloud-sdk-extraction (alignment passed)
intel352 May 14, 2026
cdc2694
refactor(module): split platform_kubernetes_kind.go into _core + _gke
intel352 May 14, 2026
c220beb
docs(module): add file-purpose headers to platform_kubernetes _core/_gke
intel352 May 14, 2026
443f495
docs(module): fix stale 'Requires the Azure SDK' comment on aksBackend
intel352 May 14, 2026
bf203f4
ci(audit): enforce k8s-backend init() partition + run audit on every PR
intel352 May 14, 2026
67c8b0a
docs(plans): IaCStateBackend transport benchmark result — decision pe…
intel352 May 14, 2026
20d7fbb
docs(plans): Task 6 resolved — unary IaCStateBackend LOCKED (operator…
intel352 May 14, 2026
6062520
Revert "chore: lock scope for cloud-sdk-extraction (alignment passed)"
intel352 May 14, 2026
2bbe60f
docs(plans): amend cloud-sdk-extraction plan — PR 6 (ctx) + de-gate PR 4
intel352 May 14, 2026
bfa06e6
chore: re-lock scope for cloud-sdk-extraction (amended — alignment re…
intel352 May 14, 2026
a3759d2
feat(proto): add IaCStateBackend service to iac.proto
intel352 May 14, 2026
fc333a0
test(module): add IaCStateBackend gRPC-vs-in-process benchmark harness
intel352 May 14, 2026
7da06cf
test(wftest): add IaCStateBackend to iacServiceChecks coverage table
intel352 May 14, 2026
6dbf1d2
fix(iac-bench): validate SaveState input, close bufconn, broaden impo…
intel352 May 14, 2026
246d923
Merge remote-tracking branch 'origin/main' into feat/cloud-sdk-extrac…
intel352 May 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions module/benchmark_iac_state_backend_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package module

import (
"context"
"encoding/json"
"net"
"strconv"
"strings"
"testing"

pb "github.com/GoCodeAlone/workflow/plugin/external/proto"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/status"
"google.golang.org/grpc/test/bufconn"
)

// oneMBState builds an IaCState whose JSON payload is ~1 MB (Outputs map padded).
func oneMBState() *IaCState {
big := strings.Repeat("x", 1024)
outputs := make(map[string]any, 1024)
for i := 0; i < 1024; i++ {
outputs["k"+strconv.Itoa(i)] = big
}
return &IaCState{
ResourceID: "bench-resource", ResourceType: "kubernetes", Provider: "azure",
Status: "active", Outputs: outputs, Config: map[string]any{"size": "large"},
CreatedAt: "2026-05-14T00:00:00Z", UpdatedAt: "2026-05-14T00:00:00Z",
}
}

// benchStateToProto — local, self-contained IaCState -> pb.IaCState converter.
// Task 7 replaces this with the production iacStateToProto.
func benchStateToProto(s *IaCState) *pb.IaCState {
outJSON, _ := json.Marshal(s.Outputs)
cfgJSON, _ := json.Marshal(s.Config)
return &pb.IaCState{
ResourceId: s.ResourceID, ResourceType: s.ResourceType, Provider: s.Provider,
Status: s.Status, OutputsJson: outJSON, ConfigJson: cfgJSON,
CreatedAt: s.CreatedAt, UpdatedAt: s.UpdatedAt,
}
}

// benchStateBackendServer wraps an IaCStateStore behind pb.IaCStateBackendServer.
// Task 7 promotes this to the production iacStateBackendServer.
type benchStateBackendServer struct {
pb.UnimplementedIaCStateBackendServer
store IaCStateStore
}

func (s *benchStateBackendServer) GetState(_ context.Context, r *pb.GetStateRequest) (*pb.GetStateResponse, error) {
st, err := s.store.GetState(r.ResourceId)
if err != nil {
return nil, err
}
if st == nil {
return &pb.GetStateResponse{Exists: false}, nil
}
return &pb.GetStateResponse{Exists: true, State: benchStateToProto(st)}, nil
}
func (s *benchStateBackendServer) SaveState(_ context.Context, r *pb.SaveStateRequest) (*pb.SaveStateResponse, error) {
if r.State == nil {
return nil, status.Error(codes.InvalidArgument, "SaveState: request State is nil")
}
var outputs, config map[string]any
if len(r.State.OutputsJson) > 0 {
if err := json.Unmarshal(r.State.OutputsJson, &outputs); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "SaveState: invalid OutputsJson: %v", err)
}
}
if len(r.State.ConfigJson) > 0 {
if err := json.Unmarshal(r.State.ConfigJson, &config); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "SaveState: invalid ConfigJson: %v", err)
}
}
return &pb.SaveStateResponse{}, s.store.SaveState(&IaCState{
ResourceID: r.State.ResourceId, ResourceType: r.State.ResourceType,
Provider: r.State.Provider, Status: r.State.Status, Outputs: outputs, Config: config,
})
Comment thread
intel352 marked this conversation as resolved.
}
func (s *benchStateBackendServer) Lock(_ context.Context, r *pb.LockRequest) (*pb.LockResponse, error) {
return &pb.LockResponse{}, s.store.Lock(r.ResourceId)
}
func (s *benchStateBackendServer) Unlock(_ context.Context, r *pb.UnlockRequest) (*pb.UnlockResponse, error) {
return &pb.UnlockResponse{}, s.store.Unlock(r.ResourceId)
}
func (s *benchStateBackendServer) ListStates(_ context.Context, _ *pb.ListStatesRequest) (*pb.ListStatesResponse, error) {
return &pb.ListStatesResponse{}, nil
}
func (s *benchStateBackendServer) DeleteState(_ context.Context, r *pb.DeleteStateRequest) (*pb.DeleteStateResponse, error) {
return &pb.DeleteStateResponse{}, s.store.DeleteState(r.ResourceId)
}

// BenchmarkIaCStateBackend_InProcess is the baseline: direct IaCStateStore calls.
func BenchmarkIaCStateBackend_InProcess(b *testing.B) {
store := NewMemoryIaCStateStore()
st := oneMBState()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := store.Lock(st.ResourceID); err != nil {
b.Fatal(err)
}
if _, err := store.GetState(st.ResourceID); err != nil {
b.Fatal(err)
}
if err := store.SaveState(st); err != nil {
b.Fatal(err)
}
if err := store.Unlock(st.ResourceID); err != nil {
b.Fatal(err)
}
}
}

// BenchmarkIaCStateBackend_GRPC is the post-extraction path: same store, same
// cycle, but every call crosses a real (in-memory bufconn) gRPC boundary.
func BenchmarkIaCStateBackend_GRPC(b *testing.B) {
// 4 MiB in-memory listener buffer. Note: this sizes the bufconn pipe only;
// gRPC's own max message size is configured separately via dial/server options.
lis := bufconn.Listen(4 << 20)
defer lis.Close()
srv := grpc.NewServer()
pb.RegisterIaCStateBackendServer(srv, &benchStateBackendServer{store: NewMemoryIaCStateStore()})
go func() { _ = srv.Serve(lis) }()
defer srv.Stop()

conn, err := grpc.NewClient("passthrough:///bufnet",
grpc.WithContextDialer(func(ctx context.Context, _ string) (net.Conn, error) { return lis.DialContext(ctx) }),
grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
b.Fatal(err)
}
defer conn.Close()
client := pb.NewIaCStateBackendClient(conn)
st := oneMBState()
pbState := benchStateToProto(st)
ctx := context.Background()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := client.Lock(ctx, &pb.LockRequest{ResourceId: st.ResourceID}); err != nil {
b.Fatal(err)
}
if _, err := client.GetState(ctx, &pb.GetStateRequest{ResourceId: st.ResourceID}); err != nil {
b.Fatal(err)
}
if _, err := client.SaveState(ctx, &pb.SaveStateRequest{State: pbState}); err != nil {
b.Fatal(err)
}
if _, err := client.Unlock(ctx, &pb.UnlockRequest{ResourceId: st.ResourceID}); err != nil {
b.Fatal(err)
}
}
}
Loading
Loading