Private
Public Access
feat: initial Go/JS/Rust Origin check-in client SDKs
CI / rust (push) Successful in 3m6s
CI / go (push) Successful in 33s
CI / js (push) Successful in 34s
CI / rust (push) Successful in 3m6s
CI / go (push) Successful in 33s
CI / js (push) Successful in 34s
Standalone clients that resolve a machine unique ID (OS machine ID first, falling back to a generated UUID persisted to disk), detect hostname/IP/ container/orchestrator, and register+re-ping origin.warky.dev's public service-checkin endpoint on a daily interval. Ported from icy2's internal origincheckin package but extended to the full check-in contract and made dependency-light for external reuse. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
package originclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func testConfig(url string) Config {
|
||||
return Config{
|
||||
URL: url,
|
||||
ServiceKey: "test-key",
|
||||
Type: "icy2",
|
||||
Version: "v1.0.0",
|
||||
Name: "icy2-test",
|
||||
Site: "Test Site",
|
||||
Environment: "test",
|
||||
IntervalHours: 24,
|
||||
InstallID: "test-install-id",
|
||||
}
|
||||
}
|
||||
|
||||
func TestNew_RequiresFields(t *testing.T) {
|
||||
_, err := New(Config{})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNew_AppliesDefaults(t *testing.T) {
|
||||
c, err := New(Config{ServiceKey: "k", Type: "t", Version: "v", Name: "n", InstallID: "id"})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, DefaultURL, c.cfg.URL)
|
||||
assert.Equal(t, "go", c.cfg.AppType)
|
||||
assert.Equal(t, DefaultIntervalHours, c.cfg.IntervalHours)
|
||||
assert.Equal(t, "id", c.installID)
|
||||
}
|
||||
|
||||
func TestBuildPayload(t *testing.T) {
|
||||
c, err := New(testConfig("https://example.invalid/checkin"))
|
||||
require.NoError(t, err)
|
||||
|
||||
payload := c.buildPayload()
|
||||
|
||||
assert.Equal(t, "icy2", payload.Type)
|
||||
assert.Equal(t, "go", payload.AppType)
|
||||
assert.Equal(t, "v1.0.0", payload.Version)
|
||||
assert.Equal(t, "icy2-test", payload.Name)
|
||||
assert.Equal(t, "Test Site", payload.Site)
|
||||
assert.Equal(t, "test", payload.Environment)
|
||||
assert.Equal(t, "test-install-id", payload.UniqueInstallID)
|
||||
}
|
||||
|
||||
func TestCheckinOnce_Success(t *testing.T) {
|
||||
var gotKey string
|
||||
var gotBody Payload
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotKey = r.Header.Get("X-Origin-Service-Key")
|
||||
require.NoError(t, json.NewDecoder(r.Body).Decode(&gotBody))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_ = json.NewEncoder(w).Encode(Response{
|
||||
Success: true,
|
||||
ServiceInstanceID: 42,
|
||||
UniqueInstallID: gotBody.UniqueInstallID,
|
||||
Status: "provisioning",
|
||||
PingedAt: "2026-08-01T00:00:00Z",
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
c, err := New(testConfig(server.URL))
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := c.CheckinOnce(t.Context())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "test-key", gotKey)
|
||||
assert.Equal(t, "icy2", gotBody.Type)
|
||||
assert.Equal(t, "icy2-test", gotBody.Name)
|
||||
assert.Equal(t, "test-install-id", gotBody.UniqueInstallID)
|
||||
assert.True(t, resp.Success)
|
||||
assert.Equal(t, int64(42), resp.ServiceInstanceID)
|
||||
}
|
||||
|
||||
func TestCheckinOnce_ServerErrorReturnsError(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
c, err := New(testConfig(server.URL))
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := c.CheckinOnce(t.Context())
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, resp)
|
||||
}
|
||||
|
||||
func TestCheckinOnce_UnreachableDoesNotPanic(t *testing.T) {
|
||||
c, err := New(testConfig("http://127.0.0.1:1"))
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
_, _ = c.CheckinOnce(t.Context())
|
||||
})
|
||||
}
|
||||
|
||||
func TestCheckinOnce_LogsOnFailure(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
cfg := testConfig(server.URL)
|
||||
var warned bool
|
||||
cfg.Logger = LoggerFunc(func(msg string, err error) { warned = true })
|
||||
|
||||
c, err := New(cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _ = c.CheckinOnce(t.Context())
|
||||
assert.True(t, warned)
|
||||
}
|
||||
|
||||
func TestRun_ChecksInImmediatelyThenStopsOnContextDone(t *testing.T) {
|
||||
var calls atomic.Int32
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
calls.Add(1)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_ = json.NewEncoder(w).Encode(Response{Success: true})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
c, err := New(testConfig(server.URL))
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx, cancel := context.WithTimeout(t.Context(), 200*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
c.Run(ctx)
|
||||
|
||||
assert.Equal(t, int32(1), calls.Load())
|
||||
}
|
||||
Reference in New Issue
Block a user