Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/main/java/io/supertokens/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.supertokens.cronjobs.deleteExpiredPasswordlessDevices.DeleteExpiredPasswordlessDevices;
import io.supertokens.cronjobs.deleteExpiredSessions.DeleteExpiredSessions;
import io.supertokens.cronjobs.deleteExpiredTotpTokens.DeleteExpiredTotpTokens;
import io.supertokens.cronjobs.syncCoreConfigWithDb.SyncCoreConfigWithDb;
import io.supertokens.cronjobs.telemetry.Telemetry;
import io.supertokens.emailpassword.PasswordHashing;
import io.supertokens.exceptions.QuitProgramException;
Expand Down Expand Up @@ -227,6 +228,8 @@ private void init() throws IOException, StorageQueryException {
// starts removing old session cronjob
List<List<TenantIdentifier>> uniqueUserPoolIdsTenants = StorageLayer.getTenantsWithUniqueUserPoolId(this);

Cronjobs.addCronjob(this, SyncCoreConfigWithDb.init(this));

Cronjobs.addCronjob(this, DeleteExpiredSessions.init(this, uniqueUserPoolIdsTenants));

// starts removing old password reset tokens
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2023, VRAI Labs and/or its affiliates. All rights reserved.
*
* This software is licensed under the Apache License, Version 2.0 (the
* "License") as published by the Apache Software Foundation.
*
* 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.
*/

package io.supertokens.cronjobs.syncCoreConfigWithDb;

import io.supertokens.Main;
import io.supertokens.cronjobs.CronTask;
import io.supertokens.cronjobs.CronTaskTest;
import io.supertokens.cronjobs.deleteExpiredSessions.DeleteExpiredSessions;
import io.supertokens.multitenancy.Multitenancy;
import io.supertokens.multitenancy.MultitenancyHelper;
import io.supertokens.pluginInterface.multitenancy.TenantIdentifier;

import java.util.List;

public class SyncCoreConfigWithDb extends CronTask {

public static final String RESOURCE_KEY = "io.supertokens.cronjobs.syncCoreConfigWithDb.SyncCoreConfigWithDb";

Main main;

private SyncCoreConfigWithDb(Main main) {
super("SyncCoreConfigWithDb", main, TenantIdentifier.BASE_TENANT);
this.main = main;
}

public static SyncCoreConfigWithDb init(Main main) {
return (SyncCoreConfigWithDb) main.getResourceDistributor()
.setResource(TenantIdentifier.BASE_TENANT, RESOURCE_KEY,
new SyncCoreConfigWithDb(main));
}

@Override
public int getIntervalTimeSeconds() {
if (Main.isTesting) {
Integer interval = CronTaskTest.getInstance(main).getIntervalInSeconds(RESOURCE_KEY);
if (interval != null) {
return interval;
}
}
return 60;
}

@Override
public int getInitialWaitTimeSeconds() {
if (Main.isTesting) {
return 0;
}
return 60;
}

@Override
protected void doTaskForTargetTenant(TenantIdentifier targetTenant) throws Exception {
MultitenancyHelper.getInstance(main).refreshTenantsInCoreBasedOnChangesInCoreConfigOrIfTenantListChanged(true);
}
}
82 changes: 82 additions & 0 deletions src/test/java/io/supertokens/test/CronjobTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@
import io.supertokens.Main;
import io.supertokens.ProcessState;
import io.supertokens.cronjobs.CronTask;
import io.supertokens.cronjobs.CronTaskTest;
import io.supertokens.cronjobs.Cronjobs;
import io.supertokens.cronjobs.deleteExpiredDashboardSessions.DeleteExpiredDashboardSessions;
import io.supertokens.cronjobs.syncCoreConfigWithDb.SyncCoreConfigWithDb;
import io.supertokens.exceptions.QuitProgramException;
import io.supertokens.featureflag.EE_FEATURES;
import io.supertokens.featureflag.FeatureFlagTestContent;
import io.supertokens.multitenancy.Multitenancy;
import io.supertokens.multitenancy.MultitenancyHelper;
import io.supertokens.pluginInterface.STORAGE_TYPE;
import io.supertokens.pluginInterface.Storage;
import io.supertokens.pluginInterface.multitenancy.*;
Expand Down Expand Up @@ -699,4 +703,82 @@ public void testPerUserPoolCronTask() throws Exception {
process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}

@Test
public void testThatCoreAutomaticallySyncsToConfigChangesInDb() throws Exception {
String[] args = {"../"};

TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false);
FeatureFlagTestContent.getInstance(process.getProcess())
.setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{EE_FEATURES.MULTI_TENANCY});
CronTaskTest.getInstance(process.getProcess()).setIntervalInSeconds(SyncCoreConfigWithDb.RESOURCE_KEY,
3);
process.startProcess();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
return;
}

if (StorageLayer.isInMemDb(process.getProcess())) {
return;
}

TenantIdentifier t1 = new TenantIdentifier(null, "a1", null);
Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
t1,
new EmailPasswordConfig(false),
new ThirdPartyConfig(false, null),
new PasswordlessConfig(false),
new JsonObject()
), false);

boolean found = false;

TenantConfig[] allTenants = MultitenancyHelper.getInstance(process.getProcess()).getAllTenants();
for (TenantConfig tenant : allTenants) {
if (tenant.tenantIdentifier.equals(t1)) {
assertFalse(tenant.emailPasswordConfig.enabled);
found = true;
}
}
assertTrue(found);

MultitenancyStorage storage = (MultitenancyStorage) StorageLayer.getStorage(process.getProcess());
storage.overwriteTenantConfig(new TenantConfig(
t1,
new EmailPasswordConfig(true),
new ThirdPartyConfig(false, null),
new PasswordlessConfig(false),
new JsonObject()
));

// Check that it was not updated in memory yet
found = false;
allTenants = MultitenancyHelper.getInstance(process.getProcess()).getAllTenants();
for (TenantConfig tenant : allTenants) {
if (tenant.tenantIdentifier.equals(t1)) {
assertFalse(tenant.emailPasswordConfig.enabled);
found = true;
}
}
assertTrue(found);

// Wait for the cronjob to run
Thread.sleep(3100);

// Check that it was updated in memory by now
found = false;
allTenants = MultitenancyHelper.getInstance(process.getProcess()).getAllTenants();
for (TenantConfig tenant : allTenants) {
if (tenant.tenantIdentifier.equals(t1)) {
assertTrue(tenant.emailPasswordConfig.enabled);
found = true;
}
}
assertTrue(found);

process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}
}