/* * Minio Cloud Storage (C) 2018 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import configureStore from "redux-mock-store" import thunk from "redux-thunk" import * as actionsObjects from "../actions" import * as alertActions from "../../alert/actions" import { minioBrowserPrefix } from "../../constants" import history from "../../history" jest.mock("../../web", () => ({ LoggedIn: jest .fn(() => true) .mockReturnValueOnce(true) .mockReturnValueOnce(false) .mockReturnValueOnce(false), ListObjects: jest.fn(({ bucketName }) => { if (bucketName === "test-deny") { return Promise.reject({ message: "listobjects is denied" }) } else { return Promise.resolve({ objects: [{ name: "test1" }, { name: "test2" }], istruncated: false, nextmarker: "test2", writable: false }) } }), RemoveObject: jest.fn(({ bucketName, objects }) => { if (!bucketName) { return Promise.reject({ message: "Invalid bucket" }) } return Promise.resolve({}) }), PresignedGet: jest.fn(({ bucket, object }) => { if (!bucket) { return Promise.reject({ message: "Invalid bucket" }) } return Promise.resolve({ url: "https://test.com/bk1/pre1/b.txt" }) }), CreateURLToken: jest .fn() .mockImplementationOnce(() => { return Promise.resolve({ token: "test" }) }) .mockImplementationOnce(() => { return Promise.reject({ message: "Error in creating token" }) }) .mockImplementationOnce(() => { return Promise.resolve({ token: "test" }) }) })) const middlewares = [thunk] const mockStore = configureStore(middlewares) describe("Objects actions", () => { it("creates objects/SET_LIST action", () => { const store = mockStore() const expectedActions = [ { type: "objects/SET_LIST", objects: [{ name: "test1" }, { name: "test2" }], isTruncated: false, marker: "test2" } ] store.dispatch( actionsObjects.setList( [{ name: "test1" }, { name: "test2" }], "test2", false ) ) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("creates objects/SET_SORT_BY action", () => { const store = mockStore() const expectedActions = [ { type: "objects/SET_SORT_BY", sortBy: "name" } ] store.dispatch(actionsObjects.setSortBy("name")) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("creates objects/SET_SORT_ORDER action", () => { const store = mockStore() const expectedActions = [ { type: "objects/SET_SORT_ORDER", sortOrder: true } ] store.dispatch(actionsObjects.setSortOrder(true)) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("creates objects/SET_LIST after fetching the objects", () => { const store = mockStore({ buckets: { currentBucket: "bk1" }, objects: { currentPrefix: "" } }) const expectedActions = [ { type: "alert/CLEAR" }, { type: "objects/SET_LIST", objects: [{ name: "test1" }, { name: "test2" }], marker: "test2", isTruncated: false }, { type: "objects/SET_SORT_BY", sortBy: "" }, { type: "objects/SET_SORT_ORDER", sortOrder: false }, { type: "objects/SET_PREFIX_WRITABLE", prefixWritable: false } ] return store.dispatch(actionsObjects.fetchObjects()).then(() => { const actions = store.getActions() expect(actions).toEqual(expectedActions) }) }) it("creates objects/APPEND_LIST after fetching more objects", () => { const store = mockStore({ buckets: { currentBucket: "bk1" }, objects: { currentPrefix: "" } }) const expectedActions = [ { type: "alert/CLEAR" }, { type: "objects/APPEND_LIST", objects: [{ name: "test1" }, { name: "test2" }], marker: "test2", isTruncated: false }, { type: "objects/SET_PREFIX_WRITABLE", prefixWritable: false } ] return store.dispatch(actionsObjects.fetchObjects(true)).then(() => { const actions = store.getActions() expect(actions).toEqual(expectedActions) }) }) it("creates objects/RESET_LIST after failing to fetch the objects from bucket with ListObjects denied for LoggedIn users", () => { const store = mockStore({ buckets: { currentBucket: "test-deny" }, objects: { currentPrefix: "" } }) const expectedActions = [ { type: "alert/CLEAR" }, { type: "alert/SET", alert: { type: "danger", message: "listobjects is denied", id: alertActions.alertId } }, { type: "object/RESET_LIST" } ] return store.dispatch(actionsObjects.fetchObjects()).then(() => { const actions = store.getActions() expect(actions).toEqual(expectedActions) }) }) it("redirect to login after failing to fetch the objects from bucket for non-LoggedIn users", () => { const store = mockStore({ buckets: { currentBucket: "test-deny" }, objects: { currentPrefix: "" } }) return store.dispatch(actionsObjects.fetchObjects()).then(() => { expect(history.location.pathname.endsWith("/login")).toBeTruthy() }) }) it("creates objects/SET_SORT_BY and objects/SET_SORT_ORDER when sortObjects is called", () => { const store = mockStore({ objects: { list: [], sortBy: "", sortOrder: false, isTruncated: false, marker: "" } }) const expectedActions = [ { type: "objects/SET_SORT_BY", sortBy: "name" }, { type: "objects/SET_SORT_ORDER", sortOrder: true }, { type: "objects/SET_LIST", objects: [], isTruncated: false, marker: "" } ] store.dispatch(actionsObjects.sortObjects("name")) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("should update browser url and creates objects/SET_CURRENT_PREFIX and objects/CHECKED_LIST_RESET actions when selectPrefix is called", () => { const store = mockStore({ buckets: { currentBucket: "test" }, objects: { currentPrefix: "" } }) const expectedActions = [ { type: "objects/SET_CURRENT_PREFIX", prefix: "abc/" }, { type: "alert/CLEAR" }, { type: "objects/CHECKED_LIST_RESET" } ] store.dispatch(actionsObjects.selectPrefix("abc/")) const actions = store.getActions() expect(actions).toEqual(expectedActions) expect(window.location.pathname.endsWith("/test/abc/")).toBeTruthy() }) it("create objects/SET_PREFIX_WRITABLE action", () => { const store = mockStore() const expectedActions = [ { type: "objects/SET_PREFIX_WRITABLE", prefixWritable: true } ] store.dispatch(actionsObjects.setPrefixWritable(true)) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("creates objects/REMOVE action", () => { const store = mockStore() const expectedActions = [{ type: "objects/REMOVE", object: "obj1" }] store.dispatch(actionsObjects.removeObject("obj1")) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("creates objects/REMOVE action when object is deleted", () => { const store = mockStore({ buckets: { currentBucket: "test" }, objects: { currentPrefix: "pre1/" } }) const expectedActions = [{ type: "objects/REMOVE", object: "obj1" }] store.dispatch(actionsObjects.deleteObject("obj1")).then(() => { const actions = store.getActions() expect(actions).toEqual(expectedActions) }) }) it("creates alert/SET action when invalid bucket is provided", () => { const store = mockStore({ buckets: { currentBucket: "" }, objects: { currentPrefix: "pre1/" } }) const expectedActions = [ { type: "alert/SET", alert: { type: "danger", message: "Invalid bucket", id: alertActions.alertId } } ] return store.dispatch(actionsObjects.deleteObject("obj1")).then(() => { const actions = store.getActions() expect(actions).toEqual(expectedActions) }) }) it("creates objects/SET_SHARE_OBJECT action for showShareObject", () => { const store = mockStore() const expectedActions = [ { type: "objects/SET_SHARE_OBJECT", show: true, object: "b.txt", url: "test" } ] store.dispatch(actionsObjects.showShareObject("b.txt", "test")) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("creates objects/SET_SHARE_OBJECT action for hideShareObject", () => { const store = mockStore() const expectedActions = [ { type: "objects/SET_SHARE_OBJECT", show: false, object: "", url: "" } ] store.dispatch(actionsObjects.hideShareObject()) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("creates objects/SET_SHARE_OBJECT when object is shared", () => { const store = mockStore({ buckets: { currentBucket: "bk1" }, objects: { currentPrefix: "pre1/" } }) const expectedActions = [ { type: "objects/SET_SHARE_OBJECT", show: true, object: "a.txt", url: "https://test.com/bk1/pre1/b.txt" }, { type: "alert/SET", alert: { type: "success", message: "Object shared. Expires in 1 days 0 hours 0 minutes", id: alertActions.alertId } } ] return store .dispatch(actionsObjects.shareObject("a.txt", 1, 0, 0)) .then(() => { const actions = store.getActions() expect(actions).toEqual(expectedActions) }) }) it("creates alert/SET when shareObject is failed", () => { const store = mockStore({ buckets: { currentBucket: "" }, objects: { currentPrefix: "pre1/" } }) const expectedActions = [ { type: "alert/SET", alert: { type: "danger", message: "Invalid bucket", id: alertActions.alertId } } ] return store .dispatch(actionsObjects.shareObject("a.txt", 1, 0, 0)) .then(() => { const actions = store.getActions() expect(actions).toEqual(expectedActions) }) }) describe("Download object", () => { it("should download the object non-LoggedIn users", () => { const setLocation = jest.fn() Object.defineProperty(window, "location", { set(url) { setLocation(url) }, get() { return { origin: "http://localhost:8080" } } }) const store = mockStore({ buckets: { currentBucket: "bk1" }, objects: { currentPrefix: "pre1/" } }) store.dispatch(actionsObjects.downloadObject("obj1")) const url = `${ window.location.origin }${minioBrowserPrefix}/download/bk1/${encodeURI("pre1/obj1")}?token=''` expect(setLocation).toHaveBeenCalledWith(url) }) it("should download the object for LoggedIn users", () => { const setLocation = jest.fn() Object.defineProperty(window, "location", { set(url) { setLocation(url) }, get() { return { origin: "http://localhost:8080" } } }) const store = mockStore({ buckets: { currentBucket: "bk1" }, objects: { currentPrefix: "pre1/" } }) return store.dispatch(actionsObjects.downloadObject("obj1")).then(() => { const url = `${ window.location.origin }${minioBrowserPrefix}/download/bk1/${encodeURI( "pre1/obj1" )}?token=test` expect(setLocation).toHaveBeenCalledWith(url) }) }) it("create alert/SET action when CreateUrlToken fails", () => { const store = mockStore({ buckets: { currentBucket: "bk1" }, objects: { currentPrefix: "pre1/" } }) const expectedActions = [ { type: "alert/SET", alert: { type: "danger", message: "Error in creating token", id: alertActions.alertId } } ] return store.dispatch(actionsObjects.downloadObject("obj1")).then(() => { const actions = store.getActions() expect(actions).toEqual(expectedActions) }) }) }) it("creates objects/CHECKED_LIST_ADD action", () => { const store = mockStore() const expectedActions = [ { type: "objects/CHECKED_LIST_ADD", object: "obj1" } ] store.dispatch(actionsObjects.checkObject("obj1")) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("creates objects/CHECKED_LIST_REMOVE action", () => { const store = mockStore() const expectedActions = [ { type: "objects/CHECKED_LIST_REMOVE", object: "obj1" } ] store.dispatch(actionsObjects.uncheckObject("obj1")) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("creates objects/CHECKED_LIST_RESET action", () => { const store = mockStore() const expectedActions = [ { type: "objects/CHECKED_LIST_RESET" } ] store.dispatch(actionsObjects.resetCheckedList()) const actions = store.getActions() expect(actions).toEqual(expectedActions) }) it("should download checked objects", () => { const open = jest.fn() const send = jest.fn() const xhrMockClass = () => ({ open: open, send: send }) window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass) const store = mockStore({ buckets: { currentBucket: "bk1" }, objects: { currentPrefix: "pre1/", checkedList: ["obj1"] } }) return store.dispatch(actionsObjects.downloadCheckedObjects()).then(() => { const requestUrl = `${ location.origin }${minioBrowserPrefix}/zip?token=test` expect(open).toHaveBeenCalledWith("POST", requestUrl, true) expect(send).toHaveBeenCalledWith( JSON.stringify({ bucketName: "bk1", prefix: "pre1/", objects: ["obj1"] }) ) }) }) })