feat: remove domains whose zones vanished at the provider on import

This commit is contained in:
2026-08-19 18:32:10 +07:00
parent e00648baf7
commit 4d05271f10
8 changed files with 310 additions and 37 deletions
+53 -6
View File
@@ -38,8 +38,13 @@ type mockTenantStore struct {
createDomains int
importDomains []store.Domain
importRemoved []store.Domain
importDomainsErr error
importCalled bool
// importDomainsFn, when set, overrides the default fake behavior of
// ImportDomains — used by tests that need to control created/removed
// independently (e.g. TestImportZonesReturnsCreatedAndRemoved).
importDomainsFn func(ctx context.Context, projectID, accountID uuid.UUID, zones []provider.Zone) ([]store.Domain, []store.Domain, error)
setDomainTemplateErr error
@@ -186,10 +191,16 @@ func (m *mockTenantStore) DeleteCustomRecord(_ context.Context, domainID, projec
return m.deleteCustomRecordErr
}
func (m *mockTenantStore) ImportDomains(_ context.Context, projectID, accountID uuid.UUID, zones []provider.Zone) ([]store.Domain, error) {
func (m *mockTenantStore) ImportDomains(ctx context.Context, projectID, accountID uuid.UUID, zones []provider.Zone) ([]store.Domain, []store.Domain, error) {
m.importCalled = true
if m.importDomainsFn != nil {
created, removed, err := m.importDomainsFn(ctx, projectID, accountID, zones)
m.importDomains, m.importRemoved = created, removed
m.domains = append(m.domains, created...)
return created, removed, err
}
if m.importDomainsErr != nil {
return nil, m.importDomainsErr
return nil, nil, m.importDomainsErr
}
out := make([]store.Domain, 0, len(zones))
for _, z := range zones {
@@ -198,7 +209,7 @@ func (m *mockTenantStore) ImportDomains(_ context.Context, projectID, accountID
}
m.domains = append(m.domains, out...)
m.importDomains = out
return out, nil
return out, nil, nil
}
type mockCipher struct{}
@@ -431,12 +442,15 @@ func TestImportZones_CreatesDomainPerZone(t *testing.T) {
if len(ts.importDomains) != 2 {
t.Fatalf("expected 2 domains created via ImportDomains, got %d", len(ts.importDomains))
}
var resp []domainResponse
var resp importResponse
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
t.Fatal(err)
}
if len(resp) != 2 {
t.Fatalf("expected 2 domains in response, got %d", len(resp))
if len(resp.Created) != 2 {
t.Fatalf("expected 2 domains in response, got %d", len(resp.Created))
}
if len(resp.Removed) != 0 {
t.Fatalf("expected 0 removed domains in response, got %d", len(resp.Removed))
}
}
@@ -471,6 +485,39 @@ func TestImportZones_AtomicRollbackOnError(t *testing.T) {
}
}
// TestImportZonesReturnsCreatedAndRemoved covers the sync response shape:
// the endpoint now reports both what appeared (created) and what vanished
// at the provider (removed) rather than a bare array of created domains.
func TestImportZonesReturnsCreatedAndRemoved(t *testing.T) {
a, ts := newTenantTestAPI()
accID := uuid.New()
ts.accounts = []store.Account{{ID: accID, Provider: "selectel", SecretEnc: "ENC(token)"}}
ts.importDomainsFn = func(_ context.Context, projectID, accountID uuid.UUID, zones []provider.Zone) ([]store.Domain, []store.Domain, error) {
return []store.Domain{{ID: uuid.New(), ProjectID: projectID, ProviderAccountID: accountID, ZoneName: "new.example.com.", ZoneID: "z1"}},
[]store.Domain{{ID: uuid.New(), ProjectID: projectID, ProviderAccountID: accountID, ZoneName: "gone.example.com.", ZoneID: "z9"}},
nil
}
router := NewRouter(a)
req := requestWithSessionCookie(http.MethodPost, "/api/v1/projects/"+testPID+"/accounts/"+accID.String()+"/import", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
if w.Code != http.StatusCreated {
t.Fatalf("expected 201, got %d: %s", w.Code, w.Body.String())
}
var got importResponse
if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
t.Fatalf("response must be an object with created/removed: %v (%s)", err, w.Body.String())
}
if len(got.Created) != 1 || got.Created[0].ZoneName != "new.example.com." {
t.Fatalf("unexpected created: %+v", got.Created)
}
if len(got.Removed) != 1 || got.Removed[0].ZoneName != "gone.example.com." {
t.Fatalf("unexpected removed: %+v", got.Removed)
}
}
func TestImportZones_BadAccountUUID(t *testing.T) {
a, _ := newTenantTestAPI()
router := NewRouter(a)