diff --git a/src/ApiService/ApiService/TestHooks/ContainerTestHooks.cs b/src/ApiService/ApiService/TestHooks/ContainerTestHooks.cs index 2be7460753..cdef6b4ae0 100644 --- a/src/ApiService/ApiService/TestHooks/ContainerTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/ContainerTestHooks.cs @@ -5,6 +5,7 @@ using Microsoft.OneFuzz.Service; +#if DEBUG namespace ApiService.TestHooks { public class ContainerTestHooks { @@ -14,12 +15,12 @@ public class ContainerTestHooks { private readonly IContainers _containers; public ContainerTestHooks(ILogTracer log, IConfigOperations configOps, IContainers containers) { - _log = log.WithTag("TestHooks", "ContainerTestHooks"); + _log = log.WithTag("TestHooks", nameof(ContainerTestHooks)); _configOps = configOps; _containers = containers; } - [Function("GetInstanceId")] + [Function("GetInstanceIdTestHook")] public async Task GetInstanceId([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/containers/instanceId")] HttpRequestData req) { _log.Info("Get instance ID"); var instanceId = await _containers.GetInstanceId(); @@ -33,3 +34,5 @@ public async Task GetInstanceId([HttpTrigger(AuthorizationLeve } } + +#endif diff --git a/src/ApiService/ApiService/TestHooks/CredsTestHookks.cs b/src/ApiService/ApiService/TestHooks/CredsTestHookks.cs index 4b9bb26cbc..23a639b9b0 100644 --- a/src/ApiService/ApiService/TestHooks/CredsTestHookks.cs +++ b/src/ApiService/ApiService/TestHooks/CredsTestHookks.cs @@ -5,7 +5,7 @@ using Microsoft.OneFuzz.Service; - +#if DEBUG namespace ApiService.TestHooks { public class CredsTestHookks { @@ -14,12 +14,12 @@ public class CredsTestHookks { private readonly ICreds _creds; public CredsTestHookks(ILogTracer log, IConfigOperations configOps, ICreds creds) { - _log = log.WithTag("TestHooks", "ContainerTestHooks"); + _log = log.WithTag("TestHooks", nameof(CredsTestHookks)); _configOps = configOps; _creds = creds; } - [Function("GetSubscription")] + [Function("GetSubscriptionTestHook")] public async Task GetSubscription([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/creds/subscription")] HttpRequestData req) { _log.Info("Get subscription"); var resp = req.CreateResponse(HttpStatusCode.OK); @@ -28,7 +28,7 @@ public async Task GetSubscription([HttpTrigger(AuthorizationLe } - [Function("GetBaseResourceGroup")] + [Function("GetBaseResourceGroupTestHook")] public async Task GetBaseResourceGroup([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/creds/baseResourceGroup")] HttpRequestData req) { _log.Info("Get base resource group"); var resp = req.CreateResponse(HttpStatusCode.OK); @@ -36,7 +36,7 @@ public async Task GetBaseResourceGroup([HttpTrigger(Authorizat return resp; } - [Function("GetInstanceName")] + [Function("GetInstanceNameTestHook")] public async Task GetInstanceName([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/creds/instanceName")] HttpRequestData req) { _log.Info("Get instance name"); var resp = req.CreateResponse(HttpStatusCode.OK); @@ -44,7 +44,7 @@ public async Task GetInstanceName([HttpTrigger(AuthorizationLe return resp; } - [Function("GetBaseRegion")] + [Function("GetBaseRegionTestHook")] public async Task GetBaseRegion([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/creds/baseRegion")] HttpRequestData req) { _log.Info("Get base region"); var resp = req.CreateResponse(HttpStatusCode.OK); @@ -53,7 +53,7 @@ public async Task GetBaseRegion([HttpTrigger(AuthorizationLeve return resp; } - [Function("GetInstanceUrl")] + [Function("GetInstanceUrlTestHook")] public async Task GetInstanceUrl([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/creds/instanceUrl")] HttpRequestData req) { _log.Info("Get instance url"); var resp = req.CreateResponse(HttpStatusCode.OK); @@ -63,3 +63,5 @@ public async Task GetInstanceUrl([HttpTrigger(AuthorizationLev } } + +#endif diff --git a/src/ApiService/ApiService/TestHooks/DiskOperationsTestHooks.cs b/src/ApiService/ApiService/TestHooks/DiskOperationsTestHooks.cs index 3422b0b79b..e6be415d4d 100644 --- a/src/ApiService/ApiService/TestHooks/DiskOperationsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/DiskOperationsTestHooks.cs @@ -6,7 +6,7 @@ using Microsoft.OneFuzz.Service; - +#if DEBUG namespace ApiService.TestHooks { public class DiskOperationsTestHooks { private readonly ILogTracer _log; @@ -15,13 +15,13 @@ public class DiskOperationsTestHooks { private readonly ICreds _creds; public DiskOperationsTestHooks(ILogTracer log, IConfigOperations configOps, IDiskOperations diskOps, ICreds creds) { - _log = log.WithTag("TestHooks", "ContainerTestHooks"); + _log = log.WithTag("TestHooks", nameof(DiskOperationsTestHooks)); _configOps = configOps; _diskOps = diskOps; _creds = creds; } - [Function("GetDiskNames")] + [Function("GetDiskNamesTestHook")] public async Task GetSubscription([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/disks")] HttpRequestData req) { _log.Info("Get disk names"); var resp = req.CreateResponse(HttpStatusCode.OK); @@ -34,3 +34,4 @@ public async Task GetSubscription([HttpTrigger(AuthorizationLe } } +#endif diff --git a/src/ApiService/ApiService/TestHooks/EventsTestHooks.cs b/src/ApiService/ApiService/TestHooks/EventsTestHooks.cs new file mode 100644 index 0000000000..09bf8307ac --- /dev/null +++ b/src/ApiService/ApiService/TestHooks/EventsTestHooks.cs @@ -0,0 +1,36 @@ +using System.Net; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.OneFuzz.Service; +using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; + +#if DEBUG +namespace ApiService.TestHooks { + + public class EventsTestHooks { + private readonly ILogTracer _log; + private readonly IConfigOperations _configOps; + private readonly IEvents _events; + + public EventsTestHooks(ILogTracer log, IConfigOperations configOps, IEvents events) { + _log = log.WithTag("TestHooks", nameof(EventsTestHooks)); + _configOps = configOps; + _events = events; + } + + [Function("LogEventTestHook")] + public async Task LogEvent([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "testhooks/events/logEvent")] HttpRequestData req) { + _log.Info("Log event"); + + var s = await req.ReadAsStringAsync(); + var msg = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); + _events.LogEvent(msg!.Event); + var resp = req.CreateResponse(HttpStatusCode.OK); + return resp; + } + } + +} +#endif diff --git a/src/ApiService/ApiService/TestHooks/ExtensionsTestHooks.cs b/src/ApiService/ApiService/TestHooks/ExtensionsTestHooks.cs new file mode 100644 index 0000000000..e33ebeb049 --- /dev/null +++ b/src/ApiService/ApiService/TestHooks/ExtensionsTestHooks.cs @@ -0,0 +1,53 @@ +using System.Net; +using System.Threading.Tasks; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.OneFuzz.Service; + + +#if DEBUG +namespace ApiService.TestHooks { + + public class ExtensionsTestHooks { + + private readonly ILogTracer _log; + private readonly IConfigOperations _configOps; + private readonly IExtensions _extensions; + + public ExtensionsTestHooks(ILogTracer log, IConfigOperations configOps, IExtensions extensions) { + _log = log.WithTag("TestHooks", nameof(ExtensionsTestHooks)); + _configOps = configOps; + _extensions = extensions; + } + + [Function("GenericExtensionsHook")] + public async Task GenericExtensions([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/extensions/genericExtensions")] HttpRequestData req) { + _log.Info("Get Generic extensions"); + + var query = UriExtension.GetQueryComponents(req.Url); + + Os os; + if (query["os"].ToLowerInvariant() == "windows") { + os = Os.Windows; + } else if (query["os"].ToLowerInvariant() == "linux") { + os = Os.Linux; + } else { + var err = req.CreateResponse(HttpStatusCode.BadRequest); + await err.WriteAsJsonAsync(new { error = $"unsupported os {query["os"]}" }); + return err; + } + + var ext = await (_extensions as Extensions)!.GenericExtensions(query["region"], os); + var resp = req.CreateResponse(HttpStatusCode.OK); + + await resp.WriteAsJsonAsync(ext); + + return resp; + } + + + + } +} + +#endif diff --git a/src/ApiService/ApiService/TestHooks/InstanceConfigTestHooks.cs b/src/ApiService/ApiService/TestHooks/InstanceConfigTestHooks.cs index f2fae2f501..840bee26ff 100644 --- a/src/ApiService/ApiService/TestHooks/InstanceConfigTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/InstanceConfigTestHooks.cs @@ -6,6 +6,8 @@ using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; + +#if DEBUG namespace ApiService.TestHooks { public class InstanceConfigTestHooks { @@ -13,11 +15,11 @@ public class InstanceConfigTestHooks { private readonly IConfigOperations _configOps; public InstanceConfigTestHooks(ILogTracer log, IConfigOperations configOps) { - _log = log.WithTag("TestHooks", "InstanceConfigTestHooks"); + _log = log.WithTag("TestHooks", nameof(InstanceConfigTestHooks)); _configOps = configOps; } - [Function("GetInstanceConfig")] + [Function("GetInstanceConfigTestHook")] public async Task Get([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/instance-config")] HttpRequestData req) { _log.Info("Fetching instance config"); var config = await _configOps.Fetch(); @@ -37,7 +39,7 @@ public async Task Get([HttpTrigger(AuthorizationLevel.Anonymou } } - [Function("PatchInstanceConfig")] + [Function("PatchInstanceConfigTestHook")] public async Task Patch([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = "testhooks/instance-config")] HttpRequestData req) { _log.Info("Patch instance config"); @@ -64,9 +66,6 @@ public async Task Patch([HttpTrigger(AuthorizationLevel.Anonym return resp; } } - - - - } } +#endif diff --git a/src/ApiService/ApiService/TestHooks/IpOperationsTestHooks.cs b/src/ApiService/ApiService/TestHooks/IpOperationsTestHooks.cs new file mode 100644 index 0000000000..469eca2dd7 --- /dev/null +++ b/src/ApiService/ApiService/TestHooks/IpOperationsTestHooks.cs @@ -0,0 +1,95 @@ +using System.Net; +using System.Threading.Tasks; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.OneFuzz.Service; + + +#if DEBUG +namespace ApiService.TestHooks { + public class IpOperationsTestHooks { + private readonly ILogTracer _log; + private readonly IConfigOperations _configOps; + private readonly IIpOperations _ipOps; + + public IpOperationsTestHooks(ILogTracer log, IConfigOperations configOps, IIpOperations ipOps) { + _log = log.WithTag("TestHooks", nameof(IpOperationsTestHooks)); + _configOps = configOps; + _ipOps = ipOps; + } + + [Function("GetPublicNicTestHook")] + public async Task GetPublicNic([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/ipOps/publicNic")] HttpRequestData req) { + _log.Info("Get public nic"); + + var query = UriExtension.GetQueryComponents(req.Url); + + var rg = query["rg"]; + var name = query["name"]; + + var nic = await _ipOps.GetPublicNic(rg, name); + + var resp = req.CreateResponse(HttpStatusCode.OK); + await resp.WriteStringAsync(nic.Get().Value.Data.Name); + return resp; + } + + [Function("GetIpTestHook")] + public async Task GetIp([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/ipOps/ip")] HttpRequestData req) { + _log.Info("Get public nic"); + + var query = UriExtension.GetQueryComponents(req.Url); + + var rg = query["rg"]; + var name = query["name"]; + + var ip = await _ipOps.GetIp(rg, name); + + var resp = req.CreateResponse(HttpStatusCode.OK); + await resp.WriteStringAsync(ip.Get().Value.Data.Name); + return resp; + } + + + [Function("DeletePublicNicTestHook")] + public async Task DeletePublicNic([HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "testhooks/ipOps/publicNic")] HttpRequestData req) { + _log.Info("Get public nic"); + + var query = UriExtension.GetQueryComponents(req.Url); + + var rg = query["rg"]; + var name = query["name"]; + var yes = UriExtension.GetBoolValue("force", query, false); + + if (yes) { + await _ipOps.DeleteNic(rg, name); + var resp = req.CreateResponse(HttpStatusCode.OK); + return resp; + } else { + var resp = req.CreateResponse(HttpStatusCode.NotModified); + return resp; + } + } + + [Function("DeleteIpTestHook")] + public async Task DeleteIp([HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "testhooks/ipOps/ip")] HttpRequestData req) { + _log.Info("Get public nic"); + + var query = UriExtension.GetQueryComponents(req.Url); + + var rg = query["rg"]; + var name = query["name"]; + var yes = UriExtension.GetBoolValue("force", query, false); + + if (yes) { + await _ipOps.DeleteIp(rg, name); + var resp = req.CreateResponse(HttpStatusCode.OK); + return resp; + } else { + var resp = req.CreateResponse(HttpStatusCode.NotModified); + return resp; + } + } + } +} +#endif diff --git a/src/ApiService/ApiService/onefuzzlib/Events.cs b/src/ApiService/ApiService/onefuzzlib/Events.cs index ebed0245c5..05f4182b98 100644 --- a/src/ApiService/ApiService/onefuzzlib/Events.cs +++ b/src/ApiService/ApiService/onefuzzlib/Events.cs @@ -13,9 +13,11 @@ List arguments public interface IEvents { - public Async.Task SendEvent(BaseEvent anEvent); + Async.Task SendEvent(BaseEvent anEvent); - public Async.Task QueueSignalrEvent(EventMessage message); + Async.Task QueueSignalrEvent(EventMessage message); + + void LogEvent(BaseEvent anEvent); } public class Events : IEvents { @@ -52,15 +54,15 @@ public async Async.Task SendEvent(BaseEvent anEvent) { ); await QueueSignalrEvent(eventMessage); await _webhook.SendEvent(eventMessage); - LogEvent(anEvent, eventType); + LogEvent(anEvent); } - public void LogEvent(BaseEvent anEvent, EventType eventType) { + public void LogEvent(BaseEvent anEvent) { var options = EntityConverter.GetJsonSerializerOptions(); options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; options.Converters.Add(new RemoveUserInfo()); var serializedEvent = JsonSerializer.Serialize(anEvent, anEvent.GetType(), options); - _log.WithTag("Event Type", eventType.ToString()).Info($"sending event: {eventType} - {serializedEvent}"); + _log.WithTag("Event Type", anEvent.GetEventType().ToString()).Info($"sending event: {anEvent.GetEventType()} - {serializedEvent}"); } } diff --git a/src/ApiService/Tests/OrmModelsTest.cs b/src/ApiService/Tests/OrmModelsTest.cs index 302193d3eb..a4b98c9f81 100644 --- a/src/ApiService/Tests/OrmModelsTest.cs +++ b/src/ApiService/Tests/OrmModelsTest.cs @@ -805,6 +805,107 @@ public bool Job(Job e) { } + [Property] + public bool EventNodeHeartbeat(EventNodeHeartbeat e) { + return Test(e); + } + + + [Property] + public bool EventTaskHeartbeat(EventTaskHeartbeat e) { + return Test(e); + } + + [Property] + public bool EventTaskStopped(EventTaskStopped e) { + return Test(e); + } + + [Property] + public bool EventInstanceConfigUpdated(EventInstanceConfigUpdated e) { + return Test(e); + } + + [Property] + public bool EventProxyCreated(EventProxyCreated e) { + return Test(e); + } + + [Property] + public bool EventProxyDeleted(EventProxyDeleted e) { + return Test(e); + } + + [Property] + public bool EventProxyFailed(EventProxyFailed e) { + return Test(e); + } + + [Property] + public bool EventProxyStateUpdated(EventProxyStateUpdated e) { + return Test(e); + } + + + [Property] + public bool EventCrashReported(EventCrashReported e) { + return Test(e); + } + + + [Property] + public bool EventRegressionReported(EventRegressionReported e) { + return Test(e); + } + + + [Property] + public bool EventFileAdded(EventFileAdded e) { + return Test(e); + } + + [Property] + public bool EventTaskFailed(EventTaskFailed e) { + return Test(e); + } + + [Property] + public bool EventTaskStateUpdated(EventTaskStateUpdated e) { + return Test(e); + } + + [Property] + public bool EventScalesetFailed(EventScalesetFailed e) { + return Test(e); + } + + + [Property] + public bool EventScalesetResizeScheduled(EventScalesetResizeScheduled e) { + return Test(e); + } + + + [Property] + public bool EventScalesetStateUpdated(EventScalesetStateUpdated e) { + return Test(e); + } + + [Property] + public bool EventNodeDeleted(EventNodeDeleted e) { + return Test(e); + } + + [Property] + public bool EventNodeCreated(EventNodeCreated e) { + return Test(e); + } + + [Property] + public bool EventMessage(EventMessage e) { + return Test(e); + } + /* //Sample function on how repro a failing test run, using Replay //functionality of FsCheck. Feel free to