|
18 | 18 |
|
19 | 19 | package org.apache.hadoop.fs.azurebfs.services; |
20 | 20 |
|
21 | | -import org.apache.hadoop.fs.Path; |
22 | | -import org.apache.hadoop.fs.azurebfs.contracts.services.AzureServiceErrorCode; |
23 | | -import org.apache.hadoop.fs.azurebfs.utils.TracingContext; |
| 21 | +import java.io.IOException; |
| 22 | +import java.net.HttpURLConnection; |
| 23 | +import java.net.URL; |
| 24 | +import java.util.List; |
| 25 | +import java.util.Optional; |
| 26 | +import javax.net.ssl.HttpsURLConnection; |
| 27 | + |
| 28 | +import org.apache.hadoop.fs.azurebfs.AbfsStatistic; |
| 29 | +import org.apache.hadoop.fs.azurebfs.AzureBlobFileSystemStore; |
24 | 30 | import org.assertj.core.api.Assertions; |
25 | | -import org.junit.Assert; |
26 | 31 | import org.junit.Assume; |
27 | 32 | import org.junit.Test; |
28 | 33 | import org.mockito.Mockito; |
29 | 34 | import org.slf4j.Logger; |
30 | 35 | import org.slf4j.LoggerFactory; |
31 | 36 |
|
| 37 | +import org.apache.hadoop.fs.Path; |
| 38 | + |
32 | 39 | import org.apache.hadoop.fs.azurebfs.AbstractAbfsIntegrationTest; |
33 | 40 | import org.apache.hadoop.fs.azurebfs.AzureBlobFileSystem; |
34 | 41 | import org.apache.hadoop.fs.azurebfs.contracts.exceptions.AbfsRestOperationException; |
35 | 42 | import org.apache.hadoop.fs.azurebfs.contracts.exceptions.AzureBlobFileSystemException; |
36 | | - |
37 | | -import javax.net.ssl.HttpsURLConnection; |
38 | | - |
39 | | -import java.io.IOException; |
40 | | -import java.net.HttpURLConnection; |
41 | | -import java.net.URL; |
42 | | -import java.util.List; |
| 43 | +import org.apache.hadoop.fs.azurebfs.utils.TracingContext; |
43 | 44 |
|
44 | 45 | import static org.apache.hadoop.fs.azurebfs.constants.AbfsHttpConstants.HTTP_METHOD_PUT; |
45 | 46 | import static org.apache.hadoop.fs.azurebfs.contracts.services.AzureServiceErrorCode.RENAME_DESTINATION_PARENT_PATH_NOT_FOUND; |
46 | | -import static org.apache.hadoop.fs.azurebfs.contracts.services.AzureServiceErrorCode.SOURCE_PATH_NOT_FOUND; |
47 | 47 | import static org.apache.hadoop.test.LambdaTestUtils.intercept; |
48 | 48 | import static org.mockito.ArgumentMatchers.nullable; |
49 | 49 | import static org.mockito.Mockito.doReturn; |
@@ -203,45 +203,100 @@ AbfsClient getMockAbfsClient() throws IOException { |
203 | 203 | @Test |
204 | 204 | public void testRenameRecoverySrcDestEtagSame() throws IOException { |
205 | 205 | AzureBlobFileSystem fs = getFileSystem(); |
| 206 | + AzureBlobFileSystemStore abfsStore = fs.getAbfsStore(); |
206 | 207 | TracingContext testTracingContext = getTestTracingContext(fs, false); |
207 | 208 |
|
208 | 209 | Assume.assumeTrue(fs.getAbfsStore().getIsNamespaceEnabled(testTracingContext)); |
209 | 210 |
|
210 | 211 | AbfsClient mockClient = getMockAbfsClient(); |
211 | 212 |
|
| 213 | + // simulating eTag check returns true |
| 214 | + // source and destination eTag equal |
| 215 | + // |
| 216 | + Mockito.doReturn(true).when(mockClient).isSourceDestEtagEqual( |
| 217 | + nullable(String.class), nullable(AbfsHttpOperation.class) |
| 218 | + ); |
212 | 219 |
|
213 | 220 | String path1 = "/dummyFile1"; |
214 | | - String path2 = "/dummyFile2"; |
215 | | - |
| 221 | + String path2 = "dummyFile2"; |
216 | 222 | fs.create(new Path(path1)); |
217 | 223 | fs.create(new Path(path2)); |
218 | 224 |
|
| 225 | + abfsStore.setClient(mockClient); |
| 226 | + |
| 227 | + // checking correct count in AbfsCounters |
| 228 | + AbfsCounters counter = mockClient.getAbfsCounters(); |
| 229 | + Long connMadeBeforeRename = counter.getIOStatistics().counters(). |
| 230 | + get(AbfsStatistic.CONNECTIONS_MADE.getStatName()); |
| 231 | + Long renamePathAttemptsBeforeRename = counter.getIOStatistics().counters(). |
| 232 | + get(AbfsStatistic.RENAME_PATH_ATTEMPTS.getStatName()); |
| 233 | + |
219 | 234 | // 404 and retry, send sourceEtag as null |
220 | 235 | // source eTag matches -> rename should pass even when execute throws exception |
221 | | - mockClient.renamePath(path1, path1, null, testTracingContext, null, false); |
| 236 | + fs.rename(new Path(path1), new Path(path2)); |
| 237 | + |
| 238 | + // validating stat counters after rename |
| 239 | + Long connMadeAfterRename = counter.getIOStatistics().counters(). |
| 240 | + get(AbfsStatistic.CONNECTIONS_MADE.getStatName()); |
| 241 | + Long renamePathAttemptsAfterRename = counter.getIOStatistics().counters(). |
| 242 | + get(AbfsStatistic.RENAME_PATH_ATTEMPTS.getStatName()); |
| 243 | + |
| 244 | + // 4 calls should have happened in total for rename |
| 245 | + // 1 -> original rename rest call, 2 -> first retry, |
| 246 | + // +2 for getPathStatus calls |
| 247 | + assertEquals(Long.valueOf(connMadeBeforeRename+4), connMadeAfterRename); |
| 248 | + |
| 249 | + // the RENAME_PATH_ATTEMPTS stat should be incremented by 1 |
| 250 | + // retries happen internally within AbfsRestOperation execute() |
| 251 | + // the stat for RENAME_PATH_ATTEMPTS is updated only once before execute() is called |
| 252 | + assertEquals(Long.valueOf(renamePathAttemptsBeforeRename+1), renamePathAttemptsAfterRename); |
| 253 | + |
222 | 254 | } |
223 | 255 |
|
224 | 256 | @Test |
225 | | - public void testRenameRecoverySrcDestEtagDifferent() throws IOException { |
| 257 | + public void testRenameRecoverySrcDestEtagDifferent() throws Exception { |
226 | 258 | AzureBlobFileSystem fs = getFileSystem(); |
| 259 | + AzureBlobFileSystemStore abfsStore = fs.getAbfsStore(); |
227 | 260 | TracingContext testTracingContext = getTestTracingContext(fs, false); |
228 | 261 |
|
229 | 262 | Assume.assumeTrue(fs.getAbfsStore().getIsNamespaceEnabled(testTracingContext)); |
230 | 263 |
|
231 | | - AbfsClient spyClient = getMockAbfsClient(); |
| 264 | + AbfsClient mockClient = getMockAbfsClient(); |
232 | 265 |
|
233 | 266 | String path1 = "/dummyFile1"; |
234 | 267 | String path2 = "/dummyFile2"; |
235 | 268 |
|
236 | 269 | fs.create(new Path(path1)); |
237 | 270 | fs.create(new Path(path2)); |
238 | 271 |
|
239 | | - // source eTag does not match -> throw exception |
240 | | - try { |
241 | | - spyClient.renamePath(path1, path2,null, testTracingContext, null, false); |
242 | | - } catch (AbfsRestOperationException e) { |
243 | | - Assert.assertEquals(SOURCE_PATH_NOT_FOUND, e.getErrorCode()); |
244 | | - } |
| 272 | + abfsStore.setClient(mockClient); |
| 273 | + |
| 274 | + // checking correct count in AbfsCounters |
| 275 | + AbfsCounters counter = mockClient.getAbfsCounters(); |
| 276 | + Long connMadeBeforeRename = counter.getIOStatistics().counters(). |
| 277 | + get(AbfsStatistic.CONNECTIONS_MADE.getStatName()); |
| 278 | + Long renamePathAttemptsBeforeRename = counter.getIOStatistics().counters(). |
| 279 | + get(AbfsStatistic.RENAME_PATH_ATTEMPTS.getStatName()); |
| 280 | + |
| 281 | + // source eTag does not match -> rename should be a failure |
| 282 | + boolean renameResult = fs.rename(new Path(path1), new Path(path2)); |
| 283 | + assertEquals(false, renameResult); |
| 284 | + |
| 285 | + // validating stat counters after rename |
| 286 | + Long connMadeAfterRename = counter.getIOStatistics().counters(). |
| 287 | + get(AbfsStatistic.CONNECTIONS_MADE.getStatName()); |
| 288 | + Long renamePathAttemptsAfterRename = counter.getIOStatistics().counters(). |
| 289 | + get(AbfsStatistic.RENAME_PATH_ATTEMPTS.getStatName()); |
| 290 | + |
| 291 | + // 4 calls should have happened in total for rename |
| 292 | + // 1 -> original rename rest call, 2 -> first retry, |
| 293 | + // +2 for getPathStatus calls |
| 294 | + assertEquals(Long.valueOf(connMadeBeforeRename+4), connMadeAfterRename); |
| 295 | + |
| 296 | + // the RENAME_PATH_ATTEMPTS stat should be incremented by 1 |
| 297 | + // retries happen internally within AbfsRestOperation execute() |
| 298 | + // the stat for RENAME_PATH_ATTEMPTS is updated only once before execute() is called |
| 299 | + assertEquals(Long.valueOf(renamePathAttemptsBeforeRename+1), renamePathAttemptsAfterRename); |
245 | 300 | } |
246 | 301 |
|
247 | 302 | /** |
|
0 commit comments