mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
* feat: add environment configuration support for Git providers and enhance git sync functionality * feat: update Git environment constants and integrate OrganizationGitSyncRepository * feat: add testProviderConnection method to gitSyncService for testing Git provider connections * chore: remove scanning on module init * feat: integrate OrganizationEnvRegistryService and reload envConfig on workspace create and slug update * feat: eload env config on onboarding * feat: add testProviderConnection method and update LicenseBase for envGitMapping * fix: handle downgrade path for env registry * fix flaky case in granular access * uncommented changes * feat: update .gitignore to include additional environment files * feat: refactor organization environment handling and remove deprecated service * feat: implement Git environment registry service and refactor organization environment handling * feat: rename envGitMapping to workspaceEnv across licensing module * chore: remove unnecessary try-catch * refactor(org-env): update interfaces — remove callback contract, add ensureResolved Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: remove reload-on-org-event, swap bootstrap init order Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(org-env): add getResolvedOrganizationIds() to interface, CE stub, and test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: improve assertions in getResolvedOrganizationIds() test * feat: refactor GitEnvRegistryService import paths and add new service implementation * feat: add applyLicenseToResolvedOrgs method to IGitEnvRegistryService and GitEnvRegistryService * refactor: replace GitEnvRegistryService with GitSyncEnvUtilService and update related references * feat: add use_env_config column to organization_git_sync and remove env_git_provider column * refactor: remove EncryptionModule import and update OrganizationEnvModule imports * feat: introduce OrganizationEnvUtilService and update OrganizationEnvModule to utilize it --------- Co-authored-by: Yukti Goyal <yuktigoyal02@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
234 lines
8.1 KiB
TypeScript
234 lines
8.1 KiB
TypeScript
jest.mock('@modules/organizations/repository', () => ({
|
|
OrganizationRepository: jest.fn(),
|
|
}));
|
|
|
|
import { GitSyncEnvUtilService } from '@ee/organization-env/services/gitsync.util.service';
|
|
import { GIT_ENV_KEYS } from '@modules/organization-env/constants';
|
|
import { GITConnectionType } from 'src/entities/organization_git_sync.entity';
|
|
|
|
const ORG_ID = '11111111-1111-1111-1111-111111111111';
|
|
|
|
function makeOrgEnvService(overrides: Partial<Record<string, jest.Mock>> = {}) {
|
|
return {
|
|
getResolvedOrganizationIds: jest.fn().mockReturnValue([]),
|
|
has: jest.fn().mockReturnValue(false),
|
|
hasAll: jest.fn().mockReturnValue(false),
|
|
get: jest.fn().mockResolvedValue(undefined),
|
|
ensureResolved: jest.fn().mockResolvedValue(undefined),
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function makeService(orgEnvService: ReturnType<typeof makeOrgEnvService>) {
|
|
const orgGitSyncRepo = {
|
|
find: jest.fn().mockResolvedValue([]),
|
|
findOrgGitByOrganizationId: jest.fn().mockResolvedValue(null),
|
|
update: jest.fn().mockResolvedValue(undefined),
|
|
create: jest.fn().mockReturnValue({}),
|
|
save: jest.fn().mockResolvedValue(undefined),
|
|
};
|
|
const logger = {
|
|
log: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn(),
|
|
};
|
|
const licenseTerms = {
|
|
getLicenseTerms: jest.fn().mockResolvedValue(true),
|
|
};
|
|
return new GitSyncEnvUtilService(
|
|
orgEnvService as any,
|
|
orgGitSyncRepo as any,
|
|
logger as any,
|
|
licenseTerms as any,
|
|
);
|
|
}
|
|
|
|
function makeServiceWithMocks(
|
|
orgEnvService: ReturnType<typeof makeOrgEnvService>,
|
|
licenseResult = true,
|
|
) {
|
|
const orgGitSyncRepo = {
|
|
find: jest.fn().mockResolvedValue([]),
|
|
findOrgGitByOrganizationId: jest.fn().mockResolvedValue(null),
|
|
update: jest.fn().mockResolvedValue(undefined),
|
|
create: jest.fn().mockReturnValue({}),
|
|
save: jest.fn().mockResolvedValue(undefined),
|
|
};
|
|
const logger = {
|
|
log: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn(),
|
|
};
|
|
const licenseTerms = {
|
|
getLicenseTerms: jest.fn().mockResolvedValue(licenseResult),
|
|
};
|
|
const service = new GitSyncEnvUtilService(
|
|
orgEnvService as any,
|
|
orgGitSyncRepo as any,
|
|
logger as any,
|
|
licenseTerms as any,
|
|
);
|
|
return { service, orgGitSyncRepo, licenseTerms };
|
|
}
|
|
|
|
describe('GitSyncEnvUtilService', () => {
|
|
describe('initialize() — proactive provider state from env store', () => {
|
|
it('sets HTTPS provider isEnabled=true when at least one HTTPS key is mapped', async () => {
|
|
const orgEnvService = makeOrgEnvService({
|
|
getResolvedOrganizationIds: jest.fn().mockReturnValue([ORG_ID]),
|
|
has: jest.fn().mockImplementation((_id: string, key: string) =>
|
|
key === GIT_ENV_KEYS.HTTPS.URL,
|
|
),
|
|
});
|
|
const service = makeService(orgEnvService);
|
|
|
|
await service.initialize();
|
|
|
|
expect(service.getProviderState(ORG_ID, GITConnectionType.GITHUB_HTTPS)).toEqual({
|
|
isEnabled: true,
|
|
isFinalized: false,
|
|
});
|
|
});
|
|
|
|
it('sets SSH provider isEnabled=true independently when SSH key is mapped', async () => {
|
|
const orgEnvService = makeOrgEnvService({
|
|
getResolvedOrganizationIds: jest.fn().mockReturnValue([ORG_ID]),
|
|
has: jest.fn().mockImplementation((_id: string, key: string) =>
|
|
key === GIT_ENV_KEYS.SSH.GIT_URL,
|
|
),
|
|
});
|
|
const service = makeService(orgEnvService);
|
|
|
|
await service.initialize();
|
|
|
|
expect(service.getProviderState(ORG_ID, GITConnectionType.GITHUB_SSH)).toEqual({
|
|
isEnabled: true,
|
|
isFinalized: false,
|
|
});
|
|
expect(service.getProviderState(ORG_ID, GITConnectionType.GITHUB_HTTPS)).toEqual({
|
|
isEnabled: false,
|
|
isFinalized: false,
|
|
});
|
|
});
|
|
|
|
it('sets GitLab provider isEnabled=true when GitLab key is mapped', async () => {
|
|
const orgEnvService = makeOrgEnvService({
|
|
getResolvedOrganizationIds: jest.fn().mockReturnValue([ORG_ID]),
|
|
has: jest.fn().mockImplementation((_id: string, key: string) =>
|
|
key === GIT_ENV_KEYS.GITLAB.URL,
|
|
),
|
|
});
|
|
const service = makeService(orgEnvService);
|
|
|
|
await service.initialize();
|
|
|
|
expect(service.getProviderState(ORG_ID, GITConnectionType.GITLAB)).toEqual({
|
|
isEnabled: true,
|
|
isFinalized: false,
|
|
});
|
|
});
|
|
|
|
it('leaves provider disabled when no keys are mapped for that provider', async () => {
|
|
const orgEnvService = makeOrgEnvService({
|
|
getResolvedOrganizationIds: jest.fn().mockReturnValue([ORG_ID]),
|
|
has: jest.fn().mockReturnValue(false),
|
|
});
|
|
const service = makeService(orgEnvService);
|
|
|
|
await service.initialize();
|
|
|
|
expect(service.getProviderState(ORG_ID, GITConnectionType.GITHUB_HTTPS)).toEqual({
|
|
isEnabled: false,
|
|
isFinalized: false,
|
|
});
|
|
});
|
|
|
|
it('does not call has() when no resolved orgs exist', async () => {
|
|
const orgEnvService = makeOrgEnvService({
|
|
getResolvedOrganizationIds: jest.fn().mockReturnValue([]),
|
|
has: jest.fn().mockReturnValue(true),
|
|
});
|
|
const service = makeService(orgEnvService);
|
|
|
|
await service.initialize();
|
|
|
|
expect(orgEnvService.has).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('sets provider isEnabled=false when license is not valid', async () => {
|
|
const orgEnvService = makeOrgEnvService({
|
|
getResolvedOrganizationIds: jest.fn().mockReturnValue([ORG_ID]),
|
|
has: jest.fn().mockImplementation((_id: string, key: string) =>
|
|
key === GIT_ENV_KEYS.HTTPS.URL,
|
|
),
|
|
});
|
|
const { service } = makeServiceWithMocks(orgEnvService, false);
|
|
|
|
await service.initialize();
|
|
|
|
expect(service.getProviderState(ORG_ID, GITConnectionType.GITHUB_HTTPS)).toEqual({
|
|
isEnabled: false,
|
|
isFinalized: false,
|
|
});
|
|
});
|
|
|
|
it('does not call hydrateUseEnvConfig when license is not valid', async () => {
|
|
const orgEnvService = makeOrgEnvService({
|
|
getResolvedOrganizationIds: jest.fn().mockReturnValue([ORG_ID]),
|
|
has: jest.fn().mockImplementation((_id: string, key: string) =>
|
|
key === GIT_ENV_KEYS.HTTPS.URL,
|
|
),
|
|
});
|
|
const { service, orgGitSyncRepo } = makeServiceWithMocks(orgEnvService, false);
|
|
|
|
await service.initialize();
|
|
|
|
// hydrateUseEnvConfig calls save (create path) or update — neither should be called
|
|
expect(orgGitSyncRepo.save).not.toHaveBeenCalled();
|
|
expect(orgGitSyncRepo.update).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('ensureResolved() — license-aware state + dedup', () => {
|
|
it('sets provider isEnabled=false when license is not valid', async () => {
|
|
const orgEnvService = makeOrgEnvService({
|
|
has: jest.fn().mockImplementation((_id: string, key: string) =>
|
|
key === GIT_ENV_KEYS.HTTPS.URL,
|
|
),
|
|
});
|
|
const { service } = makeServiceWithMocks(orgEnvService, false);
|
|
|
|
await service.ensureResolved(ORG_ID);
|
|
|
|
expect(service.getProviderState(ORG_ID, GITConnectionType.GITHUB_HTTPS)).toEqual({
|
|
isEnabled: false,
|
|
isFinalized: false,
|
|
});
|
|
});
|
|
|
|
it('does not call hydrateUseEnvConfig when license is not valid', async () => {
|
|
const orgEnvService = makeOrgEnvService({
|
|
has: jest.fn().mockImplementation((_id: string, key: string) =>
|
|
key === GIT_ENV_KEYS.HTTPS.URL,
|
|
),
|
|
});
|
|
const { service, orgGitSyncRepo } = makeServiceWithMocks(orgEnvService, false);
|
|
|
|
await service.ensureResolved(ORG_ID);
|
|
|
|
expect(orgGitSyncRepo.save).not.toHaveBeenCalled();
|
|
expect(orgGitSyncRepo.update).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('runs license check only once across multiple ensureResolved calls (dedup)', async () => {
|
|
const orgEnvService = makeOrgEnvService({
|
|
has: jest.fn().mockImplementation((_id: string, key: string) =>
|
|
key === GIT_ENV_KEYS.HTTPS.URL,
|
|
),
|
|
});
|
|
const { service, licenseTerms } = makeServiceWithMocks(orgEnvService, false);
|
|
|
|
await service.ensureResolved(ORG_ID);
|
|
await service.ensureResolved(ORG_ID);
|
|
|
|
// getLicenseTerms called twice per check (WORKSPACE_ENV + VALID), but only on first call
|
|
expect(licenseTerms.getLicenseTerms).toHaveBeenCalledTimes(2);
|
|
});
|
|
});
|
|
});
|