{ "info": { "name": "Line Gestao - SystemTenant Multi-tenant Tests", "_postman_id": "c4c0b7d9-7f11-4a0c-b8ca-332633f12601", "description": "Fluxo de testes para sysadmin, endpoints /api/system/* e isolamento por tenant.", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "variable": [ { "key": "adminMasterToken", "value": "" }, { "key": "tenantAUserToken", "value": "" }, { "key": "newTenantAUserToken", "value": "" }, { "key": "tenantAUserId", "value": "" }, { "key": "newTenantAUserId", "value": "" }, { "key": "newTenantAUserEmail", "value": "" }, { "key": "newTenantAUserPassword", "value": "" }, { "key": "newTenantAUserName", "value": "" } ], "item": [ { "name": "1) Login sysadmin", "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"email\": \"{{adminMasterEmail}}\",\n \"password\": \"{{adminMasterPassword}}\",\n \"tenantId\": \"{{systemTenantId}}\"\n}" }, "url": { "raw": "{{baseUrl}}/auth/login", "host": ["{{baseUrl}}"], "path": ["auth", "login"] } }, "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status 200', function () {", " pm.response.to.have.status(200);", "});", "const json = pm.response.json();", "pm.test('Retorna token JWT', function () {", " pm.expect(json.token).to.be.a('string').and.not.empty;", "});", "pm.collectionVariables.set('adminMasterToken', json.token);" ] } } ] }, { "name": "2) GET /api/system/tenants (sysadmin)", "request": { "auth": { "type": "bearer", "bearer": [ { "key": "token", "value": "{{adminMasterToken}}", "type": "string" } ] }, "method": "GET", "url": { "raw": "{{baseUrl}}/api/system/tenants?source=MobileLines.Cliente&active=true", "host": ["{{baseUrl}}"], "path": ["api", "system", "tenants"], "query": [ { "key": "source", "value": "MobileLines.Cliente" }, { "key": "active", "value": "true" } ] } }, "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status 200', function () {", " pm.response.to.have.status(200);", "});", "const tenants = pm.response.json();", "pm.test('Retorna array de tenants', function () {", " pm.expect(Array.isArray(tenants)).to.eql(true);", "});", "const tenantAClientName = pm.environment.get('tenantAClientName');", "const tenantBClientName = pm.environment.get('tenantBClientName');", "if (tenantAClientName) {", " const tenantA = tenants.find(t => t.nomeOficial === tenantAClientName || t.NomeOficial === tenantAClientName);", " pm.test('Tenant A encontrado por nomeOficial', function () {", " pm.expect(tenantA).to.exist;", " });", " if (tenantA && (tenantA.tenantId || tenantA.TenantId)) {", " pm.environment.set('tenantAId', tenantA.tenantId || tenantA.TenantId);", " }", "}", "if (tenantBClientName) {", " const tenantB = tenants.find(t => t.nomeOficial === tenantBClientName || t.NomeOficial === tenantBClientName);", " pm.test('Tenant B encontrado por nomeOficial', function () {", " pm.expect(tenantB).to.exist;", " });", " if (tenantB && (tenantB.tenantId || tenantB.TenantId)) {", " pm.environment.set('tenantBId', tenantB.tenantId || tenantB.TenantId);", " }", "}" ] } } ] }, { "name": "3) POST /api/system/tenants/{tenantId}/users (criar usuário comum tenant A)", "request": { "auth": { "type": "bearer", "bearer": [ { "key": "token", "value": "{{adminMasterToken}}", "type": "string" } ] }, "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"name\": \"{{tenantAUserName}}\",\n \"email\": \"{{tenantAUserEmail}}\",\n \"password\": \"{{tenantAUserPassword}}\",\n \"roles\": [\"cliente\"]\n}" }, "url": { "raw": "{{baseUrl}}/api/system/tenants/{{tenantAId}}/users", "host": ["{{baseUrl}}"], "path": ["api", "system", "tenants", "{{tenantAId}}", "users"] } }, "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status 201 (criado) ou 409 (já existe)', function () {", " pm.expect([201, 409]).to.include(pm.response.code);", "});", "if (pm.response.code === 201) {", " const json = pm.response.json();", " pm.collectionVariables.set('tenantAUserId', json.userId || json.UserId || '');", "}" ] } } ] }, { "name": "4) Login usuário comum tenant A", "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"email\": \"{{tenantAUserEmail}}\",\n \"password\": \"{{tenantAUserPassword}}\",\n \"tenantId\": \"{{tenantAId}}\"\n}" }, "url": { "raw": "{{baseUrl}}/auth/login", "host": ["{{baseUrl}}"], "path": ["auth", "login"] } }, "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status 200', function () {", " pm.response.to.have.status(200);", "});", "const json = pm.response.json();", "pm.collectionVariables.set('tenantAUserToken', json.token);" ] } } ] }, { "name": "5) Usuário comum NÃO acessa /api/system/*", "request": { "auth": { "type": "bearer", "bearer": [ { "key": "token", "value": "{{tenantAUserToken}}", "type": "string" } ] }, "method": "GET", "url": { "raw": "{{baseUrl}}/api/system/tenants?source=MobileLines.Cliente&active=true", "host": ["{{baseUrl}}"], "path": ["api", "system", "tenants"], "query": [ { "key": "source", "value": "MobileLines.Cliente" }, { "key": "active", "value": "true" } ] } }, "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status 403 Forbidden', function () {", " pm.response.to.have.status(403);", "});" ] } } ] }, { "name": "6) Usuário comum tenant A vê apenas seu tenant", "request": { "auth": { "type": "bearer", "bearer": [ { "key": "token", "value": "{{tenantAUserToken}}", "type": "string" } ] }, "method": "GET", "url": { "raw": "{{baseUrl}}/api/lines/clients", "host": ["{{baseUrl}}"], "path": ["api", "lines", "clients"] } }, "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status 200', function () {", " pm.response.to.have.status(200);", "});", "const clients = pm.response.json();", "pm.test('Retorna lista de clientes', function () {", " pm.expect(Array.isArray(clients)).to.eql(true);", "});", "const tenantAClientName = pm.environment.get('tenantAClientName');", "const tenantBClientName = pm.environment.get('tenantBClientName');", "if (tenantAClientName) {", " pm.test('Contém cliente do tenant A', function () {", " pm.expect(clients).to.include(tenantAClientName);", " });", "}", "if (tenantBClientName) {", " pm.test('Não contém cliente do tenant B', function () {", " pm.expect(clients).to.not.include(tenantBClientName);", " });", "}" ] } } ] }, { "name": "7) POST /api/system/tenants/{tenantId}/users (novo usuário tenant A)", "event": [ { "listen": "prerequest", "script": { "type": "text/javascript", "exec": [ "const suffix = Date.now().toString().slice(-8);", "pm.collectionVariables.set('newTenantAUserEmail', `novo.tenant.a.${suffix}@test.local`);", "pm.collectionVariables.set('newTenantAUserPassword', 'ClienteA123!');", "pm.collectionVariables.set('newTenantAUserName', `Novo Tenant A ${suffix}`);" ] } }, { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status 201', function () {", " pm.response.to.have.status(201);", "});", "const json = pm.response.json();", "pm.collectionVariables.set('newTenantAUserId', json.userId || json.UserId || '');" ] } } ], "request": { "auth": { "type": "bearer", "bearer": [ { "key": "token", "value": "{{adminMasterToken}}", "type": "string" } ] }, "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"name\": \"{{newTenantAUserName}}\",\n \"email\": \"{{newTenantAUserEmail}}\",\n \"password\": \"{{newTenantAUserPassword}}\",\n \"roles\": [\"cliente\"]\n}" }, "url": { "raw": "{{baseUrl}}/api/system/tenants/{{tenantAId}}/users", "host": ["{{baseUrl}}"], "path": ["api", "system", "tenants", "{{tenantAId}}", "users"] } } }, { "name": "8) Login novo usuário tenant A", "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"email\": \"{{newTenantAUserEmail}}\",\n \"password\": \"{{newTenantAUserPassword}}\",\n \"tenantId\": \"{{tenantAId}}\"\n}" }, "url": { "raw": "{{baseUrl}}/auth/login", "host": ["{{baseUrl}}"], "path": ["auth", "login"] } }, "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status 200', function () {", " pm.response.to.have.status(200);", "});", "const json = pm.response.json();", "pm.collectionVariables.set('newTenantAUserToken', json.token);" ] } } ] }, { "name": "9) Novo usuário tenant A vê apenas seu tenant", "request": { "auth": { "type": "bearer", "bearer": [ { "key": "token", "value": "{{newTenantAUserToken}}", "type": "string" } ] }, "method": "GET", "url": { "raw": "{{baseUrl}}/api/lines/clients", "host": ["{{baseUrl}}"], "path": ["api", "lines", "clients"] } }, "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "pm.test('Status 200', function () {", " pm.response.to.have.status(200);", "});", "const clients = pm.response.json();", "const tenantAClientName = pm.environment.get('tenantAClientName');", "const tenantBClientName = pm.environment.get('tenantBClientName');", "if (tenantAClientName) {", " pm.test('Contém cliente do tenant A', function () {", " pm.expect(clients).to.include(tenantAClientName);", " });", "}", "if (tenantBClientName) {", " pm.test('Não contém cliente do tenant B', function () {", " pm.expect(clients).to.not.include(tenantBClientName);", " });", "}" ] } } ] } ] }