117 lines
7.2 KiB
C#
117 lines
7.2 KiB
C#
using System;
|
|
using Xunit;
|
|
using Newtonsoft.Json.Linq;
|
|
using FluentAssertions;
|
|
|
|
namespace raven_integration
|
|
{
|
|
|
|
public class CustomerCrud
|
|
{
|
|
|
|
/// <summary>
|
|
/// Full CRUD for a Customer, including concurrency violation and alert retrieval.
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task CRUD()
|
|
{
|
|
var token = await Util.GetTokenAsync("BizAdmin");
|
|
|
|
// CREATE
|
|
var name = Util.Uniquify("Test Customer");
|
|
var payload = $$"""
|
|
{"id":0,"concurrency":0,"name":"{{name}}","active":true,"notes":"The quick brown fox jumped over the six lazy dogs!","wiki":null,"customFields":"{}","tags":[],"webAddress":null,"alertNotes":"Test alert text for this customer","billHeadOffice":false,"headOfficeId":null,"techNotes":"Tech-only notes","accountNumber":"ACC-001","contractId":null,"contractExpires":null,"phone1":"555-1234","phone2":null,"phone3":null,"phone4":null,"phone5":null,"emailAddress":"test@example.com","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("customer", 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($"customer/{Id}", token);
|
|
Util.ValidateDataReturnResponseOk(a);
|
|
a.ObjectResponse["data"]["name"].Value<string>().Should().Be(name);
|
|
a.ObjectResponse["data"]["phone1"].Value<string>().Should().Be("555-1234");
|
|
var concurrency = a.ObjectResponse["data"]["concurrency"].Value<uint>();
|
|
|
|
// GET ALERT
|
|
a = await Util.GetAsync($"customer/alert/{Id}", token);
|
|
Util.ValidateDataReturnResponseOk(a);
|
|
a.ObjectResponse["data"].Value<string>().Should().Be("Test alert text for this customer");
|
|
|
|
// PUT (update name and phone)
|
|
var updatedName = Util.Uniquify("Updated Customer");
|
|
var putPayload = $$"""
|
|
{"id":{{Id}},"concurrency":{{concurrency}},"name":"{{updatedName}}","active":true,"notes":"Updated notes","wiki":null,"customFields":"{}","tags":[],"webAddress":null,"alertNotes":"Updated alert text","billHeadOffice":false,"headOfficeId":null,"techNotes":null,"accountNumber":null,"contractId":null,"contractExpires":null,"phone1":"555-9999","phone2":null,"phone3":null,"phone4":null,"phone5":null,"emailAddress":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("customer", 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($"customer/{Id}", token);
|
|
Util.ValidateDataReturnResponseOk(a);
|
|
a.ObjectResponse["data"]["name"].Value<string>().Should().Be(updatedName);
|
|
a.ObjectResponse["data"]["phone1"].Value<string>().Should().Be("555-9999");
|
|
|
|
// CONCURRENCY VIOLATION: PUT with stale concurrency should return 409
|
|
a = await Util.PutAsync("customer", token, putPayload); // putPayload still has old concurrency
|
|
Util.ValidateConcurrencyError(a);
|
|
|
|
// DELETE
|
|
a = await Util.DeleteAsync($"customer/{Id}", token);
|
|
Util.ValidateHTTPStatusCode(a, 204);
|
|
|
|
// Confirm deleted
|
|
a = await Util.GetAsync($"customer/{Id}", token);
|
|
Util.ValidateResponseNotFound(a);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// A customer that has at least one work order associated with it should not
|
|
/// be deletable — referential integrity must be enforced.
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task CustomerWithWorkOrders_CannotBeDeleted()
|
|
{
|
|
var token = await Util.GetTokenAsync("BizAdmin");
|
|
|
|
// Create a dedicated customer so we control what is linked to it
|
|
var name = Util.Uniquify("RefInt Customer");
|
|
var payload = $$"""
|
|
{"id":0,"concurrency":0,"name":"{{name}}","active":true,"notes":null,"wiki":null,"customFields":"{}","tags":[],"webAddress":null,"alertNotes":null,"billHeadOffice":false,"headOfficeId":null,"techNotes":null,"accountNumber":null,"contractId":null,"contractExpires":null,"phone1":null,"phone2":null,"phone3":null,"phone4":null,"phone5":null,"emailAddress":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("customer", token, payload);
|
|
Util.ValidateDataReturnResponseOk(a);
|
|
long customerId = a.ObjectResponse["data"]["id"].Value<long>();
|
|
|
|
// Create a work order linked to this customer
|
|
var isoNow = DateTime.UtcNow.ToString("o");
|
|
var woPayload = $$"""
|
|
{"id":0,"concurrency":0,"serial":0,"notes":"RefInt test WO","wiki":null,"customFields":"{}","tags":[],"customerId":{{customerId}},"projectId":null,"contractId":null,"internalReferenceNumber":null,"customerReferenceNumber":null,"customerContactName":null,"fromQuoteId":null,"fromPMId":null,"serviceDate":"{{isoNow}}","completeByDate":null,"durationToCompleted":"00:00:00","invoiceNumber":null,"onsite":true,"customerSignature":null,"customerSignatureName":null,"customerSignatureCaptured":null,"techSignature":null,"techSignatureName":null,"techSignatureCaptured":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,"isDirty":true,"isLockedAtServer":false}
|
|
""";
|
|
a = await Util.PostAsync("workorder", token, woPayload);
|
|
Util.ValidateDataReturnResponseOk(a);
|
|
long woId = a.ObjectResponse["data"]["id"].Value<long>();
|
|
|
|
// Attempt to delete the customer — should be blocked by referential integrity
|
|
//bugbug: this is returning a 500 due to a bug at the server end
|
|
//case 4653, holding off fixing until ready for refactor.
|
|
a = await Util.DeleteAsync($"customer/{customerId}", token);
|
|
Util.ValidateViolatesReferentialIntegrityError(a);
|
|
|
|
// Clean up: delete the work order first, then the customer
|
|
a = await Util.DeleteAsync($"workorder/{woId}", token);
|
|
Util.ValidateHTTPStatusCode(a, 204);
|
|
|
|
a = await Util.DeleteAsync($"customer/{customerId}", token);
|
|
Util.ValidateHTTPStatusCode(a, 204);
|
|
}
|
|
|
|
}//eoc
|
|
}//eons
|