|
1 | 1 | package configobserver
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "context" |
4 | 5 | "encoding/json"
|
5 | 6 | "fmt"
|
6 |
| - "io/ioutil" |
7 |
| - "os" |
8 | 7 | "reflect"
|
| 8 | + "sync" |
9 | 9 | "testing"
|
10 | 10 | "time"
|
11 | 11 |
|
@@ -66,22 +66,9 @@ func TestChangeSupportConfig(t *testing.T) {
|
66 | 66 |
|
67 | 67 | ctrl := config.Controller{}
|
68 | 68 | kube := kubeClientResponder{}
|
69 |
| - secs := tt.config |
70 | 69 | // setup mock responses for secretes by secret name
|
71 |
| - kube.CoreV1().(*corefake.FakeCoreV1).Fake.AddReactor("get", "secrets", |
72 |
| - func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { |
73 |
| - actionName := "" |
74 |
| - if getAction, ok := action.(clienttesting.GetAction); ok { |
75 |
| - actionName = getAction.GetName() |
76 |
| - } |
77 |
| - |
78 |
| - key := fmt.Sprintf("(%s) %s.%s", action.GetResource(), action.GetNamespace(), actionName) |
79 |
| - sv, ok := secs[key] |
80 |
| - if !ok { |
81 |
| - return false, nil, nil |
82 |
| - } |
83 |
| - return true, sv, nil |
84 |
| - }) |
| 70 | + provideSecretMock(&kube, tt.config) |
| 71 | + |
85 | 72 | // imitates New function
|
86 | 73 | c := &Controller{
|
87 | 74 | kubeClient: &kube,
|
@@ -111,31 +98,115 @@ func TestChangeSupportConfig(t *testing.T) {
|
111 | 98 |
|
112 | 99 | }
|
113 | 100 |
|
| 101 | +func TestChangeObserved(t *testing.T) { |
| 102 | + setIntervals := map[int]time.Duration{ |
| 103 | + 0: time.Duration(10 * time.Minute), |
| 104 | + 1: time.Duration(1 * time.Minute), |
| 105 | + 2: time.Duration(3 * time.Minute), |
| 106 | + 3: time.Duration(4 * time.Minute), |
| 107 | + } |
| 108 | + |
| 109 | + klog.SetOutput(utils.NewTestLog(t).Writer()) |
| 110 | + |
| 111 | + ctrl := config.Controller{} |
| 112 | + kube := kubeClientResponder{} |
| 113 | + // The initial values set in configobserver.New |
| 114 | + secs := map[string]*corev1.Secret{ |
| 115 | + pullSecretKey: &corev1.Secret{Data: map[string][]byte{ |
| 116 | + ".dockerconfigjson": fakeDockerConfig(), |
| 117 | + }}, |
| 118 | + supportKey: &corev1.Secret{Data: map[string][]byte{ |
| 119 | + "username": []byte("someone"), |
| 120 | + "password": []byte("secret"), |
| 121 | + "endpoint": []byte("http://po.rt"), |
| 122 | + intervalKey: []byte("10m"), |
| 123 | + }}, |
| 124 | + } |
| 125 | + |
| 126 | + provideSecretMock(&kube, secs) |
| 127 | + // New reads first k8 configuration |
| 128 | + co := New(ctrl, &kube) |
| 129 | + // set some initial config because we are tracking changes only |
| 130 | + co.setConfigLocked(&config.Controller{}) |
| 131 | + |
| 132 | + // observe changes every 50 ms |
| 133 | + co.checkPeriod = 50 * time.Millisecond |
| 134 | + ctx, cancel := context.WithCancel(context.Background()) |
| 135 | + defer cancel() |
| 136 | + |
| 137 | + // Watch for changes in configurations |
| 138 | + done := make(chan bool) |
| 139 | + go co.Start(ctx) |
| 140 | + changedC, _ := co.ConfigChanged() |
| 141 | + |
| 142 | + // Sets gather intervals in config to 3 and 4 minutes after 100ms elapses |
| 143 | + go func() { |
| 144 | + |
| 145 | + for i := range setIntervals { |
| 146 | + time.Sleep(100 * time.Millisecond) |
| 147 | + secs[supportKey].Data[intervalKey] = []byte(setIntervals[i].String()) |
| 148 | + } |
| 149 | + // Give observer chance to catch the change |
| 150 | + time.Sleep(50 * time.Millisecond) |
| 151 | + done <- true |
| 152 | + }() |
| 153 | + |
| 154 | + actualIntervals := map[int]time.Duration{} |
| 155 | + actIntMu := sync.Mutex{} |
| 156 | + go func() { |
| 157 | + for { |
| 158 | + select { |
| 159 | + case <-ctx.Done(): |
| 160 | + done <- true |
| 161 | + |
| 162 | + case <-changedC: |
| 163 | + actInt := co.Config().Interval |
| 164 | + |
| 165 | + actIntMu.Lock() |
| 166 | + actIntMu.Unlock() |
| 167 | + actualIntervals[len(actualIntervals)] = actInt |
| 168 | + } |
| 169 | + } |
| 170 | + }() |
| 171 | + <-done |
| 172 | + |
| 173 | + if !reflect.DeepEqual(setIntervals, actualIntervals) { |
| 174 | + t.Fatalf("the expected intervals didn't match actual intervals. \nExpected %v \nActual %v", setIntervals, actualIntervals) |
| 175 | + } |
| 176 | +} |
| 177 | + |
114 | 178 | const (
|
115 | 179 | pullSecretKey = "(/v1, Resource=secrets) openshift-config.pull-secret"
|
116 | 180 | supportKey = "(/v1, Resource=secrets) openshift-config.support"
|
117 | 181 | intervalKey = "interval"
|
118 | 182 | )
|
119 | 183 |
|
120 |
| -func mustMarshal(v interface{}) []byte { |
121 |
| - bt, err := json.Marshal(v) |
122 |
| - if err != nil { |
123 |
| - panic(err) |
124 |
| - } |
125 |
| - return bt |
| 184 | +func fakeDockerConfig() []byte { |
| 185 | + d, _ := json.Marshal( |
| 186 | + serializedAuthMap{ |
| 187 | + Auths: map[string]serializedAuth{ |
| 188 | + "cloud.openshift.com": serializedAuth{Auth: ".."}, |
| 189 | + }, |
| 190 | + }) |
| 191 | + return d |
126 | 192 | }
|
127 | 193 |
|
128 |
| -func mustLoad(filename string) []byte { |
129 |
| - f, err := os.Open(filename) |
130 |
| - if err != nil { |
131 |
| - panic(fmt.Errorf("test failed to load data: %v", err)) |
132 |
| - } |
133 |
| - defer f.Close() |
134 |
| - bts, err := ioutil.ReadAll(f) |
135 |
| - if err != nil { |
136 |
| - panic(fmt.Errorf("test failed to read data: %v", err)) |
137 |
| - } |
138 |
| - return bts |
| 194 | +func provideSecretMock(kube kubernetes.Interface, secs map[string]*corev1.Secret) { |
| 195 | + kube.CoreV1().(*corefake.FakeCoreV1).Fake.AddReactor("get", "secrets", |
| 196 | + func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { |
| 197 | + actionName := "" |
| 198 | + if getAction, ok := action.(clienttesting.GetAction); ok { |
| 199 | + actionName = getAction.GetName() |
| 200 | + } |
| 201 | + |
| 202 | + key := fmt.Sprintf("(%s) %s.%s", action.GetResource(), action.GetNamespace(), actionName) |
| 203 | + sv, ok := secs[key] |
| 204 | + |
| 205 | + if !ok { |
| 206 | + return false, nil, nil |
| 207 | + } |
| 208 | + return true, sv, nil |
| 209 | + }) |
139 | 210 | }
|
140 | 211 |
|
141 | 212 | type kubeClientResponder struct {
|
|
0 commit comments