Skip to content

Commit

Permalink
Fix getblocks long (#19078)
Browse files Browse the repository at this point in the history
* INCOMPLETE: retire int block size; introduce long

Regenerated with new swagger to present block size on a GetBlocks call
as long instead of int, while preserving backwards compatibility.
Currently build error CS0282 due to a mix of generated and handwritten
properties.

* Updated autorest swagger pointer

* Fixed build error

Moved all BlobBlock properties into handwritten partial file to avoid
compile error CS0282.

* Ignore multi GB test

* ModelFactory support

* export api

* Fix codegen url

* Handled overflow bug

* disabled long test due to timeout

* fixed broken url; regenerated

* Changelog

Co-authored-by: jschrepp-MSFT <41338290+jschrepp-MSFT@users.noreply.github.com>
  • Loading branch information
jaschrep-msft and jaschrep-msft authored Mar 1, 2021
1 parent 0341734 commit 4128795
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 13 deletions.
3 changes: 2 additions & 1 deletion sdk/storage/Azure.Storage.Blobs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Release History

## 12.9.0-beta.2 (Unreleased)
- Fixed bug where `Stream` returned by `BlockBlobClient.OpenWrite` could corrupt blocks if flushed between writes.
- Fixed a bug where BlockBlobClient.GetBlockList threw when dealing with extremely large blocks.
- Fixed bug where `Stream` returned by `BlockBlobClient.OpenWrite` could corrupt blocks if flushed between writes.

## 12.9.0-beta.1 (2021-02-09)
- Added support for service version 2020-06-12.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,9 @@ internal BlobAppendInfo() { }
private readonly object _dummy;
private readonly int _dummyPrimitive;
public string Name { get { throw null; } }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public int Size { get { throw null; } }
public long SizeLong { get { throw null; } }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public bool Equals(Azure.Storage.Blobs.Models.BlobBlock other) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
Expand Down Expand Up @@ -839,7 +841,9 @@ public static partial class BlobsModelFactory
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public static Azure.Storage.Blobs.Models.BlobAppendInfo BlobAppendInfo(Azure.ETag eTag, System.DateTimeOffset lastModified, byte[] contentHash, byte[] contentCrc64, string blobAppendOffset, int blobCommittedBlockCount, bool isServerEncrypted, string encryptionKeySha256) { throw null; }
public static Azure.Storage.Blobs.Models.BlobAppendInfo BlobAppendInfo(Azure.ETag eTag, System.DateTimeOffset lastModified, byte[] contentHash, byte[] contentCrc64, string blobAppendOffset, int blobCommittedBlockCount, bool isServerEncrypted, string encryptionKeySha256, string encryptionScope) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public static Azure.Storage.Blobs.Models.BlobBlock BlobBlock(string name, int size) { throw null; }
public static Azure.Storage.Blobs.Models.BlobBlock BlobBlock(string name, long size) { throw null; }
public static Azure.Storage.Blobs.Models.BlobContainerAccessPolicy BlobContainerAccessPolicy(Azure.Storage.Blobs.Models.PublicAccessType blobPublicAccess, Azure.ETag eTag, System.DateTimeOffset lastModified, System.Collections.Generic.IEnumerable<Azure.Storage.Blobs.Models.BlobSignedIdentifier> signedIdentifiers) { throw null; }
public static Azure.Storage.Blobs.Models.BlobContainerInfo BlobContainerInfo(Azure.ETag eTag, System.DateTimeOffset lastModified) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions sdk/storage/Azure.Storage.Blobs/src/Models/BlobBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

using System;
using System.ComponentModel;
using Azure.Core;

namespace Azure.Storage.Blobs.Models
Expand All @@ -12,6 +13,28 @@ namespace Azure.Storage.Blobs.Models
[CodeGenModel("Block")]
public readonly partial struct BlobBlock : IEquatable<BlobBlock>
{
// All properties are rebuilt by hand in this class to avoid compile error CS0282

/// <summary>
/// The block size in bytes.
/// </summary>
[CodeGenMember("Size")]
public long SizeLong { get; }

/// <summary>
/// This property is a backwards-compatible facade for <see cref="SizeLong"/>,
/// which supports long values. Use <see cref="SizeLong"/> for full access of
/// supported values.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public int Size => checked((int)SizeLong);

/// <summary>
/// The base64 encoded block ID.
/// </summary>
[CodeGenMember("Name")]
public string Name { get; }

/// <summary>
/// Check if two BlobBlock instances are equal.
/// </summary>
Expand Down
11 changes: 11 additions & 0 deletions sdk/storage/Azure.Storage.Blobs/src/Models/BlobsModelFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1416,12 +1416,23 @@ public static PageBlobInfo PageBlobInfo(
/// <summary>
/// Creates a new BlobBlock instance for mocking.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static BlobBlock BlobBlock(
string name,
int size)
{
return new BlobBlock(name, size);
}

/// <summary>
/// Creates a new BlobBlock instance for mocking.
/// </summary>
public static BlobBlock BlobBlock(
string name,
long size)
{
return new BlobBlock(name, size);
}
#endregion

#region BlobGeoReplication
Expand Down
2 changes: 1 addition & 1 deletion sdk/storage/Azure.Storage.Blobs/src/autorest.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Run `dotnet build /t:GenerateCode` to generate code.

``` yaml
input-file:
- https://raw.githubusercontent.com/Azure/azure-rest-api-specs/011761be1285d14feb41796b5d97df1126495c5c/specification/storage/data-plane/Microsoft.BlobStorage/preview/2020-06-12/blob.json
- https://raw.githubusercontent.com/Azure/azure-rest-api-specs/8c1f9b739165035d9ced32761cebb19125bce233/specification/storage/data-plane/Microsoft.BlobStorage/preview/2020-06-12/blob.json
```
### Move path parameters to constructor.
Expand Down
45 changes: 45 additions & 0 deletions sdk/storage/Azure.Storage.Blobs/tests/BlockBlobClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Azure.Storage.Test.Shared;
using Moq;
using NUnit.Framework;
using static Azure.Storage.Blobs.BlobClientOptions;
using Metadata = System.Collections.Generic.IDictionary<string, string>;
using Tags = System.Collections.Generic.IDictionary<string, string>;

Expand Down Expand Up @@ -1513,6 +1514,50 @@ public async Task GetBlockListAsync()
Assert.AreEqual(blockId1, response.Value.UncommittedBlocks.First().Name);
}

[Test]
[LiveOnly]
[ServiceVersion(Min = ServiceVersion.V2019_12_12)]
[Ignore("https://github.com/Azure/azure-sdk-for-net/issues/12312")]
public async Task GetBlockListAsync_LongBlock()
{
const long bigBlockSize = int.MaxValue + 1024L;
await using DisposingContainer test = await GetTestContainerAsync();

// Arrange
BlockBlobClient blob = InstrumentClient(test.Container.GetBlockBlobClient(GetNewBlobName()));
var data = GetRandomBuffer(Size);

// Upload to blockBlobUri, so it exists
using (var stream = new MemoryStream(data))
{
await blob.UploadAsync(stream);
}

var blockId0 = ToBase64(GetNewBlockName());
using (var stream = new Storage.Tests.Shared.PredictableStream(length: bigBlockSize))
{
await blob.StageBlockAsync(blockId0, stream);
}
await blob.CommitBlockListAsync(new string[] { blockId0 });

var blockId1 = ToBase64(GetNewBlobName());
using (var stream = new MemoryStream(data))
{
await blob.StageBlockAsync(blockId1, stream);
}

// Act
Response<BlockList> response = await blob.GetBlockListAsync();

// Assert
Assert.AreEqual(1, response.Value.CommittedBlocks.Count());
Assert.AreEqual(blockId0, response.Value.CommittedBlocks.First().Name);
Assert.AreEqual(1, response.Value.UncommittedBlocks.Count());
Assert.AreEqual(blockId1, response.Value.UncommittedBlocks.First().Name);
Assert.AreEqual(bigBlockSize, response.Value.CommittedBlocks.First().SizeLong);
Assert.Throws<OverflowException>(() => _ = response.Value.CommittedBlocks.First().Size); // if no overflow then we didn't actually test handling of long lengths
}

[Test]
public async Task GetBlockListAsync_Type()
{
Expand Down

0 comments on commit 4128795

Please sign in to comment.