Skip to content

Commit 28a6f98

Browse files
authored
fix: stats fix (#816)
* fix: stats fix * fix: pr comments * fix: disable for in mem * fix: pr comments
1 parent 3cf7fdc commit 28a6f98

File tree

5 files changed

+178
-9
lines changed

5 files changed

+178
-9
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [unreleased]
99

10+
## [6.0.13] - 2023-09-15
11+
12+
- Fixes paid stats reporting for multitenancy
13+
1014
## [6.0.12] - 2023-09-04
1115

1216
- Fixes randomly occurring `serialization error for concurrent update` in `verifySession` API

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ compileTestJava { options.encoding = "UTF-8" }
1919
// }
2020
//}
2121

22-
version = "6.0.12"
22+
version = "6.0.13"
2323

2424

2525
repositories {

ee/src/main/java/io/supertokens/ee/EEFeatureFlag.java

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public class EEFeatureFlag implements io.supertokens.featureflag.EEFeatureFlagIn
5959
public static final String FEATURE_FLAG_KEY_IN_DB = "FEATURE_FLAG";
6060
public static final String LICENSE_KEY_IN_DB = "LICENSE_KEY";
6161

62+
private static List<JsonObject> licenseCheckRequests = new ArrayList<>();
63+
6264
private static final String[] ENTERPRISE_THIRD_PARTY_IDS = new String[] {
6365
"google-workspaces",
6466
"okta",
@@ -151,6 +153,12 @@ public void syncFeatureFlagWithLicenseKey()
151153
licenseKey = this.getLicenseKeyFromDb();
152154
this.isLicenseKeyPresent = true;
153155
} catch (NoLicenseKeyFoundException ex) {
156+
try {
157+
licenseKey = this.getRootLicenseKeyFromDb();
158+
verifyLicenseKey(licenseKey); // also sends paid user stats for the app
159+
} catch (NoLicenseKeyFoundException | InvalidLicenseKeyException ex2) {
160+
// follow through below
161+
}
154162
this.isLicenseKeyPresent = false;
155163
this.setEnabledEEFeaturesInDb(new EE_FEATURES[]{});
156164
return;
@@ -394,6 +402,9 @@ private EE_FEATURES[] doServerCall(String licenseKey)
394402
json.addProperty("licenseKey", licenseKey);
395403
json.addProperty("superTokensVersion", Version.getVersion(main).getCoreVersion());
396404
json.add("paidFeatureUsageStats", this.getPaidFeatureStats());
405+
if (Main.isTesting) {
406+
licenseCheckRequests.add(json);
407+
}
397408
ProcessState.getInstance(main).addState(ProcessState.PROCESS_STATE.LICENSE_KEY_CHECK_NETWORK_CALL, null);
398409
JsonObject licenseCheckResponse = HttpRequest.sendJsonPOSTRequest(this.main, REQUEST_ID,
399410
"https://api.supertokens.io/0/st/license/check",
@@ -476,17 +487,40 @@ private void removeLicenseKeyFromDb() throws StorageQueryException, TenantOrAppN
476487
new KeyValueInfo(LICENSE_KEY_IN_DB_NOT_PRESENT_VALUE));
477488
}
478489

479-
@Override
480-
public String getLicenseKeyFromDb()
481-
throws NoLicenseKeyFoundException, StorageQueryException, TenantOrAppNotFoundException {
482-
Logging.debug(main, appIdentifier.getAsPublicTenantIdentifier(), "Attempting to fetch license key from db");
483-
KeyValueInfo info = StorageLayer.getStorage(this.appIdentifier.getAsPublicTenantIdentifier(), main)
484-
.getKeyValue(this.appIdentifier.getAsPublicTenantIdentifier(), LICENSE_KEY_IN_DB);
490+
private String getLicenseKeyInDb(TenantIdentifier tenantIdentifier)
491+
throws TenantOrAppNotFoundException, StorageQueryException, NoLicenseKeyFoundException {
492+
Logging.debug(main, tenantIdentifier, "Attempting to fetch license key from db");
493+
KeyValueInfo info = StorageLayer.getStorage(tenantIdentifier, main)
494+
.getKeyValue(tenantIdentifier, LICENSE_KEY_IN_DB);
485495
if (info == null || info.value.equals(LICENSE_KEY_IN_DB_NOT_PRESENT_VALUE)) {
486-
Logging.debug(main, appIdentifier.getAsPublicTenantIdentifier(), "No license key found in db");
496+
Logging.debug(main, tenantIdentifier, "No license key found in db");
487497
throw new NoLicenseKeyFoundException();
488498
}
489-
Logging.debug(main, appIdentifier.getAsPublicTenantIdentifier(), "Fetched license key from db: " + info.value);
499+
Logging.debug(main, tenantIdentifier, "Fetched license key from db: " + info.value);
490500
return info.value;
491501
}
502+
503+
@Override
504+
public String getLicenseKeyFromDb()
505+
throws NoLicenseKeyFoundException, StorageQueryException, TenantOrAppNotFoundException {
506+
return getLicenseKeyInDb(appIdentifier.getAsPublicTenantIdentifier());
507+
}
508+
509+
private String getRootLicenseKeyFromDb()
510+
throws TenantOrAppNotFoundException, StorageQueryException, NoLicenseKeyFoundException {
511+
return getLicenseKeyInDb(TenantIdentifier.BASE_TENANT);
512+
}
513+
514+
@TestOnly
515+
public static List<JsonObject> getLicenseCheckRequests() {
516+
assert (Main.isTesting);
517+
return licenseCheckRequests;
518+
}
519+
520+
@TestOnly
521+
public static void resetLisenseCheckRequests() {
522+
licenseCheckRequests = new ArrayList<>();
523+
}
524+
525+
492526
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package io.supertokens.ee.test;
2+
3+
import com.google.gson.JsonArray;
4+
import com.google.gson.JsonElement;
5+
import com.google.gson.JsonObject;
6+
import io.supertokens.ProcessState;
7+
import io.supertokens.cronjobs.CronTaskTest;
8+
import io.supertokens.ee.EEFeatureFlag;
9+
import io.supertokens.ee.cronjobs.EELicenseCheck;
10+
import io.supertokens.ee.test.httpRequest.HttpRequestForTesting;
11+
import io.supertokens.featureflag.FeatureFlag;
12+
import io.supertokens.multitenancy.Multitenancy;
13+
import io.supertokens.pluginInterface.multitenancy.*;
14+
import io.supertokens.storageLayer.StorageLayer;
15+
import io.supertokens.webserver.WebserverAPI;
16+
import org.junit.*;
17+
import org.junit.rules.TestRule;
18+
19+
import java.util.HashSet;
20+
import java.util.List;
21+
import java.util.Set;
22+
23+
public class TestMultitenancyStats {
24+
@Rule
25+
public TestRule watchman = Utils.getOnFailure();
26+
27+
@AfterClass
28+
public static void afterTesting() {
29+
Utils.afterTesting();
30+
}
31+
32+
@Before
33+
public void beforeEach() {
34+
Utils.reset();
35+
FeatureFlag.clearURLClassLoader();
36+
}
37+
38+
private final String OPAQUE_KEY_WITH_MULTITENANCY_FEATURE = "ijaleljUd2kU9XXWLiqFYv5br8nutTxbyBqWypQdv2N-" +
39+
"BocoNriPrnYQd0NXPm8rVkeEocN9ayq0B7c3Pv-BTBIhAZSclXMlgyfXtlwAOJk=9BfESEleW6LyTov47dXu";
40+
41+
@Test
42+
public void testPaidStatsIsSentForAllAppsInMultitenancy() throws Exception {
43+
String[] args = {"../../"};
44+
45+
TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
46+
CronTaskTest.getInstance(process.main).setIntervalInSeconds(EELicenseCheck.RESOURCE_KEY, 1);
47+
Assert.assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
48+
49+
if (StorageLayer.isInMemDb(process.main)) {
50+
// cause we keep all features enabled in memdb anyway
51+
return;
52+
}
53+
54+
{
55+
// Add the license
56+
JsonObject requestBody = new JsonObject();
57+
58+
requestBody.addProperty("licenseKey", OPAQUE_KEY_WITH_MULTITENANCY_FEATURE);
59+
60+
HttpRequestForTesting.sendJsonPUTRequest(process.getProcess(), "",
61+
"http://localhost:3567/ee/license",
62+
requestBody, 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");
63+
}
64+
65+
{
66+
// Create tenants and apps
67+
JsonObject config = new JsonObject();
68+
StorageLayer.getStorage(new TenantIdentifier(null, null, null), process.getProcess())
69+
.modifyConfigToAddANewUserPoolForTesting(config, 1);
70+
71+
Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
72+
new TenantIdentifier("127.0.0.1", null, null),
73+
new EmailPasswordConfig(true),
74+
new ThirdPartyConfig(true, null),
75+
new PasswordlessConfig(true),
76+
config
77+
), false);
78+
79+
Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
80+
new TenantIdentifier("127.0.0.1", "a1", null),
81+
new EmailPasswordConfig(true),
82+
new ThirdPartyConfig(true, null),
83+
new PasswordlessConfig(true),
84+
config
85+
), false);
86+
87+
Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
88+
new TenantIdentifier("127.0.0.1", "a1", "t1"),
89+
new EmailPasswordConfig(true),
90+
new ThirdPartyConfig(true, null),
91+
new PasswordlessConfig(true),
92+
config
93+
), false);
94+
}
95+
96+
Thread.sleep(2000); // Let all the cron tasks run
97+
98+
List<JsonObject> requests = EEFeatureFlag.getLicenseCheckRequests();
99+
Set<TenantIdentifier> tenantIdentifiers = new HashSet<>();
100+
101+
for (JsonObject request : requests) {
102+
if (request.has("paidFeatureUsageStats")) {
103+
JsonObject paidStats = request.getAsJsonObject("paidFeatureUsageStats");
104+
if (paidStats.has("multi_tenancy")) {
105+
JsonObject mtStats = paidStats.getAsJsonObject("multi_tenancy");
106+
String cud = mtStats.get("connectionUriDomain").getAsString();
107+
String appId = mtStats.get("appId").getAsString();
108+
109+
JsonArray tenants = mtStats.get("tenants").getAsJsonArray();
110+
for (JsonElement tenantElem : tenants) {
111+
JsonObject tenant = tenantElem.getAsJsonObject();
112+
String tenantId = tenant.get("tenantId").getAsString();
113+
114+
tenantIdentifiers.add(new TenantIdentifier(cud, appId, tenantId));
115+
}
116+
}
117+
}
118+
}
119+
120+
Assert.assertEquals(tenantIdentifiers.size(), 4);
121+
Assert.assertTrue(tenantIdentifiers.contains(new TenantIdentifier(null, null, null)));
122+
Assert.assertTrue(tenantIdentifiers.contains(new TenantIdentifier("127.0.0.1", null, null)));
123+
Assert.assertTrue(tenantIdentifiers.contains(new TenantIdentifier("127.0.0.1", "a1", null)));
124+
Assert.assertTrue(tenantIdentifiers.contains(new TenantIdentifier("127.0.0.1", "a1", "t1")));
125+
126+
process.kill();
127+
Assert.assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
128+
}
129+
}

ee/src/test/java/io/supertokens/ee/test/Utils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.supertokens.ee.test;
22

33
import io.supertokens.Main;
4+
import io.supertokens.ee.EEFeatureFlag;
45
import io.supertokens.pluginInterface.PluginInterfaceTesting;
56
import io.supertokens.storageLayer.StorageLayer;
67
import org.apache.tomcat.util.http.fileupload.FileUtils;
@@ -51,6 +52,7 @@ public static void reset() {
5152
Main.isTesting = true;
5253
PluginInterfaceTesting.isTesting = true;
5354
Main.makeConsolePrintSilent = true;
55+
EEFeatureFlag.resetLisenseCheckRequests();
5456
String installDir = "../../";
5557
try {
5658

0 commit comments

Comments
 (0)