2using System.Collections.Concurrent;
3using System.Collections.Generic;
4using System.Diagnostics;
7using System.Reflection;
9using System.Threading.Tasks;
19using Microsoft.VisualStudio.TestTools.UnitTesting;
24using TestCategory =
NUnit.Framework.CategoryAttribute;
33 private const string Category =
"Test Utilities";
35 #region Test Sample Injection
36 [
TestMethod, TestCategory(Category), TestCategory(
"Randomized")]
49 if (
property.PropertyType.GetGenericArguments()[0]
57 while (!result.IsCompleted)
61 "concurrent resource injection:\n" + String.Join(
"\n",
thread_failures));
69 "\" (type " +
property.PropertyType.NiceTypeName() +
") concurrent request received.");
73 "\" (type " +
property.PropertyType.NiceTypeName() +
") acquired. Invoking Post.");
76 "\" (type " +
property.PropertyType.NiceTypeName() +
") Post Complete.");
115 [
TestMethod, TestCategory(Category), TestCategory(
"Randomized")]
121 Console.WriteLine(
"Note: Configured Target Analysis Profile is: " +
123 Console.WriteLine(
" Configured Target Event Catalog is: " +
128#pragma warning disable 162
130 tests.AsParallel().ForAll(RandomTypeTest);
132 tests.ToList().ForEach(RandomTypeTest);
133#pragma warning restore 162
137 private void RandomTypeTest(Type
subtype)
143 Assert.Fail(
"CreateRandomizedInstance did not generate a valid " +
144 $"{subtype.NiceTypeName()} instance. Result was \"{test ?? "(
null)
"}\"");
148 string threadId =
$"T{Thread.CurrentThread.ManagedThreadId} ";
149 Console.WriteLine(
$"{threadId}{DateTime.UtcNow:mm:ss.ff} Generated a random " +
150 $"{subtype.NiceTypeName()} with runtime type {test.GetType().NiceTypeName()}");
160 apiError.RestResponse.StatusCode == HttpStatusCode.BadRequest ?
161 $"generated an invalid {subtype.NiceTypeName()} resulting in a rejected POST" :
162 $"encountered an unexpected POST error for a random {subtype.NiceTypeName()}";
163 string msg =
$"{threadId}{DateTime.UtcNow:mm:ss.ff} CreateRandomizedInstance {issue}." +
164 $"\nThe posted JSON was:\n{testResource.Serialize()}" +
165 $"\nThe response error was:\n{ex}";
177 .GetUserFacingProperties(
true,
true).ToList();
183 string strProperty =
$"the {test.GetType().NiceTypeName()} property " +
184 $"{prop.PropertyType.NiceTypeName()} {prop.DeclaringType.NiceTypeName()}.{prop.Name}";
185 Console.WriteLine(
$"{threadId}{DateTime.UtcNow:mm:ss.ff} Randomizing {strProperty}");
191 Console.WriteLine(
$"{threadId}{DateTime.UtcNow:mm:ss.ff} RandomizePropertyValue " +
192 $"reported an error generating {strProperty}:\n{ex.Message}");
200 $"\n Original: {Output.AutoFormat(v1)}" +
201 $"\n Modified: {Output.AutoFormat(v2)}";
204 try { modified = modified.Post(); }
208 apiError.RestResponse.StatusCode == HttpStatusCode.BadRequest ?
209 $"generated an invalid value for {strProperty} resulting in a rejected POST" :
210 $"encountered an unexpected POST error after randomly modifying {strProperty}";
211 string msg =
$"{threadId}{DateTime.UtcNow:mm:ss.ff} RandomizePropertyValue {issue}." +
212 $"Property values are:{DebugValues(originalValue, newValue)}\n\n" +
213 $"Entire resource definitions:{DebugValues(testResource, modified)}\n";
214 Console.WriteLine(
$"{msg}{ex.Message}");
222 Console.WriteLine(
$"{threadId}{DateTime.UtcNow:mm:ss.ff} RandomizePropertyValue " +
223 $"failed to change {strProperty} - possibly because validation rules are " +
224 $"overly restrictive.{DebugValues(originalValue, newValue)}");
228 Assert.Fail(
$"The server returned the same resource id ({modified.id}) after " +
229 $"randomly changing {strProperty}.{DebugValues(originalValue, newValue)}");
234 #endregion Test Sample Injection
240 Assert.Inconclusive(
"RUN_OFFLINE = true");
245 "The test utility did not properly detect that the server is not clean.");
252 Assert.Inconclusive(
"Cannot test wiping server while running tests in parallel.");
279 if (
elapsed.TotalMilliseconds < 10)
280 Assert.Inconclusive(
"This test relies on timing out before a request completes, " +
281 "but this request appears to have completed so quickly (< 10ms) " +
282 "that timeout couldn't be enforced.");
286 string messageIfFailed =
"The returned error message isn't as expected:\n" +
ex.Message;
289 "If this is a large request, you may need to wait longer for a response. " +
290 "Check your API.DefaultRequestTimeout or set a timeout directly in your API call."),
Create a test class that takes care of setting the server URL and cleaning up after each unit test.
Exposes sample resource objects, with built-in methods for injecting dependencies.
static List< Type > GetAPIResourceTypes()
A list of base "production" resource types on the server, (e.g. each with their own collection) used ...
IInjectableResource< BinomialDistribution > Distribution_BinomialDistribution
static void IsValidUUID(string toCheck)
Assert that the string is a valid UUID.
Utilities for cleaning up the server.
static bool CheckServerIsClean(bool ignoreExceptions=false)
Check all known server endpoints and determine whether there are any resources on the server.
Retrieve settings from environment variables if they exist, or the project settings file otherwise.
static bool RUN_OFFLINE
Controls whether tests that normally require a connection to the server should be allowed to try to r...
static bool ROOT_DELETE_SUPPORTED
Indicates whether the server currently supports the DELETE method on the server root to wipe out all ...
static bool RESOURCE_DELETE_SUPPORTED
Indicates whether the server currently supports the DELETE method on resources.
static bool EXECUTING_IN_PARALLEL
If true, tests are being run in parallel, so certain assumptions about the state of the server after ...
An exception throw when a random generation routine fails to produce a POSTable resource.
A collection of filthy hacks to populate some fields of APIResources objects of any type.
static IEnumerable< Type > GetAllInstantiableSubtypes(Type type)
Creates a list of types that can be derived from a given type.
AnalysisProfile Target_AnalysisProfile
The default AnalysisProfile to use for various validation assurances.
object ChangePropertyValueRandomly(IAPIType obj, PropertyInfo prop, int max_attempts=Max_ReRandomize_Attempts, RecursionContext parentRecursionInfo=null)
Randomly change the specified property to some different value.
object CreateRandomizedInstance(Type desiredType, RecursionContext parentRecursionInfo=null)
Generates a new randomized object of the specified type.
A collection of scripts that are sometimes used to batch seed or modify data on a test server.
A custom exception class that includes the RestSharp.IRestResponse that generated the exception,...
string id
The resource's unique identifier. It will be used in the request URL when requesting the resource fro...
Describes a collection of resources which can be listed.
API methods / requests made available to the user.
static ICollectionResponse< IAPIResource > GetResourceList(Type resourceType, IEnumerable< Parameter > requestParameters=null, string collectionNameOverride=null, int? timeout=null)
Get a collection of resources from the server.
List< IReference< EventCatalog > > event_catalogs
The EventCatalogs to use during this simulation.
Indicates that while the current APIResource-derived class can be constructed and potentially inlined...
Abstract representation of a distribution, used for parametric loss sets.
Abstract representation of a layer. This resource type cannot be instantiated instead derived resourc...
Determines the behaviour of the API when automatically retrying a request whose result is not yet rea...
static PollingOptions Default
The default PollingArguments used when none are specified.
Extends the TimeoutException class to contain the IRestResponse that timed out.
T Posted
The posted resource, ready to be referenced.
Interface for Base class used by all resources.
string id
The resource's unique identifier. It will be used in the request URL when requesting the resource fro...