Skip to content

Commit

Permalink
fix: Startup log (#655)
Browse files Browse the repository at this point in the history
* fix: tenant id in loadConfig

* fix: remove repeat log

* fix: added test
  • Loading branch information
sattvikc authored Apr 28, 2023
1 parent 3e51187 commit 5dde394
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 9 deletions.
6 changes: 5 additions & 1 deletion src/main/java/io/supertokens/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import io.supertokens.ResourceDistributor;
import io.supertokens.cliOptions.CLIOptions;
import io.supertokens.output.Logging;
import io.supertokens.pluginInterface.LOG_LEVEL;
import io.supertokens.pluginInterface.Storage;
import io.supertokens.pluginInterface.exceptions.InvalidConfigException;
import io.supertokens.pluginInterface.multitenancy.TenantConfig;
Expand All @@ -37,6 +38,7 @@
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Config extends ResourceDistributor.SingletonResource {

Expand Down Expand Up @@ -141,7 +143,9 @@ public static void assertAllTenantConfigsAreValid(Main main,
// of view cause getNewStorageInstance calls loadConfig on the db plugin
// which calls creates a new instance of the Config object, which calls
// the validate function.
Storage storage = StorageLayer.getNewStorageInstance(main, currentConfig);

// doNotLog is set to true so that the plugin loading message is not logged from here
Storage storage = StorageLayer.getNewStorageInstance(main, currentConfig, key.getTenantIdentifier(), true);
final String userPoolId = storage.getUserPoolId();
final String connectionUriAndAppId =
key.getTenantIdentifier().getConnectionUriDomain() + "|" + key.getTenantIdentifier().getAppId();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/supertokens/inmemorydb/Start.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public STORAGE_TYPE getType() {
}

@Override
public void loadConfig(JsonObject ignored, Set<LOG_LEVEL> logLevel) throws InvalidConfigException {
public void loadConfig(JsonObject ignored, Set<LOG_LEVEL> logLevel, TenantIdentifier tenantIdentifier) throws InvalidConfigException {
Config.loadConfig(this);
}

Expand Down
22 changes: 15 additions & 7 deletions src/main/java/io/supertokens/storageLayer/StorageLayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.supertokens.exceptions.QuitProgramException;
import io.supertokens.inmemorydb.Start;
import io.supertokens.output.Logging;
import io.supertokens.pluginInterface.LOG_LEVEL;
import io.supertokens.pluginInterface.Storage;
import io.supertokens.pluginInterface.authRecipe.AuthRecipeStorage;
import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException;
Expand Down Expand Up @@ -53,7 +54,7 @@ public Storage getUnderlyingStorage() {
return storage;
}

public static Storage getNewStorageInstance(Main main, JsonObject config) throws InvalidConfigException {
public static Storage getNewStorageInstance(Main main, JsonObject config, TenantIdentifier tenantIdentifier, boolean doNotLog) throws InvalidConfigException {
Storage result;
if (StorageLayer.ucl == null) {
result = new Start(main);
Expand All @@ -80,18 +81,24 @@ public static Storage getNewStorageInstance(Main main, JsonObject config) throws
}
result.constructor(main.getProcessId(), Main.makeConsolePrintSilent);

Set<LOG_LEVEL> logLevels = null;
if (doNotLog) {
logLevels = new HashSet<>();
} else {
logLevels = Config.getBaseConfig(main).getLogLevels(main);
}
// this is intentionally null, null below cause log levels is per core and not per tenant anyway
result.loadConfig(config, Config.getBaseConfig(main).getLogLevels(main));
result.loadConfig(config, logLevels, tenantIdentifier);
return result;
}

private StorageLayer(Storage storage) {
this.storage = storage;
}

private StorageLayer(Main main, String pluginFolderPath, JsonObject configJson)
private StorageLayer(Main main, String pluginFolderPath, JsonObject configJson, TenantIdentifier tenantIdentifier)
throws MalformedURLException, InvalidConfigException {
Logging.info(main, TenantIdentifier.BASE_TENANT, "Loading storage layer.", true);
Logging.info(main, tenantIdentifier, "Loading storage layer.", true);
File loc = new File(pluginFolderPath);

File[] flist = loc.listFiles(file -> file.getPath().toLowerCase().endsWith(".jar"));
Expand All @@ -110,7 +117,7 @@ private StorageLayer(Main main, String pluginFolderPath, JsonObject configJson)
}
}

this.storage = getNewStorageInstance(main, configJson);
this.storage = getNewStorageInstance(main, configJson, tenantIdentifier, false);

if (this.storage instanceof Start) {
Logging.info(main, TenantIdentifier.BASE_TENANT, "Using in memory storage.", true);
Expand Down Expand Up @@ -175,7 +182,7 @@ private static StorageLayer getInstance(TenantIdentifier tenantIdentifier, Main
public static void initPrimary(Main main, String pluginFolderPath, JsonObject configJson)
throws MalformedURLException, InvalidConfigException {
main.getResourceDistributor().setResource(new TenantIdentifier(null, null, null), RESOURCE_KEY,
new StorageLayer(main, pluginFolderPath, configJson));
new StorageLayer(main, pluginFolderPath, configJson, TenantIdentifier.BASE_TENANT));
}

public static void loadAllTenantStorage(Main main, TenantConfig[] tenants)
Expand All @@ -190,7 +197,8 @@ public static void loadAllTenantStorage(Main main, TenantConfig[] tenants)
{
Map<String, Storage> idToStorageMap = new HashMap<>();
for (ResourceDistributor.KeyClass key : normalisedConfigs.keySet()) {
Storage storage = StorageLayer.getNewStorageInstance(main, normalisedConfigs.get(key));
// setting doNotLog to true so that plugin loading is not logged here
Storage storage = StorageLayer.getNewStorageInstance(main, normalisedConfigs.get(key), key.getTenantIdentifier(), true);
String userPoolId = storage.getUserPoolId();
String connectionPoolId = storage.getConnectionPoolId();
String uniqueId = userPoolId + "~" + connectionPoolId;
Expand Down
145 changes: 145 additions & 0 deletions src/test/java/io/supertokens/test/multitenant/LogTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* 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.test.multitenant;

import com.google.gson.JsonObject;
import io.supertokens.Main;
import io.supertokens.ProcessState;
import io.supertokens.cliOptions.CLIOptions;
import io.supertokens.config.Config;
import io.supertokens.featureflag.EE_FEATURES;
import io.supertokens.featureflag.FeatureFlagTestContent;
import io.supertokens.multitenancy.Multitenancy;
import io.supertokens.pluginInterface.multitenancy.*;
import io.supertokens.storageLayer.StorageLayer;
import io.supertokens.test.TestingProcessManager;
import io.supertokens.test.Utils;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;

import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.HashSet;
import java.util.Set;

import static org.junit.Assert.*;

public class LogTest {
@Rule
public TestRule watchman = Utils.getOnFailure();

@AfterClass
public static void afterTesting() {
Utils.afterTesting();
}

@Before
public void beforeEach() {
Utils.reset();
}

@Test
public void testLogThatEachLineIsUniqueOnStartup() throws Exception {
String[] args = {"../"};
Utils.setValueInConfig("log_level", "DEBUG");

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

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

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

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

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

ByteArrayOutputStream stdOutput = new ByteArrayOutputStream();
ByteArrayOutputStream errorOutput = new ByteArrayOutputStream();


System.setOut(new PrintStream(stdOutput));
System.setErr(new PrintStream(errorOutput));

process = TestingProcessManager.start(args, false);
Main.makeConsolePrintSilent = false;
FeatureFlagTestContent.getInstance(process.getProcess())
.setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{EE_FEATURES.MULTI_TENANCY});
process.startProcess();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

String outputString = stdOutput.toString();

System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
System.setErr(new PrintStream(new FileOutputStream(FileDescriptor.err)));

// Check that each line is unique in the output
String[] lines = outputString.split("\\r?\\n");

Set<String> uniqueLines = new HashSet<>();
for (String line : lines) {
uniqueLines.add(line);
}

assertEquals(uniqueLines.size(), lines.length);

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

0 comments on commit 5dde394

Please sign in to comment.