Commit 890f31ee authored by Ryan Senior's avatar Ryan Senior

(PDB-16) Added status to "store report" and report query results

Previously there was no way to distinguish between failed puppet runs
and successful puppet runs as we didn't store report status. This commit
adds support for report status to the "store report" command, v4 query
API and model.
parent 93817dbd
......@@ -8,6 +8,7 @@ canonical: "/puppetdb/latest/api/query/v4/reports.html"
[operator]: ../v4/operators.html
[event]: ./events.html
[paging]: ./paging.html
[statues]: ./puppet/3/reference/format_report.html#puppettransactionreport
Querying reports is accomplished by making an HTTP request to the `/reports` REST
endpoint.
......@@ -45,6 +46,9 @@ The only available [OPERATOR][] is `=`.
`environment`
: the environment associated to report's node
`status`
: the status associated to report's node, possible values for this field come from Puppet's report status which can be found [here][statuses]
#### Response format
The response is a JSON array of report summaries for all reports
......@@ -61,7 +65,9 @@ the completion time of the report, in descending order:
"hash": "bd899b1ee825ec1d2c671fe5541b5c8f4a783472",
"certname": "foo.local",
"report-format": 4,
"transaction-uuid": "030c1717-f175-4644-b048-ac9ea328f221"
"transaction-uuid": "030c1717-f175-4644-b048-ac9ea328f221",
"environment": "DEV",
"status": "unchanged"
},
{
"end-time": "2012-10-26T22:39:32.000Z",
......@@ -73,6 +79,8 @@ the completion time of the report, in descending order:
"certname": "foo.local",
"report-format": 4,
"transaction-uuid": null
"environment": "DEV",
"status": "unchanged"
}
]
......
......@@ -412,6 +412,10 @@
[{:keys [version] :as command} {:keys [db]}]
(store-report* 3 db command))
(defmethod process-command! [(command-names :store-report) 4]
[{:keys [version] :as command} {:keys [db]}]
(store-report* 4 db command))
;; ## MQ I/O
;;
;; The data flow through the code is as follows:
......
......@@ -49,6 +49,13 @@
[version rows]
(map #(remove-environment % version) rows))
(defn remove-status
"Status is only for the v4 version of the reports response"
[result-map version]
(if-not (= :v4 version)
(dissoc result-map :status)
result-map))
(defn v4?
"Returns a function that always returns true if `version` is :v4"
[version]
......
......@@ -3,7 +3,7 @@
(ns com.puppetlabs.puppetdb.query.reports
(:require [puppetlabs.kitchensink.core :as kitchensink]
[clojure.string :as string]
[com.puppetlabs.puppetdb.http :refer [remove-environment v4?]]
[com.puppetlabs.puppetdb.http :refer [remove-environment remove-status v4?]]
[clojure.core.match :refer [match]])
(:use [com.puppetlabs.jdbc :only [query-to-vec underscores->dashes valid-jdbc-query?]]
[com.puppetlabs.puppetdb.query :only [execute-query compile-term compile-and]]
......@@ -39,6 +39,10 @@
{:where "environments.name = ?"
:params [value]}
["status" :guard (v4? version)]
{:where "report_statuses.status = ?"
:params [value]}
:else
(throw (IllegalArgumentException.
(format "'%s' is not a valid query term for version %s of the reports API" path (last (name version))))))))
......@@ -67,7 +71,8 @@
"end_time"
"receive_time"
"transaction_uuid"
"environments.name as environment"])
"environments.name as environment"
"report_statuses.status as status"])
(defn query-reports
"Take a query and its parameters, and return a vector of matching reports."
......@@ -75,7 +80,11 @@
([version paging-options [sql & params]]
{:pre [(string? sql)]}
(validate-order-by! (map keyword report-columns) paging-options)
(let [query (format "SELECT %s FROM reports LEFT OUTER JOIN environments on reports.environment_id = environments.id %s ORDER BY start_time DESC"
(let [query (format "SELECT %s
FROM reports
LEFT OUTER JOIN environments on reports.environment_id = environments.id
LEFT OUTER JOIN report_statuses on reports.status_id = report_statuses.id
%s ORDER BY start_time DESC"
(string/join ", " report-columns)
sql)
results (execute-query
......@@ -83,7 +92,8 @@
paging-options)]
(update-in results [:result]
(fn [rs] (map (comp #(kitchensink/mapkeys underscores->dashes %)
#(remove-environment % version)) rs))))))
#(remove-environment % version)
#(remove-status % version)) rs))))))
(defn reports-for-node
"Return reports for a particular node."
......
......@@ -23,6 +23,8 @@
:type :string}
:environment {:optional? true
:type :string}
:status {:optional? true
:type :string}
})
(def report-fields
......@@ -105,6 +107,15 @@
(throw (IllegalArgumentException. "Version 3 of reports must contain an environment")))
report)
(defmethod validate! 4
[_ report]
(validate! 2 report)
(when (nil? (:environment report))
(throw (IllegalArgumentException. "Version 4 of reports must contain an environment")))
(when (nil? (:status report))
(throw (IllegalArgumentException. "Version 4 of reports must contain a status")))
report)
(defn sanitize-events
"This function takes an array of events and santizes them, ensuring only
valid keys are returned."
......
......@@ -694,6 +694,20 @@
"CREATE INDEX idx_reports_env ON reports(environment_id)"
))
(defn add-report-status []
(sql/create-table :report_statuses
["id" "bigserial NOT NULL PRIMARY KEY"]
["status" "TEXT NOT NULL" "UNIQUE"])
(sql/do-commands
"ALTER TABLE reports ADD status_id integer"
"ALTER TABLE reports
ADD CONSTRAINT reports_status_fkey FOREIGN KEY (status_id)
REFERENCES report_statuses (id) ON UPDATE NO ACTION ON DELETE CASCADE"
"CREATE INDEX idx_reports_status ON reports(status_id)"))
;; The available migrations, as a map from migration version to migration function.
(def migrations
......@@ -718,7 +732,8 @@
19 differential-edges
20 differential-catalog-resources
21 reset-catalog-sequence-to-latest-id
22 add-environments})
22 add-environments
23 add-report-status})
(def desired-schema-version (apply max (keys migrations)))
......
......@@ -186,6 +186,7 @@
:gc-catalogs (timer [ns-str "default" "gc-catalogs-time"])
:gc-params (timer [ns-str "default" "gc-params-time"])
:gc-environments (timer [ns-str "default" "gc-environments-time"])
:gc-report-statuses (timer [ns-str "default" "gc-report-statuses"])
:updated-catalog (counter [ns-str "default" "new-catalogs"])
:duplicate-catalog (counter [ns-str "default" "duplicate-catalogs"])
......@@ -262,29 +263,61 @@
["name=?" certname]
{:deactivated nil}))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Environments querying/updating
(pls/defn-validated create-row :- s/Int
"Creates a row using `row-map` for `table`, returning the PK that was created upon insert"
[table :- s/Keyword
row-map :- {s/Keyword s/Any}]
(:id (first (sql/insert-records table row-map))))
(pls/defn-validated create-environment :- s/Int
"Inserts `env-name` into the environments table"
[env-name :- s/Str]
(:id (first (sql/insert-records :environments {:name env-name}))))
(pls/defn-validated query-id :- (s/maybe s/Int)
"Returns the id (primary key) from `table` that contain `row-map` values"
[table :- s/Keyword
row-map :- {s/Keyword s/Any}]
(let [cols (keys row-map)
where-clause (str "where " (str/join " " (map (fn [col] (str (name col) "=?") ) cols)))]
(sql/with-query-results rs (apply vector (format "select id from %s %s" (name table) where-clause) (map row-map cols))
(:id (first rs)))))
(pls/defn-validated ensure-row :- (s/maybe s/Int)
"Check if the given row (defined by `row-map` exists in `table`, creates it if it does not. Always returns
the id of the row (whether created or existing)"
[table :- s/Keyword
row-map :- {s/Keyword s/Any}]
(when row-map
(if-let [id (query-id table row-map)]
id
(create-row table row-map))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Environments querying/updating
(pls/defn-validated environment-id :- (s/maybe s/Int)
"Returns the id (primary key) from the environments table for the given `env-name`"
[env-name :- s/Str]
(sql/with-query-results rs ["select id from environments where name=?" env-name]
(:id (first rs))))
(query-id :environments {:name env-name}))
(pls/defn-validated ensure-environment :- (s/maybe s/Int)
"Check if the given `env-name` exists, creates it if it does not. Always returns
the id of the `env-name` (whether created or existing)"
[env-name :- (s/maybe s/Str)]
(when env-name
(if-let [id (environment-id env-name)]
id
(create-environment env-name))))
(ensure-row :environments {:name env-name})))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Status querying/updating
(pls/defn-validated status-id :- (s/maybe s/Int)
"Returns the id (primary key) from the result_statuses table for the given `status`"
[status :- s/Str]
(query-id :report_statuses {:status status}))
(pls/defn-validated ensure-status :- (s/maybe s/Int)
"Check if the given `status` exists, creates it if it does not. Always returns
the id of the `status` (whether created or existing)"
[status :- (s/maybe s/Str)]
(when status
(ensure-row :report_statuses {:status status})))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Catalog updates/changes
......@@ -707,6 +740,13 @@
UNION ALL
SELECT environment_id FROM certname_facts_metadata)"])))
(defn delete-unassociated-statuses!
"Remove any statuses that aren't associated with a report"
[]
(time! (:gc-report-statuses metrics)
(sql/delete-rows :report_statuses
["ID NOT IN (SELECT status_id FROM reports)"])))
(defn garbage-collect!
"Delete any lingering, unassociated data in the database"
[]
......@@ -714,7 +754,9 @@
(sql/transaction
(delete-unassociated-params!))
(sql/transaction
(delete-unassociated-environments!))))
(delete-unassociated-environments!))
(sql/transaction
(delete-unassociated-statuses!))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Facts
......@@ -850,7 +892,8 @@
the transaction. This should always be set to `true`, except during some very specific testing
scenarios."
[{:keys [puppet-version certname report-format configuration-version
start-time end-time resource-events transaction-uuid environment]
start-time end-time resource-events transaction-uuid environment
status]
:as report}
timestamp update-latest-report?]
{:pre [(map? report)
......@@ -879,7 +922,9 @@
:end_time (to-timestamp end-time)
:receive_time (to-timestamp timestamp)
:transaction_uuid transaction-uuid
:environment_id (ensure-environment environment)}))
:environment_id (ensure-environment environment)
:status_id (ensure-status status)}))
(apply sql/insert-records :resource_events resource-event-rows)
(if update-latest-report?
(update-latest-report! certname))))))
......
......@@ -36,5 +36,6 @@
"puppet-version": "3.0.0",
"report-format": 4,
"transaction-uuid": "68b08e2a-eeb1-4322-b241-bfdf151d294b",
"environment": "DEV"
"environment": "DEV",
"status" : "unchanged"
}
......@@ -11,6 +11,7 @@
:start-time "2011-01-01T12:00:00-03:00"
:end-time "2011-01-01T12:10:00-03:00"
:environment "DEV"
:status "unchanged"
:resource-events
;; NOTE: this is a bit wonky because resource events should *not* contain
;; a certname or containment-class on input, but they will have one on output
......@@ -73,6 +74,7 @@
:start-time "2013-08-28T19:00:00-03:00"
:end-time "2013-08-28T19:10:00-03:00"
:environment "DEV"
:status "unchanged"
:resource-events
;; NOTE: this is a bit wonky because resource events should *not* contain
;; a certname on input, but they will have one on output. To make it
......@@ -132,6 +134,7 @@
:start-time "2011-01-03T12:00:00-03:00"
:end-time "2011-01-03T12:10:00-03:00"
:environment "DEV"
:status "unchanged"
:resource-events
;; NOTE: this is a bit wonky because resource events should *not* contain
;; a certname or containment-class on input, but they will have one on output
......@@ -191,6 +194,7 @@
:start-time "2011-01-03T12:00:00-03:00"
:end-time "2011-01-03T12:10:00-03:00"
:environment "DEV"
:status "unchanged"
:resource-events
;; NOTE: this is a bit wonky because resource events should *not* contain
;; a certname or containment-class on input, but they will have one on output
......@@ -241,8 +245,3 @@
:containment-path ["Foo" "" "Bar[Baz]"]
:containing-class "Foo"}]}
})
(defn dissoc-env
"Removes the environment key (keyword or string) from a catalog"
[catalog]
(dissoc catalog :environment "environment"))
......@@ -226,7 +226,7 @@
(export/catalog-for-node "localhost" *port* :v3)
json/parse-string))))
(is (= (tur/munge-report-for-comparison (-> report
(dissoc :environment)
(dissoc :environment :status)
tur/munge-example-report-for-storage))
(tur/munge-report-for-comparison (-> (first (export/reports-for-node "localhost" *port* :v3 (:certname report)))
(update-in [:resource-events] vec)))))
......
......@@ -8,7 +8,8 @@
[com.puppetlabs.puppetdb.scf.hash :as shash]
[puppetlabs.trapperkeeper.testutils.logging :refer [atom-logger]]
[clj-time.format :as tfmt]
[clojure.walk :as walk])
[clojure.walk :as walk]
[com.puppetlabs.puppetdb.http :refer [remove-environment]])
(:use [com.puppetlabs.puppetdb.command]
[com.puppetlabs.puppetdb.testutils]
[com.puppetlabs.puppetdb.fixtures]
......@@ -1072,7 +1073,7 @@
default-report-munging if a munge function has not been specified"
(munge-command default-report-munging))
(let [report (munge-example-report-for-storage (report-examples/dissoc-env (:basic report-examples/reports)))
(let [report (munge-example-report-for-storage (remove-environment (:basic report-examples/reports) :v2))
v2-command {:command (command-names :store-report)
:version 2
:payload report}]
......
......@@ -3,7 +3,8 @@
[com.puppetlabs.puppetdb.scf.storage :as scf-store]
[com.puppetlabs.puppetdb.reports :as report]
[puppetlabs.kitchensink.core :as kitchensink]
[com.puppetlabs.puppetdb.examples.reports :refer [reports dissoc-env]])
[com.puppetlabs.puppetdb.examples.reports :refer [reports]]
[com.puppetlabs.puppetdb.http :refer [remove-status remove-environment]])
(:use clojure.test
ring.mock.request
com.puppetlabs.puppetdb.fixtures
......@@ -33,7 +34,7 @@
(defn reports-response
[reports]
(set (map (comp dissoc-env report-response) reports)))
(set (map (comp #(remove-status % :v3) #(remove-environment % :v3) report-response) reports)))
(defn remove-receive-times
[reports]
......@@ -79,10 +80,10 @@
:include-total count?})]
(is (= 2 (count results)))
(is (= (sort-by :hash
(vec (reports-response
[(assoc basic1 :hash basic1-hash)
(assoc basic2 :hash basic2-hash)])))
(sort-by :hash (vec (remove-receive-times results))))))))))
(vec (reports-response
[(assoc basic1 :hash basic1-hash)
(assoc basic2 :hash basic2-hash)])))
(sort-by :hash (vec (remove-receive-times results))))))))))
(deftest invalid-queries
(let [response (get-response ["<" "timestamp" 0])]
......
......@@ -52,6 +52,7 @@
(testing "should return all reports for a certname"
(let [result (get-response endpoint ["=" "certname" (:certname basic)])]
(is (every? #(= "DEV" (:environment %)) (json/parse-string (:body result) true)))
(is (every? #(= "unchanged" (:status %)) (json/parse-string (:body result) true)))
(response-equal?
result
(reports-response [(assoc basic :hash report-hash)])
......@@ -63,6 +64,45 @@
(reports-response [(assoc basic :hash report-hash)])
remove-receive-times))))
(deftest query-by-status
(let [basic (:basic reports)
hash1 (:hash (store-example-report! basic (now)))
basic2 (:basic2 reports)
hash2 (:hash (store-example-report! basic2 (now)))
basic3 (assoc (:basic3 reports) :status "changed")
hash3 (:hash (store-example-report! basic3 (now)))
basic4 (assoc (:basic4 reports) :status "failed")
hash4 (:hash (store-example-report! basic4 (now)))]
(testing "should return all reports for a certname"
(let [unchanged-result (get-response endpoint ["=" "status" "unchanged"])
unchanged-reports (json/parse-string (:body unchanged-result) true)
changed-result (get-response endpoint ["=" "status" "changed"])
changed-reports (json/parse-string (:body changed-result) true)
failed-result (get-response endpoint ["=" "status" "failed"])
failed-reports (json/parse-string (:body failed-result) true)]
(is (= 2 (count unchanged-reports)))
(is (every? #(= "unchanged" (:status %)) unchanged-reports))
(response-equal?
unchanged-result
(reports-response [(assoc basic :hash hash1)
(assoc basic2 :hash hash2)])
remove-receive-times)
(is (= 1 (count changed-reports)))
(response-equal?
changed-result
(reports-response [(assoc basic3 :hash hash3)])
remove-receive-times)
(is (= 1 (count failed-reports)))
(response-equal?
failed-result
(reports-response [(assoc basic4 :hash hash4)])
remove-receive-times)))))
(deftest query-by-certname-with-environment
(let [basic (:basic reports)
report-hash (:hash (store-example-report! basic (now)))]
......
......@@ -2,8 +2,7 @@
(:require [com.puppetlabs.puppetdb.scf.migrate :as migrate]
[com.puppetlabs.puppetdb.scf.storage-utils :refer [db-serialize]]
[cheshire.core :as json]
[clojure.java.jdbc :as sql]
[com.puppetlabs.puppetdb.examples.reports :refer [reports dissoc-env]])
[clojure.java.jdbc :as sql])
(:use [com.puppetlabs.puppetdb.scf.migrate]
[clj-time.coerce :only [to-timestamp]]
[clj-time.core :only [now ago days secs]]
......
......@@ -45,7 +45,7 @@
(sql/transaction
(certname-facts-metadata! "some_certname"))))
(is (empty? (cert-fact-map "some_certname")))
(add-facts! certname facts (-> 2 days ago) nil)
(testing "should have entries for each fact"
(is (= (query-to-vec "SELECT certname, name, value FROM certname_facts ORDER BY name")
......@@ -58,7 +58,7 @@
(is (sql/transaction
(certname-facts-metadata! "some_certname")))
(is (= facts (cert-fact-map "some_certname"))))
(testing "should add the certname if necessary"
(is (= (query-to-vec "SELECT name FROM certnames")
[{:name certname}])))
......@@ -112,7 +112,7 @@
:values {"foo" "bar"}
:environment "DEV"} (now))
(is (= {"foo" "bar"} (cert-fact-map "some_certname"))))
(testing "replace-facts with only additions"
(let [fact-map (cert-fact-map "some_certname")]
(replace-facts! {:name certname
......@@ -475,6 +475,22 @@
(is (= (query-to-vec ["SELECT * FROM environments"])
[]))))
(deftest delete-with-gc-report-statuses
(add-certname! certname)
(let [timestamp (now)
report (:basic reports)
certname (:certname report)]
(store-example-report! report timestamp)
(is (= [{:c 1}] (query-to-vec ["SELECT COUNT(*) as c FROM report_statuses"])))
(delete-reports-older-than! (ago (days 2)))
(is (= [{:c 1}] (query-to-vec ["SELECT COUNT(*) as c FROM report_statuses"])))
(garbage-collect!)
(is (= [{:c 0}] (query-to-vec ["SELECT COUNT(*) as c FROM report_statuses"])))))
(deftest catalog-bad-input
(testing "should noop"
(testing "on bad input"
......@@ -520,7 +536,7 @@
(is (= 1 (count results)))
(is (= (to-timestamp old-date) (to-timestamp timestamp)))))
(testing "changing a resource title"
(let [{orig-id :id
orig-tx-id :transaction_uuid
......@@ -532,7 +548,7 @@
(is (= #{{:type "Class" :title "foobar"}
{:type "File" :title "/etc/foobar"}
{:type "File" :title "/etc/foobar/baz"}}
(set (query-to-vec "SELECT cr.type, cr.title
(set (query-to-vec "SELECT cr.type, cr.title
FROM catalogs c INNER JOIN catalog_resources cr ON c.id = cr.catalog_id
WHERE c.certname=?" certname))))
......@@ -560,7 +576,7 @@
(is (= #{{:type "Class" :title "foobar"}
{:type "File" :title "/etc/foobar2"}
{:type "File" :title "/etc/foobar/baz"}}
(set (query-to-vec "SELECT cr.type, cr.title
(set (query-to-vec "SELECT cr.type, cr.title
FROM catalogs c INNER JOIN catalog_resources cr ON c.id = cr.catalog_id
WHERE c.certname=?" certname))))
......@@ -622,7 +638,7 @@
(add-catalog! (update-in catalog [:resources]
(fn [resources]
(kitchensink/mapvals #(assoc % :line 1000) resources))))
(is (= [{:line 1000}
{:line 1000}
{:line 1000}]
......@@ -631,7 +647,7 @@
(deftest change-exported-resource-metadata
(add-certname! certname)
(add-catalog! catalog)
(testing "changing exported"
(is (= #{{:exported false
:title "foobar"}
......@@ -747,7 +763,7 @@
(tu/with-wrapped-fn-args [inserts sql/insert-records
updates sql/update-values
deletes sql/delete-rows]
(add-catalog! catalog nil yesterday)
(is (empty? @inserts))
(is (= [:catalogs]
......@@ -758,7 +774,7 @@
(let [catalog-results (query-to-vec "SELECT timestamp from catalogs where certname=?" certname)
{:keys [timestamp]} (first catalog-results)
resources (set (query-to-vec "SELECT type, title from catalog_resources where catalog_id = ?" catalog-id))]
(is (= 1 (count catalog-results)))
(is (= 3 (count resources)))
(is (= (set (keys (:resources catalog)))
......@@ -808,28 +824,28 @@
add-param-catalog (assoc-in catalog [:resources {:type "File" :title "/etc/foobar"} :parameters :uid] "100")]
(is (= (get-in catalog [:resources {:type "File" :title "/etc/foobar"} :parameters])
(foobar-params)))
(is (= (get-in catalog [:resources {:type "File" :title "/etc/foobar"} :parameters])
(foobar-params-cache)))
(tu/with-wrapped-fn-args [inserts sql/insert-records
updates sql/update-values
deletes sql/delete-rows]
(add-catalog! add-param-catalog nil yesterday)
(is (sort= [:catalogs :catalog_resources]
(table-args @updates)))
(is (empty? (remove-edge-changes @deletes)))
(is (sort= [:resource_params_cache :resource_params]
(table-args @inserts))))
(is (not= orig-resource-hash (foobar-param-hash)))
(is (= (get-in add-param-catalog [:resources {:type "File" :title "/etc/foobar"} :parameters])
(foobar-params)))
(is (= (get-in add-param-catalog [:resources {:type "File" :title "/etc/foobar"} :parameters])
(foobar-params-cache)))
(tu/with-wrapped-fn-args [inserts sql/insert-records
......@@ -846,7 +862,7 @@
(is (= (get-in catalog [:resources {:type "File" :title "/etc/foobar"} :parameters])
(foobar-params)))
(is (= (get-in catalog [:resources {:type "File" :title "/etc/foobar"} :parameters])
(foobar-params-cache))))))
......@@ -979,19 +995,26 @@
:puppet-version "3.2.1 (Puppet Enterprise 3.0.0-preview0-168-g32c839e)") timestamp)))
(deftest report-storage-with-environment
(testing "should store reports"
(is (nil? (environment-id "DEV")))
(is (nil? (environment-id "DEV")))
(store-example-report! (assoc report :environment "DEV") timestamp)
(store-example-report! (assoc report :environment "DEV") timestamp)
(is (number? (environment-id "DEV")))
(is (number? (environment-id "DEV")))
(is (= (query-to-vec ["SELECT certname, environment_id FROM reports"])
[{:certname (:certname report)
:environment_id (environment-id "DEV")}]))
(is (= (query-to-vec ["SELECT certname, environment_id FROM reports"])
[{:certname (:certname report)
:environment_id (environment-id "DEV")}])))
(is (= (query-to-vec ["SELECT hash FROM reports"])
[{:hash report-hash}]))))
(deftest report-storage-with-status
(is (nil? (status-id "unchanged")))
(store-example-report! (assoc report :status "unchanged") timestamp)
(is (number? (status-id "unchanged")))
(is (= (query-to-vec ["SELECT certname, status_id FROM reports"])
[{:certname (:certname report)
:status_id (status-id "unchanged")}])))
(deftest report-storage-with-existing-environment
(testing "should store reports"
......@@ -1196,17 +1219,17 @@
(deftest test-merge-resource-hash
(let [ref->resource {{:type "File" :title "/tmp/foo"}
{:line 10}
{:type "File" :title "/tmp/bar"}
{:line 20}}
ref->hash {{:type "File" :title "/tmp/foo"}
"foo hash"
{:type "File" :title "/tmp/bar"}
"bar hash"}]
(is (= {{:type "File" :title "/tmp/foo"}
{:line 10 :resource "foo hash"}
{:type "File" :title "/tmp/bar"}
{:line 20 :resource "bar hash"}}
......
......@@ -82,7 +82,7 @@
([example-report timestamp]
(store-example-report! example-report timestamp true))
([example-report timestamp update-latest-report?]
(store-example-report*! #(report/validate! 3 (munge-example-report-for-storage example-report)) example-report timestamp update-latest-report?)))
(store-example-report*! #(report/validate! 4 (munge-example-report-for-storage example-report)) example-report timestamp update-latest-report?)))
(defn store-v2-example-report!
"See store-example-reports*! calls that, passing in a version 2 validation function"
......