...

Source file src/oras.land/oras-go/pkg/registry/remote/internal/syncutil/once_test.go

Documentation: oras.land/oras-go/pkg/registry/remote/internal/syncutil

     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  }
   193  

View as plain text