11package com .lambdatest .selenium .agent ;
22
3- import java .net .URL ;
43import java .util .Map ;
54
6- import org .openqa .selenium .Capabilities ;
75import org .openqa .selenium .MutableCapabilities ;
86
97import com .lambdatest .selenium .lambdatest .LambdaTestConfig ;
8+ import com .lambdatest .selenium .lambdatest .SessionThreadManager ;
109
11- import net .bytebuddy .asm .Advice ;
12-
10+ /**
11+ * ByteBuddy Advice for RemoteWebDriver constructor interception.
12+ *
13+ * This class enhances capabilities before RemoteWebDriver is created,
14+ * adding LambdaTest-specific configuration from lambdatest.yml.
15+ */
1316public class RemoteWebDriverAdvice {
1417
1518 // Track which capabilities objects have been enhanced to prevent double-processing
@@ -24,77 +27,16 @@ public class RemoteWebDriverAdvice {
2427
2528 // Flag to warn only once about missing tunnel (avoid spam in parallel execution)
2629 private static volatile boolean warnedAboutMissingTunnel = false ;
27-
28- @ Advice .OnMethodEnter
29- static void onEnter (@ Advice .Argument (0 ) URL hubUrl , @ Advice .Argument (1 ) Capabilities capabilities ) {
30-
31-
32- // Check if capabilities can be modified
33- if (!(capabilities instanceof MutableCapabilities )) {
34- return ;
35- }
36-
37- MutableCapabilities mutableCapabilities = (MutableCapabilities ) capabilities ;
38-
39- // Only intercept if it's a LambdaTest URL or if lt:options is present
40- boolean isLambdaTestUrl = hubUrl .toString ().contains ("lambdatest.com" );
41- boolean hasLtOptions = capabilities .asMap ().containsKey ("lt:options" );
42-
43- if (isLambdaTestUrl || hasLtOptions ) {
44-
45- try {
46- // Check if SDK capabilities are stored by TestNG listener
47- String storedCapabilities = System .getProperty ("lambdatest.sdk.capabilities" );
48- if (storedCapabilities != null ) {
49-
50- // Load configuration from lambdatest.yml
51- LambdaTestConfig config = LambdaTestConfig .getInstance ();
52- Map <String , Object > sdkCapMap = config .getCapabilitiesFromYaml ().asMap ();
53- Map <String , Object > userCapMap = mutableCapabilities .asMap ();
54-
55- // Add missing capabilities from SDK config
56- for (Map .Entry <String , Object > entry : sdkCapMap .entrySet ()) {
57- String key = entry .getKey ();
58- Object value = entry .getValue ();
59-
60- if (!userCapMap .containsKey (key )) {
61- mutableCapabilities .setCapability (key , value );
62- }
63- }
64-
65- // Ensure lt:options contains credentials
66- if (userCapMap .containsKey ("lt:options" )) {
67- Map <String , Object > ltOptions = (Map <String , Object >) userCapMap .get ("lt:options" );
68- if (sdkCapMap .containsKey ("lt:options" )) {
69- Map <String , Object > sdkLtOptions = (Map <String , Object >) sdkCapMap .get ("lt:options" );
70- ltOptions .putAll (sdkLtOptions );
71- }
72- }
73-
74-
75- } else {
76- }
77-
78- } catch (Exception e ) {
79- }
80- } else {
81- }
82- }
83-
84- /**
85- * Set flag to indicate SDK is creating RemoteWebDriver internally.
86- * This prevents recursive enhancement.
87- */
88- public static void setInternalDriverCreation (boolean value ) {
89- internalDriverCreation .set (value );
90- }
9130
31+ // Session-thread manager for validating thread affinity
32+ private static final SessionThreadManager sessionThreadManager = SessionThreadManager .getInstance ();
33+
9234 /**
9335 * Static method to enhance capabilities that can be called from ASM bytecode.
94- * This is the ACTUAL method that gets called by the agent's bytecode transformation .
36+ * This is called by RemoteWebDriverBytecodeTransformer .
9537 */
9638 public static void enhanceCapabilities (MutableCapabilities capabilities ) {
97- // Skip if this is an internal SDK driver creation (e.g., from ChromeDriverAdvice)
39+ // Skip if this is an internal SDK driver creation
9840 if (internalDriverCreation .get ()) {
9941 System .out .println ("[LambdaTest SDK RemoteWebDriverAdvice] Skipping enhancement for internal driver creation" );
10042 return ;
@@ -114,35 +56,41 @@ public static void enhanceCapabilities(MutableCapabilities capabilities) {
11456 }
11557 processedCapabilities .add (capabilitiesHash );
11658
59+ // Log thread information for debugging
60+ long threadId = Thread .currentThread ().getId ();
61+ String threadName = Thread .currentThread ().getName ();
62+ System .out .println (String .format (
63+ "[LambdaTest SDK RemoteWebDriverAdvice] Enhancing capabilities on thread %d/%s" ,
64+ threadId , threadName ));
65+
11766 // Set re-entrance guard
11867 isEnhancing .set (true );
11968
12069 try {
121-
12270 // Load configuration from lambdatest.yml
12371 LambdaTestConfig config = LambdaTestConfig .getInstance ();
12472 Map <String , Object > sdkCapMap = config .getCapabilitiesFromYaml ().asMap ();
12573 Map <String , Object > userCapMap = capabilities .asMap ();
12674
127- // Add missing capabilities from SDK config
128- for (Map .Entry <String , Object > entry : sdkCapMap .entrySet ()) {
129- String key = entry .getKey ();
130- Object value = entry .getValue ();
131-
132- if (!userCapMap .containsKey (key )) {
133- capabilities .setCapability (key , value );
134- }
75+ // Add missing capabilities from SDK config
76+ for (Map .Entry <String , Object > entry : sdkCapMap .entrySet ()) {
77+ String key = entry .getKey ();
78+ Object value = entry .getValue ();
79+
80+ if (!userCapMap .containsKey (key )) {
81+ capabilities .setCapability (key , value );
82+ }
83+ }
84+
85+ // Ensure lt:options contains credentials
86+ if (userCapMap .containsKey ("lt:options" )) {
87+ Map <String , Object > ltOptions = (Map <String , Object >) userCapMap .get ("lt:options" );
88+ if (sdkCapMap .containsKey ("lt:options" )) {
89+ Map <String , Object > sdkLtOptions = (Map <String , Object >) sdkCapMap .get ("lt:options" );
90+ ltOptions .putAll (sdkLtOptions );
13591 }
13692
137- // Ensure lt:options contains credentials
138- if (userCapMap .containsKey ("lt:options" )) {
139- Map <String , Object > ltOptions = (Map <String , Object >) userCapMap .get ("lt:options" );
140- if (sdkCapMap .containsKey ("lt:options" )) {
141- Map <String , Object > sdkLtOptions = (Map <String , Object >) sdkCapMap .get ("lt:options" );
142- ltOptions .putAll (sdkLtOptions );
143- }
144-
145- // Check if tunnel is enabled in YAML/capabilities only (no environment variable check)
93+ // Check if tunnel is enabled in capabilities
14694 if (ltOptions .containsKey ("tunnel" )) {
14795 Object tunnelValue = ltOptions .get ("tunnel" );
14896 boolean tunnelInCapabilities = false ;
@@ -154,7 +102,7 @@ public static void enhanceCapabilities(MutableCapabilities capabilities) {
154102 }
155103
156104 if (tunnelInCapabilities ) {
157- // Tunnel is enabled in YAML - check if it's running and add tunnel name
105+ // Tunnel is enabled - check if it's running and add tunnel name
158106 try {
159107 com .lambdatest .selenium .tunnel .TunnelManager tunnelManager =
160108 com .lambdatest .selenium .tunnel .TunnelManager .getInstance ();
@@ -165,7 +113,7 @@ public static void enhanceCapabilities(MutableCapabilities capabilities) {
165113 ltOptions .put ("tunnelName" , tunnelName );
166114 }
167115 } else {
168- // Tunnel configured in YAML but not running - warn but allow test to continue
116+ // Tunnel configured but not running - warn once
169117 if (!warnedAboutMissingTunnel ) {
170118 warnedAboutMissingTunnel = true ;
171119 System .err .println ("[LambdaTest SDK] WARNING: tunnel=true in YAML but no tunnel is running." );
@@ -177,22 +125,32 @@ public static void enhanceCapabilities(MutableCapabilities capabilities) {
177125 }
178126 }
179127 }
180- }
128+ }
181129
182130 } catch (Exception e ) {
183131 System .err .println ("[LambdaTest SDK RemoteWebDriverAdvice] Error enhancing capabilities: " + e .getMessage ());
184132 e .printStackTrace ();
185133 } finally {
186- // Always clear the re-entrance guard and clean up ThreadLocal
134+ // Always clear the re-entrance guard
187135 isEnhancing .set (false );
188- // Clean up ThreadLocal to prevent memory leaks in long-running applications
189- // Note: We don't remove internalDriverCreation here as it might still be needed
136+
137+ // Log completion with thread info
138+ System .out .println (String .format (
139+ "[LambdaTest SDK RemoteWebDriverAdvice] Capability enhancement completed on thread %d/%s" ,
140+ Thread .currentThread ().getId (), Thread .currentThread ().getName ()));
190141 }
191142 }
192143
144+ /**
145+ * Set flag to indicate SDK is creating RemoteWebDriver internally.
146+ * This prevents recursive enhancement.
147+ */
148+ public static void setInternalDriverCreation (boolean value ) {
149+ internalDriverCreation .set (value );
150+ }
151+
193152 /**
194153 * Clean up all ThreadLocal variables to prevent memory leaks.
195- * Should be called after all tests complete.
196154 */
197155 public static void cleanupThreadLocals () {
198156 try {
@@ -202,4 +160,5 @@ public static void cleanupThreadLocals() {
202160 // Ignore cleanup errors
203161 }
204162 }
205- }
163+ }
164+
0 commit comments