github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/flow/io_test.gno (about) 1 // 2 // Written by Maxim Khitrov (November 2012) 3 // 4 5 package flow 6 7 import ( 8 "bytes" 9 "testing" 10 "time" 11 12 ios_test "internal/os_test" 13 ) 14 15 // XXX ugh, I can't even sleep milliseconds. 16 // XXX 17 18 const ( 19 _50ms = 50 * time.Millisecond 20 _100ms = 100 * time.Millisecond 21 _200ms = 200 * time.Millisecond 22 _300ms = 300 * time.Millisecond 23 _400ms = 400 * time.Millisecond 24 _500ms = 500 * time.Millisecond 25 ) 26 27 func nextStatus(m *Monitor) Status { 28 samples := m.samples 29 for i := 0; i < 30; i++ { 30 if s := m.Status(); s.Samples != samples { 31 return s 32 } 33 ios_test.Sleep(5 * time.Millisecond) 34 } 35 return m.Status() 36 } 37 38 func TestReader(t *testing.T) { 39 in := make([]byte, 100) 40 for i := range in { 41 in[i] = byte(i) 42 } 43 b := make([]byte, 100) 44 r := NewReader(bytes.NewReader(in), 100) 45 start := time.Now() 46 47 // Make sure r implements Limiter 48 _ = Limiter(r) 49 50 // 1st read of 10 bytes is performed immediately 51 if n, err := r.Read(b); n != 10 { 52 t.Fatalf("r.Read(b) expected 10 (<nil>); got %v", n) 53 } else if err != nil { 54 t.Fatalf("r.Read(b) expected 10 (<nil>); got %v (%v)", n, err.Error()) 55 } else if rt := time.Since(start); rt > _50ms { 56 t.Fatalf("r.Read(b) took too long (%v)", rt.String()) 57 } 58 59 // No new Reads allowed in the current sample 60 r.SetBlocking(false) 61 if n, err := r.Read(b); n != 0 { 62 t.Fatalf("r.Read(b) expected 0 (<nil>); got %v", n) 63 } else if err != nil { 64 t.Fatalf("r.Read(b) expected 0 (<nil>); got %v (%v)", n, err.Error()) 65 } else if rt := time.Since(start); rt > _50ms { 66 t.Fatalf("r.Read(b) took too long (%v)", rt.String()) 67 } 68 69 status := [6]Status{0: r.Status()} // No samples in the first status 70 71 // 2nd read of 10 bytes blocks until the next sample 72 // r.SetBlocking(true) 73 ios_test.Sleep(100 * time.Millisecond) 74 if n, err := r.Read(b[10:]); n != 10 { 75 t.Fatalf("r.Read(b[10:]) expected 10 (<nil>); got %v", n) 76 } else if err != nil { 77 t.Fatalf("r.Read(b[10:]) expected 10 (<nil>); got %v (%v)", n, err.Error()) 78 } else if rt := time.Since(start); rt < _100ms { 79 t.Fatalf("r.Read(b[10:]) returned ahead of time (%v)", rt.String()) 80 } 81 82 status[1] = r.Status() // 1st sample 83 status[2] = nextStatus(r.Monitor) // 2nd sample 84 status[3] = nextStatus(r.Monitor) // No activity for the 3rd sample 85 86 if n := r.Done(); n != 20 { 87 t.Fatalf("r.Done() expected 20; got %v", n) 88 } 89 90 status[4] = r.Status() 91 status[5] = nextStatus(r.Monitor) // Timeout 92 start = status[0].Start 93 94 // Active, Start, Duration, Idle, Bytes, Samples, InstRate, CurRate, AvgRate, PeakRate, BytesRem, TimeRem, Progress 95 want := []Status{ 96 {true, start, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 97 {true, start, _100ms, 0, 10, 1, 100, 100, 100, 100, 0, 0, 0}, 98 {true, start, _200ms, _100ms, 20, 2, 100, 100, 100, 100, 0, 0, 0}, 99 {true, start, _300ms, _200ms, 20, 3, 0, 90, 67, 100, 0, 0, 0}, 100 {false, start, _300ms, 0, 20, 3, 0, 0, 67, 100, 0, 0, 0}, 101 {false, start, _300ms, 0, 20, 3, 0, 0, 67, 100, 0, 0, 0}, 102 } 103 for i, s := range status { 104 // XXX s := s 105 if !statusesAreEqual(&s, &want[i]) { 106 t.Errorf("r.Status(%v)\nexpected: %v\ngot : %v", i, want[i].String(), s.String()) 107 } 108 } 109 if !bytes.Equal(b[:20], in[:20]) { 110 t.Errorf("r.Read() input doesn't match output") 111 } 112 } 113 114 // XXX blocking writer test doesn't work. 115 func _TestWriter(t *testing.T) { 116 b := make([]byte, 100) 117 for i := range b { 118 b[i] = byte(i) 119 } 120 w := NewWriter(&bytes.Buffer{}, 200) 121 start := time.Now() 122 123 // Make sure w implements Limiter 124 _ = Limiter(w) 125 126 // Non-blocking 20-byte write for the first sample returns ErrLimit 127 w.SetBlocking(false) 128 if n, err := w.Write(b); n != 20 || err != ErrLimit { 129 t.Fatalf("w.Write(b) expected 20 (ErrLimit); got %v (%v)", n, err.Error()) 130 } else if rt := time.Since(start); rt > _50ms { 131 t.Fatalf("w.Write(b) took too long (%v)", rt) 132 } 133 134 // Blocking 80-byte write 135 // w.SetBlocking(true) 136 // XXX This test doesn't work, because w.Write calls w.Limit(block=false), 137 // XXX and it returns ErrLimit after 20. What we want is to keep waiting until 80 is returned, 138 // XXX but blocking isn't supported. Sleeping 800 shouldn't be sufficient either (its a burst). 139 // XXX This limits the usage of Limiter and m.Limit(). 140 ios_test.Sleep(800 * time.Millisecond) 141 if n, err := w.Write(b[20:]); n < 80 { 142 } else if n != 80 || err != nil { 143 t.Fatalf("w.Write(b[20:]) expected 80 (<nil>); got %v (%v)", n, err.Error()) 144 } else if rt := time.Since(start); rt < _300ms { 145 // Explanation for `rt < _300ms` (as opposed to `< _400ms`) 146 // 147 // |<-- start | | 148 // epochs: -----0ms|---100ms|---200ms|---300ms|---400ms 149 // sends: 20|20 |20 |20 |20# 150 // 151 // NOTE: The '#' symbol can thus happen before 400ms is up. 152 // Thus, we can only panic if rt < _300ms. 153 t.Fatalf("w.Write(b[20:]) returned ahead of time (%v)", rt.String()) 154 } 155 156 w.SetTransferSize(100) 157 status := []Status{w.Status(), nextStatus(w.Monitor)} 158 start = status[0].Start 159 160 // Active, Start, Duration, Idle, Bytes, Samples, InstRate, CurRate, AvgRate, PeakRate, BytesRem, TimeRem, Progress 161 want := []Status{ 162 {true, start, _400ms, 0, 80, 4, 200, 200, 200, 200, 20, _100ms, 80000}, 163 {true, start, _500ms, _100ms, 100, 5, 200, 200, 200, 200, 0, 0, 100000}, 164 } 165 for i, s := range status { 166 // XXX s := s 167 if !statusesAreEqual(&s, &want[i]) { 168 t.Errorf("w.Status(%v)\nexpected: %v\ngot : %v\n", i, want[i].String(), s.String()) 169 } 170 } 171 if !bytes.Equal(b, w.Writer.(*bytes.Buffer).Bytes()) { 172 t.Errorf("w.Write() input doesn't match output") 173 } 174 } 175 176 const ( 177 maxDeviationForDuration = 50 * time.Millisecond 178 maxDeviationForRate int64 = 50 179 ) 180 181 // statusesAreEqual returns true if s1 is equal to s2. Equality here means 182 // general equality of fields except for the duration and rates, which can 183 // drift due to unpredictable delays (e.g. thread wakes up 25ms after 184 // `time.Sleep` has ended). 185 func statusesAreEqual(s1 *Status, s2 *Status) bool { 186 if s1.Active == s2.Active && 187 s1.Start == s2.Start && 188 durationsAreEqual(s1.Duration, s2.Duration, maxDeviationForDuration) && 189 s1.Idle == s2.Idle && 190 s1.Bytes == s2.Bytes && 191 s1.Samples == s2.Samples && 192 ratesAreEqual(s1.InstRate, s2.InstRate, maxDeviationForRate) && 193 ratesAreEqual(s1.CurRate, s2.CurRate, maxDeviationForRate) && 194 ratesAreEqual(s1.AvgRate, s2.AvgRate, maxDeviationForRate) && 195 ratesAreEqual(s1.PeakRate, s2.PeakRate, maxDeviationForRate) && 196 s1.BytesRem == s2.BytesRem && 197 durationsAreEqual(s1.TimeRem, s2.TimeRem, maxDeviationForDuration) && 198 s1.Progress == s2.Progress { 199 return true 200 } 201 return false 202 } 203 204 func durationsAreEqual(d1 time.Duration, d2 time.Duration, maxDeviation time.Duration) bool { 205 return d2-d1 <= maxDeviation 206 } 207 208 func ratesAreEqual(r1 int64, r2 int64, maxDeviation int64) bool { 209 sub := r1 - r2 210 if sub < 0 { 211 sub = -sub 212 } 213 if sub <= maxDeviation { 214 return true 215 } 216 return false 217 }