@@ -1005,72 +1005,70 @@ func (e TimeoutError) Error() string {
1005
1005
1006
1006
// TestCreateServiceInstanceWithProvisionFailure tests creating a ServiceInstance
1007
1007
// with various failure results in response to the provision request.
1008
- // TODO(carolynvs): I'm disabling this test because it's a flake that fails so much that I'm seeing 🔥
1009
- func FlakeTestCreateServiceInstanceWithProvisionFailure (t * testing.T ) {
1008
+ func TestCreateServiceInstanceWithProvisionFailure (t * testing.T ) {
1010
1009
cases := []struct {
1011
- name string
1012
- statusCode int
1013
- nonHTTPResponseError error
1014
- conditionReason string
1015
- expectFailCondition bool
1010
+ // name of the test
1011
+ name string
1012
+ // status code returned by failing provision calls
1013
+ statusCode int
1014
+ // non-HTTP error returned by failing provision calls
1015
+ nonHTTPResponseError error
1016
+ // expected reason used in the instance condition to indiciate that the provision failed
1017
+ provisionErrorReason string
1018
+ // expected reason used in the instance condiiton to indicate that the provision failed terminally
1019
+ failReason string
1020
+ // true if the failed provision is expected to trigger orphan mitigation
1016
1021
triggersOrphanMitigation bool
1017
1022
}{
1018
1023
{
1019
- name : "Status OK" ,
1020
- statusCode : http .StatusOK ,
1021
- conditionReason : "ProvisionedSuccessfully" ,
1022
- expectFailCondition : false ,
1024
+ name : "Status OK" ,
1025
+ statusCode : http .StatusOK ,
1026
+ provisionErrorReason : "ProvisionCallFailed" ,
1023
1027
},
1024
1028
{
1025
1029
name : "Status Created" ,
1026
1030
statusCode : http .StatusCreated ,
1027
- conditionReason : "ProvisionedSuccessfully" ,
1028
- expectFailCondition : false ,
1031
+ provisionErrorReason : "ProvisionCallFailed" ,
1029
1032
triggersOrphanMitigation : true ,
1030
1033
},
1031
1034
{
1032
1035
name : "other 2xx" ,
1033
1036
statusCode : http .StatusNoContent ,
1034
- conditionReason : "ProvisionedSuccessfully" ,
1035
- expectFailCondition : false ,
1037
+ provisionErrorReason : "ProvisionCallFailed" ,
1036
1038
triggersOrphanMitigation : true ,
1037
1039
},
1038
1040
{
1039
- name : "3XX" ,
1040
- statusCode : 300 ,
1041
- conditionReason : "ProvisionedSuccessfully" ,
1042
- expectFailCondition : false ,
1041
+ name : "3XX" ,
1042
+ statusCode : 300 ,
1043
+ provisionErrorReason : "ProvisionCallFailed" ,
1043
1044
},
1044
1045
{
1045
1046
name : "Status Request Timeout" ,
1046
1047
statusCode : http .StatusRequestTimeout ,
1047
- conditionReason : "ProvisionedSuccessfully" ,
1048
- expectFailCondition : false ,
1048
+ provisionErrorReason : "ProvisionCallFailed" ,
1049
1049
triggersOrphanMitigation : false ,
1050
1050
},
1051
1051
{
1052
- name : "400" ,
1053
- statusCode : 400 ,
1054
- conditionReason : "ClusterServiceBrokerReturnedFailure " ,
1055
- expectFailCondition : true ,
1052
+ name : "400" ,
1053
+ statusCode : 400 ,
1054
+ provisionErrorReason : "ProvisionCallFailed " ,
1055
+ failReason : "ClusterServiceBrokerReturnedFailure" ,
1056
1056
},
1057
1057
{
1058
- name : "other 4XX" ,
1059
- statusCode : 403 ,
1060
- conditionReason : "ProvisionedSuccessfully" ,
1061
- expectFailCondition : false ,
1058
+ name : "other 4XX" ,
1059
+ statusCode : 403 ,
1060
+ provisionErrorReason : "ProvisionCallFailed" ,
1062
1061
},
1063
1062
{
1064
1063
name : "5XX" ,
1065
1064
statusCode : 500 ,
1066
- conditionReason : "ProvisionedSuccessfully" ,
1067
- expectFailCondition : false ,
1065
+ provisionErrorReason : "ProvisionCallFailed" ,
1068
1066
triggersOrphanMitigation : true ,
1069
1067
},
1070
1068
{
1071
1069
name : "non-url transport error" ,
1072
1070
nonHTTPResponseError : fmt .Errorf ("non-url error" ),
1073
- conditionReason : "ProvisionedSuccessfully " ,
1071
+ provisionErrorReason : "ErrorCallingProvision " ,
1074
1072
},
1075
1073
{
1076
1074
name : "non-timeout url error" ,
@@ -1079,7 +1077,7 @@ func FlakeTestCreateServiceInstanceWithProvisionFailure(t *testing.T) {
1079
1077
URL : "https://fakebroker.com/v2/service_instances/instance_id" ,
1080
1078
Err : fmt .Errorf ("non-timeout error" ),
1081
1079
},
1082
- conditionReason : "ProvisionedSuccessfully " ,
1080
+ provisionErrorReason : "ErrorCallingProvision " ,
1083
1081
},
1084
1082
{
1085
1083
name : "network timeout" ,
@@ -1088,14 +1086,26 @@ func FlakeTestCreateServiceInstanceWithProvisionFailure(t *testing.T) {
1088
1086
URL : "https://fakebroker.com/v2/service_instances/instance_id" ,
1089
1087
Err : TimeoutError ("timeout error" ),
1090
1088
},
1091
- conditionReason : "ProvisionedSuccessfully" ,
1092
- expectFailCondition : false ,
1089
+ provisionErrorReason : "ErrorCallingProvision" ,
1093
1090
triggersOrphanMitigation : true ,
1094
1091
},
1095
1092
}
1096
1093
for _ , tc := range cases {
1097
1094
tc := tc
1098
1095
t .Run (tc .name , func (t * testing.T ) {
1096
+
1097
+ provisionSuccessChan := make (chan bool , 2 )
1098
+ deprovisionSuccessChan := make (chan bool , 2 )
1099
+ deprovisionBlockChan := make (chan bool , 2 )
1100
+
1101
+ // Ensure that broker requests respond successfully after running
1102
+ // the core of the test so that the resource cleanup can proceed.
1103
+ defer func () {
1104
+ provisionSuccessChan <- true
1105
+ deprovisionSuccessChan <- true
1106
+ deprovisionBlockChan <- false
1107
+ }()
1108
+
1099
1109
//t.Parallel()
1100
1110
ct := & controllerTest {
1101
1111
t : t ,
@@ -1111,72 +1121,127 @@ func FlakeTestCreateServiceInstanceWithProvisionFailure(t *testing.T) {
1111
1121
Description : strPtr ("response description" ),
1112
1122
}
1113
1123
}
1124
+ respondSuccessfullyToProvision := false
1114
1125
ct .osbClient .ProvisionReaction = fakeosb .DynamicProvisionReaction (
1115
- getProvisionResponseByPollCountReactions (2 , []fakeosb.ProvisionReaction {
1116
- fakeosb.ProvisionReaction {
1117
- Error : reactionError ,
1118
- },
1119
- fakeosb.ProvisionReaction {
1120
- Response : & osb.ProvisionResponse {},
1121
- },
1122
- }))
1126
+ func (r * osb.ProvisionRequest ) (* osb.ProvisionResponse , error ) {
1127
+ select {
1128
+ case respondSuccessfullyToProvision = <- provisionSuccessChan :
1129
+ default :
1130
+ }
1131
+ if respondSuccessfullyToProvision {
1132
+ return & osb.ProvisionResponse {}, nil
1133
+ } else {
1134
+ return nil , reactionError
1135
+ }
1136
+ })
1137
+ respondSuccessfullyToDeprovision := false
1138
+ blockDeprovision := true
1123
1139
ct .osbClient .DeprovisionReaction = fakeosb .DynamicDeprovisionReaction (
1124
- getDeprovisionResponseByPollCountReactions (2 , []fakeosb.DeprovisionReaction {
1125
- fakeosb.DeprovisionReaction {
1126
- Error : osb.HTTPStatusCodeError {
1140
+ func (r * osb.DeprovisionRequest ) (* osb.DeprovisionResponse , error ) {
1141
+ for blockDeprovision {
1142
+ blockDeprovision = <- deprovisionBlockChan
1143
+ }
1144
+ select {
1145
+ case respondSuccessfullyToDeprovision = <- deprovisionSuccessChan :
1146
+ default :
1147
+ }
1148
+ if respondSuccessfullyToDeprovision {
1149
+ return & osb.DeprovisionResponse {}, nil
1150
+ } else {
1151
+ return nil , osb.HTTPStatusCodeError {
1127
1152
StatusCode : 500 ,
1128
1153
ErrorMessage : strPtr ("temporary deprovision error" ),
1129
- },
1130
- },
1131
- fakeosb.DeprovisionReaction {
1132
- Response : & osb.DeprovisionResponse {},
1133
- },
1134
- }))
1154
+ }
1155
+ }
1156
+ })
1135
1157
},
1136
1158
}
1137
1159
ct .run (func (ct * controllerTest ) {
1138
- var condition v1beta1.ServiceInstanceCondition
1139
- if tc .expectFailCondition {
1140
- // Instance should get stuck in a Failed condition
1141
- condition = v1beta1.ServiceInstanceCondition {
1142
- Type : v1beta1 .ServiceInstanceConditionFailed ,
1143
- Status : v1beta1 .ConditionTrue ,
1144
- Reason : tc .conditionReason ,
1145
- }
1146
- } else {
1147
- // Instance provisioning should be retried and succeed
1148
- condition = v1beta1.ServiceInstanceCondition {
1149
- Type : v1beta1 .ServiceInstanceConditionReady ,
1150
- Status : v1beta1 .ConditionTrue ,
1151
- Reason : tc .conditionReason ,
1152
- }
1160
+ // Wait for the provision to fail
1161
+ condition := v1beta1.ServiceInstanceCondition {
1162
+ Type : v1beta1 .ServiceInstanceConditionReady ,
1163
+ Status : v1beta1 .ConditionFalse ,
1164
+ Reason : tc .provisionErrorReason ,
1165
+ }
1166
+ if tc .triggersOrphanMitigation {
1167
+ condition .Reason = "StartingInstanceOrphanMitigation"
1153
1168
}
1154
1169
if err := util .WaitForInstanceCondition (ct .client , testNamespace , testInstanceName , condition ); err != nil {
1155
- t .Fatalf ("error waiting for instance condition : %v" , err )
1170
+ t .Fatalf ("error waiting for provision to fail : %v" , err )
1156
1171
}
1157
1172
1158
- if tc .expectFailCondition {
1159
- if err := util .WaitForInstanceProcessedGeneration (ct .client , ct .instance .Namespace , ct .instance .Name , 1 ); err != nil {
1160
- t .Fatalf ("error waiting for instance reconciliation to complete: %v" , err )
1161
- }
1173
+ // Assert that the latest generation has been observed
1174
+ instance , err := ct .client .ServiceInstances (testNamespace ).Get (testInstanceName , metav1.GetOptions {})
1175
+ if err != nil {
1176
+ t .Fatalf ("error getting instance: %v" , err )
1177
+ }
1178
+ if e , a := int64 (1 ), instance .Status .ObservedGeneration ; e != a {
1179
+ t .Fatalf ("unexpected observed generation: expected %v, got %v" , e , a )
1162
1180
}
1163
1181
1164
- brokerActions := ct .osbClient .Actions ()
1165
- fmt .Printf ("%#v" , brokerActions )
1182
+ // If the provision failed with a terminating failure
1183
+ if tc .failReason != "" {
1184
+ util .AssertServiceInstanceCondition (t , instance , v1beta1 .ServiceInstanceConditionFailed , v1beta1 .ConditionTrue , tc .failReason )
1185
+ if e , a := 0 , len (findBrokerActions (t , ct .osbClient , fakeosb .DeprovisionInstance )); e != a {
1186
+ t .Fatalf ("unexpected calls to deprovision instance: expected %v, got %v" , e , a )
1187
+ }
1188
+ return
1189
+ }
1166
1190
1167
- // Ensure that we meet expectations on deprovision requests for orphan mitigation
1168
- deprovisionActions := findBrokerActions (t , ct .osbClient , fakeosb .DeprovisionInstance )
1191
+ // Assert that the orphan mitigation reason was set correctly
1169
1192
if tc .triggersOrphanMitigation {
1170
- if len (deprovisionActions ) == 0 {
1171
- t .Fatal ("expected orphan mitigation deprovision request to occur" )
1193
+ util .AssertServiceInstanceCondition (t , instance , v1beta1 .ServiceInstanceConditionOrphanMitigation , v1beta1 .ConditionTrue , tc .provisionErrorReason )
1194
+ if ! instance .Status .OrphanMitigationInProgress {
1195
+ t .Fatalf ("expected orphan mitigation to be in progress" )
1172
1196
}
1173
1197
} else {
1174
- if len (deprovisionActions ) != 0 {
1175
- t .Fatal ("unexpected deprovision requests" )
1198
+ util .AssertServiceInstanceConditionFalseOrAbsent (t , instance , v1beta1 .ServiceInstanceConditionOrphanMitigation )
1199
+ if instance .Status .OrphanMitigationInProgress {
1200
+ t .Fatalf ("expected orphan mitigation to not be in progress" )
1201
+ }
1202
+ }
1203
+
1204
+ // Now that the provision error conditions have been asserted, allow the broker to send its response to the deprovision request
1205
+ deprovisionBlockChan <- false
1206
+
1207
+ if tc .triggersOrphanMitigation {
1208
+ // Assert that the ready condition is set to Unknown when the deprovision request fails
1209
+ if err := util .WaitForInstanceCondition (ct .client , testNamespace , testInstanceName , v1beta1.ServiceInstanceCondition {
1210
+ Type : v1beta1 .ServiceInstanceConditionReady ,
1211
+ Status : v1beta1 .ConditionUnknown ,
1212
+ }); err != nil {
1213
+ t .Fatalf ("error waiting for instance deprovision to fail: %v" , err )
1176
1214
}
1177
1215
}
1178
1216
1179
- // All instances should eventually succeed
1217
+ // Now that everything surround the failed provision has been asserted, allow provision requests
1218
+ // to succeed. Also, allow orphan mitigation to complete by allowing deprovision requests to succeed.
1219
+ provisionSuccessChan <- true
1220
+ deprovisionSuccessChan <- true
1221
+
1222
+ // Wait for the instance to be provisioned successfully
1223
+ if err := util .WaitForInstanceCondition (ct .client , testNamespace , testInstanceName , v1beta1.ServiceInstanceCondition {
1224
+ Type : v1beta1 .ServiceInstanceConditionReady ,
1225
+ Status : v1beta1 .ConditionTrue ,
1226
+ }); err != nil {
1227
+ t .Fatalf ("error waiting for instance to be provisioned: %v" , err )
1228
+ }
1229
+
1230
+ // Assert that the observed generation is up-to-date, that orphan mitigation is not in progress,
1231
+ // and that the instance is not in a failed state.
1232
+ instance , err = ct .client .ServiceInstances (testNamespace ).Get (testInstanceName , metav1.GetOptions {})
1233
+ if err != nil {
1234
+ t .Fatalf ("error getting instance: %v" , err )
1235
+ }
1236
+ if g , og := instance .Generation , instance .Status .ObservedGeneration ; g != og {
1237
+ t .Fatalf ("latest generation not observed: generation: %v, observed: %v" , g , og )
1238
+ }
1239
+ if instance .Status .OrphanMitigationInProgress {
1240
+ t .Fatalf ("unexpected orphan mitigation in progress" )
1241
+ }
1242
+ util .AssertServiceInstanceConditionFalseOrAbsent (t , instance , v1beta1 .ServiceInstanceConditionFailed )
1243
+
1244
+ // Assert that the last broker action was a provision-instance request.
1180
1245
getLastBrokerAction (t , ct .osbClient , fakeosb .ProvisionInstance )
1181
1246
})
1182
1247
})
0 commit comments