Skip to content

Commit 3559935

Browse files
authored
[datalake] Fix path rename operations (#653)
* fix apth rename operation and improve tests * remove commented code * pr comments
1 parent 967b9bd commit 3559935

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+283
-168
lines changed

sdk/storage_datalake/examples/file_rename.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,14 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
4343
);
4444

4545
println!("renaming file '{}' to '{}'...", file_path1, file_path2);
46-
let rename_file_response = file_client1.rename(file_path2).into_future().await?;
47-
println!("rename file response == {:?}\n", rename_file_response);
46+
let file_client3 = file_client1.rename(file_path2).into_future().await?;
47+
let renamed_file_properties = file_client3.get_properties().into_future().await?;
48+
println!("renamed file properties == {:?}\n", renamed_file_properties);
49+
50+
// getting properties for the source file should fail, when the file no longer exists
51+
// Eventually we will implement the `exists` method, which internally employs a similar check
52+
let source_file_properties_result = file_client1.get_properties().into_future().await;
53+
assert!(source_file_properties_result.is_err());
4854

4955
println!("deleting file system...");
5056
let delete_fs_response = file_system_client.delete().into_future().await?;

sdk/storage_datalake/src/clients/directory_client.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ impl DirectoryClient {
8181
.if_match_condition(IfMatchCondition::NotMatch("*".to_string()))
8282
}
8383

84-
// TODO rename seems to not delete source
8584
pub fn rename<P>(&self, destination_path: P) -> RenamePathBuilder<Self>
8685
where
8786
P: Into<String>,
@@ -93,7 +92,6 @@ impl DirectoryClient {
9392
// the path will contain a leading '/' as we extract if from the path component of the url
9493
let dir_path = vec![fs_url.path(), &self.dir_path].join("/");
9594
RenamePathBuilder::new(destination_client, self.file_system_client.context.clone())
96-
.resource(ResourceType::Directory)
9795
.mode(PathRenameMode::Legacy)
9896
.rename_source(dir_path)
9997
}

sdk/storage_datalake/src/clients/file_client.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ impl FileClient {
8989
GetFileBuilder::new(self.clone(), self.file_system_client.context.clone())
9090
}
9191

92-
// TODO rename seems to not delete source
9392
pub fn rename<P>(&self, destination_path: P) -> RenamePathBuilder<Self>
9493
where
9594
P: Into<String>,
@@ -99,7 +98,6 @@ impl FileClient {
9998
// the path will contain a leading '/' as we extract if from the path component of the url
10099
let file_path = vec![fs_url.path(), &self.file_path].join("/");
101100
RenamePathBuilder::new(destination_client, self.file_system_client.context.clone())
102-
.resource(ResourceType::File)
103101
.mode(PathRenameMode::Legacy)
104102
.rename_source(file_path)
105103
}

sdk/storage_datalake/src/operations/path_put.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ where
2929
if_match_condition: Option<IfMatchCondition>,
3030
if_modified_since: Option<IfModifiedSinceCondition>,
3131
client_request_id: Option<ClientRequestId>,
32-
rename_source: Option<RenameSource>,
3332
properties: Option<Properties>,
3433
timeout: Option<Timeout>,
3534
context: Context,
@@ -45,7 +44,6 @@ impl<C: PathClient + 'static> PutPathBuilder<C> {
4544
if_match_condition: None,
4645
if_modified_since: None,
4746
client_request_id: None,
48-
rename_source: None,
4947
properties: None,
5048
timeout: None,
5149
context,
@@ -59,7 +57,6 @@ impl<C: PathClient + 'static> PutPathBuilder<C> {
5957
if_match_condition: IfMatchCondition => Some(if_match_condition),
6058
if_modified_since: IfModifiedSinceCondition => Some(if_modified_since),
6159
client_request_id: ClientRequestId => Some(client_request_id),
62-
rename_source: RenameSource => Some(rename_source),
6360
properties: Properties => Some(properties),
6461
timeout: Timeout => Some(timeout),
6562
context: Context => context,
@@ -85,7 +82,6 @@ impl<C: PathClient + 'static> PutPathBuilder<C> {
8582
add_optional_header2(&this.properties, &mut request)?;
8683
add_optional_header2(&this.if_match_condition, &mut request)?;
8784
add_optional_header2(&this.if_modified_since, &mut request)?;
88-
add_optional_header2(&this.rename_source, &mut request)?;
8985
add_mandatory_header2(&ContentLength::new(0), &mut request)?;
9086

