Skip to content

Commit 3d0a0da

Browse files
jsell-rhclaude
andcommitted
test(sdk): cover Runs, streaming client, InsecureSkipVerify, patch JSON
Adds tests for gaps found by coverage audit: - ScheduledSessionAPI.Runs (project-scoped, verifies path and response) - streamingClient initialization (DisableCompression=true) - WithInsecureSkipVerify applies to both httpClient and streamingClient - ScheduledSessionPatch JSON round-trip (all 11 fields, omitempty semantics) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 002e991 commit 3d0a0da

1 file changed

Lines changed: 185 additions & 0 deletions

File tree

components/ambient-sdk/go-sdk/client/extensions_test.go

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,3 +412,188 @@ func TestClientProjectAccessor(t *testing.T) {
412412
t.Errorf("expected project %q, got %q", testProject, c.Project())
413413
}
414414
}
415+
416+
// ---------------------------------------------------------------------------
417+
// ScheduledSession Runs
418+
// ---------------------------------------------------------------------------
419+
420+
func TestScheduledSessionRuns(t *testing.T) {
421+
want := &types.SessionList{
422+
ListMeta: types.ListMeta{Kind: "SessionList", Page: 1, Size: 10, Total: 2},
423+
Items: []types.Session{
424+
{ObjectReference: types.ObjectReference{ID: "sess-run-1"}, Name: "run-1"},
425+
{ObjectReference: types.ObjectReference{ID: "sess-run-2"}, Name: "run-2"},
426+
},
427+
}
428+
429+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
430+
if r.Method != http.MethodGet {
431+
t.Errorf("expected GET, got %s", r.Method)
432+
}
433+
if !strings.HasSuffix(r.URL.Path, "/scheduled-sessions/ss-runs/runs") {
434+
t.Errorf("unexpected path: %s", r.URL.Path)
435+
}
436+
if !strings.Contains(r.URL.Path, "/projects/proj-a/") {
437+
t.Errorf("expected project in path: %s", r.URL.Path)
438+
}
439+
w.Header().Set("Content-Type", "application/json")
440+
w.WriteHeader(http.StatusOK)
441+
_, _ = w.Write(marshalJSON(t, want))
442+
}))
443+
defer srv.Close()
444+
445+
c := newTestClient(t, srv)
446+
got, err := c.ScheduledSessions().Runs(context.Background(), "proj-a", "ss-runs", &types.ListOptions{})
447+
if err != nil {
448+
t.Fatalf("Runs: %v", err)
449+
}
450+
if len(got.Items) != 2 {
451+
t.Errorf("expected 2 runs, got %d", len(got.Items))
452+
}
453+
if got.Items[0].ID != "sess-run-1" {
454+
t.Errorf("unexpected first run: %+v", got.Items[0])
455+
}
456+
}
457+
458+
// ---------------------------------------------------------------------------
459+
// streamingClient initialization
460+
// ---------------------------------------------------------------------------
461+
462+
func TestNewClient_StreamingClientCreated(t *testing.T) {
463+
c, err := NewClient("http://localhost:8080", testToken, testProject)
464+
if err != nil {
465+
t.Fatalf("NewClient: %v", err)
466+
}
467+
if c.streamingClient == nil {
468+
t.Fatal("expected streamingClient to be initialized")
469+
}
470+
tr, ok := c.streamingClient.Transport.(*http.Transport)
471+
if !ok {
472+
t.Fatal("expected streamingClient transport to be *http.Transport")
473+
}
474+
if !tr.DisableCompression {
475+
t.Error("expected streamingClient transport to have DisableCompression=true")
476+
}
477+
}
478+
479+
// ---------------------------------------------------------------------------
480+
// WithInsecureSkipVerify applies to both clients
481+
// ---------------------------------------------------------------------------
482+
483+
func TestWithInsecureSkipVerify_BothClients(t *testing.T) {
484+
c, err := NewClient("http://localhost:8080", testToken, testProject, WithInsecureSkipVerify())
485+
if err != nil {
486+
t.Fatalf("NewClient: %v", err)
487+
}
488+
if !c.insecureSkipVerify {
489+
t.Error("expected insecureSkipVerify=true")
490+
}
491+
492+
checkInsecure := func(name string, hc *http.Client) {
493+
t.Helper()
494+
tr, ok := hc.Transport.(*http.Transport)
495+
if !ok || tr == nil {
496+
t.Fatalf("%s: expected *http.Transport, got %T", name, hc.Transport)
497+
}
498+
if tr.TLSClientConfig == nil {
499+
t.Fatalf("%s: expected TLSClientConfig to be set", name)
500+
}
501+
if !tr.TLSClientConfig.InsecureSkipVerify {
502+
t.Errorf("%s: expected InsecureSkipVerify=true", name)
503+
}
504+
}
505+
checkInsecure("httpClient", c.httpClient)
506+
checkInsecure("streamingClient", c.streamingClient)
507+
}
508+
509+
// ---------------------------------------------------------------------------
510+
// ScheduledSessionPatch JSON round-trip
511+
// ---------------------------------------------------------------------------
512+
513+
func TestScheduledSessionPatch_JSONRoundTrip(t *testing.T) {
514+
enabled := true
515+
timeout := int32(3600)
516+
inactivity := int32(300)
517+
stopOnRun := false
518+
519+
patch := types.ScheduledSessionPatch{
520+
AgentID: strPtr("agent-1"),
521+
Description: strPtr("nightly build"),
522+
Enabled: &enabled,
523+
InactivityTimeout: &inactivity,
524+
Name: strPtr("nightly"),
525+
RunnerType: strPtr("claude"),
526+
Schedule: strPtr("0 2 * * *"),
527+
SessionPrompt: strPtr("run tests"),
528+
StopOnRunFinished: &stopOnRun,
529+
Timeout: &timeout,
530+
Timezone: strPtr("UTC"),
531+
}
532+
533+
b, err := json.Marshal(patch)
534+
if err != nil {
535+
t.Fatalf("marshal: %v", err)
536+
}
537+
538+
var m map[string]any
539+
if err := json.Unmarshal(b, &m); err != nil {
540+
t.Fatalf("unmarshal to map: %v", err)
541+
}
542+
543+
expectedKeys := []string{
544+
"agent_id", "description", "enabled", "inactivity_timeout",
545+
"name", "runner_type", "schedule", "session_prompt",
546+
"stop_on_run_finished", "timeout", "timezone",
547+
}
548+
for _, k := range expectedKeys {
549+
if _, ok := m[k]; !ok {
550+
t.Errorf("missing key %q in marshaled JSON", k)
551+
}
552+
}
553+
if len(m) != len(expectedKeys) {
554+
t.Errorf("expected %d keys, got %d: %v", len(expectedKeys), len(m), m)
555+
}
556+
557+
// Verify false bool is NOT omitted (pointer semantics)
558+
if m["stop_on_run_finished"] != false {
559+
t.Errorf("expected stop_on_run_finished=false, got %v", m["stop_on_run_finished"])
560+
}
561+
562+
// Round-trip back to struct
563+
var decoded types.ScheduledSessionPatch
564+
if err := json.Unmarshal(b, &decoded); err != nil {
565+
t.Fatalf("unmarshal to struct: %v", err)
566+
}
567+
if *decoded.AgentID != "agent-1" {
568+
t.Errorf("agent_id mismatch: %v", decoded.AgentID)
569+
}
570+
if *decoded.Timeout != 3600 {
571+
t.Errorf("timeout mismatch: %v", decoded.Timeout)
572+
}
573+
}
574+
575+
// Omitted fields should not appear in JSON
576+
func TestScheduledSessionPatch_OmitEmpty(t *testing.T) {
577+
patch := types.ScheduledSessionPatch{
578+
Name: strPtr("only-name"),
579+
}
580+
581+
b, err := json.Marshal(patch)
582+
if err != nil {
583+
t.Fatalf("marshal: %v", err)
584+
}
585+
586+
var m map[string]any
587+
if err := json.Unmarshal(b, &m); err != nil {
588+
t.Fatalf("unmarshal: %v", err)
589+
}
590+
591+
if len(m) != 1 {
592+
t.Errorf("expected 1 key (name only), got %d: %v", len(m), m)
593+
}
594+
if m["name"] != "only-name" {
595+
t.Errorf("expected name=only-name, got %v", m["name"])
596+
}
597+
}
598+
599+
func strPtr(s string) *string { return &s }

0 commit comments

Comments
 (0)