nikolai.one
● SYS_CONSOLE // type 'help' for commands
Nikolai Systems Terminal v1.0.4 [x86_64-linux]
Type 'help' to see all available commands. Press '~' or ESC to toggle console.
Try: 'whoami', 'articles' or especially 'showoff'
>
MY ARCHIVE Click the book on the shelf to view bio • Move mouse to look • Press ESC to exit
πŸ“– Inspect Book
← All writing

Mocking Agones Game Server SDK for Painless Local Development

#golang #gamedev #kubernetes #agones #testing

Google Cloud and Ubisoft created Agones as an open-source system for running dedicated game servers on Kubernetes. It manages game server lifecycles, matchmaking allocations, autoscaling, and health checking via a gRPC sidecar container.

However, developing a game server locally with the official Agones Go SDK is awkward.

When your game binary calls agonesSDK.Connect(), the SDK attempts to establish a gRPC connection to localhost:9357 (the sidecar). If you are running the game locally on macOS or Linux during rapid development without a full Minikube/Kind cluster running, the initialization immediately fails.

Developers usually end up writing messy wrappers filled with:

if os.Getenv("ENV") != "local" {
    sdk.Health()
}

Spreading environment checks across game loops and networking code makes unit testing impossible and introduces bugs.

The AgonesSDK Interface

To fix this, I created agones-go-mock. It abstracts the entire Agones Go SDK behind a clean interface:

type AgonesSDK interface {
    Ready() error
    Allocate() error
    Shutdown() error
    Health(<-chan bool) error
    SetLabel(key, value string) error
    SetAnnotation(key, value string) error
    GameServer() (*sdk.GameServer, error)
    WatchGameServer(f sdk.GameServerCallback) error
    Alpha() AlphaSDK
    Beta() BetaSDK
}

How to Use It

Instead of creating the concrete SDK directly, you instantiate the client via the factory helper:

import "github.com/kennycoder/agones-go-mock"

func main() {
    // Returns MockSDK if AGONES_ENV=local, otherwise RealSDK
    sdk, err := agonesmock.NewSDK()
    if err != nil {
        log.Fatalf("Failed to initialize SDK: %v", err)
    }

    // Pass interface to your game engine loop
    game := NewGameSession(sdk)
    game.Run()
}

In Local Mode

When you run:

AGONES_ENV=local go run main.go

The mock implementation logs all lifecycle state transitions, player capacity adjustments, and health pings to standard output:

2025/12/05 09:30:00 Initializing MOCK SDK...
[2025-12-05T09:30:00Z] Agones Mock: Ready called
[2025-12-05T09:30:01Z] Agones Mock [Alpha]: SetPlayerCapacity(64)
[2025-12-05T09:30:02Z] Agones Mock: Health ping received

When deployed to production in Kubernetes, you run without AGONES_ENV=local, and the exact same binary connects to the Agones gRPC sidecar seamlessly.