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

     1  /*
     2  Copyright 2022 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 ibmcloud
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/IBM/go-sdk-core/v5/core"
    28  	"github.com/IBM/networking-go-sdk/dnsrecordsv1"
    29  
    30  	"github.com/IBM/networking-go-sdk/dnssvcsv1"
    31  
    32  	. "github.com/onsi/ginkgo"
    33  	"github.com/stretchr/testify/assert"
    34  	"github.com/stretchr/testify/mock"
    35  	"sigs.k8s.io/external-dns/endpoint"
    36  	"sigs.k8s.io/external-dns/plan"
    37  	"sigs.k8s.io/external-dns/provider"
    38  )
    39  
    40  func NewMockIBMCloudDNSAPI() *mockIbmcloudClientInterface {
    41  	//  Setup public example responses
    42  	firstPublicRecord := dnsrecordsv1.DnsrecordDetails{
    43  		ID:      core.StringPtr("123"),
    44  		Name:    core.StringPtr("test.example.com"),
    45  		Type:    core.StringPtr("A"),
    46  		Content: core.StringPtr("1.2.3.4"),
    47  		Proxied: core.BoolPtr(true),
    48  		TTL:     core.Int64Ptr(int64(120)),
    49  	}
    50  	secondPublicRecord := dnsrecordsv1.DnsrecordDetails{
    51  		ID:      core.StringPtr("456"),
    52  		Name:    core.StringPtr("test.example.com"),
    53  		Type:    core.StringPtr("TXT"),
    54  		Proxied: core.BoolPtr(false),
    55  		Content: core.StringPtr("\"heritage=external-dns,external-dns/owner=tower-pdns\""),
    56  		TTL:     core.Int64Ptr(int64(120)),
    57  	}
    58  	publicRecordsResult := []dnsrecordsv1.DnsrecordDetails{firstPublicRecord, secondPublicRecord}
    59  	publicRecordsResultInfo := &dnsrecordsv1.ResultInfo{
    60  		Page:       core.Int64Ptr(int64(1)),
    61  		TotalCount: core.Int64Ptr(int64(1)),
    62  	}
    63  
    64  	publicRecordsResp := &dnsrecordsv1.ListDnsrecordsResp{
    65  		Result:     publicRecordsResult,
    66  		ResultInfo: publicRecordsResultInfo,
    67  	}
    68  	// Setup private example responses
    69  	firstPrivateZone := dnssvcsv1.Dnszone{
    70  		ID:    core.StringPtr("123"),
    71  		Name:  core.StringPtr("example.com"),
    72  		State: core.StringPtr(zoneStatePendingNetwork),
    73  	}
    74  
    75  	secondPrivateZone := dnssvcsv1.Dnszone{
    76  		ID:    core.StringPtr("456"),
    77  		Name:  core.StringPtr("example1.com"),
    78  		State: core.StringPtr(zoneStateActive),
    79  	}
    80  	privateZones := []dnssvcsv1.Dnszone{firstPrivateZone, secondPrivateZone}
    81  	listZonesResp := &dnssvcsv1.ListDnszones{
    82  		Dnszones: privateZones,
    83  	}
    84  	firstPrivateRecord := dnssvcsv1.ResourceRecord{
    85  		ID:    core.StringPtr("123"),
    86  		Name:  core.StringPtr("test.example.com"),
    87  		Type:  core.StringPtr("A"),
    88  		Rdata: map[string]interface{}{"ip": "1.2.3.4"},
    89  		TTL:   core.Int64Ptr(int64(120)),
    90  	}
    91  	secondPrivateRecord := dnssvcsv1.ResourceRecord{
    92  		ID:    core.StringPtr("456"),
    93  		Name:  core.StringPtr("testCNAME.example.com"),
    94  		Type:  core.StringPtr("CNAME"),
    95  		Rdata: map[string]interface{}{"cname": "test.example.com"},
    96  		TTL:   core.Int64Ptr(int64(120)),
    97  	}
    98  	thirdPrivateRecord := dnssvcsv1.ResourceRecord{
    99  		ID:    core.StringPtr("789"),
   100  		Name:  core.StringPtr("test.example.com"),
   101  		Type:  core.StringPtr("TXT"),
   102  		Rdata: map[string]interface{}{"text": "\"heritage=external-dns,external-dns/owner=tower-pdns\""},
   103  		TTL:   core.Int64Ptr(int64(120)),
   104  	}
   105  	privateRecords := []dnssvcsv1.ResourceRecord{firstPrivateRecord, secondPrivateRecord, thirdPrivateRecord}
   106  	privateRecordsResop := &dnssvcsv1.ListResourceRecords{
   107  		ResourceRecords: privateRecords,
   108  		Offset:          core.Int64Ptr(int64(0)),
   109  		TotalCount:      core.Int64Ptr(int64(1)),
   110  	}
   111  
   112  	// Setup record rData
   113  	inputARecord := &dnssvcsv1.ResourceRecordInputRdataRdataARecord{
   114  		Ip: core.StringPtr("1.2.3.4"),
   115  	}
   116  	inputCnameRecord := &dnssvcsv1.ResourceRecordInputRdataRdataCnameRecord{
   117  		Cname: core.StringPtr("test.example.com"),
   118  	}
   119  	inputTxtRecord := &dnssvcsv1.ResourceRecordInputRdataRdataTxtRecord{
   120  		Text: core.StringPtr("test"),
   121  	}
   122  
   123  	updateARecord := &dnssvcsv1.ResourceRecordUpdateInputRdataRdataARecord{
   124  		Ip: core.StringPtr("1.2.3.4"),
   125  	}
   126  	updateCnameRecord := &dnssvcsv1.ResourceRecordUpdateInputRdataRdataCnameRecord{
   127  		Cname: core.StringPtr("test.example.com"),
   128  	}
   129  	updateTxtRecord := &dnssvcsv1.ResourceRecordUpdateInputRdataRdataTxtRecord{
   130  		Text: core.StringPtr("test"),
   131  	}
   132  
   133  	// Setup mock services
   134  	mockDNSClient := &mockIbmcloudClientInterface{}
   135  	mockDNSClient.On("CreateDNSRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
   136  	mockDNSClient.On("UpdateDNSRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
   137  	mockDNSClient.On("DeleteDNSRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
   138  	mockDNSClient.On("ListAllDDNSRecordsWithContext", mock.Anything, mock.Anything).Return(publicRecordsResp, nil, nil)
   139  	mockDNSClient.On("ListDnszonesWithContext", mock.Anything, mock.Anything).Return(listZonesResp, nil, nil)
   140  	mockDNSClient.On("GetDnszoneWithContext", mock.Anything, mock.Anything).Return(&firstPrivateZone, nil, nil)
   141  	mockDNSClient.On("ListResourceRecordsWithContext", mock.Anything, mock.Anything).Return(privateRecordsResop, nil, nil)
   142  	mockDNSClient.On("CreatePermittedNetworkWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
   143  	mockDNSClient.On("CreateResourceRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
   144  	mockDNSClient.On("DeleteResourceRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
   145  	mockDNSClient.On("UpdateResourceRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
   146  	mockDNSClient.On("NewResourceRecordInputRdataRdataARecord", mock.Anything).Return(inputARecord, nil)
   147  	mockDNSClient.On("NewResourceRecordInputRdataRdataCnameRecord", mock.Anything).Return(inputCnameRecord, nil)
   148  	mockDNSClient.On("NewResourceRecordInputRdataRdataTxtRecord", mock.Anything).Return(inputTxtRecord, nil)
   149  	mockDNSClient.On("NewResourceRecordUpdateInputRdataRdataARecord", mock.Anything).Return(updateARecord, nil)
   150  	mockDNSClient.On("NewResourceRecordUpdateInputRdataRdataCnameRecord", mock.Anything).Return(updateCnameRecord, nil)
   151  	mockDNSClient.On("NewResourceRecordUpdateInputRdataRdataTxtRecord", mock.Anything).Return(updateTxtRecord, nil)
   152  
   153  	return mockDNSClient
   154  }
   155  
   156  func newTestIBMCloudProvider(private bool) *IBMCloudProvider {
   157  	mockSource := &mockSource{}
   158  	endpoints := []*endpoint.Endpoint{
   159  		{
   160  			DNSName: "new.example.com",
   161  			Targets: endpoint.Targets{"4.3.2.1"},
   162  			ProviderSpecific: endpoint.ProviderSpecific{
   163  				{
   164  					Name:  "ibmcloud-vpc",
   165  					Value: "crn:v1:staging:public:is:us-south:a/0821fa9f9ebcc7b7c9a0d6e9bf9442a4::vpc:be33cdad-9a03-4bfa-82ca-eadb9f1de688",
   166  				},
   167  			},
   168  		},
   169  	}
   170  	mockSource.On("Endpoints", mock.Anything).Return(endpoints, nil, nil)
   171  
   172  	domainFilterTest := endpoint.NewDomainFilter([]string{"example.com"})
   173  
   174  	return &IBMCloudProvider{
   175  		Client:       NewMockIBMCloudDNSAPI(),
   176  		source:       mockSource,
   177  		domainFilter: domainFilterTest,
   178  		DryRun:       false,
   179  		instanceID:   "test123",
   180  		privateZone:  private,
   181  	}
   182  }
   183  
   184  func TestPublic_Records(t *testing.T) {
   185  	p := newTestIBMCloudProvider(false)
   186  	endpoints, err := p.Records(context.Background())
   187  	if err != nil {
   188  		t.Errorf("Failed to get records: %v", err)
   189  	} else {
   190  		if len(endpoints) != 2 {
   191  			t.Errorf("Incorrect number of records: %d", len(endpoints))
   192  		}
   193  		for _, endpoint := range endpoints {
   194  			t.Logf("Endpoint for %++v", *endpoint)
   195  		}
   196  	}
   197  }
   198  
   199  func TestPrivate_Records(t *testing.T) {
   200  	p := newTestIBMCloudProvider(true)
   201  	endpoints, err := p.Records(context.Background())
   202  	if err != nil {
   203  		t.Errorf("Failed to get records: %v", err)
   204  	} else {
   205  		if len(endpoints) != 3 {
   206  			t.Errorf("Incorrect number of records: %d", len(endpoints))
   207  		}
   208  		for _, endpoint := range endpoints {
   209  			t.Logf("Endpoint for %++v", *endpoint)
   210  		}
   211  	}
   212  }
   213  
   214  func TestPublic_ApplyChanges(t *testing.T) {
   215  	p := newTestIBMCloudProvider(false)
   216  
   217  	changes := plan.Changes{
   218  		Create: []*endpoint.Endpoint{
   219  			{
   220  				DNSName:    "newA.example.com",
   221  				RecordType: "A",
   222  				RecordTTL:  300,
   223  				Targets:    endpoint.NewTargets("4.3.2.1"),
   224  				ProviderSpecific: endpoint.ProviderSpecific{
   225  					{
   226  						Name:  "ibmcloud-proxied",
   227  						Value: "false",
   228  					},
   229  				},
   230  			},
   231  		},
   232  		UpdateOld: []*endpoint.Endpoint{
   233  			{
   234  				DNSName:    "test.example.com",
   235  				RecordType: "A",
   236  				RecordTTL:  180,
   237  				Targets:    endpoint.NewTargets("1.2.3.4"),
   238  				ProviderSpecific: endpoint.ProviderSpecific{
   239  					{
   240  						Name:  "ibmcloud-proxied",
   241  						Value: "false",
   242  					},
   243  				},
   244  			},
   245  		},
   246  		UpdateNew: []*endpoint.Endpoint{
   247  			{
   248  				DNSName:    "test.example.com",
   249  				RecordType: "A",
   250  				RecordTTL:  180,
   251  				Targets:    endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
   252  				ProviderSpecific: endpoint.ProviderSpecific{
   253  					{
   254  						Name:  "ibmcloud-proxied",
   255  						Value: "true",
   256  					},
   257  				},
   258  			},
   259  		},
   260  		Delete: []*endpoint.Endpoint{
   261  			{
   262  				DNSName:    "test.example.com",
   263  				RecordType: "TXT",
   264  				RecordTTL:  300,
   265  				Targets:    endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=tower-pdns\""),
   266  			},
   267  		},
   268  	}
   269  	ctx := context.Background()
   270  	err := p.ApplyChanges(ctx, &changes)
   271  	if err != nil {
   272  		t.Errorf("should not fail, %s", err)
   273  	}
   274  }
   275  
   276  func TestPrivate_ApplyChanges(t *testing.T) {
   277  	p := newTestIBMCloudProvider(true)
   278  
   279  	endpointsCreate, err := p.AdjustEndpoints([]*endpoint.Endpoint{
   280  		{
   281  			DNSName:    "newA.example.com",
   282  			RecordType: "A",
   283  			RecordTTL:  120,
   284  			Targets:    endpoint.NewTargets("4.3.2.1"),
   285  			ProviderSpecific: endpoint.ProviderSpecific{
   286  				{
   287  					Name:  "ibmcloud-vpc",
   288  					Value: "crn:v1:staging:public:is:us-south:a/0821fa9f9ebcc7b7c9a0d6e9bf9442a4::vpc:be33cdad-9a03-4bfa-82ca-eadb9f1de688",
   289  				},
   290  			},
   291  		},
   292  		{
   293  			DNSName:    "newCNAME.example.com",
   294  			RecordType: "CNAME",
   295  			RecordTTL:  180,
   296  			Targets:    endpoint.NewTargets("newA.example.com"),
   297  		},
   298  		{
   299  			DNSName:    "newTXT.example.com",
   300  			RecordType: "TXT",
   301  			RecordTTL:  240,
   302  			Targets:    endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=tower-pdns\""),
   303  		},
   304  	})
   305  	assert.NoError(t, err)
   306  
   307  	endpointsUpdate, err := p.AdjustEndpoints([]*endpoint.Endpoint{
   308  		{
   309  			DNSName:    "test.example.com",
   310  			RecordType: "A",
   311  			RecordTTL:  180,
   312  			Targets:    endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
   313  		},
   314  	})
   315  	assert.NoError(t, err)
   316  
   317  	changes := plan.Changes{
   318  		Create: endpointsCreate,
   319  		UpdateOld: []*endpoint.Endpoint{
   320  			{
   321  				DNSName:    "test.example.com",
   322  				RecordType: "A",
   323  				RecordTTL:  180,
   324  				Targets:    endpoint.NewTargets("1.2.3.4"),
   325  			},
   326  		},
   327  		UpdateNew: endpointsUpdate,
   328  		Delete: []*endpoint.Endpoint{
   329  			{
   330  				DNSName:    "test.example.com",
   331  				RecordType: "TXT",
   332  				RecordTTL:  300,
   333  				Targets:    endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=tower-pdns\""),
   334  			},
   335  		},
   336  	}
   337  	ctx := context.Background()
   338  	err = p.ApplyChanges(ctx, &changes)
   339  	if err != nil {
   340  		t.Errorf("should not fail, %s", err)
   341  	}
   342  }
   343  
   344  func TestAdjustEndpoints(t *testing.T) {
   345  	p := newTestIBMCloudProvider(false)
   346  	endpoints := []*endpoint.Endpoint{
   347  		{
   348  			DNSName:    "test.example.com",
   349  			Targets:    endpoint.Targets{"1.2.3.4"},
   350  			RecordType: endpoint.RecordTypeA,
   351  			RecordTTL:  300,
   352  			Labels:     endpoint.Labels{},
   353  			ProviderSpecific: endpoint.ProviderSpecific{
   354  				{
   355  					Name:  "ibmcloud-proxied",
   356  					Value: "1",
   357  				},
   358  			},
   359  		},
   360  	}
   361  
   362  	ep, err := p.AdjustEndpoints(endpoints)
   363  	assert.NoError(t, err)
   364  
   365  	assert.Equal(t, endpoint.TTL(0), ep[0].RecordTTL)
   366  	assert.Equal(t, "test.example.com", ep[0].DNSName)
   367  	proxied, _ := ep[0].GetProviderSpecificProperty("ibmcloud-proxied")
   368  	assert.Equal(t, "true", proxied)
   369  }
   370  
   371  func TestPrivateZone_withFilterID(t *testing.T) {
   372  	p := newTestIBMCloudProvider(true)
   373  	p.zoneIDFilter = provider.NewZoneIDFilter([]string{"123", "456"})
   374  
   375  	zones, err := p.privateZones(context.Background())
   376  	if err != nil {
   377  		t.Errorf("should not fail, %s", err)
   378  	} else {
   379  		if len(zones) != 2 {
   380  			t.Errorf("Incorrect number of zones: %d", len(zones))
   381  		}
   382  		for _, zone := range zones {
   383  			t.Logf("zone %s", *zone.ID)
   384  		}
   385  	}
   386  }
   387  
   388  func TestPublicConfig_Validate(t *testing.T) {
   389  	// mock http server
   390  	testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   391  		defer GinkgoRecover()
   392  		time.Sleep(0)
   393  
   394  		// Set mock response
   395  		res.Header().Set("Content-type", "application/json")
   396  		res.WriteHeader(200)
   397  		fmt.Fprintf(res, "%s", `{"success": true, "errors": [["Errors"]], "messages": [["Messages"]], "result": [{"id": "123", "created_on": "2014-01-01T05:20:00.12345Z", "modified_on": "2014-01-01T05:20:00.12345Z", "name": "example.com", "original_registrar": "GoDaddy", "original_dnshost": "NameCheap", "status": "active", "paused": false, "original_name_servers": ["ns1.originaldnshost.com"], "name_servers": ["ns001.name.cloud.ibm.com"]}], "result_info": {"page": 1, "per_page": 20, "count": 1, "total_count": 2000}}`)
   398  	}))
   399  	zoneIDFilterTest := provider.NewZoneIDFilter([]string{"123"})
   400  	domainFilterTest := endpoint.NewDomainFilter([]string{"example.com"})
   401  	cfg := &ibmcloudConfig{
   402  		Endpoint: testServer.URL,
   403  		CRN:      "crn:v1:bluemix:public:internet-svcs:global:a/bcf1865e99742d38d2d5fc3fb80a5496:a6338168-9510-4951-9d67-425612de96f0::",
   404  	}
   405  	crn := cfg.CRN
   406  	authenticator := &core.NoAuthAuthenticator{}
   407  	service, isPrivate, err := cfg.Validate(authenticator, domainFilterTest, provider.NewZoneIDFilter([]string{""}))
   408  	assert.NoError(t, err)
   409  	assert.Equal(t, false, isPrivate)
   410  	assert.Equal(t, crn, *service.publicRecordsService.Crn)
   411  	assert.Equal(t, "123", *service.publicRecordsService.ZoneIdentifier)
   412  
   413  	service, isPrivate, err = cfg.Validate(authenticator, endpoint.NewDomainFilter([]string{""}), zoneIDFilterTest)
   414  	assert.NoError(t, err)
   415  	assert.Equal(t, false, isPrivate)
   416  	assert.Equal(t, crn, *service.publicRecordsService.Crn)
   417  	assert.Equal(t, "123", *service.publicRecordsService.ZoneIdentifier)
   418  
   419  	testServer.Close()
   420  }
   421  
   422  func TestPrivateConfig_Validate(t *testing.T) {
   423  	zoneIDFilterTest := provider.NewZoneIDFilter([]string{"123"})
   424  	domainFilterTest := endpoint.NewDomainFilter([]string{"example.com"})
   425  	authenticator := &core.NoAuthAuthenticator{}
   426  	cfg := &ibmcloudConfig{
   427  		Endpoint: "XXX",
   428  		CRN:      "crn:v1:bluemix:public:dns-svcs:global:a/bcf1865e99742d38d2d5fc3fb80a5496:a6338168-9510-4951-9d67-425612de96f0::",
   429  	}
   430  	_, isPrivate, err := cfg.Validate(authenticator, domainFilterTest, zoneIDFilterTest)
   431  	assert.NoError(t, err)
   432  	assert.Equal(t, true, isPrivate)
   433  }
   434  
   435  // mockIbmcloudClientInterface is an autogenerated mock type for the ibmcloudClient type
   436  type mockIbmcloudClientInterface struct {
   437  	mock.Mock
   438  }
   439  
   440  // CreateDNSRecordWithContext provides a mock function with given fields: ctx, createDnsRecordOptions
   441  func (_m *mockIbmcloudClientInterface) CreateDNSRecordWithContext(ctx context.Context, createDnsRecordOptions *dnsrecordsv1.CreateDnsRecordOptions) (*dnsrecordsv1.DnsrecordResp, *core.DetailedResponse, error) {
   442  	ret := _m.Called(ctx, createDnsRecordOptions)
   443  
   444  	var r0 *dnsrecordsv1.DnsrecordResp
   445  	if rf, ok := ret.Get(0).(func(context.Context, *dnsrecordsv1.CreateDnsRecordOptions) *dnsrecordsv1.DnsrecordResp); ok {
   446  		r0 = rf(ctx, createDnsRecordOptions)
   447  	} else {
   448  		if ret.Get(0) != nil {
   449  			r0 = ret.Get(0).(*dnsrecordsv1.DnsrecordResp)
   450  		}
   451  	}
   452  
   453  	var r1 *core.DetailedResponse
   454  	if rf, ok := ret.Get(1).(func(context.Context, *dnsrecordsv1.CreateDnsRecordOptions) *core.DetailedResponse); ok {
   455  		r1 = rf(ctx, createDnsRecordOptions)
   456  	} else {
   457  		if ret.Get(1) != nil {
   458  			r1 = ret.Get(1).(*core.DetailedResponse)
   459  		}
   460  	}
   461  
   462  	var r2 error
   463  	if rf, ok := ret.Get(2).(func(context.Context, *dnsrecordsv1.CreateDnsRecordOptions) error); ok {
   464  		r2 = rf(ctx, createDnsRecordOptions)
   465  	} else {
   466  		r2 = ret.Error(2)
   467  	}
   468  
   469  	return r0, r1, r2
   470  }
   471  
   472  // CreatePermittedNetworkWithContext provides a mock function with given fields: ctx, createPermittedNetworkOptions
   473  func (_m *mockIbmcloudClientInterface) CreatePermittedNetworkWithContext(ctx context.Context, createPermittedNetworkOptions *dnssvcsv1.CreatePermittedNetworkOptions) (*dnssvcsv1.PermittedNetwork, *core.DetailedResponse, error) {
   474  	ret := _m.Called(ctx, createPermittedNetworkOptions)
   475  
   476  	var r0 *dnssvcsv1.PermittedNetwork
   477  	if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.CreatePermittedNetworkOptions) *dnssvcsv1.PermittedNetwork); ok {
   478  		r0 = rf(ctx, createPermittedNetworkOptions)
   479  	} else {
   480  		if ret.Get(0) != nil {
   481  			r0 = ret.Get(0).(*dnssvcsv1.PermittedNetwork)
   482  		}
   483  	}
   484  
   485  	var r1 *core.DetailedResponse
   486  	if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.CreatePermittedNetworkOptions) *core.DetailedResponse); ok {
   487  		r1 = rf(ctx, createPermittedNetworkOptions)
   488  	} else {
   489  		if ret.Get(1) != nil {
   490  			r1 = ret.Get(1).(*core.DetailedResponse)
   491  		}
   492  	}
   493  
   494  	var r2 error
   495  	if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.CreatePermittedNetworkOptions) error); ok {
   496  		r2 = rf(ctx, createPermittedNetworkOptions)
   497  	} else {
   498  		r2 = ret.Error(2)
   499  	}
   500  
   501  	return r0, r1, r2
   502  }
   503  
   504  // CreateResourceRecordWithContext provides a mock function with given fields: ctx, createResourceRecordOptions
   505  func (_m *mockIbmcloudClientInterface) CreateResourceRecordWithContext(ctx context.Context, createResourceRecordOptions *dnssvcsv1.CreateResourceRecordOptions) (*dnssvcsv1.ResourceRecord, *core.DetailedResponse, error) {
   506  	ret := _m.Called(ctx, createResourceRecordOptions)
   507  
   508  	var r0 *dnssvcsv1.ResourceRecord
   509  	if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.CreateResourceRecordOptions) *dnssvcsv1.ResourceRecord); ok {
   510  		r0 = rf(ctx, createResourceRecordOptions)
   511  	} else {
   512  		if ret.Get(0) != nil {
   513  			r0 = ret.Get(0).(*dnssvcsv1.ResourceRecord)
   514  		}
   515  	}
   516  
   517  	var r1 *core.DetailedResponse
   518  	if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.CreateResourceRecordOptions) *core.DetailedResponse); ok {
   519  		r1 = rf(ctx, createResourceRecordOptions)
   520  	} else {
   521  		if ret.Get(1) != nil {
   522  			r1 = ret.Get(1).(*core.DetailedResponse)
   523  		}
   524  	}
   525  
   526  	var r2 error
   527  	if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.CreateResourceRecordOptions) error); ok {
   528  		r2 = rf(ctx, createResourceRecordOptions)
   529  	} else {
   530  		r2 = ret.Error(2)
   531  	}
   532  
   533  	return r0, r1, r2
   534  }
   535  
   536  // DeleteDNSRecordWithContext provides a mock function with given fields: ctx, deleteDnsRecordOptions
   537  func (_m *mockIbmcloudClientInterface) DeleteDNSRecordWithContext(ctx context.Context, deleteDnsRecordOptions *dnsrecordsv1.DeleteDnsRecordOptions) (*dnsrecordsv1.DeleteDnsrecordResp, *core.DetailedResponse, error) {
   538  	ret := _m.Called(ctx, deleteDnsRecordOptions)
   539  
   540  	var r0 *dnsrecordsv1.DeleteDnsrecordResp
   541  	if rf, ok := ret.Get(0).(func(context.Context, *dnsrecordsv1.DeleteDnsRecordOptions) *dnsrecordsv1.DeleteDnsrecordResp); ok {
   542  		r0 = rf(ctx, deleteDnsRecordOptions)
   543  	} else {
   544  		if ret.Get(0) != nil {
   545  			r0 = ret.Get(0).(*dnsrecordsv1.DeleteDnsrecordResp)
   546  		}
   547  	}
   548  
   549  	var r1 *core.DetailedResponse
   550  	if rf, ok := ret.Get(1).(func(context.Context, *dnsrecordsv1.DeleteDnsRecordOptions) *core.DetailedResponse); ok {
   551  		r1 = rf(ctx, deleteDnsRecordOptions)
   552  	} else {
   553  		if ret.Get(1) != nil {
   554  			r1 = ret.Get(1).(*core.DetailedResponse)
   555  		}
   556  	}
   557  
   558  	var r2 error
   559  	if rf, ok := ret.Get(2).(func(context.Context, *dnsrecordsv1.DeleteDnsRecordOptions) error); ok {
   560  		r2 = rf(ctx, deleteDnsRecordOptions)
   561  	} else {
   562  		r2 = ret.Error(2)
   563  	}
   564  
   565  	return r0, r1, r2
   566  }
   567  
   568  // DeleteResourceRecordWithContext provides a mock function with given fields: ctx, deleteResourceRecordOptions
   569  func (_m *mockIbmcloudClientInterface) DeleteResourceRecordWithContext(ctx context.Context, deleteResourceRecordOptions *dnssvcsv1.DeleteResourceRecordOptions) (*core.DetailedResponse, error) {
   570  	ret := _m.Called(ctx, deleteResourceRecordOptions)
   571  
   572  	var r0 *core.DetailedResponse
   573  	if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.DeleteResourceRecordOptions) *core.DetailedResponse); ok {
   574  		r0 = rf(ctx, deleteResourceRecordOptions)
   575  	} else {
   576  		if ret.Get(0) != nil {
   577  			r0 = ret.Get(0).(*core.DetailedResponse)
   578  		}
   579  	}
   580  
   581  	var r1 error
   582  	if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.DeleteResourceRecordOptions) error); ok {
   583  		r1 = rf(ctx, deleteResourceRecordOptions)
   584  	} else {
   585  		r1 = ret.Error(1)
   586  	}
   587  
   588  	return r0, r1
   589  }
   590  
   591  // GetDnszoneWithContext provides a mock function with given fields: ctx, getDnszoneOptions
   592  func (_m *mockIbmcloudClientInterface) GetDnszoneWithContext(ctx context.Context, getDnszoneOptions *dnssvcsv1.GetDnszoneOptions) (*dnssvcsv1.Dnszone, *core.DetailedResponse, error) {
   593  	ret := _m.Called(ctx, getDnszoneOptions)
   594  
   595  	var r0 *dnssvcsv1.Dnszone
   596  	if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.GetDnszoneOptions) *dnssvcsv1.Dnszone); ok {
   597  		r0 = rf(ctx, getDnszoneOptions)
   598  	} else {
   599  		if ret.Get(0) != nil {
   600  			r0 = ret.Get(0).(*dnssvcsv1.Dnszone)
   601  		}
   602  	}
   603  
   604  	var r1 *core.DetailedResponse
   605  	if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.GetDnszoneOptions) *core.DetailedResponse); ok {
   606  		r1 = rf(ctx, getDnszoneOptions)
   607  	} else {
   608  		if ret.Get(1) != nil {
   609  			r1 = ret.Get(1).(*core.DetailedResponse)
   610  		}
   611  	}
   612  
   613  	var r2 error
   614  	if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.GetDnszoneOptions) error); ok {
   615  		r2 = rf(ctx, getDnszoneOptions)
   616  	} else {
   617  		r2 = ret.Error(2)
   618  	}
   619  
   620  	return r0, r1, r2
   621  }
   622  
   623  // ListAllDDNSRecordsWithContext provides a mock function with given fields: ctx, listAllDnsRecordsOptions
   624  func (_m *mockIbmcloudClientInterface) ListAllDDNSRecordsWithContext(ctx context.Context, listAllDnsRecordsOptions *dnsrecordsv1.ListAllDnsRecordsOptions) (*dnsrecordsv1.ListDnsrecordsResp, *core.DetailedResponse, error) {
   625  	ret := _m.Called(ctx, listAllDnsRecordsOptions)
   626  
   627  	var r0 *dnsrecordsv1.ListDnsrecordsResp
   628  	if rf, ok := ret.Get(0).(func(context.Context, *dnsrecordsv1.ListAllDnsRecordsOptions) *dnsrecordsv1.ListDnsrecordsResp); ok {
   629  		r0 = rf(ctx, listAllDnsRecordsOptions)
   630  	} else {
   631  		if ret.Get(0) != nil {
   632  			r0 = ret.Get(0).(*dnsrecordsv1.ListDnsrecordsResp)
   633  		}
   634  	}
   635  
   636  	var r1 *core.DetailedResponse
   637  	if rf, ok := ret.Get(1).(func(context.Context, *dnsrecordsv1.ListAllDnsRecordsOptions) *core.DetailedResponse); ok {
   638  		r1 = rf(ctx, listAllDnsRecordsOptions)
   639  	} else {
   640  		if ret.Get(1) != nil {
   641  			r1 = ret.Get(1).(*core.DetailedResponse)
   642  		}
   643  	}
   644  
   645  	var r2 error
   646  	if rf, ok := ret.Get(2).(func(context.Context, *dnsrecordsv1.ListAllDnsRecordsOptions) error); ok {
   647  		r2 = rf(ctx, listAllDnsRecordsOptions)
   648  	} else {
   649  		r2 = ret.Error(2)
   650  	}
   651  
   652  	return r0, r1, r2
   653  }
   654  
   655  // ListDnszonesWithContext provides a mock function with given fields: ctx, listDnszonesOptions
   656  func (_m *mockIbmcloudClientInterface) ListDnszonesWithContext(ctx context.Context, listDnszonesOptions *dnssvcsv1.ListDnszonesOptions) (*dnssvcsv1.ListDnszones, *core.DetailedResponse, error) {
   657  	ret := _m.Called(ctx, listDnszonesOptions)
   658  
   659  	var r0 *dnssvcsv1.ListDnszones
   660  	if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.ListDnszonesOptions) *dnssvcsv1.ListDnszones); ok {
   661  		r0 = rf(ctx, listDnszonesOptions)
   662  	} else {
   663  		if ret.Get(0) != nil {
   664  			r0 = ret.Get(0).(*dnssvcsv1.ListDnszones)
   665  		}
   666  	}
   667  
   668  	var r1 *core.DetailedResponse
   669  	if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.ListDnszonesOptions) *core.DetailedResponse); ok {
   670  		r1 = rf(ctx, listDnszonesOptions)
   671  	} else {
   672  		if ret.Get(1) != nil {
   673  			r1 = ret.Get(1).(*core.DetailedResponse)
   674  		}
   675  	}
   676  
   677  	var r2 error
   678  	if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.ListDnszonesOptions) error); ok {
   679  		r2 = rf(ctx, listDnszonesOptions)
   680  	} else {
   681  		r2 = ret.Error(2)
   682  	}
   683  
   684  	return r0, r1, r2
   685  }
   686  
   687  // ListResourceRecordsWithContext provides a mock function with given fields: ctx, listResourceRecordsOptions
   688  func (_m *mockIbmcloudClientInterface) ListResourceRecordsWithContext(ctx context.Context, listResourceRecordsOptions *dnssvcsv1.ListResourceRecordsOptions) (*dnssvcsv1.ListResourceRecords, *core.DetailedResponse, error) {
   689  	ret := _m.Called(ctx, listResourceRecordsOptions)
   690  
   691  	var r0 *dnssvcsv1.ListResourceRecords
   692  	if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.ListResourceRecordsOptions) *dnssvcsv1.ListResourceRecords); ok {
   693  		r0 = rf(ctx, listResourceRecordsOptions)
   694  	} else {
   695  		if ret.Get(0) != nil {
   696  			r0 = ret.Get(0).(*dnssvcsv1.ListResourceRecords)
   697  		}
   698  	}
   699  
   700  	var r1 *core.DetailedResponse
   701  	if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.ListResourceRecordsOptions) *core.DetailedResponse); ok {
   702  		r1 = rf(ctx, listResourceRecordsOptions)
   703  	} else {
   704  		if ret.Get(1) != nil {
   705  			r1 = ret.Get(1).(*core.DetailedResponse)
   706  		}
   707  	}
   708  
   709  	var r2 error
   710  	if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.ListResourceRecordsOptions) error); ok {
   711  		r2 = rf(ctx, listResourceRecordsOptions)
   712  	} else {
   713  		r2 = ret.Error(2)
   714  	}
   715  
   716  	return r0, r1, r2
   717  }
   718  
   719  // NewResourceRecordInputRdataRdataARecord provides a mock function with given fields: ip
   720  func (_m *mockIbmcloudClientInterface) NewResourceRecordInputRdataRdataARecord(ip string) (*dnssvcsv1.ResourceRecordInputRdataRdataARecord, error) {
   721  	ret := _m.Called(ip)
   722  
   723  	var r0 *dnssvcsv1.ResourceRecordInputRdataRdataARecord
   724  	if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordInputRdataRdataARecord); ok {
   725  		r0 = rf(ip)
   726  	} else {
   727  		if ret.Get(0) != nil {
   728  			r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordInputRdataRdataARecord)
   729  		}
   730  	}
   731  
   732  	var r1 error
   733  	if rf, ok := ret.Get(1).(func(string) error); ok {
   734  		r1 = rf(ip)
   735  	} else {
   736  		r1 = ret.Error(1)
   737  	}
   738  
   739  	return r0, r1
   740  }
   741  
   742  // NewResourceRecordInputRdataRdataCnameRecord provides a mock function with given fields: cname
   743  func (_m *mockIbmcloudClientInterface) NewResourceRecordInputRdataRdataCnameRecord(cname string) (*dnssvcsv1.ResourceRecordInputRdataRdataCnameRecord, error) {
   744  	ret := _m.Called(cname)
   745  
   746  	var r0 *dnssvcsv1.ResourceRecordInputRdataRdataCnameRecord
   747  	if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordInputRdataRdataCnameRecord); ok {
   748  		r0 = rf(cname)
   749  	} else {
   750  		if ret.Get(0) != nil {
   751  			r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordInputRdataRdataCnameRecord)
   752  		}
   753  	}
   754  
   755  	var r1 error
   756  	if rf, ok := ret.Get(1).(func(string) error); ok {
   757  		r1 = rf(cname)
   758  	} else {
   759  		r1 = ret.Error(1)
   760  	}
   761  
   762  	return r0, r1
   763  }
   764  
   765  // NewResourceRecordInputRdataRdataTxtRecord provides a mock function with given fields: text
   766  func (_m *mockIbmcloudClientInterface) NewResourceRecordInputRdataRdataTxtRecord(text string) (*dnssvcsv1.ResourceRecordInputRdataRdataTxtRecord, error) {
   767  	ret := _m.Called(text)
   768  
   769  	var r0 *dnssvcsv1.ResourceRecordInputRdataRdataTxtRecord
   770  	if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordInputRdataRdataTxtRecord); ok {
   771  		r0 = rf(text)
   772  	} else {
   773  		if ret.Get(0) != nil {
   774  			r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordInputRdataRdataTxtRecord)
   775  		}
   776  	}
   777  
   778  	var r1 error
   779  	if rf, ok := ret.Get(1).(func(string) error); ok {
   780  		r1 = rf(text)
   781  	} else {
   782  		r1 = ret.Error(1)
   783  	}
   784  
   785  	return r0, r1
   786  }
   787  
   788  // NewResourceRecordUpdateInputRdataRdataARecord provides a mock function with given fields: ip
   789  func (_m *mockIbmcloudClientInterface) NewResourceRecordUpdateInputRdataRdataARecord(ip string) (*dnssvcsv1.ResourceRecordUpdateInputRdataRdataARecord, error) {
   790  	ret := _m.Called(ip)
   791  
   792  	var r0 *dnssvcsv1.ResourceRecordUpdateInputRdataRdataARecord
   793  	if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordUpdateInputRdataRdataARecord); ok {
   794  		r0 = rf(ip)
   795  	} else {
   796  		if ret.Get(0) != nil {
   797  			r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordUpdateInputRdataRdataARecord)
   798  		}
   799  	}
   800  
   801  	var r1 error
   802  	if rf, ok := ret.Get(1).(func(string) error); ok {
   803  		r1 = rf(ip)
   804  	} else {
   805  		r1 = ret.Error(1)
   806  	}
   807  
   808  	return r0, r1
   809  }
   810  
   811  // NewResourceRecordUpdateInputRdataRdataCnameRecord provides a mock function with given fields: cname
   812  func (_m *mockIbmcloudClientInterface) NewResourceRecordUpdateInputRdataRdataCnameRecord(cname string) (*dnssvcsv1.ResourceRecordUpdateInputRdataRdataCnameRecord, error) {
   813  	ret := _m.Called(cname)
   814  
   815  	var r0 *dnssvcsv1.ResourceRecordUpdateInputRdataRdataCnameRecord
   816  	if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordUpdateInputRdataRdataCnameRecord); ok {
   817  		r0 = rf(cname)
   818  	} else {
   819  		if ret.Get(0) != nil {
   820  			r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordUpdateInputRdataRdataCnameRecord)
   821  		}
   822  	}
   823  
   824  	var r1 error
   825  	if rf, ok := ret.Get(1).(func(string) error); ok {
   826  		r1 = rf(cname)
   827  	} else {
   828  		r1 = ret.Error(1)
   829  	}
   830  
   831  	return r0, r1
   832  }
   833  
   834  // NewResourceRecordUpdateInputRdataRdataTxtRecord provides a mock function with given fields: text
   835  func (_m *mockIbmcloudClientInterface) NewResourceRecordUpdateInputRdataRdataTxtRecord(text string) (*dnssvcsv1.ResourceRecordUpdateInputRdataRdataTxtRecord, error) {
   836  	ret := _m.Called(text)
   837  
   838  	var r0 *dnssvcsv1.ResourceRecordUpdateInputRdataRdataTxtRecord
   839  	if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordUpdateInputRdataRdataTxtRecord); ok {
   840  		r0 = rf(text)
   841  	} else {
   842  		if ret.Get(0) != nil {
   843  			r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordUpdateInputRdataRdataTxtRecord)
   844  		}
   845  	}
   846  
   847  	var r1 error
   848  	if rf, ok := ret.Get(1).(func(string) error); ok {
   849  		r1 = rf(text)
   850  	} else {
   851  		r1 = ret.Error(1)
   852  	}
   853  
   854  	return r0, r1
   855  }
   856  
   857  // UpdateDNSRecordWithContext provides a mock function with given fields: ctx, updateDnsRecordOptions
   858  func (_m *mockIbmcloudClientInterface) UpdateDNSRecordWithContext(ctx context.Context, updateDnsRecordOptions *dnsrecordsv1.UpdateDnsRecordOptions) (*dnsrecordsv1.DnsrecordResp, *core.DetailedResponse, error) {
   859  	ret := _m.Called(ctx, updateDnsRecordOptions)
   860  
   861  	var r0 *dnsrecordsv1.DnsrecordResp
   862  	if rf, ok := ret.Get(0).(func(context.Context, *dnsrecordsv1.UpdateDnsRecordOptions) *dnsrecordsv1.DnsrecordResp); ok {
   863  		r0 = rf(ctx, updateDnsRecordOptions)
   864  	} else {
   865  		if ret.Get(0) != nil {
   866  			r0 = ret.Get(0).(*dnsrecordsv1.DnsrecordResp)
   867  		}
   868  	}
   869  
   870  	var r1 *core.DetailedResponse
   871  	if rf, ok := ret.Get(1).(func(context.Context, *dnsrecordsv1.UpdateDnsRecordOptions) *core.DetailedResponse); ok {
   872  		r1 = rf(ctx, updateDnsRecordOptions)
   873  	} else {
   874  		if ret.Get(1) != nil {
   875  			r1 = ret.Get(1).(*core.DetailedResponse)
   876  		}
   877  	}
   878  
   879  	var r2 error
   880  	if rf, ok := ret.Get(2).(func(context.Context, *dnsrecordsv1.UpdateDnsRecordOptions) error); ok {
   881  		r2 = rf(ctx, updateDnsRecordOptions)
   882  	} else {
   883  		r2 = ret.Error(2)
   884  	}
   885  
   886  	return r0, r1, r2
   887  }
   888  
   889  // UpdateResourceRecordWithContext provides a mock function with given fields: ctx, updateResourceRecordOptions
   890  func (_m *mockIbmcloudClientInterface) UpdateResourceRecordWithContext(ctx context.Context, updateResourceRecordOptions *dnssvcsv1.UpdateResourceRecordOptions) (*dnssvcsv1.ResourceRecord, *core.DetailedResponse, error) {
   891  	ret := _m.Called(ctx, updateResourceRecordOptions)
   892  
   893  	var r0 *dnssvcsv1.ResourceRecord
   894  	if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.UpdateResourceRecordOptions) *dnssvcsv1.ResourceRecord); ok {
   895  		r0 = rf(ctx, updateResourceRecordOptions)
   896  	} else {
   897  		if ret.Get(0) != nil {
   898  			r0 = ret.Get(0).(*dnssvcsv1.ResourceRecord)
   899  		}
   900  	}
   901  
   902  	var r1 *core.DetailedResponse
   903  	if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.UpdateResourceRecordOptions) *core.DetailedResponse); ok {
   904  		r1 = rf(ctx, updateResourceRecordOptions)
   905  	} else {
   906  		if ret.Get(1) != nil {
   907  			r1 = ret.Get(1).(*core.DetailedResponse)
   908  		}
   909  	}
   910  
   911  	var r2 error
   912  	if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.UpdateResourceRecordOptions) error); ok {
   913  		r2 = rf(ctx, updateResourceRecordOptions)
   914  	} else {
   915  		r2 = ret.Error(2)
   916  	}
   917  
   918  	return r0, r1, r2
   919  }
   920  
   921  type mockSource struct {
   922  	mock.Mock
   923  }
   924  
   925  // Endpoints provides a mock function with given fields: ctx
   926  func (_m *mockSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
   927  	ret := _m.Called(ctx)
   928  
   929  	var r0 []*endpoint.Endpoint
   930  	if rf, ok := ret.Get(0).(func(context.Context) []*endpoint.Endpoint); ok {
   931  		r0 = rf(ctx)
   932  	} else {
   933  		if ret.Get(0) != nil {
   934  			r0 = ret.Get(0).([]*endpoint.Endpoint)
   935  		}
   936  	}
   937  
   938  	var r1 error
   939  	if rf, ok := ret.Get(1).(func(context.Context) error); ok {
   940  		r1 = rf(ctx)
   941  	} else {
   942  		r1 = ret.Error(1)
   943  	}
   944  
   945  	return r0, r1
   946  }
   947  
   948  // AddEventHandler provides a mock function with given fields: _a0, _a1
   949  func (_m *mockSource) AddEventHandler(_a0 context.Context, _a1 func()) {
   950  	_m.Called(_a0, _a1)
   951  }