Files
raven-test-integration/Part/PartCrud.cs
2026-03-02 15:51:01 -08:00

120 lines
5.6 KiB
C#

using System;
using Xunit;
using Newtonsoft.Json.Linq;
using FluentAssertions;
namespace raven_integration
{
public class PartCrud
{
/// <summary>
/// Full CRUD for a Part, including concurrency violation.
/// </summary>
[Fact]
public async Task CRUD()
{
var token = await Util.GetTokenAsync("BizAdmin");
// CREATE
var name = Util.Uniquify("Test Part");
var payload = $$"""
{"id":0,"concurrency":0,"name":"{{name}}","active":true,"cost":9.99,"retail":14.99,"description":null,"notes":null,"wiki":null,"customFields":"{}","tags":[],"manufacturerId":null,"manufacturerNumber":null,"wholeSalerId":null,"wholeSalerNumber":null,"alternativeWholeSalerId":null,"alternativeWholeSalerNumber":null,"unitOfMeasure":null,"upc":null}
""";
ApiResponse a = await Util.PostAsync("part", token, payload);
Util.ValidateDataReturnResponseOk(a);
long Id = a.ObjectResponse["data"]["id"].Value<long>();
Id.Should().BeGreaterThan(0);
a.ObjectResponse["data"]["name"].Value<string>().Should().Be(name);
// GET
a = await Util.GetAsync($"part/{Id}", token);
Util.ValidateDataReturnResponseOk(a);
a.ObjectResponse["data"]["name"].Value<string>().Should().Be(name);
a.ObjectResponse["data"]["cost"].Value<decimal>().Should().Be(9.99m);
var concurrency = a.ObjectResponse["data"]["concurrency"].Value<uint>();
// PUT (update name and cost)
var updatedName = Util.Uniquify("Updated Part");
var putPayload = $$"""
{"id":{{Id}},"concurrency":{{concurrency}},"name":"{{updatedName}}","active":true,"cost":11.99,"retail":14.99,"description":null,"notes":null,"wiki":null,"customFields":"{}","tags":[],"manufacturerId":null,"manufacturerNumber":null,"wholeSalerId":null,"wholeSalerNumber":null,"alternativeWholeSalerId":null,"alternativeWholeSalerNumber":null,"unitOfMeasure":null,"upc":null}
""";
a = await Util.PutAsync("part", token, putPayload);
Util.ValidateHTTPStatusCode(a, 200);
var newConcurrency = a.ObjectResponse["data"]["concurrency"].Value<uint>();
newConcurrency.Should().NotBe(concurrency, "concurrency should have been bumped by the update");
// Verify the update was persisted
a = await Util.GetAsync($"part/{Id}", token);
Util.ValidateDataReturnResponseOk(a);
a.ObjectResponse["data"]["name"].Value<string>().Should().Be(updatedName);
a.ObjectResponse["data"]["cost"].Value<decimal>().Should().Be(11.99m);
// CONCURRENCY VIOLATION: PUT with stale concurrency should return 409
a = await Util.PutAsync("part", token, putPayload); // putPayload still has old concurrency
Util.ValidateConcurrencyError(a);
// DELETE
a = await Util.DeleteAsync($"part/{Id}", token);
Util.ValidateHTTPStatusCode(a, 204);
// Confirm deleted
a = await Util.GetAsync($"part/{Id}", token);
Util.ValidateResponseNotFound(a);
}
/// <summary>
/// Verifies that serial numbers can be written to and read back from a Part.
/// </summary>
[Fact]
public async Task Serials_RoundTrip()
{
var token = await Util.GetTokenAsync("BizAdmin");
// CREATE a part to attach serials to
var name = Util.Uniquify("Test Part");
var payload = $$"""
{"id":0,"concurrency":0,"name":"{{name}}","active":true,"cost":9.99,"retail":14.99,"description":null,"notes":null,"wiki":null,"customFields":"{}","tags":[],"manufacturerId":null,"manufacturerNumber":null,"wholeSalerId":null,"wholeSalerNumber":null,"alternativeWholeSalerId":null,"alternativeWholeSalerNumber":null,"unitOfMeasure":null,"upc":null}
""";
ApiResponse a = await Util.PostAsync("part", token, payload);
Util.ValidateDataReturnResponseOk(a);
long Id = a.ObjectResponse["data"]["id"].Value<long>();
Id.Should().BeGreaterThan(0);
// GET serials — should be empty initially
a = await Util.GetAsync($"part/serials/{Id}", token);
Util.ValidateDataReturnResponseOk(a);
Util.ValidateHTTPStatusCode(a, 200);
((JArray)a.ObjectResponse["data"]).Count.Should().Be(0);
// PUT serials — write three serial numbers
var serialsPayload = """["SN-A001","SN-A002","SN-A003"]""";
a = await Util.PutAsync($"part/serials/{Id}", token, serialsPayload);
Util.ValidateHTTPStatusCode(a, 200);
// GET serials again — verify all three are returned
a = await Util.GetAsync($"part/serials/{Id}", token);
Util.ValidateDataReturnResponseOk(a);
Util.ValidateHTTPStatusCode(a, 200);
var serials = (JArray)a.ObjectResponse["data"];
serials.Count.Should().Be(3);
serials.Values<string>().Should().Contain("SN-A001");
serials.Values<string>().Should().Contain("SN-A002");
serials.Values<string>().Should().Contain("SN-A003");
// Clean up: clear serials before deleting (parts with serials cannot be deleted)
a = await Util.PutAsync($"part/serials/{Id}", token, "[]");
Util.ValidateHTTPStatusCode(a, 200);
a = await Util.DeleteAsync($"part/{Id}", token);
Util.ValidateHTTPStatusCode(a, 204);
}
}//eoc
}//eons