github.com/lingyao2333/mo-zero@v1.4.1/core/mr/mapreduce_fuzzcase_test.go (about)

     1  //go:build fuzz
     2  // +build fuzz
     3  
     4  package mr
     5  
     6  import (
     7  	"fmt"
     8  	"math/rand"
     9  	"runtime"
    10  	"strconv"
    11  	"strings"
    12  	"sync"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/lingyao2333/mo-zero/core/threading"
    17  	"github.com/stretchr/testify/assert"
    18  	"gopkg.in/cheggaaa/pb.v1"
    19  )
    20  
    21  // If Fuzz stuck, we don't know why, because it only returns hung or unexpected,
    22  // so we need to simulate the fuzz test in test mode.
    23  func TestMapReduceRandom(t *testing.T) {
    24  	rand.Seed(time.Now().UnixNano())
    25  
    26  	const (
    27  		times  = 10000
    28  		nRange = 500
    29  		mega   = 1024 * 1024
    30  	)
    31  
    32  	bar := pb.New(times).Start()
    33  	runner := threading.NewTaskRunner(runtime.NumCPU())
    34  	var wg sync.WaitGroup
    35  	wg.Add(times)
    36  	for i := 0; i < times; i++ {
    37  		runner.Schedule(func() {
    38  			start := time.Now()
    39  			defer func() {
    40  				if time.Since(start) > time.Minute {
    41  					t.Fatal("timeout")
    42  				}
    43  				wg.Done()
    44  			}()
    45  
    46  			t.Run(strconv.Itoa(i), func(t *testing.T) {
    47  				n := rand.Int63n(nRange)%nRange + nRange
    48  				workers := rand.Int()%50 + runtime.NumCPU()/2
    49  				genPanic := rand.Intn(100) == 0
    50  				mapperPanic := rand.Intn(100) == 0
    51  				reducerPanic := rand.Intn(100) == 0
    52  				genIdx := rand.Int63n(n)
    53  				mapperIdx := rand.Int63n(n)
    54  				reducerIdx := rand.Int63n(n)
    55  				squareSum := (n - 1) * n * (2*n - 1) / 6
    56  
    57  				fn := func() (interface{}, error) {
    58  					return MapReduce(func(source chan<- interface{}) {
    59  						for i := int64(0); i < n; i++ {
    60  							source <- i
    61  							if genPanic && i == genIdx {
    62  								panic("foo")
    63  							}
    64  						}
    65  					}, func(item interface{}, writer Writer, cancel func(error)) {
    66  						v := item.(int64)
    67  						if mapperPanic && v == mapperIdx {
    68  							panic("bar")
    69  						}
    70  						writer.Write(v * v)
    71  					}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
    72  						var idx int64
    73  						var total int64
    74  						for v := range pipe {
    75  							if reducerPanic && idx == reducerIdx {
    76  								panic("baz")
    77  							}
    78  							total += v.(int64)
    79  							idx++
    80  						}
    81  						writer.Write(total)
    82  					}, WithWorkers(int(workers)%50+runtime.NumCPU()/2))
    83  				}
    84  
    85  				if genPanic || mapperPanic || reducerPanic {
    86  					var buf strings.Builder
    87  					buf.WriteString(fmt.Sprintf("n: %d", n))
    88  					buf.WriteString(fmt.Sprintf(", genPanic: %t", genPanic))
    89  					buf.WriteString(fmt.Sprintf(", mapperPanic: %t", mapperPanic))
    90  					buf.WriteString(fmt.Sprintf(", reducerPanic: %t", reducerPanic))
    91  					buf.WriteString(fmt.Sprintf(", genIdx: %d", genIdx))
    92  					buf.WriteString(fmt.Sprintf(", mapperIdx: %d", mapperIdx))
    93  					buf.WriteString(fmt.Sprintf(", reducerIdx: %d", reducerIdx))
    94  					assert.Panicsf(t, func() { fn() }, buf.String())
    95  				} else {
    96  					val, err := fn()
    97  					assert.Nil(t, err)
    98  					assert.Equal(t, squareSum, val.(int64))
    99  				}
   100  				bar.Increment()
   101  			})
   102  		})
   103  	}
   104  
   105  	wg.Wait()
   106  	bar.Finish()
   107  }