summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorScott Ostler <scottbot9000@gmail.com>2010-06-11 15:07:46 -0400
committerScott Ostler <scottbot9000@gmail.com>2010-06-11 15:07:46 -0400
commit378ba01ba8a4b67fb5d01dd5adc57fb72e3c86a5 (patch)
treee0cfed1c91bfc2d5c46f4158d2fe9279fe9dae24 /test
parent39ec1ea2114ff86e4f318b2994b457716476c4d0 (diff)
load testing code
Diffstat (limited to 'test')
-rw-r--r--test/dumpfm/load_test.clj81
-rw-r--r--test/dumpfm/millstone.clj95
2 files changed, 176 insertions, 0 deletions
diff --git a/test/dumpfm/load_test.clj b/test/dumpfm/load_test.clj
new file mode 100644
index 0000000..68eda68
--- /dev/null
+++ b/test/dumpfm/load_test.clj
@@ -0,0 +1,81 @@
+(ns dumpfm.load-test
+ (:import org.postgresql.ds.PGPoolingDataSource)
+ (:use clojure.contrib.json.read
+ clojure.contrib.json.write
+ clojure.contrib.seq-utils
+ clojure.contrib.sql
+ dumpfm.millstone))
+
+
+(let [db-host "localhost"
+ db-name "dumpfm"
+ db-user "postgres"
+ db-pass "root"]
+ (def *db* {:datasource (doto (new PGPoolingDataSource)
+ (.setServerName db-host)
+ (.setDatabaseName db-name)
+ (.setUser db-user)
+ (.setPassword db-pass)
+ (.setMaxConnections 3))}))
+
+(def userlist-query "
+select u.nick, u.hash
+from users u, messages m where u.user_id = m.user_id
+group by u.nick, u.hash
+having count(*) > 50
+order by count(*) desc
+")
+
+(print "Fetching userlist: ")
+(def userlist (time
+ (with-connection *db*
+ (with-query-results rs [userlist-query]
+ (doall rs)))))
+
+
+(def sample-messages-query "
+select content
+from messages
+order by random()
+limit 100
+")
+
+(print "Fetching messages: ")
+(def message-contents (time
+ (with-connection *db*
+ (with-query-results rs [sample-messages-query]
+ (doall (map :content rs))))))
+
+(defn login-client []
+ (let [user-info (rand-elt userlist)
+ params (select-keys user-info [:nick :hash])]
+ (do-setup-request! "/login"
+ :params params
+ :method "GET")))
+
+(defn refresh []
+ (let [params {:since (- (System/currentTimeMillis) 2000)
+ :room "test"}]
+ (do-request! "/refresh"
+ :params params
+ :method "GET")
+ (Thread/sleep 1000)))
+
+(defn post-msg []
+ (let [params {:content (rand-elt message-contents)
+ :room "test"}]
+ (do-request! "/msg"
+ :params params
+ :method "POST")))
+
+(def test-spec {:server "http://localhost:8080"
+ :clients 100
+ :requests 10000
+ :setup-func login-client
+ :funcs [[55 refresh]
+ [5 post-msg]]
+ :frequency 1
+ })
+
+(grind! test-spec)
+(System/exit 0) \ No newline at end of file
diff --git a/test/dumpfm/millstone.clj b/test/dumpfm/millstone.clj
new file mode 100644
index 0000000..e59bb61
--- /dev/null
+++ b/test/dumpfm/millstone.clj
@@ -0,0 +1,95 @@
+(ns dumpfm.millstone
+ (:use clojure.contrib.def
+ clojure.contrib.seq-utils
+ clojure-http.client))
+
+(def *spec*)
+(def *cookies*)
+
+(def printer (agent nil))
+
+(defn log [& args]
+ (send printer (fn [_] (apply println args))))
+
+(defmacro with-timing [e]
+ `(let [s# (System/nanoTime)
+ r# ~e
+ f# (System/nanoTime)]
+ [(float (/ (- f# s#) 1e6)) r#]))
+
+(defn do-base-request [server path method cookies params]
+ (let [method (.toUpperCase method)
+ url (str server path)]
+ (if (= method "GET")
+ (request (add-query-params url params) method nil cookies)
+ (request url method nil cookies params))))
+
+(defnk do-setup-request! [path
+ :params nil
+ :method "GET"]
+ (let [res (do-base-request (:server *spec*) path method *cookies* params)]
+ (if (:cookies res)
+ (set! *cookies* (merge *cookies* (:cookies res))))
+ res))
+
+(defnk do-request! [path
+ :params nil
+ :method :GET]
+ (let [[time res] (with-timing
+ (do-base-request (:server *spec*)
+ path
+ method
+ *cookies*
+ params))]
+ (log (format "%s - %sms [%s %s]" path time (:code res) (:msg res)))
+ (if (:cookies res)
+ (log "should set cookies" (:cookies res)))
+ res))
+
+(defn build-client! [spec client-id]
+ (binding [*cookies* {}]
+ (if (:setup-func spec)
+ ((:setup-func spec)))
+ {:client-id client-id
+ :cookies *cookies*}))
+
+(defn print-run-results [spec elapsed]
+ (log (format "\nFinished\n--------\n%s runs in %s s (%s r/s)\n%s clients"
+ (:requests spec)
+ (/ elapsed 1000)
+ (/ (:requests spec) elapsed 1000)
+ (:clients spec))))
+
+(defn build-func-list [routes]
+ (flatten (for [[n f] routes]
+ (repeat n f))))
+
+(defn grind! [spec]
+ (binding [*spec* spec]
+ (let [clients (doall
+ (for [id (range (:clients spec))]
+ (build-client! spec id)))
+ funcs (build-func-list (:funcs spec))
+ results (atom [])
+ counter (atom (:requests spec))
+ threads (doall
+ (for [c clients]
+ (Thread.
+ (fn []
+ (log "starting thread" (:client-id c))
+ (binding [*spec* spec
+ *cookies* (:cookies c)]
+ (loop []
+ (if (> (swap! counter dec) 0)
+ (let [f (rand-elt funcs)]
+ (f)
+ (recur))))
+ (log "finishing thread" (:client-id c)))))))]
+ (println "Finished setup")
+ (let [[elapsed _] (with-timing
+ (do
+ (doseq [t threads]
+ (.start t))
+ (doseq [t threads]
+ (.join t))))]
+ (print-run-results spec elapsed)))))