kops/pkg/resources/digitalocean/dns/dns_test.go

464 lines
12 KiB
Go

/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dns
import (
"bytes"
"context"
"errors"
"io/ioutil"
"net/http"
"testing"
"github.com/digitalocean/godo"
"k8s.io/kops/dnsprovider/pkg/dnsprovider/rrstype"
)
type fakeDomainService struct {
listFunc func(ctx context.Context, listOpt *godo.ListOptions) ([]godo.Domain, *godo.Response, error)
getFunc func(ctx context.Context, name string) (*godo.Domain, *godo.Response, error)
createFunc func(ctx context.Context, domainCreateRequest *godo.DomainCreateRequest) (*godo.Domain, *godo.Response, error)
deleteFunc func(ctx context.Context, name string) (*godo.Response, error)
recordsFunc func(ctx context.Context, domain string, listOpts *godo.ListOptions) ([]godo.DomainRecord, *godo.Response, error)
recordFunc func(ctx context.Context, domain string, id int) (*godo.DomainRecord, *godo.Response, error)
deleteRecordFunc func(ctx context.Context, domain string, id int) (*godo.Response, error)
editRecordFunc func(ctx context.Context, domain string, id int, editRequest *godo.DomainRecordEditRequest) (*godo.DomainRecord, *godo.Response, error)
createRecordFunc func(ctx context.Context, domain string, createRequest *godo.DomainRecordEditRequest) (*godo.DomainRecord, *godo.Response, error)
}
func (f *fakeDomainService) List(ctx context.Context, listOpt *godo.ListOptions) ([]godo.Domain, *godo.Response, error) {
return f.listFunc(ctx, listOpt)
}
func (f *fakeDomainService) Get(ctx context.Context, name string) (*godo.Domain, *godo.Response, error) {
return f.getFunc(ctx, name)
}
func (f *fakeDomainService) Create(ctx context.Context, domainCreateRequest *godo.DomainCreateRequest) (*godo.Domain, *godo.Response, error) {
return f.createFunc(ctx, domainCreateRequest)
}
func (f *fakeDomainService) Delete(ctx context.Context, name string) (*godo.Response, error) {
return f.deleteFunc(ctx, name)
}
func (f *fakeDomainService) Records(ctx context.Context, domain string, listOpts *godo.ListOptions) ([]godo.DomainRecord, *godo.Response, error) {
return f.recordsFunc(ctx, domain, listOpts)
}
func (f *fakeDomainService) Record(ctx context.Context, domain string, id int) (*godo.DomainRecord, *godo.Response, error) {
return f.recordFunc(ctx, domain, id)
}
func (f *fakeDomainService) DeleteRecord(ctx context.Context, domain string, id int) (*godo.Response, error) {
return f.deleteRecordFunc(ctx, domain, id)
}
func (f *fakeDomainService) EditRecord(ctx context.Context, domain string,
id int, editRequest *godo.DomainRecordEditRequest) (*godo.DomainRecord, *godo.Response, error) {
return f.editRecordFunc(ctx, domain, id, editRequest)
}
func (f *fakeDomainService) CreateRecord(ctx context.Context, domain string,
createRequest *godo.DomainRecordEditRequest) (*godo.DomainRecord, *godo.Response, error) {
return f.createRecordFunc(ctx, domain, createRequest)
}
func TestZonesList(t *testing.T) {
client := godo.NewClient(nil)
fake := &fakeDomainService{}
// happy path
fake.listFunc = func(ctx context.Context, listOpts *godo.ListOptions) ([]godo.Domain, *godo.Response, error) {
domains := []godo.Domain{
{
Name: "example.com",
},
}
return domains, nil, nil
}
client.Domains = fake
z := &zones{client}
zoneList, err := z.List()
if err != nil {
t.Errorf("error listing zones: %v", err)
}
if len(zoneList) != 1 {
t.Errorf("expected only 1 zone, got %d", len(zoneList))
}
zone := zoneList[0]
if zone.Name() != "example.com" {
t.Errorf("expected example.com as zone name, got: %s", zone.Name())
}
// bad response path
fake.listFunc = func(ctx context.Context, listOpts *godo.ListOptions) ([]godo.Domain, *godo.Response, error) {
domains := []godo.Domain{
{
Name: "example.com",
},
}
return domains, nil, errors.New("internal error!")
}
client.Domains = fake
z = &zones{client}
zoneList, err = z.List()
if err == nil {
t.Errorf("expected non-nil err")
}
if zoneList != nil {
t.Errorf("expected nil zone, got %v", zoneList)
}
// godo client returned error path
fake.listFunc = func(ctx context.Context, listOpts *godo.ListOptions) ([]godo.Domain, *godo.Response, error) {
return nil, nil, errors.New("error!")
}
client.Domains = fake
z = &zones{client}
zoneList, err = z.List()
if err == nil {
t.Errorf("expected non-nil err")
}
if zoneList != nil {
t.Errorf("expected nil zone, got %v", zoneList)
}
}
func TestAdd(t *testing.T) {
client := godo.NewClient(nil)
fake := &fakeDomainService{}
// happy path
fake.createFunc = func(ctx context.Context, domainCreateRequest *godo.DomainCreateRequest) (*godo.Domain, *godo.Response, error) {
domain := &godo.Domain{Name: domainCreateRequest.Name}
resp := &godo.Response{
Response: &http.Response{},
}
resp.StatusCode = http.StatusOK
return domain, resp, nil
}
client.Domains = fake
dnsProvider := NewProvider(client)
zs, _ := dnsProvider.Zones()
inZone := &zone{name: "test", client: client}
outZone, err := zs.Add(inZone)
if outZone.Name() != "test" {
t.Errorf("unexpected zone name: %s", outZone.Name())
}
if err != nil {
t.Errorf("unexpected err: %v", err)
}
// bad status code
fake.createFunc = func(ctx context.Context, domainCreateRequest *godo.DomainCreateRequest) (*godo.Domain, *godo.Response, error) {
domain := &godo.Domain{Name: domainCreateRequest.Name}
return domain, nil, errors.New("bad response!")
}
client.Domains = fake
dnsProvider = NewProvider(client)
zs, _ = dnsProvider.Zones()
inZone = &zone{name: "test", client: client}
outZone, err = zs.Add(inZone)
if outZone != nil {
t.Errorf("expected zone to be nil, got :%v", outZone)
}
if err == nil {
t.Errorf("expected non-nil err: %v", err)
}
// godo returns error
fake.createFunc = func(ctx context.Context, domainCreateRequest *godo.DomainCreateRequest) (*godo.Domain, *godo.Response, error) {
domain := &godo.Domain{Name: domainCreateRequest.Name}
return domain, nil, errors.New("error!")
}
client.Domains = fake
dnsProvider = NewProvider(client)
zs, _ = dnsProvider.Zones()
inZone = &zone{name: "test", client: client}
outZone, err = zs.Add(inZone)
if outZone != nil {
t.Errorf("expected zone to be nil, got :%v", outZone)
}
if err == nil {
t.Errorf("expected non-nil err: %v", err)
}
}
func TestRemove(t *testing.T) {
client := godo.NewClient(nil)
fake := &fakeDomainService{}
// happy path
fake.deleteFunc = func(ctx context.Context, name string) (*godo.Response, error) {
return nil, nil
}
client.Domains = fake
dnsProvider := NewProvider(client)
zs, _ := dnsProvider.Zones()
inZone := &zone{name: "test", client: client}
err := zs.Remove(inZone)
if err != nil {
t.Errorf("unexpected err: %v", err)
}
// bad status code
fake.deleteFunc = func(ctx context.Context, name string) (*godo.Response, error) {
return nil, errors.New("bad response!")
}
client.Domains = fake
dnsProvider = NewProvider(client)
zs, _ = dnsProvider.Zones()
inZone = &zone{name: "test", client: client}
err = zs.Remove(inZone)
if err == nil {
t.Errorf("expected non-nil err: %v", err)
}
// godo returns error
fake.deleteFunc = func(ctx context.Context, name string) (*godo.Response, error) {
resp := &godo.Response{
Response: &http.Response{},
}
resp.StatusCode = http.StatusOK
resp.Body = ioutil.NopCloser(bytes.NewBufferString("error!"))
return resp, errors.New("error!")
}
client.Domains = fake
dnsProvider = NewProvider(client)
zs, _ = dnsProvider.Zones()
inZone = &zone{name: "test", client: client}
err = zs.Remove(inZone)
if err == nil {
t.Errorf("expected non-nil err: %v", err)
}
}
func TestNewZone(t *testing.T) {
client := godo.NewClient(nil)
dnsprovider := NewProvider(client)
zs, _ := dnsprovider.Zones()
zone, err := zs.New("test")
if err != nil {
t.Errorf("error creating zone: %v", err)
}
if zone.Name() != "test" {
t.Errorf("unexpected zone name: %v", zone.Name())
}
}
func TestNewResourceRecordSet(t *testing.T) {
fake := &fakeDomainService{}
fake.recordsFunc = func(ctx context.Context, domain string, listOpts *godo.ListOptions) ([]godo.DomainRecord, *godo.Response, error) {
domainRecords := []godo.DomainRecord{
{
Name: "test",
Data: "127.0.0.1",
TTL: 3600,
Type: "A",
},
}
resp := &godo.Response{
Response: &http.Response{},
}
resp.StatusCode = http.StatusOK
return domainRecords, resp, nil
}
client := godo.NewClient(nil)
client.Domains = fake
dnsprovider := NewProvider(client)
zs, _ := dnsprovider.Zones()
zone, err := zs.New("example.com")
if err != nil {
t.Errorf("error creating zone: %v", err)
}
if zone.Name() != "example.com" {
t.Errorf("unexpected zone name: %v", zone.Name())
}
rrset, _ := zone.ResourceRecordSets()
rrsets, err := rrset.List()
if err != nil {
t.Errorf("error listing resource record sets: %v", err)
}
if len(rrsets) != 1 {
t.Errorf("unexpected number of records: %d", len(rrsets))
}
records, err := rrset.Get("test.example.com")
if err != nil {
t.Errorf("unexpected error getting resource record set: %v", err)
}
if len(records) != 1 {
t.Errorf("unexpected records from resource record set: %d, expected 1 record", len(records))
}
if records[0].Name() != "test.example.com" {
t.Errorf("unexpected record name: %s, expected 'test'", records[0].Name())
}
if len(records[0].Rrdatas()) != 1 {
t.Errorf("unexpected number of resource record data: %d", len(records[0].Rrdatas()))
}
if records[0].Rrdatas()[0] != "127.0.0.1" {
t.Errorf("unexpected resource record data: %s", records[0].Rrdatas()[0])
}
if records[0].Ttl() != 3600 {
t.Errorf("unexpected record TTL: %d, expected 3600", records[0].Ttl())
}
if records[0].Type() != rrstype.A {
t.Errorf("unexpected resource record type: %s, expected %s", records[0].Type(), rrstype.A)
}
}
func TestResourceRecordChangeset(t *testing.T) {
fake := &fakeDomainService{}
fake.recordsFunc = func(ctx context.Context, domain string, listOpts *godo.ListOptions) ([]godo.DomainRecord, *godo.Response, error) {
domainRecords := []godo.DomainRecord{
{
Name: "test",
Data: "127.0.0.1",
TTL: 3600,
Type: "A",
},
{
Name: "to-remove",
Data: "127.0.0.1",
TTL: 3600,
Type: "A",
},
{
Name: "to-upsert",
Data: "127.0.0.1",
TTL: 3600,
Type: "A",
},
}
resp := &godo.Response{
Response: &http.Response{},
}
resp.StatusCode = http.StatusOK
return domainRecords, resp, nil
}
fake.createRecordFunc = func(ctx context.Context, domain string, createRequest *godo.DomainRecordEditRequest) (*godo.DomainRecord, *godo.Response, error) {
resp := &godo.Response{
Response: &http.Response{},
}
resp.StatusCode = http.StatusOK
return &godo.DomainRecord{}, resp, nil
}
fake.deleteRecordFunc = func(ctx context.Context, domain string, id int) (*godo.Response, error) {
resp := &godo.Response{
Response: &http.Response{},
}
resp.StatusCode = http.StatusOK
return resp, nil
}
fake.editRecordFunc = func(ctx context.Context, domain string, id int, editRequest *godo.DomainRecordEditRequest) (*godo.DomainRecord, *godo.Response, error) {
resp := &godo.Response{
Response: &http.Response{},
}
resp.StatusCode = http.StatusOK
return &godo.DomainRecord{}, resp, nil
}
client := godo.NewClient(nil)
client.Domains = fake
dnsprovider := NewProvider(client)
zs, _ := dnsprovider.Zones()
zone, err := zs.New("example.com")
if err != nil {
t.Errorf("error creating zone: %v", err)
}
if zone.Name() != "example.com" {
t.Errorf("unexpected zone name: %v", zone.Name())
}
rrset, _ := zone.ResourceRecordSets()
changeset := rrset.StartChangeset()
if !changeset.IsEmpty() {
t.Error("expected empty changeset")
}
record := rrset.New("to-add", []string{"127.0.0.1"}, 3600, rrstype.A)
changeset.Add(record)
record = rrset.New("to-remove", []string{"127.0.0.1"}, 3600, rrstype.A)
changeset.Remove(record)
record = rrset.New("to-upsert", []string{"127.0.0.1"}, 3600, rrstype.A)
changeset.Upsert(record)
err = changeset.Apply()
if err != nil {
t.Errorf("error applying changeset: %v", err)
}
}