knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/test/upgrade/functions.go (about)

     1  /*
     2  Copyright 2020 The Knative 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 upgrade
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  
    23  	"go.uber.org/zap"
    24  	"go.uber.org/zap/zaptest"
    25  )
    26  
    27  // Execute the Suite of upgrade tests with a Configuration given.
    28  // When the suite includes Continual tests the number of logical CPUs
    29  // usable by the test process must be at least <NUMBER OF CONTINUAL TESTS> + 1.
    30  // The -parallel test flag or GOMAXPROCS environment variable might be
    31  // used to adjust the settings.
    32  func (s *Suite) Execute(c Configuration) {
    33  	l := c.logger(c.T)
    34  	se := suiteExecution{
    35  		suite:         enrichSuite(s),
    36  		configuration: c,
    37  	}
    38  	l.Info("🏃 Running upgrade test suite...")
    39  
    40  	se.execute()
    41  
    42  	if !c.T.Failed() {
    43  		l.Info("🥳🎉 Success! Upgrade suite completed without errors.")
    44  	} else {
    45  		l.Error("💣🤬💔️ Upgrade suite have failed!")
    46  	}
    47  }
    48  
    49  func (c Configuration) logger(t *testing.T) *zap.SugaredLogger {
    50  	return zaptest.NewLogger(t, zaptest.WrapOptions(c.Options...)).Sugar()
    51  }
    52  
    53  // NewOperation creates a new upgrade operation or test.
    54  func NewOperation(name string, handler func(c Context)) Operation {
    55  	return &simpleOperation{name: name, handler: handler}
    56  }
    57  
    58  // NewBackgroundVerification is convenience function to easily setup a
    59  // background operation that will setup environment and then verify environment
    60  // status after receiving a stop event.
    61  func NewBackgroundVerification(name string, setup func(c Context), verify func(c Context)) BackgroundOperation {
    62  	return NewBackgroundOperation(name, setup, func(bc BackgroundContext) {
    63  		WaitForStopEvent(bc, WaitForStopEventConfiguration{
    64  			Name: name,
    65  			OnStop: func() {
    66  				verify(Context{
    67  					T:   bc.T,
    68  					Log: bc.Log,
    69  				})
    70  			},
    71  			OnWait:   DefaultOnWait,
    72  			WaitTime: DefaultWaitTime,
    73  		})
    74  	})
    75  }
    76  
    77  // NewBackgroundOperation creates a new background operation or test that can be
    78  // notified to stop its operation.
    79  func NewBackgroundOperation(name string, setup func(c Context),
    80  	handler func(bc BackgroundContext),
    81  ) BackgroundOperation {
    82  	return &simpleBackgroundOperation{
    83  		name:    name,
    84  		setup:   setup,
    85  		handler: handler,
    86  	}
    87  }
    88  
    89  // WaitForStopEvent will wait until upgrade suite sends a stop event to it.
    90  // After that happen a handler is invoked to verify environment state and report
    91  // failures.
    92  func WaitForStopEvent(bc BackgroundContext, w WaitForStopEventConfiguration) {
    93  	for {
    94  		select {
    95  		case <-bc.Stop:
    96  			bc.Log.Debugf("%s received a stop event", w.Name)
    97  			w.OnStop()
    98  			return
    99  		default:
   100  			w.OnWait(bc, w)
   101  		}
   102  		time.Sleep(w.WaitTime)
   103  	}
   104  }
   105  
   106  func enrichSuite(s *Suite) *enrichedSuite {
   107  	es := &enrichedSuite{
   108  		installations: s.Installations,
   109  		tests: enrichedTests{
   110  			preUpgrade:    s.Tests.PreUpgrade,
   111  			postUpgrade:   s.Tests.PostUpgrade,
   112  			postDowngrade: s.Tests.PostDowngrade,
   113  			continual:     make([]stoppableOperation, len(s.Tests.Continual)),
   114  		},
   115  	}
   116  	for i, test := range s.Tests.Continual {
   117  		es.tests.continual[i] = stoppableOperation{
   118  			BackgroundOperation: test,
   119  			stop:                make(chan struct{}),
   120  		}
   121  	}
   122  	return es
   123  }
   124  
   125  // Name is a human readable operation title, and it will be used in t.Run.
   126  func (h *simpleOperation) Name() string {
   127  	return h.name
   128  }
   129  
   130  // Handler is a function that will be called to perform an operation.
   131  func (h *simpleOperation) Handler() func(c Context) {
   132  	return h.handler
   133  }
   134  
   135  // Name is a human readable operation title, and it will be used in t.Run.
   136  func (s *simpleBackgroundOperation) Name() string {
   137  	return s.name
   138  }
   139  
   140  // Setup method may be used to set up environment before upgrade/downgrade is
   141  // performed.
   142  func (s *simpleBackgroundOperation) Setup() func(c Context) {
   143  	return s.setup
   144  }
   145  
   146  // Handler will be executed in background while upgrade/downgrade is being
   147  // executed. It can be used to constantly validate environment during that
   148  // time and/or wait for a stop event being sent. After a stop event is received
   149  // user should validate environment, clean up resources, and report found
   150  // issues to testing.T forwarded in BackgroundContext.
   151  func (s *simpleBackgroundOperation) Handler() func(bc BackgroundContext) {
   152  	return s.handler
   153  }