Fix stack overflow during startup

Fix stack overflow during startup

--- src/lcmap/clownfish/system.clj
+++ src/lcmap/clownfish/system.clj
@@ -18,7 +18,7 @@

 (defn start
   ([environment]
-   (start default-retry-strategy))
+   (start environment default-retry-strategy))

   ([environment startup-retry-strategy]
    (again/with-retries startup-retry-strategy


Keep only the last 50 share entries.

Keep only the last 50 share entries.

--- src/oc/storage/api/entries.clj
+++ src/oc/storage/api/entries.clj
@@ -123,7 +123,7 @@
             entry (:existing-entry ctx)
             user (:user ctx)
             share-requests (:share-requests ctx)
-            shared {:shared (concat (or (:shared entry) []) share-requests)}
+            shared {:shared (take 50 (sort-by :shared-at (concat (or (:shared entry) []) share-requests)))}
             update-result (entry-res/update-entry-no-version! conn (:uuid entry) shared user)
             entry-with-comments (assoc entry :existing-comments (entry-res/list-comments-for-entry conn (:uuid entry)))]
     (do


Last step doesn't need to be an output.

Last step doesn't need to be an output.

--- src/onyx/static/validation.clj
+++ src/onyx/static/validation.clj
@@ -69,13 +69,6 @@
                                           input-tasks)))]
     (throw (Exception. (str "Input task " invalid " has incoming edge.")))))

