Files
OpenShell/sdk/go/openshell/v1/example_fake_test.go
Roland Huss 5add9df2cd feat(sdk/go)!: replace positional labels with functional Create options (#3198)
* feat(sdk/go)!: replace positional labels with functional Create options

Move labels and annotations from separate parameter positions into
functional options (WithLabels, WithAnnotations) on Create() and
CreateFromTemplate().

Before: Create(ctx, ws, name, spec, labels, CreateOptions{Annotations: ann})
After:  Create(ctx, ws, name, spec, WithLabels(labels), WithAnnotations(ann))

This unifies two resource metadata fields that were inconsistently
placed (labels as positional, annotations in a struct) into a single
extensible options pattern matching the existing LogOption convention.

BREAKING CHANGE: Create() and CreateFromTemplate() signatures changed.
All callers must use WithLabels() and WithAnnotations() functional
options instead of positional labels and CreateOptions struct.

Closes #2807

Signed-off-by: Roland Huß <rhuss@redhat.com>

* fix(sdk/go): ignore nil Create options

Callers of the previous signature passed nil for the positional labels
parameter to create an unlabeled sandbox:

    Create(ctx, ws, name, spec, nil)

That call still compiles against the new variadic signature, because an
untyped nil converts to CreateOption. ApplyCreateOptions then invoked it
and panicked with a nil pointer dereference, so the migration was unsafe
for existing consumers.

Skip nil options in ApplyCreateOptions and cover the legacy trailing-nil
call with regression tests against ApplyCreateOptions directly, the fake
client (Create and CreateFromTemplate), and the gRPC client.

Signed-off-by: Roland Huß <rhuss@redhat.com>

* refactor(sdk/go): apply Create options through the shared options helper

Signed-off-by: Roland Huß <rhuss@redhat.com>

* docs(sdk/go): use WithLabels in CreateSandboxFromTemplate examples

Signed-off-by: Roland Huß <rhuss@redhat.com>

---------

Signed-off-by: Roland Huß <rhuss@redhat.com>
2026-10-16 07:23:42 +00:00

156 lines
3.8 KiB
Go

// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package v1_test
import (
"context"
"fmt"
"log"
v1 "github.com/NVIDIA/OpenShell/sdk/go/openshell/v1"
"github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/fake"
"github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/types"
)
// ExampleNewClient_addSandbox demonstrates pre-seeding a fake client with
// a sandbox fixture.
func ExampleNewClient_addSandbox() {
client := fake.NewClient()
defer client.Close() //nolint:errcheck
// Pre-seed a sandbox that already exists in Ready state
client.AddSandbox("default", &types.Sandbox{
Name: "pre-existing",
Status: types.SandboxStatus{
Phase: types.SandboxReady,
},
ResourceVersion: 5,
})
ctx := context.Background()
sb, err := client.Sandboxes().Get(ctx, "default", "pre-existing")
if err != nil {
log.Fatal(err)
}
fmt.Println("Name:", sb.Name)
fmt.Println("Phase:", sb.Status.Phase)
// Output:
// Name: pre-existing
// Phase: Ready
}
// ExampleNewClient_addProvider demonstrates pre-seeding a fake client with
// a provider fixture.
func ExampleNewClient_addProvider() {
client := fake.NewClient()
defer client.Close() //nolint:errcheck
// Pre-seed a provider
client.AddProvider("default", &types.Provider{
Name: "seeded-provider",
Type: "openai",
})
ctx := context.Background()
providers, err := client.Providers().ListAll(ctx, "default")
if err != nil {
log.Fatal(err)
}
fmt.Println("Count:", len(providers))
fmt.Println("Name:", providers[0].Name)
// Output:
// Count: 1
// Name: seeded-provider
}
// ExampleNewClient_withHealthResult demonstrates configuring the fake
// health sub-client to return a custom result.
func ExampleNewClient_withHealthResult() {
client := fake.NewClient(fake.WithHealthResult(&types.HealthResult{
Healthy: false,
Version: "1.2.3",
}))
defer client.Close() //nolint:errcheck
ctx := context.Background()
result, err := client.Health().Check(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println("Healthy:", result.Healthy)
fmt.Println("Version:", result.Version)
// Output:
// Healthy: false
// Version: 1.2.3
}
// ExampleNewClient_watchEvents demonstrates watching for sandbox events
// using the fake client.
func ExampleNewClient_watchEvents() {
client := fake.NewClient()
defer client.Close() //nolint:errcheck
ctx := context.Background()
// Start watching before creating
watcher, err := client.Sandboxes().Watch(ctx, "default", "my-sandbox")
if err != nil {
log.Fatal(err)
}
defer watcher.Stop()
// Create triggers an ADDED event
_, err = client.Sandboxes().Create(ctx, "default", "my-sandbox", &v1.SandboxSpec{})
if err != nil {
log.Fatal(err)
}
event := <-watcher.ResultChan()
fmt.Println("Type:", event.Type)
fmt.Println("Name:", event.Object.Name)
// Output:
// Type: ADDED
// Name: my-sandbox
}
// ExampleNewClient_stopOnTerminal demonstrates the StopOnTerminal watch
// option that automatically closes the watcher when a sandbox reaches a
// terminal phase.
func ExampleNewClient_stopOnTerminal() {
client := fake.NewClient()
defer client.Close() //nolint:errcheck
ctx := context.Background()
// Watch with StopOnTerminal
watcher, err := client.Sandboxes().Watch(ctx, "default", "my-sandbox", v1.WatchOptions{
StopOnTerminal: true,
})
if err != nil {
log.Fatal(err)
}
// Create and transition to Ready
_, err = client.Sandboxes().Create(ctx, "default", "my-sandbox", &v1.SandboxSpec{})
if err != nil {
log.Fatal(err)
}
_, err = client.Sandboxes().WaitReady(ctx, "default", "my-sandbox")
if err != nil {
log.Fatal(err)
}
// Drain events, channel closes after terminal phase
var count int
for range watcher.ResultChan() {
count++
}
fmt.Println("Events received:", count)
// Output:
// Events received: 2
}