From b63132c860018ed7eda7cd014c997b6eb07bac13 Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Wed, 6 Dec 2023 17:09:44 +0100 Subject: [PATCH 01/14] Fix rio.loader/getter expecting an ooapi/id instead of rio/opleidingscode --- src/nl/surf/eduhub_rio_mapper/cli.clj | 4 +- src/nl/surf/eduhub_rio_mapper/job.clj | 11 ++++- src/nl/surf/eduhub_rio_mapper/processing.clj | 3 +- src/nl/surf/eduhub_rio_mapper/rio/loader.clj | 47 ++++++++++---------- 4 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/nl/surf/eduhub_rio_mapper/cli.clj b/src/nl/surf/eduhub_rio_mapper/cli.clj index aab73ac5..4f572d47 100644 --- a/src/nl/surf/eduhub_rio_mapper/cli.clj +++ b/src/nl/surf/eduhub_rio_mapper/cli.clj @@ -198,7 +198,9 @@ response-type (and response-type (keyword response-type))] (assert (rio.loader/valid-get-types type)) (-> (when pagina {:pagina pagina}) - (assoc (if (= type "opleidingsrelatiesBijOpleidingseenheid") ::rio/opleidingscode ::ooapi/id) id + (assoc (if (rio.loader/aangeboden-opleiding-types type) + ::ooapi/id + ::rio/opleidingscode) id :response-type response-type ::rio/type type)))) diff --git a/src/nl/surf/eduhub_rio_mapper/job.clj b/src/nl/surf/eduhub_rio_mapper/job.clj index db50eeae..c0ec6952 100644 --- a/src/nl/surf/eduhub_rio_mapper/job.clj +++ b/src/nl/surf/eduhub_rio_mapper/job.clj @@ -39,8 +39,15 @@ :institution-schac-home institution-schac-home :institution-oin institution-oin :institution-name institution-name) - job (select-keys request [:action :args :institution-oin :institution-name :institution-schac-home - ::rio/aangeboden-opleiding-code ::rio/opleidingscode ::ooapi/type ::ooapi/id])] + job (select-keys request [:action + :args + :institution-oin + :institution-name + :institution-schac-home + ::rio/aangeboden-opleiding-code + ::rio/opleidingscode + ::ooapi/type + ::ooapi/id])] (logging/with-mdc log-context (log/infof "Started job %s, action %s, type %s, id %s" token action type id) (binding [*http-messages* (if http-logging-enabled (atom []) nil)] diff --git a/src/nl/surf/eduhub_rio_mapper/processing.clj b/src/nl/surf/eduhub_rio_mapper/processing.clj index 83144aeb..bc46980c 100644 --- a/src/nl/surf/eduhub_rio_mapper/processing.clj +++ b/src/nl/surf/eduhub_rio_mapper/processing.clj @@ -108,8 +108,7 @@ (defn- make-updater-mutate-rio-phase [{:keys [rio-config]}] (fn mutate-rio-phase [{:keys [job result eduspec]}] {:pre [(s/valid? ::Mutation/mutation-response result)]} - (logging/with-mdc - {:soap-action (:action result) :ooapi-id (::ooapi/id job)} + (logging/with-mdc {:soap-action (:action result) :ooapi-id (::ooapi/id job)} {:job job :eduspec eduspec :mutate-result (mutator/mutate! result rio-config)}))) (defn- make-updater-confirm-rio-phase [{:keys [resolver]} rio-config] diff --git a/src/nl/surf/eduhub_rio_mapper/rio/loader.clj b/src/nl/surf/eduhub_rio_mapper/rio/loader.clj index 8c33bbdc..943290c9 100644 --- a/src/nl/surf/eduhub_rio_mapper/rio/loader.clj +++ b/src/nl/surf/eduhub_rio_mapper/rio/loader.clj @@ -45,12 +45,14 @@ (def aangeboden-opleiding-namen #{:aangebodenHOOpleidingsonderdeel :aangebodenHOOpleiding :aangebodenParticuliereOpleiding}) +;; NOTE: aangeboden opleidingen are reference by OOAPI UID +(def aangeboden-opleiding-types #{aangeboden-opleiding + aangeboden-opleidingen-van-organisatie}) -(def valid-get-types #{aangeboden-opleiding - aangeboden-opleidingen-van-organisatie - opleidingseenheid - opleidingseenheden-van-organisatie - opleidingsrelaties-bij-opleidingseenheid}) +(def valid-get-types (into aangeboden-opleiding-types + #{opleidingseenheid + opleidingseenheden-van-organisatie + opleidingsrelaties-bij-opleidingseenheid})) (def schema "http://duo.nl/schema/DUO_RIO_Raadplegen_OnderwijsOrganisatie_V4") (def contract "http://duo.nl/contract/DUO_RIO_Raadplegen_OnderwijsOrganisatie_V4") @@ -184,8 +186,9 @@ (defn- response-handler-for-type [response-type type] (case response-type - :xml rio-xml-getter-response - :json rio-json-getter-response + :literal identity + :xml rio-xml-getter-response + :json rio-json-getter-response ;; If unspecified, use edn for relations and json for everything else (if (= type opleidingsrelaties-bij-opleidingseenheid) rio-relation-getter-response @@ -193,8 +196,10 @@ (defn find-opleidingseenheid [rio-code getter institution-oin] {:pre [rio-code]} - (-> (getter {::rio/type opleidingseenheid ::ooapi/id rio-code - :institution-oin institution-oin :response-type :xml}) + (-> (getter {::rio/type opleidingseenheid + ::rio/opleidingscode rio-code + :institution-oin institution-oin + :response-type :xml}) clj-xml/parse-str xml-seq (xml-utils/find-in-xmlseq #(when (opleidingseenheid-namen (:tag %)) %)))) @@ -244,28 +249,25 @@ ::rio/keys [type opleidingscode] :keys [institution-oin pagina response-type] :or {pagina 0}}] - {:pre [(or (not= type opleidingseenheid) - id)]} + {:pre [(or (and (aangeboden-opleiding-types type) id) + opleidingscode)]} (when-not (valid-get-types type) (throw (ex-info (str "Unexpected type: " type) - {:id id, - :opleidingscode opleidingscode, + {:id id + :opleidingscode opleidingscode :retryable? false}))) (when (and (= type opleidingseenheden-van-organisatie) - (not (valid-onderwijsbestuurcode? id))) - ;; WHOAA!! This is not a real OOAPI ID but a hack to allow - ;; command line to get opleidingseenheden. - (throw (ex-info (str "Type 'onderwijsbestuurcode' has ID invalid format: " id) - {:type type, - :opleidingscode opleidingscode + (not (valid-onderwijsbestuurcode? opleidingscode))) + (throw (ex-info (str "Type 'onderwijsbestuurcode' has ID invalid format: " opleidingscode) + {:type type :retryable? false}))) (let [soap-action (str "opvragen_" type) rio-sexp (condp = type ;; Command line only. opleidingseenheden-van-organisatie - [[:duo:onderwijsbestuurcode id] + [[:duo:onderwijsbestuurcode opleidingscode] ;; FIXME: this is not an opleidingscode! [:duo:pagina pagina]] ;; Command line only. @@ -280,9 +282,8 @@ [[:duo:aangebodenOpleidingCode id]] opleidingseenheid - [[:duo:opleidingseenheidcode id]])] - (logging/with-mdc - {:soap-action soap-action} + [[:duo:opleidingseenheidcode opleidingscode]])] + (logging/with-mdc {:soap-action soap-action} (let [xml (soap/prepare-soap-call soap-action rio-sexp (make-datamap institution-oin recipient-oin) From 0fc299e29b7728549367d8a56042693ef316b8a2 Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Wed, 6 Dec 2023 17:11:02 +0100 Subject: [PATCH 02/14] e2e: assert hoOpleiding data in RIO correctly upserted --- test/nl/surf/eduhub_rio_mapper/e2e_helper.clj | 65 ++++++++++++++----- test/nl/surf/eduhub_rio_mapper/e2e_test.clj | 15 ++--- 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj b/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj index da7c91b7..9ff4b3cd 100644 --- a/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj +++ b/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj @@ -15,25 +15,30 @@ [nl.surf.eduhub-rio-mapper.rio.loader :as rio-loader] [nl.surf.eduhub-rio-mapper.xml-utils :as xml-utils]) (:import (java.util Base64) - (java.io ByteArrayInputStream))) + (java.io ByteArrayInputStream StringWriter) + (javax.xml.xpath XPathFactory))) (def ^:private last-seen-testing-contexts (atom nil)) (defn- print-testing-contexts "Print eye catching testing context (when it's not already printed)." [] - (when-not (= @last-seen-testing-contexts test/*testing-contexts*) - (reset! last-seen-testing-contexts test/*testing-contexts*) - (println) - (println "╔═══════════════════") - (println (str/replace (first test/*testing-contexts*) #"(?m)^\s*" "║ ")))) + (when (seq test/*testing-contexts*) + (when-not (= @last-seen-testing-contexts test/*testing-contexts*) + (reset! last-seen-testing-contexts test/*testing-contexts*) + (println) + (println "╔═══════════════════") + (println (str/replace (first test/*testing-contexts*) #"(?m)^\s*" "║ "))))) (def ^:private last-boxed-print (atom nil)) (defmacro print-boxed "Print pretty box around output of evaluating `form`." [title & form] - `(let [s# (with-out-str (do ~@form))] + `(let [r# (transient []) + sw# (StringWriter.) + r# (binding [*out* sw#] ~@form) + s# (str sw#)] (if (= @last-boxed-print s#) (do (print ".") @@ -44,7 +49,8 @@ (print "╭─────" ~title "\n│ ") (println (str/replace (str/trim s#) #"\n" "\n│ ")) (println "╰─────") - (reset! last-boxed-print s#))))) + (reset! last-boxed-print s#))) + r#)) (defn- print-soap-body "Print the body of a SOAP request or response." @@ -396,19 +402,22 @@ (def ^:private client-info (delay (clients-info/client-info (:clients @config) (:client-id env)))) -(defn rio-relations - "Call RIO `opleidingsrelaties-bij-opleidingseenheid`." - [code] - {:pre [(spec/valid? ::rio/opleidingscode code)]} +(defn- rio-get [req] (let [messages-atom (atom []) - result - (binding [http-utils/*http-messages* messages-atom] - (@rio-getter {::rio/type rio-loader/opleidingsrelaties-bij-opleidingseenheid - ::rio/opleidingscode code - :institution-oin (:institution-oin @client-info)}))] + result (binding [http-utils/*http-messages* messages-atom] + (@rio-getter req))] (print-http-messages @messages-atom) result)) +(defn rio-relations + "Call RIO `opvragen_opleidingsrelatiesBijOpleidingseenheid`." + [code] + {:pre [(spec/valid? ::rio/opleidingscode code)]} + (print-boxed "rio-relations" + (rio-get {::rio/type rio-loader/opleidingsrelaties-bij-opleidingseenheid + ::rio/opleidingscode code + :institution-oin (:institution-oin @client-info)}))) + (defn rio-with-relation? "Fetch relations of `rio-child` and test if it includes `rio-parent`. @@ -429,6 +438,28 @@ (recur (dec tries))) result))))) +(defn rio-opleidingseenheid + "Call RIO `opvragen_opleidingseenheid`." + [code] + {:pre [(spec/valid? ::rio/opleidingscode code)]} + (print-boxed "rio-opleidingseenheid" + (-> {::rio/type rio-loader/opleidingseenheid + ::rio/opleidingscode code + :institution-oin (:institution-oin @client-info) + :response-type :literal} + (rio-get)))) + +(defn get-in-xml + "Get text node from `path` starting at `node`." + [node path] + (let [xpath (str "//" + (->> path + (map #(str "*[local-name()='" % "']")) + (str/join "/")))] + (.evaluate (.newXPath (XPathFactory/newInstance)) + xpath + node))) + ;; Using atoms to keep process to make interactive development easier. diff --git a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj index efecdd2a..c7358756 100644 --- a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj +++ b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj @@ -17,21 +17,15 @@ (is (job-done? job)) (is (job-dry-run-not-found? job)))) - ;; TODO this fails because eduspec is added to rio but linking - ;; currently silently fails - (comment - (testing "scenario [4b]: Test /job/upsert with the program. You can - expect an error, because the edspec child is not - upserted." - (let [job (post-job :upsert :education-specifications "child")] - (is (job-error? job))))) - (testing "scenario [1b]: Test /job/upsert with the edspec parent. You can expect 'done' and a opleidingeenheid in RIO is inserted." (let [parent-job (post-job :upsert :education-specifications "parent")] (is (job-done? parent-job)) (is (job-result-opleidingseenheidcode parent-job)) + (let [xml (rio-opleidingseenheid (job-result-opleidingseenheidcode parent-job))] + (is (= "parent education specification" + (get-in-xml xml ["hoOpleiding" "hoOpleidingPeriode" "naamLang"])))) (testing "(you can repeat this to test an update of the same data.)" (let [job (post-job :upsert :education-specifications "parent")] @@ -52,6 +46,9 @@ (is (job-done? child-job)) (is (rio-with-relation? (job-result-opleidingseenheidcode parent-job) (job-result-opleidingseenheidcode child-job))) + (let [xml (rio-opleidingseenheid (job-result-opleidingseenheidcode child-job))] + (is (= "child education specification" + (get-in-xml xml ["hoOpleiding" "hoOpleidingPeriode" "naamLang"])))) (testing "scenario [2a]: Test /job/link of the edspec parent and create a new 'eigen sleutel'. You can expect the 'eigen From 9f57807db0fe2e1e34d985e3f13f9250bcaa1167 Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Wed, 6 Dec 2023 14:05:08 +0100 Subject: [PATCH 03/14] e2e: add gh actions workflow --- .github/workflows/e2e.yml | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/e2e.yml diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 00000000..b588624f --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,49 @@ +name: Run e2e tests + +on: + release: + types: [published] + +jobs: + e2e: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/cache@v3 + with: { path: "~/.m2", key: "${{ runner.os }}-m2" } + + - name: Start Redis + uses: supercharge/redis-github-action@1.4.0 + with: + redis-version: 6.2 + + - name: Run tests + env: + CLIENT_ID: ${{ secrets.CLIENT_ID }} + CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} + CLIENTS_INFO_PATH: ${{ secrets.CLIENTS_INFO_PATH }} + GATEWAY_PASSWORD: ${{ secrets.GATEWAY_PASSWORD }} + GATEWAY_ROOT_URL: ${{ secrets.GATEWAY_ROOT_URL }} + GATEWAY_USER: ${{ secrets.GATEWAY_USER }} + KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }} + KEYSTORE_JKS_B64: ${{ secrets.KEYSTORE_JKS_B64 }} + KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} + KEYSTORE: test/keystore.jks + OS_AUTH_URL: ${{ secrets.OS_AUTH_URL }} + OS_CONTAINER_NAME: ${{ secrets.OS_CONTAINER_NAME }} + OS_PASSWORD: ${{ secrets.OS_PASSWORD }} + OS_PROJECT_NAME: ${{ secrets.OS_PROJECT_NAME }} + OS_USERNAME: ${{ secrets.OS_USERNAME }} + RIO_READ_URL: ${{ secrets.RIO_READ_URL }} + RIO_RECIPIENT_OIN: ${{ secrets.RIO_RECIPIENT_OIN }} + RIO_SENDER_OIN: ${{ secrets.RIO_SENDER_OIN }} + RIO_UPDATE_URL: ${{ secrets.RIO_UPDATE_URL }} + SURF_CONEXT_CLIENT_ID: ${{ secrets.SURF_CONEXT_CLIENT_ID }} + SURF_CONEXT_CLIENT_SECRET: ${{ secrets.SURF_CONEXT_CLIENT_SECRET }} + SURF_CONEXT_INTROSPECTION_ENDPOINT: ${{ secrets.SURF_CONEXT_INTROSPECTION_ENDPOINT }} + TOKEN_ENDPOINT: ${{ secrets.TOKEN_ENDPOINT }} + TRUSTSTORE_JKS_B64: ${{ secrets.TRUSTSTORE_JKS_B64 }} + TRUSTSTORE_PASSWORD: ${{ secrets.TRUSTSTORE_PASSWORD }} + TRUSTSTORE: truststore.jks + run: lein test :e2e From 84da0a72d2f00f239d10cf0af9e2069cdc7043f6 Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Wed, 13 Dec 2023 11:19:26 +0100 Subject: [PATCH 04/14] e2e: add "try to create edspecs with invalid data" scenario --- .../education-specifications/bad-type.json | 77 +++++++++++++++++++ test/nl/surf/eduhub_rio_mapper/e2e_test.clj | 12 ++- 2 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/remote-entities/education-specifications/bad-type.json diff --git a/test/fixtures/remote-entities/education-specifications/bad-type.json b/test/fixtures/remote-entities/education-specifications/bad-type.json new file mode 100644 index 00000000..09ac3f43 --- /dev/null +++ b/test/fixtures/remote-entities/education-specifications/bad-type.json @@ -0,0 +1,77 @@ +{ + "level": "bachelor", + "children": [], + "organization": "c388522c-ebc1-2889-1899-06a89e4f5091", + "educationSpecificationType": "badType", + "educationSpecificationId": "{{education-specifications/bad-type}}", + "validFrom": "1950-09-20", + "abbreviation": "1T", + "validTo": "2060-08-28", + "learningOutcomes": [ + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + } + ], + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: nieuw talent op het gebied van programmeren" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: nieuw talent op het gebied van programmeren" + } + ] + ], + "formalDocument": "diploma", + "sector": "higher professional education", + "name": [ + { + "language": "en-GB", + "value": "bad-type education specification" + }, + { + "language": "nl-NL", + "value": "bad-type education specification" + } + ], + "primaryCode": { + "codeType": "identifier", + "code": "{{education-specifications/bad-type}}" + }, + "link": "https://universiteit-van-boxtel.nl/education-specifications/{{education-specifications/bad-type}}", + "fieldsOfStudy": "0912", + "description": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: There is a 12 credits course which offers student the opportunity to experience in the domain will be paid to the depletion of fossil resources to biomass resources for energy, raw materials and tree form. The course addresses the question if and how this relates to material struggles over natural resources and its relationship to economic and technological domains;- solving optimization problems is climate change. Within a theoretical stance to support making conscious study and career choices." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: There is a 12 credits course which offers student the opportunity to experience in the domain will be paid to the depletion of fossil resources to biomass resources for energy, raw materials and tree form. The course addresses the question if and how this relates to material struggles over natural resources and its relationship to economic and technological domains;- solving optimization problems is climate change. Within a theoretical stance to support making conscious study and career choices." + } + ], + "levelOfQualification": "6", + "consumers": [ + { + "consumerKey": "rio", + "category": [ + "business_and_project_support", + "education", + "cross_sectoral", + "language_and_culture", + "technology_and_ict" + ] + } + ], + "studyLoad": { + "value": 93, + "studyLoadUnit": "sbu" + } +} diff --git a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj index c7358756..f9c0d05d 100644 --- a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj +++ b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj @@ -1,5 +1,6 @@ (ns nl.surf.eduhub-rio-mapper.e2e-test (:require [clojure.test :refer :all] + [nl.jomco.http-status-codes :as http-status] [nl.surf.eduhub-rio-mapper.e2e-helper :refer :all] [nl.surf.eduhub-rio-mapper.remote-entities-helper :refer [remote-entities-fixture]]) (:import (java.util UUID))) @@ -78,9 +79,14 @@ (is (job-has-diffs? job))))))) (deftest ^:e2e try-to-create-edspecs-with-invalid-data - ;; scenario [3a]: Test /job/upsert/ to see how the rio mapper reacts on an invalid api call. You can expect a 404 response. - ;; scenario [3b]: Test /job/upsert with an edspec parent with an invalid type attribute. You can expect 'error'. - :TODO) + (testing "scenario [3a]: Test /job/upsert/ to see how the rio mapper reacts on an invalid api call. You can expect a 404 response." + (let [job (post-job :upsert "not-a-valid-type" (UUID/randomUUID))] + (is (= http-status/not-found (:status job))))) + + (testing "scenario [3b]: Test /job/upsert with an edspec parent with an invalid type attribute. You can expect 'error'." + (let [job (post-job :upsert :education-specifications "bad-type")] + (is (job-error? job)) + (is (= "fetching-ooapi" (job-result job :phase)))))) (deftest ^:e2e create-a-program-for-the-edspec-child ;; scenario [4a]: Test /job/dry-run to see the difference between the program in OOAPI en de aangeboden opleiding in RIO. You can expect RIO to be empty, when you start fresh. From 4165f2d74fedc026a26d4fa0fa83abd41a9cea1c Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Wed, 13 Dec 2023 11:57:52 +0100 Subject: [PATCH 05/14] e2e: rename eduspec entity for clarity --- .../{child.json => child-program.json} | 12 +++++------ .../{parent.json => parent-program.json} | 12 +++++------ test/nl/surf/eduhub_rio_mapper/e2e_test.clj | 21 +++++++++---------- 3 files changed, 22 insertions(+), 23 deletions(-) rename test/fixtures/remote-entities/education-specifications/{child.json => child-program.json} (85%) rename test/fixtures/remote-entities/education-specifications/{parent.json => parent-program.json} (90%) diff --git a/test/fixtures/remote-entities/education-specifications/child.json b/test/fixtures/remote-entities/education-specifications/child-program.json similarity index 85% rename from test/fixtures/remote-entities/education-specifications/child.json rename to test/fixtures/remote-entities/education-specifications/child-program.json index 280ebf31..9b0ac3b9 100644 --- a/test/fixtures/remote-entities/education-specifications/child.json +++ b/test/fixtures/remote-entities/education-specifications/child-program.json @@ -1,9 +1,9 @@ { "level": "bachelor", - "parent": "{{education-specifications/parent}}", + "parent": "{{education-specifications/parent-program}}", "organization": "c388522c-ebc1-2889-1899-06a89e4f5091", "educationSpecificationType": "program", - "educationSpecificationId": "{{education-specifications/child}}", + "educationSpecificationId": "{{education-specifications/child-program}}", "validFrom": "2016-12-15", "abbreviation": "OT", "validTo": "2025-04-25", @@ -24,18 +24,18 @@ "name": [ { "language": "en-GB", - "value": "child education specification" + "value": "child-program education specification" }, { "language": "nl-NL", - "value": "child education specification" + "value": "child-program education specification" } ], "primaryCode": { "codeType": "identifier", - "code": "{{education-specifications/child}}" + "code": "{{education-specifications/child-program}}" }, - "link": "https://universiteit-van-boxtel.nl/education-specifications/{{education-specifications/child}}", + "link": "https://universiteit-van-boxtel.nl/education-specifications/{{education-specifications/child-program}}", "fieldsOfStudy": "0612", "description": [ { diff --git a/test/fixtures/remote-entities/education-specifications/parent.json b/test/fixtures/remote-entities/education-specifications/parent-program.json similarity index 90% rename from test/fixtures/remote-entities/education-specifications/parent.json rename to test/fixtures/remote-entities/education-specifications/parent-program.json index 667921e6..daa86912 100644 --- a/test/fixtures/remote-entities/education-specifications/parent.json +++ b/test/fixtures/remote-entities/education-specifications/parent-program.json @@ -1,9 +1,9 @@ { "level": "bachelor", - "children": ["{{education-specifications/child}}"], + "children": ["{{education-specifications/child-program}}"], "organization": "c388522c-ebc1-2889-1899-06a89e4f5091", "educationSpecificationType": "program", - "educationSpecificationId": "{{education-specifications/parent}}", + "educationSpecificationId": "{{education-specifications/parent-program}}", "validFrom": "1950-09-20", "abbreviation": "1T", "validTo": "2060-08-28", @@ -34,18 +34,18 @@ "name": [ { "language": "en-GB", - "value": "parent education specification" + "value": "parent-program education specification" }, { "language": "nl-NL", - "value": "parent education specification" + "value": "parent-program education specification" } ], "primaryCode": { "codeType": "identifier", - "code": "{{education-specifications/parent}}" + "code": "{{education-specifications/parent-program}}" }, - "link": "https://universiteit-van-boxtel.nl/education-specifications/{{education-specifications/parent}}", + "link": "https://universiteit-van-boxtel.nl/education-specifications/{{education-specifications/parent-program}}", "fieldsOfStudy": "0912", "description": [ { diff --git a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj index f9c0d05d..54ab2633 100644 --- a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj +++ b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj @@ -14,28 +14,27 @@ between the edspec parent in OOAPI en de opleidingeenheid in RIO. You can expect RIO to be empty, when you start fresh." - (let [job (post-job :dry-run/upsert :education-specifications "parent")] + (let [job (post-job :dry-run/upsert :education-specifications "parent-program")] (is (job-done? job)) (is (job-dry-run-not-found? job)))) - (testing "scenario [1b]: Test /job/upsert with the edspec - parent. You can expect 'done' and a opleidingeenheid in - RIO is inserted." - (let [parent-job (post-job :upsert :education-specifications "parent")] + (testing "scenario [1b]: Test /job/upsert with the program. You can + expect 'done' and a opleidingeenheid in RIO is inserted." + (let [parent-job (post-job :upsert :education-specifications "parent-program")] (is (job-done? parent-job)) (is (job-result-opleidingseenheidcode parent-job)) (let [xml (rio-opleidingseenheid (job-result-opleidingseenheidcode parent-job))] - (is (= "parent education specification" + (is (= "parent-program education specification" (get-in-xml xml ["hoOpleiding" "hoOpleidingPeriode" "naamLang"])))) (testing "(you can repeat this to test an update of the same data.)" - (let [job (post-job :upsert :education-specifications "parent")] + (let [job (post-job :upsert :education-specifications "parent-program")] (is (job-done? job)))) (testing "scenario [1a]: Test /job/dry-run to see the difference between the edspec parent in OOAPI en de opleidingeenheid in RIO. You can expect them to be the same." - (let [job (post-job :dry-run/upsert :education-specifications "parent")] + (let [job (post-job :dry-run/upsert :education-specifications "parent-program")] (is (job-done? job)) (is (job-dry-run-found? job)) (is (job-without-diffs? job)))) @@ -43,12 +42,12 @@ (testing "scenario [1c]: Test /job/upsert with the edspec child. You can expect 'done' and a variant in RIO is inserted met een relatie met de parent." - (let [child-job (post-job :upsert :education-specifications "child")] + (let [child-job (post-job :upsert :education-specifications "child-program")] (is (job-done? child-job)) (is (rio-with-relation? (job-result-opleidingseenheidcode parent-job) (job-result-opleidingseenheidcode child-job))) (let [xml (rio-opleidingseenheid (job-result-opleidingseenheidcode child-job))] - (is (= "child education specification" + (is (= "child-program education specification" (get-in-xml xml ["hoOpleiding" "hoOpleidingPeriode" "naamLang"])))) (testing "scenario [2a]: Test /job/link of the edspec parent and @@ -74,7 +73,7 @@ (testing "scenario [2b]: Test /job/link to reset the edspec parent to the old 'eigen sleutel'." (let [job (post-job :link (job-result-opleidingseenheidcode parent-job) - :education-specifications "parent")] + :education-specifications "parent-program")] (is (job-done? job)) (is (job-has-diffs? job))))))) From 5c5a88f27520da43dfde8ce463223ee70fc08d9b Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Wed, 13 Dec 2023 15:37:33 +0100 Subject: [PATCH 06/14] e2e: support remote entity programs with offerings --- .../remote-entities/programs/some.json | 190 ++++++++++++++++++ .../programs/some/offerings.json | 106 ++++++++++ .../remote_entities_helper.clj | 131 +++++++----- 3 files changed, 377 insertions(+), 50 deletions(-) create mode 100644 test/fixtures/remote-entities/programs/some.json create mode 100644 test/fixtures/remote-entities/programs/some/offerings.json diff --git a/test/fixtures/remote-entities/programs/some.json b/test/fixtures/remote-entities/programs/some.json new file mode 100644 index 00000000..1f0048d9 --- /dev/null +++ b/test/fixtures/remote-entities/programs/some.json @@ -0,0 +1,190 @@ +{ + "fieldsOfStudy": "0612", + "teachingLanguage": "eng", + "studyLoad": { + "value": 155, + "studyLoadUnit": "ects" + }, + "organization": "6fd6c513-5a3c-cac7-99a4-d73001b99497", + "level": "nt2-2", + "educationSpecification": "{{education-specifications/parent-program}}", + "name": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: Talenonderwijs en Communicatie" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: Talenonderwijs en Communicatie" + } + ], + "sector": "secondary vocational education", + "validFrom": "2008-10-18", + "addresses": [ + { + "countryCode": "NL", + "city": "Morra", + "geoLocation": { + "longitude": 88, + "latitude": 0 + }, + "addressType": "teaching", + "streetNumber": 23, + "postalCode": "4184QU", + "street": "Tollenslaan", + "additional": "a" + } + ], + "programType": "program", + "primaryCode": { + "codeType": "crohoCreboCode", + "code": "60740" + }, + "modeOfDelivery": [ + "on campus", + "distance-learning", + "hybrid", + "online" + ], + "duration": "P1DT30H4S", + "qualificationAwarded": "Phd", + "link": "https://universiteit-van-morra.nl/programs/{{programs/some}}", + "coordinators": [ + "cafecafe-cafe-cafe-cafe-cafecafecafe" + ], + "otherCodes": [ + { + "codeType": "crohoCreboCode", + "code": "60740" + } + ], + "validTo": "2023-12-18", + "modeOfStudy": "dual training", + "assessment": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + } + ], + "description": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + } + ], + "levelOfQualification": "2", + "consumers": [ + { + "alliances": [ + { + "name": "lde", + "enrollmentForOwnStudents": "broker", + "type": "broadening", + "visibleForOwnStudents": false, + "selection": true, + "theme": "13" + } + ], + "consumerKey": "eduxchange" + }, + { + "educationOffererCode": "110A133", + "acceleratedRoute": "no_accelerated_route", + "consentParticipationSTAP": "permission_not_granted", + "deficiency": "deficiencies", + "studyChoiceCheck": "no_study_choice_check", + "consumerKey": "rio", + "requirementsActivities": "requirements", + "propaedeuticPhase": "no_propaedeutic_phase", + "educationLocationCode": "107X215" + } + ], + "programId": "{{programs/some}}", + "firstStartDate": "2010-01-31", + "resources": [ + "Lelieveldt, H. Course guide. Sage.Miles, M.", + "- lecture hand-outs and additional book chapters will be available online. Sage. Mourato (2006).", + "B. Practical manual Soil Pollution and Soil Protection. ." + ], + "qualificationRequirements": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + } + ], + "abbreviation": "TEC", + "learningOutcomes": [ + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: inzicht in de bijzondere eigenschappen van materialen" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: inzicht in de bijzondere eigenschappen van materialen" + } + ], + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: algemene empathie voor levende wezens" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: algemene empathie voor levende wezens" + } + ], + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: nieuw talent op het gebied van programmeren" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: nieuw talent op het gebied van programmeren" + } + ], + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + } + ] + ], + "admissionRequirements": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + } + ], + "enrollment": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: . . ." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: . . ." + } + ] +} diff --git a/test/fixtures/remote-entities/programs/some/offerings.json b/test/fixtures/remote-entities/programs/some/offerings.json new file mode 100644 index 00000000..0a8cc203 --- /dev/null +++ b/test/fixtures/remote-entities/programs/some/offerings.json @@ -0,0 +1,106 @@ +{ + "pageSize": 10, + "pageNumber": 1, + "hasPreviousPage": false, + "hasNextPage": false, + "totalPages": 1, + "items": [ + { + "offeringId": "cafecafe-cafe-cafe-cafe-cafecafecafe", + "primaryCode": { + "codeType": "identifier", + "code": "1234qwe12" + }, + "offeringType": "component", + "academicSession": "fadefade-fade-fade-fade-fadefadefade", + "name": [ + { + "language": "en-GB", + "value": "Final written test for INFOMQNM for fall semseter 2020" + } + ], + "abbreviation": "Test-INFOMQNM-20FS", + "description": [ + { + "language": "en-GB", + "value": "'Prove in writing knowledge of research methods, including:\nAcquire knowledge of HCI research paradigms\nAble to design suitable research studies (e.g., choose between within and between subject designs)\nDefine/apply/design metrics and scales\nDefine/produce materials (e.g., stimuli and questionnaires)\nDefine protocols for research studies\nUnderstands and take in account concepts of reliability and validity\nAnalyze and improve methods and analysis of published scientific articles\nAble to deliver scientific reports\nProve in writing knowledge of ­­­statistics, including:\nHandle hypothesis testing with complex designs (e.g., including , dependent, independent, and co variates)\nData preparation (e.g., coding and feature selection)\nReason towards adequate techniques to ensure valid outcomes (e.g., be aware of type I, type II errors)\nSelect an appropriate sampling method (e.g., stratified)\nPerform parametric tests (e.g., repeated measures (M)ANOVA)\nPerform non-parametric tests (e.g., Chi-square, Mann-Whitney, and Kruskal-Wallis)'\n" + } + ], + "teachingLanguage": "nld", + "modeOfDelivery": [ + "situated" + ], + "maxNumberStudents": 200, + "enrolledNumberStudents": 150, + "pendingNumberStudents": 50, + "minNumberStudents": 15, + "resultExpected": true, + "resultValueType": "1-10", + "link": "https://osiris.uu.nl/osiris_student_uuprd/OnderwijsCatalogusZoekCursus.do#submitForm?cursuscode=INFOMQNM", + "otherCodes": [ + { + "codeType": "identifier", + "code": "1234qwe12" + } + ], + "consumers": [ + { + "consumerKey": "rio", + "explanationRequiredPermission": "Toestemming is vereist omdat we daarom vragen.", + "requiredPermissionRegistration": "yes", + "registrationStatus": "open" + } + ], + "ext": {}, + "startDate": "2019-08-21", + "endDate": "2023-06-15", + "enrollStartDate": "2019-05-01", + "enrollEndDate": "2019-08-01", + "flexibleEntryPeriodStart": "2019-08-24", + "flexibleEntryPeriodEnd": "2019-09-24", + "addresses": [ + { + "addressType": "postal", + "street": "Moreelsepark", + "streetNumber": "48", + "additional": [ + { + "language": "en-GB", + "value": "On the other side of the road" + } + ], + "postalCode": "3511 EP", + "city": "Utrecht", + "countryCode": "NL", + "geolocation": { + "latitude": 52.089123, + "longitude": 5.113337 + }, + "ext": {} + } + ], + "priceInformation": [ + { + "costType": "total costs", + "amount": "340.84", + "vatAmount": "40", + "amountWithoutVat": "300.84", + "currency": "EUR", + "displayAmount": [ + { + "language": "nl-NL", + "value": "€380,84" + }, + { + "language": "en-US", + "value": "$401.17" + } + ], + "ext": {} + } + ], + "program": "{{programs/some}}" + } + ], + "ext": {} +} diff --git a/test/nl/surf/eduhub_rio_mapper/remote_entities_helper.clj b/test/nl/surf/eduhub_rio_mapper/remote_entities_helper.clj index c73a3545..62d009a2 100644 --- a/test/nl/surf/eduhub_rio_mapper/remote_entities_helper.clj +++ b/test/nl/surf/eduhub_rio_mapper/remote_entities_helper.clj @@ -7,19 +7,19 @@ the JSON files are replaced by random UUIDs and the paths and base names replace with those UUIDs when referenced using `{{` and `}}`. - For instance `education-specifications/parent.json` may contain: + For instance `education-specifications/some.json` may contain: ``` { \"level\": \"bachelor\", - \"parent\": \"{{education-specifications/parent}}\", + \"parent\": \"{{education-specifications/some}}\", \"organization\": \"{{organizations/acme}}\", ``` Say we generated a UUID of `beefbeef-beef-beef-beef-beefbeefbeef` for this entity and `cafecafe-cafe-cafe-cafe-cafecafecafe` for `organizations/acme`, the uploaded version will be named - `education-specifications/beefbeef-beef-beef-beef-beefbeefbeef.json` + `education-specifications/beefbeef-beef-beef-beef-beefbeefbeef` and contain: ``` @@ -30,7 +30,12 @@ ``` and the uploaded version of `organizations/acme` will be named - `organizations/cafecafe-cafe-cafe-cafe-cafecafecafe.json`. + `organizations/cafecafe-cafe-cafe-cafe-cafecafecafe`. + + Nested resources are handled slightly different. For resource like + `programs/some/offerings.json` the `programs/some` part will be + considered its name and the uploaded object will be named something + like: `programs/cafecafe-cafe-cafe-cafe-cafecafecafe/offerings`. This only works if the following environment variables are set: @@ -154,20 +159,35 @@ io/resource io/file)] (when-not (and dir (.isDirectory dir)) - (throw (IllegalStateException. (str entities-resource-path " is not a directory -- are you running in a jar?")))) + (throw (IllegalStateException. + (str entities-resource-path " is not a directory -- are you running in a jar?")))) dir)) -(defn- input-resources +(defn- input-files [] - (->> (entities-dir) - (.listFiles) - (filter #(.isDirectory %)) - (remove #(string/starts-with? (.getName %) ".")) - (mapcat (fn [dir] - (let [dirname (.getName dir)] - (->> (.listFiles dir) - (map #(str dirname "/" (.getName %))) - (filter #(string/ends-with? % ".json")))))))) + (letfn [(f [dir] + (loop [[file & files] (.listFiles dir) + result []] + (if file + (recur files + (if (.isDirectory file) + (concat result (f file)) + (conj result file))) + result)))] + (f (entities-dir)))) + +(defn- file->base + [file] + (string/replace + (subs (.getCanonicalPath file) + (inc (count (.getCanonicalPath (entities-dir))))) + #"\.json$" "")) + +(defn- file->key + [file] + (second + (re-matches #"^([^/]+/[^./]+).*" + (file->base file)))) (defn make-session "Return a new session map of entity names to random ids. @@ -177,18 +197,21 @@ So `courses/some-course.json` will be mapped as: - \"courses/some-course\" => some-random-uuid. + \"courses/some-course\" => some-random-uuid + + and `programs/some-program/offerings.json` will be mapped as: + + \"programs/some-program\" => some-other-random-uuid See also `with-session`" [] - (let [input (input-resources)] - (into {} (map #(vector (string/replace % #".json" "") (UUID/randomUUID)) input)))) - -(defn- resource-path - [n] - (str entities-resource-path "/" n ".json")) + (into {} + (->> (input-files) + (map file->key) + (set) + (map #(vector % (UUID/randomUUID)))))) -(defn- replace-exprs +(defn- replace-content-exprs [templ session] (string/replace templ #"\{\{\s*([^}\s]+)\s*}\}" @@ -197,13 +220,41 @@ (throw (ex-info (str "Can't find name '" name "'") {:name name :session session}))))))) -(defn- resource-content - [n session] - (-> n - resource-path - io/resource - slurp - (replace-exprs session))) +(defn- object-content + [f session] + (-> f + (slurp) + (replace-content-exprs session))) + +(defn- object-location + "Determine object location from file name and session." + [f session] + (let [loc (file->base f)] + (loop [[[k v] & more] session] + (assert k) + (if (string/starts-with? loc k) + (let [[_ base] (re-matches #"^([^/]+)/.*" k)] + (str base "/" (string/replace loc k (str v)))) + (recur more))))) + +(defn- remote-objects + [session] + (map (fn [f] + {:path (object-location f session) + :body (object-content f session)}) + (input-files))) + +(defn- put-session + [info container-name session] + (println "Adding remote entities to" container-name) + (doseq [object (remote-objects session)] + (os-put-object info container-name object))) + +(defn- delete-session + [info container-name session] + (println "Removing entities from" container-name) + (doseq [object (remote-objects session)] + (os-delete-object info container-name object))) (def ^:dynamic *session* @@ -227,26 +278,6 @@ :post [%]} (get *session* n)) - -(defn- remote-objects - [session] - (->> session - (map (fn [[n id]] - {:path (str (string/replace n #"/.*" "") "/" id) - :body (resource-content n session)})))) - -(defn- put-session - [info container-name session] - (println "Adding remote entities to" container-name) - (doseq [object (remote-objects session)] - (os-put-object info container-name object))) - -(defn- delete-session - [info container-name session] - (println "Removing entities from" container-name) - (doseq [object (remote-objects session)] - (os-delete-object info container-name object))) - (defn remote-entities-fixture "A fixture that uploads the entities to the remote container. From 03cb997a7fcaa63f3bda828d793488fadf1d4edf Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Wed, 13 Dec 2023 16:59:20 +0100 Subject: [PATCH 07/14] e2e: add "create a program (for the edSpec child)" scenario --- src/nl/surf/eduhub_rio_mapper/rio/mutator.clj | 1 + test/nl/surf/eduhub_rio_mapper/e2e_helper.clj | 39 +++- test/nl/surf/eduhub_rio_mapper/e2e_test.clj | 197 ++++++++++-------- 3 files changed, 145 insertions(+), 92 deletions(-) diff --git a/src/nl/surf/eduhub_rio_mapper/rio/mutator.clj b/src/nl/surf/eduhub_rio_mapper/rio/mutator.clj index 431a3d4c..a81dc335 100644 --- a/src/nl/surf/eduhub_rio_mapper/rio/mutator.clj +++ b/src/nl/surf/eduhub_rio_mapper/rio/mutator.clj @@ -60,6 +60,7 @@ "A01160" ;; Externe identificatie niet uniek is niet recoverable dus zou niet moeten retryen "K01010" ;; 'propedeutischeFase' komt niet vaak genoeg voor als kenmerk "P01081" ;; Er bestaat al een opleidingseenheid met dezelfde eigenOpleidingseenheidSleutel + "N11030" ;; De einddatum van een instroomperiode moet na de begindatum liggen }) ;; Note: `P01810: Er bestaan nog verwijzingen naar de te verwijderen diff --git a/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj b/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj index 9ff4b3cd..fde45666 100644 --- a/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj +++ b/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj @@ -10,6 +10,7 @@ [nl.surf.eduhub-rio-mapper.cli :as cli] [nl.surf.eduhub-rio-mapper.clients-info :as clients-info] [nl.surf.eduhub-rio-mapper.http-utils :as http-utils] + [nl.surf.eduhub-rio-mapper.ooapi :as ooapi] [nl.surf.eduhub-rio-mapper.remote-entities-helper :as remote-entities] [nl.surf.eduhub-rio-mapper.rio :as rio] [nl.surf.eduhub-rio-mapper.rio.loader :as rio-loader] @@ -203,10 +204,11 @@ (let [[rio-id type] args] (str "/job/unlink/" rio-id "/" (name type))))) -(defn ooapi +(defn ooapi-id "Get OOAPI UUID of automatically uploaded fixture." - [name] - (get remote-entities/*session* name)) + [type id] + (let [name (str (name type) "/" id)] + (get remote-entities/*session* name))) (defn- interpret-post-job-args "Automatically find OOAPI ID from session. @@ -219,7 +221,7 @@ (let [[type id] (take-last 2 args)] (concat (drop-last args) [(if (and (keyword? type) (string? id)) - (let [uuid (ooapi (str (name type) "/" id))] + (let [uuid (ooapi-id type id)] (assert uuid (str "Expect a UUID for " id)) uuid) id)]))) @@ -316,9 +318,21 @@ (defmethod test/assert-expr 'job-result-opleidingseenheidcode [msg form] `(let [job# ~(second form) attrs# (job-result-attributes job#)] - (test/do-report {:type (if (job-result-opleidingseenheidcode job#) :pass :fail) - :message (or ~msg "Expect job result attributes to include opleidingseenheidcode."), - :expected '~form, :actual attrs#}))) + (test/do-report {:type (if (job-result-opleidingseenheidcode job#) :pass :fail) + :message (or ~msg "Expect job result attributes to include opleidingseenheidcode."), + :expected '~form, :actual attrs#}))) + +(defn job-result-aangebodenopleidingcode + "Short cut to `post-job` job response attributes aangebodenopleidingcode." + [job] + (job-result-attributes job :aangebodenopleidingcode)) + +(defmethod test/assert-expr 'job-result-aangebodenopleidingcode [msg form] + `(let [job# ~(second form) + attrs# (job-result-attributes job#)] + (test/do-report {:type (if (job-result-aangebodenopleidingcode job#) :pass :fail) + :message (or ~msg "Expect job result attributes to include aangebodenopleidingcode."), + :expected '~form, :actual attrs#}))) (defn job-has-diffs? "Returns `true` if \"diff\" is detected in given attributes." @@ -449,6 +463,17 @@ :response-type :literal} (rio-get)))) +(defn rio-aangebodenopleiding + "Call RIO `opvragen_aangebodenOpleiding`." + [id] + {:pre [(spec/valid? ::ooapi/id id)]} + (print-boxed "rio-aangebodenopleiding" + (-> {::rio/type rio-loader/aangeboden-opleiding + ::ooapi/id id + :institution-oin (:institution-oin @client-info) + :response-type :literal} + (rio-get)))) + (defn get-in-xml "Get text node from `path` starting at `node`." [node path] diff --git a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj index 54ab2633..7387cafd 100644 --- a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj +++ b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj @@ -7,96 +7,115 @@ (use-fixtures :once with-running-mapper remote-entities-fixture) -(def test-eigensleutel (UUID/randomUUID)) - -(deftest ^:e2e create-edspecs - (testing "scenario [1a]: Test /job/dry-run to see the difference - between the edspec parent in OOAPI en de opleidingeenheid - in RIO. You can expect RIO to be empty, when you start - fresh." - (let [job (post-job :dry-run/upsert :education-specifications "parent-program")] - (is (job-done? job)) - (is (job-dry-run-not-found? job)))) - - (testing "scenario [1b]: Test /job/upsert with the program. You can - expect 'done' and a opleidingeenheid in RIO is inserted." - (let [parent-job (post-job :upsert :education-specifications "parent-program")] - (is (job-done? parent-job)) - (is (job-result-opleidingseenheidcode parent-job)) - (let [xml (rio-opleidingseenheid (job-result-opleidingseenheidcode parent-job))] - (is (= "parent-program education specification" - (get-in-xml xml ["hoOpleiding" "hoOpleidingPeriode" "naamLang"])))) - - (testing "(you can repeat this to test an update of the same data.)" - (let [job (post-job :upsert :education-specifications "parent-program")] - (is (job-done? job)))) - - (testing "scenario [1a]: Test /job/dry-run to see the difference - between the edspec parent in OOAPI en de opleidingeenheid - in RIO. You can expect them to be the same." - (let [job (post-job :dry-run/upsert :education-specifications "parent-program")] +(deftest ^:e2e create-edspecs-and-program + (testing "create edspecs" + (testing "scenario [1a]: Test /job/dry-run to see the difference between the edspec parent in OOAPI en de opleidingeenheid in RIO. You can expect RIO to be empty, when you start fresh." + (let [job (post-job :dry-run/upsert :education-specifications "parent-program")] + (is (job-done? job)) + (is (job-dry-run-not-found? job)))) + + (testing "scenario [1b]: Test /job/upsert with the program. You can expect 'done' and a opleidingeenheid in RIO is inserted." + (let [parent-job (post-job :upsert :education-specifications "parent-program")] + (is (job-done? parent-job)) + (is (job-result-opleidingseenheidcode parent-job)) + (let [xml (rio-opleidingseenheid (job-result-opleidingseenheidcode parent-job))] + (is (= "parent-program education specification" + (get-in-xml xml ["hoOpleiding" "hoOpleidingPeriode" "naamLang"])))) + + (testing "(you can repeat this to test an update of the same data.)" + (let [job (post-job :upsert :education-specifications "parent-program")] + (is (job-done? job)))) + + (testing "scenario [1a]: Test /job/dry-run to see the difference between the edspec parent in OOAPI en de opleidingeenheid in RIO. You can expect them to be the same." + (let [job (post-job :dry-run/upsert :education-specifications "parent-program")] + (is (job-done? job)) + (is (job-dry-run-found? job)) + (is (job-without-diffs? job)))) + + (testing "scenario [1c]: Test /job/upsert with the edspec child. You can expect 'done' and a variant in RIO is inserted met een relatie met de parent." + (let [child-job (post-job :upsert :education-specifications "child-program")] + (is (job-done? child-job)) + (is (rio-with-relation? (job-result-opleidingseenheidcode parent-job) + (job-result-opleidingseenheidcode child-job))) + (let [xml (rio-opleidingseenheid (job-result-opleidingseenheidcode child-job))] + (is (= "child-program education specification" + (get-in-xml xml ["hoOpleiding" "hoOpleidingPeriode" "naamLang"])))) + + (let [test-eigensleutel (UUID/randomUUID)] + (testing "scenario [2a]: Test /job/link of the edspec parent and create a new 'eigen sleutel'. You can expect the 'eigen sleutel' to be changed." + (let [job (post-job :link (job-result-opleidingseenheidcode parent-job) + :education-specifications test-eigensleutel)] + (is (job-done? job)) + (is (job-has-diffs? job))) + + (testing "(you can repeat this to expect an error becoause the new 'eigen sleutel' already exists.)" + (let [job (post-job :link (job-result-opleidingseenheidcode child-job) + :education-specifications test-eigensleutel)] + (is (job-error? job)))))))) + + (testing "scenario [2d]: Test /job/unlink to reset the edspec parent to an empty 'eigen sleutel'." + (let [job (post-job :unlink (job-result-opleidingseenheidcode parent-job) + :education-specifications)] + (is (job-done? job)))) + + (testing "scenario [2b]: Test /job/link to reset the edspec parent to the old 'eigen sleutel'." + (let [job (post-job :link (job-result-opleidingseenheidcode parent-job) + :education-specifications "parent-program")] + (is (job-done? job)) + (is (job-has-diffs? job))))))) + + (testing "create a program (for the edSpec child)" + (testing "scenario [4a]: Test /job/dry-run to see the difference between the program in OOAPI en de aangeboden opleiding in RIO. You can expect RIO to be empty, when you start fresh." + (let [job (post-job :dry-run/upsert :programs "some")] + (is (job-done? job)) + (is (job-dry-run-not-found? job)))) + + (testing "scenario [4c]: Test /job/delete with the program. You can expect an error, because the program is not upserted yet." + (let [job (post-job :delete :programs "some")] + (is (job-error? job)))) + + (testing "scenario [4b]: Test /job/upsert with the program. You can expect a new aangeboden opleiding. This aangeboden opleiding includes a periode and a cohort. (you can repeat this to test an update of the same data.)" + (let [job (post-job :upsert :programs "some")] + (is (job-done? job)) + (is (job-result-aangebodenopleidingcode job)) + (is (= (str (ooapi-id :programs "some")) + (job-result-aangebodenopleidingcode job)) + "aangebodenopleidingcode is the same as the OOAPI id") + (let [xml (rio-aangebodenopleiding (job-result-aangebodenopleidingcode job))] + (is (= "2008-10-18" + (get-in-xml xml ["aangebodenHOOpleiding" "aangebodenHOOpleidingPeriode" "begindatum"]))) + (is (= "1234qwe12" + (get-in-xml xml ["aangebodenHOOpleiding" "aangebodenHOOpleidingCohort" "cohortcode"])))))) + + (testing "scenario [4a]: Test /job/dry-run to see the difference between the program in OOAPI en de opleidingeenheid in RIO. You can expect them to be the same." + (let [job (post-job :dry-run/upsert :programs "some")] + (is (job-done? job)) + (is (job-dry-run-found? job)) + (is (job-without-diffs? job)))) + + (let [test-eigensleutel (UUID/randomUUID)] + (testing "scenario [5a]: Test /job/link of the program and create a new 'eigen sleutel'. You can expect the 'eigen sleutel' to be changed." + (let [job (post-job :link (str (ooapi-id :programs "some")) + :programs test-eigensleutel)] (is (job-done? job)) - (is (job-dry-run-found? job)) - (is (job-without-diffs? job)))) - - (testing "scenario [1c]: Test /job/upsert with the edspec child. You - can expect 'done' and a variant in RIO is inserted met een - relatie met de parent." - (let [child-job (post-job :upsert :education-specifications "child-program")] - (is (job-done? child-job)) - (is (rio-with-relation? (job-result-opleidingseenheidcode parent-job) - (job-result-opleidingseenheidcode child-job))) - (let [xml (rio-opleidingseenheid (job-result-opleidingseenheidcode child-job))] - (is (= "child-program education specification" - (get-in-xml xml ["hoOpleiding" "hoOpleidingPeriode" "naamLang"])))) - - (testing "scenario [2a]: Test /job/link of the edspec parent and - create a new 'eigen sleutel'. You can expect the 'eigen - sleutel' to be changed." - (let [job (post-job :link (job-result-opleidingseenheidcode parent-job) - :education-specifications test-eigensleutel)] - (is (job-done? job)) - (is (job-has-diffs? job))) - - (testing "(you can repeat this to expect an error becoause the new - 'eigen sleutel' already exists.)" - (let [job (post-job :link (job-result-opleidingseenheidcode child-job) - :education-specifications test-eigensleutel)] - (is (job-error? job))))))) - - (testing "scenario [2d]: Test /job/unlink to reset the edspec parent - to an empty 'eigen sleutel'." - (let [job (post-job :unlink (job-result-opleidingseenheidcode parent-job) - :education-specifications)] + (is (job-has-diffs? job))) + + (testing "(you can repeat this to expect an error becoause the new 'eigen sleutel' already exists.)" + (let [job (post-job :link (str (ooapi-id :programs "some")) + :programs test-eigensleutel)] + (is (job-error? job))))) + + (testing "scenario [5d]: Test /job/unlink to reset the program to an empty 'eigen sleutel'." + (let [job (post-job :unlink (str (ooapi-id :programs "some")) + :programs test-eigensleutel)] (is (job-done? job)))) - (testing "scenario [2b]: Test /job/link to reset the edspec parent - to the old 'eigen sleutel'." - (let [job (post-job :link (job-result-opleidingseenheidcode parent-job) - :education-specifications "parent-program")] + (testing "scenario [5b]: Test /job/link to reset the program to the old 'eigen sleutel'." + (let [job (post-job :link (str (ooapi-id :programs "some")) + :programs test-eigensleutel)] (is (job-done? job)) (is (job-has-diffs? job))))))) -(deftest ^:e2e try-to-create-edspecs-with-invalid-data - (testing "scenario [3a]: Test /job/upsert/ to see how the rio mapper reacts on an invalid api call. You can expect a 404 response." - (let [job (post-job :upsert "not-a-valid-type" (UUID/randomUUID))] - (is (= http-status/not-found (:status job))))) - - (testing "scenario [3b]: Test /job/upsert with an edspec parent with an invalid type attribute. You can expect 'error'." - (let [job (post-job :upsert :education-specifications "bad-type")] - (is (job-error? job)) - (is (= "fetching-ooapi" (job-result job :phase)))))) - -(deftest ^:e2e create-a-program-for-the-edspec-child - ;; scenario [4a]: Test /job/dry-run to see the difference between the program in OOAPI en de aangeboden opleiding in RIO. You can expect RIO to be empty, when you start fresh. - ;; scenario [4c]: Test /job/delete with the program. You can expect an error, because the program is not upserted yet. - ;; scenario [4b]: Test /job/upsert with the program. You can expect a new aangeboden opleiding. This aangeboden opleiding includes a periode and a cohort. (you can repeat this to test an update of the same data.) - ;; scenario [4a]: Test /job/dry-run to see the difference between the program in OOAPI en de opleidingeenheid in RIO. You can expect them to be the same. - ;; scenario [5a]: Test /job/link of the program and create a new 'eigen sleutel'. You can expect the 'eigen sleutel' to be changed. (you can repeat this to expect an error becoause the new 'eigen sleutel' already exists.) - ;; scenario [5d]: Test /job/unlink to reset the program to an empty 'eigen sleutel'. - ;; scenario [5b]: Test /job/link to reset the program to the old 'eigen sleutel'. - :TODO) - (deftest ^:e2e try-to-create-a-program-with-invalid-data ;; scenario [6a]: Test /job/upsert with a program with an invalid onderwijsaanbieder attribute. You can expect 'error'. ;; scenario [6b]: Test /job/upsert with a program with an invalid onderwijslocatie attribute. You can expect 'error'. @@ -113,4 +132,12 @@ ;; scenario [8b]: Test /job/link to reset the course to the old 'eigen sleutel'. :TODO) -;; TODO add test to upsert non existing eduspec +(deftest ^:e2e try-to-create-edspecs-with-invalid-data + (testing "scenario [3a]: Test /job/upsert/ to see how the rio mapper reacts on an invalid api call. You can expect a 404 response." + (let [job (post-job :upsert "not-a-valid-type" (UUID/randomUUID))] + (is (= http-status/not-found (:status job))))) + + (testing "scenario [3b]: Test /job/upsert with an edspec parent with an invalid type attribute. You can expect 'error'." + (let [job (post-job :upsert :education-specifications "bad-type")] + (is (job-error? job)) + (is (= "fetching-ooapi" (job-result job :phase)))))) From eb73a4c292b21e889bf9e681202df0612f96bcfc Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Mon, 18 Dec 2023 10:46:37 +0100 Subject: [PATCH 08/14] e2e: add "try to create a program with invalid data" scenario --- .../programs/bad-edu-location.json | 190 ++++++++++++++++++ .../programs/bad-edu-location/offerings.json | 106 ++++++++++ .../programs/bad-edu-offerer.json | 190 ++++++++++++++++++ .../programs/bad-edu-offerer/offerings.json | 106 ++++++++++ test/nl/surf/eduhub_rio_mapper/e2e_test.clj | 12 +- 5 files changed, 600 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/remote-entities/programs/bad-edu-location.json create mode 100644 test/fixtures/remote-entities/programs/bad-edu-location/offerings.json create mode 100644 test/fixtures/remote-entities/programs/bad-edu-offerer.json create mode 100644 test/fixtures/remote-entities/programs/bad-edu-offerer/offerings.json diff --git a/test/fixtures/remote-entities/programs/bad-edu-location.json b/test/fixtures/remote-entities/programs/bad-edu-location.json new file mode 100644 index 00000000..583e4146 --- /dev/null +++ b/test/fixtures/remote-entities/programs/bad-edu-location.json @@ -0,0 +1,190 @@ +{ + "fieldsOfStudy": "0612", + "teachingLanguage": "eng", + "studyLoad": { + "value": 155, + "studyLoadUnit": "ects" + }, + "organization": "6fd6c513-5a3c-cac7-99a4-d73001b99497", + "level": "nt2-2", + "educationSpecification": "{{education-specifications/parent-program}}", + "name": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: Talenonderwijs en Communicatie" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: Talenonderwijs en Communicatie" + } + ], + "sector": "secondary vocational education", + "validFrom": "2008-10-18", + "addresses": [ + { + "countryCode": "NL", + "city": "Morra", + "geoLocation": { + "longitude": 88, + "latitude": 0 + }, + "addressType": "teaching", + "streetNumber": 23, + "postalCode": "4184QU", + "street": "Tollenslaan", + "additional": "a" + } + ], + "programType": "program", + "primaryCode": { + "codeType": "crohoCreboCode", + "code": "60740" + }, + "modeOfDelivery": [ + "on campus", + "distance-learning", + "hybrid", + "online" + ], + "duration": "P1DT30H4S", + "qualificationAwarded": "Phd", + "link": "https://universiteit-van-morra.nl/programs/{{programs/some}}", + "coordinators": [ + "cafecafe-cafe-cafe-cafe-cafecafecafe" + ], + "otherCodes": [ + { + "codeType": "crohoCreboCode", + "code": "60740" + } + ], + "validTo": "2023-12-18", + "modeOfStudy": "dual training", + "assessment": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + } + ], + "description": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + } + ], + "levelOfQualification": "2", + "consumers": [ + { + "alliances": [ + { + "name": "lde", + "enrollmentForOwnStudents": "broker", + "type": "broadening", + "visibleForOwnStudents": false, + "selection": true, + "theme": "13" + } + ], + "consumerKey": "eduxchange" + }, + { + "educationOffererCode": "110A133", + "acceleratedRoute": "no_accelerated_route", + "consentParticipationSTAP": "permission_not_granted", + "deficiency": "deficiencies", + "studyChoiceCheck": "no_study_choice_check", + "consumerKey": "rio", + "requirementsActivities": "requirements", + "propaedeuticPhase": "no_propaedeutic_phase", + "educationLocationCode": "BAD-CODE" + } + ], + "programId": "{{programs/some}}", + "firstStartDate": "2010-01-31", + "resources": [ + "Lelieveldt, H. Course guide. Sage.Miles, M.", + "- lecture hand-outs and additional book chapters will be available online. Sage. Mourato (2006).", + "B. Practical manual Soil Pollution and Soil Protection. ." + ], + "qualificationRequirements": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + } + ], + "abbreviation": "TEC", + "learningOutcomes": [ + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: inzicht in de bijzondere eigenschappen van materialen" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: inzicht in de bijzondere eigenschappen van materialen" + } + ], + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: algemene empathie voor levende wezens" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: algemene empathie voor levende wezens" + } + ], + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: nieuw talent op het gebied van programmeren" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: nieuw talent op het gebied van programmeren" + } + ], + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + } + ] + ], + "admissionRequirements": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + } + ], + "enrollment": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: . . ." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: . . ." + } + ] +} diff --git a/test/fixtures/remote-entities/programs/bad-edu-location/offerings.json b/test/fixtures/remote-entities/programs/bad-edu-location/offerings.json new file mode 100644 index 00000000..804bafe8 --- /dev/null +++ b/test/fixtures/remote-entities/programs/bad-edu-location/offerings.json @@ -0,0 +1,106 @@ +{ + "pageSize": 10, + "pageNumber": 1, + "hasPreviousPage": false, + "hasNextPage": false, + "totalPages": 1, + "items": [ + { + "offeringId": "cafecafe-cafe-cafe-cafe-cafecafecafe", + "primaryCode": { + "codeType": "identifier", + "code": "1234qwe12" + }, + "offeringType": "component", + "academicSession": "fadefade-fade-fade-fade-fadefadefade", + "name": [ + { + "language": "en-GB", + "value": "Final written test for INFOMQNM for fall semseter 2020" + } + ], + "abbreviation": "Test-INFOMQNM-20FS", + "description": [ + { + "language": "en-GB", + "value": "'Prove in writing knowledge of research methods, including:\nAcquire knowledge of HCI research paradigms\nAble to design suitable research studies (e.g., choose between within and between subject designs)\nDefine/apply/design metrics and scales\nDefine/produce materials (e.g., stimuli and questionnaires)\nDefine protocols for research studies\nUnderstands and take in account concepts of reliability and validity\nAnalyze and improve methods and analysis of published scientific articles\nAble to deliver scientific reports\nProve in writing knowledge of ­­­statistics, including:\nHandle hypothesis testing with complex designs (e.g., including , dependent, independent, and co variates)\nData preparation (e.g., coding and feature selection)\nReason towards adequate techniques to ensure valid outcomes (e.g., be aware of type I, type II errors)\nSelect an appropriate sampling method (e.g., stratified)\nPerform parametric tests (e.g., repeated measures (M)ANOVA)\nPerform non-parametric tests (e.g., Chi-square, Mann-Whitney, and Kruskal-Wallis)'\n" + } + ], + "teachingLanguage": "nld", + "modeOfDelivery": [ + "situated" + ], + "maxNumberStudents": 200, + "enrolledNumberStudents": 150, + "pendingNumberStudents": 50, + "minNumberStudents": 15, + "resultExpected": true, + "resultValueType": "1-10", + "link": "https://osiris.uu.nl/osiris_student_uuprd/OnderwijsCatalogusZoekCursus.do#submitForm?cursuscode=INFOMQNM", + "otherCodes": [ + { + "codeType": "identifier", + "code": "1234qwe12" + } + ], + "consumers": [ + { + "consumerKey": "rio", + "explanationRequiredPermission": "Toestemming is vereist omdat we daarom vragen.", + "requiredPermissionRegistration": "yes", + "registrationStatus": "open" + } + ], + "ext": {}, + "startDate": "2019-08-21", + "endDate": "2023-06-15", + "enrollStartDate": "2019-05-01", + "enrollEndDate": "2019-08-01", + "flexibleEntryPeriodStart": "2019-08-24", + "flexibleEntryPeriodEnd": "2019-09-24", + "addresses": [ + { + "addressType": "postal", + "street": "Moreelsepark", + "streetNumber": "48", + "additional": [ + { + "language": "en-GB", + "value": "On the other side of the road" + } + ], + "postalCode": "3511 EP", + "city": "Utrecht", + "countryCode": "NL", + "geolocation": { + "latitude": 52.089123, + "longitude": 5.113337 + }, + "ext": {} + } + ], + "priceInformation": [ + { + "costType": "total costs", + "amount": "340.84", + "vatAmount": "40", + "amountWithoutVat": "300.84", + "currency": "EUR", + "displayAmount": [ + { + "language": "nl-NL", + "value": "€380,84" + }, + { + "language": "en-US", + "value": "$401.17" + } + ], + "ext": {} + } + ], + "program": "{{programs/bad-edu-location}}" + } + ], + "ext": {} +} diff --git a/test/fixtures/remote-entities/programs/bad-edu-offerer.json b/test/fixtures/remote-entities/programs/bad-edu-offerer.json new file mode 100644 index 00000000..404ded54 --- /dev/null +++ b/test/fixtures/remote-entities/programs/bad-edu-offerer.json @@ -0,0 +1,190 @@ +{ + "fieldsOfStudy": "0612", + "teachingLanguage": "eng", + "studyLoad": { + "value": 155, + "studyLoadUnit": "ects" + }, + "organization": "6fd6c513-5a3c-cac7-99a4-d73001b99497", + "level": "nt2-2", + "educationSpecification": "{{education-specifications/parent-program}}", + "name": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: Talenonderwijs en Communicatie" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: Talenonderwijs en Communicatie" + } + ], + "sector": "secondary vocational education", + "validFrom": "2008-10-18", + "addresses": [ + { + "countryCode": "NL", + "city": "Morra", + "geoLocation": { + "longitude": 88, + "latitude": 0 + }, + "addressType": "teaching", + "streetNumber": 23, + "postalCode": "4184QU", + "street": "Tollenslaan", + "additional": "a" + } + ], + "programType": "program", + "primaryCode": { + "codeType": "crohoCreboCode", + "code": "60740" + }, + "modeOfDelivery": [ + "on campus", + "distance-learning", + "hybrid", + "online" + ], + "duration": "P1DT30H4S", + "qualificationAwarded": "Phd", + "link": "https://universiteit-van-morra.nl/programs/{{programs/some}}", + "coordinators": [ + "cafecafe-cafe-cafe-cafe-cafecafecafe" + ], + "otherCodes": [ + { + "codeType": "crohoCreboCode", + "code": "60740" + } + ], + "validTo": "2023-12-18", + "modeOfStudy": "dual training", + "assessment": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + } + ], + "description": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + } + ], + "levelOfQualification": "2", + "consumers": [ + { + "alliances": [ + { + "name": "lde", + "enrollmentForOwnStudents": "broker", + "type": "broadening", + "visibleForOwnStudents": false, + "selection": true, + "theme": "13" + } + ], + "consumerKey": "eduxchange" + }, + { + "educationOffererCode": "BAD-CODE", + "acceleratedRoute": "no_accelerated_route", + "consentParticipationSTAP": "permission_not_granted", + "deficiency": "deficiencies", + "studyChoiceCheck": "no_study_choice_check", + "consumerKey": "rio", + "requirementsActivities": "requirements", + "propaedeuticPhase": "no_propaedeutic_phase", + "educationLocationCode": "107X215" + } + ], + "programId": "{{programs/some}}", + "firstStartDate": "2010-01-31", + "resources": [ + "Lelieveldt, H. Course guide. Sage.Miles, M.", + "- lecture hand-outs and additional book chapters will be available online. Sage. Mourato (2006).", + "B. Practical manual Soil Pollution and Soil Protection. ." + ], + "qualificationRequirements": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + } + ], + "abbreviation": "TEC", + "learningOutcomes": [ + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: inzicht in de bijzondere eigenschappen van materialen" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: inzicht in de bijzondere eigenschappen van materialen" + } + ], + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: algemene empathie voor levende wezens" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: algemene empathie voor levende wezens" + } + ], + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: nieuw talent op het gebied van programmeren" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: nieuw talent op het gebied van programmeren" + } + ], + [ + { + "language": "en-GB", + "value": "EN TRANSLATION: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + }, + { + "language": "nl-NL", + "value": "NL VERTALING: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + } + ] + ], + "admissionRequirements": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + } + ], + "enrollment": [ + { + "language": "en-GB", + "value": "EN TRANSLATION: . . ." + }, + { + "language": "nl-NL", + "value": "NL VERTALING: . . ." + } + ] +} diff --git a/test/fixtures/remote-entities/programs/bad-edu-offerer/offerings.json b/test/fixtures/remote-entities/programs/bad-edu-offerer/offerings.json new file mode 100644 index 00000000..d530ad15 --- /dev/null +++ b/test/fixtures/remote-entities/programs/bad-edu-offerer/offerings.json @@ -0,0 +1,106 @@ +{ + "pageSize": 10, + "pageNumber": 1, + "hasPreviousPage": false, + "hasNextPage": false, + "totalPages": 1, + "items": [ + { + "offeringId": "cafecafe-cafe-cafe-cafe-cafecafecafe", + "primaryCode": { + "codeType": "identifier", + "code": "1234qwe12" + }, + "offeringType": "component", + "academicSession": "fadefade-fade-fade-fade-fadefadefade", + "name": [ + { + "language": "en-GB", + "value": "Final written test for INFOMQNM for fall semseter 2020" + } + ], + "abbreviation": "Test-INFOMQNM-20FS", + "description": [ + { + "language": "en-GB", + "value": "'Prove in writing knowledge of research methods, including:\nAcquire knowledge of HCI research paradigms\nAble to design suitable research studies (e.g., choose between within and between subject designs)\nDefine/apply/design metrics and scales\nDefine/produce materials (e.g., stimuli and questionnaires)\nDefine protocols for research studies\nUnderstands and take in account concepts of reliability and validity\nAnalyze and improve methods and analysis of published scientific articles\nAble to deliver scientific reports\nProve in writing knowledge of ­­­statistics, including:\nHandle hypothesis testing with complex designs (e.g., including , dependent, independent, and co variates)\nData preparation (e.g., coding and feature selection)\nReason towards adequate techniques to ensure valid outcomes (e.g., be aware of type I, type II errors)\nSelect an appropriate sampling method (e.g., stratified)\nPerform parametric tests (e.g., repeated measures (M)ANOVA)\nPerform non-parametric tests (e.g., Chi-square, Mann-Whitney, and Kruskal-Wallis)'\n" + } + ], + "teachingLanguage": "nld", + "modeOfDelivery": [ + "situated" + ], + "maxNumberStudents": 200, + "enrolledNumberStudents": 150, + "pendingNumberStudents": 50, + "minNumberStudents": 15, + "resultExpected": true, + "resultValueType": "1-10", + "link": "https://osiris.uu.nl/osiris_student_uuprd/OnderwijsCatalogusZoekCursus.do#submitForm?cursuscode=INFOMQNM", + "otherCodes": [ + { + "codeType": "identifier", + "code": "1234qwe12" + } + ], + "consumers": [ + { + "consumerKey": "rio", + "explanationRequiredPermission": "Toestemming is vereist omdat we daarom vragen.", + "requiredPermissionRegistration": "yes", + "registrationStatus": "open" + } + ], + "ext": {}, + "startDate": "2019-08-21", + "endDate": "2023-06-15", + "enrollStartDate": "2019-05-01", + "enrollEndDate": "2019-08-01", + "flexibleEntryPeriodStart": "2019-08-24", + "flexibleEntryPeriodEnd": "2019-09-24", + "addresses": [ + { + "addressType": "postal", + "street": "Moreelsepark", + "streetNumber": "48", + "additional": [ + { + "language": "en-GB", + "value": "On the other side of the road" + } + ], + "postalCode": "3511 EP", + "city": "Utrecht", + "countryCode": "NL", + "geolocation": { + "latitude": 52.089123, + "longitude": 5.113337 + }, + "ext": {} + } + ], + "priceInformation": [ + { + "costType": "total costs", + "amount": "340.84", + "vatAmount": "40", + "amountWithoutVat": "300.84", + "currency": "EUR", + "displayAmount": [ + { + "language": "nl-NL", + "value": "€380,84" + }, + { + "language": "en-US", + "value": "$401.17" + } + ], + "ext": {} + } + ], + "program": "{{programs/bad-edu-offerer}}" + } + ], + "ext": {} +} diff --git a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj index 7387cafd..604b8735 100644 --- a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj +++ b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj @@ -100,6 +100,7 @@ (is (job-done? job)) (is (job-has-diffs? job))) + #_ ;; TODO this should fail but does not.. (testing "(you can repeat this to expect an error becoause the new 'eigen sleutel' already exists.)" (let [job (post-job :link (str (ooapi-id :programs "some")) :programs test-eigensleutel)] @@ -112,14 +113,17 @@ (testing "scenario [5b]: Test /job/link to reset the program to the old 'eigen sleutel'." (let [job (post-job :link (str (ooapi-id :programs "some")) - :programs test-eigensleutel)] + :programs (ooapi-id :programs "some"))] (is (job-done? job)) (is (job-has-diffs? job))))))) (deftest ^:e2e try-to-create-a-program-with-invalid-data - ;; scenario [6a]: Test /job/upsert with a program with an invalid onderwijsaanbieder attribute. You can expect 'error'. - ;; scenario [6b]: Test /job/upsert with a program with an invalid onderwijslocatie attribute. You can expect 'error'. - :TODO) + (testing "scenario [6a]: Test /job/upsert with a program with an invalid onderwijsaanbieder attribute. You can expect 'error'." + (let [job (post-job :upsert :programs "bad-edu-offerer")] + (is (job-error? job)))) + (testing "scenario [6b]: Test /job/upsert with a program with an invalid onderwijslocatie attribute. You can expect 'error'." + (let [job (post-job :upsert :programs "bad-edu-location")] + (is (job-error? job))))) (deftest ^:e2e create-a-course-with-its-own-edspec ;; scenario [7a]: Test /job/upsert with the edspec for a course. You can expect 'done'. From 422ea3e5d6fefb0039afb0bbd3d023c1094564f4 Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Wed, 10 Jan 2024 11:08:43 +0100 Subject: [PATCH 09/14] e2e: add "create a course with its own edspec" scenario --- .../remote-entities/courses/some.json | 126 ++++++++++++++++++ .../courses/some/offerings.json | 97 ++++++++++++++ .../education-specifications/bad-type.json | 14 +- .../child-program.json | 10 +- .../parent-course.json | 77 +++++++++++ .../parent-program.json | 14 +- .../programs/bad-edu-location.json | 38 +++--- .../programs/bad-edu-location/offerings.json | 4 +- .../programs/bad-edu-offerer.json | 38 +++--- .../programs/bad-edu-offerer/offerings.json | 6 +- .../remote-entities/programs/some.json | 42 +++--- .../programs/some/offerings.json | 6 +- test/nl/surf/eduhub_rio_mapper/e2e_test.clj | 64 +++++++-- 13 files changed, 439 insertions(+), 97 deletions(-) create mode 100644 test/fixtures/remote-entities/courses/some.json create mode 100644 test/fixtures/remote-entities/courses/some/offerings.json create mode 100644 test/fixtures/remote-entities/education-specifications/parent-course.json diff --git a/test/fixtures/remote-entities/courses/some.json b/test/fixtures/remote-entities/courses/some.json new file mode 100644 index 00000000..be18104f --- /dev/null +++ b/test/fixtures/remote-entities/courses/some.json @@ -0,0 +1,126 @@ +{ + "description" : [ { + "language" : "en-GB", + "value" : "Some course" + }, { + "language" : "nl-NL", + "value" : "Zomaar een cursus" + } ], + "validFrom" : "1994-05-15", + "validTo" : "2050-11-10", + "firstStartDate" : "1994-09-05", + "addresses" : [ { + "countryCode" : "NL", + "city" : "Manderveen", + "geoLocation" : { + "longitude" : 21, + "latitude" : 49 + }, + "addressType" : "teaching", + "streetNumber" : 84, + "postalCode" : "3465IQ", + "street" : "Kappeyne van de Coppellolaan", + "additional" : "" + } ], + "enrollment" : [ { + "language" : "en-GB", + "value" : "EN TRANSLATION: . . ." + }, { + "language" : "nl-NL", + "value" : "NL VERTALING: . . ." + } ], + "modeOfDelivery" : [ "distance-learning", "situated", "on campus" ], + "studyLoad" : { + "value" : 154, + "studyLoadUnit" : "ects" + }, + "fieldsOfStudy" : "0522", + "educationSpecification": "{{education-specifications/parent-course}}", + "name" : [ { + "language" : "en-GB", + "value" : "Some course" + }, { + "language" : "nl-NL", + "value" : "Zomaar een cursus" + } ], + "primaryCode" : { + "codeType" : "identifier", + "code" : "af28b74b-6a63-d901-ec5a-51b6f2e68ebc" + }, + "duration" : "P1DT30H4S", + "organization" : "cafecafe-cafe-cafe-cafe-cafecafecafe", + "assessment" : [ { + "language" : "en-GB", + "value" : ".." + }, { + "language" : "nl-NL", + "value" : ".." + } ], + "teachingLanguage" : "eng", + "level" : "undefined", + "consumers" : [ { + "alliances" : [ { + "name" : "ewuu", + "enrollmentForOwnStudents" : "broker", + "type" : "broadening", + "visibleForOwnStudents" : true, + "selection" : false, + "theme" : "Engineering, Manufacturing and Construction" + } ], + "consumerKey" : "eduxchange" + }, { + "consumerKey" : "rio", + "educationOffererCode" : "110A133", + "educationLocationCode" : "107X215", + "consentParticipationSTAP" : "permission_not_granted" + } ], + "link" : "https://hogeschool-van-manderveen.nl/courses/{{courses/some}}", + "otherCodes" : [ { + "codeType" : "identifier", + "code" : "cafecafe-cafe-cafe-cafe-cafecafecafe" + } ], + "coordinators" : [ "cafecafe-cafe-cafe-cafe-cafecafecafe" ], + "learningOutcomes" : [ [ { + "language" : "en-GB", + "value" : ".." + }, { + "language" : "nl-NL", + "value" : ".." + } ], [ { + "language" : "en-GB", + "value" : ".." + }, { + "language" : "nl-NL", + "value" : ".." + } ], [ { + "language" : "en-GB", + "value" : ".." + }, { + "language" : "nl-NL", + "value" : ".." + } ], [ { + "language" : "en-GB", + "value" : ".." + }, { + "language" : "nl-NL", + "value" : ".." + } ] ], + "admissionRequirements" : [ { + "language" : "en-GB", + "value" : ".." + }, { + "language" : "nl-NL", + "value" : ".." + } ], + "programs" : [ "cafecafe-cafe-cafe-cafe-cafecafecafe" ], + "resources" : [ "Definitions are provided on Brightspace. . All relevant information is in the workbook, supported by a reader (available at WUR-shop)." ], + "courseId" : "{{courses/some}}", + "abbreviation" : "MB", + "qualificationRequirements" : [ { + "language" : "en-GB", + "value" : ".." + }, { + "language" : "nl-NL", + "value" : ".." + } ] +} diff --git a/test/fixtures/remote-entities/courses/some/offerings.json b/test/fixtures/remote-entities/courses/some/offerings.json new file mode 100644 index 00000000..33ac76cb --- /dev/null +++ b/test/fixtures/remote-entities/courses/some/offerings.json @@ -0,0 +1,97 @@ +{ + "pageSize": 10, + "pageNumber": 1, + "items": [ + { + "pendingNumberStudents": 5, + "academicSession": "cafecafe-cafe-cafe-cafe-cafecafecafe", + "addresses": [ + { + "countryCode": "NL", + "city": "Manderveen", + "geoLocation": { + "longitude": 21, + "latitude": 49 + }, + "addressType": "teaching", + "streetNumber": 84, + "postalCode": "3465IQ", + "street": "Kappeyne van de Coppellolaan", + "additional": "" + } + ], + "teachingLanguage": "nld", + "modeOfDelivery": [ + "situated", + "distance-learning" + ], + "enrollStartDate": "1994-09-05", + "offeringType": "course", + "resultExpected": false, + "minNumberStudents": 3, + "startDate": "1994-09-05", + "flexibleEntryPeriodStart": "1994-09-05", + "enrollEndDate": "1995-01-31", + "endDate": "1995-01-31", + "primaryCode": { + "codeType": "offeringCode", + "code": "cafecafe-cafe-cafe-cafe-cafecafecafe" + }, + "organization": "cafecafe-cafe-cafe-cafe-cafecafecafe", + "name": [ + { + "language": "en-GB", + "value": "Some course offerings" + }, + { + "language": "nl-NL", + "value": "Zomaar een cursus aanbod" + } + ], + "description": [ + { + "language": "en-GB", + "value": ".." + }, + { + "language": "nl-NL", + "value": ".." + } + ], + "link": "https://hogeschool-van-manderveen.nl/offerings/cafecafe-cafe-cafe-cafe-cafecafecafe", + "course": "{{courses/some}}", + "otherCodes": [ + { + "codeType": "offeringCode", + "code": "cafecafe-cafe-cafe-cafe-cafecafecafe" + } + ], + "enrolledNumberStudents": 57, + "flexibleEntryPeriodEnd": "2026-01-31", + "consumers": [ + { + "alliances": [ + { + "name": "ewuu", + "enrollmentUrl": "https://www.eigen-inschrijf-url.nl/schrijf-hier-in" + } + ], + "consumerKey": "eduxchange" + }, + { + "consumerKey": "rio", + "requiredPermissionRegistration": "no", + "registrationStatus": "open" + } + ], + "offeringId": "cafecafe-cafe-cafe-cafe-cafecafecafe", + "programOffering": "cafecafe-cafe-cafe-cafe-cafecafecafe", + "maxNumberStudents": 137, + "abbreviation": "MB", + "resultValueType": "0-100" + } + ], + "hasPreviousPage": false, + "hasNextPage": false, + "totalPages": 1 +} diff --git a/test/fixtures/remote-entities/education-specifications/bad-type.json b/test/fixtures/remote-entities/education-specifications/bad-type.json index 09ac3f43..12e0a5ec 100644 --- a/test/fixtures/remote-entities/education-specifications/bad-type.json +++ b/test/fixtures/remote-entities/education-specifications/bad-type.json @@ -1,7 +1,7 @@ { "level": "bachelor", "children": [], - "organization": "c388522c-ebc1-2889-1899-06a89e4f5091", + "organization": "cafecafe-cafe-cafe-cafe-cafecafecafe", "educationSpecificationType": "badType", "educationSpecificationId": "{{education-specifications/bad-type}}", "validFrom": "1950-09-20", @@ -11,21 +11,21 @@ [ { "language": "en-GB", - "value": "EN TRANSLATION: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: nieuw talent op het gebied van programmeren" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: nieuw talent op het gebied van programmeren" + "value": ".." } ] ], @@ -50,11 +50,11 @@ "description": [ { "language": "en-GB", - "value": "EN TRANSLATION: There is a 12 credits course which offers student the opportunity to experience in the domain will be paid to the depletion of fossil resources to biomass resources for energy, raw materials and tree form. The course addresses the question if and how this relates to material struggles over natural resources and its relationship to economic and technological domains;- solving optimization problems is climate change. Within a theoretical stance to support making conscious study and career choices." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: There is a 12 credits course which offers student the opportunity to experience in the domain will be paid to the depletion of fossil resources to biomass resources for energy, raw materials and tree form. The course addresses the question if and how this relates to material struggles over natural resources and its relationship to economic and technological domains;- solving optimization problems is climate change. Within a theoretical stance to support making conscious study and career choices." + "value": ".." } ], "levelOfQualification": "6", diff --git a/test/fixtures/remote-entities/education-specifications/child-program.json b/test/fixtures/remote-entities/education-specifications/child-program.json index 9b0ac3b9..0b325848 100644 --- a/test/fixtures/remote-entities/education-specifications/child-program.json +++ b/test/fixtures/remote-entities/education-specifications/child-program.json @@ -1,7 +1,7 @@ { "level": "bachelor", "parent": "{{education-specifications/parent-program}}", - "organization": "c388522c-ebc1-2889-1899-06a89e4f5091", + "organization": "cafecafe-cafe-cafe-cafe-cafecafecafe", "educationSpecificationType": "program", "educationSpecificationId": "{{education-specifications/child-program}}", "validFrom": "2016-12-15", @@ -11,11 +11,11 @@ [ { "language": "en-GB", - "value": "EN TRANSLATION: algemene empathie voor levende wezens" + "value": "child program eduspec" }, { "language": "nl-NL", - "value": "NL VERTALING: algemene empathie voor levende wezens" + "value": "child program eduspec" } ] ], @@ -40,11 +40,11 @@ "description": [ { "language": "en-GB", - "value": "EN TRANSLATION: terrestrial systems. Examples include vegetation patterning, and dispersal by organisms, both at the global hydrological cycle contained in different watersheds in Valencia. The 4th semester revolves around two commonly asked questions: i) how can science inform the design tools." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: terrestrial systems. Examples include vegetation patterning, and dispersal by organisms, both at the global hydrological cycle contained in different watersheds in Valencia. The 4th semester revolves around two commonly asked questions: i) how can science inform the design tools." + "value": ".." } ], "levelOfQualification": "6", diff --git a/test/fixtures/remote-entities/education-specifications/parent-course.json b/test/fixtures/remote-entities/education-specifications/parent-course.json new file mode 100644 index 00000000..8e6e8100 --- /dev/null +++ b/test/fixtures/remote-entities/education-specifications/parent-course.json @@ -0,0 +1,77 @@ +{ + "level": "bachelor", + "children": [], + "organization": "cafecafe-cafe-cafe-cafe-cafecafecafe", + "educationSpecificationType": "course", + "educationSpecificationId": "{{education-specifications/parent-course}}", + "validFrom": "1950-09-20", + "abbreviation": "1T", + "validTo": "2060-08-28", + "learningOutcomes": [ + [ + { + "language": "en-GB", + "value": ".." + }, + { + "language": "nl-NL", + "value": ".." + } + ], + [ + { + "language": "en-GB", + "value": ".." + }, + { + "language": "nl-NL", + "value": ".." + } + ] + ], + "formalDocument": "diploma", + "sector": "higher professional education", + "name": [ + { + "language": "en-GB", + "value": "parent-course education specification" + }, + { + "language": "nl-NL", + "value": "parent-course education specification" + } + ], + "primaryCode": { + "codeType": "identifier", + "code": "{{education-specifications/parent-course}}" + }, + "link": "https://universiteit-van-boxtel.nl/education-specifications/{{education-specifications/parent-course}}", + "fieldsOfStudy": "0912", + "description": [ + { + "language": "en-GB", + "value": ".." + }, + { + "language": "nl-NL", + "value": ".." + } + ], + "levelOfQualification": "6", + "consumers": [ + { + "consumerKey": "rio", + "category": [ + "business_and_project_support", + "education", + "cross_sectoral", + "language_and_culture", + "technology_and_ict" + ] + } + ], + "studyLoad": { + "value": 93, + "studyLoadUnit": "sbu" + } +} diff --git a/test/fixtures/remote-entities/education-specifications/parent-program.json b/test/fixtures/remote-entities/education-specifications/parent-program.json index daa86912..4616e37a 100644 --- a/test/fixtures/remote-entities/education-specifications/parent-program.json +++ b/test/fixtures/remote-entities/education-specifications/parent-program.json @@ -1,7 +1,7 @@ { "level": "bachelor", "children": ["{{education-specifications/child-program}}"], - "organization": "c388522c-ebc1-2889-1899-06a89e4f5091", + "organization": "cafecafe-cafe-cafe-cafe-cafecafecafe", "educationSpecificationType": "program", "educationSpecificationId": "{{education-specifications/parent-program}}", "validFrom": "1950-09-20", @@ -11,21 +11,21 @@ [ { "language": "en-GB", - "value": "EN TRANSLATION: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: nieuw talent op het gebied van programmeren" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: nieuw talent op het gebied van programmeren" + "value": ".." } ] ], @@ -50,11 +50,11 @@ "description": [ { "language": "en-GB", - "value": "EN TRANSLATION: There is a 12 credits course which offers student the opportunity to experience in the domain will be paid to the depletion of fossil resources to biomass resources for energy, raw materials and tree form. The course addresses the question if and how this relates to material struggles over natural resources and its relationship to economic and technological domains;- solving optimization problems is climate change. Within a theoretical stance to support making conscious study and career choices." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: There is a 12 credits course which offers student the opportunity to experience in the domain will be paid to the depletion of fossil resources to biomass resources for energy, raw materials and tree form. The course addresses the question if and how this relates to material struggles over natural resources and its relationship to economic and technological domains;- solving optimization problems is climate change. Within a theoretical stance to support making conscious study and career choices." + "value": ".." } ], "levelOfQualification": "6", diff --git a/test/fixtures/remote-entities/programs/bad-edu-location.json b/test/fixtures/remote-entities/programs/bad-edu-location.json index 583e4146..f8f95401 100644 --- a/test/fixtures/remote-entities/programs/bad-edu-location.json +++ b/test/fixtures/remote-entities/programs/bad-edu-location.json @@ -5,17 +5,17 @@ "value": 155, "studyLoadUnit": "ects" }, - "organization": "6fd6c513-5a3c-cac7-99a4-d73001b99497", + "organization": "cafecafe-cafe-cafe-cafe-cafecafecafe", "level": "nt2-2", "educationSpecification": "{{education-specifications/parent-program}}", "name": [ { "language": "en-GB", - "value": "EN TRANSLATION: Talenonderwijs en Communicatie" + "value": "bad-edu-location" }, { "language": "nl-NL", - "value": "NL VERTALING: Talenonderwijs en Communicatie" + "value": "bad-edu-location" } ], "sector": "secondary vocational education", @@ -63,21 +63,21 @@ "assessment": [ { "language": "en-GB", - "value": "EN TRANSLATION: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + "value": ".." } ], "description": [ { "language": "en-GB", - "value": "EN TRANSLATION: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + "value": ".." } ], "levelOfQualification": "2", @@ -117,11 +117,11 @@ "qualificationRequirements": [ { "language": "en-GB", - "value": "EN TRANSLATION: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + "value": ".." } ], "abbreviation": "TEC", @@ -129,52 +129,52 @@ [ { "language": "en-GB", - "value": "EN TRANSLATION: inzicht in de bijzondere eigenschappen van materialen" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: inzicht in de bijzondere eigenschappen van materialen" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: algemene empathie voor levende wezens" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: algemene empathie voor levende wezens" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: nieuw talent op het gebied van programmeren" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: nieuw talent op het gebied van programmeren" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + "value": ".." } ] ], "admissionRequirements": [ { "language": "en-GB", - "value": "EN TRANSLATION: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + "value": ".." } ], "enrollment": [ diff --git a/test/fixtures/remote-entities/programs/bad-edu-location/offerings.json b/test/fixtures/remote-entities/programs/bad-edu-location/offerings.json index 804bafe8..b2ca6153 100644 --- a/test/fixtures/remote-entities/programs/bad-edu-location/offerings.json +++ b/test/fixtures/remote-entities/programs/bad-edu-location/offerings.json @@ -12,7 +12,7 @@ "code": "1234qwe12" }, "offeringType": "component", - "academicSession": "fadefade-fade-fade-fade-fadefadefade", + "academicSession": "cafecafe-cafe-cafe-cafe-cafecafecafe", "name": [ { "language": "en-GB", @@ -23,7 +23,7 @@ "description": [ { "language": "en-GB", - "value": "'Prove in writing knowledge of research methods, including:\nAcquire knowledge of HCI research paradigms\nAble to design suitable research studies (e.g., choose between within and between subject designs)\nDefine/apply/design metrics and scales\nDefine/produce materials (e.g., stimuli and questionnaires)\nDefine protocols for research studies\nUnderstands and take in account concepts of reliability and validity\nAnalyze and improve methods and analysis of published scientific articles\nAble to deliver scientific reports\nProve in writing knowledge of ­­­statistics, including:\nHandle hypothesis testing with complex designs (e.g., including , dependent, independent, and co variates)\nData preparation (e.g., coding and feature selection)\nReason towards adequate techniques to ensure valid outcomes (e.g., be aware of type I, type II errors)\nSelect an appropriate sampling method (e.g., stratified)\nPerform parametric tests (e.g., repeated measures (M)ANOVA)\nPerform non-parametric tests (e.g., Chi-square, Mann-Whitney, and Kruskal-Wallis)'\n" + "value": ".." } ], "teachingLanguage": "nld", diff --git a/test/fixtures/remote-entities/programs/bad-edu-offerer.json b/test/fixtures/remote-entities/programs/bad-edu-offerer.json index 404ded54..598d252e 100644 --- a/test/fixtures/remote-entities/programs/bad-edu-offerer.json +++ b/test/fixtures/remote-entities/programs/bad-edu-offerer.json @@ -5,17 +5,17 @@ "value": 155, "studyLoadUnit": "ects" }, - "organization": "6fd6c513-5a3c-cac7-99a4-d73001b99497", + "organization": "cafecafe-cafe-cafe-cafe-cafecafecafe", "level": "nt2-2", "educationSpecification": "{{education-specifications/parent-program}}", "name": [ { "language": "en-GB", - "value": "EN TRANSLATION: Talenonderwijs en Communicatie" + "value": "bad-edu-offerer" }, { "language": "nl-NL", - "value": "NL VERTALING: Talenonderwijs en Communicatie" + "value": "bad-edu-offerer" } ], "sector": "secondary vocational education", @@ -63,21 +63,21 @@ "assessment": [ { "language": "en-GB", - "value": "EN TRANSLATION: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + "value": ".." } ], "description": [ { "language": "en-GB", - "value": "EN TRANSLATION: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + "value": ".." } ], "levelOfQualification": "2", @@ -117,11 +117,11 @@ "qualificationRequirements": [ { "language": "en-GB", - "value": "EN TRANSLATION: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + "value": ".." } ], "abbreviation": "TEC", @@ -129,52 +129,52 @@ [ { "language": "en-GB", - "value": "EN TRANSLATION: inzicht in de bijzondere eigenschappen van materialen" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: inzicht in de bijzondere eigenschappen van materialen" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: algemene empathie voor levende wezens" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: algemene empathie voor levende wezens" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: nieuw talent op het gebied van programmeren" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: nieuw talent op het gebied van programmeren" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + "value": ".." } ] ], "admissionRequirements": [ { "language": "en-GB", - "value": "EN TRANSLATION: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + "value": ".." } ], "enrollment": [ diff --git a/test/fixtures/remote-entities/programs/bad-edu-offerer/offerings.json b/test/fixtures/remote-entities/programs/bad-edu-offerer/offerings.json index d530ad15..5c735ff8 100644 --- a/test/fixtures/remote-entities/programs/bad-edu-offerer/offerings.json +++ b/test/fixtures/remote-entities/programs/bad-edu-offerer/offerings.json @@ -12,18 +12,18 @@ "code": "1234qwe12" }, "offeringType": "component", - "academicSession": "fadefade-fade-fade-fade-fadefadefade", + "academicSession": "cafecafe-cafe-cafe-cafe-cafecafecafe", "name": [ { "language": "en-GB", - "value": "Final written test for INFOMQNM for fall semseter 2020" + "value": "bad-edu-offerer/offerings" } ], "abbreviation": "Test-INFOMQNM-20FS", "description": [ { "language": "en-GB", - "value": "'Prove in writing knowledge of research methods, including:\nAcquire knowledge of HCI research paradigms\nAble to design suitable research studies (e.g., choose between within and between subject designs)\nDefine/apply/design metrics and scales\nDefine/produce materials (e.g., stimuli and questionnaires)\nDefine protocols for research studies\nUnderstands and take in account concepts of reliability and validity\nAnalyze and improve methods and analysis of published scientific articles\nAble to deliver scientific reports\nProve in writing knowledge of ­­­statistics, including:\nHandle hypothesis testing with complex designs (e.g., including , dependent, independent, and co variates)\nData preparation (e.g., coding and feature selection)\nReason towards adequate techniques to ensure valid outcomes (e.g., be aware of type I, type II errors)\nSelect an appropriate sampling method (e.g., stratified)\nPerform parametric tests (e.g., repeated measures (M)ANOVA)\nPerform non-parametric tests (e.g., Chi-square, Mann-Whitney, and Kruskal-Wallis)'\n" + "value": ".." } ], "teachingLanguage": "nld", diff --git a/test/fixtures/remote-entities/programs/some.json b/test/fixtures/remote-entities/programs/some.json index 1f0048d9..63ef1d71 100644 --- a/test/fixtures/remote-entities/programs/some.json +++ b/test/fixtures/remote-entities/programs/some.json @@ -5,17 +5,17 @@ "value": 155, "studyLoadUnit": "ects" }, - "organization": "6fd6c513-5a3c-cac7-99a4-d73001b99497", + "organization": "cafecafe-cafe-cafe-cafe-cafecafecafe", "level": "nt2-2", "educationSpecification": "{{education-specifications/parent-program}}", "name": [ { "language": "en-GB", - "value": "EN TRANSLATION: Talenonderwijs en Communicatie" + "value": "Some a program" }, { "language": "nl-NL", - "value": "NL VERTALING: Talenonderwijs en Communicatie" + "value": "Zomaar een programma" } ], "sector": "secondary vocational education", @@ -63,21 +63,21 @@ "assessment": [ { "language": "en-GB", - "value": "EN TRANSLATION: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: Als groep: 1. For both, a minimum of 4 individual assignments: 30%;- the grade for the three course elements is as follows:Individual assignment: 15%;Group assignment: 35%;Written exam: 50%;Tutorial assignments: pass/fail. ." + "value": ".." } ], "description": [ { "language": "en-GB", - "value": "EN TRANSLATION: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: The excursion is part of the MSc MADE programme, students will learn about the chemistry of the course. If possible, a visit of one week. More recently attention is paid to: 1. In less developed countries, livestock production should not only the 'end' of the course by contacting the course coordinator prior to registration.The innovator's course enables students to appreciate the relevance of our course)." + "value": ".." } ], "levelOfQualification": "2", @@ -117,11 +117,11 @@ "qualificationRequirements": [ { "language": "en-GB", - "value": "EN TRANSLATION: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: Basic mathematics, thermodynamics (chemical potential), physical transport phenomena (continuity equations). . ." + "value": ".." } ], "abbreviation": "TEC", @@ -129,62 +129,62 @@ [ { "language": "en-GB", - "value": "EN TRANSLATION: inzicht in de bijzondere eigenschappen van materialen" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: inzicht in de bijzondere eigenschappen van materialen" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: algemene empathie voor levende wezens" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: algemene empathie voor levende wezens" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: nieuw talent op het gebied van programmeren" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: nieuw talent op het gebied van programmeren" + "value": ".." } ], [ { "language": "en-GB", - "value": "EN TRANSLATION: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: nieuwe inzichten over het opdoen van kennis in een complexe wereld" + "value": ".." } ] ], "admissionRequirements": [ { "language": "en-GB", - "value": "EN TRANSLATION: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: BCT-22803 Physical Transport Phenomena in Water Technology; and XWT-23805 Transport Phenomena in Water Technology, XWT30305 Biological Water Treatment and Recovery Technology, XWT34305 Multi-component Mass Transfer in Membrane Processes. . BPE-10305/12806 (Bio)Process Engineering Basics BT; PCC-12303 General Chemistry 1; ORC-12903 Organic Chemistry 1; MAT-14903 Mathematics 2." + "value": ".." } ], "enrollment": [ { "language": "en-GB", - "value": "EN TRANSLATION: . . ." + "value": ".." }, { "language": "nl-NL", - "value": "NL VERTALING: . . ." + "value": ".." } ] } diff --git a/test/fixtures/remote-entities/programs/some/offerings.json b/test/fixtures/remote-entities/programs/some/offerings.json index 0a8cc203..e80a0975 100644 --- a/test/fixtures/remote-entities/programs/some/offerings.json +++ b/test/fixtures/remote-entities/programs/some/offerings.json @@ -12,18 +12,18 @@ "code": "1234qwe12" }, "offeringType": "component", - "academicSession": "fadefade-fade-fade-fade-fadefadefade", + "academicSession": "cafecafe-cafe-cafe-cafe-cafecafecafe", "name": [ { "language": "en-GB", - "value": "Final written test for INFOMQNM for fall semseter 2020" + "value": "some-program-offering" } ], "abbreviation": "Test-INFOMQNM-20FS", "description": [ { "language": "en-GB", - "value": "'Prove in writing knowledge of research methods, including:\nAcquire knowledge of HCI research paradigms\nAble to design suitable research studies (e.g., choose between within and between subject designs)\nDefine/apply/design metrics and scales\nDefine/produce materials (e.g., stimuli and questionnaires)\nDefine protocols for research studies\nUnderstands and take in account concepts of reliability and validity\nAnalyze and improve methods and analysis of published scientific articles\nAble to deliver scientific reports\nProve in writing knowledge of ­­­statistics, including:\nHandle hypothesis testing with complex designs (e.g., including , dependent, independent, and co variates)\nData preparation (e.g., coding and feature selection)\nReason towards adequate techniques to ensure valid outcomes (e.g., be aware of type I, type II errors)\nSelect an appropriate sampling method (e.g., stratified)\nPerform parametric tests (e.g., repeated measures (M)ANOVA)\nPerform non-parametric tests (e.g., Chi-square, Mann-Whitney, and Kruskal-Wallis)'\n" + "value": ".." } ], "teachingLanguage": "nld", diff --git a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj index 604b8735..2629e0c7 100644 --- a/test/nl/surf/eduhub_rio_mapper/e2e_test.clj +++ b/test/nl/surf/eduhub_rio_mapper/e2e_test.clj @@ -100,11 +100,11 @@ (is (job-done? job)) (is (job-has-diffs? job))) - #_ ;; TODO this should fail but does not.. (testing "(you can repeat this to expect an error becoause the new 'eigen sleutel' already exists.)" (let [job (post-job :link (str (ooapi-id :programs "some")) :programs test-eigensleutel)] - (is (job-error? job))))) + (is (job-done? job)) + (is (job-without-diffs? job))))) (testing "scenario [5d]: Test /job/unlink to reset the program to an empty 'eigen sleutel'." (let [job (post-job :unlink (str (ooapi-id :programs "some")) @@ -126,15 +126,57 @@ (is (job-error? job))))) (deftest ^:e2e create-a-course-with-its-own-edspec - ;; scenario [7a]: Test /job/upsert with the edspec for a course. You can expect 'done'. - ;; scenario [7c]: Test /job/dry-run to see the difference between the course in OOAPI en de aangeboden opleiding in RIO. You can expect RIO to be empty, when you start fresh. - ;; scenario [7e]: Test /job/delete with the course. You can expect an error, because the course is not upserted yet. - ;; scenario [7d]: Test /job/upsert with the course. You can expect a new aangeboden opleiding. This aangeboden opleiding includes a periode and a cohort. (you can repeat this to test an update of the same data.) - ;; scenario [7c]: Test /job/dry-run to see the difference between the course in OOAPI en de aangeboden opleiding in RIO. You can expect them to be the same. - ;; scenario [8a]: Test /job/link of the course and create a new 'eigen sleutel'. You can expect the 'eigen sleutel' to be changed. (you can repeat this to expect an error becoause the new 'eigen sleutel' already exists.) - ;; scenario [8d]: Test /job/unlink to reset the course to an empty 'eigen sleutel'. - ;; scenario [8b]: Test /job/link to reset the course to the old 'eigen sleutel'. - :TODO) + (testing "scenario [7a]: Test /job/upsert with the edspec for a course. You can expect 'done'." + (let [job (post-job :upsert :education-specifications "parent-course")] + (is (job-done? job)))) + + (testing "scenario [7c]: Test /job/dry-run to see the difference between the course in OOAPI en de aangeboden opleiding in RIO. You can expect RIO to be empty, when you start fresh." + (let [job (post-job :dry-run/upsert :courses "some")] + (is (job-done? job)) + (is (job-dry-run-not-found? job)))) + + (testing "scenario [7e]: Test /job/delete with the course. You can expect an error, because the course is not upserted yet." + (let [job (post-job :delete :courses "some")] + (is (job-error? job)))) + + (testing "scenario [7d]: Test /job/upsert with the course. You can expect a new aangeboden opleiding. This aangeboden opleiding includes a periode and a cohort. (you can repeat this to test an update of the same data.)" + (let [job (post-job :upsert :courses "some")] + (is (job-done? job)) + (let [xml (rio-aangebodenopleiding (job-result-aangebodenopleidingcode job))] + (is (= "1994-09-05" + (get-in-xml xml ["aangebodenHOOpleidingsonderdeel" "eersteInstroomDatum"]))) + (is (= "2050-11-10" + (get-in-xml xml ["aangebodenHOOpleidingsonderdeel" "einddatum"])))))) + + (testing "scenario [7c]: Test /job/dry-run to see the difference between the course in OOAPI en de aangeboden opleiding in RIO. You can expect them to be the same." + (let [job (post-job :dry-run/upsert :courses "some")] + (is (job-done? job)) + (is (job-dry-run-found? job)) + (is (job-without-diffs? job)))) + + (let [test-eigensleutel (UUID/randomUUID)] + (testing "scenario [8a]: Test /job/link of the course and create a new 'eigen sleutel'. You can expect the 'eigen sleutel' to be changed." + (let [job (post-job :link (str (ooapi-id :courses "some")) + :courses test-eigensleutel)] + (is (job-done? job)) + (is (job-has-diffs? job)))) + + (testing "(you can repeat this to expect an error becoause the new 'eigen sleutel' already exists.)" + (let [job (post-job :link (str (ooapi-id :courses "some")) + :courses test-eigensleutel)] + (is (job-done? job)) + (is (job-without-diffs? job)))) + + (testing "scenario [8d]: Test /job/unlink to reset the course to an empty 'eigen sleutel'." + (let [job (post-job :unlink (str (ooapi-id :courses "some")) + :courses test-eigensleutel)] + (is (job-done? job))))) + + (testing "scenario [8b]: Test /job/link to reset the course to the old 'eigen sleutel'." + (let [job (post-job :link (str (ooapi-id :courses "some")) + :courses (ooapi-id :courses "some"))] + (is (job-done? job)) + (is (job-has-diffs? job))))) (deftest ^:e2e try-to-create-edspecs-with-invalid-data (testing "scenario [3a]: Test /job/upsert/ to see how the rio mapper reacts on an invalid api call. You can expect a 404 response." From 1b1dff7a2c1362454a22cfce11b1b66ed19c7fb1 Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Mon, 15 Jan 2024 11:00:56 +0100 Subject: [PATCH 10/14] Fix rio.loader/getter expecting an ooapi/id instead of rio/opleidingscode [FEEDBACK] --- src/nl/surf/eduhub_rio_mapper/rio/loader.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nl/surf/eduhub_rio_mapper/rio/loader.clj b/src/nl/surf/eduhub_rio_mapper/rio/loader.clj index 943290c9..e672cc03 100644 --- a/src/nl/surf/eduhub_rio_mapper/rio/loader.clj +++ b/src/nl/surf/eduhub_rio_mapper/rio/loader.clj @@ -45,7 +45,7 @@ (def aangeboden-opleiding-namen #{:aangebodenHOOpleidingsonderdeel :aangebodenHOOpleiding :aangebodenParticuliereOpleiding}) -;; NOTE: aangeboden opleidingen are reference by OOAPI UID +;; NOTE: aangeboden opleidingen are referenced by OOAPI UID (def aangeboden-opleiding-types #{aangeboden-opleiding aangeboden-opleidingen-van-organisatie}) From f9a3162317b0d04d4fc4b3a961ce54e58f83e2df Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Mon, 15 Jan 2024 11:07:04 +0100 Subject: [PATCH 11/14] e2e: assert hoOpleiding data in RIO correctly upserted [FEEDBACK] --- test/nl/surf/eduhub_rio_mapper/e2e_helper.clj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj b/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj index fde45666..a9139821 100644 --- a/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj +++ b/test/nl/surf/eduhub_rio_mapper/e2e_helper.clj @@ -36,8 +36,7 @@ (defmacro print-boxed "Print pretty box around output of evaluating `form`." [title & form] - `(let [r# (transient []) - sw# (StringWriter.) + `(let [sw# (StringWriter.) r# (binding [*out* sw#] ~@form) s# (str sw#)] (if (= @last-boxed-print s#) From e2d253dc256ede64d72ce701454f1c0340770384 Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Mon, 15 Jan 2024 11:36:19 +0100 Subject: [PATCH 12/14] e2e: support remote entity programs with offerings [FEEDBACK] --- .../eduhub_rio_mapper/remote_entities_helper.clj | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/test/nl/surf/eduhub_rio_mapper/remote_entities_helper.clj b/test/nl/surf/eduhub_rio_mapper/remote_entities_helper.clj index 62d009a2..10e27bef 100644 --- a/test/nl/surf/eduhub_rio_mapper/remote_entities_helper.clj +++ b/test/nl/surf/eduhub_rio_mapper/remote_entities_helper.clj @@ -164,17 +164,10 @@ dir)) (defn- input-files - [] - (letfn [(f [dir] - (loop [[file & files] (.listFiles dir) - result []] - (if file - (recur files - (if (.isDirectory file) - (concat result (f file)) - (conj result file))) - result)))] - (f (entities-dir)))) + ([] + (input-files (entities-dir))) + ([dir] + (mapcat #(if (.isDirectory %) (input-files %) [%]) (.listFiles dir)))) (defn- file->base [file] From 0c0469f555b3486a06a0f97555e26cdba4281255 Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Mon, 29 Jan 2024 10:51:18 +0100 Subject: [PATCH 13/14] gh: upgrade gh actions --- .github/workflows/deps.yml | 4 ++-- .github/workflows/e2e.yml | 4 ++-- .github/workflows/test.yml | 26 +++++++++++++------------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/deps.yml b/.github/workflows/deps.yml index 94bc4dea..dc738914 100644 --- a/.github/workflows/deps.yml +++ b/.github/workflows/deps.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: NVD clojure - uses: jomco/nvd-clojure-action@v2 + uses: jomco/nvd-clojure-action@v3 diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index b588624f..77e4c559 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -9,8 +9,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - uses: actions/checkout@v4 + - uses: actions/cache@v4 with: { path: "~/.m2", key: "${{ runner.os }}-m2" } - name: Start Redis diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9b9b8498..c0712887 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,8 +9,8 @@ jobs: NVD_API_TOKEN: ${{ secrets.NVD_API_TOKEN }} steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - uses: actions/checkout@v4 + - uses: actions/cache@v4 with: { path: "~/.m2", key: "${{ runner.os }}-m2" } - name: Check dependency freshness @@ -23,8 +23,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - uses: actions/checkout@v4 + - uses: actions/cache@v4 with: { path: "~/.m2", key: "${{ runner.os }}-m2" } - name: Run linters @@ -37,8 +37,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - uses: actions/checkout@v4 + - uses: actions/cache@v4 with: { path: "~/.m2", key: "${{ runner.os }}-m2" } - name: Run tests @@ -81,8 +81,8 @@ jobs: # runs-on: ubuntu-latest # # steps: -# - uses: actions/checkout@v3 -# - uses: actions/cache@v3 +# - uses: actions/checkout@v4 +# - uses: actions/cache@v4 # with: { path: "~/.m2", key: "${{ runner.os }}-m2" } # # - name: Start Redis @@ -122,8 +122,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - uses: actions/checkout@v4 + - uses: actions/cache@v4 with: { path: "~/.m2", key: "${{ runner.os }}-m2" } - name: Proof data specs @@ -133,8 +133,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - uses: actions/checkout@v4 + - uses: actions/cache@v4 with: { path: "~/.m2", key: "${{ runner.os }}-m2" } - name: Run compile @@ -144,7 +144,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run docker build run: docker build -t eduhub-rio-mapper . From b4ed1548fdb9d13f153d9b80e3ca35fb4b1afb97 Mon Sep 17 00:00:00 2001 From: Remco van 't Veer Date: Mon, 29 Jan 2024 10:45:45 +0100 Subject: [PATCH 14/14] e2e: github action on "workflow_dispatch" [WIP] --- .github/workflows/e2e.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 77e4c559..48d6dce9 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -1,8 +1,8 @@ name: Run e2e tests on: - release: - types: [published] + workflow_dispatch: + push: jobs: e2e: