github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/maintenance_test.go (about)

     1  /*
     2  Copyright 2022 Gravitational, Inc.
     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 types
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestAgentUpgradeWindow(t *testing.T) {
    27  	newTime := func(day int, hour int) time.Time {
    28  		return time.Date(
    29  			2000,
    30  			time.January,
    31  			day,
    32  			hour,
    33  			0, // min
    34  			0, // sec
    35  			0, // nsec
    36  			time.UTC,
    37  		)
    38  	}
    39  
    40  	from := newTime(1, 12)
    41  
    42  	require.Equal(t, time.Saturday, from.Weekday()) // verify that newTime starts from expected pos
    43  
    44  	conf := AgentUpgradeWindow{
    45  		UTCStartHour: 2,
    46  	}
    47  
    48  	tts := []struct{ start, stop time.Time }{
    49  		{newTime(1, 2), newTime(1, 3)},
    50  		{newTime(2, 2), newTime(2, 3)},
    51  		{newTime(3, 2), newTime(3, 3)},
    52  		{newTime(4, 2), newTime(4, 3)},
    53  		{newTime(5, 2), newTime(5, 3)},
    54  		{newTime(6, 2), newTime(6, 3)},
    55  		{newTime(7, 2), newTime(7, 3)},
    56  		{newTime(8, 2), newTime(8, 3)},
    57  		{newTime(9, 2), newTime(9, 3)},
    58  	}
    59  
    60  	gen := conf.generator(from)
    61  
    62  	for _, tt := range tts {
    63  		start, stop := gen()
    64  		require.Equal(t, tt.start, start)
    65  		require.Equal(t, tt.stop, stop)
    66  	}
    67  
    68  	// set weekdays fileter s.t. windows limited to m-f.
    69  	conf.Weekdays = []string{
    70  		"Monday",
    71  		"tue",
    72  		"Wed",
    73  		"thursday",
    74  		"Friday",
    75  	}
    76  
    77  	tts = []struct{ start, stop time.Time }{
    78  		// sat {newTime(1, 2), newTime(1, 3)},
    79  		// sun {newTime(2, 2), newTime(2, 3)},
    80  		{newTime(3, 2), newTime(3, 3)},
    81  		{newTime(4, 2), newTime(4, 3)},
    82  		{newTime(5, 2), newTime(5, 3)},
    83  		{newTime(6, 2), newTime(6, 3)},
    84  		{newTime(7, 2), newTime(7, 3)},
    85  		// sat {newTime(8, 2), newTime(8, 3)},
    86  		// sun {newTime(9, 2), newTime(9, 3)},
    87  	}
    88  
    89  	gen = conf.generator(from)
    90  
    91  	for _, tt := range tts {
    92  		start, stop := gen()
    93  		require.Equal(t, tt.start, start)
    94  		require.Equal(t, tt.stop, stop)
    95  	}
    96  
    97  	// verify that invalid weekdays are omitted from filter.
    98  	conf.Weekdays = []string{
    99  		"Monday",
   100  		"tues", // invalid
   101  		"Wed",
   102  		"Th", // invalid
   103  		"Friday",
   104  	}
   105  
   106  	tts = []struct{ start, stop time.Time }{
   107  		// sat {newTime(1, 2), newTime(1, 3)},
   108  		// sun {newTime(2, 2), newTime(2, 3)},
   109  		{newTime(3, 2), newTime(3, 3)},
   110  		// tue {newTime(4, 2), newTime(4, 3)},
   111  		{newTime(5, 2), newTime(5, 3)},
   112  		// thu {newTime(6, 2), newTime(6, 3)},
   113  		{newTime(7, 2), newTime(7, 3)},
   114  		// sat {newTime(8, 2), newTime(8, 3)},
   115  		// sun {newTime(9, 2), newTime(9, 3)},
   116  	}
   117  
   118  	gen = conf.generator(from)
   119  
   120  	for _, tt := range tts {
   121  		start, stop := gen()
   122  		require.Equal(t, tt.start, start)
   123  		require.Equal(t, tt.stop, stop)
   124  	}
   125  
   126  	// if all weekdays are invalid, revert to firing every day
   127  	conf.Weekdays = []string{
   128  		"Mo",
   129  		"Tu",
   130  		"We",
   131  		"Th",
   132  		"Fr",
   133  	}
   134  
   135  	tts = []struct{ start, stop time.Time }{
   136  		{newTime(1, 2), newTime(1, 3)},
   137  		{newTime(2, 2), newTime(2, 3)},
   138  		{newTime(3, 2), newTime(3, 3)},
   139  		{newTime(4, 2), newTime(4, 3)},
   140  		{newTime(5, 2), newTime(5, 3)},
   141  		{newTime(6, 2), newTime(6, 3)},
   142  		{newTime(7, 2), newTime(7, 3)},
   143  		{newTime(8, 2), newTime(8, 3)},
   144  		{newTime(9, 2), newTime(9, 3)},
   145  	}
   146  
   147  	gen = conf.generator(from)
   148  
   149  	for _, tt := range tts {
   150  		start, stop := gen()
   151  		require.Equal(t, tt.start, start)
   152  		require.Equal(t, tt.stop, stop)
   153  	}
   154  }
   155  
   156  // verify that the default (empty) maintenance window value is valid.
   157  func TestClusterMaintenanceConfigDefault(t *testing.T) {
   158  	t.Parallel()
   159  
   160  	mw := NewClusterMaintenanceConfig()
   161  
   162  	require.NoError(t, mw.CheckAndSetDefaults())
   163  }
   164  
   165  func TestWeekdayParser(t *testing.T) {
   166  	t.Parallel()
   167  
   168  	tts := []struct {
   169  		input  string
   170  		expect time.Weekday
   171  		fail   bool
   172  	}{
   173  		{
   174  			input:  "Tue",
   175  			expect: time.Tuesday,
   176  		},
   177  		{
   178  			input:  "tue",
   179  			expect: time.Tuesday,
   180  		},
   181  		{
   182  			input: "tues",
   183  			fail:  true, // only 3-letter shorthand is accepted
   184  		},
   185  		{
   186  			input:  "Saturday",
   187  			expect: time.Saturday,
   188  		},
   189  		{
   190  			input:  "saturday",
   191  			expect: time.Saturday,
   192  		},
   193  		{
   194  			input:  "sun",
   195  			expect: time.Sunday,
   196  		},
   197  		{
   198  			input: "sundae", // containing a valid prefix is insufficient
   199  			fail:  true,
   200  		},
   201  		{
   202  			input: "",
   203  			fail:  true,
   204  		},
   205  	}
   206  
   207  	for _, tt := range tts {
   208  		day, ok := parseWeekday(tt.input)
   209  		if tt.fail {
   210  			require.False(t, ok)
   211  			continue
   212  		}
   213  
   214  		require.Equal(t, tt.expect, day)
   215  	}
   216  }
   217  
   218  func TestWithinUpgradeWindow(t *testing.T) {
   219  	t.Parallel()
   220  
   221  	tests := []struct {
   222  		desc          string
   223  		upgradeWindow AgentUpgradeWindow
   224  		date          string
   225  		withinWindow  bool
   226  	}{
   227  		{
   228  			desc: "within upgrade window",
   229  			upgradeWindow: AgentUpgradeWindow{
   230  				UTCStartHour: 8,
   231  			},
   232  			date:         "Mon, 02 Jan 2006 08:04:05 UTC",
   233  			withinWindow: true,
   234  		},
   235  		{
   236  			desc: "not within upgrade window",
   237  			upgradeWindow: AgentUpgradeWindow{
   238  				UTCStartHour: 8,
   239  			},
   240  			date:         "Mon, 02 Jan 2006 09:04:05 UTC",
   241  			withinWindow: false,
   242  		},
   243  		{
   244  			desc: "within upgrade window weekday",
   245  			upgradeWindow: AgentUpgradeWindow{
   246  				UTCStartHour: 8,
   247  				Weekdays:     []string{"Monday"},
   248  			},
   249  			date:         "Mon, 02 Jan 2006 08:04:05 UTC",
   250  			withinWindow: true,
   251  		},
   252  		{
   253  			desc: "not within upgrade window weekday",
   254  			upgradeWindow: AgentUpgradeWindow{
   255  				UTCStartHour: 8,
   256  				Weekdays:     []string{"Tuesday"},
   257  			},
   258  			date:         "Mon, 02 Jan 2006 08:04:05 UTC",
   259  			withinWindow: false,
   260  		},
   261  	}
   262  
   263  	for _, tt := range tests {
   264  		t.Run(tt.desc, func(t *testing.T) {
   265  			cmc := NewClusterMaintenanceConfig()
   266  			cmc.SetAgentUpgradeWindow(tt.upgradeWindow)
   267  
   268  			date, err := time.Parse(time.RFC1123, tt.date)
   269  			require.NoError(t, err)
   270  			require.Equal(t, tt.withinWindow, cmc.WithinUpgradeWindow(date))
   271  		})
   272  	}
   273  }