singrdk/base/Applications/Tests/RamDiskTest/RamDiskTest.cs

415 lines
18 KiB
C#
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Note: Perform short test of some RamDisk and RamDiskClientManager operations.
// Used MemStress.cs as an application template.
//
using System;
using System.Collections;
using System.Threading;
using Microsoft.Singularity.UnitTest;
using Microsoft.Singularity.V1.Services;
using Microsoft.Contracts;
using Microsoft.SingSharp;
using Microsoft.SingSharp.Reflection;
using Microsoft.Singularity.Applications;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Directory;
using Microsoft.Singularity.Configuration;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.Services.RamDisk;
using Microsoft.Singularity.Services.RamDisk.Contracts;
[assembly: Transform(typeof(ApplicationResourceTransform))]
namespace Microsoft.Singularity.Applications
{
[ConsoleCategory(DefaultAction=true)]
internal class Parameters {
[InputEndpoint("data")]
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
[OutputEndpoint("data")]
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
reflective internal Parameters();
internal int AppMain() {
return RamDiskTest.AppMain(this);
}
}
public class RamDiskTest
{
internal static int AppMain(Parameters! config)
{
const int diskBytes = 2000000 /*bytes*/;
RamDiskControlContract.Imp managerImp = null;
DirectoryServiceContract.Imp dsImp = null;
DiskDeviceContract.Imp diskImp = null;
try {
managerImp = ConnectToRamDiskClientManager();
string! diskPath = CreateTest(managerImp, diskBytes);
dsImp = DirectoryService.NewClientEndpoint();
diskImp = OpenDevice(dsImp, diskPath);
int lastSector = (diskBytes - 1 + RamDisk.SECTOR_SIZE - 1)/RamDisk.SECTOR_SIZE;
BasicReadWriteTest(diskImp, 0/*sector*/, RamDisk.SECTOR_SIZE);
BasicReadWriteTest(diskImp, lastSector, RamDisk.SECTOR_SIZE);
BasicReadWriteTest(diskImp, lastSector/2, RamDisk.SECTOR_SIZE);
for (int size = RamDisk.SECTOR_SIZE; size < diskBytes; size *= 2) {
BasicReadWriteTest(diskImp, 0/*sector*/, size);
}
BasicReadWriteTest(diskImp, 0/*sector*/, diskBytes);
BasicReadWriteErrorTest(diskImp, lastSector + 1, RamDisk.SECTOR_SIZE);
BasicReadWriteErrorTest(diskImp, lastSector, 2*RamDisk.SECTOR_SIZE);
BasicReadWriteErrorTest(diskImp, 0/*sector*/, diskBytes + RamDisk.SECTOR_SIZE);
BasicReadWriteErrorTest(diskImp, lastSector/2, (lastSector + 1 - lastSector/2 + 1) * RamDisk.SECTOR_SIZE);
RandomReadWriteTest(diskImp, diskBytes);
EnsureDestroyFailsWithInUse(managerImp, diskPath);
delete diskImp;
diskImp = null;
Destroy(managerImp, diskPath, false/*force*/);
EnsureDoesNotExist(dsImp, diskPath);
OutOfMemoryTest(managerImp);
}
catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message + "\n" + ex.StackTrace);
}
finally {
delete managerImp;
delete dsImp;
delete diskImp;
}
return 0;
}
private static void BasicReadWriteTest(DiskDeviceContract.Imp:Ready! diskImp,
int sector,
int size)
{
byte[] in ExHeap data = null;
try {
data = new[ExHeap] byte[size];
for (int i = 0; i < data.Length; i++) {
data[i] = (byte)i;
}
data = Write(diskImp, 0, data);
delete data;
data = new[ExHeap] byte[size];
data = Read(diskImp, 0, data);
for (int i = 0; i < data.Length; i++) {
if (data[i] != (byte)i) {
throw new Exception(String.Format("Data did not match after write-read sequence: at byte {0} got {1}, expected {2}",
i, data[i], (byte)i));
}
}
}
finally {
delete data;
}
}
private static void BasicReadWriteErrorTest(DiskDeviceContract.Imp:Ready! imp,
int sector,
int size)
{
byte[] in ExHeap data = new[ExHeap] byte[size];
imp.SendRead(data, 0, (ulong)size, (ulong)sector);
switch receive {
case imp.AckRead(outBuffer):
delete outBuffer;
throw new Exception("RamDisk read operation succeeded where expected to fail");
case imp.NakRead():
break;
case imp.ChannelClosed():
throw new Exception("RamDisk closed channel prematurely");
}
data = new[ExHeap] byte[size];
imp.SendWrite(data, 0, (ulong)size, (ulong)sector);
switch receive {
case imp.AckWrite(outBuffer):
throw new Exception("RamDisk write operation succeeded where expected to fail");
case imp.NakWrite():
break;
case imp.ChannelClosed():
throw new Exception("RamDisk closed channel prematurely");
}
}
private static void RandomReadWriteTest(DiskDeviceContract.Imp:Ready! diskImp,
int diskBytes)
{
const int seed = 840799514; // Just an arbitrary value
const int sectorsToWrite = 1000;
int numSectors = (diskBytes - 1 + RamDisk.SECTOR_SIZE - 1)/RamDisk.SECTOR_SIZE + 1;
Random r = new Random(seed);
ArrayList! visitedSectors = new ArrayList();
byte[]! in ExHeap data = new[ExHeap] byte[RamDisk.SECTOR_SIZE];
try {
byte[]! gcData = new byte[RamDisk.SECTOR_SIZE];
for (int i = 0; i < sectorsToWrite; i++) {
int sectorNum = r.Next(numSectors);
if (visitedSectors.Contains(sectorNum)) {
continue;
}
else {
visitedSectors.Add(sectorNum);
}
r.NextBytes(gcData);
Bitter.FromByteArray(data, 0, RamDisk.SECTOR_SIZE, gcData, 0);
data = Write(diskImp, (ulong)sectorNum, data);
}
visitedSectors.Clear();
r = new Random(seed);
for (int i = 0; i < sectorsToWrite; i++) {
int sectorNum = r.Next(numSectors);
if (visitedSectors.Contains(sectorNum)) {
continue;
}
else {
visitedSectors.Add(sectorNum);
}
r.NextBytes(gcData);
data = Read(diskImp, (ulong)sectorNum, data);
for (int byteNum = 0; byteNum < data.Length; byteNum++) {
if (data[byteNum] != gcData[byteNum]) {
throw new Exception(
String.Format("Data did not match after write-read sequence: at sector {0}, byte {1}, got {2}, expected {3}",
sectorNum, byteNum, data[byteNum], gcData[byteNum]));
}
}
}
}
finally {
delete data;
}
}
private static RamDiskControlContract.Imp! ConnectToRamDiskClientManager()
{
DirectoryServiceContract.Imp! dsExp =
DirectoryService.NewClientEndpoint();
RamDiskControlContract.Imp! fccImp;
RamDiskControlContract.Exp! fccExp;
RamDiskControlContract.NewChannel(out fccImp, out fccExp);
try {
dsExp.SendBind(
Bitter.FromString2(
RamDiskControlContract.ManagerControlPath
),
fccExp);
switch receive {
case dsExp.AckBind():
switch receive {
case fccImp.Success():
return fccImp;
case fccImp.ChannelClosed():
throw new Exception("RamDisk client manager closed channel prematurely");
}
// unreached
case dsExp.NakBind(exp, errorCode):
delete exp;
delete fccImp;
throw new Exception("RamDisk client manager rejected bind");
case dsExp.ChannelClosed():
delete fccImp;
throw new Exception("RamDisk client manager closed channel prematurely");
}
}
finally {
delete dsExp;
}
}
private static void OutOfMemoryTest(RamDiskControlContract.Imp! controller)
{
controller.SendCreate(1000000000000L);
switch receive {
case controller.CreateSuccess(diskPath):
delete diskPath;
throw new Exception("Creation of very large disk succeeded where expected to fail with out of memory");
case controller.Fail(error):
if (error != RamDiskContractErrorCode.OutOfMemory) {
throw new Exception("Creation of very large disk failed with unexpected error code " + error + ", expected to fail with out of memory");
}
return;
case controller.ChannelClosed():
throw new Exception("RamDisk client manager closed channel prematurely");
}
}
private static string! CreateTest(RamDiskControlContract.Imp! controller,
ulong diskSizeBytes)
{
controller.SendCreate(diskSizeBytes);
switch receive {
case controller.CreateSuccess(diskPath):
string result = Bitter.ToString2(diskPath);
delete diskPath;
return result;
case controller.Fail(error):
throw new Exception("Create disk failed with error code " + error);
case controller.ChannelClosed():
throw new Exception("RamDisk client manager closed channel prematurely");
}
}
private static DiskDeviceContract.Imp:Ready!
OpenDevice(DirectoryServiceContract.Imp:Ready! nsImp,
string! deviceName)
{
DiskDeviceContract.Exp! diskExp;
DiskDeviceContract.Imp! diskImp;
DiskDeviceContract.NewChannel(out diskImp, out diskExp);
nsImp.SendBind(Bitter.FromString2(deviceName), diskExp);
switch receive {
case nsImp.AckBind():
switch receive {
case diskImp.Success():
return diskImp;
case diskImp.ContractNotSupported():
delete diskImp;
throw new Exception("RamDisk does not support disk contract");
case diskImp.ChannelClosed():
delete diskImp;
throw new Exception("RamDisk closed channel prematurely");
}
// unreached
case nsImp.NakBind(badExp, errorCode):
delete diskImp;
delete badExp;
throw new Exception("Failed to bind disk '" + deviceName + "' with error code " + errorCode);
case nsImp.ChannelClosed():
delete diskImp;
throw new Exception("Directory Service closed channel prematurely");
}
}
private static void EnsureDoesNotExist(DirectoryServiceContract.Imp:Ready! nsImp,
string! fileName)
{
DiskDeviceContract.Exp! fileExp;
DiskDeviceContract.Imp! fileImp;
DiskDeviceContract.NewChannel(out fileImp, out fileExp);
nsImp.SendBind(Bitter.FromString2(fileName), fileExp);
switch receive {
case nsImp.AckBind():
throw new Exception("File expected to be missing exists");
case nsImp.NakBind(badExp, errorCode):
delete fileImp;
delete badExp;
if (errorCode != ErrorCode.NotFound) {
throw new Exception("Failed to bind file '" + fileName + "' expected to be missing with unexpected error code " + errorCode);
}
return;
case nsImp.ChannelClosed():
delete fileImp;
throw new Exception("Directory Service closed channel prematurely");
}
}
private static byte[]! in ExHeap Read(DiskDeviceContract.Imp:Ready! imp,
ulong sectorId,
[Claims] byte[]! in ExHeap data)
{
ulong dataLength = (ulong)data.Length;
imp.SendRead(data, 0, dataLength, sectorId);
switch receive {
case imp.AckRead(outBuffer):
return outBuffer;
case imp.NakRead():
throw new Exception("RamDisk rejected read operation");
case imp.ChannelClosed():
throw new Exception("RamDisk closed channel prematurely");
}
}
private static byte[]! in ExHeap Write(DiskDeviceContract.Imp:Ready! imp,
ulong sectorId,
[Claims] byte[]! in ExHeap data)
{
imp.SendWrite(data, 0, (ulong)data.Length, sectorId);
switch receive {
case imp.AckWrite(outBuffer):
return outBuffer;
case imp.NakWrite():
throw new Exception("RamDisk rejected write operation");
case imp.ChannelClosed():
throw new Exception("RamDisk closed channel prematurely");
}
}
private static void EnsureDestroyFailsWithInUse(RamDiskControlContract.Imp! controller,
string! diskPath)
{
char[] in ExHeap diskPathExHeap = Bitter.FromString2(diskPath);
controller.SendDestroy(diskPathExHeap, false/*force*/);
switch receive {
case controller.Success():
throw new Exception("Destroy disk succeeded where expected to fail with in-use error");
case controller.Fail(errorCode):
if (errorCode != RamDiskContractErrorCode.IsInUse) {
throw new Exception("Destroy disk failed with unexpected error code " + errorCode + ", expected in-use");
}
return;
case controller.ChannelClosed():
throw new Exception("RamDisk client manager closed channel prematurely");
}
}
private static void Destroy(RamDiskControlContract.Imp! controller,
string! diskPath,
bool force)
{
char[] in ExHeap diskPathExHeap = Bitter.FromString2(diskPath);
controller.SendDestroy(diskPathExHeap, force);
switch receive {
case controller.Success():
return;
case controller.Fail(error):
throw new Exception("Destroy disk failed with error code " + error);
case controller.ChannelClosed():
throw new Exception("RamDisk client manager closed channel prematurely");
}
}
}
}