github.com/puellanivis/breton@v0.2.16/lib/mapreduce/engine_test.go (about)

     1  package mapreduce
     2  
     3  import (
     4  	"context"
     5  	"runtime"
     6  	"testing"
     7  	"time"
     8  )
     9  
    10  type TestMR struct {
    11  	ranges []Range
    12  	widths []int
    13  }
    14  
    15  func (mr *TestMR) Map(ctx context.Context, in interface{}) (out interface{}, err error) {
    16  	rng := in.(Range)
    17  
    18  	for i := rng.Start; i < rng.End; i++ {
    19  		runtime.Gosched()
    20  	}
    21  
    22  	return rng, nil
    23  }
    24  
    25  func (mr *TestMR) Reduce(ctx context.Context, in interface{}) error {
    26  	rng := in.(Range)
    27  
    28  	mr.ranges = append(mr.ranges, rng)
    29  	mr.widths = append(mr.widths, rng.Width())
    30  
    31  	return nil
    32  }
    33  
    34  func (mr *TestMR) reset() {
    35  	mr.ranges = nil
    36  	mr.widths = nil
    37  }
    38  
    39  func TestEngine(t *testing.T) {
    40  	ctx := context.Background()
    41  	DefaultThreadCount = -1
    42  
    43  	rng := Range{
    44  		Start: 42,
    45  		End:   42 + 53, // Give this a width of 53, a prime number.
    46  	}
    47  
    48  	mr := &TestMR{}
    49  	e := &engine{
    50  		MapReduce: MapReduce{
    51  			m: mr,
    52  			r: mr,
    53  		},
    54  	}
    55  
    56  	WithOrdering(true)(&e.MapReduce)
    57  	WithThreadCount(1)(&e.MapReduce)
    58  
    59  	for n := 0; n <= rng.Width(); n++ {
    60  		WithMapperCount(n)(&e.MapReduce)
    61  
    62  		mr.reset()
    63  
    64  		for err := range e.run(ctx, rng) {
    65  			t.Errorf("%d mappers: %+v", n, err)
    66  		}
    67  
    68  		t.Log(n, len(mr.widths), mr.widths)
    69  
    70  		if n > 0 && len(mr.ranges) != n {
    71  			t.Log(mr.ranges)
    72  
    73  			t.Errorf("wrong number of mappers ran, expected %d, but got %d", n, len(mr.ranges))
    74  		}
    75  	}
    76  }
    77  
    78  func TestEngineMaxSliceSize(t *testing.T) {
    79  	ctx := context.Background()
    80  	DefaultThreadCount = -1
    81  
    82  	rng := Range{
    83  		Start: 42,
    84  		End:   42 + 53, // Give this a width of 53, a prime number.
    85  	}
    86  
    87  	mr := &TestMR{}
    88  
    89  	e := &engine{
    90  		MapReduce: MapReduce{
    91  			m: mr,
    92  			r: mr,
    93  		},
    94  	}
    95  
    96  	testWidth := 7
    97  
    98  	WithOrdering(true)(&e.MapReduce)
    99  	WithThreadCount(1)(&e.MapReduce)
   100  	WithMaxStripeSize(testWidth)(&e.MapReduce)
   101  
   102  	f := func(n int) {
   103  		WithMapperCount(n)(&e.MapReduce)
   104  
   105  		mr.reset()
   106  
   107  		for err := range e.run(ctx, rng) {
   108  			t.Errorf("%d mappers: %+v", n, err)
   109  		}
   110  
   111  		t.Log(n, len(mr.widths), mr.widths)
   112  
   113  		for _, width := range mr.widths {
   114  			if width > testWidth {
   115  				t.Log(mr.ranges)
   116  				t.Errorf("range was greater than maximum, expected %d, but got %d", width, testWidth)
   117  				break
   118  			}
   119  		}
   120  	}
   121  
   122  	for i := 0; i <= rng.Width(); i++ {
   123  		f(i)
   124  	}
   125  }
   126  
   127  func TestEngineMinSliceSize(t *testing.T) {
   128  	ctx := context.Background()
   129  	DefaultThreadCount = -1
   130  
   131  	rng := Range{
   132  		Start: 42,
   133  		End:   42 + 53, // Give this a width of 53, a prime number.
   134  	}
   135  
   136  	mr := &TestMR{}
   137  
   138  	e := &engine{
   139  		MapReduce: MapReduce{
   140  			m: mr,
   141  			r: mr,
   142  		},
   143  	}
   144  
   145  	testWidth := 7
   146  
   147  	WithOrdering(true)(&e.MapReduce)
   148  	WithThreadCount(1)(&e.MapReduce)
   149  	WithMinStripeSize(testWidth)(&e.MapReduce)
   150  
   151  	f := func(n int) {
   152  		WithMapperCount(n)(&e.MapReduce)
   153  
   154  		mr.reset()
   155  
   156  		for err := range e.run(ctx, rng) {
   157  			t.Errorf("%d mappers: %+v", n, err)
   158  		}
   159  
   160  		t.Log(n, len(mr.widths), mr.widths)
   161  
   162  		for _, width := range mr.widths {
   163  			if width < testWidth {
   164  				t.Log(mr.ranges)
   165  				t.Errorf("range was less than minimum, expected %d, but got %d", width, testWidth)
   166  				break
   167  			}
   168  		}
   169  	}
   170  
   171  	for i := 0; i <= rng.Width(); i++ {
   172  		f(i)
   173  	}
   174  }
   175  
   176  type TestMRBlock struct {
   177  	reduces      int
   178  	duringReduce bool
   179  }
   180  
   181  func (mr *TestMRBlock) Map(ctx context.Context, in interface{}) (out interface{}, err error) {
   182  	out = struct{}{}
   183  
   184  	if !mr.duringReduce {
   185  		<-ctx.Done()
   186  		return out, ctx.Err()
   187  	}
   188  
   189  	return out, nil
   190  }
   191  
   192  func (mr *TestMRBlock) Reduce(ctx context.Context, in interface{}) error {
   193  	mr.reduces++
   194  
   195  	if mr.duringReduce {
   196  		<-ctx.Done()
   197  		return ctx.Err()
   198  	}
   199  
   200  	return nil
   201  }
   202  
   203  func TestEngineStall(t *testing.T) {
   204  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
   205  	defer cancel()
   206  
   207  	DefaultThreadCount = -1
   208  
   209  	rng := Range{
   210  		Start: 42,
   211  		End:   42 + 53, // Give this a width of 53, a prime number.
   212  	}
   213  
   214  	mr := &TestMRBlock{}
   215  
   216  	e := &engine{
   217  		MapReduce: MapReduce{
   218  			m: mr,
   219  			r: mr,
   220  		},
   221  	}
   222  
   223  	n := 4
   224  
   225  	WithThreadCount(n)(&e.MapReduce)
   226  	WithMapperCount(n)(&e.MapReduce)
   227  
   228  	var errCount int
   229  	for err := range e.run(ctx, rng) {
   230  		t.Logf("%+v", err)
   231  		errCount++
   232  	}
   233  
   234  	if errCount != n {
   235  		t.Errorf("expected %d errors, but got %d", n, errCount)
   236  	}
   237  
   238  	expectedReduces := 0
   239  	if mr.reduces != expectedReduces {
   240  		t.Errorf("wrong number of mappers got to reduce phase, expected %d, but got %d", expectedReduces, mr.reduces)
   241  	}
   242  
   243  	errCount = 0
   244  	mr.duringReduce = true
   245  
   246  	ctx, cancel = context.WithTimeout(context.Background(), 10*time.Millisecond)
   247  	defer cancel()
   248  
   249  	for err := range e.run(ctx, rng) {
   250  		t.Logf("%+v", err)
   251  		errCount++
   252  	}
   253  
   254  	if errCount != n {
   255  		t.Errorf("expected %d errors, but got %d", n, errCount)
   256  	}
   257  
   258  	expectedReduces = 1
   259  	if mr.reduces != expectedReduces {
   260  		t.Errorf("wrong number of mappers got to reduce phase, expected %d, but got %d", expectedReduces, mr.reduces)
   261  	}
   262  
   263  }