mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-10 01:01:34 +00:00
tests and bug fixes (#2379)
Co-authored-by: stas <statis@microsoft.com>
This commit is contained in:
parent
9f03a174ec
commit
9eaf92ea35
@ -40,7 +40,7 @@ public class Node {
|
||||
req,
|
||||
new Error(
|
||||
Code: ErrorCode.UNABLE_TO_FIND,
|
||||
Errors: new string[] { "unable to find node " }),
|
||||
Errors: new string[] { "unable to find node" }),
|
||||
context: machineId.ToString());
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ public class Node {
|
||||
req,
|
||||
new Error(
|
||||
Code: ErrorCode.UNABLE_TO_FIND,
|
||||
Errors: new string[] { "unable to find node " }),
|
||||
Errors: new string[] { "unable to find node" }),
|
||||
context: patch.MachineId.ToString());
|
||||
}
|
||||
|
||||
@ -129,7 +129,7 @@ public class Node {
|
||||
req,
|
||||
new Error(
|
||||
Code: ErrorCode.UNABLE_TO_FIND,
|
||||
Errors: new string[] { "unable to find node " }),
|
||||
Errors: new string[] { "unable to find node" }),
|
||||
context: post.MachineId.ToString());
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ public class Tasks {
|
||||
return await RequestHandling.Ok(req, result);
|
||||
}
|
||||
|
||||
var tasks = await _context.TaskOperations.SearchAll().ToListAsync();
|
||||
var tasks = await _context.TaskOperations.SearchStates(request.OkV.JobId, request.OkV.State).ToListAsync();
|
||||
var response2 = req.CreateResponse(HttpStatusCode.OK);
|
||||
await response2.WriteAsJsonAsync(tasks);
|
||||
return response2;
|
||||
|
@ -77,7 +77,7 @@ public class ScalesetOperations : StatefulOrm<Scaleset, ScalesetState, ScalesetO
|
||||
_log.Info($"{SCALESET_LOG_PREFIX} unexpected scaleset size, resizing. scaleset_id: {scaleset.ScalesetId} expected:{scaleset.Size} actual:{size}");
|
||||
|
||||
scaleset = scaleset with { Size = size.Value };
|
||||
var replaceResult = await Update(scaleset);
|
||||
var replaceResult = await Replace(scaleset);
|
||||
if (!replaceResult.IsOk) {
|
||||
_log.Error($"Failed to update scaleset size for scaleset {scaleset.ScalesetId} due to {replaceResult.ErrorV}");
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ public class VmssOperations : IVmssOperations {
|
||||
var res = await GetVmssResource(name).GetAsync();
|
||||
_log.Verbose($"getting vmss: {name}");
|
||||
return res.Value.Data;
|
||||
} catch (Exception ex) when (ex is RequestFailedException) {
|
||||
} catch (RequestFailedException ex) when (ex.Status == 404) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,135 @@
|
||||
using System.Text.Json;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
public static class JsonObjectExt {
|
||||
public static JsonObject AddIfNotNullV<T>(this JsonObject o, string name, T? v) {
|
||||
if (v is not null)
|
||||
o.Add(name, JsonValue.Create(v));
|
||||
return o;
|
||||
}
|
||||
|
||||
public static JsonObject AddIfNotNullEnumerableV<T>(this JsonObject o, string name, IEnumerable<T>? v) {
|
||||
if (v is not null)
|
||||
o.Add(name, JsonValue.Create(new JsonArray(v.Select(s => JsonValue.Create(s)).ToArray())));
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
public static JsonObject AddV<T>(this JsonObject o, string name, T v) {
|
||||
o.Add(name, JsonValue.Create(v));
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
public static class JsonElementExt {
|
||||
public static string GetRawTextProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).GetRawText();
|
||||
}
|
||||
|
||||
public static DateTimeOffset GetDateTimeOffsetProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).GetDateTimeOffset()!;
|
||||
}
|
||||
|
||||
public static DateTimeOffset? GetNullableDateTimeOffsetProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).GetDateTimeOffset();
|
||||
}
|
||||
|
||||
public static Guid? GetNullableGuidProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).ValueKind == JsonValueKind.Null ? null : e.GetProperty(property).GetGuid();
|
||||
}
|
||||
|
||||
public static Guid GetGuidProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).GetGuid();
|
||||
}
|
||||
|
||||
public static bool? GetNullableBoolProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).ValueKind == JsonValueKind.Null ? null : e.GetProperty(property).GetBoolean();
|
||||
}
|
||||
|
||||
public static long? GetNullableLongProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).ValueKind == JsonValueKind.Null ? null : e.GetProperty(property).GetInt64();
|
||||
}
|
||||
|
||||
public static string? GetNullableStringProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).ValueKind == JsonValueKind.Null ? null : e.GetProperty(property).GetString();
|
||||
}
|
||||
|
||||
public static string GetStringProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).GetString()!;
|
||||
}
|
||||
|
||||
public static long GetLongProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).GetInt64();
|
||||
}
|
||||
|
||||
public static int GetIntProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).GetInt32();
|
||||
}
|
||||
|
||||
public static bool GetBoolProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).GetBoolean();
|
||||
}
|
||||
|
||||
public static T GetObjectProperty<T>(this JsonElement e, string property) where T : IFromJsonElement<T>, new() {
|
||||
return new T().Convert(e.GetProperty(property)!);
|
||||
}
|
||||
|
||||
public static T? GetNullableObjectProperty<T>(this JsonElement e, string property) where T : IFromJsonElement<T>, new() {
|
||||
return e.GetProperty(property).ValueKind == JsonValueKind.Null ? default(T) : new T().Convert(e.GetProperty(property)!);
|
||||
}
|
||||
|
||||
public static IDictionary<string, string>? GetNullableStringDictProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).Deserialize<IDictionary<string, string>>();
|
||||
}
|
||||
|
||||
public static IDictionary<string, string> GetStringDictProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property).Deserialize<IDictionary<string, string>>()!;
|
||||
}
|
||||
|
||||
public static IDictionary<string, T> GetDictProperty<T>(this JsonElement e, string property) where T : IFromJsonElement<T>, new() {
|
||||
return new Dictionary<string, T>(
|
||||
e.GetProperty(property)!.Deserialize<IDictionary<string, JsonElement>>()!.Select(
|
||||
kv => KeyValuePair.Create(kv.Key, new T().Convert(kv.Value))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static IEnumerable<Guid> GetEnumerableGuidProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property)!.EnumerateArray().Select(e => e.GetGuid()!);
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<string> GetEnumerableStringProperty(this JsonElement e, string property) {
|
||||
return e.GetProperty(property)!.EnumerateArray().Select(e => e.GetString()!);
|
||||
}
|
||||
|
||||
public static IEnumerable<string>? GetEnumerableNullableStringProperty(this JsonElement e, string property) {
|
||||
if (e.GetProperty(property).ValueKind == JsonValueKind.Null)
|
||||
return null;
|
||||
else
|
||||
return e.GetProperty(property)!.EnumerateArray().Select(e => e.GetString()!);
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<T> GetEnumerableProperty<T>(this JsonElement e, string property) where T : IFromJsonElement<T>, new() {
|
||||
return e.GetProperty(property).EnumerateArray().Select(e => new T().Convert(e)!);
|
||||
}
|
||||
|
||||
public static IEnumerable<T>? GetEnumerableNullableProperty<T>(this JsonElement e, string property) where T : IFromJsonElement<T>, new() {
|
||||
if (e.GetProperty(property).ValueKind == JsonValueKind.Null)
|
||||
return null;
|
||||
else
|
||||
return e.GetProperty(property).EnumerateArray().Select(e => new T().Convert(e)!);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public interface IFromJsonElement<T> {
|
||||
T Convert(JsonElement e);
|
||||
}
|
||||
@ -14,6 +139,10 @@ public class BooleanResult : IFromJsonElement<BooleanResult> {
|
||||
public BooleanResult() { }
|
||||
public BooleanResult(JsonElement e) => _e = e;
|
||||
|
||||
public bool IsError => Error.IsError(_e);
|
||||
|
||||
public Error? Error => new Error(_e);
|
||||
|
||||
public bool Result => _e.GetProperty("result").GetBoolean();
|
||||
|
||||
public BooleanResult Convert(JsonElement e) => new BooleanResult(e);
|
||||
@ -30,6 +159,22 @@ public abstract class ApiBase {
|
||||
_endpoint = new Uri(endpoint, relativeUri);
|
||||
_output = output;
|
||||
}
|
||||
public async Task<Result<Stream, (HttpStatusCode, Error?)>> QueryGet(string? query) {
|
||||
Uri uri;
|
||||
if (String.IsNullOrEmpty(query))
|
||||
uri = _endpoint;
|
||||
else
|
||||
uri = new Uri($"{_endpoint}?{query}");
|
||||
var r = await _request.Get(uri);
|
||||
if (r.IsSuccessStatusCode) {
|
||||
return Result<Stream, (HttpStatusCode, Error?)>.Ok(r.Content.ReadAsStream());
|
||||
} else if (r.StatusCode == HttpStatusCode.InternalServerError) {
|
||||
return Result<Stream, (HttpStatusCode, Error?)>.Error((r.StatusCode, null));
|
||||
} else {
|
||||
var e = (await JsonDocument.ParseAsync(r.Content.ReadAsStream())).RootElement;
|
||||
return Result<Stream, (HttpStatusCode, Error?)>.Error((r.StatusCode, new Error(e)));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<JsonElement> Get(JsonObject root) {
|
||||
var body = root.ToJsonString();
|
||||
|
18
src/ApiService/FunctionalTests/1f-api/Authentication.cs
Normal file
18
src/ApiService/FunctionalTests/1f-api/Authentication.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
public class Authentication : IFromJsonElement<Authentication> {
|
||||
JsonElement _e;
|
||||
|
||||
public Authentication() { }
|
||||
public Authentication(JsonElement e) => _e = e;
|
||||
|
||||
public string Password => _e.GetStringProperty("password");
|
||||
|
||||
public string PublicKey => _e.GetStringProperty("public_key");
|
||||
public string PrivateKey => _e.GetStringProperty("private_key");
|
||||
|
||||
public Authentication Convert(JsonElement e) => new Authentication(e);
|
||||
|
||||
}
|
48
src/ApiService/FunctionalTests/1f-api/Container.cs
Normal file
48
src/ApiService/FunctionalTests/1f-api/Container.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests {
|
||||
|
||||
public class ContainerInfo : IFromJsonElement<ContainerInfo> {
|
||||
JsonElement _e;
|
||||
public ContainerInfo() { }
|
||||
public ContainerInfo(JsonElement e) => _e = e;
|
||||
public ContainerInfo Convert(JsonElement e) => new ContainerInfo(e);
|
||||
public string Name => _e.GetStringProperty("name");
|
||||
public IDictionary<string, string>? Metadata => _e.GetNullableStringDictProperty("metadata");
|
||||
public Uri SasUrl => new Uri(_e.GetStringProperty("sas_url"));
|
||||
}
|
||||
|
||||
public class ContainerApi : ApiBase {
|
||||
|
||||
public ContainerApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||
base(endpoint, "/api/Containers", request, output) {
|
||||
}
|
||||
|
||||
public async Task<Result<IEnumerable<ContainerInfo>, Error>> Get(string? name = null) {
|
||||
var n = new JsonObject()
|
||||
.AddIfNotNullV("name", name);
|
||||
|
||||
var res = await Get(n);
|
||||
return IEnumerableResult<ContainerInfo>(res);
|
||||
}
|
||||
|
||||
public async Task<BooleanResult> Delete(string name, IDictionary<string, string>? metadata = null) {
|
||||
var n = new JsonObject()
|
||||
.AddV("name", name)
|
||||
.AddIfNotNullV("metadata", metadata);
|
||||
|
||||
return Return<BooleanResult>(await Delete(n));
|
||||
}
|
||||
|
||||
public async Task<Result<ContainerInfo, Error>> Post(string name, IDictionary<string, string>? metadata = null) {
|
||||
var n = new JsonObject()
|
||||
.AddV("name", name)
|
||||
.AddIfNotNullV("metadata", metadata);
|
||||
var res = await Post(n);
|
||||
return Result<ContainerInfo>(res);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
21
src/ApiService/FunctionalTests/1f-api/Download.cs
Normal file
21
src/ApiService/FunctionalTests/1f-api/Download.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests {
|
||||
public class DownloadApi : ApiBase {
|
||||
|
||||
public DownloadApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||
base(endpoint, "/api/Download", request, output) {
|
||||
}
|
||||
|
||||
public async Task<Result<Stream, (HttpStatusCode, Error?)>> Get(string? container = null, string? filename = null) {
|
||||
var n = HttpUtility.ParseQueryString(string.Empty);
|
||||
if (container is not null)
|
||||
n.Add("container", container);
|
||||
if (filename is not null)
|
||||
n.Add("filename", filename);
|
||||
return await QueryGet(n.ToString());
|
||||
}
|
||||
}
|
||||
}
|
@ -6,14 +6,16 @@ namespace FunctionalTests;
|
||||
public class Error : IComparable<Error>, IFromJsonElement<Error> {
|
||||
JsonElement _e;
|
||||
|
||||
public Error() { }
|
||||
|
||||
public Error(JsonElement e) {
|
||||
_e = e;
|
||||
Assert.True(_e.EnumerateObject().Count() == 2);
|
||||
}
|
||||
|
||||
public int Code => _e.GetProperty("code").GetInt32();
|
||||
public int Code => _e.GetIntProperty("code");
|
||||
|
||||
public IEnumerable<string> Errors => _e.GetProperty("errors").EnumerateArray().Select(e => e.GetString()!);
|
||||
public IEnumerable<string> Errors => _e.GetEnumerableStringProperty("errors");
|
||||
|
||||
public Error Convert(JsonElement e) => new Error(e);
|
||||
|
||||
@ -49,5 +51,9 @@ public class Error : IComparable<Error>, IFromJsonElement<Error> {
|
||||
|
||||
public bool UnableToFindScalesetError => Code == 450 && Errors.First() == "unable to find scaleset";
|
||||
|
||||
public bool UnableToFindNode => Code == 467 && Errors.First() == "unable to find node ";
|
||||
public bool UnableToFindNode => Code == 467 && Errors.First() == "unable to find node";
|
||||
|
||||
public bool ShouldBeProvided(string p) => Code == 450 && Errors.First() == $"'{p}' query parameter must be provided";
|
||||
|
||||
public bool UnableToFindTask => Code == 450 && Errors.First() == "unable to find task";
|
||||
}
|
||||
|
48
src/ApiService/FunctionalTests/1f-api/Info.cs
Normal file
48
src/ApiService/FunctionalTests/1f-api/Info.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests {
|
||||
|
||||
public class InfoVersion : IFromJsonElement<InfoVersion> {
|
||||
JsonElement _e;
|
||||
|
||||
public InfoVersion() { }
|
||||
public InfoVersion(JsonElement e) => _e = e;
|
||||
public InfoVersion Convert(JsonElement e) => new InfoVersion(e);
|
||||
|
||||
public string Git => _e.GetProperty("git").GetString()!;
|
||||
public string Build => _e.GetProperty("build").GetString()!;
|
||||
public string Version => _e.GetProperty("version").GetString()!;
|
||||
}
|
||||
|
||||
|
||||
public class InfoResponse : IFromJsonElement<InfoResponse> {
|
||||
JsonElement _e;
|
||||
|
||||
public InfoResponse() { }
|
||||
|
||||
public InfoResponse(JsonElement e) => _e = e;
|
||||
|
||||
public InfoResponse Convert(JsonElement e) => new InfoResponse(e);
|
||||
|
||||
public string ResourceGroup => _e.GetStringProperty("resource_group")!;
|
||||
public string Region => _e.GetStringProperty("region")!;
|
||||
public string Subscription => _e.GetStringProperty("subscription")!;
|
||||
public IDictionary<string, InfoVersion> Versions => _e.GetDictProperty<InfoVersion>("property");
|
||||
}
|
||||
|
||||
|
||||
class InfoApi : ApiBase {
|
||||
|
||||
public InfoApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||
base(endpoint, "/api/Info", request, output) {
|
||||
}
|
||||
|
||||
public async Task<Result<InfoResponse, Error>> Get() {
|
||||
var n = new JsonObject();
|
||||
var res = await Get(n);
|
||||
return Result<InfoResponse>(res);
|
||||
}
|
||||
}
|
||||
}
|
78
src/ApiService/FunctionalTests/1f-api/Jobs.cs
Normal file
78
src/ApiService/FunctionalTests/1f-api/Jobs.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
public class JobTaskInfo : IFromJsonElement<JobTaskInfo> {
|
||||
JsonElement _e;
|
||||
|
||||
public JobTaskInfo() { }
|
||||
|
||||
public JobTaskInfo(JsonElement e) => _e = e;
|
||||
|
||||
public JobTaskInfo Convert(JsonElement e) => new JobTaskInfo(e);
|
||||
|
||||
public Guid TaskId => _e.GetGuidProperty("task_id");
|
||||
|
||||
public string Type => _e.GetStringProperty("type");
|
||||
|
||||
public string State => _e.GetStringProperty("state");
|
||||
}
|
||||
|
||||
|
||||
public class Job : IFromJsonElement<Job> {
|
||||
JsonElement _e;
|
||||
|
||||
public Job() { }
|
||||
public Job(JsonElement e) => _e = e;
|
||||
|
||||
public Job Convert(JsonElement e) => new Job(e);
|
||||
|
||||
public Guid JobId => _e.GetGuidProperty("job_id");
|
||||
|
||||
public string State => _e.GetStringProperty("state");
|
||||
|
||||
public string? Error => _e.GetNullableStringProperty("error");
|
||||
|
||||
public DateTimeOffset? EndTime => _e.GetNullableDateTimeOffsetProperty("end_time");
|
||||
|
||||
public IEnumerable<JobTaskInfo>? TaskInfo => _e.GetEnumerableNullableProperty<JobTaskInfo>("task_info");
|
||||
}
|
||||
|
||||
public class Jobs : ApiBase {
|
||||
|
||||
public Jobs(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||
base(endpoint, "/api/Jobs", request, output) {
|
||||
}
|
||||
|
||||
public async Task<Result<IEnumerable<Job>, Error>> Get(Guid? jobId = null, List<string>? state = null, List<string>? taskState = null, bool? withTasks = null) {
|
||||
var n = new JsonObject()
|
||||
.AddIfNotNullV("job_id", jobId)
|
||||
.AddIfNotNullV("state", state)
|
||||
.AddIfNotNullV("task_state", taskState)
|
||||
.AddIfNotNullV("with_tasks", withTasks);
|
||||
|
||||
var r = await Get(n);
|
||||
return IEnumerableResult<Job>(r);
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result<Job, Error>> Post(string project, string name, string build, long duration, string? logs = null) {
|
||||
var n = new JsonObject()
|
||||
.AddV("project", project)
|
||||
.AddV("name", name)
|
||||
.AddV("build", build)
|
||||
.AddV("duration", duration)
|
||||
.AddIfNotNullV("logs", logs);
|
||||
|
||||
var r = await Post(n);
|
||||
return Result<Job>(r);
|
||||
}
|
||||
|
||||
public async Task<Result<Job, Error>> Delete(Guid jobId) {
|
||||
var n = new JsonObject().AddV("job_id", jobId);
|
||||
var r = await Delete(n);
|
||||
return Result<Job>(r);
|
||||
}
|
||||
}
|
4
src/ApiService/FunctionalTests/1f-api/Negotiate.cs
Normal file
4
src/ApiService/FunctionalTests/1f-api/Negotiate.cs
Normal file
@ -0,0 +1,4 @@
|
||||
namespace FunctionalTests {
|
||||
public class NegotiateApi {
|
||||
}
|
||||
}
|
@ -12,24 +12,24 @@ public class Node : IFromJsonElement<Node> {
|
||||
|
||||
public Node(JsonElement e) => _e = e;
|
||||
|
||||
public string PoolName => _e.GetProperty("pool_name").GetString()!;
|
||||
public string PoolName => _e.GetStringProperty("pool_name");
|
||||
|
||||
public Guid MachineId => _e.GetProperty("machine_id").GetGuid();
|
||||
public Guid MachineId => _e.GetGuidProperty("machine_id");
|
||||
|
||||
public Guid? PoolId => _e.GetProperty("pool_id").ValueKind == JsonValueKind.Null ? null : _e.GetProperty("pool_id").GetGuid();
|
||||
public Guid? PoolId => _e.GetNullableGuidProperty("pool_id");
|
||||
|
||||
public string Version => _e.GetProperty("version").GetString()!;
|
||||
public string Version => _e.GetStringProperty("version");
|
||||
|
||||
public DateTimeOffset? HeartBeat => _e.GetProperty("heart_beat").ValueKind == JsonValueKind.Null ? null : _e.GetProperty("heart_beat").GetDateTimeOffset();
|
||||
public DateTimeOffset? HeartBeat => _e.GetNullableDateTimeOffsetProperty("heart_beat");
|
||||
|
||||
public DateTimeOffset? InitializedAt => _e.GetProperty("initialized_at").ValueKind == JsonValueKind.Null ? null : _e.GetProperty("initialized_at").GetDateTimeOffset();
|
||||
public DateTimeOffset? InitializedAt => _e.GetNullableDateTimeOffsetProperty("initialized_at");
|
||||
|
||||
public string State => _e.GetProperty("state").GetString()!;
|
||||
public string State => _e.GetStringProperty("state");
|
||||
|
||||
public Guid? ScalesetId => _e.GetProperty("scaleset_id").ValueKind == JsonValueKind.Null ? null : _e.GetProperty("scaleset_id").GetGuid();
|
||||
public bool ReimageRequested => _e.GetProperty("reimage_requested").GetBoolean();
|
||||
public bool DeleteRequested => _e.GetProperty("delete_requested").GetBoolean();
|
||||
public bool DebugKeepNode => _e.GetProperty("debug_keep_node").GetBoolean();
|
||||
public Guid? ScalesetId => _e.GetNullableGuidProperty("scaleset_id");
|
||||
public bool ReimageRequested => _e.GetBoolProperty("reimage_requested");
|
||||
public bool DeleteRequested => _e.GetBoolProperty("delete_requested");
|
||||
public bool DebugKeepNode => _e.GetBoolProperty("debug_keep_node");
|
||||
|
||||
public Node Convert(JsonElement e) => new Node(e);
|
||||
}
|
||||
@ -42,39 +42,28 @@ public class NodeApi : ApiBase {
|
||||
}
|
||||
|
||||
public async Task<BooleanResult> Update(Guid machineId, bool? debugKeepNode = null) {
|
||||
var j = new JsonObject();
|
||||
if (debugKeepNode is not null)
|
||||
j.Add("debug_keep_node", JsonValue.Create(debugKeepNode));
|
||||
|
||||
j.Add("machine_id", JsonValue.Create(machineId));
|
||||
var j = new JsonObject()
|
||||
.AddIfNotNullV("debug_keep_node", debugKeepNode)
|
||||
.AddV("machine_id", machineId);
|
||||
return Return<BooleanResult>(await Post(j));
|
||||
}
|
||||
public async Task<Result<IEnumerable<Node>, Error>> Get(Guid? machineId = null, List<string>? state = null, Guid? scalesetId = null, string? poolName = null) {
|
||||
var j = new JsonObject();
|
||||
if (machineId is not null)
|
||||
j.Add("machine_id", JsonValue.Create(machineId));
|
||||
if (state is not null) {
|
||||
var states = new JsonArray(state.Select(s => JsonValue.Create(s)).ToArray());
|
||||
j.Add("state", JsonValue.Create(states));
|
||||
}
|
||||
if (scalesetId is not null)
|
||||
j.Add("scaleset_id", JsonValue.Create(scalesetId));
|
||||
|
||||
if (poolName is not null)
|
||||
j.Add("pool_name", JsonValue.Create(poolName));
|
||||
public async Task<Result<IEnumerable<Node>, Error>> Get(Guid? machineId = null, IEnumerable<string>? state = null, Guid? scalesetId = null, string? poolName = null) {
|
||||
var j = new JsonObject()
|
||||
.AddIfNotNullV("machine_id", machineId)
|
||||
.AddIfNotNullEnumerableV("state", state)
|
||||
.AddIfNotNullV("scaleset_id", scalesetId)
|
||||
.AddIfNotNullV("pool_name", poolName);
|
||||
|
||||
return IEnumerableResult<Node>(await Get(j));
|
||||
}
|
||||
|
||||
public async Task<BooleanResult> Patch(Guid machineId) {
|
||||
var j = new JsonObject();
|
||||
j.Add("machine_id", JsonValue.Create(machineId));
|
||||
var j = new JsonObject().AddV("machine_id", machineId);
|
||||
return Return<BooleanResult>(await Patch(j));
|
||||
}
|
||||
|
||||
public async Task<BooleanResult> Delete(Guid machineId) {
|
||||
var j = new JsonObject();
|
||||
j.Add("machine_id", JsonValue.Create(machineId));
|
||||
var j = new JsonObject().AddV("machine_id", machineId);
|
||||
return Return<BooleanResult>(await Delete(j));
|
||||
}
|
||||
|
||||
|
21
src/ApiService/FunctionalTests/1f-api/NodeAddSshKey.cs
Normal file
21
src/ApiService/FunctionalTests/1f-api/NodeAddSshKey.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
||||
namespace FunctionalTests {
|
||||
public class NodeAddSshKeyApi : ApiBase {
|
||||
|
||||
public NodeAddSshKeyApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||
base(endpoint, "/api/node_add_ssh_key", request, output) {
|
||||
}
|
||||
|
||||
public async Task<BooleanResult> Post(Guid machineId, string publicSshKey) {
|
||||
var n = new JsonObject()
|
||||
.AddV("machine_id", machineId)
|
||||
.AddV("public_key", publicSshKey);
|
||||
|
||||
var r = await Post(n);
|
||||
return Return<BooleanResult>(r);
|
||||
}
|
||||
}
|
||||
}
|
55
src/ApiService/FunctionalTests/1f-api/Notifications.cs
Normal file
55
src/ApiService/FunctionalTests/1f-api/Notifications.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
public class Notification : IFromJsonElement<Notification> {
|
||||
JsonElement _e;
|
||||
|
||||
public Notification() { }
|
||||
|
||||
public Notification(JsonElement e) => _e = e;
|
||||
|
||||
public Notification Convert(JsonElement e) => new Notification(e);
|
||||
|
||||
public Guid NotificationId => _e.GetGuidProperty("notification_id");
|
||||
|
||||
public string Container => _e.GetStringProperty("container");
|
||||
|
||||
public string Config => _e.GetRawTextProperty("config");
|
||||
}
|
||||
|
||||
public class NotificationsApi : ApiBase {
|
||||
public NotificationsApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||
base(endpoint, "/api/Notifications", request, output) {
|
||||
}
|
||||
|
||||
public async Task<Result<IEnumerable<Notification>, Error>> Get(List<string>? containers = null) {
|
||||
var n = new JsonObject()
|
||||
.AddIfNotNullEnumerableV("container", containers);
|
||||
|
||||
var r = await Get(n);
|
||||
return IEnumerableResult<Notification>(r);
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result<Notification, Error>> Post(string container, bool replaceExisting, string config) {
|
||||
var n = new JsonObject()
|
||||
.AddV("container", container)
|
||||
.AddV("replace_existing", replaceExisting)
|
||||
.AddV("config", config);
|
||||
|
||||
var r = await Post(n);
|
||||
return Result<Notification>(r);
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result<Notification, Error>> Delete(Guid notificationId) {
|
||||
var n = new JsonObject()
|
||||
.AddV("notification_id", notificationId);
|
||||
|
||||
var r = await Delete(n);
|
||||
return Result<Notification>(r);
|
||||
}
|
||||
}
|
@ -11,12 +11,11 @@ public class Pool : IFromJsonElement<Pool> {
|
||||
|
||||
public Pool() { }
|
||||
public Pool(JsonElement e) => _e = e;
|
||||
|
||||
public string Name => _e.GetProperty("name").GetString()!;
|
||||
public string PoolId => _e.GetProperty("pool_id").GetString()!;
|
||||
public string Os => _e.GetProperty("os").GetString()!;
|
||||
|
||||
public Pool Convert(JsonElement e) => new Pool(e);
|
||||
|
||||
public string Name => _e.GetStringProperty("name");
|
||||
public string PoolId => _e.GetStringProperty("pool_id");
|
||||
public string Os => _e.GetStringProperty("os");
|
||||
}
|
||||
|
||||
public class PoolApi : ApiBase {
|
||||
@ -29,21 +28,17 @@ public class PoolApi : ApiBase {
|
||||
|
||||
public async Task<BooleanResult> Delete(string name, bool now = true) {
|
||||
_output.WriteLine($"deleting pool: {name}, now: {now}");
|
||||
var root = new JsonObject();
|
||||
root.Add("name", JsonValue.Create(name));
|
||||
root.Add("now", JsonValue.Create(now));
|
||||
var root = new JsonObject()
|
||||
.AddV("name", name)
|
||||
.AddV("now", now);
|
||||
return Return<BooleanResult>(await Delete(root));
|
||||
}
|
||||
|
||||
public async Task<Result<IEnumerable<Pool>, Error>> Get(string? name = null, string? id = null, string? state = null) {
|
||||
var root = new JsonObject();
|
||||
if (id is not null)
|
||||
root.Add("pool_id", id);
|
||||
if (name is not null)
|
||||
root.Add("name", name);
|
||||
if (state is not null)
|
||||
root.Add("state", state);
|
||||
|
||||
var root = new JsonObject()
|
||||
.AddIfNotNullV("pool_id", id)
|
||||
.AddIfNotNullV("name", name)
|
||||
.AddIfNotNullV("state", state);
|
||||
var res = await Get(root);
|
||||
return IEnumerableResult<Pool>(res);
|
||||
}
|
||||
@ -62,14 +57,14 @@ public class PoolApi : ApiBase {
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result<Pool, Error>> Create(string poolName, string os, string arch = "x86_64") {
|
||||
public async Task<Result<Pool, Error>> Create(string poolName, string os, string arch = "x86_64", bool managed = true) {
|
||||
_output.WriteLine($"creating new pool {poolName} os: {os}");
|
||||
|
||||
var rootPoolCreate = new JsonObject();
|
||||
rootPoolCreate.Add("name", poolName);
|
||||
rootPoolCreate.Add("os", os);
|
||||
rootPoolCreate.Add("arch", arch);
|
||||
rootPoolCreate.Add("managed", true);
|
||||
var rootPoolCreate = new JsonObject()
|
||||
.AddV("name", poolName)
|
||||
.AddV("os", os)
|
||||
.AddV("arch", arch)
|
||||
.AddV("managed", managed);
|
||||
return Result<Pool>(await Post(rootPoolCreate));
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,10 @@ public class Proxy : IFromJsonElement<Proxy> {
|
||||
public Proxy() { }
|
||||
public Proxy(JsonElement e) => _e = e;
|
||||
|
||||
public string Region => _e.GetProperty("region").GetString()!;
|
||||
public Guid ProxyId => _e.GetProperty("proxy_id").GetGuid()!;
|
||||
public string Region => _e.GetStringProperty("region");
|
||||
public Guid ProxyId => _e.GetGuidProperty("proxy_id");
|
||||
|
||||
public string VmState => _e.GetProperty("state").GetString()!;
|
||||
public string VmState => _e.GetStringProperty("state");
|
||||
|
||||
public Proxy Convert(JsonElement e) => new Proxy(e);
|
||||
}
|
||||
@ -22,10 +22,10 @@ public class Forward : IFromJsonElement<Forward>, IComparable<Forward> {
|
||||
public Forward() { }
|
||||
public Forward(JsonElement e) => _e = e;
|
||||
|
||||
public long SrcPort => _e.GetProperty("src_port").GetInt64();
|
||||
public long DstPort => _e.GetProperty("dst_port").GetInt64();
|
||||
public long SrcPort => _e.GetLongProperty("src_port");
|
||||
public long DstPort => _e.GetLongProperty("dst_port");
|
||||
|
||||
public string DstIp => _e.GetProperty("dst_ip").GetString()!;
|
||||
public string DstIp => _e.GetStringProperty("dst_ip");
|
||||
|
||||
public Forward Convert(JsonElement e) => new Forward(e);
|
||||
|
||||
@ -93,44 +93,35 @@ public class ProxyApi : ApiBase {
|
||||
}
|
||||
|
||||
public async Task<Result<IEnumerable<Proxy>, Error>> Get(Guid? scalesetId = null, Guid? machineId = null, int? dstPort = null) {
|
||||
var root = new JsonObject();
|
||||
if (scalesetId is not null)
|
||||
root.Add("scaleset_id", scalesetId);
|
||||
if (machineId is not null)
|
||||
root.Add("machine_id", machineId);
|
||||
if (dstPort is not null)
|
||||
root.Add("dst_port", dstPort);
|
||||
var root = new JsonObject()
|
||||
.AddIfNotNullV("scaleset_id", scalesetId)
|
||||
.AddIfNotNullV("machine_id", machineId)
|
||||
.AddIfNotNullV("dst_port", dstPort);
|
||||
|
||||
var r = await Get(root);
|
||||
if (Error.IsError(r)) {
|
||||
return Result<IEnumerable<Proxy>, Error>.Error(new Error(r));
|
||||
} else {
|
||||
return IEnumerableResult<Proxy>(r.GetProperty("proxies"));
|
||||
}
|
||||
return IEnumerableResult<Proxy>(r.GetProperty("proxies"));
|
||||
}
|
||||
|
||||
public async Task<BooleanResult> Delete(Guid scalesetId, Guid machineId, int? dstPort = null) {
|
||||
var root = new JsonObject();
|
||||
root.Add("scaleset_id", scalesetId);
|
||||
root.Add("machine_id", machineId);
|
||||
if (dstPort != null)
|
||||
root.Add("dst_port", dstPort);
|
||||
var root = new JsonObject()
|
||||
.AddV("scaleset_id", scalesetId)
|
||||
.AddV("machine_id", machineId)
|
||||
.AddIfNotNullV("dst_port", dstPort);
|
||||
return Return<BooleanResult>(await Delete(root));
|
||||
}
|
||||
|
||||
public async Task<BooleanResult> Reset(string region) {
|
||||
var root = new JsonObject();
|
||||
root.Add("region", region);
|
||||
var root = new JsonObject().AddV("region", region);
|
||||
var r = await Patch(root);
|
||||
return Return<BooleanResult>(r);
|
||||
}
|
||||
|
||||
public async Task<Result<ProxyGetResult, Error>> Create(Guid scalesetId, Guid machineId, int dstPort, int duration) {
|
||||
var root = new JsonObject();
|
||||
root.Add("scaleset_id", scalesetId);
|
||||
root.Add("machine_id", machineId);
|
||||
root.Add("dst_port", dstPort);
|
||||
root.Add("duration", duration);
|
||||
var root = new JsonObject()
|
||||
.AddV("scaleset_id", scalesetId)
|
||||
.AddV("machin_id", machineId)
|
||||
.AddV("dst_port", dstPort)
|
||||
.AddV("duration", duration);
|
||||
|
||||
var r = await Post(root);
|
||||
return Result<ProxyGetResult>(r);
|
||||
|
83
src/ApiService/FunctionalTests/1f-api/ReproVmss.cs
Normal file
83
src/ApiService/FunctionalTests/1f-api/ReproVmss.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
public class ReproConfig : IFromJsonElement<ReproConfig> {
|
||||
JsonElement _e;
|
||||
|
||||
public ReproConfig() { }
|
||||
public ReproConfig(JsonElement e) => _e = e;
|
||||
|
||||
public ReproConfig Convert(JsonElement e) => new ReproConfig(e);
|
||||
|
||||
public string Container => _e.GetStringProperty("container");
|
||||
public string Path => _e.GetStringProperty("path");
|
||||
|
||||
public long Duration => _e.GetLongProperty("duration");
|
||||
}
|
||||
|
||||
public class Repro : IFromJsonElement<Repro> {
|
||||
|
||||
JsonElement _e;
|
||||
|
||||
public Repro() { }
|
||||
public Repro(JsonElement e) => _e = e;
|
||||
|
||||
public Repro Convert(JsonElement e) => new Repro(e);
|
||||
|
||||
public Guid VmId => _e.GetGuidProperty("vm_id");
|
||||
|
||||
public Guid TaskId => _e.GetGuidProperty("task_id");
|
||||
|
||||
public string Os => _e.GetStringProperty("os");
|
||||
|
||||
public string? Ip => _e.GetNullableStringProperty("ip");
|
||||
|
||||
public DateTimeOffset? EndTime => _e.GetNullableDateTimeOffsetProperty("end_time");
|
||||
|
||||
public string State => _e.GetStringProperty("state");
|
||||
|
||||
public Error? Error => _e.GetNullableObjectProperty<Error>("error");
|
||||
|
||||
public Authentication? Auth => _e.GetNullableObjectProperty<Authentication>("auth");
|
||||
|
||||
ReproConfig Config => _e.GetObjectProperty<ReproConfig>("config");
|
||||
|
||||
UserInfo? UserInfo => _e.GetNullableObjectProperty<UserInfo>("user_info");
|
||||
}
|
||||
|
||||
|
||||
public class ReproVmss : ApiBase {
|
||||
|
||||
|
||||
public ReproVmss(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||
base(endpoint, "/api/repro_vms", request, output) {
|
||||
}
|
||||
|
||||
public async Task<Result<Repro, Error>> Get(Guid? vmId) {
|
||||
var n = new JsonObject().AddV("vm_id", vmId);
|
||||
|
||||
var r = await Get(n);
|
||||
return Result<Repro>(r);
|
||||
}
|
||||
|
||||
public async Task<Result<Repro, Error>> Post(string container, string path, long duration) {
|
||||
var n = new JsonObject()
|
||||
.AddV("container", container)
|
||||
.AddV("path", path)
|
||||
.AddV("duration", duration);
|
||||
|
||||
var r = await Post(n);
|
||||
return Result<Repro>(r);
|
||||
}
|
||||
|
||||
public async Task<Result<Repro, Error>> Delete(Guid? vmId) {
|
||||
var n = new JsonObject()
|
||||
.AddV("vm_id", vmId);
|
||||
var r = await Delete(n);
|
||||
return Result<Repro>(r);
|
||||
}
|
||||
|
||||
}
|
@ -4,65 +4,55 @@ using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests;
|
||||
public class Authentication {
|
||||
JsonElement _e;
|
||||
|
||||
public Authentication() { }
|
||||
public Authentication(JsonElement e) => _e = e;
|
||||
|
||||
string Password => _e.GetProperty("password").GetString()!;
|
||||
|
||||
string PublicKey => _e.GetProperty("public_key").GetString()!;
|
||||
string PrivateKey => _e.GetProperty("private_key").GetString()!;
|
||||
}
|
||||
|
||||
|
||||
public class ScalesetNodeState {
|
||||
public class ScalesetNodeState : IFromJsonElement<ScalesetNodeState> {
|
||||
JsonElement _e;
|
||||
|
||||
public ScalesetNodeState() { }
|
||||
public ScalesetNodeState(JsonElement e) => _e = e;
|
||||
|
||||
public Guid MachineId => _e.GetProperty("machine_id").GetGuid();
|
||||
public string InstanceId => _e.GetProperty("instance_id").GetString()!;
|
||||
public ScalesetNodeState Convert(JsonElement e) => new ScalesetNodeState(e);
|
||||
|
||||
public string? NodeState => _e.GetProperty("state").GetString();
|
||||
public Guid MachineId => _e.GetGuidProperty("machine_id");
|
||||
public string InstanceId => _e.GetStringProperty("instance_id");
|
||||
|
||||
public string? NodeState => _e.GetNullableStringProperty("state");
|
||||
}
|
||||
|
||||
public class Scaleset : IFromJsonElement<Scaleset> {
|
||||
JsonElement _e;
|
||||
public Scaleset() { }
|
||||
public Scaleset(JsonElement e) => _e = e;
|
||||
|
||||
public Guid ScalesetId => _e.GetProperty("scaleset_id").GetGuid();
|
||||
public string PoolName => _e.GetProperty("pool_name").GetString()!;
|
||||
public string State => _e.GetProperty("state").GetString()!;
|
||||
|
||||
public Error? Error => _e.GetProperty("error").ValueKind == JsonValueKind.Null ? null : new Error(_e.GetProperty("error"));
|
||||
public int Size => _e.GetProperty("size").GetInt32();
|
||||
|
||||
public string VmSku => _e.GetProperty("vm_sku").GetString()!;
|
||||
public string Image => _e.GetProperty("image").GetString()!;
|
||||
|
||||
public string Region => _e.GetProperty("region").GetString()!;
|
||||
|
||||
public bool? SpotInstance => _e.GetProperty("spot_instance").ValueKind == JsonValueKind.Null ? null : _e.GetProperty("spot_instance").GetBoolean();
|
||||
|
||||
public bool EphemeralOsDisks => _e.GetProperty("ephemeral_os_disks").GetBoolean();
|
||||
|
||||
public bool NeedsConfigUpdate => _e.GetProperty("needs_config_update").GetBoolean();
|
||||
|
||||
public Dictionary<string, string> Tags => _e.GetProperty("tags").Deserialize<Dictionary<string, string>>()!;
|
||||
|
||||
public Authentication? Auth => _e.GetProperty("auth").ValueKind == JsonValueKind.Null ? null : new Authentication(_e.GetProperty("auth"));
|
||||
|
||||
public Guid? ClientId => _e.GetProperty("client_id").ValueKind == JsonValueKind.Null ? null : _e.GetProperty("client_id").GetGuid();
|
||||
|
||||
public Guid? ClientObjectId => _e.GetProperty("client_object_id").ValueKind == JsonValueKind.Null ? null : _e.GetProperty("client_object_id").GetGuid();
|
||||
|
||||
public List<ScalesetNodeState>? Nodes => _e.GetProperty("nodes").ValueKind == JsonValueKind.Null ? null : _e.GetProperty("nodes").EnumerateArray().Select(node => new ScalesetNodeState(node)).ToList();
|
||||
|
||||
public Scaleset Convert(JsonElement e) => new Scaleset(e);
|
||||
|
||||
public Guid ScalesetId => _e.GetGuidProperty("scaleset_id");
|
||||
public string PoolName => _e.GetStringProperty("pool_name");
|
||||
public string State => _e.GetStringProperty("state");
|
||||
|
||||
public Error? Error => _e.GetNullableObjectProperty<Error>("error");
|
||||
|
||||
public long Size => _e.GetLongProperty("size");
|
||||
|
||||
public string VmSku => _e.GetStringProperty("vm_sku");
|
||||
public string Image => _e.GetStringProperty("image");
|
||||
|
||||
public string Region => _e.GetStringProperty("region");
|
||||
|
||||
public bool? SpotInstance => _e.GetNullableBoolProperty("spot_instance");
|
||||
|
||||
public bool EphemeralOsDisks => _e.GetBoolProperty("ephemeral_os_disks");
|
||||
|
||||
public bool NeedsConfigUpdate => _e.GetBoolProperty("needs_config_update");
|
||||
|
||||
public IDictionary<string, string> Tags => _e.GetStringDictProperty("tags");
|
||||
|
||||
public Authentication? Auth => _e.GetNullableObjectProperty<Authentication>("auth");
|
||||
|
||||
public Guid? ClientId => _e.GetNullableGuidProperty("client_id");
|
||||
|
||||
public Guid? ClientObjectId => _e.GetNullableGuidProperty("client_object_id");
|
||||
|
||||
public IEnumerable<ScalesetNodeState>? Nodes => _e.GetEnumerableNullableProperty<ScalesetNodeState>("nodes");
|
||||
}
|
||||
|
||||
public class ScalesetApi : ApiBase {
|
||||
@ -75,47 +65,41 @@ public class ScalesetApi : ApiBase {
|
||||
|
||||
|
||||
public async Task<Result<IEnumerable<Scaleset>, Error>> Get(Guid? id = null, string? state = null, bool? includeAuth = false) {
|
||||
var root = new JsonObject();
|
||||
if (id is not null)
|
||||
root.Add("scaleset_id", id);
|
||||
if (state is not null)
|
||||
root.Add("state", state);
|
||||
if (includeAuth is not null)
|
||||
root.Add("include_auth", includeAuth);
|
||||
var res = await Get(root);
|
||||
var j = new JsonObject()
|
||||
.AddIfNotNullV("scaleset_id", id)
|
||||
.AddIfNotNullV("state", state)
|
||||
.AddIfNotNullV("include_auth", includeAuth);
|
||||
var res = await Get(j);
|
||||
return IEnumerableResult<Scaleset>(res);
|
||||
}
|
||||
|
||||
public async Task<Result<Scaleset, Error>> Create(string poolName, int size, string? region = null, string vmSku = "Standard_D2s_v3", string image = Image_Ubuntu_20_04, bool spotInstance = false) {
|
||||
_output.WriteLine($"Creating scaleset in pool {poolName}, size: {size}");
|
||||
var rootScalesetCreate = new JsonObject();
|
||||
rootScalesetCreate.Add("pool_name", poolName);
|
||||
rootScalesetCreate.Add("vm_sku", vmSku);
|
||||
rootScalesetCreate.Add("image", image);
|
||||
rootScalesetCreate.Add("size", size);
|
||||
rootScalesetCreate.Add("spot_instances", spotInstance);
|
||||
if (region is not null)
|
||||
rootScalesetCreate.Add("region", region);
|
||||
|
||||
var tags = new JsonObject();
|
||||
tags.Add("Purpose", "Functional-Test");
|
||||
rootScalesetCreate.Add("tags", tags);
|
||||
var rootScalesetCreate = new JsonObject()
|
||||
.AddV("pool_name", poolName)
|
||||
.AddV("vm_sku", vmSku)
|
||||
.AddV("image", image)
|
||||
.AddV("size", size)
|
||||
.AddV("spot_instances", spotInstance)
|
||||
.AddIfNotNullV("region", region);
|
||||
|
||||
rootScalesetCreate.Add("tags", new JsonObject().AddV("Purpose", "Functional-Test"));
|
||||
|
||||
return Result<Scaleset>(await Post(rootScalesetCreate));
|
||||
}
|
||||
|
||||
public async Task<Result<Scaleset, Error>> Patch(Guid id, int size) {
|
||||
var scalesetPatch = new JsonObject();
|
||||
scalesetPatch.Add("scaleset_id", id);
|
||||
scalesetPatch.Add("size", size);
|
||||
var scalesetPatch = new JsonObject()
|
||||
.AddV("scaleset_id", id)
|
||||
.AddV("size", size);
|
||||
return Result<Scaleset>(await Patch(scalesetPatch));
|
||||
}
|
||||
|
||||
public async Task<BooleanResult> Delete(Guid id, bool now) {
|
||||
var scalesetDelete = new JsonObject();
|
||||
scalesetDelete.Add("scaleset_id", id);
|
||||
scalesetDelete.Add("now", now);
|
||||
|
||||
var scalesetDelete = new JsonObject()
|
||||
.AddV("scaleset_id", id)
|
||||
.AddV("now", now);
|
||||
return Return<BooleanResult>(await Delete(scalesetDelete));
|
||||
}
|
||||
|
||||
|
239
src/ApiService/FunctionalTests/1f-api/Tasks.cs
Normal file
239
src/ApiService/FunctionalTests/1f-api/Tasks.cs
Normal file
@ -0,0 +1,239 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
|
||||
public class TaskDetails {
|
||||
JsonElement _e;
|
||||
public TaskDetails() { }
|
||||
public TaskDetails(JsonElement e) => _e = e;
|
||||
|
||||
public string Type => _e.GetStringProperty("type");
|
||||
|
||||
public long Duration => _e.GetLongProperty("duration");
|
||||
public string? TargetExe => _e.GetStringProperty("target_exe");
|
||||
|
||||
public IDictionary<string, string>? TargetEnv => _e.GetNullableStringDictProperty("target_env");
|
||||
|
||||
public IEnumerable<string>? TargetOptions => _e.GetEnumerableStringProperty("target_options");
|
||||
|
||||
public long? TargetWorkers => _e.GetNullableLongProperty("target_workers");
|
||||
|
||||
public bool? TargetOptionsMerge => _e.GetNullableBoolProperty("target_option_merge");
|
||||
|
||||
public bool? CheckAsanLog => _e.GetNullableBoolProperty("check_asan_log");
|
||||
|
||||
public bool? CheckDebugger => _e.GetNullableBoolProperty("check_debugger");
|
||||
|
||||
public long? CheckRetryCount => _e.GetNullableLongProperty("check_retry_count");
|
||||
|
||||
public bool? CheckFuzzerHelp => _e.GetNullableBoolProperty("check_fuzzer_help");
|
||||
|
||||
public bool? ExpectCrashOnFailure => _e.GetNullableBoolProperty("expect_crash_on_failure");
|
||||
|
||||
public bool? RenameOutput => _e.GetNullableBoolProperty("rename_output");
|
||||
|
||||
public string? SupervisorExe => _e.GetNullableStringProperty("supervisor_exe");
|
||||
|
||||
public IDictionary<string, string>? SupervisonEnv => _e.GetNullableStringDictProperty("supervisor_env");
|
||||
|
||||
public IEnumerable<string>? SupervisorOptions => _e.GetEnumerableNullableStringProperty("supervisor_options");
|
||||
|
||||
public string? SupervisorInputMarker => _e.GetStringProperty("supervison_input_marker");
|
||||
|
||||
public string? GeneraroExe => _e.GetStringProperty("generator_exe");
|
||||
|
||||
public IDictionary<string, string>? GeneratorEnv => _e.GetStringDictProperty("generator_env");
|
||||
|
||||
public IEnumerable<string>? GeneratorOptions => _e.GetEnumerableNullableStringProperty("generator_options");
|
||||
|
||||
public string? AnalyzerExe => _e.GetNullableStringProperty("analyzer_exe");
|
||||
|
||||
public IDictionary<string, string>? AnalyzerEnv => _e.GetNullableStringDictProperty("analyzer_env");
|
||||
|
||||
public IEnumerable<string>? AnalyzerOptions => _e.GetEnumerableNullableStringProperty("analyzer_options");
|
||||
|
||||
public string? StatsFile => _e.GetNullableStringProperty("stats_file");
|
||||
|
||||
public bool? RebootAfterSetup => _e.GetNullableBoolProperty("reboot_after_setup");
|
||||
|
||||
public long? TargetTimeout => _e.GetNullableLongProperty("target_timeout");
|
||||
|
||||
public long? EnsembleSyncDelay => _e.GetNullableLongProperty("ensemble_sync_delay");
|
||||
|
||||
public bool? PreserveExistingOutputs => _e.GetNullableBoolProperty("preserve_existing_outputs");
|
||||
|
||||
public IEnumerable<string>? ReportList => _e.GetEnumerableNullableStringProperty("report_list");
|
||||
|
||||
public long? MinimizedStackDepth => _e.GetNullableLongProperty("minimized_stack_depth");
|
||||
|
||||
public string? CoverageFilter => _e.GetNullableStringProperty("coverage_filter");
|
||||
|
||||
public string? WaitForFiles => _e.GetNullableStringProperty("wait_for_files");
|
||||
public string? StatsFormat => _e.GetNullableStringProperty("stats_format");
|
||||
}
|
||||
|
||||
|
||||
public class TaskConfig : IFromJsonElement<TaskConfig> {
|
||||
JsonElement _e;
|
||||
public TaskConfig() { }
|
||||
public TaskConfig(JsonElement e) => _e = e;
|
||||
public TaskConfig Convert(JsonElement e) => new TaskConfig(e);
|
||||
|
||||
public Guid JobId => _e.GetGuidProperty("job_id");
|
||||
public IEnumerable<Guid>? PrereqTasks => _e.GetEnumerableGuidProperty("prereq_tasks");
|
||||
}
|
||||
|
||||
public class OneFuzzTask : IFromJsonElement<OneFuzzTask> {
|
||||
JsonElement _e;
|
||||
|
||||
public OneFuzzTask() { }
|
||||
public OneFuzzTask(JsonElement e) => _e = e;
|
||||
|
||||
public OneFuzzTask Convert(JsonElement e) => new OneFuzzTask(e);
|
||||
|
||||
public Guid JobId => _e.GetGuidProperty("job_id");
|
||||
public Guid TaskId => _e.GetGuidProperty("task_id");
|
||||
public string State => _e.GetStringProperty("state");
|
||||
public string Os => _e.GetStringProperty("os");
|
||||
public Error? Error => _e.GetNullableObjectProperty<Error>("error");
|
||||
|
||||
public DateTimeOffset? Heartbeat => _e.GetNullableDateTimeOffsetProperty("heartbeat");
|
||||
public DateTimeOffset? EndTime => _e.GetNullableDateTimeOffsetProperty("end_time");
|
||||
|
||||
public Authentication? Auth => _e.GetNullableObjectProperty<Authentication>("auth");
|
||||
|
||||
public UserInfo? UserInfo => _e.GetNullableObjectProperty<UserInfo>("user_info");
|
||||
|
||||
public TaskConfig Config => _e.GetObjectProperty<TaskConfig>("task_config");
|
||||
}
|
||||
|
||||
|
||||
public class TaskApi : ApiBase {
|
||||
|
||||
public TaskApi(Uri endpoint, Microsoft.OneFuzz.Service.Request request, ITestOutputHelper output) :
|
||||
base(endpoint, "/api/tasks", request, output) {
|
||||
}
|
||||
|
||||
public static JsonObject TaskDetails(
|
||||
string taskType,
|
||||
long duration,
|
||||
string? targetExe = null,
|
||||
IDictionary<string, string>? targetEnv = null,
|
||||
IEnumerable<string>? targetOptions = null,
|
||||
long? targetWorkers = null,
|
||||
bool? targetOptionsMerge = null,
|
||||
bool? checkAsanLog = null,
|
||||
bool? checkDebugger = null,
|
||||
long? checkRetryCount = null,
|
||||
bool? checkFuzzerHelp = null,
|
||||
bool? expectCrashOnFailure = null,
|
||||
bool? renameOutput = null,
|
||||
string? supervisorExe = null,
|
||||
IDictionary<string, string>? supervisorEnv = null,
|
||||
IEnumerable<string>? supervisorOptions = null,
|
||||
string? supervisorInputMarker = null,
|
||||
string? generatorExe = null,
|
||||
IDictionary<string, string>? generatorEnv = null,
|
||||
IEnumerable<string>? generatorOptions = null,
|
||||
string? analyzerExe = null,
|
||||
IDictionary<string, string>? analyzerEnv = null,
|
||||
IEnumerable<string>? analyzerOptions = null,
|
||||
string? waitForFiles = null,
|
||||
string? statsFile = null,
|
||||
string? statsFormat = null,
|
||||
bool? rebootAfterSetup = null,
|
||||
long? targetTimeout = null,
|
||||
long? ensembleSyncDelay = null,
|
||||
bool? preserveExistingOutputs = null,
|
||||
IEnumerable<string>? reportList = null,
|
||||
long? minimizedStackDepth = null,
|
||||
string? coverageFilter = null
|
||||
) {
|
||||
|
||||
return new JsonObject()
|
||||
.AddV("task_type", taskType)
|
||||
.AddV("duration", duration)
|
||||
.AddIfNotNullV("target_exe", targetExe)
|
||||
.AddIfNotNullV("target_env", targetEnv)
|
||||
.AddIfNotNullV("target_options", targetOptions)
|
||||
.AddIfNotNullV("target_workers", targetWorkers)
|
||||
.AddIfNotNullV("target_options_merge", targetOptionsMerge)
|
||||
.AddIfNotNullV("check_asan_log", checkAsanLog)
|
||||
.AddIfNotNullV("check_debugger", checkDebugger)
|
||||
.AddIfNotNullV("check_retry_count", checkRetryCount)
|
||||
.AddIfNotNullV("check_fuzzer_help", checkFuzzerHelp)
|
||||
.AddIfNotNullV("expect_crash_on_failure", expectCrashOnFailure)
|
||||
.AddIfNotNullV("rename_output", renameOutput)
|
||||
.AddIfNotNullV("supervisor_exe", supervisorExe)
|
||||
.AddIfNotNullV("supervisor_env", supervisorEnv)
|
||||
.AddIfNotNullV("supervisor_options", supervisorOptions)
|
||||
.AddIfNotNullV("supervisor_input_marker", supervisorInputMarker)
|
||||
.AddIfNotNullV("generator_exe", generatorExe)
|
||||
.AddIfNotNullV("generator_env", generatorEnv)
|
||||
.AddIfNotNullV("generator_options", generatorOptions)
|
||||
.AddIfNotNullV("analyzer_exe", analyzerExe)
|
||||
.AddIfNotNullV("analyzer_env", analyzerEnv)
|
||||
.AddIfNotNullV("analyzer_options", analyzerOptions)
|
||||
.AddIfNotNullV("wait_for_files", waitForFiles)
|
||||
.AddIfNotNullV("stats_file", statsFile)
|
||||
.AddIfNotNullV("stats_format", statsFormat)
|
||||
.AddIfNotNullV("reboot_after_setup", rebootAfterSetup)
|
||||
.AddIfNotNullV("target_timeout", targetTimeout)
|
||||
.AddIfNotNullV("ensemble_sync_delay", ensembleSyncDelay)
|
||||
.AddIfNotNullV("preserve_existing_outputs", preserveExistingOutputs)
|
||||
.AddIfNotNullV("reprot_list", reportList)
|
||||
.AddIfNotNullV("minimized_stack_depth", minimizedStackDepth)
|
||||
.AddIfNotNullV("coverage_filter", coverageFilter);
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result<IEnumerable<OneFuzzTask>, Error>> Get(Guid? jobId = null, Guid? taskId = null, List<string>? state = null) {
|
||||
var n = new JsonObject()
|
||||
.AddIfNotNullV("job_id", jobId)
|
||||
.AddIfNotNullV("task_id", taskId)
|
||||
.AddIfNotNullV("state", state);
|
||||
var r = await Get(n);
|
||||
return IEnumerableResult<OneFuzzTask>(r);
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result<OneFuzzTask, Error>> Post(
|
||||
Guid jobId,
|
||||
JsonObject taskDetails,
|
||||
string taskPoolName,
|
||||
long taskPoolCount,
|
||||
IEnumerable<Guid>? prereqTasks = null,
|
||||
IEnumerable<(string, string)>? containers = null,
|
||||
IDictionary<string, string>? tags = null,
|
||||
bool? colocate = null
|
||||
) {
|
||||
|
||||
var j = new JsonObject()
|
||||
.AddV("job_id", jobId)
|
||||
.AddIfNotNullEnumerableV("prereq_tasks", prereqTasks)
|
||||
.AddIfNotNullEnumerableV("containers", containers)
|
||||
.AddIfNotNullV("tags", tags)
|
||||
.AddIfNotNullV("colocate", colocate)
|
||||
;
|
||||
|
||||
var pool = new JsonObject()
|
||||
.AddV("count", taskPoolCount)
|
||||
.AddV("pool_name", taskPoolName);
|
||||
|
||||
j.Add("task", taskDetails);
|
||||
j.Add("pool", pool);
|
||||
|
||||
var r = await Post(j);
|
||||
return Result<OneFuzzTask>(r);
|
||||
}
|
||||
|
||||
public async Task<BooleanResult> Delete(Guid taskId) {
|
||||
var j = new JsonObject().AddV("task_id", taskId);
|
||||
|
||||
var r = await Delete(j);
|
||||
return new BooleanResult(r);
|
||||
}
|
||||
}
|
16
src/ApiService/FunctionalTests/1f-api/UserInfo.cs
Normal file
16
src/ApiService/FunctionalTests/1f-api/UserInfo.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace FunctionalTests;
|
||||
|
||||
public class UserInfo : IFromJsonElement<UserInfo> {
|
||||
|
||||
JsonElement _e;
|
||||
public UserInfo() { }
|
||||
public UserInfo(JsonElement e) => _e = e;
|
||||
public UserInfo Convert(JsonElement e) => new UserInfo(e);
|
||||
|
||||
public Guid? ApplicationId => _e.GetNullableGuidProperty("application_id");
|
||||
public Guid? ObjectId => _e.GetNullableGuidProperty("object_id");
|
||||
public string? Upn => _e.GetNullableStringProperty("upn");
|
||||
}
|
||||
|
4
src/ApiService/FunctionalTests/1f-api/WebhookLogs.cs
Normal file
4
src/ApiService/FunctionalTests/1f-api/WebhookLogs.cs
Normal file
@ -0,0 +1,4 @@
|
||||
namespace FunctionalTests {
|
||||
public class WebhookLogs {
|
||||
}
|
||||
}
|
4
src/ApiService/FunctionalTests/1f-api/WebhookPing.cs
Normal file
4
src/ApiService/FunctionalTests/1f-api/WebhookPing.cs
Normal file
@ -0,0 +1,4 @@
|
||||
namespace FunctionalTests {
|
||||
public class WebhookPing {
|
||||
}
|
||||
}
|
4
src/ApiService/FunctionalTests/1f-api/Webhooks.cs
Normal file
4
src/ApiService/FunctionalTests/1f-api/Webhooks.cs
Normal file
@ -0,0 +1,4 @@
|
||||
namespace FunctionalTests {
|
||||
public class Webhooks {
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.46.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace FunctionalTests {
|
||||
public class Helpers {
|
||||
|
||||
public static async Task<(Pool, Scaleset)> CreatePoolAndScaleset(PoolApi poolApi, ScalesetApi scalesetApi, string os = "linux", string? region = null, int numNodes = 2) {
|
||||
var image = (os == "linux") ? ScalesetApi.Image_Ubuntu_20_04 : ScalesetApi.ImageWindows;
|
||||
|
55
src/ApiService/FunctionalTests/TestContainer.cs
Normal file
55
src/ApiService/FunctionalTests/TestContainer.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
||||
namespace FunctionalTests {
|
||||
[Trait("Category", "Live")]
|
||||
public class TestContainer {
|
||||
|
||||
private readonly ITestOutputHelper _output;
|
||||
ContainerApi _containerApi;
|
||||
DownloadApi _downloadApi;
|
||||
public TestContainer(ITestOutputHelper output) {
|
||||
_output = output;
|
||||
_containerApi = new ContainerApi(ApiClient.Endpoint, ApiClient.Request, output);
|
||||
_downloadApi = new DownloadApi(ApiClient.Endpoint, ApiClient.Request, output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DownloadNonExistentContainer() {
|
||||
var r1 = await _downloadApi.Get();
|
||||
r1.IsOk!.Should().BeFalse();
|
||||
r1.ErrorV!.Item2!.ShouldBeProvided("container").Should().BeTrue();
|
||||
|
||||
var r2 = await _downloadApi.Get(container: Guid.NewGuid().ToString());
|
||||
r2.IsOk!.Should().BeFalse();
|
||||
r2.ErrorV!.Item2!.ShouldBeProvided("filename").Should().BeTrue();
|
||||
|
||||
var r3 = await _downloadApi.Get(filename: Guid.NewGuid().ToString());
|
||||
r3.IsOk!.Should().BeFalse();
|
||||
r3.ErrorV!.Item2!.ShouldBeProvided("container").Should().BeTrue();
|
||||
|
||||
var r4 = await _downloadApi.Get(container: Guid.NewGuid().ToString(), filename: Guid.NewGuid().ToString());
|
||||
r4.IsOk!.Should().BeFalse();
|
||||
r4.ErrorV!.Item1.Should().Be(System.Net.HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateGetDeleteContainer() {
|
||||
var containerName = Guid.NewGuid().ToString();
|
||||
var container = await _containerApi.Post(containerName);
|
||||
container.IsOk.Should().BeTrue($"failed to create container due to {container.ErrorV}");
|
||||
|
||||
var c = await _containerApi.Get(containerName);
|
||||
|
||||
|
||||
var d = await _containerApi.Delete(containerName);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
23
src/ApiService/FunctionalTests/TestInfo.cs
Normal file
23
src/ApiService/FunctionalTests/TestInfo.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
||||
namespace FunctionalTests {
|
||||
[Trait("Category", "Live")]
|
||||
public class TestInfo {
|
||||
private readonly ITestOutputHelper _output;
|
||||
InfoApi _infoApi;
|
||||
public TestInfo(ITestOutputHelper output) {
|
||||
_output = output;
|
||||
_infoApi = new InfoApi(ApiClient.Endpoint, ApiClient.Request, output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
async Task GetInfo() {
|
||||
var info = await _infoApi.Get();
|
||||
info.IsOk.Should().BeTrue();
|
||||
info.OkV!.Versions.ContainsKey("onefuzz").Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests {
|
||||
@ -23,47 +24,52 @@ namespace FunctionalTests {
|
||||
async Task GetNonExistentNode() {
|
||||
var n = await _nodeApi.Get(Guid.NewGuid());
|
||||
|
||||
Assert.False(n.IsOk);
|
||||
Assert.True(n.ErrorV!.UnableToFindNode);
|
||||
n.IsOk.Should().BeFalse();
|
||||
n.ErrorV!.UnableToFindNode.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
async Task GetAllNodes() {
|
||||
var ns = await _nodeApi.Get();
|
||||
|
||||
Assert.True(ns.IsOk, $"Failed to get all nodes due to {ns.ErrorV}");
|
||||
ns.IsOk.Should().BeTrue("failed to get all nodes due to {0}", ns.ErrorV);
|
||||
foreach (var n in ns.OkV!) {
|
||||
_output.WriteLine($"node machine id: {n.MachineId}, scaleset id: {n.ScalesetId}, poolName: {n.PoolName}, poolId: {n.PoolId} state: {n.State}, version: {n.Version}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
async Task DeleteNonExistentNode() {
|
||||
var n = await _nodeApi.Delete(Guid.NewGuid());
|
||||
n.IsError.Should().BeTrue();
|
||||
n.Error!.UnableToFindNode.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
async Task GetPatchPostDelete() {
|
||||
|
||||
var (pool, scaleset) = await Helpers.CreatePoolAndScaleset(_poolApi, _scalesetApi, "linux");
|
||||
|
||||
scaleset = await _scalesetApi.WaitWhile(scaleset.ScalesetId, sc => sc.State == "init" || sc.State == "setup");
|
||||
Assert.True(scaleset.Nodes!.Count > 0);
|
||||
scaleset.Nodes!.Should().NotBeEmpty();
|
||||
|
||||
var nodeState = scaleset.Nodes!.First();
|
||||
var nodeResult = await _nodeApi.Get(nodeState.MachineId);
|
||||
|
||||
Assert.True(nodeResult.IsOk, $"failed to get node due to {nodeResult.ErrorV}");
|
||||
nodeResult.IsOk.Should().BeTrue("failed to get node due to {0}", nodeResult.ErrorV);
|
||||
var node = nodeResult.OkV!.First();
|
||||
node = await _nodeApi.WaitWhile(node.MachineId, n => n.State == "init" || n.State == "setup");
|
||||
|
||||
var r = await _nodeApi.Patch(node.MachineId);
|
||||
Assert.True(r.Result);
|
||||
r.Result.Should().BeTrue();
|
||||
|
||||
var rr = await _nodeApi.Update(node.MachineId, false);
|
||||
|
||||
var d = await _nodeApi.Delete(node.MachineId);
|
||||
Assert.True(d.Result);
|
||||
d.Result.Should().BeTrue();
|
||||
|
||||
var deletePool = await _poolApi.Delete(pool.Name);
|
||||
Assert.True(deletePool.Result);
|
||||
deletePool.Result.Should().BeTrue();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests {
|
||||
@ -20,7 +21,7 @@ namespace FunctionalTests {
|
||||
[Fact]
|
||||
async Task GetNonExistentPool() {
|
||||
var p = await _poolApi.Get(name: Guid.NewGuid().ToString());
|
||||
Assert.True(p.ErrorV!.UnableToFindPoolError);
|
||||
p.ErrorV!.UnableToFindPoolError.Should().BeTrue("{0}", p.ErrorV!);
|
||||
}
|
||||
|
||||
|
||||
@ -33,7 +34,7 @@ namespace FunctionalTests {
|
||||
[Fact]
|
||||
public async Task GetPools() {
|
||||
var pools = await _poolApi.Get();
|
||||
Assert.True(pools.IsOk);
|
||||
pools.IsOk.Should().BeTrue();
|
||||
|
||||
if (!pools.OkV!.Any()) {
|
||||
_output.WriteLine("Got empty pools");
|
||||
@ -53,16 +54,16 @@ namespace FunctionalTests {
|
||||
_output.WriteLine($"creating pool {newPoolName}");
|
||||
var newPool = await _poolApi.Create(newPoolName, "linux");
|
||||
|
||||
Assert.True(newPool.IsOk, $"failed to create new pool: {newPool.ErrorV}");
|
||||
newPool.IsOk.Should().BeTrue("failed to create new pool: {0}", newPool.ErrorV);
|
||||
|
||||
var poolsCreated = await _poolApi.Get();
|
||||
Assert.True(poolsCreated.IsOk, $"failed to get pools: {poolsCreated.ErrorV}");
|
||||
poolsCreated.IsOk.Should().BeTrue("failed to get pools: {0}", poolsCreated.ErrorV);
|
||||
|
||||
var newPools = poolsCreated.OkV!.Where(p => p.Name == newPoolName);
|
||||
Assert.True(newPools.Count() == 1);
|
||||
newPools.Count().Should().Be(1);
|
||||
|
||||
var deletedPoolResult = await _poolApi.Delete(newPoolName);
|
||||
Assert.True(deletedPoolResult.Result);
|
||||
deletedPoolResult.Result.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests {
|
||||
@ -24,7 +25,8 @@ namespace FunctionalTests {
|
||||
[Fact]
|
||||
public async Task GetProxies() {
|
||||
var allProxiesResult = await _proxyApi.Get();
|
||||
Assert.True(allProxiesResult.IsOk, $"failed to get proxies due to {allProxiesResult.ErrorV}");
|
||||
|
||||
allProxiesResult.IsOk.Should().BeTrue("failed to get proxies due to {0}", allProxiesResult.ErrorV);
|
||||
|
||||
if (!allProxiesResult.OkV!.Any()) {
|
||||
_output.WriteLine("Got empty list of proxies");
|
||||
@ -35,18 +37,18 @@ namespace FunctionalTests {
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
//TODO: do not run this for now - this triggers: https://github.com/microsoft/onefuzz/issues/2331
|
||||
//[Fact]
|
||||
public async Task CreateResetDelete() {
|
||||
var (newPool, newScaleset) = await Helpers.CreatePoolAndScaleset(_poolApi, _scalesetApi, "linux");
|
||||
|
||||
newScaleset = await _scalesetApi.WaitWhile(newScaleset.ScalesetId, sc => sc.State == "init" || sc.State == "setup");
|
||||
newScaleset.Nodes!.Should().NotBeEmpty();
|
||||
|
||||
Assert.True(newScaleset.Nodes!.Count > 0);
|
||||
|
||||
var firstNode = newScaleset.Nodes.First();
|
||||
var firstNode = newScaleset.Nodes!.First();
|
||||
|
||||
var nodeResult = await _nodeApi.Get(machineId: firstNode.MachineId);
|
||||
Assert.True(nodeResult.IsOk);
|
||||
nodeResult.IsOk.Should().BeTrue();
|
||||
var node = nodeResult.OkV!.First();
|
||||
|
||||
node = await _nodeApi.WaitWhile(node.MachineId, n => n.State == "init" || n.State == "setup");
|
||||
@ -55,26 +57,23 @@ namespace FunctionalTests {
|
||||
|
||||
var proxyAgain = await _proxyApi.Create(newScaleset.ScalesetId, node.MachineId, 2223, 1);
|
||||
|
||||
Assert.True(proxy.IsOk, $"failed to create proxy due to {proxy.ErrorV}");
|
||||
Assert.True(proxyAgain.IsOk, $"failed to create proxy with same config due to {proxyAgain.ErrorV}");
|
||||
|
||||
Assert.Equal(proxy.OkV!, proxyAgain.OkV!);
|
||||
proxy.IsOk.Should().BeTrue("failed to create proxy due to {0}", proxy.ErrorV);
|
||||
proxyAgain.IsOk.Should().BeTrue("failed to create proxy with same config due to {0}", proxyAgain.ErrorV);
|
||||
|
||||
proxy.OkV!.Should().BeEquivalentTo(proxyAgain.OkV!);
|
||||
_output.WriteLine($"created proxy dst ip: {proxy.OkV!.Forward.DstIp}, srcPort: {proxy.OkV.Forward.SrcPort} dstport: {proxy.OkV!.Forward.DstPort}, ip: {proxy.OkV!.Ip}");
|
||||
|
||||
|
||||
var proxyReset = await _proxyApi.Reset(newScaleset.Region);
|
||||
Assert.True(proxyReset.Result);
|
||||
proxyReset.Result.Should().BeTrue();
|
||||
|
||||
var deleteProxy = await _proxyApi.Delete(newScaleset.ScalesetId, node.MachineId);
|
||||
Assert.True(deleteProxy.Result);
|
||||
|
||||
deleteProxy.Result.Should().BeTrue();
|
||||
|
||||
_output.WriteLine($"deleted proxy");
|
||||
|
||||
var deletePool = await _poolApi.Delete(newPool.Name);
|
||||
Assert.True(deletePool.Result);
|
||||
|
||||
deletePool.Result.Should().BeTrue();
|
||||
_output.WriteLine($"deleted pool {newPool.Name}");
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace FunctionalTests {
|
||||
@ -20,11 +21,10 @@ namespace FunctionalTests {
|
||||
[Fact]
|
||||
public async Task GetScalesets() {
|
||||
var scalesets = await _scalesetApi.Get();
|
||||
Assert.True(scalesets.IsOk, $"failed to get scalesets due to {scalesets.ErrorV}");
|
||||
scalesets.IsOk.Should().BeTrue("failed to get scalesets due to {0}", scalesets.ErrorV);
|
||||
if (!scalesets.OkV!.Any()) {
|
||||
_output.WriteLine("Got empty scalesets");
|
||||
} else {
|
||||
|
||||
foreach (var sc in scalesets.OkV!) {
|
||||
if (sc.Error is not null)
|
||||
_output.WriteLine($"Pool: {sc.PoolName} Scaleset: {sc.ScalesetId}, state; {sc.State}, error: {sc.Error}");
|
||||
@ -44,16 +44,16 @@ namespace FunctionalTests {
|
||||
_output.WriteLine($"New scale set info id: {newScaleset.ScalesetId}, pool: {newScaleset.PoolName}, state: {newScaleset.State}, error: {newScaleset.Error}");
|
||||
|
||||
var scalesetsCreated = await _scalesetApi.Get();
|
||||
Assert.True(scalesetsCreated.IsOk, $"failed to get scalesets: {scalesetsCreated.ErrorV}");
|
||||
scalesetsCreated.IsOk.Should().BeTrue("failed to get scalesets: {0}", scalesetsCreated.ErrorV);
|
||||
|
||||
var poolsCreated = await _poolApi.Get();
|
||||
Assert.True(poolsCreated.IsOk, $"failed to get pools: {poolsCreated.ErrorV}");
|
||||
poolsCreated.IsOk.Should().BeTrue("failed to get pools: {0}", poolsCreated.ErrorV);
|
||||
|
||||
var newPools = poolsCreated.OkV!.Where(p => p.Name == newPool.Name);
|
||||
var newScalesets = scalesetsCreated.OkV!.Where(sc => sc.ScalesetId == newScaleset.ScalesetId);
|
||||
|
||||
Assert.True(newPools.Count() == 1);
|
||||
Assert.True(newScalesets.Count() == 1);
|
||||
newPools.Count().Should().Be(1);
|
||||
newScalesets.Count().Should().Be(1);
|
||||
|
||||
Console.WriteLine($"Waiting for scaleset to move out from Init State");
|
||||
newScaleset = await _scalesetApi.WaitWhile(newScaleset.ScalesetId, sc => sc.State == "init" || sc.State == "setup");
|
||||
@ -67,8 +67,8 @@ namespace FunctionalTests {
|
||||
}
|
||||
|
||||
var patch0 = await _scalesetApi.Patch(newScaleset.ScalesetId, 0);
|
||||
Assert.False(patch0.IsOk);
|
||||
Assert.True(patch0.ErrorV!.IsWrongSizeError);
|
||||
patch0.IsOk.Should().BeFalse();
|
||||
patch0.ErrorV!.IsWrongSizeError.Should().BeTrue();
|
||||
// https://github.com/microsoft/onefuzz/issues/2311
|
||||
//var patch1 = await _scalesetApi.Patch(newScaleset.ScalesetId, 1);
|
||||
//Assert.True(patch1.IsOk, $"scaleset patch failed due to: {patch1}");
|
||||
@ -89,9 +89,9 @@ namespace FunctionalTests {
|
||||
var preDeleteScalesets = await _scalesetApi.Get();
|
||||
var deletedPoolResult = await _poolApi.Delete(newPool.Name);
|
||||
|
||||
Assert.True(preDeleteScalesets.IsOk, $"failed to get pre-deleted scalesets due to: {preDeleteScalesets.ErrorV}");
|
||||
preDeleteScalesets.IsOk.Should().BeTrue("failed to get pre-deleted scalesets due to: {0}", preDeleteScalesets.ErrorV);
|
||||
var preDelete = preDeleteScalesets.OkV!.Where(sc => sc.PoolName == newPool.Name);
|
||||
Assert.True(preDelete.Count() == 3);
|
||||
preDelete.Count().Should().Be(3);
|
||||
|
||||
Result<IEnumerable<Pool>, Error> deletedPool;
|
||||
do {
|
||||
@ -99,17 +99,18 @@ namespace FunctionalTests {
|
||||
deletedPool = await _poolApi.Get(newPool.Name);
|
||||
|
||||
} while (deletedPool.IsOk);
|
||||
Assert.True(deletedPool.ErrorV!.UnableToFindPoolError);
|
||||
|
||||
deletedPool.ErrorV!.UnableToFindPoolError.Should().BeTrue();
|
||||
var postDeleteScalesets = await _scalesetApi.Get();
|
||||
Assert.True(postDeleteScalesets.IsOk, $"failed to get scalesets after finishing pool deletion due to {postDeleteScalesets.ErrorV}");
|
||||
postDeleteScalesets.IsOk.Should().BeTrue("failed to get scalesets after finishing pool deletion due to {0}", postDeleteScalesets.ErrorV);
|
||||
|
||||
_output.WriteLine($"Pool is deleted {newPool.Name}");
|
||||
|
||||
var postDelete = postDeleteScalesets.OkV!.Where(sc => sc.PoolName == newPool.Name);
|
||||
Assert.False(postDelete.Any());
|
||||
postDelete.Should().BeEmpty();
|
||||
var patch1 = await _scalesetApi.Patch(newScaleset.ScalesetId, 1);
|
||||
Assert.False(patch1.IsOk);
|
||||
Assert.True(patch1.ErrorV!.UnableToFindScalesetError);
|
||||
patch1.IsOk.Should().BeFalse();
|
||||
patch1.ErrorV!.UnableToFindScalesetError.Should().BeTrue();
|
||||
}
|
||||
return;
|
||||
|
||||
|
32
src/ApiService/FunctionalTests/TestTasks.cs
Normal file
32
src/ApiService/FunctionalTests/TestTasks.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
||||
namespace FunctionalTests {
|
||||
[Trait("Category", "Live")]
|
||||
public class TestTasks {
|
||||
TaskApi _taskApi;
|
||||
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public TestTasks(ITestOutputHelper output) {
|
||||
this._output = output;
|
||||
_taskApi = new TaskApi(ApiClient.Endpoint, ApiClient.Request, output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetNonExistentTask() {
|
||||
var t1 = await _taskApi.Get(Guid.NewGuid());
|
||||
t1.IsOk.Should().BeTrue();
|
||||
t1.OkV.Should().BeEmpty();
|
||||
|
||||
|
||||
var t2 = await _taskApi.Get(Guid.NewGuid(), Guid.NewGuid());
|
||||
t2.IsOk.Should().BeFalse();
|
||||
t2.ErrorV!.UnableToFindTask.Should().BeTrue();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -8,6 +8,15 @@
|
||||
"resolved": "3.1.2",
|
||||
"contentHash": "wuLDIDKD5XMt0A7lE31JPenT7QQwZPFkP5rRpdJeblyXZ9MGLI8rYjvm5fvAKln+2/X+4IxxQDxBtwdrqKNLZw=="
|
||||
},
|
||||
"FluentAssertions": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.7.0, )",
|
||||
"resolved": "6.7.0",
|
||||
"contentHash": "PWbow/R3MnYDP8UW7zh/w80rGb+1NufGoNJeuzouTo2bqpvwNTFxbDwF6XWfFZ5IuquL2225Um+qSyZ8jVsT+w==",
|
||||
"dependencies": {
|
||||
"System.Configuration.ConfigurationManager": "4.4.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Identity.Client": {
|
||||
"type": "Direct",
|
||||
"requested": "[4.46.1, )",
|
||||
@ -354,6 +363,14 @@
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Configuration.ConfigurationManager": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.4.0",
|
||||
"contentHash": "gWwQv/Ug1qWJmHCmN17nAbxJYmQBM/E94QxKLksvUiiKB1Ld3Sc/eK1lgmbSjDFxkQhVuayI/cGFZhpBSodLrg==",
|
||||
"dependencies": {
|
||||
"System.Security.Cryptography.ProtectedData": "4.4.0"
|
||||
}
|
||||
},
|
||||
"System.Console": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
@ -922,6 +939,11 @@
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Security.Cryptography.ProtectedData": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.4.0",
|
||||
"contentHash": "cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog=="
|
||||
},
|
||||
"System.Security.Cryptography.X509Certificates": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
|
@ -5,6 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
||||
<PackageReference Include="Moq" Version="4.17.2" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
|
@ -8,6 +8,15 @@
|
||||
"resolved": "3.1.2",
|
||||
"contentHash": "wuLDIDKD5XMt0A7lE31JPenT7QQwZPFkP5rRpdJeblyXZ9MGLI8rYjvm5fvAKln+2/X+4IxxQDxBtwdrqKNLZw=="
|
||||
},
|
||||
"FluentAssertions": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.7.0, )",
|
||||
"resolved": "6.7.0",
|
||||
"contentHash": "PWbow/R3MnYDP8UW7zh/w80rGb+1NufGoNJeuzouTo2bqpvwNTFxbDwF6XWfFZ5IuquL2225Um+qSyZ8jVsT+w==",
|
||||
"dependencies": {
|
||||
"System.Configuration.ConfigurationManager": "4.4.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.NET.Test.Sdk": {
|
||||
"type": "Direct",
|
||||
"requested": "[17.1.0, )",
|
||||
@ -1214,6 +1223,14 @@
|
||||
"System.Threading": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Configuration.ConfigurationManager": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.4.0",
|
||||
"contentHash": "gWwQv/Ug1qWJmHCmN17nAbxJYmQBM/E94QxKLksvUiiKB1Ld3Sc/eK1lgmbSjDFxkQhVuayI/cGFZhpBSodLrg==",
|
||||
"dependencies": {
|
||||
"System.Security.Cryptography.ProtectedData": "4.4.0"
|
||||
}
|
||||
},
|
||||
"System.Console": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
@ -2160,39 +2177,39 @@
|
||||
"apiservice": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.25.0",
|
||||
"Azure.Data.Tables": "12.5.0",
|
||||
"Azure.Identity": "1.6.0",
|
||||
"Azure.Messaging.EventGrid": "4.10.0",
|
||||
"Azure.ResourceManager": "1.3.1",
|
||||
"Azure.ResourceManager.Compute": "1.0.0-beta.8",
|
||||
"Azure.ResourceManager.Monitor": "1.0.0-beta.2",
|
||||
"Azure.ResourceManager.Network": "1.0.0",
|
||||
"Azure.ResourceManager.Resources": "1.3.0",
|
||||
"Azure.ResourceManager.Storage": "1.0.0-beta.11",
|
||||
"Azure.Security.KeyVault.Secrets": "4.3.0",
|
||||
"Azure.Storage.Blobs": "12.13.0",
|
||||
"Azure.Storage.Queues": "12.11.0",
|
||||
"Faithlife.Utility": "0.12.2",
|
||||
"Microsoft.ApplicationInsights.DependencyCollector": "2.21.0",
|
||||
"Microsoft.Azure.Functions.Worker": "1.6.0",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "2.1.0",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Http": "3.0.13",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.SignalRService": "1.7.0",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Storage": "5.0.0",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Timer": "4.1.0",
|
||||
"Microsoft.Azure.Functions.Worker.Sdk": "1.3.0",
|
||||
"Microsoft.Azure.Management.Monitor": "0.28.0-preview",
|
||||
"Microsoft.Azure.Management.OperationalInsights": "0.24.0-preview",
|
||||
"Microsoft.Extensions.Logging.ApplicationInsights": "2.21.0",
|
||||
"Microsoft.Graph": "4.37.0",
|
||||
"Microsoft.Identity.Client": "4.46.2",
|
||||
"Microsoft.Identity.Web.TokenCache": "1.23.1",
|
||||
"Scriban": "5.5.0",
|
||||
"Semver": "2.1.0",
|
||||
"System.IdentityModel.Tokens.Jwt": "6.22.1",
|
||||
"System.Linq.Async": "6.0.1",
|
||||
"TaskTupleAwaiter": "2.0.0"
|
||||
"Azure.Core": "[1.25.0, )",
|
||||
"Azure.Data.Tables": "[12.5.0, )",
|
||||
"Azure.Identity": "[1.6.0, )",
|
||||
"Azure.Messaging.EventGrid": "[4.10.0, )",
|
||||
"Azure.ResourceManager": "[1.3.1, )",
|
||||
"Azure.ResourceManager.Compute": "[1.0.0-beta.8, )",
|
||||
"Azure.ResourceManager.Monitor": "[1.0.0-beta.2, )",
|
||||
"Azure.ResourceManager.Network": "[1.0.0, )",
|
||||
"Azure.ResourceManager.Resources": "[1.3.0, )",
|
||||
"Azure.ResourceManager.Storage": "[1.0.0-beta.11, )",
|
||||
"Azure.Security.KeyVault.Secrets": "[4.3.0, )",
|
||||
"Azure.Storage.Blobs": "[12.13.0, )",
|
||||
"Azure.Storage.Queues": "[12.11.0, )",
|
||||
"Faithlife.Utility": "[0.12.2, )",
|
||||
"Microsoft.ApplicationInsights.DependencyCollector": "[2.21.0, )",
|
||||
"Microsoft.Azure.Functions.Worker": "[1.6.0, )",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "[2.1.0, )",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Http": "[3.0.13, )",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.SignalRService": "[1.7.0, )",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Storage": "[5.0.0, )",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Timer": "[4.1.0, )",
|
||||
"Microsoft.Azure.Functions.Worker.Sdk": "[1.3.0, )",
|
||||
"Microsoft.Azure.Management.Monitor": "[0.28.0-preview, )",
|
||||
"Microsoft.Azure.Management.OperationalInsights": "[0.24.0-preview, )",
|
||||
"Microsoft.Extensions.Logging.ApplicationInsights": "[2.21.0, )",
|
||||
"Microsoft.Graph": "[4.37.0, )",
|
||||
"Microsoft.Identity.Client": "[4.46.2, )",
|
||||
"Microsoft.Identity.Web.TokenCache": "[1.23.1, )",
|
||||
"Scriban": "[5.5.0, )",
|
||||
"Semver": "[2.1.0, )",
|
||||
"System.IdentityModel.Tokens.Jwt": "[6.22.1, )",
|
||||
"System.Linq.Async": "[6.0.1, )",
|
||||
"TaskTupleAwaiter": "[2.0.0, )"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2304,39 +2304,39 @@
|
||||
"apiservice": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.25.0",
|
||||
"Azure.Data.Tables": "12.5.0",
|
||||
"Azure.Identity": "1.6.0",
|
||||
"Azure.Messaging.EventGrid": "4.10.0",
|
||||
"Azure.ResourceManager": "1.3.1",
|
||||
"Azure.ResourceManager.Compute": "1.0.0-beta.8",
|
||||
"Azure.ResourceManager.Monitor": "1.0.0-beta.2",
|
||||
"Azure.ResourceManager.Network": "1.0.0",
|
||||
"Azure.ResourceManager.Resources": "1.3.0",
|
||||
"Azure.ResourceManager.Storage": "1.0.0-beta.11",
|
||||
"Azure.Security.KeyVault.Secrets": "4.3.0",
|
||||
"Azure.Storage.Blobs": "12.13.0",
|
||||
"Azure.Storage.Queues": "12.11.0",
|
||||
"Faithlife.Utility": "0.12.2",
|
||||
"Microsoft.ApplicationInsights.DependencyCollector": "2.21.0",
|
||||
"Microsoft.Azure.Functions.Worker": "1.6.0",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "2.1.0",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Http": "3.0.13",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.SignalRService": "1.7.0",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Storage": "5.0.0",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Timer": "4.1.0",
|
||||
"Microsoft.Azure.Functions.Worker.Sdk": "1.3.0",
|
||||
"Microsoft.Azure.Management.Monitor": "0.28.0-preview",
|
||||
"Microsoft.Azure.Management.OperationalInsights": "0.24.0-preview",
|
||||
"Microsoft.Extensions.Logging.ApplicationInsights": "2.21.0",
|
||||
"Microsoft.Graph": "4.37.0",
|
||||
"Microsoft.Identity.Client": "4.46.2",
|
||||
"Microsoft.Identity.Web.TokenCache": "1.23.1",
|
||||
"Scriban": "5.5.0",
|
||||
"Semver": "2.1.0",
|
||||
"System.IdentityModel.Tokens.Jwt": "6.22.1",
|
||||
"System.Linq.Async": "6.0.1",
|
||||
"TaskTupleAwaiter": "2.0.0"
|
||||
"Azure.Core": "[1.25.0, )",
|
||||
"Azure.Data.Tables": "[12.5.0, )",
|
||||
"Azure.Identity": "[1.6.0, )",
|
||||
"Azure.Messaging.EventGrid": "[4.10.0, )",
|
||||
"Azure.ResourceManager": "[1.3.1, )",
|
||||
"Azure.ResourceManager.Compute": "[1.0.0-beta.8, )",
|
||||
"Azure.ResourceManager.Monitor": "[1.0.0-beta.2, )",
|
||||
"Azure.ResourceManager.Network": "[1.0.0, )",
|
||||
"Azure.ResourceManager.Resources": "[1.3.0, )",
|
||||
"Azure.ResourceManager.Storage": "[1.0.0-beta.11, )",
|
||||
"Azure.Security.KeyVault.Secrets": "[4.3.0, )",
|
||||
"Azure.Storage.Blobs": "[12.13.0, )",
|
||||
"Azure.Storage.Queues": "[12.11.0, )",
|
||||
"Faithlife.Utility": "[0.12.2, )",
|
||||
"Microsoft.ApplicationInsights.DependencyCollector": "[2.21.0, )",
|
||||
"Microsoft.Azure.Functions.Worker": "[1.6.0, )",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "[2.1.0, )",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Http": "[3.0.13, )",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.SignalRService": "[1.7.0, )",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Storage": "[5.0.0, )",
|
||||
"Microsoft.Azure.Functions.Worker.Extensions.Timer": "[4.1.0, )",
|
||||
"Microsoft.Azure.Functions.Worker.Sdk": "[1.3.0, )",
|
||||
"Microsoft.Azure.Management.Monitor": "[0.28.0-preview, )",
|
||||
"Microsoft.Azure.Management.OperationalInsights": "[0.24.0-preview, )",
|
||||
"Microsoft.Extensions.Logging.ApplicationInsights": "[2.21.0, )",
|
||||
"Microsoft.Graph": "[4.37.0, )",
|
||||
"Microsoft.Identity.Client": "[4.46.2, )",
|
||||
"Microsoft.Identity.Web.TokenCache": "[1.23.1, )",
|
||||
"Scriban": "[5.5.0, )",
|
||||
"Semver": "[2.1.0, )",
|
||||
"System.IdentityModel.Tokens.Jwt": "[6.22.1, )",
|
||||
"System.Linq.Async": "[6.0.1, )",
|
||||
"TaskTupleAwaiter": "[2.0.0, )"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user