| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 pool |
| |
| import ( |
| "context" |
| "fmt" |
| "sync" |
| "testing" |
| "time" |
| |
| "github.com/pkg/errors" |
| "github.com/stretchr/testify/assert" |
| ) |
| |
| func Test_future_AwaitCompletion(t *testing.T) { |
| type args struct { |
| ctx context.Context |
| } |
| tests := []struct { |
| name string |
| args args |
| completer func(*sync.WaitGroup, *future) |
| wantErr assert.ErrorAssertionFunc |
| }{ |
| { |
| name: "completes with error", |
| args: args{ctx: t.Context()}, |
| completer: func(wg *sync.WaitGroup, f *future) { |
| defer wg.Done() |
| f.Cancel(false, errors.New("Uh oh")) |
| }, |
| wantErr: assert.Error, |
| }, |
| { |
| name: "completes regular", |
| args: args{ctx: t.Context()}, |
| completer: func(wg *sync.WaitGroup, f *future) { |
| defer wg.Done() |
| time.Sleep(30 * time.Millisecond) |
| f.complete() |
| }, |
| wantErr: assert.NoError, |
| }, |
| { |
| name: "completes not int time", |
| args: args{ctx: func() context.Context { |
| deadline, cancel := context.WithDeadline(context.Background(), time.Now().Add(30*time.Millisecond)) |
| t.Cleanup(cancel) |
| return deadline |
| }()}, |
| completer: func(wg *sync.WaitGroup, f *future) { |
| defer wg.Done() |
| time.Sleep(300 * time.Millisecond) |
| }, |
| wantErr: assert.Error, |
| }, |
| { |
| name: "completes canceled without error", |
| args: args{ctx: t.Context()}, |
| completer: func(wg *sync.WaitGroup, f *future) { |
| defer wg.Done() |
| time.Sleep(300 * time.Millisecond) |
| f.Cancel(true, nil) |
| }, |
| wantErr: func(t assert.TestingT, err error, i ...any) bool { |
| assert.Same(t, Canceled, err) |
| return true |
| }, |
| }, |
| { |
| name: "completes canceled with particular error", |
| args: args{ctx: t.Context()}, |
| completer: func(wg *sync.WaitGroup, f *future) { |
| defer wg.Done() |
| time.Sleep(300 * time.Millisecond) |
| f.Cancel(true, errors.New("Uh oh")) |
| }, |
| wantErr: func(t assert.TestingT, err error, i ...any) bool { |
| assert.Equal(t, "Uh oh", err.Error()) |
| return true |
| }, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| f := &future{} |
| wg := sync.WaitGroup{} |
| wg.Add(1) |
| go tt.completer(&wg, f) |
| tt.wantErr(t, f.AwaitCompletion(tt.args.ctx), fmt.Sprintf("AwaitCompletion(%v)", tt.args.ctx)) |
| wg.Wait() |
| }) |
| } |
| } |
| |
| func Test_future_Cancel(t *testing.T) { |
| type args struct { |
| interrupt bool |
| err error |
| } |
| tests := []struct { |
| name string |
| args args |
| verifier func(*testing.T, *future) |
| }{ |
| { |
| name: "cancel cancels", |
| verifier: func(t *testing.T, f *future) { |
| assert.True(t, f.cancelRequested.Load()) |
| }, |
| }, |
| { |
| name: "cancel with interrupt", |
| args: args{ |
| interrupt: true, |
| err: nil, |
| }, |
| verifier: func(t *testing.T, f *future) { |
| assert.True(t, f.cancelRequested.Load()) |
| assert.False(t, f.errored.Load()) |
| assert.Nil(t, f.err.Load()) |
| }, |
| }, |
| { |
| name: "cancel with err", |
| args: args{ |
| interrupt: true, |
| err: errors.New("Uh Oh"), |
| }, |
| verifier: func(t *testing.T, f *future) { |
| assert.True(t, f.cancelRequested.Load()) |
| assert.True(t, f.errored.Load()) |
| assert.NotNil(t, f.err.Load()) |
| }, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| f := &future{} |
| f.Cancel(tt.args.interrupt, tt.args.err) |
| tt.verifier(t, f) |
| }) |
| } |
| } |
| |
| func Test_future_String(t *testing.T) { |
| tests := []struct { |
| name string |
| want string |
| }{ |
| { |
| name: "string it", |
| want: ` |
| ╔═future══════════════════════════════════════════════════════╗ |
| ║╔═cancelRequested╗╔═interruptRequested╗╔═completed╗╔═errored╗║ |
| ║║ b0 false ║║ b0 false ║║ b0 false ║║b0 false║║ |
| ║╚════════════════╝╚═══════════════════╝╚══════════╝╚════════╝║ |
| ╚═════════════════════════════════════════════════════════════╝`[1:], |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| f := &future{} |
| assert.Equalf(t, tt.want, f.String(), "String()") |
| }) |
| } |
| } |
| |
| func Test_future_complete(t *testing.T) { |
| tests := []struct { |
| name string |
| verifier func(*testing.T, *future) |
| }{ |
| { |
| name: "complete completes", |
| verifier: func(t *testing.T, f *future) { |
| assert.True(t, f.completed.Load()) |
| }, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| f := &future{} |
| f.complete() |
| tt.verifier(t, f) |
| }) |
| } |
| } |