github.com/nikkelma/oras-project_oras-go@v1.1.1-0.20220201001104-a75f6a419090/pkg/registry/remote/internal/syncutil/once_test.go (about) 1 /* 2 Copyright The ORAS Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 package syncutil 16 17 import ( 18 "context" 19 "errors" 20 "io" 21 "reflect" 22 "strconv" 23 "sync" 24 "testing" 25 "time" 26 ) 27 28 func TestOnce_Do(t *testing.T) { 29 var f []func() (interface{}, error) 30 for i := 0; i < 100; i++ { 31 f = append(f, func(i int) func() (interface{}, error) { 32 return func() (interface{}, error) { 33 return i + 1, errors.New(strconv.Itoa(i)) 34 } 35 }(i)) 36 } 37 38 once := NewOnce() 39 first := make([]bool, len(f)) 40 result := make([]interface{}, len(f)) 41 err := make([]error, len(f)) 42 var wg sync.WaitGroup 43 for i := 0; i < len(f); i++ { 44 wg.Add(1) 45 go func(i int) { 46 defer wg.Done() 47 ctx := context.Background() 48 first[i], result[i], err[i] = once.Do(ctx, f[i]) 49 }(i) 50 } 51 wg.Wait() 52 53 target := 0 54 for i := 0; i < len(f); i++ { 55 if first[i] { 56 target = i 57 break 58 } 59 } 60 targetErr := err[target] 61 if targetErr == nil || targetErr.Error() != strconv.Itoa(target) { 62 t.Errorf("Once.Do(%d) error = %v, wantErr %v", target, targetErr, strconv.Itoa(target)) 63 } 64 65 wantResult := target + 1 66 wantErr := targetErr 67 for i := 0; i < len(f); i++ { 68 wantFirst := false 69 if i == target { 70 wantFirst = true 71 } 72 if first[i] != wantFirst { 73 t.Errorf("Once.Do(%d) first = %v, want %v", i, first[i], wantFirst) 74 } 75 if err[i] != wantErr { 76 t.Errorf("Once.Do(%d) error = %v, wantErr %v", i, err[i], wantErr) 77 } 78 if !reflect.DeepEqual(result[i], wantResult) { 79 t.Errorf("Once.Do(%d) result = %v, want %v", i, result[i], wantResult) 80 } 81 } 82 } 83 84 func TestOnce_Do_Cancel_Context(t *testing.T) { 85 once := NewOnce() 86 87 var wg sync.WaitGroup 88 var ( 89 first bool 90 result interface{} 91 err error 92 ) 93 wg.Add(1) 94 go func() { 95 defer wg.Done() 96 ctx := context.Background() 97 first, result, err = once.Do(ctx, func() (interface{}, error) { 98 time.Sleep(200 * time.Millisecond) 99 return "foo", io.EOF 100 }) 101 }() 102 time.Sleep(100 * time.Millisecond) 103 ctx := context.Background() 104 ctx, cancel := context.WithCancel(ctx) 105 cancel() 106 first2, result2, err2 := once.Do(ctx, func() (interface{}, error) { 107 return "bar", nil 108 }) 109 wg.Wait() 110 111 if wantFirst := true; first != wantFirst { 112 t.Fatalf("Once.Do() first = %v, want %v", first, wantFirst) 113 } 114 if wantErr := io.EOF; err != wantErr { 115 t.Fatalf("Once.Do() error = %v, wantErr %v", err, wantErr) 116 } 117 if wantResult := "foo"; !reflect.DeepEqual(result, wantResult) { 118 t.Fatalf("Once.Do() result = %v, want %v", result, wantResult) 119 } 120 121 if wantFirst := false; first2 != wantFirst { 122 t.Fatalf("Once.Do() first = %v, want %v", first2, wantFirst) 123 } 124 if wantErr := context.Canceled; err2 != wantErr { 125 t.Fatalf("Once.Do() error = %v, wantErr %v", err2, wantErr) 126 } 127 if wantResult := interface{}(nil); !reflect.DeepEqual(result2, wantResult) { 128 t.Fatalf("Once.Do() result = %v, want %v", result2, wantResult) 129 } 130 } 131 132 func TestOnce_Do_Cancel_Function(t *testing.T) { 133 ctx := context.Background() 134 once := NewOnce() 135 136 first, result, err := once.Do(ctx, func() (interface{}, error) { 137 return "foo", context.Canceled 138 }) 139 if wantFirst := false; first != wantFirst { 140 t.Fatalf("Once.Do() first = %v, want %v", first, wantFirst) 141 } 142 if wantErr := context.Canceled; err != wantErr { 143 t.Fatalf("Once.Do() error = %v, wantErr %v", err, wantErr) 144 } 145 if wantResult := interface{}(nil); !reflect.DeepEqual(result, wantResult) { 146 t.Fatalf("Once.Do() result = %v, want %v", result, wantResult) 147 } 148 149 first, result, err = once.Do(ctx, func() (interface{}, error) { 150 return "bar", io.EOF 151 }) 152 if wantFirst := true; first != wantFirst { 153 t.Fatalf("Once.Do() first = %v, want %v", first, wantFirst) 154 } 155 if wantErr := io.EOF; err != wantErr { 156 t.Fatalf("Once.Do() error = %v, wantErr %v", err, wantErr) 157 } 158 if wantResult := "bar"; !reflect.DeepEqual(result, wantResult) { 159 t.Fatalf("Once.Do() result = %v, want %v", result, wantResult) 160 } 161 } 162 163 func TestOnce_Do_Cancel_Panic(t *testing.T) { 164 ctx := context.Background() 165 once := NewOnce() 166 167 func() { 168 defer func() { 169 got := recover() 170 want := "foo" 171 if got != want { 172 t.Fatalf("Once.Do() panic = %v, want %v", got, want) 173 } 174 }() 175 once.Do(ctx, func() (interface{}, error) { 176 panic("foo") 177 }) 178 }() 179 180 first, result, err := once.Do(ctx, func() (interface{}, error) { 181 return "bar", io.EOF 182 }) 183 if wantFirst := true; first != wantFirst { 184 t.Fatalf("Once.Do() first = %v, want %v", first, wantFirst) 185 } 186 if wantErr := io.EOF; err != wantErr { 187 t.Fatalf("Once.Do() error = %v, wantErr %v", err, wantErr) 188 } 189 if wantResult := "bar"; !reflect.DeepEqual(result, wantResult) { 190 t.Fatalf("Once.Do() result = %v, want %v", result, wantResult) 191 } 192 }