Skip to content

Commit

Permalink
Show http-messages in output failing test-rio command (#350)
Browse files Browse the repository at this point in the history
* Show http-messages in output failing test-rio command

* Review feedback

* More review feedback
  • Loading branch information
mdemare authored Jan 9, 2025
1 parent 9528e17 commit b8c1342
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 115 deletions.
71 changes: 38 additions & 33 deletions src/nl/surf/eduhub_rio_mapper/cli_commands.clj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
[nl.surf.eduhub-rio-mapper.rio.loader :as rio.loader]
[nl.surf.eduhub-rio-mapper.specs.ooapi :as ooapi]
[nl.surf.eduhub-rio-mapper.specs.rio :as rio]
[nl.surf.eduhub-rio-mapper.utils.http-utils :refer [*http-messages*]]
[nl.surf.eduhub-rio-mapper.utils.printer :as printer]
[nl.surf.eduhub-rio-mapper.worker :as worker])
(:import [java.util UUID]))

Expand Down Expand Up @@ -76,44 +78,47 @@

"test-rio"
(let [[client-info _args] (parse-client-info-args args clients)
uuid (UUID/randomUUID)
new-uuid (UUID/randomUUID)
old-uuid (UUID/randomUUID)
new-uuid (UUID/randomUUID)

eduspec (-> "../test/fixtures/ooapi/education-specification-template.json"
io/resource
slurp
(json/read-str :key-fn keyword)
(assoc :educationSpecificationId uuid))]

(try
(let [insert-req {:institution-oin (:institution-oin client-info)
:institution-schac-home (:institution-schac-home client-info)
::ooapi/type "education-specification"
::ooapi/id uuid
::ooapi/entity eduspec}
rio-code (-> insert-req insert! :aanleveren_opleidingseenheid_response :opleidingseenheidcode)
link-req (merge insert-req {::ooapi/id new-uuid ::rio/opleidingscode rio-code})]
(link! link-req)
(let [rio-obj (rio.loader/find-rio-object rio-code getter (:institution-oin client-info) "opleidingseenheid")
nieuwe-sleutel (->> rio-obj
:content
(filter #(= :kenmerken (:tag %)))
(map :content)
(map #(reduce (fn [m el] (assoc m (:tag el) (-> el :content first))) {} %))
(filter #(= "eigenOpleidingseenheidSleutel" (:kenmerknaam %)))
first
:kenmerkwaardeTekst)]
(when (not= nieuwe-sleutel (str uuid))
(throw (ex-info "Failed to set eigenOpleidingseenheidSleutel" {:rio-queue-status :down})))))

(println "The RIO Queue is UP")
(catch Exception ex
(when-let [ex-data (ex-data ex)]
(when (= :down (:rio-queue-status ex-data))
(println "The RIO Queue is DOWN;" (.getMessage ex))
(System/exit 255)))
(println "An unexpected exception has occurred: " ex)
(System/exit 254))))
(assoc :educationSpecificationId old-uuid))]

(binding [*http-messages* (atom [])]
(try
(let [insert-req {:institution-oin (:institution-oin client-info)
:institution-schac-home (:institution-schac-home client-info)
::ooapi/type "education-specification"
::ooapi/id old-uuid
::ooapi/entity eduspec}
rio-code (-> insert-req insert! :aanleveren_opleidingseenheid_response :opleidingseenheidcode)
link-req (merge insert-req {::ooapi/id new-uuid ::rio/opleidingscode rio-code})]
(link! link-req)
(let [rio-obj (rio.loader/find-rio-object rio-code getter (:institution-oin client-info) "opleidingseenheid")
nieuwe-sleutel (->> rio-obj
:content
(filter #(= :kenmerken (:tag %)))
(map :content)
(map #(reduce (fn [m el] (assoc m (:tag el) (-> el :content first))) {} %))
(filter #(= "eigenOpleidingseenheidSleutel" (:kenmerknaam %)))
first
:kenmerkwaardeTekst)]
(when (not= nieuwe-sleutel (str new-uuid))
(println "old uuid " old-uuid)
(println "new uuid " new-uuid)
(throw (ex-info "Failed to set eigenOpleidingseenheidSleutel" {:rio-queue-status :down}))))
(println "The RIO Queue is UP"))
(catch Exception ex
(when-let [ex-data (ex-data ex)]
(when (= :down (:rio-queue-status ex-data))
(println "The RIO Queue is DOWN;" (.getMessage ex))
(printer/print-http-messages @*http-messages*)
(System/exit 255)))
(println "An unexpected exception has occurred: " ex)
(System/exit 254)))))

"get"
(let [[client-info rest-args] (parse-client-info-args args clients)]
Expand Down
121 changes: 121 additions & 0 deletions src/nl/surf/eduhub_rio_mapper/utils/printer.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
;; This file is part of eduhub-rio-mapper
;;
;; Copyright (C) 2022 SURFnet B.V.
;;
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU Affero General Public License
;; as published by the Free Software Foundation, either version 3 of
;; the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public
;; License along with this program. If not, see
;; <https://www.gnu.org/licenses/>.

(ns nl.surf.eduhub-rio-mapper.utils.printer
(:require [clojure.data.json :as json]
[clojure.string :as str]
[clojure.xml :as xml]
[nl.jomco.http-status-codes :as http-status]
[nl.surf.eduhub-rio-mapper.utils.xml-utils :as xml-utils])
(:import [java.io ByteArrayInputStream StringWriter]))

(defmacro print-boxed
"Print pretty box around output of evaluating `form`."
[title & form]
`(let [sw# (StringWriter.)
r# (binding [*out* sw#] ~@form)
s# (str sw#)]
(println)
(print "╭─────" ~title "\n")
(println (str/replace (str/trim s#) #"\n" "\n"))
(println "╰─────")
r#))

(defn- print-soap-body
"Print the body of a SOAP request or response."
[s]
;; Use clojure.xml/parse because it is more lenient than
;; clojure.data.xml/parse which trips over missing namespaces.
(let [xml (xml/parse (ByteArrayInputStream. (.getBytes s)))]
(xml-utils/debug-print-xml (-> xml :content second :content first)
:initial-indent " ")))

(defn print-json
"Print indented JSON."
[v]
(when v
(print " ")
(println (json/write-str v :indent true :indent-depth 1))))

(defn- print-json-str
"Parse string as JSON and print it."
[s]
(when s
(print-json (json/read-str s))))

(defn- print-rio-message
"Print boxed RIO request and response."
[{{:keys [method url]
req-body :body
{action :SOAPAction} :headers} :req
{res-body :body
:keys [status]} :res}]
(println (str/upper-case (name method)) url status)
(println "- action:" action)
(println "- request:\n")
(print-soap-body req-body)
(println)
(when (= http-status/ok status)
(println "- response:\n")
(print-soap-body res-body)
(println)))

(defn- print-ooapi-message
"Print boxed OOAPI request and response."
[{{:keys [method url]} :req
{:keys [status body]} :res}]
(println (str/upper-case method) url status)
(println)
(when (= http-status/ok status)
(print-json-str body)))

(defn- keywordize-keys
"Recursively change map keys to keywords."
[m]
(->> m
(map (fn [[k v]]
[(if (keyword? k)
k
(keyword k))
(if (map? v)
(keywordize-keys v)
v)]))
(into {})))

(defn print-http-messages-with-boxed-printer
"Print HTTP message as returned by API status."
[http-messages print-boxed-fn]
(when-let [msg (first http-messages)]
;; need to keywordize-keys because http-message may be translated
;; from from JSON (in which case they are all keywords) or come
;; strait from http-utils (which is a mixed bag)
(let [{:keys [req] :as msg} (keywordize-keys msg)
soap? (-> req :headers :SOAPAction)
title (if soap? "RIO" "OOAPI")
print-fn (if soap? print-rio-message
print-ooapi-message)]
(print-boxed-fn title print-fn msg))
(recur (next http-messages) print-boxed-fn)))

(defn print-single-http-message [title print-fn msg]
(print-boxed title (print-fn msg)))

(defn print-http-messages
"Print HTTP message as returned by API status."
[http-messages]
(print-http-messages-with-boxed-printer http-messages print-single-http-message))
95 changes: 13 additions & 82 deletions test/nl/surf/eduhub_rio_mapper/e2e_helper.clj
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@

(ns nl.surf.eduhub-rio-mapper.e2e-helper
(:require [clj-http.client :as http]
[clojure.data.json :as json]
[clojure.string :as str]
[clojure.test :as test]
[clojure.xml :as xml]
[environ.core :refer [env]]
[nl.jomco.http-status-codes :as http-status]
[nl.surf.eduhub-rio-mapper.clients-info :as clients-info]
Expand All @@ -31,8 +29,9 @@
[nl.surf.eduhub-rio-mapper.rio.loader :as rio-loader]
[nl.surf.eduhub-rio-mapper.specs.rio :as rio]
[nl.surf.eduhub-rio-mapper.utils.http-utils :as http-utils]
[nl.surf.eduhub-rio-mapper.utils.printer :as printer]
[nl.surf.eduhub-rio-mapper.utils.xml-utils :as xml-utils])
(:import [java.io ByteArrayInputStream StringWriter]
(:import [java.io StringWriter]
[java.net ConnectException]
[java.util Base64]
[javax.xml.xpath XPathFactory]
Expand Down Expand Up @@ -71,90 +70,21 @@
(reset! last-boxed-print s#)))
r#))

(defn- print-soap-body
"Print the body of a SOAP request or response."
[s]
;; Use clojure.xml/parse because it is more lenient than
;; clojure.data.xml/parse which trips over missing namespaces.
(let [xml (xml/parse (ByteArrayInputStream. (.getBytes s)))]
(xml-utils/debug-print-xml (-> xml :content second :content first)
:initial-indent " ")))

(defn- print-json
"Print indented JSON."
[v]
(when v
(print " ")
(println (json/write-str v :indent true :indent-depth 1))))

(defn- print-json-str
"Parse string as JSON and print it."
[s]
(when s
(print-json (json/read-str s))))

(defn- print-api-message
"Print boxed API request and response."
[{{:keys [method url]} :req
{:keys [status body]} :res}]
(print-boxed "API"
(println (str/upper-case (name method)) url status)
(when body
(print-json body))))

(defn- print-rio-message
"Print boxed RIO request and response."
[{{:keys [method url]
req-body :body
{action :SOAPAction} :headers} :req
{res-body :body
:keys [status]} :res}]
(print-boxed "RIO"
(println (str/upper-case (name method)) url status)
(println "- action:" action)
(println "- request:\n")
(print-soap-body req-body)
(println)
(when (= http-status/ok status)
(println "- response:\n")
(print-soap-body res-body)
(println))))

(defn- print-ooapi-message
"Print boxed OOAPI request and response."
[{{:keys [method url]} :req
{:keys [status body]} :res}]
(print-boxed "OOAPI"
(println (str/upper-case method) url status)
(println)
(when (= http-status/ok status)
(print-json-str body))))

(defn- keywordize-keys
"Recursively change map keys to keywords."
[m]
(->> m
(map (fn [[k v]]
[(if (keyword? k)
k
(keyword k))
(if (map? v)
(keywordize-keys v)
v)]))
(into {})))

(defn- print-http-messages
(println (str/upper-case (name method)) url status)
(when body
(printer/print-json body)))

(defn print-single-http-message [title print-fn msg]
(print-boxed title (print-fn msg)))

(defn print-http-messages
"Print HTTP message as returned by API status."
[http-messages]
(when-let [msg (first http-messages)]
;; need to keywordize-keys because http-message may be translated
;; from from JSON (in which case they are all keywords) or come
;; strait from http-utils (which is a mixed bag)
(let [{:keys [req] :as msg} (keywordize-keys msg)]
(if (-> req :headers :SOAPAction)
(print-rio-message msg)
(print-ooapi-message msg)))
(recur (next http-messages))))
(printer/print-http-messages-with-boxed-printer http-messages print-single-http-message))



Expand Down Expand Up @@ -270,7 +200,8 @@
;; else on error
(update res :body dissoc :http-messages)
res)]
(print-api-message {:req req, :res res})
(print-boxed "API"
(print-api-message {:req req, :res res}))
(when (seq http-messages)
(print-boxed "Job HTTP messages"
(print-http-messages http-messages)))
Expand Down

0 comments on commit b8c1342

Please sign in to comment.