133 lines
4.2 KiB
Go
133 lines
4.2 KiB
Go
package selectel
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/vasyakrg/dns-autoresolver/internal/diff"
|
|
"github.com/vasyakrg/dns-autoresolver/internal/model"
|
|
"github.com/vasyakrg/dns-autoresolver/internal/provider"
|
|
)
|
|
|
|
func creds() provider.Credentials { return provider.Credentials{Secret: "secret-token"} }
|
|
|
|
func newTestClient(h http.Handler) (*Client, *httptest.Server) {
|
|
srv := httptest.NewServer(h)
|
|
return &Client{BaseURL: srv.URL, HTTP: srv.Client()}, srv
|
|
}
|
|
|
|
func TestListZonesSendsTokenAndParses(t *testing.T) {
|
|
var gotToken string
|
|
c, srv := newTestClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotToken = r.Header.Get("X-Auth-Token")
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"result": []map[string]any{
|
|
{"id": "z1", "name": "example.com."},
|
|
{"id": "z2", "name": "test.org."},
|
|
},
|
|
"next_offset": 0,
|
|
})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
zs, err := c.ListZones(context.Background(), creds())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if gotToken != "secret-token" {
|
|
t.Fatalf("token not sent, got %q", gotToken)
|
|
}
|
|
if len(zs) != 2 || zs[0].ID != "z1" || zs[1].Name != "test.org." {
|
|
t.Fatalf("unexpected zones: %+v", zs)
|
|
}
|
|
}
|
|
|
|
func TestGetRecordsMapsRRSet(t *testing.T) {
|
|
c, srv := newTestClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"result": []map[string]any{
|
|
{"id": "r1", "name": "example.com.", "type": "MX", "ttl": 3600,
|
|
"records": []map[string]any{{"content": "10 mx1.example.com.", "disabled": false}}},
|
|
{"id": "r2", "name": "www.example.com.", "type": "A", "ttl": 300,
|
|
"records": []map[string]any{{"content": "1.2.3.4"}, {"content": "5.6.7.8", "disabled": true}}},
|
|
},
|
|
"next_offset": 0,
|
|
})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
recs, err := c.GetRecords(context.Background(), creds(), "z1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(recs) != 2 {
|
|
t.Fatalf("want 2 records, got %d", len(recs))
|
|
}
|
|
var a model.Record
|
|
for _, r := range recs {
|
|
if r.Type == model.A {
|
|
a = r
|
|
}
|
|
}
|
|
// disabled record dropped -> only one value
|
|
if len(a.Values) != 1 || a.Values[0] != "1.2.3.4" {
|
|
t.Fatalf("disabled record must be skipped, got %+v", a.Values)
|
|
}
|
|
}
|
|
|
|
func TestApplyChangesRoutesVerbs(t *testing.T) {
|
|
type call struct{ method, path string }
|
|
var calls []call
|
|
c, srv := newTestClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// GET rrset -> return existing set with ids for update/delete resolution
|
|
if r.Method == http.MethodGet {
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"result": []map[string]any{
|
|
{"id": "up1", "name": "b.example.com.", "type": "A", "ttl": 300,
|
|
"records": []map[string]any{{"content": "9.9.9.9"}}},
|
|
{"id": "del1", "name": "d.example.com.", "type": "A", "ttl": 300,
|
|
"records": []map[string]any{{"content": "4.4.4.4"}}},
|
|
},
|
|
"next_offset": 0,
|
|
})
|
|
return
|
|
}
|
|
calls = append(calls, call{r.Method, r.URL.Path})
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
add := model.Record{Type: model.A, Name: "c.example.com.", TTL: 300, Values: []string{"3.3.3.3"}}
|
|
updDesired := model.Record{Type: model.A, Name: "b.example.com.", TTL: 300, Values: []string{"2.2.2.2"}}
|
|
delActual := model.Record{Type: model.A, Name: "d.example.com.", TTL: 300, Values: []string{"4.4.4.4"}}
|
|
ns := model.Record{Type: model.NS, Name: "example.com.", TTL: 3600, Values: []string{"ns1.example.com."}}
|
|
|
|
cs := diff.Changeset{Diffs: []diff.RecordDiff{
|
|
{Kind: diff.Add, Type: add.Type, Name: add.Name, Desired: &add},
|
|
{Kind: diff.Update, Type: updDesired.Type, Name: updDesired.Name, Desired: &updDesired},
|
|
{Kind: diff.Delete, Type: delActual.Type, Name: delActual.Name, Actual: &delActual},
|
|
{Kind: diff.Update, Type: ns.Type, Name: ns.Name, Desired: &ns, ReadOnly: true}, // must be skipped
|
|
}}
|
|
|
|
if err := c.ApplyChanges(context.Background(), creds(), "z1", cs); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
want := map[string]bool{
|
|
"POST /zones/z1/rrset": true,
|
|
"PATCH /zones/z1/rrset/up1": true,
|
|
"DELETE /zones/z1/rrset/del1": true,
|
|
}
|
|
if len(calls) != len(want) {
|
|
t.Fatalf("want %d calls, got %v", len(want), calls)
|
|
}
|
|
for _, cl := range calls {
|
|
if !want[cl.method+" "+cl.path] {
|
|
t.Fatalf("unexpected call %s %s", cl.method, cl.path)
|
|
}
|
|
}
|
|
}
|