Skip to content
This repository was archived by the owner on Feb 23, 2026. It is now read-only.

Commit 85e5e4c

Browse files
authored
Merge pull request #627 from GoogleCloudPlatform/quoct/fixed_typed_metadata
Fix a bug where fixed type metadata is not handled properly in GCS Object cmdlets.
2 parents da648ae + d3c26d8 commit 85e5e4c

7 files changed

Lines changed: 308 additions & 59 deletions

File tree

Google.PowerShell.IntegrationTests/Dns/Dns.GcdChange.Tests.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Describe "Get-GcdChange" {
1111
}
1212

1313
It "should fail to return changes of non-existent project" {
14-
{ Get-GcdChange -Project $nonExistProject -Zone $testZone1 } | Should Throw "404"
14+
{ Get-GcdChange -Project $nonExistProject -Zone $testZone1 } | Should Throw "403"
1515
}
1616

1717
It "should give access errors as appropriate" {
@@ -86,7 +86,7 @@ Describe "Add-GcdChange" {
8686
$copyChange.Deletions = $null
8787

8888
It "should fail to add a Change to a non-existent project" {
89-
{ Add-GcdChange -Project $nonExistProject $testZone1 $copyChange } | Should Throw "404"
89+
{ Add-GcdChange -Project $nonExistProject $testZone1 $copyChange } | Should Throw "403"
9090
}
9191

9292
It "should give access errors as appropriate" {

Google.PowerShell.IntegrationTests/Dns/Dns.GcdManagedZone.Tests.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Describe "Get-GcdManagedZone" {
1111
}
1212

1313
It "should fail to return ManagedZones of non-existent project" {
14-
{ Get-GcdManagedZone -Project $nonExistProject } | Should Throw "404"
14+
{ Get-GcdManagedZone -Project $nonExistProject } | Should Throw "403"
1515
}
1616

1717
It "should give access errors as appropriate" {
@@ -62,7 +62,7 @@ Describe "Add-GcdManagedZone" {
6262
}
6363

6464
It "should fail to create a ManagedZone in a non-existent project" {
65-
{ Add-GcdManagedZone -Project $nonExistProject $testZone1 $dnsName1 } | Should Throw "404"
65+
{ Add-GcdManagedZone -Project $nonExistProject $testZone1 $dnsName1 } | Should Throw "403"
6666
}
6767

6868
It "should give access errors as appropriate" {
@@ -114,7 +114,7 @@ Describe "Remove-GcdManagedZone" {
114114
}
115115

116116
It "should fail to delete a ManagedZone in a non-existent project" {
117-
{ Remove-GcdManagedZone -Project $nonExistProject $testZone1 } | Should Throw "404"
117+
{ Remove-GcdManagedZone -Project $nonExistProject $testZone1 } | Should Throw "403"
118118
}
119119

120120
It "should give access errors as appropriate" {

Google.PowerShell.IntegrationTests/Dns/Dns.GcdQuota.Tests.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ $project, $zone, $oldActiveConfig, $configName = Set-GCloudConfig
55
Describe "Get-GcdQuota" {
66

77
It "should fail to return DNS quota of non-existent project" {
8-
{ Get-GcdQuota -Project $nonExistProject } | Should Throw "404"
8+
{ Get-GcdQuota -Project $nonExistProject } | Should Throw "403"
99
}
1010

1111
It "should give access errors as appropriate" {

Google.PowerShell.IntegrationTests/Dns/Dns.GcdResourceRecordSet.Tests.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Describe "Get-GcdResourceRecordSet" {
1111
}
1212

1313
It "should fail to return ResourceRecordSets of non-existent project" {
14-
{ Get-GcdResourceRecordSet -Project $nonExistProject $testZone1 } | Should Throw "404"
14+
{ Get-GcdResourceRecordSet -Project $nonExistProject $testZone1 } | Should Throw "403"
1515
}
1616

1717
It "should give access errors as appropriate" {

Google.PowerShell.IntegrationTests/Storage/Storage.GcsObject.Tests.ps1

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -295,18 +295,47 @@ Describe "New-GcsObject" {
295295
Remove-GcsObject $emptyObj
296296
}
297297

298+
It "should work with fixed-type metadata" {
299+
$obj = New-GcsObject $bucket "metadata-test" `
300+
-ContentEncoding "gzip" -ContentType "image/png"
301+
$obj.Metadata | Should BeNullOrEmpty
302+
$obj.ContentType | Should Be "image/png"
303+
$obj.ContentEncoding | Should Be "gzip"
304+
Remove-GcsObject $obj
305+
}
306+
307+
It "should work with fixed-type metadata through -Metadata parameter" {
308+
$obj = New-GcsObject $bucket "metadata-test" `
309+
-Metadata @{ "Content-Encoding" = "gzip"; "Content-Type" = "image/png" }
310+
$obj.Metadata | Should BeNullOrEmpty
311+
$obj.ContentType | Should Be "image/png"
312+
$obj.ContentEncoding | Should Be "gzip"
313+
Remove-GcsObject $obj
314+
}
315+
298316
It "should write metadata" {
299317
$obj = New-GcsObject $bucket "metadata-test" `
300318
-Metadata @{ "alpha" = 1; "beta" = "two"; "Content-Type" = "image/png" }
301-
$obj.Metadata.Count = 3
319+
$obj.Metadata.Count = 2
302320
$obj.Metadata["alpha"] | Should Be 1
303321
$obj.Metadata["beta"] | Should Be "two"
304-
$obj.Metadata["Content-Type"] | Should Be "image/png"
305322
# Content-Type can be set from metadata.
306323
$obj.ContentType | Should Be "image/png"
307324
Remove-GcsObject $obj
308325
}
309326

327+
It "should work with both fixed-type and custom metadata" {
328+
$obj = New-GcsObject $bucket "metadata-test" `
329+
-Metadata @{ "Content-Encoding" = "gzip"; "Content-Type" = "image/png";
330+
"alpha" = 1; "beta" = "two" }
331+
$obj.Metadata.Count = 2
332+
$obj.Metadata["alpha"] | Should Be 1
333+
$obj.Metadata["beta"] | Should Be "two"
334+
$obj.ContentType | Should Be "image/png"
335+
$obj.ContentEncoding | Should Be "gzip"
336+
Remove-GcsObject $obj
337+
}
338+
310339
# Regression for a bug found while unit testing other scenarios.
311340
It "should write metadata when accepting content from pipeline" {
312341
$obj = "XXX" | New-GcsObject $bucket "metadata-test-2" `
@@ -316,13 +345,15 @@ Describe "New-GcsObject" {
316345
Remove-GcsObject $obj
317346
}
318347

319-
It "will prefer the -ContentType parameter to -Metadata" {
348+
It "will prefer the fixed-type metadata parameter to -Metadata" {
320349
$obj = New-GcsObject $bucket "metadata-test" `
350+
-ContentLanguage "aa" `
321351
-ContentType "image/jpeg" `
322-
-Metadata @{ "Content-Type" = "image/png" }
352+
-Metadata @{ "Content-Type" = "image/png"; "Content-Language" = "en" }
323353
$obj.ContentType | Should Be "image/jpeg"
324-
# It will also apply to the Metadata too.
325-
$obj.Metadata["Content-Type"] | Should Be "image/jpeg"
354+
$obj.ContentLanguage | Should Be "aa"
355+
# It should not apply to the Metadata too.
356+
$obj.Metadata | Should BeNullOrEmpty
326357
Remove-GcsObject $obj
327358
}
328359

@@ -1151,7 +1182,7 @@ Describe "Write-GcsObject" {
11511182
Remove-GcsObject $bucket "acl-test"
11521183
}
11531184

1154-
It "should not clobber existing metadata" {
1185+
It "should not clobber existing custom metadata" {
11551186
$orgObj = "original contents" | New-GcsObject $bucket "metadata-test" `
11561187
-Metadata @{ "one" = 1; "two" = 2}
11571188
$orgObj.Metadata.Count | Should Be 2
@@ -1162,6 +1193,30 @@ Describe "Write-GcsObject" {
11621193
Remove-GcsObject $bucket "metadata-test"
11631194
}
11641195

1196+
It "should not clobber existing fixed-key metadata" {
1197+
$orgObj = "original contents" | New-GcsObject $bucket "metadata-test" `
1198+
-ContentEncoding "gzip" -ContentLanguage "aa"
1199+
1200+
$updatedObj = "new contents" | Write-GcsObject $bucket "metadata-test" `
1201+
-ContentLanguage "en"
1202+
$updatedObj.ContentLanguage | Should Be "en"
1203+
$updatedObj.ContentEncoding | Should Be "gzip"
1204+
1205+
Remove-GcsObject $bucket "metadata-test"
1206+
}
1207+
1208+
It "should update fixed-key metadata to null" {
1209+
$orgObj = "original contents" | New-GcsObject $bucket "metadata-test" `
1210+
-ContentEncoding "gzip" -ContentLanguage "aa"
1211+
1212+
$updatedObj = "new contents" | Write-GcsObject $bucket "metadata-test" `
1213+
-ContentLanguage $null -ContentEncoding $null
1214+
$updatedObj.ContentLanguage | Should BeNullOrEmpty
1215+
$updatedObj.ContentEncoding | Should BeNullOrEmpty
1216+
1217+
Remove-GcsObject $bucket "metadata-test"
1218+
}
1219+
11651220
It "should merge Metadata updates" {
11661221
$step1 = "XXX" | New-GcsObject $bucket "metadata-test2" `
11671222
-Metadata @{ "alpha" = 1; "beta" = 2; "gamma" = 3 }
@@ -1183,17 +1238,36 @@ Describe "Write-GcsObject" {
11831238
Remove-GcsObject $bucket "metadata-test2"
11841239
}
11851240

1186-
It "should give precidence to the ContentType parameter" {
1241+
It "should use fixed-key parameter in -Metadata parameter" {
1242+
# Where Write-Gcs object creates a new object (-Force)
1243+
$newObjectCase = "XXX" | Write-GcsObject $bucket "content-type-test" `
1244+
-ContentType "image/png" -ContentLanguage "en" `
1245+
-Metadata @{ "Content-Type" = "image/jpeg" } -Force
1246+
$newObjectCase.ContentType | Should Be "image/png"
1247+
$newObjectCase.ContentLanguage | Should Be "en"
1248+
1249+
$both = "XXX" | Write-GcsObject $bucket "content-type-test" `
1250+
-Metadata @{ "Content-Type" = "test/beta"; "Content-Language" = "aa" }
1251+
$both.ContentType | Should Be "test/beta"
1252+
$both.ContentLanguage | Should Be "aa"
1253+
1254+
Remove-GcsObject $bucket "content-type-test"
1255+
}
1256+
1257+
It "should give precedence to the fixed type parameter" {
11871258
# Where Write-Gcs object creates a new object (-Force)
11881259
$newObjectCase = "XXX" | Write-GcsObject $bucket "content-type-test" `
1189-
-ContentType "image/png" -Metadata @{ "Content-Type" = "image/jpeg" } `
1190-
-Force
1260+
-ContentType "image/png" -ContentLanguage "en" `
1261+
-Metadata @{ "Content-Type" = "image/jpeg" } -Force
11911262
$newObjectCase.ContentType | Should Be "image/png"
1263+
$newObjectCase.ContentLanguage | Should Be "en"
11921264

1193-
# Where Write-Gcs has both ContentType and a Metadata value.
1265+
# Where Write-Gcs has both ContentType, ContentLanguage and a Metadata value.
11941266
$both = "XXX" | Write-GcsObject $bucket "content-type-test" `
1195-
-ContentType "test/alpha" -Metadata @{ "Content-Type" = "test/beta" }
1267+
-ContentType "test/alpha" -ContentLanguage "aa" `
1268+
-Metadata @{ "Content-Type" = "test/beta"; "Content-Language" = "bb" }
11961269
$both.ContentType | Should Be "test/alpha"
1270+
$both.ContentLanguage | Should Be "aa"
11971271

11981272
Remove-GcsObject $bucket "content-type-test"
11991273
}

Google.PowerShell/Storage/GcsCmdlet.cs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,16 @@ protected Dictionary<string, string> ConvertToDictionary(IDictionary<string, str
7676
}
7777

7878
/// <summary>
79-
/// Infer the MIME type of a non-qualified file path. Returns null if no match is found.
79+
/// Infer the MIME type of a non-qualified file path.
80+
/// Returns octet stream mime type if no match is found.
8081
/// </summary>
8182
public static string InferContentType(string file)
8283
{
84+
if (file == null)
85+
{
86+
return OctetStreamMimeType;
87+
}
88+
8389
int index = file.LastIndexOf('.');
8490
if (index == -1)
8591
{
@@ -110,34 +116,28 @@ public static string InferContentType(string file)
110116
}
111117

112118
/// <summary>
113-
/// Return the content type to use for a Cloud Storage object given existing values, defauts, etc. The order of
114-
/// precidence is:
115-
/// 1. New content type, e.g. a ContentType parameter.
116-
/// 2. New metadata, e.g. Metadata value specified via parameter.
117-
/// 3. Default content type to apply (potentially null), e.g. sniffing file content.
118-
/// If no match is found, will return OctetStreamMimeType.
119+
/// Gets fixed type metadata from the cmdlet parameter if user provides that.
120+
/// If not, tries retrieving it from the metadata dictionary using keyNameInMetadataDictionary.
121+
/// If that also fails, returns the default content type.
119122
/// </summary>
120-
public string GetContentType(
121-
string newContentType,
122-
Dictionary<string, string> newMetadata,
123-
string defaultContentType = null)
123+
/// <returns></returns>
124+
protected string GetFixedTypeMetadata(
125+
string parameterName,
126+
IReadOnlyDictionary<string, string> metadataDictionary,
127+
string keyNameInMetadataDictionary,
128+
string defaultValue = null)
124129
{
125-
if (!String.IsNullOrEmpty(newContentType))
130+
if (MyInvocation.BoundParameters.ContainsKey(parameterName))
126131
{
127-
return newContentType;
132+
return MyInvocation.BoundParameters[parameterName] as string;
128133
}
129134

130-
if (newMetadata != null && newMetadata.ContainsKey("Content-Type"))
135+
if (metadataDictionary != null && metadataDictionary.ContainsKey(keyNameInMetadataDictionary))
131136
{
132-
return newMetadata["Content-Type"];
137+
return metadataDictionary[keyNameInMetadataDictionary];
133138
}
134139

135-
if (!String.IsNullOrEmpty(defaultContentType))
136-
{
137-
return defaultContentType;
138-
}
139-
140-
return OctetStreamMimeType;
140+
return defaultValue;
141141
}
142142
}
143143
}

0 commit comments

Comments
 (0)