feat: rewrite pipeline-bridge in Go
Replace Python implementation with Go for smaller container images. Uses handler-base Go module for NATS, health, and telemetry. - main.go: pipeline bridge with Argo/Kubeflow HTTP submission - main_test.go: 8 tests covering helpers and HTTP submit functions - Dockerfile: multi-stage golang:1.25-alpine → scratch - CI: Gitea Actions with lint/test/release/docker/notify
This commit is contained in:
163
main_test.go
Normal file
163
main_test.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStrVal(t *testing.T) {
|
||||
m := map[string]any{"key": "value", "num": 42}
|
||||
if got := strVal(m, "key", ""); got != "value" {
|
||||
t.Errorf("strVal(key) = %q, want %q", got, "value")
|
||||
}
|
||||
if got := strVal(m, "missing", "default"); got != "default" {
|
||||
t.Errorf("strVal(missing) = %q, want %q", got, "default")
|
||||
}
|
||||
if got := strVal(m, "num", "fallback"); got != "fallback" {
|
||||
t.Errorf("strVal(num) = %q, want %q", got, "fallback")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapVal(t *testing.T) {
|
||||
inner := map[string]any{"a": "b"}
|
||||
m := map[string]any{"nested": inner, "scalar": "hi"}
|
||||
got := mapVal(m, "nested")
|
||||
if got["a"] != "b" {
|
||||
t.Errorf("mapVal(nested) = %v, want {a:b}", got)
|
||||
}
|
||||
got2 := mapVal(m, "missing")
|
||||
if len(got2) != 0 {
|
||||
t.Errorf("mapVal(missing) should be empty, got %v", got2)
|
||||
}
|
||||
got3 := mapVal(m, "scalar")
|
||||
if len(got3) != 0 {
|
||||
t.Errorf("mapVal(scalar) should be empty, got %v", got3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEnv(t *testing.T) {
|
||||
t.Setenv("TEST_HOST", "http://test:8080")
|
||||
if got := getEnv("TEST_HOST", "fallback"); got != "http://test:8080" {
|
||||
t.Errorf("getEnv(TEST_HOST) = %q, want %q", got, "http://test:8080")
|
||||
}
|
||||
if got := getEnv("MISSING_VAR_XYZ", "default"); got != "default" {
|
||||
t.Errorf("getEnv(MISSING) = %q, want %q", got, "default")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPipelinesMap(t *testing.T) {
|
||||
expected := []string{"document-ingestion", "batch-inference", "rag-query", "voice-pipeline", "model-evaluation"}
|
||||
for _, name := range expected {
|
||||
if _, ok := pipelines[name]; !ok {
|
||||
t.Errorf("pipeline %q not found in pipelines map", name)
|
||||
}
|
||||
}
|
||||
if got := pipelines["document-ingestion"].Engine; got != "argo" {
|
||||
t.Errorf("document-ingestion engine = %q, want argo", got)
|
||||
}
|
||||
if got := pipelines["rag-query"].Engine; got != "kubeflow" {
|
||||
t.Errorf("rag-query engine = %q, want kubeflow", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubmitArgo(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
t.Errorf("expected POST, got %s", r.Method)
|
||||
}
|
||||
if r.URL.Path != "/api/v1/workflows/ai-ml" {
|
||||
t.Errorf("unexpected path: %s", r.URL.Path)
|
||||
}
|
||||
if r.Header.Get("Content-Type") != "application/json" {
|
||||
t.Errorf("expected application/json content type")
|
||||
}
|
||||
|
||||
var body map[string]any
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
t.Errorf("failed to decode body: %v", err)
|
||||
}
|
||||
wf, ok := body["workflow"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatal("missing workflow key")
|
||||
}
|
||||
meta := wf["metadata"].(map[string]any)
|
||||
if meta["namespace"] != "ai-ml" {
|
||||
t.Errorf("unexpected namespace: %v", meta["namespace"])
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"metadata": map[string]any{"name": "document-ingestion-abc123"},
|
||||
})
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
ctx := t.Context()
|
||||
runID, err := submitArgo(ctx, ts.Client(), ts.URL, "ai-ml", "document-ingestion", map[string]any{
|
||||
"source": "test",
|
||||
}, "req-001")
|
||||
if err != nil {
|
||||
t.Fatalf("submitArgo() error: %v", err)
|
||||
}
|
||||
if runID != "document-ingestion-abc123" {
|
||||
t.Errorf("runID = %q, want %q", runID, "document-ingestion-abc123")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubmitArgoError(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(`{"message":"bad request"}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
ctx := t.Context()
|
||||
_, err := submitArgo(ctx, ts.Client(), ts.URL, "ai-ml", "bad-template", nil, "req-err")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for 400 response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubmitKubeflow(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
t.Errorf("expected POST, got %s", r.Method)
|
||||
}
|
||||
if r.URL.Path != "/apis/v1beta1/runs" {
|
||||
t.Errorf("unexpected path: %s", r.URL.Path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"run": map[string]any{"id": "kf-run-456"},
|
||||
})
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
ctx := t.Context()
|
||||
runID, err := submitKubeflow(ctx, ts.Client(), ts.URL, "rag-pipeline", map[string]any{
|
||||
"query": "test",
|
||||
}, "req-002")
|
||||
if err != nil {
|
||||
t.Fatalf("submitKubeflow() error: %v", err)
|
||||
}
|
||||
if runID != "kf-run-456" {
|
||||
t.Errorf("runID = %q, want %q", runID, "kf-run-456")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubmitKubeflowError(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte("internal error"))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
ctx := t.Context()
|
||||
_, err := submitKubeflow(ctx, ts.Client(), ts.URL, "bad-pipeline", nil, "req-err2")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for 500 response")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user