mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
This simplifes the mental model on how it works and simplifies testing of the related code. This also normalizes storage object deletion in the same way as the rest of objects in penpot (now future deletion date on storage object also means storage object to be deleted).
224 lines
7.7 KiB
Clojure
224 lines
7.7 KiB
Clojure
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
;;
|
|
;; Copyright (c) KALEIDOS INC
|
|
|
|
(ns backend-tests.rpc-file-snapshot-test
|
|
(:require
|
|
[app.common.features :as cfeat]
|
|
[app.common.pprint :as pp]
|
|
[app.common.thumbnails :as thc]
|
|
[app.common.time :as ct]
|
|
[app.common.types.shape :as cts]
|
|
[app.common.uuid :as uuid]
|
|
[app.config :as cf]
|
|
[app.db :as db]
|
|
[app.db.sql :as sql]
|
|
[app.http :as http]
|
|
[app.rpc :as-alias rpc]
|
|
[app.setup.clock :as clock]
|
|
[app.storage :as sto]
|
|
[backend-tests.helpers :as th]
|
|
[clojure.test :as t]
|
|
[cuerdas.core :as str]))
|
|
|
|
(t/use-fixtures :once th/state-init)
|
|
(t/use-fixtures :each th/database-reset)
|
|
|
|
(defn- update-file!
|
|
[& {:keys [profile-id file-id changes revn] :or {revn 0}}]
|
|
(let [params {::th/type :update-file
|
|
::rpc/profile-id profile-id
|
|
:id file-id
|
|
:session-id (uuid/random)
|
|
:revn revn
|
|
:vern 0
|
|
:features cfeat/supported-features
|
|
:changes changes}
|
|
out (th/command! params)]
|
|
;; (th/print-result! out)
|
|
(t/is (nil? (:error out)))
|
|
(:result out)))
|
|
|
|
(t/deftest snapshots-crud
|
|
(let [profile (th/create-profile* 1 {:is-active true})
|
|
team-id (:default-team-id profile)
|
|
proj-id (:default-project-id profile)
|
|
|
|
file (th/create-file* 1 {:profile-id (:id profile)
|
|
:project-id proj-id
|
|
:is-shared false})
|
|
snapshot-id (volatile! nil)]
|
|
|
|
(t/testing "create snapshot"
|
|
(let [params {::th/type :create-file-snapshot
|
|
::rpc/profile-id (:id profile)
|
|
:file-id (:id file)
|
|
:label "label1"}
|
|
out (th/command! params)]
|
|
;; (th/print-result! out)
|
|
|
|
(t/is (nil? (:error out)))
|
|
(let [result (:result out)]
|
|
(t/is (= "label1" (:label result)))
|
|
(t/is (uuid? (:id result)))
|
|
(vswap! snapshot-id (constantly (:id result))))))
|
|
|
|
(t/testing "list snapshots"
|
|
(let [params {::th/type :get-file-snapshots
|
|
::rpc/profile-id (:id profile)
|
|
:file-id (:id file)}
|
|
out (th/command! params)]
|
|
;; (th/print-result! out)
|
|
(t/is (nil? (:error out)))
|
|
(let [[row :as result] (:result out)]
|
|
(t/is (= 1 (count result)))
|
|
(t/is (= "label1" (:label row)))
|
|
(t/is (uuid? (:id row)))
|
|
(t/is (= @snapshot-id (:id row)))
|
|
(t/is (= 0 (:revn row)))
|
|
(t/is (= (:id profile) (:profile-id row))))))
|
|
|
|
(t/testing "restore snapshot"
|
|
(let [params {::th/type :restore-file-snapshot
|
|
::rpc/profile-id (:id profile)
|
|
:file-id (:id file)
|
|
:id @snapshot-id}
|
|
out (th/command! params)]
|
|
|
|
;; (th/print-result! out)
|
|
(t/is (nil? (:error out)))
|
|
(t/is (nil? (:result out))))
|
|
|
|
(let [[row1 row2 :as rows]
|
|
(th/db-query :file-change
|
|
{:file-id (:id file)}
|
|
{:order-by [:created-at]})]
|
|
|
|
(t/is (= 2 (count rows)))
|
|
(t/is (= "user" (:created-by row1)))
|
|
(t/is (= "system" (:created-by row2)))))
|
|
|
|
(t/testing "delete snapshot"
|
|
(let [[row1 row2 :as rows]
|
|
(th/db-query :file-change
|
|
{:file-id (:id file)}
|
|
{:order-by [:created-at]})]
|
|
|
|
(t/testing "delete user created snapshot"
|
|
(let [params {::th/type :delete-file-snapshot
|
|
::rpc/profile-id (:id profile)
|
|
:file-id (:id file)
|
|
:id (:id row1)}
|
|
out (th/command! params)]
|
|
|
|
;; (th/print-result! out)
|
|
(t/is (nil? (:error out)))
|
|
(t/is (true? (:result out)))))
|
|
|
|
(t/testing "delete system created snapshot"
|
|
(let [params {::th/type :delete-file-snapshot
|
|
::rpc/profile-id (:id profile)
|
|
:file-id (:id file)
|
|
:id (:id row2)}
|
|
out (th/command! params)]
|
|
|
|
;; (th/print-result! out)
|
|
(let [error (:error out)
|
|
data (ex-data error)]
|
|
(t/is (th/ex-info? error))
|
|
(t/is (= (:type data) :validation))
|
|
(t/is (= (:code data) :system-snapshots-cant-be-deleted)))))
|
|
|
|
;; this will run pending task triggered by deleting user snapshot
|
|
(th/run-pending-tasks!)
|
|
|
|
(binding [ct/*clock* (clock/fixed (ct/in-future {:days 8}))]
|
|
(let [res (th/run-task! :objects-gc {})]
|
|
;; delete 2 snapshots and 2 file data entries
|
|
(t/is (= 4 (:processed res)))))))))
|
|
|
|
(t/deftest snapshots-locking
|
|
(let [profile-1 (th/create-profile* 1 {:is-active true})
|
|
profile-2 (th/create-profile* 2 {:is-active true})
|
|
|
|
team
|
|
(th/create-team* 1 {:profile-id (:id profile-1)})
|
|
|
|
project
|
|
(th/create-project* 1 {:profile-id (:id profile-1)
|
|
:team-id (:id team)})
|
|
|
|
file
|
|
(th/create-file* 1 {:profile-id (:id profile-1)
|
|
:project-id (:id project)
|
|
:is-shared false})
|
|
|
|
snapshot
|
|
(let [params {::th/type :create-file-snapshot
|
|
::rpc/profile-id (:id profile-1)
|
|
:file-id (:id file)
|
|
:label "label1"}
|
|
out (th/command! params)]
|
|
;; (th/print-result! out)
|
|
|
|
(t/is (nil? (:error out)))
|
|
(:result out))]
|
|
|
|
;; Add the secont profile to the team
|
|
(th/create-team-role* {:team-id (:id team)
|
|
:profile-id (:id profile-2)
|
|
:role :admin})
|
|
|
|
(t/testing "lock snapshot"
|
|
(let [params {::th/type :lock-file-snapshot
|
|
::rpc/profile-id (:id profile-1)
|
|
:file-id (:id file)
|
|
:id (:id snapshot)}
|
|
out (th/command! params)]
|
|
;; (th/print-result! out)
|
|
(t/is (nil? (:error out)))
|
|
(t/is (true? (:result out)))
|
|
|
|
(let [snapshot (th/db-get :file-change {:id (:id snapshot)} {::db/remove-deleted false})]
|
|
(t/is (= (:id profile-1) (:locked-by snapshot))))))
|
|
|
|
(t/testing "delete locked snapshot"
|
|
(let [params {::th/type :delete-file-snapshot
|
|
::rpc/profile-id (:id profile-2)
|
|
:file-id (:id file)
|
|
:id (:id snapshot)}
|
|
out (th/command! params)]
|
|
|
|
;; (th/print-result! out)
|
|
(let [error (:error out)
|
|
data (ex-data error)]
|
|
(t/is (th/ex-info? error))
|
|
(t/is (= (:type data) :validation))
|
|
(t/is (= (:code data) :snapshot-is-locked)))))
|
|
|
|
(t/testing "unlock snapshot"
|
|
(let [params {::th/type :unlock-file-snapshot
|
|
::rpc/profile-id (:id profile-1)
|
|
:file-id (:id file)
|
|
:id (:id snapshot)}
|
|
out (th/command! params)]
|
|
;; (th/print-result! out)
|
|
(t/is (nil? (:error out)))
|
|
(t/is (true? (:result out)))
|
|
|
|
(let [snapshot (th/db-get :file-change {:id (:id snapshot)})]
|
|
(t/is (= nil (:locked-by snapshot))))))
|
|
|
|
(t/testing "delete locked snapshot"
|
|
(let [params {::th/type :delete-file-snapshot
|
|
::rpc/profile-id (:id profile-2)
|
|
:file-id (:id file)
|
|
:id (:id snapshot)}
|
|
out (th/command! params)]
|
|
|
|
;; (th/print-result! out)
|
|
(t/is (nil? (:error out)))
|
|
(t/is (true? (:result out)))))))
|