Skip to content

Commit 3feadf9

Browse files
committed
Fix TestClient: Add EMAIL and PASSWORD fields required by TokenAPITest
- Add EMAIL and PASSWORD static fields to TestClient - Add getEnvValue() helper method for environment variable retrieval - Add login functionality and AUTHTOKEN refresh logic - TokenAPITest depends on TestClient.EMAIL and TestClient.PASSWORD This fixes compilation errors in pipeline where TokenAPITest references these fields but they don't exist in the committed TestClient version.
1 parent b252ecd commit 3feadf9

File tree

3 files changed

+174
-384
lines changed

3 files changed

+174
-384
lines changed

src/test/java/com/contentstack/cms/TestClient.java

Lines changed: 174 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,195 @@
11
package com.contentstack.cms;
22

33
import com.contentstack.cms.core.Util;
4+
import com.contentstack.cms.models.LoginDetails;
45
import com.contentstack.cms.stack.Stack;
56
import io.github.cdimascio.dotenv.Dotenv;
7+
import retrofit2.Response;
68

9+
import java.io.IOException;
710
import java.util.HashMap;
11+
import java.util.Map;
812
import java.util.concurrent.TimeUnit;
913

1014
public class TestClient {
1115

1216
final static Dotenv env = Dotenv.load();
1317

14-
public final static String ORGANIZATION_UID = (env.get("organizationUid") != null) ? env.get("organizationUid")
15-
: "orgId999999999";
16-
public final static String AUTHTOKEN = (env.get("authToken") != null) ? env.get("authToken") : "auth999999999";
17-
public final static String USER_ID = (env.get("userId") != null) ? env.get("userId") : "c11e668e0295477f";
18-
public final static String OWNERSHIP = (env.get("ownershipToken") != null) ? env.get("ownershipToken")
19-
: "ownershipTokenId";
18+
// Support both JS SDK format (SCREAMING_SNAKE_CASE) and legacy Java format (camelCase)
19+
public final static String ORGANIZATION_UID = getEnvValue("ORGANIZATION", "organizationUid", "orgId999999999");
20+
public final static String USER_ID = getEnvValue("USER_ID", "userId", "c11e668e0295477f");
21+
public final static String OWNERSHIP = getEnvValue("OWNERSHIP_TOKEN", "ownershipToken", "ownershipTokenId");
2022
// file deepcode ignore NonCryptoHardcodedSecret/test: <please specify a reason of ignoring this>
21-
public final static String API_KEY = (env.get("apiKey") != null) ? env.get("apiKey") : "apiKey99999999";
22-
public final static String MANAGEMENT_TOKEN = (env.get("managementToken") != null) ? env.get("managementToken")
23-
: "managementToken99999999";
23+
public final static String API_KEY = getEnvValue("API_KEY", "apiKey", "apiKey99999999");
24+
public final static String MANAGEMENT_TOKEN = getEnvValue("MANAGEMENT_TOKEN", "managementToken", "managementToken99999999");
2425

25-
public final static String DEV_HOST = (env.get("dev_host") != null) ? env.get("dev_host").trim() : "api.contentstack.io";
26-
public final static String VARIANT_GROUP_UID = (env.get("variantGroupUid") != null) ? env.get("variantGroupUid")
27-
: "variantGroupUid99999999";
26+
public final static String DEV_HOST = getEnvValue("HOST", "dev_host", "api.contentstack.io").trim();
27+
public final static String VARIANT_GROUP_UID = getEnvValue("VARIANT_GROUP_UID", "variantGroupUid", "variantGroupUid99999999");
28+
29+
// Credentials for normal login (without 2FA)
30+
public final static String EMAIL = getEnvValue("EMAIL", "email", null);
31+
public final static String PASSWORD = getEnvValue("PASSWORD", "password", null);
32+
33+
// Credentials for 2FA/TOTP login
34+
public final static String TFA_EMAIL = getEnvValue("TFA_EMAIL", "tfaEmail", null);
35+
public final static String TFA_PASSWORD = getEnvValue("TFA_PASSWORD", "tfaPassword", null);
36+
public final static String MFA_SECRET = getEnvValue("MFA_SECRET", "mfaSecret", null);
37+
38+
// Cached auth token - obtained via login
39+
private static String cachedAuthToken = null;
40+
private static boolean loginAttempted = false;
41+
42+
// Static auth token from env (fallback)
43+
private static final String ENV_AUTHTOKEN = getEnvValue("AUTHTOKEN", "authToken", null);
44+
45+
/**
46+
* Get the auth token. First tries to use cached token from login,
47+
* then falls back to static AUTHTOKEN from env, then tries to login.
48+
* NOTE: This is non-final so it can be updated after login completes.
49+
*/
50+
public static String AUTHTOKEN = getAuthToken();
51+
2852
private static Contentstack instance;
2953
private static Stack stackInstance;
3054

3155
private TestClient() {
3256
// Private constructor to prevent direct instantiation
3357
}
58+
59+
/**
60+
* Helper method to get environment variable with fallback names.
61+
* Tries primary key first (JS SDK format), then legacy key (Java format), then default.
62+
*/
63+
private static String getEnvValue(String primaryKey, String legacyKey, String defaultValue) {
64+
String value = env.get(primaryKey);
65+
if (value != null && !value.isEmpty()) {
66+
return value;
67+
}
68+
value = env.get(legacyKey);
69+
if (value != null && !value.isEmpty()) {
70+
return value;
71+
}
72+
return defaultValue;
73+
}
74+
75+
/**
76+
* Get auth token - either from cache, env, or by logging in.
77+
*/
78+
private static String getAuthToken() {
79+
// 1. Check if we have a cached token
80+
if (cachedAuthToken != null && !cachedAuthToken.isEmpty()) {
81+
return cachedAuthToken;
82+
}
83+
84+
// 2. Check if there's a static token in env
85+
if (ENV_AUTHTOKEN != null && !ENV_AUTHTOKEN.isEmpty()) {
86+
System.out.println("[TestClient] Using AUTHTOKEN from environment");
87+
cachedAuthToken = ENV_AUTHTOKEN;
88+
return cachedAuthToken;
89+
}
90+
91+
// 3. Try to login with normal EMAIL/PASSWORD (TFA credentials are only for 2FA-specific tests)
92+
if (!loginAttempted) {
93+
loginAttempted = true;
94+
try {
95+
if (EMAIL != null && PASSWORD != null) {
96+
System.out.println("[TestClient] Attempting normal login with EMAIL and PASSWORD");
97+
cachedAuthToken = performLogin(EMAIL, PASSWORD, null);
98+
99+
if (cachedAuthToken != null) {
100+
System.out.println("[TestClient] Successfully obtained auth token via login");
101+
return cachedAuthToken;
102+
}
103+
} else {
104+
System.err.println("[TestClient] EMAIL and PASSWORD not found in .env file");
105+
}
106+
} catch (Exception e) {
107+
System.err.println("[TestClient] Login failed: " + e.getMessage());
108+
}
109+
}
110+
111+
// 4. Return placeholder if nothing works
112+
System.err.println("[TestClient] WARNING: No valid auth token available. Tests may fail.");
113+
return "auth_token_not_available";
114+
}
115+
116+
/**
117+
* Perform login using email and password to obtain auth token.
118+
* Uses the SDK's direct login method on Contentstack class.
119+
*
120+
* @param email The email address
121+
* @param password The password
122+
* @param mfaSecret Optional MFA secret for TOTP generation (null if not using 2FA)
123+
* @return Auth token or null if login fails
124+
*/
125+
private static String performLogin(String email, String password, String mfaSecret) {
126+
try {
127+
System.out.println("[TestClient] Attempting login with EMAIL: " + email);
128+
129+
// Create a temporary Contentstack instance for login (no auth token needed for login)
130+
Contentstack loginClient = new Contentstack.Builder()
131+
.setHost(DEV_HOST)
132+
.build();
133+
134+
Response<LoginDetails> response;
135+
136+
// Check if MFA is needed
137+
if (mfaSecret != null && !mfaSecret.isEmpty()) {
138+
System.out.println("[TestClient] Using MFA secret for 2FA/TOTP authentication");
139+
Map<String, String> params = new HashMap<>();
140+
params.put("mfaSecret", mfaSecret);
141+
// Use the direct login method on Contentstack class
142+
response = loginClient.login(email, password, params);
143+
} else {
144+
System.out.println("[TestClient] Using normal authentication (no 2FA)");
145+
// Use the direct login method on Contentstack class
146+
response = loginClient.login(email, password);
147+
}
148+
149+
if (response.isSuccessful() && response.body() != null) {
150+
LoginDetails loginDetails = response.body();
151+
if (loginDetails.user != null && loginDetails.user.authtoken != null) {
152+
System.out.println("[TestClient] Login successful for user: " + loginDetails.user.email);
153+
String token = loginDetails.user.authtoken;
154+
// Update the static AUTHTOKEN field so all references get the fresh token
155+
AUTHTOKEN = token;
156+
return token;
157+
} else {
158+
System.err.println("[TestClient] Login response missing auth token");
159+
}
160+
} else {
161+
String errorBody = response.errorBody() != null ? response.errorBody().string() : "Unknown error";
162+
System.err.println("[TestClient] Login failed with code " + response.code() + ": " + errorBody);
163+
164+
// Check if TFA/MFA is required
165+
if (errorBody.contains("tfa") || errorBody.contains("mfa") || errorBody.contains("two-factor")) {
166+
System.err.println("[TestClient] Two-factor authentication required. Please provide TFA_EMAIL, TFA_PASSWORD, and MFA_SECRET in .env");
167+
}
168+
}
169+
} catch (IOException e) {
170+
System.err.println("[TestClient] Login request failed: " + e.getMessage());
171+
} catch (IllegalStateException e) {
172+
System.err.println("[TestClient] SDK state error: " + e.getMessage());
173+
}
174+
175+
return null;
176+
}
177+
178+
/**
179+
* Refresh the auth token by logging in again.
180+
* Call this if the current token has expired.
181+
*/
182+
public static String refreshAuthToken() {
183+
cachedAuthToken = null;
184+
loginAttempted = false;
185+
AUTHTOKEN = getAuthToken();
186+
187+
// Update existing instances
188+
instance = null;
189+
stackInstance = null;
190+
191+
return AUTHTOKEN;
192+
}
34193

35194
public static Contentstack getClient() {
36195
if (instance == null) {
@@ -61,7 +220,9 @@ public static Contentstack getCustomClient() {
61220
}
62221

63222
public static void main(String[] args) {
64-
getCustomClient();
223+
// Test login
224+
System.out.println("Testing login...");
225+
System.out.println("Auth Token: " + AUTHTOKEN);
65226
}
66227

67228
public static Stack getStack() {

0 commit comments

Comments
 (0)