9187
let response = self
@@ -106,7 +102,6 @@ where
106102
{
107103
client: C,
108104
mode: Option<PathRenameMode>,
109-
resource: Option<ResourceType>,
110105
continuation: Option<NextMarker>,
111106
if_match_condition: Option<IfMatchCondition>,
112107
if_modified_since: Option<IfModifiedSinceCondition>,
@@ -123,7 +118,6 @@ impl<C: PathClient + 'static> RenamePathBuilder<C> {
123118
client,
124119
mode: None,
125120
continuation: None,
126-
resource: None,
127121
if_match_condition: None,
128122
if_modified_since: None,
129123
client_request_id: None,
@@ -136,7 +130,6 @@ impl<C: PathClient + 'static> RenamePathBuilder<C> {
136130

137131
setters! {
138132
mode: PathRenameMode => Some(mode),
139-
resource: ResourceType => Some(resource),
140133
continuation: NextMarker => Some(continuation),
141134
if_match_condition: IfMatchCondition => Some(if_match_condition),
142135
if_modified_since: IfModifiedSinceCondition => Some(if_modified_since),
@@ -157,7 +150,6 @@ impl<C: PathClient + 'static> RenamePathBuilder<C> {
157150
if let Some(continuation) = self.continuation {
158151
continuation.append_to_url_query_as_continuation(&mut url);
159152
};
160-
self.resource.append_to_url_query(&mut url);
161153
self.mode.append_to_url_query(&mut url);
162154
self.timeout.append_to_url_query(&mut url);
163155

sdk/storage_datalake/src/properties.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ impl TryFrom<&HeaderMap> for Properties {
7676
fn try_from(headers: &HeaderMap) -> Result<Self, Self::Error> {
7777
let mut properties = Self::new();
7878

79+
let header_value = headers
80+
.get(HEADER)
81+
.ok_or_else(|| crate::Error::HeaderNotFound(HEADER.to_owned()))?
82+
.to_str()?;
83+
if header_value.is_empty() {
84+
return Ok(properties);
85+
}
86+
7987
// this is probably too complicated. Should we split
8088
// it in more manageable code blocks?
8189
// The logic is this:
@@ -86,10 +94,7 @@ impl TryFrom<&HeaderMap> for Properties {
8694
// 5. For each pair:
8795
// 6. Base64 decode the second entry (value). If error, return error.
8896
// 7. Insert the key value pair in the returned struct.
89-
headers
90-
.get(HEADER)
91-
.ok_or_else(|| crate::Error::HeaderNotFound(HEADER.to_owned()))? // HEADER must exists or we return Err
92-
.to_str()?
97+
header_value
9398
.split(',') // The list is a CSV so we split by comma
9499
.map(|key_value_pair| {
95100
let mut key_and_value = key_value_pair.split('='); // Each entry is key and value separated by =

sdk/storage_datalake/src/request_options.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Request properties used in datalake rest api operations
22
use azure_core::AddAsHeader;
33
use azure_core::AppendToUrlQuery;
4+
use azure_storage::core::headers::RENAME_SOURCE;
45
use http::request::Builder;
56

67
#[derive(Debug, Clone)]
@@ -197,10 +198,10 @@ impl AddAsHeader for RenameSource {
197198
&self,
198199
request: &mut azure_core::Request,
199200
) -> Result<(), azure_core::HttpHeaderError> {
200-
request.headers_mut().append(
201-
http::header::CONTENT_LANGUAGE,
202-
http::HeaderValue::from_str(&self.0)?,
203-
);
201+
let encoded: String = url::form_urlencoded::byte_serialize(self.0.as_bytes()).collect();
202+
request
203+
.headers_mut()
204+
.append(RENAME_SOURCE, http::HeaderValue::from_str(&encoded)?);
204205

205206
Ok(())
206207
}

sdk/storage_datalake/tests/files.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![cfg(feature = "mock_transport_framework")]
2+
use azure_storage_datalake::Properties;
23
use std::error::Error;
34

45
mod setup;
@@ -138,16 +139,38 @@ async fn file_rename() -> Result<(), Box<dyn Error + Send + Sync>> {
138139
let file_path2 = "some/path/e2etest-file2.txt";
139140
let file_client2 = file_system_client.get_file_client(file_path2);
140141

141-
file_client1.create().into_future().await?;
142+
let mut file_properties = Properties::new();
143+
file_properties.insert("AddedVia", "Azure SDK for Rust");
144+
145+
file_client1
146+
.create()
147+
.properties(file_properties.clone())
148+
.into_future()
149+
.await?;
142150
file_client2.create().into_future().await?;
143151

152+
// original file properties
153+
let original_target_file_properties = file_client2.get_properties().into_future().await?;
154+
144155
let rename_file_if_not_exists_result = file_client1
145156
.rename_if_not_exists(file_path2)
146157
.into_future()
147158
.await;
148159
assert!(rename_file_if_not_exists_result.is_err());
149160

150-
file_client1.rename(file_path2).into_future().await?;
161+
let file_client3 = file_client1.rename(file_path2).into_future().await?;
162+
let renamed_file_properties = file_client3.get_properties().into_future().await?;
163+
164+
// when renaming a file, the source file properties should be propagated
165+
assert_eq!(renamed_file_properties.properties, file_properties);
166+
assert_ne!(
167+
renamed_file_properties.properties,
168+
original_target_file_properties.properties
169+
);
170+
171+
// getting properties for the source file should fail, when the file no longer exists
172+
let source_file_properties_result = file_client1.get_properties().into_future().await;
173+
assert!(source_file_properties_result.is_err());
151174

152175
file_system_client.delete().into_future().await?;
153176

test/transactions/datalake_file_create_delete/0_request.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"authorization": "<<STRIPPED>>",
66
"content-length": "0",
77
"user-agent": "azsdk-rust-storage_datalake/0.1.0 (1.58.0; linux; x86_64)",
8-
"x-ms-date": "Fri, 21 Jan 2022 19:04:17 GMT",
8+
"x-ms-date": "Tue, 08 Feb 2022 19:19:33 GMT",
99
"x-ms-version": "2019-12-12"
1010
},
1111
"body": ""

test/transactions/datalake_file_create_delete/0_response.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
"status": 201,
33
"headers": {
44
"content-length": "0",
5-
"date": "Fri, 21 Jan 2022 19:04:19 GMT",
6-
"etag": "\"0x8D9DD10D460A632\"",
7-
"last-modified": "Fri, 21 Jan 2022 19:04:20 GMT",
5+
"date": "Tue, 08 Feb 2022 19:19:34 GMT",
6+
"etag": "\"0x8D9EB37F12127AD\"",
7+
"last-modified": "Tue, 08 Feb 2022 19:19:35 GMT",
88
"server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0",
99
"x-ms-namespace-enabled": "true",
10-
"x-ms-request-id": "9c6cdfe8-801f-0007-34f9-0e3678000000",
10+
"x-ms-request-id": "c47a931d-801f-0017-7920-1d865a000000",
1111
"x-ms-version": "2019-12-12"
1212
},
1313
"body": ""

test/transactions/datalake_file_create_delete/1_request.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"authorization": "<<STRIPPED>>",
66
"content-length": "0",
77
"user-agent": "azsdk-rust-storage_datalake/0.1.0 (1.58.0; linux; x86_64)",
8-
"x-ms-date": "Fri, 21 Jan 2022 19:04:18 GMT",
8+
"x-ms-date": "Tue, 08 Feb 2022 19:19:33 GMT",
99
"x-ms-version": "2019-12-12"
1010
},
1111
"body": ""

0 commit comments

Comments
 (0)