sigs.k8s.io/external-dns@v0.14.1/provider/infoblox/infoblox_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package infoblox
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/base64"
    23  	"fmt"
    24  	"net/http"
    25  	"net/url"
    26  	"regexp"
    27  	"strings"
    28  	"testing"
    29  
    30  	ibclient "github.com/infobloxopen/infoblox-go-client/v2"
    31  	"github.com/miekg/dns"
    32  	"github.com/stretchr/testify/assert"
    33  
    34  	"sigs.k8s.io/external-dns/endpoint"
    35  	"sigs.k8s.io/external-dns/internal/testutils"
    36  	"sigs.k8s.io/external-dns/plan"
    37  	"sigs.k8s.io/external-dns/provider"
    38  )
    39  
    40  type mockIBConnector struct {
    41  	mockInfobloxZones   *[]ibclient.ZoneAuth
    42  	mockInfobloxObjects *[]ibclient.IBObject
    43  	createdEndpoints    []*endpoint.Endpoint
    44  	deletedEndpoints    []*endpoint.Endpoint
    45  	updatedEndpoints    []*endpoint.Endpoint
    46  	getObjectRequests   []*getObjectRequest
    47  	requestBuilder      ExtendedRequestBuilder
    48  }
    49  
    50  type getObjectRequest struct {
    51  	obj         string
    52  	ref         string
    53  	queryParams string
    54  	url         url.URL
    55  	verified    bool
    56  }
    57  
    58  func (req *getObjectRequest) ExpectRequestURLQueryParam(t *testing.T, name string, value string) *getObjectRequest {
    59  	if req.url.Query().Get(name) != value {
    60  		t.Errorf("Expected GetObject Request URL to contain query parameter %s=%s, Got: %v", name, value, req.url.Query())
    61  	}
    62  
    63  	return req
    64  }
    65  
    66  func (req *getObjectRequest) ExpectNotRequestURLQueryParam(t *testing.T, name string) *getObjectRequest {
    67  	if req.url.Query().Has(name) {
    68  		t.Errorf("Expected GetObject Request URL not to contain query parameter %s, Got: %v", name, req.url.Query())
    69  	}
    70  
    71  	return req
    72  }
    73  
    74  func (client *mockIBConnector) verifyGetObjectRequest(t *testing.T, obj string, ref string, query *map[string]string) *getObjectRequest {
    75  	qp := ""
    76  	if query != nil {
    77  		qp = fmt.Sprint(ibclient.NewQueryParams(false, *query))
    78  	}
    79  
    80  	for _, req := range client.getObjectRequests {
    81  		if !req.verified && req.obj == obj && req.ref == ref && req.queryParams == qp {
    82  			req.verified = true
    83  			return req
    84  		}
    85  	}
    86  
    87  	t.Errorf("Expected GetObject obj=%s, query=%s, ref=%s", obj, qp, ref)
    88  	return &getObjectRequest{}
    89  }
    90  
    91  // verifyNoMoreGetObjectRequests will assert that all "GetObject" calls have been verified.
    92  func (client *mockIBConnector) verifyNoMoreGetObjectRequests(t *testing.T) {
    93  	unverified := []getObjectRequest{}
    94  	for _, req := range client.getObjectRequests {
    95  		if !req.verified {
    96  			unverified = append(unverified, *req)
    97  		}
    98  	}
    99  
   100  	if len(unverified) > 0 {
   101  		b := new(bytes.Buffer)
   102  		for _, req := range unverified {
   103  			fmt.Fprintf(b, "obj=%s, ref=%s, params=%s (url=%s)\n", req.obj, req.ref, req.queryParams, req.url.String())
   104  		}
   105  
   106  		t.Errorf("Unverified GetObject Requests: %v", unverified)
   107  	}
   108  }
   109  
   110  func (client *mockIBConnector) CreateObject(obj ibclient.IBObject) (ref string, err error) {
   111  	switch obj.ObjectType() {
   112  	case "record:a":
   113  		client.createdEndpoints = append(
   114  			client.createdEndpoints,
   115  			endpoint.NewEndpoint(
   116  				*obj.(*ibclient.RecordA).Name,
   117  				endpoint.RecordTypeA,
   118  				*obj.(*ibclient.RecordA).Ipv4Addr,
   119  			),
   120  		)
   121  		ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(*obj.(*ibclient.RecordA).Name)), *obj.(*ibclient.RecordA).Name)
   122  		obj.(*ibclient.RecordA).Ref = ref
   123  	case "record:cname":
   124  		client.createdEndpoints = append(
   125  			client.createdEndpoints,
   126  			endpoint.NewEndpoint(
   127  				*obj.(*ibclient.RecordCNAME).Name,
   128  				endpoint.RecordTypeCNAME,
   129  				*obj.(*ibclient.RecordCNAME).Canonical,
   130  			),
   131  		)
   132  		ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(*obj.(*ibclient.RecordCNAME).Name)), *obj.(*ibclient.RecordCNAME).Name)
   133  		obj.(*ibclient.RecordCNAME).Ref = ref
   134  	case "record:host":
   135  		for _, i := range obj.(*ibclient.HostRecord).Ipv4Addrs {
   136  			client.createdEndpoints = append(
   137  				client.createdEndpoints,
   138  				endpoint.NewEndpoint(
   139  					*obj.(*ibclient.HostRecord).Name,
   140  					endpoint.RecordTypeA,
   141  					*i.Ipv4Addr,
   142  				),
   143  			)
   144  		}
   145  		ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(*obj.(*ibclient.HostRecord).Name)), *obj.(*ibclient.HostRecord).Name)
   146  		obj.(*ibclient.HostRecord).Ref = ref
   147  	case "record:txt":
   148  		client.createdEndpoints = append(
   149  			client.createdEndpoints,
   150  			endpoint.NewEndpoint(
   151  				*obj.(*ibclient.RecordTXT).Name,
   152  				endpoint.RecordTypeTXT,
   153  				*obj.(*ibclient.RecordTXT).Text,
   154  			),
   155  		)
   156  		obj.(*ibclient.RecordTXT).Ref = ref
   157  		ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(*obj.(*ibclient.RecordTXT).Name)), *obj.(*ibclient.RecordTXT).Name)
   158  	case "record:ptr":
   159  		client.createdEndpoints = append(
   160  			client.createdEndpoints,
   161  			endpoint.NewEndpoint(
   162  				*obj.(*ibclient.RecordPTR).PtrdName,
   163  				endpoint.RecordTypePTR,
   164  				*obj.(*ibclient.RecordPTR).Ipv4Addr,
   165  			),
   166  		)
   167  		obj.(*ibclient.RecordPTR).Ref = ref
   168  		reverseAddr, err := dns.ReverseAddr(*obj.(*ibclient.RecordPTR).Ipv4Addr)
   169  		if err != nil {
   170  			return ref, fmt.Errorf("unable to create reverse addr from %s", *obj.(*ibclient.RecordPTR).Ipv4Addr)
   171  		}
   172  		ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(*obj.(*ibclient.RecordPTR).PtrdName)), reverseAddr)
   173  	}
   174  	*client.mockInfobloxObjects = append(
   175  		*client.mockInfobloxObjects,
   176  		obj,
   177  	)
   178  	return ref, nil
   179  }
   180  
   181  func (client *mockIBConnector) GetObject(obj ibclient.IBObject, ref string, queryParams *ibclient.QueryParams, res interface{}) (err error) {
   182  	req := getObjectRequest{
   183  		obj: obj.ObjectType(),
   184  		ref: ref,
   185  	}
   186  	if queryParams != nil {
   187  		req.queryParams = fmt.Sprint(queryParams)
   188  	}
   189  	r, _ := client.requestBuilder.BuildRequest(ibclient.GET, obj, ref, queryParams)
   190  	if r != nil {
   191  		req.url = *r.URL
   192  	}
   193  	client.getObjectRequests = append(client.getObjectRequests, &req)
   194  	switch obj.ObjectType() {
   195  	case "record:a":
   196  		var result []ibclient.RecordA
   197  		for _, object := range *client.mockInfobloxObjects {
   198  			if object.ObjectType() == "record:a" {
   199  				if ref != "" &&
   200  					ref != object.(*ibclient.RecordA).Ref {
   201  					continue
   202  				}
   203  				if obj.(*ibclient.RecordA).Name != nil &&
   204  					*obj.(*ibclient.RecordA).Name != *object.(*ibclient.RecordA).Name {
   205  					continue
   206  				}
   207  				result = append(result, *object.(*ibclient.RecordA))
   208  			}
   209  		}
   210  		*res.(*[]ibclient.RecordA) = result
   211  	case "record:cname":
   212  		var result []ibclient.RecordCNAME
   213  		for _, object := range *client.mockInfobloxObjects {
   214  			if object.ObjectType() == "record:cname" {
   215  				if ref != "" &&
   216  					ref != object.(*ibclient.RecordCNAME).Ref {
   217  					continue
   218  				}
   219  				if obj.(*ibclient.RecordCNAME).Name != nil &&
   220  					*obj.(*ibclient.RecordCNAME).Name != *object.(*ibclient.RecordCNAME).Name {
   221  					continue
   222  				}
   223  				result = append(result, *object.(*ibclient.RecordCNAME))
   224  			}
   225  		}
   226  		*res.(*[]ibclient.RecordCNAME) = result
   227  	case "record:host":
   228  		var result []ibclient.HostRecord
   229  		for _, object := range *client.mockInfobloxObjects {
   230  			if object.ObjectType() == "record:host" {
   231  				if ref != "" &&
   232  					ref != object.(*ibclient.HostRecord).Ref {
   233  					continue
   234  				}
   235  				if obj.(*ibclient.HostRecord).Name != nil &&
   236  					*obj.(*ibclient.HostRecord).Name != *object.(*ibclient.HostRecord).Name {
   237  					continue
   238  				}
   239  				result = append(result, *object.(*ibclient.HostRecord))
   240  			}
   241  		}
   242  		*res.(*[]ibclient.HostRecord) = result
   243  	case "record:txt":
   244  		var result []ibclient.RecordTXT
   245  		for _, object := range *client.mockInfobloxObjects {
   246  			if object.ObjectType() == "record:txt" {
   247  				if ref != "" &&
   248  					ref != object.(*ibclient.RecordTXT).Ref {
   249  					continue
   250  				}
   251  				if obj.(*ibclient.RecordTXT).Name != nil &&
   252  					*obj.(*ibclient.RecordTXT).Name != *object.(*ibclient.RecordTXT).Name {
   253  					continue
   254  				}
   255  				result = append(result, *object.(*ibclient.RecordTXT))
   256  			}
   257  		}
   258  		*res.(*[]ibclient.RecordTXT) = result
   259  	case "record:ptr":
   260  		var result []ibclient.RecordPTR
   261  		for _, object := range *client.mockInfobloxObjects {
   262  			if object.ObjectType() == "record:ptr" {
   263  				if ref != "" &&
   264  					ref != object.(*ibclient.RecordPTR).Ref {
   265  					continue
   266  				}
   267  				if obj.(*ibclient.RecordPTR).PtrdName != nil &&
   268  					*obj.(*ibclient.RecordPTR).PtrdName != *object.(*ibclient.RecordPTR).PtrdName {
   269  					continue
   270  				}
   271  				result = append(result, *object.(*ibclient.RecordPTR))
   272  			}
   273  		}
   274  		*res.(*[]ibclient.RecordPTR) = result
   275  	case "zone_auth":
   276  		*res.(*[]ibclient.ZoneAuth) = *client.mockInfobloxZones
   277  	}
   278  	return
   279  }
   280  
   281  func (client *mockIBConnector) DeleteObject(ref string) (refRes string, err error) {
   282  	re := regexp.MustCompile(`([^/]+)/[^:]+:([^/]+)/default`)
   283  	result := re.FindStringSubmatch(ref)
   284  
   285  	switch result[1] {
   286  	case "record:a":
   287  		var records []ibclient.RecordA
   288  		obj := ibclient.NewEmptyRecordA()
   289  		obj.Name = &result[2]
   290  		client.GetObject(obj, ref, nil, &records)
   291  		for _, record := range records {
   292  			client.deletedEndpoints = append(
   293  				client.deletedEndpoints,
   294  				endpoint.NewEndpoint(
   295  					*record.Name,
   296  					endpoint.RecordTypeA,
   297  					"",
   298  				),
   299  			)
   300  		}
   301  	case "record:cname":
   302  		var records []ibclient.RecordCNAME
   303  		obj := ibclient.NewEmptyRecordCNAME()
   304  		obj.Name = &result[2]
   305  		client.GetObject(obj, ref, nil, &records)
   306  		for _, record := range records {
   307  			client.deletedEndpoints = append(
   308  				client.deletedEndpoints,
   309  				endpoint.NewEndpoint(
   310  					*record.Name,
   311  					endpoint.RecordTypeCNAME,
   312  					"",
   313  				),
   314  			)
   315  		}
   316  	case "record:host":
   317  		var records []ibclient.HostRecord
   318  		obj := ibclient.NewEmptyHostRecord()
   319  		obj.Name = &result[2]
   320  		client.GetObject(obj, ref, nil, &records)
   321  		for _, record := range records {
   322  			client.deletedEndpoints = append(
   323  				client.deletedEndpoints,
   324  				endpoint.NewEndpoint(
   325  					*record.Name,
   326  					endpoint.RecordTypeA,
   327  					"",
   328  				),
   329  			)
   330  		}
   331  	case "record:txt":
   332  		var records []ibclient.RecordTXT
   333  		obj := ibclient.NewEmptyRecordTXT()
   334  		obj.Name = &result[2]
   335  		client.GetObject(obj, ref, nil, &records)
   336  		for _, record := range records {
   337  			client.deletedEndpoints = append(
   338  				client.deletedEndpoints,
   339  				endpoint.NewEndpoint(
   340  					*record.Name,
   341  					endpoint.RecordTypeTXT,
   342  					"",
   343  				),
   344  			)
   345  		}
   346  	case "record:ptr":
   347  		var records []ibclient.RecordPTR
   348  		obj := ibclient.NewEmptyRecordPTR()
   349  		obj.Name = &result[2]
   350  		client.GetObject(obj, ref, nil, &records)
   351  		for _, record := range records {
   352  			client.deletedEndpoints = append(
   353  				client.deletedEndpoints,
   354  				endpoint.NewEndpoint(
   355  					*record.PtrdName,
   356  					endpoint.RecordTypePTR,
   357  					"",
   358  				),
   359  			)
   360  		}
   361  	}
   362  	return "", nil
   363  }
   364  
   365  func (client *mockIBConnector) UpdateObject(obj ibclient.IBObject, ref string) (refRes string, err error) {
   366  	switch obj.ObjectType() {
   367  	case "record:a":
   368  		client.updatedEndpoints = append(
   369  			client.updatedEndpoints,
   370  			endpoint.NewEndpoint(
   371  				*obj.(*ibclient.RecordA).Name,
   372  				*obj.(*ibclient.RecordA).Ipv4Addr,
   373  				endpoint.RecordTypeA,
   374  			),
   375  		)
   376  	case "record:cname":
   377  		client.updatedEndpoints = append(
   378  			client.updatedEndpoints,
   379  			endpoint.NewEndpoint(
   380  				*obj.(*ibclient.RecordCNAME).Name,
   381  				*obj.(*ibclient.RecordCNAME).Canonical,
   382  				endpoint.RecordTypeCNAME,
   383  			),
   384  		)
   385  	case "record:host":
   386  		for _, i := range obj.(*ibclient.HostRecord).Ipv4Addrs {
   387  			client.updatedEndpoints = append(
   388  				client.updatedEndpoints,
   389  				endpoint.NewEndpoint(
   390  					*obj.(*ibclient.HostRecord).Name,
   391  					*i.Ipv4Addr,
   392  					endpoint.RecordTypeA,
   393  				),
   394  			)
   395  		}
   396  	case "record:txt":
   397  		client.updatedEndpoints = append(
   398  			client.updatedEndpoints,
   399  			endpoint.NewEndpoint(
   400  				*obj.(*ibclient.RecordTXT).Name,
   401  				*obj.(*ibclient.RecordTXT).Text,
   402  				endpoint.RecordTypeTXT,
   403  			),
   404  		)
   405  	}
   406  	return "", nil
   407  }
   408  
   409  func createMockInfobloxZone(fqdn string) ibclient.ZoneAuth {
   410  	return ibclient.ZoneAuth{
   411  		Fqdn: fqdn,
   412  	}
   413  }
   414  
   415  func createMockInfobloxObject(name, recordType, value string) ibclient.IBObject {
   416  	ref := fmt.Sprintf("record:%s/%s:%s/default", strings.ToLower(recordType), base64.StdEncoding.EncodeToString([]byte(name)), name)
   417  	switch recordType {
   418  	case endpoint.RecordTypeA:
   419  		obj := ibclient.NewEmptyRecordA()
   420  		obj.Name = &name
   421  		obj.Ref = ref
   422  		obj.Ipv4Addr = &value
   423  		return obj
   424  	case endpoint.RecordTypeCNAME:
   425  		obj := ibclient.NewEmptyRecordCNAME()
   426  		obj.Name = &name
   427  		obj.Ref = ref
   428  		obj.Canonical = &value
   429  		return obj
   430  	case endpoint.RecordTypeTXT:
   431  		obj := ibclient.NewEmptyRecordTXT()
   432  		obj.Name = &name
   433  		obj.Ref = ref
   434  		obj.Text = &value
   435  		return obj
   436  	case "HOST":
   437  		obj := ibclient.NewEmptyHostRecord()
   438  		obj.Name = &name
   439  		obj.Ref = ref
   440  		obj.Ipv4Addrs = []ibclient.HostRecordIpv4Addr{
   441  			{
   442  				Ipv4Addr: &value,
   443  			},
   444  		}
   445  		return obj
   446  	case endpoint.RecordTypePTR:
   447  		obj := ibclient.NewEmptyRecordPTR()
   448  		obj.PtrdName = &name
   449  		obj.Ref = ref
   450  		obj.Ipv4Addr = &value
   451  		return obj
   452  	}
   453  
   454  	return nil
   455  }
   456  
   457  func newInfobloxProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, view string, dryRun bool, createPTR bool, client ibclient.IBConnector) *ProviderConfig {
   458  	return &ProviderConfig{
   459  		client:       client,
   460  		domainFilter: domainFilter,
   461  		zoneIDFilter: zoneIDFilter,
   462  		dryRun:       dryRun,
   463  		createPTR:    createPTR,
   464  		view:         view,
   465  	}
   466  }
   467  
   468  func TestInfobloxRecords(t *testing.T) {
   469  	client := mockIBConnector{
   470  		mockInfobloxZones: &[]ibclient.ZoneAuth{
   471  			createMockInfobloxZone("example.com"),
   472  			createMockInfobloxZone("other.com"),
   473  		},
   474  		mockInfobloxObjects: &[]ibclient.IBObject{
   475  			createMockInfobloxObject("example.com", endpoint.RecordTypeA, "123.123.123.122"),
   476  			createMockInfobloxObject("example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"),
   477  			createMockInfobloxObject("nginx.example.com", endpoint.RecordTypeA, "123.123.123.123"),
   478  			createMockInfobloxObject("nginx.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"),
   479  			createMockInfobloxObject("whitespace.example.com", endpoint.RecordTypeA, "123.123.123.124"),
   480  			createMockInfobloxObject("whitespace.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=white space"),
   481  			createMockInfobloxObject("hack.example.com", endpoint.RecordTypeCNAME, "cerberus.infoblox.com"),
   482  			createMockInfobloxObject("multiple.example.com", endpoint.RecordTypeA, "123.123.123.122"),
   483  			createMockInfobloxObject("multiple.example.com", endpoint.RecordTypeA, "123.123.123.121"),
   484  			createMockInfobloxObject("multiple.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"),
   485  			createMockInfobloxObject("existing.example.com", endpoint.RecordTypeA, "124.1.1.1"),
   486  			createMockInfobloxObject("existing.example.com", endpoint.RecordTypeA, "124.1.1.2"),
   487  			createMockInfobloxObject("existing.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=existing"),
   488  			createMockInfobloxObject("host.example.com", "HOST", "125.1.1.1"),
   489  		},
   490  	}
   491  
   492  	providerCfg := newInfobloxProvider(endpoint.NewDomainFilter([]string{"example.com"}), provider.NewZoneIDFilter([]string{""}), "", true, false, &client)
   493  	actual, err := providerCfg.Records(context.Background())
   494  	if err != nil {
   495  		t.Fatal(err)
   496  	}
   497  	expected := []*endpoint.Endpoint{
   498  		endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "123.123.123.122"),
   499  		endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=default\""),
   500  		endpoint.NewEndpoint("nginx.example.com", endpoint.RecordTypeA, "123.123.123.123"),
   501  		endpoint.NewEndpoint("nginx.example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=default\""),
   502  		endpoint.NewEndpoint("whitespace.example.com", endpoint.RecordTypeA, "123.123.123.124"),
   503  		endpoint.NewEndpoint("whitespace.example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=white space\""),
   504  		endpoint.NewEndpoint("hack.example.com", endpoint.RecordTypeCNAME, "cerberus.infoblox.com"),
   505  		endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeA, "123.123.123.122", "123.123.123.121"),
   506  		endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=default\""),
   507  		endpoint.NewEndpoint("existing.example.com", endpoint.RecordTypeA, "124.1.1.1", "124.1.1.2"),
   508  		endpoint.NewEndpoint("existing.example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=existing\""),
   509  		endpoint.NewEndpoint("host.example.com", endpoint.RecordTypeA, "125.1.1.1"),
   510  	}
   511  	validateEndpoints(t, actual, expected)
   512  	client.verifyGetObjectRequest(t, "zone_auth", "", &map[string]string{}).
   513  		ExpectNotRequestURLQueryParam(t, "view").
   514  		ExpectNotRequestURLQueryParam(t, "zone")
   515  	client.verifyGetObjectRequest(t, "record:a", "", &map[string]string{"zone": "example.com"}).
   516  		ExpectRequestURLQueryParam(t, "zone", "example.com")
   517  	client.verifyGetObjectRequest(t, "record:host", "", &map[string]string{"zone": "example.com"}).
   518  		ExpectRequestURLQueryParam(t, "zone", "example.com")
   519  	client.verifyGetObjectRequest(t, "record:cname", "", &map[string]string{"zone": "example.com"}).
   520  		ExpectRequestURLQueryParam(t, "zone", "example.com")
   521  	client.verifyGetObjectRequest(t, "record:txt", "", &map[string]string{"zone": "example.com"}).
   522  		ExpectRequestURLQueryParam(t, "zone", "example.com")
   523  	client.verifyNoMoreGetObjectRequests(t)
   524  }
   525  
   526  func TestInfobloxRecordsWithView(t *testing.T) {
   527  	client := mockIBConnector{
   528  		mockInfobloxZones: &[]ibclient.ZoneAuth{
   529  			createMockInfobloxZone("foo.example.com"),
   530  			createMockInfobloxZone("bar.example.com"),
   531  		},
   532  		mockInfobloxObjects: &[]ibclient.IBObject{
   533  			createMockInfobloxObject("cat.foo.example.com", endpoint.RecordTypeA, "123.123.123.122"),
   534  			createMockInfobloxObject("dog.bar.example.com", endpoint.RecordTypeA, "123.123.123.123"),
   535  		},
   536  	}
   537  
   538  	providerCfg := newInfobloxProvider(endpoint.NewDomainFilter([]string{"foo.example.com", "bar.example.com"}), provider.NewZoneIDFilter([]string{""}), "Inside", true, false, &client)
   539  	actual, err := providerCfg.Records(context.Background())
   540  	if err != nil {
   541  		t.Fatal(err)
   542  	}
   543  	expected := []*endpoint.Endpoint{
   544  		endpoint.NewEndpoint("cat.foo.example.com", endpoint.RecordTypeA, "123.123.123.122"),
   545  		endpoint.NewEndpoint("dog.bar.example.com", endpoint.RecordTypeA, "123.123.123.123"),
   546  	}
   547  	validateEndpoints(t, actual, expected)
   548  	client.verifyGetObjectRequest(t, "zone_auth", "", &map[string]string{"view": "Inside"}).
   549  		ExpectRequestURLQueryParam(t, "view", "Inside").
   550  		ExpectNotRequestURLQueryParam(t, "zone")
   551  	client.verifyGetObjectRequest(t, "record:a", "", &map[string]string{"zone": "foo.example.com", "view": "Inside"}).
   552  		ExpectRequestURLQueryParam(t, "zone", "foo.example.com").
   553  		ExpectRequestURLQueryParam(t, "view", "Inside")
   554  	client.verifyGetObjectRequest(t, "record:host", "", &map[string]string{"zone": "foo.example.com", "view": "Inside"}).
   555  		ExpectRequestURLQueryParam(t, "zone", "foo.example.com").
   556  		ExpectRequestURLQueryParam(t, "view", "Inside")
   557  	client.verifyGetObjectRequest(t, "record:cname", "", &map[string]string{"zone": "foo.example.com", "view": "Inside"}).
   558  		ExpectRequestURLQueryParam(t, "zone", "foo.example.com").
   559  		ExpectRequestURLQueryParam(t, "view", "Inside")
   560  	client.verifyGetObjectRequest(t, "record:txt", "", &map[string]string{"zone": "foo.example.com", "view": "Inside"}).
   561  		ExpectRequestURLQueryParam(t, "zone", "foo.example.com").
   562  		ExpectRequestURLQueryParam(t, "view", "Inside")
   563  	client.verifyGetObjectRequest(t, "record:a", "", &map[string]string{"zone": "bar.example.com", "view": "Inside"}).
   564  		ExpectRequestURLQueryParam(t, "zone", "bar.example.com").
   565  		ExpectRequestURLQueryParam(t, "view", "Inside")
   566  	client.verifyGetObjectRequest(t, "record:host", "", &map[string]string{"zone": "bar.example.com", "view": "Inside"}).
   567  		ExpectRequestURLQueryParam(t, "zone", "bar.example.com").
   568  		ExpectRequestURLQueryParam(t, "view", "Inside")
   569  	client.verifyGetObjectRequest(t, "record:cname", "", &map[string]string{"zone": "bar.example.com", "view": "Inside"}).
   570  		ExpectRequestURLQueryParam(t, "zone", "bar.example.com").
   571  		ExpectRequestURLQueryParam(t, "view", "Inside")
   572  	client.verifyGetObjectRequest(t, "record:txt", "", &map[string]string{"zone": "bar.example.com", "view": "Inside"}).
   573  		ExpectRequestURLQueryParam(t, "zone", "bar.example.com").
   574  		ExpectRequestURLQueryParam(t, "view", "Inside")
   575  	client.verifyNoMoreGetObjectRequests(t)
   576  }
   577  
   578  func TestInfobloxAdjustEndpoints(t *testing.T) {
   579  	client := mockIBConnector{
   580  		mockInfobloxZones: &[]ibclient.ZoneAuth{
   581  			createMockInfobloxZone("example.com"),
   582  			createMockInfobloxZone("other.com"),
   583  		},
   584  		mockInfobloxObjects: &[]ibclient.IBObject{
   585  			createMockInfobloxObject("example.com", endpoint.RecordTypeA, "123.123.123.122"),
   586  			createMockInfobloxObject("example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"),
   587  			createMockInfobloxObject("hack.example.com", endpoint.RecordTypeCNAME, "cerberus.infoblox.com"),
   588  			createMockInfobloxObject("host.example.com", "HOST", "125.1.1.1"),
   589  		},
   590  	}
   591  
   592  	providerCfg := newInfobloxProvider(endpoint.NewDomainFilter([]string{"example.com"}), provider.NewZoneIDFilter([]string{""}), "", true, true, &client)
   593  	actual, err := providerCfg.Records(context.Background())
   594  	if err != nil {
   595  		t.Fatal(err)
   596  	}
   597  	providerCfg.AdjustEndpoints(actual)
   598  
   599  	expected := []*endpoint.Endpoint{
   600  		endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "123.123.123.122").WithProviderSpecific(providerSpecificInfobloxPtrRecord, "true"),
   601  		endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=default\""),
   602  		endpoint.NewEndpoint("hack.example.com", endpoint.RecordTypeCNAME, "cerberus.infoblox.com"),
   603  		endpoint.NewEndpoint("host.example.com", endpoint.RecordTypeA, "125.1.1.1").WithProviderSpecific(providerSpecificInfobloxPtrRecord, "true"),
   604  	}
   605  	validateEndpoints(t, actual, expected)
   606  }
   607  
   608  func TestInfobloxRecordsReverse(t *testing.T) {
   609  	client := mockIBConnector{
   610  		mockInfobloxZones: &[]ibclient.ZoneAuth{
   611  			createMockInfobloxZone("10.0.0.0/24"),
   612  			createMockInfobloxZone("10.0.1.0/24"),
   613  		},
   614  		mockInfobloxObjects: &[]ibclient.IBObject{
   615  			createMockInfobloxObject("example.com", endpoint.RecordTypePTR, "10.0.0.1"),
   616  			createMockInfobloxObject("example2.com", endpoint.RecordTypePTR, "10.0.0.2"),
   617  		},
   618  	}
   619  
   620  	providerCfg := newInfobloxProvider(endpoint.NewDomainFilter([]string{"10.0.0.0/24"}), provider.NewZoneIDFilter([]string{""}), "", true, true, &client)
   621  	actual, err := providerCfg.Records(context.Background())
   622  	if err != nil {
   623  		t.Fatal(err)
   624  	}
   625  	expected := []*endpoint.Endpoint{
   626  		endpoint.NewEndpoint("example.com", endpoint.RecordTypePTR, "10.0.0.1"),
   627  		endpoint.NewEndpoint("example2.com", endpoint.RecordTypePTR, "10.0.0.2"),
   628  	}
   629  	validateEndpoints(t, actual, expected)
   630  }
   631  
   632  func TestInfobloxApplyChanges(t *testing.T) {
   633  	client := mockIBConnector{}
   634  
   635  	testInfobloxApplyChangesInternal(t, false, false, &client)
   636  
   637  	validateEndpoints(t, client.createdEndpoints, []*endpoint.Endpoint{
   638  		endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "1.2.3.4"),
   639  		endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "tag"),
   640  		endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.4"),
   641  		endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeTXT, "tag"),
   642  		endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeCNAME, "other.com"),
   643  		endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeTXT, "tag"),
   644  		endpoint.NewEndpoint("other.com", endpoint.RecordTypeA, "5.6.7.8"),
   645  		endpoint.NewEndpoint("other.com", endpoint.RecordTypeTXT, "tag"),
   646  		endpoint.NewEndpoint("new.example.com", endpoint.RecordTypeA, "111.222.111.222"),
   647  		endpoint.NewEndpoint("newcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
   648  		endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeA, "1.2.3.4,3.4.5.6,8.9.10.11"),
   649  		endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeTXT, "tag-multiple-A-records"),
   650  	})
   651  
   652  	validateEndpoints(t, client.deletedEndpoints, []*endpoint.Endpoint{
   653  		endpoint.NewEndpoint("old.example.com", endpoint.RecordTypeA, ""),
   654  		endpoint.NewEndpoint("oldcname.example.com", endpoint.RecordTypeCNAME, ""),
   655  		endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypeA, ""),
   656  		endpoint.NewEndpoint("deletedcname.example.com", endpoint.RecordTypeCNAME, ""),
   657  	})
   658  
   659  	validateEndpoints(t, client.updatedEndpoints, []*endpoint.Endpoint{})
   660  }
   661  
   662  func TestInfobloxApplyChangesReverse(t *testing.T) {
   663  	client := mockIBConnector{}
   664  
   665  	testInfobloxApplyChangesInternal(t, false, true, &client)
   666  
   667  	validateEndpoints(t, client.createdEndpoints, []*endpoint.Endpoint{
   668  		endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "1.2.3.4"),
   669  		endpoint.NewEndpoint("example.com", endpoint.RecordTypePTR, "1.2.3.4"),
   670  		endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "tag"),
   671  		endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.4"),
   672  		endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypePTR, "1.2.3.4"),
   673  		endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeTXT, "tag"),
   674  		endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeCNAME, "other.com"),
   675  		endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeTXT, "tag"),
   676  		endpoint.NewEndpoint("other.com", endpoint.RecordTypeA, "5.6.7.8"),
   677  		endpoint.NewEndpoint("other.com", endpoint.RecordTypeTXT, "tag"),
   678  		endpoint.NewEndpoint("new.example.com", endpoint.RecordTypeA, "111.222.111.222"),
   679  		endpoint.NewEndpoint("newcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
   680  		endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeA, "1.2.3.4,3.4.5.6,8.9.10.11"),
   681  		endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeTXT, "tag-multiple-A-records"),
   682  	})
   683  
   684  	validateEndpoints(t, client.deletedEndpoints, []*endpoint.Endpoint{
   685  		endpoint.NewEndpoint("old.example.com", endpoint.RecordTypeA, ""),
   686  		endpoint.NewEndpoint("oldcname.example.com", endpoint.RecordTypeCNAME, ""),
   687  		endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypeA, ""),
   688  		endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypePTR, ""),
   689  		endpoint.NewEndpoint("deletedcname.example.com", endpoint.RecordTypeCNAME, ""),
   690  	})
   691  
   692  	validateEndpoints(t, client.updatedEndpoints, []*endpoint.Endpoint{})
   693  }
   694  
   695  func TestInfobloxApplyChangesDryRun(t *testing.T) {
   696  	client := mockIBConnector{
   697  		mockInfobloxObjects: &[]ibclient.IBObject{},
   698  	}
   699  
   700  	testInfobloxApplyChangesInternal(t, true, false, &client)
   701  
   702  	validateEndpoints(t, client.createdEndpoints, []*endpoint.Endpoint{})
   703  
   704  	validateEndpoints(t, client.deletedEndpoints, []*endpoint.Endpoint{})
   705  
   706  	validateEndpoints(t, client.updatedEndpoints, []*endpoint.Endpoint{})
   707  }
   708  
   709  func testInfobloxApplyChangesInternal(t *testing.T, dryRun, createPTR bool, client ibclient.IBConnector) {
   710  	client.(*mockIBConnector).mockInfobloxZones = &[]ibclient.ZoneAuth{
   711  		createMockInfobloxZone("example.com"),
   712  		createMockInfobloxZone("other.com"),
   713  		createMockInfobloxZone("1.2.3.0/24"),
   714  	}
   715  	client.(*mockIBConnector).mockInfobloxObjects = &[]ibclient.IBObject{
   716  		createMockInfobloxObject("deleted.example.com", endpoint.RecordTypeA, "121.212.121.212"),
   717  		createMockInfobloxObject("deleted.example.com", endpoint.RecordTypeTXT, "test-deleting-txt"),
   718  		createMockInfobloxObject("deleted.example.com", endpoint.RecordTypePTR, "121.212.121.212"),
   719  		createMockInfobloxObject("deletedcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
   720  		createMockInfobloxObject("old.example.com", endpoint.RecordTypeA, "121.212.121.212"),
   721  		createMockInfobloxObject("oldcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
   722  	}
   723  
   724  	providerCfg := newInfobloxProvider(
   725  		endpoint.NewDomainFilter([]string{""}),
   726  		provider.NewZoneIDFilter([]string{""}),
   727  		"",
   728  		dryRun,
   729  		createPTR,
   730  		client,
   731  	)
   732  
   733  	createRecords := []*endpoint.Endpoint{
   734  		endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "1.2.3.4"),
   735  		endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "tag"),
   736  		endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.4"),
   737  		endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeTXT, "tag"),
   738  		endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeCNAME, "other.com"),
   739  		endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeTXT, "tag"),
   740  		endpoint.NewEndpoint("other.com", endpoint.RecordTypeA, "5.6.7.8"),
   741  		endpoint.NewEndpoint("other.com", endpoint.RecordTypeTXT, "tag"),
   742  		endpoint.NewEndpoint("nope.com", endpoint.RecordTypeA, "4.4.4.4"),
   743  		endpoint.NewEndpoint("nope.com", endpoint.RecordTypeTXT, "tag"),
   744  		endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeA, "1.2.3.4,3.4.5.6,8.9.10.11"),
   745  		endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeTXT, "tag-multiple-A-records"),
   746  	}
   747  
   748  	updateOldRecords := []*endpoint.Endpoint{
   749  		endpoint.NewEndpoint("old.example.com", endpoint.RecordTypeA, "121.212.121.212"),
   750  		endpoint.NewEndpoint("oldcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
   751  		endpoint.NewEndpoint("old.nope.com", endpoint.RecordTypeA, "121.212.121.212"),
   752  	}
   753  
   754  	updateNewRecords := []*endpoint.Endpoint{
   755  		endpoint.NewEndpoint("new.example.com", endpoint.RecordTypeA, "111.222.111.222"),
   756  		endpoint.NewEndpoint("newcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
   757  		endpoint.NewEndpoint("new.nope.com", endpoint.RecordTypeA, "222.111.222.111"),
   758  	}
   759  
   760  	deleteRecords := []*endpoint.Endpoint{
   761  		endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypeA, "121.212.121.212"),
   762  		endpoint.NewEndpoint("deletedcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
   763  		endpoint.NewEndpoint("deleted.nope.com", endpoint.RecordTypeA, "222.111.222.111"),
   764  	}
   765  
   766  	if createPTR {
   767  		deleteRecords = append(deleteRecords, endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypePTR, "121.212.121.212"))
   768  	}
   769  
   770  	changes := &plan.Changes{
   771  		Create:    createRecords,
   772  		UpdateNew: updateNewRecords,
   773  		UpdateOld: updateOldRecords,
   774  		Delete:    deleteRecords,
   775  	}
   776  
   777  	if err := providerCfg.ApplyChanges(context.Background(), changes); err != nil {
   778  		t.Fatal(err)
   779  	}
   780  }
   781  
   782  func TestInfobloxZones(t *testing.T) {
   783  	client := mockIBConnector{
   784  		mockInfobloxZones: &[]ibclient.ZoneAuth{
   785  			createMockInfobloxZone("example.com"),
   786  			createMockInfobloxZone("lvl1-1.example.com"),
   787  			createMockInfobloxZone("lvl2-1.lvl1-1.example.com"),
   788  			createMockInfobloxZone("1.2.3.0/24"),
   789  		},
   790  		mockInfobloxObjects: &[]ibclient.IBObject{},
   791  	}
   792  
   793  	providerCfg := newInfobloxProvider(endpoint.NewDomainFilter([]string{"example.com", "1.2.3.0/24"}), provider.NewZoneIDFilter([]string{""}), "", true, false, &client)
   794  	zones, _ := providerCfg.zones()
   795  	var emptyZoneAuth *ibclient.ZoneAuth
   796  	assert.Equal(t, providerCfg.findZone(zones, "example.com").Fqdn, "example.com")
   797  	assert.Equal(t, providerCfg.findZone(zones, "nomatch-example.com"), emptyZoneAuth)
   798  	assert.Equal(t, providerCfg.findZone(zones, "nginx.example.com").Fqdn, "example.com")
   799  	assert.Equal(t, providerCfg.findZone(zones, "lvl1-1.example.com").Fqdn, "lvl1-1.example.com")
   800  	assert.Equal(t, providerCfg.findZone(zones, "lvl1-2.example.com").Fqdn, "example.com")
   801  	assert.Equal(t, providerCfg.findZone(zones, "lvl2-1.lvl1-1.example.com").Fqdn, "lvl2-1.lvl1-1.example.com")
   802  	assert.Equal(t, providerCfg.findZone(zones, "lvl2-2.lvl1-1.example.com").Fqdn, "lvl1-1.example.com")
   803  	assert.Equal(t, providerCfg.findZone(zones, "lvl2-2.lvl1-2.example.com").Fqdn, "example.com")
   804  	assert.Equal(t, providerCfg.findZone(zones, "1.2.3.0/24").Fqdn, "1.2.3.0/24")
   805  }
   806  
   807  func TestInfobloxReverseZones(t *testing.T) {
   808  	client := mockIBConnector{
   809  		mockInfobloxZones: &[]ibclient.ZoneAuth{
   810  			createMockInfobloxZone("example.com"),
   811  			createMockInfobloxZone("1.2.3.0/24"),
   812  			createMockInfobloxZone("10.0.0.0/8"),
   813  		},
   814  		mockInfobloxObjects: &[]ibclient.IBObject{},
   815  	}
   816  
   817  	providerCfg := newInfobloxProvider(endpoint.NewDomainFilter([]string{"example.com", "1.2.3.0/24", "10.0.0.0/8"}), provider.NewZoneIDFilter([]string{""}), "", true, false, &client)
   818  	zones, _ := providerCfg.zones()
   819  	var emptyZoneAuth *ibclient.ZoneAuth
   820  	assert.Equal(t, providerCfg.findReverseZone(zones, "nomatch-example.com"), emptyZoneAuth)
   821  	assert.Equal(t, providerCfg.findReverseZone(zones, "192.168.0.1"), emptyZoneAuth)
   822  	assert.Equal(t, providerCfg.findReverseZone(zones, "1.2.3.4").Fqdn, "1.2.3.0/24")
   823  	assert.Equal(t, providerCfg.findReverseZone(zones, "10.28.29.30").Fqdn, "10.0.0.0/8")
   824  }
   825  
   826  func TestExtendedRequestFDQDRegExBuilder(t *testing.T) {
   827  	hostCfg := ibclient.HostConfig{
   828  		Host:    "localhost",
   829  		Port:    "8080",
   830  		Version: "2.3.1",
   831  	}
   832  
   833  	authCfg := ibclient.AuthConfig{
   834  		Username: "user",
   835  		Password: "abcd",
   836  	}
   837  
   838  	requestBuilder := NewExtendedRequestBuilder(0, "^staging.*test.com$", "")
   839  	requestBuilder.Init(hostCfg, authCfg)
   840  
   841  	obj := ibclient.NewZoneAuth(ibclient.ZoneAuth{})
   842  
   843  	req, _ := requestBuilder.BuildRequest(ibclient.GET, obj, "", &ibclient.QueryParams{})
   844  
   845  	assert.True(t, req.URL.Query().Get("fqdn~") == "^staging.*test.com$")
   846  
   847  	req, _ = requestBuilder.BuildRequest(ibclient.CREATE, obj, "", &ibclient.QueryParams{})
   848  
   849  	assert.True(t, req.URL.Query().Get("fqdn~") == "")
   850  }
   851  
   852  func TestExtendedRequestNameRegExBuilder(t *testing.T) {
   853  	hostCfg := ibclient.HostConfig{
   854  		Host:    "localhost",
   855  		Port:    "8080",
   856  		Version: "2.3.1",
   857  	}
   858  
   859  	authCfg := ibclient.AuthConfig{
   860  		Username: "user",
   861  		Password: "abcd",
   862  	}
   863  
   864  	requestBuilder := NewExtendedRequestBuilder(0, "", "^staging.*test.com$")
   865  	requestBuilder.Init(hostCfg, authCfg)
   866  
   867  	obj := ibclient.NewEmptyRecordCNAME()
   868  
   869  	req, _ := requestBuilder.BuildRequest(ibclient.GET, obj, "", &ibclient.QueryParams{})
   870  
   871  	assert.True(t, req.URL.Query().Get("name~") == "^staging.*test.com$")
   872  
   873  	req, _ = requestBuilder.BuildRequest(ibclient.CREATE, obj, "", &ibclient.QueryParams{})
   874  
   875  	assert.True(t, req.URL.Query().Get("name~") == "")
   876  }
   877  
   878  func TestExtendedRequestMaxResultsBuilder(t *testing.T) {
   879  	hostCfg := ibclient.HostConfig{
   880  		Host:    "localhost",
   881  		Port:    "8080",
   882  		Version: "2.3.1",
   883  	}
   884  
   885  	authCfg := ibclient.AuthConfig{
   886  		Username: "user",
   887  		Password: "abcd",
   888  	}
   889  
   890  	requestBuilder := NewExtendedRequestBuilder(54321, "", "")
   891  	requestBuilder.Init(hostCfg, authCfg)
   892  
   893  	obj := ibclient.NewEmptyRecordCNAME()
   894  	obj.Zone = "foo.bar.com"
   895  
   896  	req, _ := requestBuilder.BuildRequest(ibclient.GET, obj, "", &ibclient.QueryParams{})
   897  
   898  	assert.True(t, req.URL.Query().Get("_max_results") == "54321")
   899  
   900  	req, _ = requestBuilder.BuildRequest(ibclient.CREATE, obj, "", &ibclient.QueryParams{})
   901  
   902  	assert.True(t, req.URL.Query().Get("_max_results") == "")
   903  }
   904  
   905  func TestGetObject(t *testing.T) {
   906  	hostCfg := ibclient.HostConfig{}
   907  	authCfg := ibclient.AuthConfig{}
   908  	transportConfig := ibclient.TransportConfig{}
   909  	requestBuilder := NewExtendedRequestBuilder(1000, "mysite.com", "")
   910  	requestor := mockRequestor{}
   911  	client, _ := ibclient.NewConnector(hostCfg, authCfg, transportConfig, requestBuilder, &requestor)
   912  
   913  	providerConfig := newInfobloxProvider(endpoint.NewDomainFilter([]string{"mysite.com"}), provider.NewZoneIDFilter([]string{""}), "", true, true, client)
   914  
   915  	providerConfig.deleteRecords(infobloxChangeMap{
   916  		"myzone.com": []*endpoint.Endpoint{
   917  			endpoint.NewEndpoint("deletethisrecord.com", endpoint.RecordTypeA, "1.2.3.4"),
   918  		},
   919  	})
   920  
   921  	requestQuery := requestor.request.URL.Query()
   922  	assert.True(t, requestQuery.Has("name"), "Expected the request to filter objects by name")
   923  }
   924  
   925  // Mock requestor that doesn't send request
   926  type mockRequestor struct {
   927  	request *http.Request
   928  }
   929  
   930  func (r *mockRequestor) Init(ibclient.AuthConfig, ibclient.TransportConfig) {}
   931  func (r *mockRequestor) SendRequest(req *http.Request) (res []byte, err error) {
   932  	res = []byte("[{}]")
   933  	r.request = req
   934  	return
   935  }
   936  
   937  func validateEndpoints(t *testing.T, endpoints []*endpoint.Endpoint, expected []*endpoint.Endpoint) {
   938  	assert.True(t, testutils.SameEndpoints(endpoints, expected), "actual and expected endpoints don't match. %s:%s", endpoints, expected)
   939  }