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 }