132 lines
8.1 KiB
C#
132 lines
8.1 KiB
C#
using System;
|
|
using Xunit;
|
|
using Newtonsoft.Json.Linq;
|
|
using FluentAssertions;
|
|
|
|
namespace raven_integration
|
|
{
|
|
|
|
public class PMCrud
|
|
{
|
|
|
|
/// <summary>
|
|
/// Full CRUD for a Preventive Maintenance header + PMItem.
|
|
/// Also tests concurrency violation and id-from-number lookup.
|
|
/// PM is structurally parallel to WorkOrder (header → items → sub-types)
|
|
/// so failures here flag regressions if the refactor consolidates those patterns.
|
|
///
|
|
/// Key enum values used:
|
|
/// PMTimeUnit: Minutes=2, Hours=3, Days=4, Months=6, Years=7
|
|
/// AyaDaysOfWeek (flags): Monday=1, Tuesday=2, Wednesday=4, Thursday=8,
|
|
/// Friday=16, Saturday=32, Sunday=64
|
|
/// excludeDaysOfWeek=96 means Saturday(32)|Sunday(64)
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task CRUD()
|
|
{
|
|
var token = await Util.GetTokenAsync("BizAdmin");
|
|
// nextServiceDate must be a future UTC timestamp
|
|
var isoNextService = DateTime.UtcNow.AddDays(7).ToString("o");
|
|
|
|
// -------------------------------------------------------------------
|
|
// CREATE PM HEADER
|
|
// customerId=1 is a seeded customer; serial=0 means server assigns it.
|
|
// -------------------------------------------------------------------
|
|
var payload = $$"""
|
|
{"id":0,"concurrency":0,"serial":0,"notes":"Test PM — the quick brown fox jumped over the six lazy dogs!","wiki":null,"customFields":"{}","tags":[],"copyWiki":false,"copyAttachments":true,"stopGeneratingDate":null,"excludeDaysOfWeek":96,"active":false,"nextServiceDate":"{{isoNextService}}","repeatUnit":6,"generateBeforeUnit":4,"repeatInterval":1,"generateBeforeInterval":3,"customerId":1,"projectId":null,"internalReferenceNumber":"PM-INT-001","customerReferenceNumber":null,"customerContactName":null,"onsite":true,"contractId":null,"postAddress":null,"postCity":null,"postRegion":null,"postCountry":null,"postCode":null,"address":null,"city":null,"region":null,"country":null,"addressPostal":null,"latitude":null,"longitude":null}
|
|
""";
|
|
|
|
ApiResponse a = await Util.PostAsync("pm", token, payload);
|
|
Util.ValidateDataReturnResponseOk(a);
|
|
long PMId = a.ObjectResponse["data"]["id"].Value<long>();
|
|
long PMSerial = a.ObjectResponse["data"]["serial"].Value<long>();
|
|
PMId.Should().BeGreaterThan(0);
|
|
PMSerial.Should().BeGreaterThan(0, "server should have assigned a non-zero serial");
|
|
|
|
// -------------------------------------------------------------------
|
|
// GET PM
|
|
// -------------------------------------------------------------------
|
|
a = await Util.GetAsync($"pm/{PMId}", token);
|
|
Util.ValidateDataReturnResponseOk(a);
|
|
a.ObjectResponse["data"]["id"].Value<long>().Should().Be(PMId);
|
|
a.ObjectResponse["data"]["repeatUnit"].Value<int>().Should().Be(6, "should be Months");
|
|
a.ObjectResponse["data"]["excludeDaysOfWeek"].Value<int>().Should().Be(96, "should be Sat+Sun flags");
|
|
a.ObjectResponse["data"]["internalReferenceNumber"].Value<string>().Should().Be("PM-INT-001");
|
|
var headerConcurrency = a.ObjectResponse["data"]["concurrency"].Value<uint>();
|
|
|
|
// -------------------------------------------------------------------
|
|
// ID-FROM-NUMBER LOOKUP
|
|
// -------------------------------------------------------------------
|
|
a = await Util.GetAsync($"pm/id-from-number/{PMSerial}", token);
|
|
Util.ValidateDataReturnResponseOk(a);
|
|
a.ObjectResponse["data"].Value<long>().Should().Be(PMId);
|
|
|
|
// -------------------------------------------------------------------
|
|
// CREATE PM ITEM
|
|
// -------------------------------------------------------------------
|
|
payload = $$"""
|
|
{"id":0,"concurrency":0,"notes":"Test PM item summary","wiki":null,"customFields":"{}","tags":[],"pmId":{{PMId}},"techNotes":"Tech notes for PM item","workOrderItemStatusId":null,"workOrderItemPriorityId":null,"requestDate":null,"warrantyService":false,"sequence":1}
|
|
""";
|
|
a = await Util.PostAsync("pm/items", token, payload);
|
|
Util.ValidateDataReturnResponseOk(a);
|
|
long PMItemId = a.ObjectResponse["data"]["id"].Value<long>();
|
|
PMItemId.Should().BeGreaterThan(0);
|
|
|
|
// GET PM ITEM
|
|
a = await Util.GetAsync($"pm/items/{PMItemId}", token);
|
|
Util.ValidateDataReturnResponseOk(a);
|
|
a.ObjectResponse["data"]["notes"].Value<string>().Should().Be("Test PM item summary");
|
|
var itemConcurrency = a.ObjectResponse["data"]["concurrency"].Value<uint>();
|
|
|
|
// -------------------------------------------------------------------
|
|
// UPDATE PM ITEM
|
|
// -------------------------------------------------------------------
|
|
|
|
payload = $$"""
|
|
{"id":{{PMItemId}},"concurrency":{{itemConcurrency}},"notes":"Updated PM item notes","wiki":null,"customFields":"{}","tags":[],"pmId":{{PMId}},"techNotes":"Updated tech notes","workOrderItemStatusId":null,"workOrderItemPriorityId":null,"requestDate":null,"warrantyService":false,"sequence":1}
|
|
""";
|
|
a = await Util.PutAsync("pm/items/", token, payload);
|
|
Util.ValidateHTTPStatusCode(a, 200);
|
|
var newItemConcurrency = a.ObjectResponse["data"]["concurrency"].Value<uint>();
|
|
newItemConcurrency.Should().NotBe(itemConcurrency, "concurrency should increment on update");
|
|
|
|
// CONCURRENCY VIOLATION on item
|
|
a = await Util.PutAsync("pm/items/", token, payload); // stale concurrency
|
|
Util.ValidateConcurrencyError(a);
|
|
|
|
// -------------------------------------------------------------------
|
|
// UPDATE PM HEADER
|
|
// -------------------------------------------------------------------
|
|
|
|
var isoNewNextService = DateTime.UtcNow.AddDays(14).ToString("o");
|
|
payload = $$"""
|
|
{"id":{{PMId}},"concurrency":{{headerConcurrency}},"serial":{{PMSerial}},"notes":"Updated PM notes","wiki":null,"customFields":"{}","tags":[],"copyWiki":true,"copyAttachments":true,"stopGeneratingDate":null,"excludeDaysOfWeek":0,"active":false,"nextServiceDate":"{{isoNewNextService}}","repeatUnit":7,"generateBeforeUnit":4,"repeatInterval":1,"generateBeforeInterval":5,"customerId":1,"projectId":null,"internalReferenceNumber":"PM-INT-002","customerReferenceNumber":null,"customerContactName":null,"onsite":false,"contractId":null,"postAddress":null,"postCity":null,"postRegion":null,"postCountry":null,"postCode":null,"address":null,"city":null,"region":null,"country":null,"addressPostal":null,"latitude":null,"longitude":null}
|
|
""";
|
|
a = await Util.PutAsync("pm", token, payload);
|
|
Util.ValidateHTTPStatusCode(a, 200);
|
|
a.ObjectResponse["data"]["internalReferenceNumber"].Value<string>().Should().Be("PM-INT-002");
|
|
a.ObjectResponse["data"]["repeatUnit"].Value<int>().Should().Be(7, "should now be Years");
|
|
var newHeaderConcurrency = a.ObjectResponse["data"]["concurrency"].Value<uint>();
|
|
newHeaderConcurrency.Should().NotBe(headerConcurrency);
|
|
|
|
// CONCURRENCY VIOLATION on header
|
|
a = await Util.PutAsync("pm", token, payload); // stale concurrency
|
|
Util.ValidateConcurrencyError(a);
|
|
|
|
// -------------------------------------------------------------------
|
|
// DELETE in bottom-up order: item → header
|
|
// -------------------------------------------------------------------
|
|
a = await Util.DeleteAsync($"pm/items/{PMItemId}", token);
|
|
Util.ValidateHTTPStatusCode(a, 204);
|
|
|
|
a = await Util.DeleteAsync($"pm/{PMId}", token);
|
|
Util.ValidateHTTPStatusCode(a, 204);
|
|
|
|
// Confirm header is gone
|
|
a = await Util.GetAsync($"pm/{PMId}", token);
|
|
Util.ValidateResponseNotFound(a);
|
|
}
|
|
|
|
}//eoc
|
|
}//eons
|