sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/vnetpeerings/vnetpeerings_test.go (about)

     1  /*
     2  Copyright 2021 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 vnetpeerings
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  	"net/http"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
    28  	. "github.com/onsi/gomega"
    29  	"go.uber.org/mock/gomock"
    30  	"k8s.io/utils/ptr"
    31  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    32  	"sigs.k8s.io/cluster-api-provider-azure/azure"
    33  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async"
    34  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/vnetpeerings/mock_vnetpeerings"
    35  	gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock"
    36  	"sigs.k8s.io/cluster-api-provider-azure/util/reconciler"
    37  )
    38  
    39  var (
    40  	fakePeering1To2 = VnetPeeringSpec{
    41  		PeeringName:         "vnet1-to-vnet2",
    42  		SourceVnetName:      "vnet1",
    43  		SourceResourceGroup: "group1",
    44  		RemoteVnetName:      "vnet2",
    45  		RemoteResourceGroup: "group2",
    46  		SubscriptionID:      "sub1",
    47  	}
    48  	fakePeering2To1 = VnetPeeringSpec{
    49  		PeeringName:         "vnet2-to-vnet1",
    50  		SourceVnetName:      "vnet2",
    51  		SourceResourceGroup: "group2",
    52  		RemoteVnetName:      "vnet1",
    53  		RemoteResourceGroup: "group1",
    54  		SubscriptionID:      "sub1",
    55  	}
    56  	fakePeering1To3 = VnetPeeringSpec{
    57  		PeeringName:         "vnet1-to-vnet3",
    58  		SourceVnetName:      "vnet1",
    59  		SourceResourceGroup: "group1",
    60  		RemoteVnetName:      "vnet3",
    61  		RemoteResourceGroup: "group3",
    62  		SubscriptionID:      "sub1",
    63  	}
    64  	fakePeering3To1 = VnetPeeringSpec{
    65  		PeeringName:         "vnet3-to-vnet1",
    66  		SourceVnetName:      "vnet3",
    67  		SourceResourceGroup: "group3",
    68  		RemoteVnetName:      "vnet1",
    69  		RemoteResourceGroup: "group1",
    70  		SubscriptionID:      "sub1",
    71  	}
    72  	fakePeeringHubToSpoke = VnetPeeringSpec{
    73  		PeeringName:               "hub-to-spoke",
    74  		SourceVnetName:            "hub-vnet",
    75  		SourceResourceGroup:       "hub-group",
    76  		RemoteVnetName:            "spoke-vnet",
    77  		RemoteResourceGroup:       "spoke-group",
    78  		SubscriptionID:            "sub1",
    79  		AllowForwardedTraffic:     ptr.To(true),
    80  		AllowGatewayTransit:       ptr.To(true),
    81  		AllowVirtualNetworkAccess: ptr.To(true),
    82  		UseRemoteGateways:         ptr.To(false),
    83  	}
    84  	fakePeeringSpokeToHub = VnetPeeringSpec{
    85  		PeeringName:               "spoke-to-hub",
    86  		SourceVnetName:            "spoke-vnet",
    87  		SourceResourceGroup:       "spoke-group",
    88  		RemoteVnetName:            "hub-vnet",
    89  		RemoteResourceGroup:       "hub-group",
    90  		SubscriptionID:            "sub1",
    91  		AllowForwardedTraffic:     ptr.To(true),
    92  		AllowGatewayTransit:       ptr.To(false),
    93  		AllowVirtualNetworkAccess: ptr.To(true),
    94  		UseRemoteGateways:         ptr.To(true),
    95  	}
    96  	fakePeeringExtra = VnetPeeringSpec{
    97  		PeeringName:         "extra-peering",
    98  		SourceVnetName:      "vnet3",
    99  		SourceResourceGroup: "group3",
   100  		RemoteVnetName:      "vnet4",
   101  		RemoteResourceGroup: "group4",
   102  		SubscriptionID:      "sub1",
   103  	}
   104  	fakePeeringSpecs      = []azure.ResourceSpecGetter{&fakePeering1To2, &fakePeering2To1, &fakePeering1To3, &fakePeering3To1, &fakePeeringHubToSpoke, &fakePeeringSpokeToHub}
   105  	fakePeeringExtraSpecs = []azure.ResourceSpecGetter{&fakePeering1To2, &fakePeering2To1, &fakePeeringExtra}
   106  	notDoneError          = azure.NewOperationNotDoneError(&infrav1.Future{})
   107  )
   108  
   109  func internalError() *azcore.ResponseError {
   110  	return &azcore.ResponseError{
   111  		RawResponse: &http.Response{
   112  			Body:       io.NopCloser(strings.NewReader("#: Internal Server Error: StatusCode=500")),
   113  			StatusCode: http.StatusInternalServerError,
   114  		},
   115  	}
   116  }
   117  
   118  func TestReconcileVnetPeerings(t *testing.T) {
   119  	testcases := []struct {
   120  		name          string
   121  		expectedError string
   122  		expect        func(s *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder)
   123  	}{
   124  		{
   125  			name:          "create one peering",
   126  			expectedError: "",
   127  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   128  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   129  				p.VnetPeeringSpecs().Return(fakePeeringSpecs[:1])
   130  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil)
   131  				p.UpdatePutStatus(infrav1.VnetPeeringReadyCondition, ServiceName, nil)
   132  			},
   133  		},
   134  		{
   135  			name:          "noop if no peering specs are found",
   136  			expectedError: "",
   137  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   138  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   139  				p.VnetPeeringSpecs().Return([]azure.ResourceSpecGetter{})
   140  			},
   141  		},
   142  		{
   143  			name:          "create even number of peerings",
   144  			expectedError: "",
   145  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   146  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   147  				p.VnetPeeringSpecs().Return(fakePeeringSpecs[:2])
   148  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil)
   149  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil)
   150  				p.UpdatePutStatus(infrav1.VnetPeeringReadyCondition, ServiceName, nil)
   151  			},
   152  		},
   153  		{
   154  			name:          "create odd number of peerings",
   155  			expectedError: "",
   156  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   157  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   158  				p.VnetPeeringSpecs().Return(fakePeeringExtraSpecs)
   159  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil)
   160  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil)
   161  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringExtra, ServiceName).Return(&fakePeeringExtra, nil)
   162  				p.UpdatePutStatus(infrav1.VnetPeeringReadyCondition, ServiceName, nil)
   163  			},
   164  		},
   165  		{
   166  			name:          "create multiple peerings on one vnet",
   167  			expectedError: "",
   168  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   169  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   170  				p.VnetPeeringSpecs().Return(fakePeeringSpecs)
   171  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil)
   172  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil)
   173  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To3, ServiceName).Return(&fakePeering1To3, nil)
   174  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering3To1, ServiceName).Return(&fakePeering3To1, nil)
   175  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringHubToSpoke, ServiceName).Return(&fakePeeringHubToSpoke, nil)
   176  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringSpokeToHub, ServiceName).Return(&fakePeeringSpokeToHub, nil)
   177  				p.UpdatePutStatus(infrav1.VnetPeeringReadyCondition, ServiceName, nil)
   178  			},
   179  		},
   180  		{
   181  			name:          "error in creating peering",
   182  			expectedError: "#: Internal Server Error: StatusCode=500",
   183  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   184  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   185  				p.VnetPeeringSpecs().Return(fakePeeringSpecs)
   186  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil)
   187  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil)
   188  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To3, ServiceName).Return(nil, internalError())
   189  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering3To1, ServiceName).Return(&fakePeering3To1, nil)
   190  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringHubToSpoke, ServiceName).Return(&fakePeeringHubToSpoke, nil)
   191  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringSpokeToHub, ServiceName).Return(&fakePeeringSpokeToHub, nil)
   192  				p.UpdatePutStatus(infrav1.VnetPeeringReadyCondition, ServiceName, internalError())
   193  			},
   194  		},
   195  		{
   196  			name:          "not done error in creating is ignored",
   197  			expectedError: "#: Internal Server Error: StatusCode=500",
   198  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   199  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   200  				p.VnetPeeringSpecs().Return(fakePeeringSpecs)
   201  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil)
   202  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil, internalError())
   203  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To3, ServiceName).Return(nil, notDoneError)
   204  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering3To1, ServiceName).Return(&fakePeering3To1, nil)
   205  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringHubToSpoke, ServiceName).Return(&fakePeeringHubToSpoke, nil)
   206  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringSpokeToHub, ServiceName).Return(&fakePeeringSpokeToHub, nil)
   207  				p.UpdatePutStatus(infrav1.VnetPeeringReadyCondition, ServiceName, internalError())
   208  			},
   209  		},
   210  		{
   211  			name:          "not done error in creating is overwritten",
   212  			expectedError: "#: Internal Server Error: StatusCode=500",
   213  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   214  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   215  				p.VnetPeeringSpecs().Return(fakePeeringSpecs)
   216  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil)
   217  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil)
   218  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To3, ServiceName).Return(nil, notDoneError)
   219  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering3To1, ServiceName).Return(nil, internalError())
   220  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringHubToSpoke, ServiceName).Return(&fakePeeringHubToSpoke, nil)
   221  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringSpokeToHub, ServiceName).Return(&fakePeeringSpokeToHub, nil)
   222  				p.UpdatePutStatus(infrav1.VnetPeeringReadyCondition, ServiceName, internalError())
   223  			},
   224  		},
   225  		{
   226  			name:          "not done error in creating remains",
   227  			expectedError: "operation type  on Azure resource / is not done",
   228  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   229  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   230  				p.VnetPeeringSpecs().Return(fakePeeringSpecs)
   231  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil)
   232  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil)
   233  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To3, ServiceName).Return(nil, notDoneError)
   234  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering3To1, ServiceName).Return(&fakePeering3To1, nil)
   235  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringHubToSpoke, ServiceName).Return(&fakePeeringHubToSpoke, nil)
   236  				r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeeringSpokeToHub, ServiceName).Return(&fakePeeringSpokeToHub, nil)
   237  				p.UpdatePutStatus(infrav1.VnetPeeringReadyCondition, ServiceName, notDoneError)
   238  			},
   239  		},
   240  	}
   241  
   242  	for _, tc := range testcases {
   243  		tc := tc
   244  		t.Run(tc.name, func(t *testing.T) {
   245  			g := NewWithT(t)
   246  
   247  			t.Parallel()
   248  			mockCtrl := gomock.NewController(t)
   249  			defer mockCtrl.Finish()
   250  			scopeMock := mock_vnetpeerings.NewMockVnetPeeringScope(mockCtrl)
   251  			asyncMock := mock_async.NewMockReconciler(mockCtrl)
   252  
   253  			tc.expect(scopeMock.EXPECT(), asyncMock.EXPECT())
   254  
   255  			s := &Service{
   256  				Scope:      scopeMock,
   257  				Reconciler: asyncMock,
   258  			}
   259  
   260  			err := s.Reconcile(context.TODO())
   261  			if tc.expectedError != "" {
   262  				g.Expect(err).To(HaveOccurred())
   263  				g.Expect(err.Error()).To(ContainSubstring(tc.expectedError))
   264  			} else {
   265  				g.Expect(err).NotTo(HaveOccurred())
   266  			}
   267  		})
   268  	}
   269  }
   270  
   271  func TestDeleteVnetPeerings(t *testing.T) {
   272  	testcases := []struct {
   273  		name          string
   274  		expectedError string
   275  		expect        func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder)
   276  	}{
   277  		{
   278  			name:          "delete one peering",
   279  			expectedError: "",
   280  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   281  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   282  				p.VnetPeeringSpecs().Return(fakePeeringSpecs[:1])
   283  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil)
   284  				p.UpdateDeleteStatus(infrav1.VnetPeeringReadyCondition, ServiceName, nil)
   285  			},
   286  		},
   287  		{
   288  			name:          "noop if no peering specs are found",
   289  			expectedError: "",
   290  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   291  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   292  				p.VnetPeeringSpecs().Return([]azure.ResourceSpecGetter{})
   293  			},
   294  		},
   295  		{
   296  			name:          "delete even number of peerings",
   297  			expectedError: "",
   298  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   299  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   300  				p.VnetPeeringSpecs().Return(fakePeeringSpecs[:2])
   301  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil)
   302  				r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil)
   303  				p.UpdateDeleteStatus(infrav1.VnetPeeringReadyCondition, ServiceName, nil)
   304  			},
   305  		},
   306  		{
   307  			name:          "delete odd number of peerings",
   308  			expectedError: "",
   309  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   310  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   311  				p.VnetPeeringSpecs().Return(fakePeeringExtraSpecs)
   312  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil)
   313  				r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil)
   314  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringExtra, ServiceName).Return(nil)
   315  				p.UpdateDeleteStatus(infrav1.VnetPeeringReadyCondition, ServiceName, nil)
   316  			},
   317  		},
   318  		{
   319  			name:          "delete multiple peerings on one vnet",
   320  			expectedError: "",
   321  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   322  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   323  				p.VnetPeeringSpecs().Return(fakePeeringSpecs)
   324  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil)
   325  				r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil)
   326  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To3, ServiceName).Return(nil)
   327  				r.DeleteResource(gomockinternal.AContext(), &fakePeering3To1, ServiceName).Return(nil)
   328  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringHubToSpoke, ServiceName).Return(nil)
   329  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringSpokeToHub, ServiceName).Return(nil)
   330  				p.UpdateDeleteStatus(infrav1.VnetPeeringReadyCondition, ServiceName, nil)
   331  			},
   332  		},
   333  		{
   334  			name:          "error in deleting peering",
   335  			expectedError: "#: Internal Server Error: StatusCode=500",
   336  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   337  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   338  				p.VnetPeeringSpecs().Return(fakePeeringSpecs)
   339  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil)
   340  				r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil)
   341  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To3, ServiceName).Return(internalError())
   342  				r.DeleteResource(gomockinternal.AContext(), &fakePeering3To1, ServiceName).Return(nil)
   343  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringHubToSpoke, ServiceName).Return(nil)
   344  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringSpokeToHub, ServiceName).Return(nil)
   345  				p.UpdateDeleteStatus(infrav1.VnetPeeringReadyCondition, ServiceName, internalError())
   346  			},
   347  		},
   348  		{
   349  			name:          "not done error in deleting is ignored",
   350  			expectedError: "#: Internal Server Error: StatusCode=500",
   351  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   352  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   353  				p.VnetPeeringSpecs().Return(fakePeeringSpecs)
   354  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil)
   355  				r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(internalError())
   356  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To3, ServiceName).Return(notDoneError)
   357  				r.DeleteResource(gomockinternal.AContext(), &fakePeering3To1, ServiceName).Return(nil)
   358  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringHubToSpoke, ServiceName).Return(nil)
   359  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringSpokeToHub, ServiceName).Return(nil)
   360  				p.UpdateDeleteStatus(infrav1.VnetPeeringReadyCondition, ServiceName, internalError())
   361  			},
   362  		},
   363  		{
   364  			name:          "not done error in deleting is overwritten",
   365  			expectedError: "#: Internal Server Error: StatusCode=500",
   366  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   367  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   368  				p.VnetPeeringSpecs().Return(fakePeeringSpecs)
   369  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil)
   370  				r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil)
   371  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To3, ServiceName).Return(notDoneError)
   372  				r.DeleteResource(gomockinternal.AContext(), &fakePeering3To1, ServiceName).Return(internalError())
   373  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringHubToSpoke, ServiceName).Return(nil)
   374  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringSpokeToHub, ServiceName).Return(nil)
   375  				p.UpdateDeleteStatus(infrav1.VnetPeeringReadyCondition, ServiceName, internalError())
   376  			},
   377  		},
   378  		{
   379  			name:          "not done error in deleting remains",
   380  			expectedError: "operation type  on Azure resource / is not done",
   381  			expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) {
   382  				p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout)
   383  				p.VnetPeeringSpecs().Return(fakePeeringSpecs)
   384  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil)
   385  				r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil)
   386  				r.DeleteResource(gomockinternal.AContext(), &fakePeering1To3, ServiceName).Return(notDoneError)
   387  				r.DeleteResource(gomockinternal.AContext(), &fakePeering3To1, ServiceName).Return(nil)
   388  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringHubToSpoke, ServiceName).Return(nil)
   389  				r.DeleteResource(gomockinternal.AContext(), &fakePeeringSpokeToHub, ServiceName).Return(nil)
   390  				p.UpdateDeleteStatus(infrav1.VnetPeeringReadyCondition, ServiceName, notDoneError)
   391  			},
   392  		},
   393  	}
   394  
   395  	for _, tc := range testcases {
   396  		tc := tc
   397  		t.Run(tc.name, func(t *testing.T) {
   398  			g := NewWithT(t)
   399  
   400  			t.Parallel()
   401  			mockCtrl := gomock.NewController(t)
   402  			defer mockCtrl.Finish()
   403  			scopeMock := mock_vnetpeerings.NewMockVnetPeeringScope(mockCtrl)
   404  			asyncMock := mock_async.NewMockReconciler(mockCtrl)
   405  
   406  			tc.expect(scopeMock.EXPECT(), asyncMock.EXPECT())
   407  
   408  			s := &Service{
   409  				Scope:      scopeMock,
   410  				Reconciler: asyncMock,
   411  			}
   412  
   413  			err := s.Delete(context.TODO())
   414  			if tc.expectedError != "" {
   415  				fmt.Printf("\nExpected error:\t%s\n", tc.expectedError)
   416  				fmt.Printf("\nActual error:\t%s\n", err.Error())
   417  				g.Expect(err).To(HaveOccurred())
   418  				g.Expect(err.Error()).To(ContainSubstring(tc.expectedError))
   419  			} else {
   420  				g.Expect(err).NotTo(HaveOccurred())
   421  			}
   422  		})
   423  	}
   424  }