23
23
import static com .github .tomakehurst .wiremock .client .WireMock .putRequestedFor ;
24
24
import static com .github .tomakehurst .wiremock .client .WireMock .urlEqualTo ;
25
25
import static com .github .tomakehurst .wiremock .client .WireMock .verify ;
26
+ import static com .github .tomakehurst .wiremock .client .WireMock .matching ;
26
27
import static com .github .tomakehurst .wiremock .core .WireMockConfiguration .wireMockConfig ;
27
28
import static org .assertj .core .api .Assertions .assertThat ;
28
29
29
- import com .github .tomakehurst .wiremock .junit . WireMockRule ;
30
+ import com .github .tomakehurst .wiremock .junit5 . WireMockExtension ;
30
31
import java .lang .reflect .Field ;
31
- import org .junit .After ;
32
- import org .junit .Before ;
33
- import org .junit .Rule ;
34
- import org .junit .Test ;
32
+ import org .junit .jupiter .api .AfterEach ;
33
+ import org .junit .jupiter .api .BeforeAll ;
34
+ import org .junit .jupiter .api .BeforeEach ;
35
+ import org .junit .jupiter .api .Test ;
36
+ import org .junit .jupiter .api .extension .RegisterExtension ;
35
37
import software .amazon .awssdk .awscore .defaultsmode .DefaultsMode ;
36
38
import software .amazon .awssdk .core .SdkSystemSetting ;
37
- import software .amazon .awssdk .http .SdkHttpClient ;
38
- import software .amazon .awssdk .imds .internal .Ec2MetadataSharedClient ;
39
39
import software .amazon .awssdk .regions .Region ;
40
40
import software .amazon .awssdk .testutils .EnvironmentVariableHelper ;
41
- import software .amazon .awssdk .utils .Lazy ;
42
41
43
42
/**
44
43
* Tests specifically for AutoDefaultsModeDiscovery's migration to use Ec2MetadataClient.
47
46
public class AutoDefaultsModeDiscoveryEc2MetadataClientTest {
48
47
private static final EnvironmentVariableHelper ENVIRONMENT_VARIABLE_HELPER = new EnvironmentVariableHelper ();
49
48
50
- @ Rule
51
- public WireMockRule wireMock = new WireMockRule (wireMockConfig ()
52
- .port (0 )
53
- .httpsPort (-1 ));
49
+ @ RegisterExtension
50
+ static WireMockExtension wireMock = WireMockExtension .newInstance ()
51
+ .options (wireMockConfig ().dynamicPort ().dynamicPort ())
52
+ .configureStaticDsl (true )
53
+ .build ();
54
54
55
- @ Before
56
- public void setup () {
55
+ @ BeforeAll
56
+ static void setupClass () {
57
57
System .setProperty (SdkSystemSetting .AWS_EC2_METADATA_SERVICE_ENDPOINT .property (),
58
- "http://localhost:" + wireMock .port ());
58
+ "http://localhost:" + wireMock .getPort ());
59
+ }
59
60
61
+ @ BeforeEach
62
+ public void setup () {
60
63
clearEnvironmentVariable ("AWS_EXECUTION_ENV" );
61
64
clearEnvironmentVariable ("AWS_REGION" );
62
65
clearEnvironmentVariable ("AWS_DEFAULT_REGION" );
63
66
}
64
67
65
- @ After
68
+ @ AfterEach
66
69
public void cleanup () {
67
70
wireMock .resetAll ();
68
71
ENVIRONMENT_VARIABLE_HELPER .reset ();
69
- System .clearProperty (SdkSystemSetting .AWS_EC2_METADATA_SERVICE_ENDPOINT .property ());
70
72
}
71
73
72
74
// Clear an environment variable by setting it to null.
@@ -82,7 +84,10 @@ private void clearEnvironmentVariable(String name) {
82
84
public void autoDefaultsModeDiscovery_shouldUseSharedHttpClient () throws Exception {
83
85
// Stub successful IMDS responses
84
86
stubFor (put ("/latest/api/token" )
85
- .willReturn (aResponse ().withStatus (200 ).withBody ("test-token" )));
87
+ .willReturn (aResponse ()
88
+ .withStatus (200 )
89
+ .withHeader ("x-aws-ec2-metadata-token-ttl-seconds" , "21600" )
90
+ .withBody ("test-token" )));
86
91
stubFor (get ("/latest/meta-data/placement/region" )
87
92
.willReturn (aResponse ().withStatus (200 ).withBody ("us-east-1" )));
88
93
@@ -92,23 +97,25 @@ public void autoDefaultsModeDiscovery_shouldUseSharedHttpClient() throws Excepti
92
97
// Should return IN_REGION since client region matches IMDS region
93
98
assertThat (result ).isEqualTo (DefaultsMode .IN_REGION );
94
99
95
- // Verify that the shared HTTP client was used
96
- Field sharedClientField = Ec2MetadataSharedClient .class .getDeclaredField ("SHARED_HTTP_CLIENT" );
97
- sharedClientField .setAccessible (true );
98
- Lazy <SdkHttpClient > sharedHttpClient = (Lazy <SdkHttpClient >) sharedClientField .get (null );
99
-
100
- // Verify the shared HTTP client was initialized
101
- assertThat (sharedHttpClient .hasValue ()).isTrue ();
102
-
103
- // Verify IMDS requests were made
100
+ // Verify token request was made
104
101
verify (putRequestedFor (urlEqualTo ("/latest/api/token" )));
105
- verify (getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" )));
102
+
103
+ // Verify region request was made with token header - IMDSv2
104
+ verify (getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" ))
105
+ .withHeader ("x-aws-ec2-metadata-token" , matching ("test-token" )));
106
+
107
+ // Verify no IMDSv1 requests were made
108
+ verify (0 , getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" ))
109
+ .withoutHeader ("x-aws-ec2-metadata-token" ));
106
110
}
107
111
108
112
@ Test
109
113
public void multipleDiscoveryInstances_shouldShareSameHttpClient () throws Exception {
110
114
stubFor (put ("/latest/api/token" )
111
- .willReturn (aResponse ().withStatus (200 ).withBody ("test-token" )));
115
+ .willReturn (aResponse ()
116
+ .withStatus (200 )
117
+ .withHeader ("x-aws-ec2-metadata-token-ttl-seconds" , "21600" )
118
+ .withBody ("test-token" )));
112
119
stubFor (get ("/latest/meta-data/placement/region" )
113
120
.willReturn (aResponse ().withStatus (200 ).withBody ("us-west-2" )));
114
121
@@ -124,16 +131,16 @@ public void multipleDiscoveryInstances_shouldShareSameHttpClient() throws Except
124
131
assertThat (result1 ).isEqualTo (DefaultsMode .CROSS_REGION );
125
132
assertThat (result2 ).isEqualTo (DefaultsMode .CROSS_REGION );
126
133
127
- // Verify shared HTTP client was used
128
- Field sharedClientField = Ec2MetadataSharedClient .class .getDeclaredField ("SHARED_HTTP_CLIENT" );
129
- sharedClientField .setAccessible (true );
130
- Lazy <SdkHttpClient > sharedHttpClient = (Lazy <SdkHttpClient >) sharedClientField .get (null );
131
-
132
- assertThat (sharedHttpClient .hasValue ()).isTrue ();
133
-
134
- // Verify IMDS requests were made
134
+ // Verify token request was made
135
135
verify (putRequestedFor (urlEqualTo ("/latest/api/token" )));
136
- verify (getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" )));
136
+
137
+ // Verify region request was made with token header - IMDSv2
138
+ verify (getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" ))
139
+ .withHeader ("x-aws-ec2-metadata-token" , matching ("test-token" )));
140
+
141
+ // Verify no IMDSv1 requests were made
142
+ verify (0 , getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" ))
143
+ .withoutHeader ("x-aws-ec2-metadata-token" ));
137
144
}
138
145
139
146
@ Test
@@ -174,7 +181,10 @@ public void imdsFailure_shouldFallbackToStandardMode() {
174
181
public void noRetryPolicy_shouldBeUsedByDefault () {
175
182
// Stub token to succeed but region to fail with retryable error
176
183
stubFor (put ("/latest/api/token" )
177
- .willReturn (aResponse ().withStatus (200 ).withBody ("test-token" )));
184
+ .willReturn (aResponse ()
185
+ .withStatus (200 )
186
+ .withHeader ("x-aws-ec2-metadata-token-ttl-seconds" , "21600" )
187
+ .withBody ("test-token" )));
178
188
stubFor (get ("/latest/meta-data/placement/region" )
179
189
.willReturn (aResponse ().withStatus (500 ).withBody ("Internal Server Error" )));
180
190
@@ -186,7 +196,14 @@ public void noRetryPolicy_shouldBeUsedByDefault() {
186
196
187
197
// Verify requests were made once (no retries)
188
198
verify (1 , putRequestedFor (urlEqualTo ("/latest/api/token" )));
189
- verify (1 , getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" )));
199
+
200
+ // Verify region request was made with token header - IMDSv2
201
+ verify (1 , getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" ))
202
+ .withHeader ("x-aws-ec2-metadata-token" , matching ("test-token" )));
203
+
204
+ // Verify no IMDSv1 requests were made
205
+ verify (0 , getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" ))
206
+ .withoutHeader ("x-aws-ec2-metadata-token" ));
190
207
}
191
208
192
209
@ Test
@@ -205,9 +222,16 @@ public void imdsV1Fallback_shouldWorkWhenTokenFails() {
205
222
// Should fall back to IMDSv1 and return IN_REGION
206
223
assertThat (result ).isEqualTo (DefaultsMode .IN_REGION );
207
224
208
- // Verify both token request and region request were made
225
+ // Verify token request was attempted
209
226
verify (putRequestedFor (urlEqualTo ("/latest/api/token" )));
210
- verify (getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" )));
227
+
228
+ // Verify region request was made without token header - IMDSv1 fallback
229
+ verify (getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" ))
230
+ .withoutHeader ("x-aws-ec2-metadata-token" ));
231
+
232
+ // Verify no IMDSv2 requests were made
233
+ verify (0 , getRequestedFor (urlEqualTo ("/latest/meta-data/placement/region" ))
234
+ .withHeader ("x-aws-ec2-metadata-token" , matching (".*" )));
211
235
}
212
236
213
237
@ Test
0 commit comments