Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional support for storage classes #766

Merged
merged 1 commit into from
Feb 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using System;
using System.Linq;
using Xunit;
using Object = Google.Apis.Storage.v1.Data.Object;

namespace Google.Cloud.Storage.V1.IntegrationTests
{
Expand All @@ -30,14 +31,6 @@ public CopyObjectTest(StorageFixture fixture)
_fixture = fixture;
}

[Fact]
public void DestinationEqualsSourceIsProhibited()
{
var bucket = _fixture.ReadBucket;
var name = _fixture.SmallObject;
Assert.Throws<ArgumentException>(() => _fixture.Client.CopyObject(bucket, name, bucket, name));
}

[Fact]
public void CopySpecificGeneration()
{
Expand Down Expand Up @@ -70,5 +63,28 @@ public void CopyLatestGeneration()

ValidateData(_fixture.SingleVersionBucket, destName, _fixture.LargeContent);
}

[Fact]
public void NoMetadataOverride()
{
var destName = GenerateName();
_fixture.Client.CopyObject(
_fixture.ReadBucket, _fixture.SmallThenLargeObject,
_fixture.SingleVersionBucket, destName);
Object fetched = _fixture.Client.GetObject(_fixture.SingleVersionBucket, destName);
Assert.Equal("text/plain", fetched.ContentType);
}

[Fact]
public void MetadataOverride()
{
var destName = GenerateName();
_fixture.Client.CopyObject(
_fixture.ReadBucket, _fixture.SmallThenLargeObject,
_fixture.SingleVersionBucket, destName,
new CopyObjectOptions { ExtraMetadata = new Object { ContentType = "text/html" } });
Object fetched = _fixture.Client.GetObject(_fixture.SingleVersionBucket, destName);
Assert.Equal("text/html", fetched.ContentType);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Google.Apis.Storage.v1.Data;
using Xunit;
using Object = Google.Apis.Storage.v1.Data.Object;

namespace Google.Cloud.Storage.V1.IntegrationTests
{
[Collection(nameof(StorageFixture))]
public class StorageClassTest
{
private readonly StorageFixture _fixture;

public StorageClassTest(StorageFixture fixture)
{
_fixture = fixture;
}

// Multi-step test to check:
// - Create a bucket with a storage class of regional
// - That storage class is used when creating a new object
// - If we rewrite the object to a different storage class, that change sticks
// - If we update the bucket's default storage class, creating a new object uses that new class
[Fact]
public void CreateBucketAndObjects()
{
// Note: this test may fail if the project location prevents multi-regional storage.
string initialBucketStorageClass = StorageClasses.MultiRegional;
string updatedObjectStorageClass = StorageClasses.Coldline;
string updatedBucketStorageClass = StorageClasses.Nearline;

string bucketName = _fixture.BucketPrefix + "storage-classes";
string objectName = TestHelpers.GenerateName();
var client = _fixture.Client;

client.CreateBucket(_fixture.ProjectId, new Bucket { Name = bucketName, StorageClass = initialBucketStorageClass });
_fixture.RegisterBucketToDelete(bucketName);

var bucket = client.GetBucket(bucketName);
Assert.Equal(initialBucketStorageClass, bucket.StorageClass);

var obj = client.UploadObject(bucketName, objectName, "application/octet-stream", TestHelpers.GenerateData(100));
Assert.Equal(initialBucketStorageClass, obj.StorageClass);

// Change storage class via a rewrite
var options = new CopyObjectOptions
{
ExtraMetadata = new Object { StorageClass = updatedObjectStorageClass }
};
client.CopyObject(bucketName, objectName, bucketName, objectName, options);

// Fetch separately rather than trusting the return value of CopyObject...
obj = client.GetObject(bucketName, objectName);
Assert.Equal(updatedObjectStorageClass, obj.StorageClass);

bucket.StorageClass = updatedBucketStorageClass;
client.UpdateBucket(bucket);
string objectName2 = TestHelpers.GenerateName();

var obj2 = client.UploadObject(bucketName, objectName2, "application/octet-stream", TestHelpers.GenerateData(100));
Assert.Equal(updatedBucketStorageClass, obj2.StorageClass);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using System;
using static Google.Apis.Storage.v1.ObjectsResource;
using static Google.Apis.Storage.v1.ObjectsResource.RewriteRequest;
using Object = Google.Apis.Storage.v1.Data.Object;

namespace Google.Cloud.Storage.V1
{
Expand Down Expand Up @@ -90,6 +91,13 @@ public sealed class CopyObjectOptions
/// </summary>
public long? IfSourceMetagenerationNotMatch { get; set; }

/// <summary>
/// Additional object metadata for the new object. This can be used to specify the storage
/// class of the new object, the content type etc. If this property is not set, the existing
/// object metadata will be used unchanged.
/// </summary>
public Object ExtraMetadata { get; set; }

internal void ModifyRequest(RewriteRequest request)
{
// Note the use of ArgumentException here, as this will basically be the result of invalid
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Google.Apis.Storage.v1.Data;

namespace Google.Cloud.Storage.V1
{
/// <summary>
/// String constants for the names of the storage classes, as used in <see cref="Bucket.StorageClass"/>
/// and <see cref="Object.StorageClass"/>. See https://cloud.google.com/storage/docs/storage-classes for details.
/// </summary>
public static class StorageClasses
{
/// <summary>
/// Name for the Multi-Regional storage class.
/// </summary>
public const string MultiRegional = "MULTI_REGIONAL";

/// <summary>
/// Name for the Regional storage class.
/// </summary>
public const string Regional = "REGIONAL";

/// <summary>
/// Name for the Nearline storage class.
/// </summary>
public const string Nearline = "NEARLINE";

/// <summary>
/// Name for the Coldline storage class.
/// </summary>
public const string Coldline = "COLDLINE";

/// <summary>
/// Name of the Standard storage class, which is equivalent to
/// Multi-Regional or Regional depending on the location.
/// </summary>
public const string Standard = "STANDARD";

/// <summary>
/// Name of the Durable Reduced Availability (DRA) storage class.
/// Use of this storage class is not recommended; Regional storage has
/// lower pricing for some operations but otherwise the same pricing structure,
/// and better performance/availability.
/// </summary>
public const string DurableReducedAvailability = "DURABLE_REDUCED_AVAILABILITY";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ public abstract partial class StorageClient
/// <param name="sourceObjectName">The name of the object to copy within the bucket. Must not be null.</param>
/// <param name="destinationBucket">The name of the bucket to copy the object to. Must not be null.</param>
/// <param name="destinationObjectName">The name of the object within the destination bucket. Must not be null.</param>
/// <param name="options">Additional options for the fetch operation. May be null, in which case appropriate
/// <param name="options">Additional options for the copy operation. May be null, in which case appropriate
/// defaults will be used.</param>
/// <exception cref="ArgumentException">The arguments attempt to copy an object to itself.</exception>
/// <returns>The <see cref="Object"/> representation of the new storage object resulting from the copy.</returns>
public virtual Object CopyObject(
string sourceBucket,
Expand All @@ -51,9 +50,8 @@ public virtual Object CopyObject(
/// <param name="sourceObjectName">The name of the object to copy within the bucket. Must not be null.</param>
/// <param name="destinationBucket">The name of the bucket to copy the object to. Must not be null.</param>
/// <param name="destinationObjectName">The name of the object within the destination bucket. Must not be null.</param>
/// <param name="options">Additional options for the fetch operation. May be null, in which case appropriate
/// <param name="options">Additional options for the copy operation. May be null, in which case appropriate
/// defaults will be used.</param>
/// <exception cref="ArgumentException">The arguments attempt to copy an object to itself.</exception>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A task representing the asynchronous operation, with a result returning the
/// <see cref="Object"/> representation of the new storage object resulting from the copy.</returns>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,8 @@ private ObjectsResource.RewriteRequest CreateCopyObjectRequest(
GaxPreconditions.CheckNotNull(sourceObjectName, nameof(sourceObjectName));
GaxPreconditions.CheckNotNull(destinationBucket, nameof(destinationBucket));
GaxPreconditions.CheckNotNull(destinationObjectName, nameof(destinationObjectName));
if (destinationBucket == sourceBucket && destinationObjectName == sourceObjectName)
{
throw new ArgumentException("Cannot copy an object to itself. Specify either a different destination bucket or a different destination object name");
}
var request = Service.Objects.Rewrite(new Object(), sourceBucket, sourceObjectName, destinationBucket, destinationObjectName);
Object obj = options?.ExtraMetadata ?? new Object();
var request = Service.Objects.Rewrite(obj, sourceBucket, sourceObjectName, destinationBucket, destinationObjectName);
options?.ModifyRequest(request);
return request;
}
Expand Down