-(defn validate-workflow-outputs [g output-tasks]
-  (when-let [invalid (ffirst (filter (comp seq second)
-                                     (map (juxt identity
-                                                (partial dep/immediate-dependents g))
-                                          output-tasks)))]
-    (throw (Exception. (str "Output task " invalid " has outgoing edge.")))))
-
 (defn validate-workflow-intermediates [g intermediate-tasks]
   (let [invalid-intermediate? (fn [[_ dependencies dependents]]
                                 (let [dependencies? (empty? dependencies)
@@ -92,8 +85,7 @@
 (defn validate-workflow-graph [{:keys [catalog workflow]}]
   (let [g (planning/to-dependency-graph workflow)]
     (validate-workflow-intermediates g (catalog->type-task-names catalog #{:function}))
-    (validate-workflow-inputs g (catalog->type-task-names catalog #{:input}))
-    (validate-workflow-outputs g (catalog->type-task-names catalog #{:output}))))
+    (validate-workflow-inputs g (catalog->type-task-names catalog #{:input}))))

 (defn validate-workflow [job]
   (validate-workflow-graph job)


Updated Hiccup to 1.0.5 in ring-devel

Updated Hiccup to 1.0.5 in ring-devel

--- ring-devel/project.clj
+++ ring-devel/project.clj
@@ -5,7 +5,7 @@
   :license {:name "The MIT License"
             :url "http://opensource.org/licenses/MIT"}
   :dependencies [[ring/ring-core "1.3.0-beta2"]
-                 [hiccup "1.0.3"]
+                 [hiccup "1.0.5"]
                  [clj-stacktrace "0.2.7"]
                  [ns-tracker "0.2.2"]]
   :profiles


Fixed issue with doseq over deftests in the events tests

--- test/com/puppetlabs/puppetdb/test/query/events.clj
+++ test/com/puppetlabs/puppetdb/test/query/events.clj
@@ -16,8 +16,8 @@

 ;; Begin tests

-(doseq [version [:v3 :v4]]
-  (deftest test-compile-resource-event-term
+(deftest test-compile-resource-event-term
+  (doseq [version [:v3 :v4]]
     (let [ops (event-query/resource-event-ops version)]
       (testing "should succesfully compile a valid equality query"
         (is (= (query/compile-term ops ["=" "report" "blah"])
@@ -25,38 +25,38 @@
                 :params  ["blah"]})))
       (testing "should fail with an invalid equality query"
         (is (thrown-with-msg?
-              IllegalArgumentException #"foo is not a queryable object for resource events"
-              (query/compile-term ops ["=" "foo" "foo"]))))
+             IllegalArgumentException #"foo is not a queryable object for resource events"
+             (query/compile-term ops ["=" "foo" "foo"]))))
       (testing "should successfully compile valid inequality queries"
         (let [start-time  "2011-01-01T12:00:01-03:00"
               end-time    "2011-01-01T12:00:03-03:00"]
           (is (= (query/compile-term ops [">" "timestamp" start-time])
-                {:where   "resource_events.timestamp > ?"
-                 :params  [(to-timestamp start-time)]}))
+                 {:where   "resource_events.timestamp > ?"
+                  :params  [(to-timestamp start-time)]}))
           (is (= (query/compile-term ops ["<" "timestamp" end-time])
-                {:where   "resource_events.timestamp < ?"
-                 :params  [(to-timestamp end-time)]}))
+                 {:where   "resource_events.timestamp < ?"
+                  :params  [(to-timestamp end-time)]}))
           (is (= (query/compile-term ops
-                    ["and" [">=" "timestamp" start-time] ["<=" "timestamp" end-time]])
-                {:where   "(resource_events.timestamp >= ?) AND (resource_events.timestamp <= ?)"
-                 :params  [(to-timestamp start-time) (to-timestamp end-time)]}))))
+                                     ["and" [">=" "timestamp" start-time] ["<=" "timestamp" end-time]])
+                 {:where   "(resource_events.timestamp >= ?) AND (resource_events.timestamp <= ?)"
+                  :params  [(to-timestamp start-time) (to-timestamp end-time)]}))))
       (testing "should fail with invalid inequality queries"
         (is (thrown-with-msg?
-              IllegalArgumentException #"> requires exactly two arguments"
-              (query/compile-term ops [">" "timestamp"])))
+             IllegalArgumentException #"> requires exactly two arguments"
+             (query/compile-term ops [">" "timestamp"])))
         (is (thrown-with-msg?
-              IllegalArgumentException #"'foo' is not a valid timestamp value"
-              (query/compile-term ops [">" "timestamp" "foo"])))
+             IllegalArgumentException #"'foo' is not a valid timestamp value"
+             (query/compile-term ops [">" "timestamp" "foo"])))
         (is (thrown-with-msg?
-              IllegalArgumentException #"> operator does not support object 'resource_type'"
-              (query/compile-term ops [">" "resource_type" "foo"]))))))
-
-  (deftest resource-event-queries
-    (let [basic             (store-example-report! (:basic reports) (now))
-          report-hash       (:hash basic)
-          basic-events      (get-in reports [:basic :resource-events])
-          basic-events-map  (get-events-map (:basic reports))]
-
+             IllegalArgumentException #"> operator does not support object 'resource_type'"
+             (query/compile-term ops [">" "resource_type" "foo"])))))))
+
+(deftest resource-event-queries
+  (let [basic             (store-example-report! (:basic reports) (now))
+        report-hash       (:hash basic)
+        basic-events      (get-in reports [:basic :resource-events])
+        basic-events-map  (get-events-map (:basic reports))]
+    (doseq [version [:v3 :v4]]
       (testing "resource event retrieval by report"
         (testing "should return the list of resource events for a given report hash"
           (let [expected  (expected-resource-events basic-events basic)
@@ -67,79 +67,78 @@
         (testing "should return the list of resource events that occurred before a given time"
           (let [end-time  "2011-01-01T12:00:03-03:00"
                 expected    (expected-resource-events
-                              (kitchensink/select-values basic-events-map [1 3])
-                              basic)
+                             (kitchensink/select-values basic-events-map [1 3])
+                             basic)
                 actual      (resource-events-query-result version ["<" "timestamp" end-time])]
             (is (= actual expected))))
         (testing "should return the list of resource events that occurred after a given time"
           (let [start-time  "2011-01-01T12:00:01-03:00"
                 expected    (expected-resource-events
-                              (kitchensink/select-values basic-events-map [2 3])
-                              basic)
+                             (kitchensink/select-values basic-events-map [2 3])
+                             basic)
                 actual      (resource-events-query-result version [">" "timestamp" start-time])]
             (is (= actual expected))))
         (testing "should return the list of resource events that occurred between a given start and end time"
           (let [start-time  "2011-01-01T12:00:01-03:00"
                 end-time    "2011-01-01T12:00:03-03:00"
                 expected    (expected-resource-events
-                              (kitchensink/select-values basic-events-map [3])
-                              basic)
+                             (kitchensink/select-values basic-events-map [3])
+                             basic)
                 actual      (resource-events-query-result
-                              version
-                              ["and"  [">" "timestamp" start-time]
-                                      ["<" "timestamp" end-time]])]
+                             version
+                             ["and"  [">" "timestamp" start-time]
+                              ["<" "timestamp" end-time]])]
             (is (= actual expected))))
         (testing "should return the list of resource events that occurred between a given start and end time (inclusive)"
           (let [start-time  "2011-01-01T12:00:01-03:00"
                 end-time    "2011-01-01T12:00:03-03:00"
                 expected    (expected-resource-events
-                              (kitchensink/select-values basic-events-map [1 2 3])
-                              basic)
+                             (kitchensink/select-values basic-events-map [1 2 3])
+                             basic)
                 actual      (resource-events-query-result
-                              version
-                              ["and"   [">=" "timestamp" start-time]
-                                       ["<=" "timestamp" end-time]])]
+                             version
+                             ["and"   [">=" "timestamp" start-time]
+                              ["<=" "timestamp" end-time]])]
             (is (= actual expected)))))

       (testing "when querying with a limit"
         (let [num-events (count basic-events)]
           (testing "should succeed if the number of returned events is less than the limit"
             (is (= num-events
-                  (count (resource-events-limited-query-result version (inc num-events) ["=" "report" report-hash])))))
+                   (count (resource-events-limited-query-result version (inc num-events) ["=" "report" report-hash])))))
           (testing "should fail if the number of returned events would exceed the limit"
             (is (thrown-with-msg?
-              IllegalStateException #"Query returns more than the maximum number of results"
-              (resource-events-limited-query-result version (dec num-events) ["=" "report" report-hash]))))))
-
+                 IllegalStateException #"Query returns more than the maximum number of results"
+                 (resource-events-limited-query-result version (dec num-events) ["=" "report" report-hash]))))))
       (testing "equality queries"
         (doseq [[field value matches]
-                    [[:resource-type    "Notify"                            [1 2 3]]
-                     [:resource-title   "notify, yo"                        [1]]
-                     [:status           "success"                           [1 2]]
-                     [:property         "message"                           [1 2]]
-                     [:property         nil                                 [3]]
-                     [:old-value        ["what" "the" "woah"]               [1]]
-                     [:new-value        "notify, yo"                        [1]]
-                     [:message          "defined 'message' as 'notify, yo'" [1 2]]
-                     [:message          nil                                 [3]]
-                     [:resource-title   "bunk"                              []]
-                     [:certname         "foo.local"                         [1 2 3]]
-                     [:certname         "bunk.remote"                       []]
-                     [:file             "foo.pp"                            [1]]
-                     [:file             "bar"                               [3]]
-                     [:file             nil                                 [2]]
-                     [:line             2                                   [3]]
-                     [:line             nil                                 [2]]
-                     [:containing-class "Foo"                               [3]]
-                     [:containing-class nil                                 [1 2]]]]
+                [[:resource-type    "Notify"                            [1 2 3]]
+                 [:resource-title   "notify, yo"                        [1]]
+                 [:status           "success"                           [1 2]]
+                 [:property         "message"                           [1 2]]
+                 [:property         nil                                 [3]]
+                 [:old-value        ["what" "the" "woah"]               [1]]
+                 [:new-value        "notify, yo"                        [1]]
+                 [:message          "defined 'message' as 'notify, yo'" [1 2]]
+                 [:message          nil                                 [3]]
+                 [:resource-title   "bunk"                              []]
+                 [:certname         "foo.local"                         [1 2 3]]
+                 [:certname         "bunk.remote"                       []]
+                 [:file             "foo.pp"                            [1]]
+                 [:file             "bar"                               [3]]
+                 [:file             nil                                 [2]]
+                 [:line             2                                   [3]]
+                 [:line             nil                                 [2]]
+                 [:containing-class "Foo"                               [3]]
+                 [:containing-class nil                                 [1 2]]]]
           (testing (format "equality query on field '%s'" field)
             (let [expected  (expected-resource-events
-                              (kitchensink/select-values basic-events-map matches)
-                              basic)
+                             (kitchensink/select-values basic-events-map matches)
+                             basic)
                   query     ["=" (name field) value]
                   actual    (resource-events-query-result version query)]
               (is (= actual expected)
-                (format "Results didn't match for query '%s'" query))))))
+                  (format "Results didn't match for query '%s'" query))))))

       (testing "'not' queries"
         (doseq [[field value matches]
@@ -165,12 +164,12 @@
                  [:containing-class nil                                 [3]]]]
           (testing (format "'not' query on field '%s'" field)
             (let [expected  (expected-resource-events
-                              (kitchensink/select-values basic-events-map matches)
-                              basic)
+                             (kitchensink/select-values basic-events-map matches)
+                             basic)
                   query     ["not" ["=" (name field) value]]
                   actual    (resource-events-query-result version query)]
               (is (= actual expected)
-                (format "Results didn't match for query '%s'" query))))))
+                  (format "Results didn't match for query '%s'" query))))))

       (testing "regex queries"
         (doseq [[field value matches]
@@ -187,12 +186,12 @@
                  [:containing-class "[fF]oo"                [3]]]]
           (testing (format "regex query on field '%s'" field)
             (let [expected  (expected-resource-events
-                              (kitchensink/select-values basic-events-map matches)
-                              basic)
+                             (kitchensink/select-values basic-events-map matches)
+                             basic)
                   query     ["~" (name field) value]
                   actual    (resource-events-query-result version query)]
               (is (= actual expected)
-                (format "Results didn't match for query '%s'" query))))))
+                  (format "Results didn't match for query '%s'" query))))))

       (testing "negated regex queries"
         (doseq [[field value matches]
@@ -209,113 +208,113 @@
                  [:containing-class "[fF]oo"                [1 2]]]]
           (testing (format "negated regex query on field '%s'" field)
             (let [expected  (expected-resource-events
-                              (kitchensink/select-values basic-events-map matches)
-                              basic)
+                             (kitchensink/select-values basic-events-map matches)
+                             basic)
                   query     ["not" ["~" (name field) value]]
                   actual    (resource-events-query-result version query)]
               (is (= actual expected)
-                (format "Results didn't match for query '%s'" query))))))
+                  (format "Results didn't match for query '%s'" query))))))

       (testing "compound queries"
         (testing "'or' equality queries"
           (doseq [[terms matches]
-                    [[[[:resource-title "notify, yo"]
-                       [:status         "skipped"]]       [1 3]]
-                     [[[:resource-type  "bunk"]
-                       [:resource-title "notify, yar"]]   [2]]
-                     [[[:resource-type  "bunk"]
-                       [:status         "bunk"]]          []]
-                     [[[:new-value      "notify, yo"]
-                       [:resource-title "notify, yar"]
-                       [:resource-title "hi"]]            [1 2 3]]
-                     [[[:file           "foo.pp"]
-                       [:line           2]]               [1 3]]]]
+                  [[[[:resource-title "notify, yo"]
+                     [:status         "skipped"]]       [1 3]]
+                   [[[:resource-type  "bunk"]
+                     [:resource-title "notify, yar"]]   [2]]
+                   [[[:resource-type  "bunk"]
+                     [:status         "bunk"]]          []]
+                   [[[:new-value      "notify, yo"]
+                     [:resource-title "notify, yar"]
+                     [:resource-title "hi"]]            [1 2 3]]
+                   [[[:file           "foo.pp"]
+                     [:line           2]]               [1 3]]]]
             (let [expected    (expected-resource-events
-                                (kitchensink/select-values basic-events-map matches)
-                                basic)
+                               (kitchensink/select-values basic-events-map matches)
+                               basic)
                   term-fn     (fn [[field value]] ["=" (name field) value])
                   query       (vec (cons "or" (map term-fn terms)))
                   actual      (resource-events-query-result version query)]
               (is (= actual expected)
-                (format "Results didn't match for query '%s'" query))))))
-
-        (testing "'and' equality queries"
-          (doseq [[terms matches]
-                  [[[[:resource-type    "Notify"]
-                     [:status           "success"]]     [1 2]]
-                   [[[:resource-type    "bunk"]
-                     [:resource-title   "notify, yar"]] []]
-                   [[[:resource-title   "notify, yo"]
-                     [:status           "skipped"]]     []]
-                   [[[:new-value        "notify, yo"]
-                     [:resource-type    "Notify"]
-                     [:certname         "foo.local"]]   [1]]
-                   [[[:certname         "foo.local"]
-                     [:resource-type    "Notify"]]      [1 2 3]]
-                   [[[:file             "foo.pp"]
-                     [:line             1]]             [1]]
-                   [[[:containing-class "Foo"]]         [3]]]]
-            (let [expected    (expected-resource-events
-                                (kitchensink/select-values basic-events-map matches)
-                                basic)
-                  term-fn     (fn [[field value]] ["=" (name field) value])
-                  query       (vec (cons "and" (map term-fn terms)))
-                  actual      (resource-events-query-result version query)]
-              (is (= actual expected)
+                  (format "Results didn't match for query '%s'" query))))))
+
+      (testing "'and' equality queries"
+        (doseq [[terms matches]
+                [[[[:resource-type    "Notify"]
+                   [:status           "success"]]     [1 2]]
+                 [[[:resource-type    "bunk"]
+                   [:resource-title   "notify, yar"]] []]
+                 [[[:resource-title   "notify, yo"]
+                   [:status           "skipped"]]     []]
+                 [[[:new-value        "notify, yo"]
+                   [:resource-type    "Notify"]
+                   [:certname         "foo.local"]]   [1]]
+                 [[[:certname         "foo.local"]
+                   [:resource-type    "Notify"]]      [1 2 3]]
+                 [[[:file             "foo.pp"]
+                   [:line             1]]             [1]]
+                 [[[:containing-class "Foo"]]         [3]]]]
+          (let [expected    (expected-resource-events
+                             (kitchensink/select-values basic-events-map matches)
+                             basic)
+                term-fn     (fn [[field value]] ["=" (name field) value])
+                query       (vec (cons "and" (map term-fn terms)))
+                actual      (resource-events-query-result version query)]
+            (is (= actual expected)
                 (format "Results didn't match for query '%s'" query)))))

