Skip to content

Instantly share code, notes, and snippets.

@candera
Last active June 30, 2020 12:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save candera/5223564 to your computer and use it in GitHub Desktop.
Save candera/5223564 to your computer and use it in GitHub Desktop.
A fairly naive implementation of a slow InputStream. Useful for simulating slow HTTP servers in Ring apps. Also shows how to proxy overloaded methods.
(defn slow-stream
"Returns an implementation of InputStream that takes `time`
milliseconds to return a random buffer of `size` bytes."
[time size]
(let [first-read (atom nil)
bytes-read (atom 0)
rate (/ (double time) size)]
(proxy [java.io.InputStream] []
(read ^int
([]
(let [now (System/currentTimeMillis)]
(when-not @first-read (reset! first-read now))
(let [sleep-to (+ @first-read (long (* rate @bytes-read)))
sleep-for (- sleep-to now)]
(when (pos? sleep-for)
(Thread/sleep sleep-for))))
(let [result (if (< @bytes-read size) (+ 65 128 (rand-int 26)) -1)]
(swap! bytes-read inc)
result))
;; TODO: This is behaving strangely. Test further.
([^bytes bytes]
(let [first-b (.read this)]
(if (neg? first-b)
-1
(loop [b first-b
bytes-read 1]
(if (neg? b)
(dec bytes-read)
(do
(aset bytes (dec bytes-read) (byte (- b 128)))
(if (< bytes-read (alength bytes))
(recur (.read this) (inc bytes-read))
bytes-read)))))))))))
// A Java variation on the same theme
package user;
import java.io.InputStream;
import java.util.Random;
public class SlowInputStream extends InputStream {
private final long time;
private final long size;
private final double rate;
private final Random random = new Random();
private long first_read = -1;
private long bytes_read = 0;
public SlowInputStream(int time, int size) {
this.time = time;
this.size = size;
this.rate = Double.valueOf(time) / size;
}
@Override
public int read() {
long now = System.currentTimeMillis();
if (now != -1) {
first_read = now;
}
long sleep_to = first_read + (long)(rate * bytes_read);
long sleep_for = sleep_to - now;
if (sleep_for > 0) {
try {
Thread.sleep(sleep_for);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
int result = bytes_read < size ? random.nextInt(256) : -1;
bytes_read++;
return result;
}
}
@Siddhartha90
Copy link

Handy! Also handy for UnitTesting :)

@candera
Copy link
Author

candera commented Jun 30, 2020

Handy! Also handy for UnitTesting :)

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment