Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Move tests for 8Gb files to outerloop and disable parallelization
  • Loading branch information
jozkee authored and github-actions committed Oct 7, 2022
commit e9a46a7fc9d8b14d0368f111c4df66715a3afd5c
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@
<Compile Include="TarTestsBase.Ustar.cs" />
<Compile Include="TarTestsBase.V7.cs" />
<Compile Include="TarWriter\TarWriter.WriteEntry.Entry.Roundtrip.Tests.cs" />
<Compile Include="TarWriter\TarWriter.WriteEntry.LongFile.Tests.cs" />
<Compile Include="TarWriter\TarWriter.WriteEntryAsync.File.Tests.cs" />
<Compile Include="TarWriter\TarWriter.WriteEntry.Base.cs" />
<Compile Include="TarWriter\TarWriter.WriteEntryAsync.LongFile.Tests.cs" />
<Compile Include="TarWriter\TarWriter.WriteEntryAsync.Tests.cs" />
<Compile Include="TarWriter\TarWriter.WriteEntryAsync.Entry.Roundtrip.Tests.cs" />
<Compile Include="TarWriter\TarWriter.WriteEntryAsync.Entry.Ustar.Tests.cs" />
Expand All @@ -68,6 +70,7 @@
<Compile Include="WrappedStream.cs" Link="WrappedStream.cs" />
<Compile Include="$(CommonPath)DisableRuntimeMarshalling.cs" Link="Common\DisableRuntimeMarshalling.cs" />
<Compile Include="$(CommonTestPath)System\IO\ReparsePointUtilities.cs" Link="Common\System\IO\ReparsePointUtilities.cs" />
<Compile Include="$(CommonTestPath)TestUtilities\System\DisableParallelization.cs" Link="Common\TestUtilities\System\DisableParallelization.cs" />
</ItemGroup>
<!-- Windows specific files -->
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'windows'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,71 +249,5 @@ public void PaxExtendedAttributes_DoNotOverwritePublicProperties_WhenLargerThanL
Assert.Equal(writeEntry.ModificationTime, readEntry.ModificationTime);
Assert.Equal(writeEntry.LinkName, readEntry.LinkName);
}

[Theory]
[InlineData(TarEntryFormat.V7, LegacyMaxFileSize)]
[InlineData(TarEntryFormat.Ustar, LegacyMaxFileSize)]
[InlineData(TarEntryFormat.Gnu, LegacyMaxFileSize)]
[InlineData(TarEntryFormat.Pax, LegacyMaxFileSize)]
// Pax supports unlimited size files.
[InlineData(TarEntryFormat.Pax, LegacyMaxFileSize + 1)]
public void WriteEntry_LongFileSize(TarEntryFormat entryFormat, long size)
{
Span<byte> dummyContent = new byte[5];
new Random(42).NextBytes(dummyContent);

// Write archive with a 8 Gb long entry.
FileStreamOptions options = new()
{
Mode = FileMode.Create,
Access = FileAccess.ReadWrite,
Options = FileOptions.DeleteOnClose // we don't want an 8 Gb file living for too long.
};

FileStream tarFile = File.Open(GetTestFilePath(), options);
using (TarWriter writer = new(tarFile, leaveOpen: true))
{
TarEntry writeEntry = InvokeTarEntryCreationConstructor(entryFormat, entryFormat is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile, "foo");
writeEntry.DataStream = CreateFileWithDummyContentAtTheEnds(GetTestFilePath(), size, dummyContent, options);
writer.WriteEntry(writeEntry);
}
tarFile.Position = 0;

// Read archive back.
using TarReader reader = new TarReader(tarFile);
TarEntry entry = reader.GetNextEntry();
Assert.Null(reader.GetNextEntry());
Assert.Equal(size, entry.Length);

Stream dataStream = entry.DataStream;
Assert.Equal(size, dataStream.Length);
Assert.Equal(0, dataStream.Position);

// Read the first bytes.
Span<byte> buffer = new byte[dummyContent.Length];
Assert.Equal(buffer.Length, dataStream.Read(buffer));
AssertExtensions.SequenceEqual(dummyContent, buffer);
Assert.Equal(0, dataStream.ReadByte()); // check next byte is correct.
buffer.Clear();

// Read the last bytes.
dataStream.Seek(size - dummyContent.Length - 1, SeekOrigin.Begin);
Assert.Equal(0, dataStream.ReadByte()); // check previous byte is correct.
Assert.Equal(buffer.Length, dataStream.Read(buffer));
AssertExtensions.SequenceEqual(dummyContent, buffer);
Assert.Equal(size, dataStream.Position);
}

