initial implementation: encapi ENC server + CLI
Postgres-backed External Node Classifier for Puppet, replacing Cobbler. - encapi HTTP server (chi + pgx): read/write API + two ENC document shapes (reshaped for the exec terminus; cobbler-wire for enc_direct_facts.rb) - encapi-cli: classify/node/role/status CRUD + import-cobbler seeder - pkg/client Go SDK; unit tests across all packages (DB via testcontainers) - Dockerfile (distroless), Makefile, nfpm RPM (encapi-cli + encapi-enc wrapper), Woodpecker CI, docs/cutover.md
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"git.unkin.net/unkin/encapi/pkg/models"
|
||||
)
|
||||
|
||||
func TestPutNodeSendsTokenAndBody(t *testing.T) {
|
||||
var gotAuth, gotMethod, gotPath string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotAuth = r.Header.Get("Authorization")
|
||||
gotMethod = r.Method
|
||||
gotPath = r.URL.Path
|
||||
_, _ = w.Write([]byte(`{"certname":"h1","role":"roles::base","environment":"testing"}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
c := New(srv.URL, "tok")
|
||||
n, err := c.PutNode(context.Background(), &models.Node{Certname: "h1", Role: "roles::base", Environment: "testing"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if gotAuth != "Bearer tok" {
|
||||
t.Errorf("auth = %q", gotAuth)
|
||||
}
|
||||
if gotMethod != http.MethodPut || gotPath != "/api/v1/nodes/h1" {
|
||||
t.Errorf("%s %s", gotMethod, gotPath)
|
||||
}
|
||||
if n.Role != "roles::base" {
|
||||
t.Errorf("node = %+v", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRoleEscapesColons(t *testing.T) {
|
||||
var gotPath string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotPath = r.URL.EscapedPath()
|
||||
_, _ = w.Write([]byte(`{"name":"roles::infra::x"}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
if _, err := New(srv.URL, "").GetRole(context.Background(), "roles::infra::x"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if gotPath != "/api/v1/roles/roles::infra::x" {
|
||||
t.Errorf("path = %q", gotPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorMapping(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = w.Write([]byte(`{"error":"not found"}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
_, err := New(srv.URL, "").GetNode(context.Background(), "ghost")
|
||||
if err == nil || !NotFound(err) {
|
||||
t.Fatalf("err = %v, want NotFound", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestENCReturnsRawYAML(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = w.Write([]byte("classes:\n- roles::base\n"))
|
||||
}))
|
||||
defer srv.Close()
|
||||
b, err := New(srv.URL, "").ENC(context.Background(), "h1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(b) != "classes:\n- roles::base\n" {
|
||||
t.Errorf("enc = %q", b)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user