| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- /*
- Copyright © The ESO Authors
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- https://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package externalsecret
- import (
- "testing"
- "time"
- robfigcron "github.com/robfig/cron/v3"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
- )
- func mustParseCron(expr string) robfigcron.Schedule {
- sched, err := cronParser.Parse(expr)
- if err != nil {
- panic(expr + ": " + err.Error())
- }
- return sched
- }
- // TestIsWithinSyncWindow exercises the half-open / closed window boundaries
- // using a daily schedule that fires at 22:00 UTC with a 2-hour duration
- // (window open 22:00-00:00 UTC).
- func TestIsWithinSyncWindow(t *testing.T) {
- sched := mustParseCron("0 22 * * *")
- dur := 2 * time.Hour
- // Reference firing: 2026-06-01 22:00 UTC (Monday).
- open := time.Date(2026, 6, 1, 22, 0, 0, 0, time.UTC)
- closeTime := open.Add(dur) // 2026-06-02 00:00 UTC
- tests := []struct {
- name string
- at time.Time
- want bool
- }{
- {
- name: "at window open (inclusive)",
- at: open,
- want: true,
- },
- {
- name: "inside window",
- at: open.Add(30 * time.Minute),
- want: true,
- },
- {
- name: "at window close (inclusive)",
- at: closeTime,
- want: true,
- },
- {
- name: "one second past window close",
- at: closeTime.Add(time.Second),
- want: false,
- },
- {
- name: "one hour before window opens",
- at: open.Add(-1 * time.Hour),
- want: false,
- },
- {
- name: "between two consecutive occurrences",
- // 03:00 UTC next day -- well past the 22:00+2h window.
- at: open.Add(5 * time.Hour),
- want: false,
- },
- {
- name: "inside the second occurrence (next day)",
- at: open.Add(24*time.Hour + 30*time.Minute),
- want: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := isWithinSyncWindow(sched, dur, tt.at)
- if got != tt.want {
- t.Errorf("at=%v: got %v, want %v", tt.at.Format(time.RFC3339), got, tt.want)
- }
- })
- }
- }
- // TestIsPeriodicRefreshAllowedByWindows covers the nil / empty / allow / deny /
- // invalid-schedule paths and the unknown-kind default.
- func TestIsPeriodicRefreshAllowedByWindows(t *testing.T) {
- // inWindow: 2026-06-01 23:00 UTC -- inside the 22:00+2h window.
- inWindow := time.Date(2026, 6, 1, 23, 0, 0, 0, time.UTC)
- // outWindow: 2026-06-01 20:00 UTC -- outside any window.
- outWindow := time.Date(2026, 6, 1, 20, 0, 0, 0, time.UTC)
- // Shared window definitions.
- validEntry := esv1.ExternalSecretSyncWindowEntry{
- Schedule: "0 22 * * *",
- Duration: metav1.Duration{Duration: 2 * time.Hour},
- }
- invalidEntry := esv1.ExternalSecretSyncWindowEntry{
- Schedule: "not-a-cron",
- Duration: metav1.Duration{Duration: 2 * time.Hour},
- }
- tests := []struct {
- name string
- sw *esv1.ExternalSecretSyncWindows
- at time.Time
- want bool
- }{
- {
- name: "nil SyncWindows always permits",
- sw: nil,
- at: inWindow,
- want: true,
- },
- {
- name: "empty Windows list always permits",
- sw: &esv1.ExternalSecretSyncWindows{Kind: esv1.SyncWindowAllow},
- at: inWindow,
- want: true,
- },
- // allow kind
- {
- name: "allow: at inside window -- permit",
- sw: &esv1.ExternalSecretSyncWindows{Kind: esv1.SyncWindowAllow, Windows: []esv1.ExternalSecretSyncWindowEntry{validEntry}},
- at: inWindow,
- want: true,
- },
- {
- name: "allow: at outside window -- block",
- sw: &esv1.ExternalSecretSyncWindows{Kind: esv1.SyncWindowAllow, Windows: []esv1.ExternalSecretSyncWindowEntry{validEntry}},
- at: outWindow,
- want: false,
- },
- // deny kind
- {
- name: "deny: at inside window -- block",
- sw: &esv1.ExternalSecretSyncWindows{Kind: esv1.SyncWindowDeny, Windows: []esv1.ExternalSecretSyncWindowEntry{validEntry}},
- at: inWindow,
- want: false,
- },
- {
- name: "deny: at outside window -- permit",
- sw: &esv1.ExternalSecretSyncWindows{Kind: esv1.SyncWindowDeny, Windows: []esv1.ExternalSecretSyncWindowEntry{validEntry}},
- at: outWindow,
- want: true,
- },
- // invalid schedule handling
- {
- name: "allow: only invalid schedule -- block (no window is active)",
- sw: &esv1.ExternalSecretSyncWindows{Kind: esv1.SyncWindowAllow, Windows: []esv1.ExternalSecretSyncWindowEntry{invalidEntry}},
- at: inWindow,
- want: false,
- },
- {
- name: "deny: only invalid schedule -- permit (no window is active)",
- sw: &esv1.ExternalSecretSyncWindows{Kind: esv1.SyncWindowDeny, Windows: []esv1.ExternalSecretSyncWindowEntry{invalidEntry}},
- at: inWindow,
- want: true,
- },
- {
- name: "allow: one invalid + one valid active window -- permit",
- sw: &esv1.ExternalSecretSyncWindows{
- Kind: esv1.SyncWindowAllow,
- Windows: []esv1.ExternalSecretSyncWindowEntry{invalidEntry, validEntry},
- },
- at: inWindow,
- want: true,
- },
- // unknown kind falls back to always-permit
- {
- name: "unknown kind -- always permit",
- sw: &esv1.ExternalSecretSyncWindows{
- Kind: "unknown",
- Windows: []esv1.ExternalSecretSyncWindowEntry{validEntry},
- },
- at: inWindow,
- want: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- es := &esv1.ExternalSecret{
- Spec: esv1.ExternalSecretSpec{SyncWindows: tt.sw},
- }
- got := isPeriodicRefreshAllowedByWindows(es, tt.at)
- if got != tt.want {
- t.Errorf("got %v, want %v", got, tt.want)
- }
- })
- }
- }
|