Commit 5aaee40b authored by Ricardo J. Mendez's avatar Ricardo J. Mendez

Refactored time calculation to a testable function

Renamed the old "data" namespace to "io", to keep Chrome-related functions
separate from the actual data transformation ones.

https://app.asana.com/0/50978096561390/62311740927042
parent 0005bc7a
(ns relevance.background
(:require [cljs.core.async :refer [>! <!]]
[relevance.data :as data]
[relevance.io :as io]
[relevance.utils :refer [on-channel key-from-url]]
[khroma.alarms :as alarms]
[khroma.context-menus :as menus]
......@@ -104,7 +105,7 @@
::initialize
(fn [_]
(go
(dispatch [:data-load (<! (data/load))])
(dispatch [:data-load (<! (io/load))])
(dispatch [::window-focus {:windowId (:id (<! (windows/get-last-focused {:populate false})))}])
;; We should only hook to the channels once, so we do it during the :initialize handler
(hook-to-channels))
......@@ -119,7 +120,7 @@
(when (empty? (:instance-id new-data))
(dispatch [:data-set :instance-id (.-uuid (random-uuid))]))
;; Save the data we just received
(data/save new-data)
(io/save new-data)
;; Process the suspend info
(let [suspend-info (:suspend-info new-data)
old-tab (:active-tab suspend-info)
......@@ -138,7 +139,7 @@
:data-set
(fn [app-state [_ key item]]
(let [new-state (assoc-in app-state [:data key] item)]
(data/save (:data new-state))
(io/save (:data new-state))
new-state)
))
......@@ -222,7 +223,7 @@
(fn [app-state [_ {:keys [message sender]}]]
; (console/log "GOT INTERNAL MESSAGE" message "from" sender)
(condp = (keyword message)
:reload-data (go (dispatch [:data-load (<! (data/load))])))
:reload-data (go (dispatch [:data-load (<! (io/load))])))
app-state
))
......@@ -292,22 +293,10 @@
:track-time
(fn [app-state [_ tab time]]
(let [url-times (or (get-in app-state url-time-path) {})
url (or (:url tab) "")
url-key (key-from-url url)
url-time (or (get url-times url-key)
{:url (:url tab)
:time 0
:timestamp 0})
;; Don't track two messages too close together
track? (and (not= 0 url-key)
(< 100 (- (now) (:timestamp url-time))))
new-time (assoc url-time :time (+ (:time url-time) time)
:title (:title tab)
:favIconUrl (:favIconUrl tab)
:timestamp (now))]
(console/trace time track? " milliseconds spent at " url-key tab)
(when track?
(dispatch [:data-set :url-times (assoc url-times url-key new-time)]))
new-times (data/track-time url-times tab time (now))]
(console/trace time " milliseconds spent at " tab)
(when (not= url-times new-times)
(dispatch [:data-set :url-times new-times]))
app-state
)))
......
(ns relevance.data
(:require [relevance.utils :refer [to-transit from-transit]]
[cljs.core.async :refer [<!]]
[khroma.storage :as storage])
(:require-macros [cljs.core.async.macros :refer [go]]))
(:require [relevance.utils :refer [key-from-url]]))
(defn save-raw
"Saves the data raw, without converting it to transit first."
[data callback]
(storage/set {:data data} storage/local callback))
(defn save
"Saves our data on the extension's storage after converting it to transit."
[data]
(save-raw (to-transit data) nil))
(defn load
"Returns a channel where we'll put the entire data block read from the
extension's storage"
[]
(go
(let [raw (:data (<! (storage/get)))]
(from-transit raw))))
(defn track-time
"Receives a time database, a tab record and a time to track, and returns new
time database which is the result of adding the time to the URL. It also
timestamps the record with the timestamp received."
[url-times tab time timestamp]
(let [url (or (:url tab) "")
url-key (key-from-url url)
url-time (or (get url-times url-key)
{:url url
:time 0
:timestamp 0})
;; Don't track two messages too close together
track? (not= 0 url-key)
new-time (assoc url-time :time (+ (:time url-time) time)
:title (:title tab)
:favIconUrl (:favIconUrl tab)
:timestamp timestamp)]
(if track?
(assoc url-times url-key new-time)
url-time)))
\ No newline at end of file
(ns relevance.io
(:require [relevance.utils :refer [to-transit from-transit key-from-url]]
[cljs.core.async :refer [<!]]
[khroma.storage :as storage])
(:require-macros [cljs.core.async.macros :refer [go]]))
;;;; We keep all the Chrome-specific i/o functions in a single file so that
;;;; can just have a separate namespace for data transformations
(defn save-raw
"Saves the data raw, without converting it to transit first."
[data callback]
(storage/set {:data data} storage/local callback))
(defn save
"Saves our data on the extension's storage after converting it to transit."
[data]
(save-raw (to-transit data) nil))
(defn load
"Returns a channel where we'll put the entire data block read from the
extension's storage"
[]
(go
(let [raw (:data (<! (storage/get)))]
(from-transit raw))))
(ns relevance.startpage
(:require [relevance.data :as data]
(:require [relevance.io :as io]
[relevance.utils :refer [key-from-url time-display]]
[dommy.core :refer-macros [sel sel1] :as dommy]
[khroma.runtime :as runtime]
......@@ -41,7 +41,7 @@
(defn do-transformations! []
(go
(let [data (<! (data/load))
(let [data (<! (io/load))
nodes (sel :.result_url_heading)
base (sel1 :.web_regular_results)]
(doseq [node nodes]
......
......@@ -9,7 +9,7 @@
[khroma.storage :as storage]
[reagent.core :as reagent]
[re-frame.core :refer [dispatch register-sub register-handler subscribe dispatch-sync]]
[relevance.data :as data])
[relevance.io :as io])
(:require-macros [cljs.core :refer [goog-define]]
[cljs.core.async.macros :refer [go go-loop]]
[reagent.ratom :refer [reaction]]))
......@@ -65,7 +65,7 @@
(fn [app-state [_ transit-data]]
;; We actually just need to save it, since ::storage-changed takes care
;; of loading it and importing it.
(data/save-raw transit-data #(runtime/send-message :reload-data))
(io/save-raw transit-data #(runtime/send-message :reload-data))
(-> app-state
(assoc-in [:ui-state :section] :time-track)
(assoc-in [:app-state :import] nil))
......
(ns relevance.test.data
(:require [cljs.test :refer-macros [deftest testing is are]]
[relevance.data :as data]
[relevance.utils :as utils]
))
(def test-db
{:instance-id "67b5c8eb-ae97-42ad-b6bc-803ac7e31221"
:suspend-info nil
:url-times {-327774960
{:url "http://numergent.com/tags/khroma/",
:time 117300,
:timestamp 1445964037798,
:title "Khroma articles",
:favIconUrl "http://numergent.com/favicon.ico"}
-526558523
{:url "http://numergent.com/opensource/",
:time 27300,
:timestamp 1445964037798,
:title "Open source projects",
:favIconUrl "http://numergent.com/favicon.ico"}
-2272190
{:url "http://lanyrd.com/conferences/",
:time 5617,
:timestamp 1446047687895,
:title "Conferences and events worldwide | Lanyrd",
:favIconUrl nil}
-327358142
{:url "https://developer.chrome.com/extensions/contextMenus",
:time 901682,
:timestamp 1446028215734,
:title "chrome.contextMenus - Google Chrome",
:favIconUrl "https://www.google.com/images/icons/product/chrome-32.png"}
1917381154
{:url "http://www.kitco.com/market/",
:time 4432,
:timestamp 1446051494575,
:title "New York spot price Gold...",
:favIconUrl nil
}
}})
(deftest test-track-time
(testing "Add time to an existing tab"
(let [tab {:url "http://numergent.com/opensource/"
:title "Open source project details"
:favIconUrl "http://numergent.com/favicon.png"}
ts 1445964037799
result (data/track-time (:url-times test-db)
tab
1234
ts)
tab-key (utils/key-from-url "http://numergent.com/opensource/")
item (get result tab-key)]
(is result)
(is (= 5 (count result)) "We should get back the same number of elements")
(is item)
(are [k] (= (k item) (k tab)) :url :title :favIconUrl) ; All the keys should have been updated from the record we're sending
(is (= ts (:timestamp item)) "Item should have been time-stamped")
(is (= 28534 (:time item)) "Time should have increased")
(doseq [other (dissoc result tab-key)]
(is (= (val other) (get (:url-times test-db) (key other))) "Other items should have remained untouched")
)
))
(testing "Add time to a new tab"
(let [tab {:url "http://numergent.com/"
:title "Numergent limited"
:favIconUrl "http://numergent.com/favicon.png"}
ts 1445964037799
result (data/track-time (:url-times test-db)
tab
9001
ts)
tab-key (utils/key-from-url "http://numergent.com/")
item (get result tab-key)]
(is result)
(is (= 6 (count result)) "We should have an extra element")
(is item)
(are [k] (= (k item) (k tab)) :url :title :favIconUrl) ; All the keys should have been updated from the record we're sending
(is (= ts (:timestamp item)) "Item should have been time-stamped")
(is (= 9001 (:time item)) "Time should have been assigned")
(doseq [other (dissoc result tab-key)]
(is (= (val other) (get (:url-times test-db) (key other))) "Other items should have remained untouched")
)
))
(testing "Add time to a new tab on an empty set"
(let [tab {:url "http://numergent.com/"
:title "Numergent limited"
:favIconUrl "http://numergent.com/favicon.png"}
ts 12345
result (data/track-time {} tab 9001 ts)
tab-key (utils/key-from-url "http://numergent.com/")
item (get result tab-key)]
(is result)
(is (= 1 (count result)) "We should have an extra element")
(is item)
(are [k] (= (k item) (k tab)) :url :title :favIconUrl) ; All the keys should have been updated from the record we're sending
(is (= ts (:timestamp item)) "Item should have been time-stamped")
(is (= 9001 (:time item)) "Time should have increased")
))
)
\ No newline at end of file
(ns relevance.test.runner
(:require [doo.runner :refer-macros [doo-tests]]
[relevance.test.data]
[relevance.test.migrations]
[relevance.test.utils]
))
))
(enable-console-print!)
(doo-tests 'relevance.test.migrations
(doo-tests 'relevance.test.data
'relevance.test.migrations
'relevance.test.utils)
......@@ -36,6 +36,7 @@
-314744948 "https://www.google.com/#hash"
-596725840 "https://www.google.com/somePath?q=v"
-327774960 "http://numergent.com/tags/khroma/"
-526558523 "http://numergent.com/opensource/"
)
)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment