From fac0354b2d8ba22449cbe6720740a96aac3a7aba Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sun, 31 Jan 2021 17:02:10 +0100 Subject: [PATCH] :ambulance: Fix broken tests. --- backend/tests/app/tests/helpers.clj | 85 ++++++- .../tests/app/tests/test_services_media.clj | 131 ++++++----- .../tests/app/tests/test_services_profile.clj | 212 ++++++++---------- .../app/tests/test_services_projects.clj | 112 ++++----- .../tests/app/tests/test_services_viewer.clj | 12 +- 5 files changed, 320 insertions(+), 232 deletions(-) diff --git a/backend/tests/app/tests/helpers.clj b/backend/tests/app/tests/helpers.clj index 339646a87..e4381587d 100644 --- a/backend/tests/app/tests/helpers.clj +++ b/backend/tests/app/tests/helpers.clj @@ -9,8 +9,9 @@ (ns app.tests.helpers (:require - [expound.alpha :as expound] + [app.common.data :as d] [app.common.pages :as cp] + [app.common.spec :as us] [app.common.uuid :as uuid] [app.config :as cfg] [app.db :as db] @@ -27,6 +28,7 @@ [cuerdas.core :as str] [datoteka.core :as fs] [environ.core :refer [env]] + [expound.alpha :as expound] [integrant.core :as ig] [promesa.core :as p]) (:import org.postgresql.ds.PGSimpleDataSource)) @@ -44,7 +46,9 @@ :app.http.auth/google :app.http.auth/gitlab :app.worker/scheduler - :app.worker/worker)) + :app.worker/worker) + (d/deep-merge + {:app.storage/storage {:backend :tmp}})) _ (ig/load-namespaces config) system (-> (ig/prep config) (ig/init))] @@ -69,6 +73,24 @@ " CASCADE;")])))) (next)) +(defn clean-storage + [next] + (fs/delete (fs/path "/tmp/penpot")) + (next)) + +(defn serial + [& funcs] + (fn [next] + (loop [f (first funcs) + fs (rest funcs)] + (when f + (let [prm (promise)] + (f #(deliver prm true)) + (deref prm) + (recur (first fs) + (rest fs))))) + (next))) + (defn mk-uuid [prefix & args] (uuid/namespaced uuid/zero (apply str prefix args))) @@ -113,6 +135,61 @@ :is-shared is-shared :name (str "file" i)})) + +;; --- NEW HELPERS + +(defn create-profile* + ([i] (create-profile* *pool* i {})) + ([i params] (create-profile* *pool* i params)) + ([conn i params] + (let [params (merge {:id (mk-uuid "profile" i) + :fullname (str "Profile " i) + :email (str "profile" i ".test@nodomain.com") + :password "123123" + :demo? false} + params)] + (->> (#'profile/create-profile conn params) + (#'profile/create-profile-relations conn))))) + +(defn create-project* + ([i params] (create-project* *pool* i params)) + ([conn i {:keys [profile-id team-id] :as params}] + (us/assert uuid? profile-id) + (us/assert uuid? team-id) + (->> (merge {:id (mk-uuid "project" i) + :name (str "project" i)} + params) + (#'projects/create-project conn)))) + +(defn create-file* + ([i params] + (create-file* *pool* i params)) + ([conn i {:keys [profile-id project-id] :as params}] + (us/assert uuid? profile-id) + (us/assert uuid? project-id) + (#'files/create-file conn + (merge {:id (mk-uuid "file" i) + :name (str "file" i)} + params)))) + + +(defn create-team* + ([i params] (create-team* *pool* i params)) + ([conn i {:keys [profile-id] :as params}] + (us/assert uuid? profile-id) + (let [id (mk-uuid "team" i) + team (#'teams/create-team conn {:id id + :profile-id profile-id + :name (str "team" i)})] + (#'teams/create-team-profile conn + {:team-id id + :profile-id profile-id + :is-owner true + :is-admin true + :can-edit true}) + team))) + + (defn handle-error [^Throwable err] (if (instance? java.util.concurrent.ExecutionException err) @@ -215,3 +292,7 @@ (io/copy (io/file rsc) (io/file tmp)) tmp)) + +(defn sleep + [ms] + (Thread/sleep ms)) diff --git a/backend/tests/app/tests/test_services_media.clj b/backend/tests/app/tests/test_services_media.clj index a2681b478..0385e4719 100644 --- a/backend/tests/app/tests/test_services_media.clj +++ b/backend/tests/app/tests/test_services_media.clj @@ -9,70 +9,83 @@ (ns app.tests.test-services-media (:require - [clojure.test :as t] - [datoteka.core :as fs] [app.common.uuid :as uuid] [app.db :as db] - [app.tests.helpers :as th])) + [app.storage :as sto] + [app.tests.helpers :as th] + [clojure.test :as t] + [datoteka.core :as fs])) (t/use-fixtures :once th/state-init) (t/use-fixtures :each th/database-reset) -(t/deftest media-crud - (let [prof (th/create-profile th/*pool* 1) - team-id (:default-team-id prof) - proj (th/create-project th/*pool* (:id prof) team-id 1) - file (th/create-file th/*pool* (:id prof) (:id proj) false 1) - object-id-1 (uuid/next) - object-id-2 (uuid/next)] - - (t/testing "create media object from url to file" - (let [url "https://raw.githubusercontent.com/uxbox/uxbox/develop/sample_media/images/unsplash/anna-pelzer.jpg" - data {::th/type :add-media-object-from-url - :id object-id-1 - :profile-id (:id prof) - :file-id (:id file) - :is-local true - :url url} - out (th/mutation! data)] - - ;; (th/print-result! out) - (t/is (nil? (:error out))) - - (t/is (= object-id-1 (get-in out [:result :id]))) - (t/is (not (nil? (get-in out [:result :name])))) - (t/is (= "image/jpeg" (get-in out [:result :mtype]))) - (t/is (= 1024 (get-in out [:result :width]))) - (t/is (= 683 (get-in out [:result :height]))) - - (t/is (string? (get-in out [:result :path]))) - (t/is (string? (get-in out [:result :thumb-path]))) - )) - - (t/testing "upload media object to file" - (let [content {:filename "sample.jpg" - :tempfile (th/tempfile "app/tests/_files/sample.jpg") - :content-type "image/jpeg" - :size 312043} - data {::th/type :upload-media-object - :id object-id-2 - :profile-id (:id prof) - :file-id (:id file) - :is-local true - :name "testfile" - :content content} - out (th/mutation! data)] - - ;; (th/print-result! out) - (t/is (nil? (:error out))) - - (t/is (= object-id-2 (get-in out [:result :id]))) - (t/is (= "testfile" (get-in out [:result :name]))) - (t/is (= "image/jpeg" (get-in out [:result :mtype]))) - (t/is (= 800 (get-in out [:result :width]))) - (t/is (= 800 (get-in out [:result :height]))) - - (t/is (string? (get-in out [:result :path]))) - (t/is (string? (get-in out [:result :thumb-path]))))) +(t/deftest media-object-from-url + (let [prof (th/create-profile* 1) + proj (th/create-project* 1 {:profile-id (:id prof) + :team-id (:default-team-id prof)}) + file (th/create-file* 1 {:profile-id (:id prof) + :project-id (:default-project-id prof) + :is-shared false}) + url "https://raw.githubusercontent.com/uxbox/uxbox/develop/sample_media/images/unsplash/anna-pelzer.jpg" + params {::th/type :create-file-media-object-from-url + :profile-id (:id prof) + :file-id (:id file) + :is-local true + :url url} + out (th/mutation! params)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (let [{:keys [media-id thumbnail-id] :as result} (:result out)] + (t/is (= (:id file) (:file-id result))) + (t/is (= 1024 (:width result))) + (t/is (= 683 (:height result))) + (t/is (= "image/jpeg" (:mtype result))) + (t/is (uuid? media-id)) + (t/is (uuid? thumbnail-id)) + (let [storage (:app.storage/storage th/*system*) + mobj1 (sto/get-object storage media-id) + mobj2 (sto/get-object storage thumbnail-id)] + (t/is (sto/storage-object? mobj1)) + (t/is (sto/storage-object? mobj2)) + (t/is (= 122785 (:size mobj1))) + (t/is (= 3303 (:size mobj2))))) + )) + +(t/deftest media-object-upload + (let [prof (th/create-profile* 1) + proj (th/create-project* 1 {:profile-id (:id prof) + :team-id (:default-team-id prof)}) + file (th/create-file* 1 {:profile-id (:id prof) + :project-id (:default-project-id prof) + :is-shared false}) + mfile {:filename "sample.jpg" + :tempfile (th/tempfile "app/tests/_files/sample.jpg") + :content-type "image/jpeg" + :size 312043} + + params {::th/type :upload-file-media-object + :profile-id (:id prof) + :file-id (:id file) + :is-local true + :name "testfile" + :content mfile} + out (th/mutation! params)] + + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (let [{:keys [media-id thumbnail-id] :as result} (:result out)] + (t/is (= (:id file) (:file-id result))) + (t/is (= 800 (:width result))) + (t/is (= 800 (:height result))) + (t/is (= "image/jpeg" (:mtype result))) + (t/is (uuid? media-id)) + (t/is (uuid? thumbnail-id)) + (let [storage (:app.storage/storage th/*system*) + mobj1 (sto/get-object storage media-id) + mobj2 (sto/get-object storage thumbnail-id)] + (t/is (sto/storage-object? mobj1)) + (t/is (sto/storage-object? mobj2)) + (t/is (= 312043 (:size mobj1))) + (t/is (= 3887 (:size mobj2))))) )) diff --git a/backend/tests/app/tests/test_services_profile.clj b/backend/tests/app/tests/test_services_profile.clj index 53a8af201..ab32ca184 100644 --- a/backend/tests/app/tests/test_services_profile.clj +++ b/backend/tests/app/tests/test_services_profile.clj @@ -15,39 +15,55 @@ [cuerdas.core :as str] [datoteka.core :as fs] [app.db :as db] + [app.rpc.mutations.profile :as profile] [app.tests.helpers :as th])) (t/use-fixtures :once th/state-init) (t/use-fixtures :each th/database-reset) -(t/deftest profile-login - (let [profile (th/create-profile th/*pool* 1)] - (t/testing "failed" - (let [data {::th/type :login - :email "profile1.test@nodomain.com" - :password "foobar" - :scope "foobar"} - out (th/mutation! data)] +;; Test with wrong credentials +(t/deftest profile-login-failed-1 + (let [profile (th/create-profile* 1) + data {::th/type :login + :email "profile1.test@nodomain.com" + :password "foobar" + :scope "foobar"} + out (th/mutation! data)] - #_(th/print-result! out) - (let [error (:error out)] - (t/is (th/ex-info? error)) - (t/is (th/ex-of-type? error :validation)) - (t/is (th/ex-of-code? error :wrong-credentials))))) + #_(th/print-result! out) + (let [error (:error out)] + (t/is (th/ex-info? error)) + (t/is (th/ex-of-type? error :validation)) + (t/is (th/ex-of-code? error :wrong-credentials))))) - (t/testing "success" - (let [data {::th/type :login - :email "profile1.test@nodomain.com" - :password "123123" - :scope "foobar"} - out (th/mutation! data)] - ;; (th/print-result! out) - (t/is (nil? (:error out))) - (t/is (= (:id profile) (get-in out [:result :id]))))))) +;; Test with good credentials but profile not activated. +(t/deftest profile-login-failed-2 + (let [profile (th/create-profile* 1) + data {::th/type :login + :email "profile1.test@nodomain.com" + :password "123123" + :scope "foobar"} + out (th/mutation! data)] + ;; (th/print-result! out) + (let [error (:error out)] + (t/is (th/ex-info? error)) + (t/is (th/ex-of-type? error :validation)) + (t/is (th/ex-of-code? error :wrong-credentials))))) +;; Test with good credentials but profile already activated +(t/deftest profile-login-success + (let [profile (th/create-profile* 1 {:is-active true}) + data {::th/type :login + :email "profile1.test@nodomain.com" + :password "123123" + :scope "foobar"} + out (th/mutation! data)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (t/is (= (:id profile) (get-in out [:result :id]))))) (t/deftest profile-query-and-manipulation - (let [profile (th/create-profile th/*pool* 1)] + (let [profile (th/create-profile* 1)] (t/testing "query profile" (let [data {::th/type :profile :profile-id (:id profile)} @@ -100,106 +116,76 @@ (t/is (nil? (:error out))))) )) +(t/deftest profile-deletion-simple + (let [task (:app.tasks.delete-profile/handler th/*system*) + prof (th/create-profile* 1) + file (th/create-file* 1 {:profile-id (:id prof) + :project-id (:default-project-id prof) + :is-shared false})] -#_(t/deftest profile-deletion - (let [prof (th/create-profile th/*pool* 1) - team (:default-team prof) - proj (:default-project prof) - file (th/create-file th/*pool* (:id prof) (:id proj) 1) - page (th/create-page th/*pool* (:id prof) (:id file) 1)] + ;; profile is not deleted because it does not meet all + ;; conditions to be deleted. + (let [result (task {:props {:profile-id (:id prof)}})] + (t/is (nil? result))) - ;; (t/testing "try to delete profile not marked for deletion" - ;; (let [params {:props {:profile-id (:id prof)}} - ;; out (th/try-on! (app.tasks.delete-profile/handler params))] + ;; Request profile to be deleted + (with-mocks [mock {:target 'app.tasks/submit! :return nil}] + (let [params {::th/type :delete-profile + :profile-id (:id prof)} + out (th/mutation! params)] + (t/is (nil? (:error out))) - ;; ;; (th/print-result! out) - ;; (t/is (nil? (:error out))) - ;; (t/is (nil? (:result out))))) + ;; check the mock + (let [mock (deref mock) + mock-params (second (:call-args mock))] + (t/is (:called? mock)) + (t/is (= 1 (:call-count mock))) + (t/is (= "delete-profile" (:name mock-params))) + (t/is (= (:id prof) (get-in mock-params [:props :profile-id])))))) - ;; (t/testing "query profile after delete" - ;; (let [data {::sq/type :profile - ;; :profile-id (:id prof)} - ;; out (th/try-on! (sq/handle data))] + ;; query files after profile soft deletion + (let [params {::th/type :files + :project-id (:default-project-id prof) + :profile-id (:id prof)} + out (th/query! params)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (t/is (= 1 (count (:result out))))) - ;; ;; (th/print-result! out) - ;; (t/is (nil? (:error out))) + ;; execute permanent deletion task + (let [result (task {:props {:profile-id (:id prof)}})] + (t/is (true? result))) - ;; (let [result (:result out)] - ;; (t/is (= (:fullname prof) (:fullname result)))))) + ;; query profile after delete + (let [params {::th/type :profile + :profile-id (:id prof)} + out (th/query! params)] + ;; (th/print-result! out) + (let [error (:error out) + error-data (ex-data error)] + (t/is (th/ex-info? error)) + (t/is (= (:type error-data) :not-found)))) - ;; (t/testing "mark profile for deletion" - ;; (with-mocks - ;; [mock {:target 'app.tasks/schedule! :return nil}] - - ;; (let [data {::sm/type :delete-profile - ;; :profile-id (:id prof)} - ;; out (th/try-on! (sm/handle data))] - ;; ;; (th/print-result! out) - ;; (t/is (nil? (:error out))) - ;; (t/is (nil? (:result out)))) - - ;; ;; check the mock - ;; (let [mock (deref mock) - ;; mock-params (second (:call-args mock))] - ;; (t/is (true? (:called? mock))) - ;; (t/is (= 1 (:call-count mock))) - ;; (t/is (= "delete-profile" (:name mock-params))) - ;; (t/is (= (:id prof) (get-in mock-params [:props :profile-id])))))) - - ;; (t/testing "query files after profile soft deletion" - ;; (let [data {::sq/type :files - ;; :project-id (:id proj) - ;; :profile-id (:id prof)} - ;; out (th/try-on! (sq/handle data))] - ;; ;; (th/print-result! out) - ;; (t/is (nil? (:error out))) - ;; (t/is (= 1 (count (:result out)))))) - - ;; (t/testing "try to delete profile marked for deletion" - ;; (let [params {:props {:profile-id (:id prof)}} - ;; out (th/try-on! (app.tasks.delete-profile/handler params))] - - ;; ;; (th/print-result! out) - ;; (t/is (nil? (:error out))) - ;; (t/is (= (:id prof) (:result out))))) - - ;; (t/testing "query profile after delete" - ;; (let [data {::sq/type :profile - ;; :profile-id (:id prof)} - ;; out (th/try-on! (sq/handle data))] - - ;; ;; (th/print-result! out) - - ;; (let [error (:error out) - ;; error-data (ex-data error)] - ;; (t/is (th/ex-info? error)) - ;; (t/is (= (:type error-data) :service-error)) - ;; (t/is (= (:name error-data) :app.services.queries.profile/profile))) - - ;; (let [error (ex-cause (:error out)) - ;; error-data (ex-data error)] - ;; (t/is (th/ex-info? error)) - ;; (t/is (= (:type error-data) :not-found))))) - - ;; (t/testing "query files after profile permanent deletion" - ;; (let [data {::sq/type :files - ;; :project-id (:id proj) - ;; :profile-id (:id prof)} - ;; out (th/try-on! (sq/handle data))] - ;; ;; (th/print-result! out) - ;; (t/is (nil? (:error out))) - ;; (t/is (= 0 (count (:result out)))))) + ;; query files after profile soft deletion + (let [params {::th/type :files + :project-id (:default-project-id prof) + :profile-id (:id prof)} + out (th/query! params)] + ;; (th/print-result! out) + (let [error (:error out) + error-data (ex-data error)] + (t/is (th/ex-info? error)) + (t/is (= (:type error-data) :not-found)))) )) +(t/deftest registration-domain-whitelist + (let [whitelist "gmail.com, hey.com, ya.ru"] + (t/testing "allowed email domain" + (t/is (true? (profile/email-domain-in-whitelist? whitelist "username@ya.ru"))) + (t/is (true? (profile/email-domain-in-whitelist? "" "username@somedomain.com")))) -;; (t/deftest registration-domain-whitelist -;; (let [whitelist "gmail.com, hey.com, ya.ru"] -;; (t/testing "allowed email domain" -;; (t/is (true? (profile/email-domain-in-whitelist? whitelist "username@ya.ru"))) -;; (t/is (true? (profile/email-domain-in-whitelist? "" "username@somedomain.com")))) - -;; (t/testing "not allowed email domain" -;; (t/is (false? (profile/email-domain-in-whitelist? whitelist "username@somedomain.com")))))) + (t/testing "not allowed email domain" + (t/is (false? (profile/email-domain-in-whitelist? whitelist "username@somedomain.com")))))) ;; TODO: profile deletion with teams ;; TODO: profile deletion with owner teams diff --git a/backend/tests/app/tests/test_services_projects.clj b/backend/tests/app/tests/test_services_projects.clj index a3202eb81..4d638a41b 100644 --- a/backend/tests/app/tests/test_services_projects.clj +++ b/backend/tests/app/tests/test_services_projects.clj @@ -20,67 +20,73 @@ (t/use-fixtures :each th/database-reset) (t/deftest projects-crud - (let [prof (th/create-profile th/*pool* 1) - team (th/create-team th/*pool* (:id prof) 1) + (let [prof (th/create-profile* 1) + team (th/create-team* 1 {:profile-id (:id prof)}) project-id (uuid/next)] - (t/testing "create a project" - (let [data {::th/type :create-project - :id project-id - :profile-id (:id prof) - :team-id (:id team) - :name "test project"} - out (th/mutation! data)] + ;; crate project + (let [data {::th/type :create-project + :id project-id + :profile-id (:id prof) + :team-id (:id team) + :name "test project"} + out (th/mutation! data)] ;; (th/print-result! out) - (t/is (nil? (:error out))) - (let [result (:result out)] - (t/is (= (:name data) (:name result)))))) + (t/is (nil? (:error out))) + (let [result (:result out)] + (t/is (= (:name data) (:name result))))) - (t/testing "query a list of projects" - (let [data {::th/type :projects - :team-id (:id team) - :profile-id (:id prof)} - out (th/query! data)] - ;; (th/print-result! out) + ;; query a list of projects + (let [data {::th/type :projects + :team-id (:id team) + :profile-id (:id prof)} + out (th/query! data)] + ;; (th/print-result! out) - (t/is (nil? (:error out))) - (let [result (:result out)] - (t/is (= 1 (count result))) - (t/is project-id (get-in result [0 :id])) - (t/is "test project" (get-in result [0 :name]))))) + (t/is (nil? (:error out))) + (let [result (:result out)] + (t/is (= 1 (count result))) + (t/is project-id (get-in result [0 :id])) + (t/is (= "test project" (get-in result [0 :name]))))) - (t/testing "rename project" - (let [data {::th/type :rename-project - :id project-id - :name "renamed project" - :profile-id (:id prof)} - out (th/mutation! data)] - ;; (th/print-result! out) - (t/is (nil? (:error out))) - (let [result (:result out)] - (t/is (= (:id data) (:id result))) - (t/is (= (:name data) (:name result))) - (t/is (= (:profile-id data) (:id prof)))))) + ;; rename project" + (let [data {::th/type :rename-project + :id project-id + :name "renamed project" + :profile-id (:id prof)} + out (th/mutation! data)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (t/is (nil? (:result out)))) - (t/testing "delete project" - (let [data {::th/type :delete-project - :id project-id - :profile-id (:id prof)} - out (th/mutation! data)] + ;; retrieve project + (let [data {::th/type :project + :id project-id + :profile-id (:id prof)} + out (th/query! data)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (let [result (:result out)] + (t/is (= "renamed project" (:name result))))) + + ;; delete project + (let [data {::th/type :delete-project + :id project-id + :profile-id (:id prof)} + out (th/mutation! data)] ;; (th/print-result! out) - (t/is (nil? (:error out))) - (t/is (nil? (:result out))))) + (t/is (nil? (:error out))) + (t/is (nil? (:result out)))) - (t/testing "query a list of projects after delete" - (let [data {::th/type :projects - :team-id (:id team) - :profile-id (:id prof)} - out (th/query! data)] - ;; (th/print-result! out) - - (t/is (nil? (:error out))) - (let [result (:result out)] - (t/is (= 0 (count result)))))) - )) + ;; query a list of projects after delete" + (let [data {::th/type :projects + :team-id (:id team) + :profile-id (:id prof)} + out (th/query! data)] + ;; (th/print-result! out) + (t/is (nil? (:error out))) + (let [result (:result out)] + (t/is (= 0 (count result))))) + )) diff --git a/backend/tests/app/tests/test_services_viewer.clj b/backend/tests/app/tests/test_services_viewer.clj index 80cb4770b..54d2ce93c 100644 --- a/backend/tests/app/tests/test_services_viewer.clj +++ b/backend/tests/app/tests/test_services_viewer.clj @@ -19,12 +19,14 @@ (t/use-fixtures :each th/database-reset) (t/deftest retrieve-bundle - (let [prof (th/create-profile th/*pool* 1) - prof2 (th/create-profile th/*pool* 2) + (let [prof (th/create-profile* 1 {:is-active true}) + prof2 (th/create-profile* 2 {:is-active true}) team-id (:default-team-id prof) proj-id (:default-project-id prof) - file (th/create-file th/*pool* (:id prof) proj-id false 1) + file (th/create-file* 1 {:profile-id (:id prof) + :project-id proj-id + :is-shared false}) token (atom nil)] (t/testing "authenticated with page-id" @@ -68,8 +70,8 @@ (let [error (:error out) error-data (ex-data error)] (t/is (th/ex-info? error)) - (t/is (= (:type error-data) :validation)) - (t/is (= (:code error-data) :not-authorized))))) + (t/is (= (:type error-data) :not-found)) + (t/is (= (:code error-data) :object-not-found))))) ;; (t/testing "authenticated with token & profile" ;; (let [data {::sq/type :viewer-bundle