-        (testing "nested compound queries"
-          (doseq [[query matches]
-                  [[["and"
-                      ["or"
-                        ["=" "resource-title" "hi"]
-                        ["=" "resource-title" "notify, yo"]]
-                      ["=" "status" "success"]]               [1]]
-                   [["or"
-                      ["and"
-                        ["=" "resource-title" "hi"]
-                        ["=" "status" "success"]]
-                      ["and"
-                        ["=" "resource-type" "Notify"]
-                        ["=" "property" "message"]]]          [1 2]]
-                   [["or"
-                      ["and"
-                        ["=" "file" "foo.pp"]
-                        ["=" "line" 1]]
-                      ["=" "line" 2]]                         [1 3]]]]
-            (let [expected  (expected-resource-events
-                              (kitchensink/select-values basic-events-map matches)
-                              basic)
-                  actual    (resource-events-query-result version query)]
-              (is (= actual expected)
+      (testing "nested compound queries"
+        (doseq [[query matches]
+                [[["and"
+                   ["or"
+                    ["=" "resource-title" "hi"]
+                    ["=" "resource-title" "notify, yo"]]
+                   ["=" "status" "success"]]               [1]]
+                 [["or"
+                   ["and"
+                    ["=" "resource-title" "hi"]
+                    ["=" "status" "success"]]
+                   ["and"
+                    ["=" "resource-type" "Notify"]
+                    ["=" "property" "message"]]]          [1 2]]
+                 [["or"
+                   ["and"
+                    ["=" "file" "foo.pp"]
+                    ["=" "line" 1]]
+                   ["=" "line" 2]]                         [1 3]]]]
+          (let [expected  (expected-resource-events
+                           (kitchensink/select-values basic-events-map matches)
+                           basic)
+                actual    (resource-events-query-result version query)]
+            (is (= actual expected)
                 (format "Results didn't match for query '%s'" query)))))

-        (testing "compound queries with both equality and inequality"
-          (doseq [[query matches]
-                  [[["and"
-                      ["=" "status" "success"]
-                      ["<" "timestamp" "2011-01-01T12:00:02-03:00"]]  [1]]
-                   [["or"
-                      ["=" "status" "skipped"]
-                      ["<" "timestamp" "2011-01-01T12:00:02-03:00"]]  [1 3]]]]
-            (let [expected  (expected-resource-events
-                              (kitchensink/select-values basic-events-map matches)
-                              basic)
-                  actual    (resource-events-query-result version query)]
-              (is (= actual expected)
-                (format "Results didn't match for query '%s'" query)))))))
-
-  (deftest latest-report-resource-event-queries
-    (let [basic1        (store-example-report! (:basic reports) (now))
-          report-hash1  (:hash basic1)
-          events1       (get-in reports [:basic :resource-events])
-          events1-map   (get-events-map (:basic reports))
-
-          basic2        (store-example-report! (:basic2 reports) (now))
-          report2-hash  (:hash basic2)
-          events2       (get-in reports [:basic2 :resource-events])
-          events2-map   (get-events-map (:basic2 reports))]
-
+      (testing "compound queries with both equality and inequality"
+        (doseq [[query matches]
+                [[["and"
+                   ["=" "status" "success"]
+                   ["<" "timestamp" "2011-01-01T12:00:02-03:00"]]  [1]]
+                 [["or"
+                   ["=" "status" "skipped"]
+                   ["<" "timestamp" "2011-01-01T12:00:02-03:00"]]  [1 3]]]]
+          (let [expected  (expected-resource-events
+                           (kitchensink/select-values basic-events-map matches)
+                           basic)
+                actual    (resource-events-query-result version query)]
+            (is (= actual expected)
+                (format "Results didn't match for query '%s'" query))))))))
+
+(deftest latest-report-resource-event-queries
+  (let [basic1        (store-example-report! (:basic reports) (now))
+        report-hash1  (:hash basic1)
+        events1       (get-in reports [:basic :resource-events])
+        events1-map   (get-events-map (:basic reports))
+
+        basic2        (store-example-report! (:basic2 reports) (now))
+        report2-hash  (:hash basic2)
+        events2       (get-in reports [:basic2 :resource-events])
+        events2-map   (get-events-map (:basic2 reports))]
+    (doseq [version [:v3 :v4]]
       (testing "retrieval of events for latest report only"
         (testing "applied to entire query"
           (let [expected  (expected-resource-events events2 basic2)
@@ -341,17 +340,17 @@
               results2  (expected-resource-events (kitchensink/select-values events2-map [5 6]) basic2)
               expected  (clojure.set/union results1 results2)
               actual    (resource-events-query-result version ["or"
-                                                        ["and" ["=" "status" "skipped"] ["=" "latest-report?" false]]
-                                                        ["and" ["=" "message" "created"] ["=" "latest-report?" true]]])]
-          (is (= actual expected))))))
-
-  (deftest distinct-resource-event-queries
-    (let [basic1        (store-example-report! (:basic reports) (now))
-          basic3        (store-example-report! (:basic3 reports) (now))
-          report-hash3  (:hash basic3)
-          events1       (get-in reports [:basic :resource-events])
-          events3       (get-in reports [:basic3 :resource-events])]
-
+                                                               ["and" ["=" "status" "skipped"] ["=" "latest-report?" false]]
+                                                               ["and" ["=" "message" "created"] ["=" "latest-report?" true]]])]
+          (is (= actual expected)))))))
+
+(deftest distinct-resource-event-queries
+  (let [basic1        (store-example-report! (:basic reports) (now))
+        basic3        (store-example-report! (:basic3 reports) (now))
+        report-hash3  (:hash basic3)
+        events1       (get-in reports [:basic :resource-events])
+        events3       (get-in reports [:basic3 :resource-events])]
+    (doseq [version [:v3 :v4]]
       (testing "retrieval of events for distinct resources only"
         (let [expected  (expected-resource-events events3 basic3)
               actual    (resource-events-query-result version ["=" "certname" "foo.local"]
@@ -375,22 +374,22 @@
       (testing "filters (such as status) should be applied *after* the distinct list of most recent events has been built up"
         (let [expected  #{}
               actual    (resource-events-query-result
-                          version
-                          ["and" ["=" "certname" "foo.local"]
-                                 ["=" "status" "success"]
-                                 ["=" "resource-title" "notify, yar"]]
-                          {} {:distinct-resources? true
-                              :distinct-start-time (to-timestamp 0)
-                              :distinct-end-time   (to-timestamp (now))})]
+                         version
+                         ["and" ["=" "certname" "foo.local"]
+                          ["=" "status" "success"]
+                          ["=" "resource-title" "notify, yar"]]
+                         {} {:distinct-resources? true
+                             :distinct-start-time (to-timestamp 0)
+                             :distinct-end-time   (to-timestamp (now))})]
           (is (= (count expected) (count actual)))
-          (is (= actual expected))))))
-
-  (deftest paging-results
-    (let [basic4        (store-example-report! (:basic4 reports) (now))
-          events        (get-in reports [:basic4 :resource-events])
-          event-count   (count events)
-          select-values #(reverse (kitchensink/select-values (get-events-map (:basic4 reports)) %))]
-
+          (is (= actual expected)))))))
+
+(deftest paging-results
+  (let [basic4        (store-example-report! (:basic4 reports) (now))
+        events        (get-in reports [:basic4 :resource-events])
+        event-count   (count events)
+        select-values #(reverse (kitchensink/select-values (get-events-map (:basic4 reports)) %))]
+    (doseq [version [:v3 :v4]]
       (testing "include total results count"
         (let [actual (:count (raw-resource-events-query-result version [">" "timestamp" 0] {:count? true}))]
           (is (= actual event-count))))
@@ -404,11 +403,11 @@
       (testing "order-by"
         (testing "rejects invalid fields"
           (is (thrown-with-msg?
-                IllegalArgumentException #"Unrecognized column 'invalid-field' specified in :order-by"
-                (resource-events-query-result
-                  version
-                  [">" "timestamp" 0]
-                  {:order-by [[:invalid-field :ascending]]}))))
+               IllegalArgumentException #"Unrecognized column 'invalid-field' specified in :order-by"
+               (resource-events-query-result
+                version
+                [">" "timestamp" 0]
+                {:order-by [[:invalid-field :ascending]]}))))

         (testing "numerical fields"
           (doseq [[order expected-events] [[:ascending  [10 11 12]]
@@ -416,9 +415,9 @@
             (testing order
               (let [expected (raw-expected-resource-events (select-values expected-events) basic4)
                     actual   (:result (raw-resource-events-query-result
-                                        version
-                                        [">" "timestamp" 0]
-                                        {:order-by [[:line order]]}))]
+                                       version
+                                       [">" "timestamp" 0]
+                                       {:order-by [[:line order]]}))]
                 (is (= actual expected))))))

         (testing "alphabetical fields"
@@ -427,9 +426,9 @@
             (testing order
               (let [expected (raw-expected-resource-events (select-values expected-events) basic4)
                     actual   (:result (raw-resource-events-query-result
-                                        version
-                                        [">" "timestamp" 0]
-                                        {:order-by [[:file order]]}))]
+                                       version
+                                       [">" "timestamp" 0]
+                                       {:order-by [[:file order]]}))]
                 (is (= actual expected))))))

         (testing "timestamp fields"
@@ -438,9 +437,9 @@
             (testing order
               (let [expected (raw-expected-resource-events (select-values expected-events) basic4)
                     actual   (:result (raw-resource-events-query-result
-                                        version
-                                        [">" "timestamp" 0]
-                                        {:order-by [[:timestamp order]]}))]
+                                       version
+                                       [">" "timestamp" 0]
+                                       {:order-by [[:timestamp order]]}))]
                 (is (= actual expected))))))

         (testing "multiple fields"
@@ -449,26 +448,26 @@
             (testing (format "status %s resource-title %s" status-order title-order)
               (let [expected (raw-expected-resource-events (select-values expected-events) basic4)
                     actual   (:result (raw-resource-events-query-result
-                                        version
-                                        [">" "timestamp" 0]
-                                        {:order-by [[:status status-order]
-                                                    [:resource-title title-order]]}))]
+                                       version
+                                       [">" "timestamp" 0]
+                                       {:order-by [[:status status-order]
+                                                   [:resource-title title-order]]}))]
                 (is (= actual expected)))))))

       (testing "offset"
         (doseq [[order expected-sequences] [[:ascending  [[0 [10 11 12]]
-                                                         [1 [11 12]]
-                                                         [2 [12]]
-                                                         [3 []]]]
+                                                          [1 [11 12]]
+                                                          [2 [12]]
+                                                          [3 []]]]
                                             [:descending [[0 [12 11 10]]
-                                                         [1 [11 10]]
-                                                         [2 [10]]
-                                                         [3 []]]]]]
+                                                          [1 [11 10]]
+                                                          [2 [10]]
+                                                          [3 []]]]]]
           (testing order
             (doseq [[offset expected-events] expected-sequences]
               (let [expected (raw-expected-resource-events (select-values expected-events) basic4)
                     actual   (:result (raw-resource-events-query-result
-                                        version
-                                        [">" "timestamp" 0]
-                                        {:order-by [[:line order]] :offset offset}))]
+                                       version
+                                       [">" "timestamp" 0]
+                                       {:order-by [[:line order]] :offset offset}))]
                 (is (= actual expected))))))))))