private static FileStream CreateFileWithDummyContentAtTheEnds(string path, long size, ReadOnlySpan<byte> dummyContent, FileStreamOptions options)
{
FileStream fs = File.Open(path, options);
fs.Write(dummyContent);

fs.Seek(size - dummyContent.Length, SeekOrigin.Begin);
fs.Write(dummyContent);

fs.Position = 0;
return fs;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.IO;
using Xunit;

namespace System.Formats.Tar.Tests
{
[OuterLoop]
[Collection(nameof(DisableParallelization))] // don't create multiple large files at the same time
public class TarWriter_WriteEntry_LongFile_Tests : TarTestsBase
{
public static IEnumerable<object[]> WriteEntry_LongFileSize_TheoryData()
{
foreach (bool unseekableStream in new[] { false, true })
{
foreach (TarEntryFormat entryFormat in new[] { TarEntryFormat.V7, TarEntryFormat.Ustar, TarEntryFormat.Gnu, TarEntryFormat.Pax })
{
yield return new object[] { entryFormat, LegacyMaxFileSize, unseekableStream };
}

// Pax supports unlimited size files.
yield return new object[] { TarEntryFormat.Pax, LegacyMaxFileSize + 1, unseekableStream };
}
}

[Theory]
[MemberData(nameof(WriteEntry_LongFileSize_TheoryData))]
public void WriteEntry_LongFileSize(TarEntryFormat entryFormat, long size, bool unseekableStream)
{
// Write archive with a 8 Gb long entry.
FileStream tarFile = File.Open(GetTestFilePath(), new FileStreamOptions { Access = FileAccess.ReadWrite, Mode = FileMode.Create, Options = FileOptions.DeleteOnClose });
Stream s = unseekableStream ? new WrappedStream(tarFile, tarFile.CanRead, tarFile.CanWrite, canSeek: false) : tarFile;

using (TarWriter writer = new(s, leaveOpen: true))
{
TarEntry writeEntry = InvokeTarEntryCreationConstructor(entryFormat, entryFormat is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile, "foo");
writeEntry.DataStream = new SimulatedDataStream(size);
writer.WriteEntry(writeEntry);
}

tarFile.Position = 0;

// Read archive back.
using TarReader reader = new TarReader(s);
TarEntry entry = reader.GetNextEntry();
Assert.Equal(size, entry.Length);

Stream dataStream = entry.DataStream;
Assert.Equal(size, dataStream.Length);
Assert.Equal(0, dataStream.Position);

ReadOnlySpan<byte> dummyData = SimulatedDataStream.DummyData.Span;

// Read the first bytes.
Span<byte> buffer = new byte[dummyData.Length];
Assert.Equal(buffer.Length, dataStream.Read(buffer));
AssertExtensions.SequenceEqual(dummyData, buffer);
Assert.Equal(0, dataStream.ReadByte()); // check next byte is correct.
buffer.Clear();

// Read the last bytes.
long dummyDataOffset = size - dummyData.Length - 1;
if (dataStream.CanSeek)
{
Assert.False(unseekableStream);
dataStream.Seek(dummyDataOffset, SeekOrigin.Begin);
}
else
{
Assert.True(unseekableStream);
Span<byte> seekBuffer = new byte[4_096];

while (dataStream.Position < dummyDataOffset)
{
int bufSize = (int)Math.Min(seekBuffer.Length, dummyDataOffset - dataStream.Position);
int res = dataStream.Read(seekBuffer.Slice(0, bufSize));
Assert.True(res > 0, "Unseekable stream finished before expected - Something went very wrong");
}
}

Assert.Equal(0, dataStream.ReadByte()); // check previous byte is correct.
Assert.Equal(buffer.Length, dataStream.Read(buffer));
AssertExtensions.SequenceEqual(dummyData, buffer);
Assert.Equal(size, dataStream.Position);

Assert.Null(reader.GetNextEntry());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -198,71 +198,5 @@ public async Task PaxExtendedAttributes_DoNotOverwritePublicProperties_WhenLarge
Assert.Equal(writeEntry.ModificationTime, readEntry.ModificationTime);
Assert.Equal(writeEntry.LinkName, readEntry.LinkName);
}

[Theory]
[InlineData(TarEntryFormat.V7, LegacyMaxFileSize)]
[InlineData(TarEntryFormat.Ustar, LegacyMaxFileSize)]
[InlineData(TarEntryFormat.Gnu, LegacyMaxFileSize)]
[InlineData(TarEntryFormat.Pax, LegacyMaxFileSize)]
// Pax supports unlimited size files.
[InlineData(TarEntryFormat.Pax, LegacyMaxFileSize + 1)]
public async Task WriteEntry_LongFileSize(TarEntryFormat entryFormat, long size)
{
byte[] dummyContent = new byte[5];
new Random(42).NextBytes(dummyContent);

// Write archive with a 8 Gb long entry.
FileStreamOptions options = new()
{
Mode = FileMode.Create,
Access = FileAccess.ReadWrite,
Options = FileOptions.DeleteOnClose // we don't want an 8 Gb file living for too long.
};

FileStream tarFile = File.Open(GetTestFilePath(), options);
await using (TarWriter writer = new(tarFile, leaveOpen: true))
{
TarEntry writeEntry = InvokeTarEntryCreationConstructor(entryFormat, entryFormat is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile, "foo");
writeEntry.DataStream = CreateFileWithDummyContentAtTheEnds(GetTestFilePath(), size, dummyContent, options);
await writer.WriteEntryAsync(writeEntry);
}
tarFile.Position = 0;

// Read archive back.
await using TarReader reader = new TarReader(tarFile);
TarEntry entry = await reader.GetNextEntryAsync();
Assert.Null(await reader.GetNextEntryAsync());
Assert.Equal(size, entry.Length);

Stream dataStream = entry.DataStream;
Assert.Equal(size, dataStream.Length);
Assert.Equal(0, dataStream.Position);

// Read the first bytes.
byte[] buffer = new byte[dummyContent.Length];
Assert.Equal(buffer.Length, dataStream.Read(buffer));
AssertExtensions.SequenceEqual(dummyContent, buffer);
Assert.Equal(0, dataStream.ReadByte()); // check next byte is correct.
buffer.AsSpan().Clear();

// Read the last bytes.
dataStream.Seek(size - dummyContent.Length - 1, SeekOrigin.Begin);
Assert.Equal(0, dataStream.ReadByte()); // check previous byte is correct.
Assert.Equal(buffer.Length, dataStream.Read(buffer));
AssertExtensions.SequenceEqual(dummyContent, buffer);
Assert.Equal(size, dataStream.Position);
}

private static FileStream CreateFileWithDummyContentAtTheEnds(string path, long size, ReadOnlySpan<byte> dummyContent, FileStreamOptions options)
{
FileStream fs = File.Open(path, options);
fs.Write(dummyContent);

fs.Seek(size - dummyContent.Length, SeekOrigin.Begin);
fs.Write(dummyContent);

fs.Position = 0;
return fs;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Xunit;

namespace System.Formats.Tar.Tests
{
[OuterLoop]
[Collection(nameof(DisableParallelization))] // don't create multiple large files at the same time
public class TarWriter_WriteEntryAsync_LongFile_Tests : TarTestsBase
{
public static IEnumerable<object[]> WriteEntry_LongFileSize_TheoryDataAsync()
=> TarWriter_WriteEntry_LongFile_Tests.WriteEntry_LongFileSize_TheoryData();

[Theory]
[MemberData(nameof(WriteEntry_LongFileSize_TheoryDataAsync))]
public async Task WriteEntry_LongFileSizeAsync(TarEntryFormat entryFormat, long size, bool unseekableStream)
{
// Write archive with a 8 Gb long entry.
FileStream tarFile = File.Open(GetTestFilePath(), new FileStreamOptions { Access = FileAccess.ReadWrite, Mode = FileMode.Create, Options = FileOptions.DeleteOnClose });
Stream s = unseekableStream ? new WrappedStream(tarFile, tarFile.CanRead, tarFile.CanWrite, canSeek: false) : tarFile;

await using (TarWriter writer = new(s, leaveOpen: true))
{
TarEntry writeEntry = InvokeTarEntryCreationConstructor(entryFormat, entryFormat is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile, "foo");
writeEntry.DataStream = new SimulatedDataStream(size);
await writer.WriteEntryAsync(writeEntry);
}

tarFile.Position = 0;

// Read the archive back.
await using TarReader reader = new TarReader(s);
TarEntry entry = await reader.GetNextEntryAsync();
Assert.Equal(size, entry.Length);

Stream dataStream = entry.DataStream;
Assert.Equal(size, dataStream.Length);
Assert.Equal(0, dataStream.Position);

ReadOnlyMemory<byte> dummyData = SimulatedDataStream.DummyData;

// Read the first bytes.
byte[] buffer = new byte[dummyData.Length];
Assert.Equal(buffer.Length, dataStream.Read(buffer));
AssertExtensions.SequenceEqual(dummyData.Span, buffer);
Assert.Equal(0, dataStream.ReadByte()); // check next byte is correct.
buffer.AsSpan().Clear();

// Read the last bytes.
long dummyDataOffset = size - dummyData.Length - 1;
if (dataStream.CanSeek)
{
Assert.False(unseekableStream);
dataStream.Seek(dummyDataOffset, SeekOrigin.Begin);
}
else
{
Assert.True(unseekableStream);
Memory<byte> seekBuffer = new byte[4_096];

while (dataStream.Position < dummyDataOffset)
{
int bufSize = (int)Math.Min(seekBuffer.Length, dummyDataOffset - dataStream.Position);
int res = await dataStream.ReadAsync(seekBuffer.Slice(0, bufSize));
Assert.True(res > 0, "Unseekable stream finished before expected - Something went very wrong");
}
}

Assert.Equal(0, dataStream.ReadByte()); // check previous byte is correct.
Assert.Equal(buffer.Length, dataStream.Read(buffer));
AssertExtensions.SequenceEqual(dummyData.Span, buffer);
Assert.Equal(size, dataStream.Position);

Assert.Null(await reader.GetNextEntryAsync());
}
}
}