| 100 | self._r = self.env.curl_parse_headerfile(self.headerfile) |
| 101 | |
| 102 | def stutter_check(self, chunks: [str], stutter: datetime.timedelta): |
| 103 | if not self.proc: |
| 104 | self.start() |
| 105 | for chunk in chunks: |
| 106 | self.send(chunk) |
| 107 | time.sleep(stutter.total_seconds()) |
| 108 | recv_out, recv_err = self.close() |
| 109 | # assert we got everything back |
| 110 | assert "".join(chunks) == "".join(recv_out) |
| 111 | # now the tricky part: check *when* we got everything back |
| 112 | recv_times = [] |
| 113 | for line in "".join(recv_err).split('\n'): |
| 114 | m = re.match(r'^\s*(\d+:\d+:\d+(\.\d+)?) <= Recv data, (\d+) bytes.*', line) |
| 115 | if m and int(m.group(3)) > 0: |
| 116 | recv_times.append(datetime.time.fromisoformat(m.group(1))) |
| 117 | # received as many chunks as we sent |
| 118 | assert len(chunks) == len(recv_times), "received response not in {0} chunks, but {1}".format( |
| 119 | len(chunks), len(recv_times)) |
| 120 | |
| 121 | def microsecs(tdelta): |
| 122 | return ((tdelta.hour * 60 + tdelta.minute) * 60 + tdelta.second) * 1000000 + tdelta.microsecond |
| 123 | |
| 124 | recv_deltas = [] |
| 125 | last_mics = microsecs(recv_times[0]) |
| 126 | for ts in recv_times[1:]: |
| 127 | mics = microsecs(ts) |
| 128 | delta_mics = mics - last_mics |
| 129 | if delta_mics < 0: |
| 130 | delta_mics += datetime.time(23, 59, 59, 999999) |
| 131 | recv_deltas.append(datetime.timedelta(microseconds=delta_mics)) |
| 132 | last_mics = mics |
| 133 | stutter_td = datetime.timedelta(seconds=stutter.total_seconds() * 0.75) # 25% leeway |
| 134 | for idx, td in enumerate(recv_deltas[1:]): |
| 135 | assert stutter_td < td, \ |
| 136 | f"chunk {idx} arrived too early \n{recv_deltas}\nafter {td}\n{recv_err}" |