added get more posts button to main-html. added post title to have href to actual post url

--- src/saved_for_reddit/core.cljs
+++ src/saved_for_reddit/core.cljs
@@ -44,10 +44,11 @@
   [:div {:class "panel panel-default" :href (if (nil? (:title p)) (:link_url p) (:url p))}
    [:div {:class "panel-heading"}
     [:h4 {:class "panel-title"}
-     (if (nil? (:title p)) (:link_title p) (:title p)) " "
+     [:a {:href (if (nil? (:title p)) (:link_url p) (:url p))}
+      (if (nil? (:title p)) (:link_title p) (:title p))] " "
      [:a {:href (str "https://www.reddit.com/r/" (:subreddit p))} [:span {:class "badge"} (:subreddit p)]]]]
    [:div {:class "panel-body"}
-    [:small  [:a {:href (str "https://www.reddit.com/user/" (:author p))} [:small (:author p)]]]]])
+    [:small  "submitted by " [:a {:href (str "https://www.reddit.com/user/" (:author p))} [:small (:author p)]]]]])

 (defn main-html []
   [:div {:class "col-md-12"}
@@ -55,6 +56,10 @@
    [:div {:class "list-group"}
     (for [p @saved-posts]
       [post-html p])]
+   [:div {:class "row"}
+    [:div {:class "col-md-12"}
+     [:input {:type "button" :value "moar!"
+              :on-click (fn [] (println "get more posts"))}]]]
    [:p "Reddit API Token: "
     [:input {:type "text" :id "token" :name "token"
              :value (:token @app-state) :readOnly "true"}]]
@@ -86,7 +91,7 @@
         (println response)
         (if (clojure.string/blank? error)
           (doseq [p posts]
-            (println (process-json-post p))
+            #_(println (process-json-post p))
             (swap! saved-posts #(conj % %2) (assoc (:data p) :key (-> p :data :id))))
           (handle-error (str error " " (:error-text response) "\nYour API token might've expired"))))))