@@ -14,6 +14,7 @@ import (
1414 "github.com/blang/semver/v4"
1515 "github.com/google/go-cmp/cmp"
1616 "github.com/google/go-cmp/cmp/cmpopts"
17+ "github.com/openshift/api/features"
1718
1819 corev1 "k8s.io/api/core/v1"
1920 k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -1175,3 +1176,86 @@ func Test_evaluateConditionalUpdates(t *testing.T) {
11751176 })
11761177 }
11771178}
1179+
1180+ // The setup is to satisfy needsConditionalUpdateEval == true and
1181+ // needFreshFetch == false in the targeting function optr.syncAvailableUpdates
1182+ // so that we simulate the scenario where the operator re-evaluates conditional updates
1183+ // without fetching the updates from the upstream.
1184+ func TestOperator_syncAvailableUpdates_noticeResolvedAlertsQuickly (t * testing.T ) {
1185+ now := time .Now ()
1186+ optr := & Operator {
1187+ queue : workqueue.NewTypedRateLimitingQueue [any ](workqueue .DefaultTypedControllerRateLimiter [any ]()),
1188+ availableUpdates : & availableUpdates {
1189+ LastSyncOrConfigChange : now ,
1190+ LastAttempt : now ,
1191+ AcceptRisks : sets.New [string ]("RiskA" ),
1192+ Architecture : "amd64" ,
1193+ upstreamUpdates : []configv1.Release {
1194+ {
1195+ Version : "4.21.2" ,
1196+ },
1197+ },
1198+ // it becomes conditional because a firing alert
1199+ ConditionalUpdates : []configv1.ConditionalUpdate {
1200+ {
1201+ Release : configv1.Release {
1202+ Version : "4.21.2" ,
1203+ },
1204+ Conditions : []metav1.Condition {
1205+ {
1206+ Type : "Recommended" ,
1207+ Status : "False" ,
1208+ },
1209+ },
1210+ Risks : []configv1.ConditionalUpdateRisk {
1211+ {
1212+ Name : "TestAlert" ,
1213+ Conditions : []metav1.Condition {},
1214+ },
1215+ },
1216+ },
1217+ },
1218+ },
1219+ }
1220+ optr .minimumUpdateCheckInterval = 10 * time .Minute
1221+ cvgGates := featuregates .CvoGatesFromFeatureGate (& configv1.FeatureGate {
1222+ Status : configv1.FeatureGateStatus {
1223+ FeatureGates : []configv1.FeatureGateDetails {
1224+ {
1225+ Enabled : []configv1.FeatureGateAttributes {
1226+ {
1227+ Name : features .FeatureGateClusterUpdateAcceptRisks ,
1228+ },
1229+ },
1230+ },
1231+ },
1232+ },
1233+ }, "" )
1234+ if ! cvgGates .AcceptRisks () {
1235+ t .Fatalf ("accept risk feature is not enabled" )
1236+ }
1237+ optr .enabledCVOFeatureGates = cvgGates
1238+ err := optr .syncAvailableUpdates (context .Background (), & configv1.ClusterVersion {
1239+ Spec : configv1.ClusterVersionSpec {
1240+ DesiredUpdate : & configv1.Update {
1241+ Architecture : "amd64" ,
1242+ },
1243+ },
1244+ })
1245+ if err != nil {
1246+ t .Fatalf ("failed to sync available updates: %v" , err )
1247+ }
1248+
1249+ // The conditional update is back to be an available update after evaluation.
1250+ // There was no available updates before the sync call.
1251+ expected := & availableUpdates {
1252+ Architecture : "amd64" ,
1253+ Updates : []configv1.Release {{
1254+ Version : "4.21.2" ,
1255+ }},
1256+ }
1257+
1258+ if diff := cmp .Diff (expected , optr .availableUpdates , availableUpdatesCmpOpts ... ); diff != "" {
1259+ t .Errorf ("syncAvailableUpdates mismatch (-want +got):\n %s" , diff )
1260+ }
1261+ }
0 commit comments