diff --git a/packages/server/appPackages/testApp/dist/package.tar.gz b/packages/server/appPackages/testApp/dist/package.tar.gz index cd657b26b..49eb5212f 100644 Binary files a/packages/server/appPackages/testApp/dist/package.tar.gz and b/packages/server/appPackages/testApp/dist/package.tar.gz differ diff --git a/packages/server/middleware/routers.js b/packages/server/middleware/routers.js index 5f75b6905..e669c1e22 100644 --- a/packages/server/middleware/routers.js +++ b/packages/server/middleware/routers.js @@ -191,10 +191,16 @@ module.exports = (config, app) => { ctx.response.status = StatusCodes.OK; }) .get("/:appname/api/record/*", async (ctx) => { - ctx.body = await ctx.instance.recordApi.load( - getRecordKey(ctx.params.appname, ctx.request.path) - ); - ctx.response.status = StatusCodes.OK; + try { + ctx.body = await ctx.instance.recordApi.load( + getRecordKey(ctx.params.appname, ctx.request.path) + ); + ctx.response.status = StatusCodes.OK; + } catch(e) { + // need to be catching for 404s here + ctx.response.status = StatusCodes.INTERAL_ERROR; + ctx.response.body = e.message; + } }) .del("/:appname/api/record/*", async (ctx) => { await ctx.instance.recordApi.delete( diff --git a/packages/server/runtime_apps/testApp/3-Ch-Pk0Sm6Xb/access_levels.json b/packages/server/runtime_apps/testApp/3-VYAktSELSd/access_levels.json similarity index 100% rename from packages/server/runtime_apps/testApp/3-Ch-Pk0Sm6Xb/access_levels.json rename to packages/server/runtime_apps/testApp/3-VYAktSELSd/access_levels.json diff --git a/packages/server/runtime_apps/testApp/3-Ch-Pk0Sm6Xb/appDefinition.json b/packages/server/runtime_apps/testApp/3-VYAktSELSd/appDefinition.json similarity index 100% rename from packages/server/runtime_apps/testApp/3-Ch-Pk0Sm6Xb/appDefinition.json rename to packages/server/runtime_apps/testApp/3-VYAktSELSd/appDefinition.json diff --git a/packages/server/runtime_apps/testApp/3-Ch-Pk0Sm6Xb/plugins.js b/packages/server/runtime_apps/testApp/3-VYAktSELSd/plugins.js similarity index 100% rename from packages/server/runtime_apps/testApp/3-Ch-Pk0Sm6Xb/plugins.js rename to packages/server/runtime_apps/testApp/3-VYAktSELSd/plugins.js diff --git a/packages/server/tests/all.spec.js b/packages/server/tests/all.spec.js index 63968a922..72b483793 100644 --- a/packages/server/tests/all.spec.js +++ b/packages/server/tests/all.spec.js @@ -1,13 +1,15 @@ const app = require("./testApp")(); const authenticateMaster = require("./authenticate"); const createNewApp = require("./createNewApp"); +const multipleInstances = require("./multipleInstances"); beforeAll(async () => await app.start()) afterAll(async () => await app.destroy()) -describe("authenticateMaster", () => authenticateMaster(app, "_master", () => app.masterAuth)); +describe("authenticateMaster", () => authenticateMaster(app, "_master", "masterOwner")); describe("createNewApp", () => createNewApp(app)); -describe("authenticateTestApp", () => authenticateMaster(app, "testApp", () => app.user1_instance1)); +describe("authenticateTestApp", () => authenticateMaster(app, "testApp", "testAppUser1")); +describe("multipleInstances", () => multipleInstances(app)); diff --git a/packages/server/tests/authenticate.js b/packages/server/tests/authenticate.js index 8a4e1624d..ce8f8ec0f 100644 --- a/packages/server/tests/authenticate.js +++ b/packages/server/tests/authenticate.js @@ -2,9 +2,9 @@ const statusCodes = require("../utilities/statusCodes"); const { readFile } = require("../utilities/fsawait"); const { timeout } = require("./helpers"); -module.exports = (app, appName) => { +module.exports = (app, appName, userName) => { - const credentials = app.credentials[appName]; + const credentials = app.credentials[userName]; it("should return unauthorized if username is incorrect", async () => { await app.post(`/${appName}/api/authenticate`, { diff --git a/packages/server/tests/createNewApp.js b/packages/server/tests/createNewApp.js index e6a049bb9..ec76affe0 100644 --- a/packages/server/tests/createNewApp.js +++ b/packages/server/tests/createNewApp.js @@ -23,13 +23,13 @@ module.exports = (app) => { const newApp = master.recordApi.getNew("/applications", "application"); newApp.name = app.testAppInfo.name newAppKey = newApp.key; - + app.apps.testApp1.key = newAppKey; await app.post(`/_master/api/record/${newApp.key}`, newApp) - .set("cookie", app.credentials._master.cookie) + .set("cookie", app.credentials.masterOwner.cookie) .expect(statusCodes.OK); const response = await app.get(`/_master/api/record/${newApp.key}`) - .set("cookie", app.credentials._master.cookie) + .set("cookie", app.credentials.masterOwner.cookie) .expect(statusCodes.OK); expect(response.body.name).toBe(newApp.name); @@ -49,14 +49,16 @@ module.exports = (app) => { version1.package = { relativePath: "package.tar.gz", size}; await app.post(`/_master/api/record/${version1.key}`, version1) - .set("cookie", app.credentials._master.cookie) + .set("cookie", app.credentials.masterOwner.cookie) .expect(statusCodes.OK); await app.post(`/_master/api/files/${version1.key}`) .attach("file", path, "package.tar.gz") - .set("cookie", app.credentials._master.cookie) + .set("cookie", app.credentials.masterOwner.cookie) .expect(statusCodes.OK); + app.apps.testApp1.version1 = version1; + }); let instance1; @@ -69,14 +71,15 @@ module.exports = (app) => { instance1.version = {key:version1Key, name:"v1", defaultAccessLevel:"owner"}; await app.post(`/_master/api/record/${instance1.key}`, instance1) - .set("cookie", app.credentials._master.cookie) + .set("cookie", app.credentials.masterOwner.cookie) .expect(statusCodes.OK); const loadInstanceResponse = await app.get(`/_master/api/record/${instance1.key}`) - .set("cookie", app.credentials._master.cookie) + .set("cookie", app.credentials.masterOwner.cookie) .expect(statusCodes.OK); instance1 = loadInstanceResponse.body; + app.apps.testApp1.instance1 = instance1; }); @@ -85,37 +88,38 @@ module.exports = (app) => { const master = await getmaster(); user1_instance1 = master.recordApi .getNew(`${newAppKey}/users`, "user"); - user1_instance1.name = app.credentials.testApp.username; + user1_instance1.name = app.credentials.testAppUser1.username; user1_instance1.createdByMaster = true; master.recordApi.setCustomId(user1_instance1, user1_instance1.name); /*const lookupResponse = await app.get(`/_master/api/lookup_field/${user1_instance1.key}?fields=instance`) - .set("cookie", app.credentials._master.cookie) + .set("cookie", app.credentials.masterOwner.cookie) .expect(statusCodes.OK); */ user1_instance1.instance = instance1; user1_instance1.active = true; //await timeout(100); await app.post(`/_master/api/record/${user1_instance1.key}`, user1_instance1) - .set("cookie", app.credentials._master.cookie) + .set("cookie", app.credentials.masterOwner.cookie) .expect(statusCodes.OK); }); it("should be able to set password for new user using temporary code", async () => { const testUserTempCode = await readFile(`./tests/.data/tempaccess${user1_instance1.name}`, "utf8"); - user1_instance1.password = app.credentials.testApp.password; + user1_instance1.password = app.credentials.testAppUser1.password; await app.post("/testApp/api/setPasswordFromTemporaryCode", { - username: app.credentials.testApp.username, + username: app.credentials.testAppUser1.username, tempCode:testUserTempCode, - newPassword:app.credentials.testApp.password + newPassword:app.credentials.testAppUser1.password }) .expect(statusCodes.OK); - await app.post("/testApp/api/authenticate", { - username: app.credentials.testApp.username, - password: app.credentials.testApp.password + const response = await app.post("/testApp/api/authenticate", { + username: app.credentials.testAppUser1.username, + password: app.credentials.testAppUser1.password }) .expect(statusCodes.OK); + app.credentials.testAppUser1.cookie = response.header['set-cookie']; }) } \ No newline at end of file diff --git a/packages/server/tests/multipleInstances.js b/packages/server/tests/multipleInstances.js new file mode 100644 index 000000000..fcc8a0f34 --- /dev/null +++ b/packages/server/tests/multipleInstances.js @@ -0,0 +1,129 @@ +const statusCodes = require("../utilities/statusCodes"); +const constructHierarchy = require("../utilities/constructHierarchy"); +const { readFile } = require("../utilities/fsawait"); +const {getRecordApi, getAuthApi} = require("budibase-core"); +const masterAppDefinition = constructHierarchy( + require("../appPackages/master/appDefinition.json")); +const {getApisWithFullAccess} = require("../utilities/budibaseApi"); +const { createTarGzPackage } = require("../utilities/targzAppPackage"); +const { timeout } = require("./helpers"); + +module.exports = (app) => { + + let _master; + const getmaster = async () => { + if(!_master) + _master = await getApisWithFullAccess({}, app.masterAppPackage); + return _master; + } + + let testInstance; + const getTestInstance = async () => { + if(!testInstance) { + const testAppInstance1AppPackage = app.testAppInstance1AppPackage; + testInstance = await getApisWithFullAccess({}, await testAppInstance1AppPackage(app)); + } + return testInstance; + } + + + let instance2; + it("should be able to create second instance of app", async () => { + const version1 = app.apps.testApp1.version1; + const master = await getmaster(); + instance2 = master.recordApi + .getNew(`${app.apps.testApp1.key}/instances`, "instance"); + instance2.name = "instance 2"; + instance2.active = true; + instance2.version = {key:version1.key, name:"v1", defaultAccessLevel:"owner"}; + + await app.post(`/_master/api/record/${instance2.key}`, instance2) + .set("cookie", app.credentials.masterOwner.cookie) + .expect(statusCodes.OK); + + const loadInstanceResponse = await app.get(`/_master/api/record/${instance2.key}`) + .set("cookie", app.credentials.masterOwner.cookie) + .expect(statusCodes.OK); + + instance2 = loadInstanceResponse.body; + app.apps.testApp1.instance2 = instance2; + + }); + + let user1_instance2; + it("should be able to create new user on second instance, via master", async () => { + const master = await getmaster(); + user1_instance2 = master.recordApi + .getNew(`${app.apps.testApp1.key}/users`, "user"); + user1_instance2.name = app.credentials.testAppUser2.username; + user1_instance2.createdByMaster = true; + master.recordApi.setCustomId(user1_instance2, user1_instance2.name); + + user1_instance2.instance = instance2; + user1_instance2.active = true; + //await timeout(100); + await app.post(`/_master/api/record/${user1_instance2.key}`, user1_instance2) + .set("cookie", app.credentials.masterOwner.cookie) + .expect(statusCodes.OK); + }); + + it("should be able to set password for new user using temporary code", async () => { + const testUserTempCode = await readFile(`./tests/.data/tempaccess${user1_instance2.name}`, "utf8"); + user1_instance2.password = app.credentials.testAppUser2.password; + + await app.post("/testApp/api/setPasswordFromTemporaryCode", { + username: app.credentials.testAppUser2.username, + tempCode:testUserTempCode, + newPassword:app.credentials.testAppUser2.password + }) + .expect(statusCodes.OK); + + const response = await app.post("/testApp/api/authenticate", { + username: app.credentials.testAppUser2.username, + password: app.credentials.testAppUser2.password + }) + .expect(statusCodes.OK); + + app.credentials.testAppUser2.cookie = response.header['set-cookie']; + + }) + + it("should create records in the correct instance", async () => { + const bb = await getTestInstance(); + + const newCustomer = name => { + const c = bb.recordApi.getNew("/customers", "customer"); + c.name = name; + return c; + } + + const customer1 = newCustomer("customer1"); + await app.post(`/testApp/api/record/${customer1.key}`, customer1) + .set("cookie", app.credentials.testAppUser1.cookie) + .expect(statusCodes.OK); + + const customer2 = newCustomer("customer2"); + await app.post(`/testApp/api/record/${customer2.key}`, customer2) + .set("cookie", app.credentials.testAppUser2.cookie) + .expect(statusCodes.OK); + + + await app.get(`/testApp/api/record/${customer1.key}`) + .set("cookie", app.credentials.testAppUser1.cookie) + .expect(statusCodes.OK); + + await app.get(`/testApp/api/record/${customer1.key}`) + .set("cookie", app.credentials.testAppUser2.cookie) + .expect(statusCodes.INTERAL_ERROR); + + await app.get(`/testApp/api/record/${customer2.key}`) + .set("cookie", app.credentials.testAppUser2.cookie) + .expect(statusCodes.OK); + + await app.get(`/testApp/api/record/${customer2.key}`) + .set("cookie", app.credentials.testAppUser1.cookie) + .expect(statusCodes.INTERAL_ERROR); + + + }); +} \ No newline at end of file diff --git a/packages/server/tests/testApp.js b/packages/server/tests/testApp.js index bb5469c52..004c41e25 100644 --- a/packages/server/tests/testApp.js +++ b/packages/server/tests/testApp.js @@ -3,7 +3,7 @@ const { rimraf, mkdir } = require("../utilities/fsawait"); const createMasterDb = require("../initialise/createMasterDb"); const request = require("supertest"); const fs = require("fs"); -const { masterAppPackage } = require("../utilities/createAppPackage"); +const { masterAppPackage, applictionVersionPackage } = require("../utilities/createAppPackage"); const buildAppContext = require("../initialise/buildAppContext"); var enableDestroy = require('server-destroy'); @@ -70,23 +70,40 @@ module.exports = () => { post: (url, body) => postRequest(server,url,body), get: (url) => getRequest(server, url), credentials: { - _master: { + masterOwner: { username: masterOwnerName, password: masterOwnerPassword, cookie: "" }, - testApp: { + testAppUser1: { username: "testAppUser1", password: "user1_instance1_password", cookie: "" + }, + testAppUser2: { + username: "testAppUser2", + password: "user1_instance2_password", + cookie: "" } }, - + apps: { + testApp1: { + key:null, + instance1:null, + instance2:null, + version1:null, + } + }, testAppInfo: { name: "testApp" }, destroy: () => server.destroy(), - masterAppPackage: masterAppPackage({ config }) + masterAppPackage: masterAppPackage({ config }), + testAppInstance1AppPackage: async (app) => applictionVersionPackage( + await buildAppContext(config, true), + "testApp", + app.apps.testApp1.instance1.version.id, + app.apps.testApp1.instance1.key) }) }; diff --git a/packages/server/utilities/createAppPackage.js b/packages/server/utilities/createAppPackage.js index e8fad5f9a..a879c961b 100644 --- a/packages/server/utilities/createAppPackage.js +++ b/packages/server/utilities/createAppPackage.js @@ -59,7 +59,6 @@ module.exports.applictionVersionPackage = async (context, appname, versionId, in pkg, context.master, appname, - instanceKey - ); + instanceKey); return pkg; }