Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

tests and bug fixes #2379

Merged
merged 1 commit into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/ApiService/ApiService/Functions/Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ private async Async.Task<HttpResponseData> Get(HttpRequestData req) {
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());
}

Expand Down Expand Up @@ -96,7 +96,7 @@ private async Async.Task<HttpResponseData> Patch(HttpRequestData req) {
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());
}

Expand Down Expand Up @@ -129,7 +129,7 @@ private async Async.Task<HttpResponseData> Post(HttpRequestData req) {
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());
}

Expand Down
2 changes: 1 addition & 1 deletion src/ApiService/ApiService/Functions/Tasks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ private async Async.Task<HttpResponseData> Get(HttpRequestData req) {
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;
Expand Down
2 changes: 1 addition & 1 deletion src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public async Async.Task SyncScalesetSize(Scaleset scaleset) {
_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}");
}
Expand Down
2 changes: 1 addition & 1 deletion src/ApiService/ApiService/onefuzzlib/VmssOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private VirtualMachineScaleSetResource GetVmssResource(Guid name) {
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;
}
}
Expand Down
147 changes: 146 additions & 1 deletion src/ApiService/FunctionalTests/1f-api/ApiBase.cs
Original file line number Diff line number Diff line change
@@ -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);
}
Expand All @@ -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);
Expand All @@ -30,6 +159,22 @@ public ApiBase(Uri endpoint, string relativeUri, Microsoft.OneFuzz.Service.Reque
_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();
Expand Down
18 changes: 18 additions & 0 deletions src/ApiService/FunctionalTests/1f-api/Authentication.cs
Original file line number Diff line number Diff line change
@@ -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 changes: 48 additions & 0 deletions src/ApiService/FunctionalTests/1f-api/Container.cs
Original file line number Diff line number Diff line change
@@ -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 changes: 21 additions & 0 deletions src/ApiService/FunctionalTests/1f-api/Download.cs
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
12 changes: 9 additions & 3 deletions src/ApiService/FunctionalTests/1f-api/Error.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -49,5 +51,9 @@ public override string ToString() {

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 changes: 48 additions & 0 deletions src/ApiService/FunctionalTests/1f-api/Info.cs
Original file line number Diff line number Diff line change
@@ -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> {
stishkin marked this conversation as resolved.
Show resolved Hide resolved
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);
}
}
}
Loading