Desk: a read of an oversize fork is 422 fork_too_large #42
4 changed files with 32 additions and 3 deletions
|
|
@ -151,7 +151,7 @@ public static class DeskRefusals
|
|||
[RequestIdConflict] = (409, "request_id_conflict: this request_id was used for a different body"),
|
||||
};
|
||||
|
||||
// fork_too_large (Libby's ruling) is list-only and names its fork, so it is built here, not read from the table.
|
||||
// fork_too_large (Libby's ruling) names its fork, so it is built here, not read from the table.
|
||||
// Not a literal const: the pinned vectors' doorRefusals do not name it yet, and the schema test pins literals to them.
|
||||
public static string ForkTooLarge => "fork_too_large";
|
||||
|
||||
|
|
@ -164,6 +164,10 @@ public static class DeskRefusals
|
|||
? $"fork_too_large: fork {forkId} (order {order}) is too large for a page; continue with cursor c{order}"
|
||||
: $"fork_too_large: fork {forkId} (order {order}) is too large for a page; the list has reached its end");
|
||||
|
||||
// A read of an oversize fork: the same permanent refusal, naming the fork and nothing to page.
|
||||
public static DeskRefusal ForkTooLargeDocument(string forkId) => new(
|
||||
DeskSchemas.Refusal, ForkTooLarge, $"fork_too_large: fork {forkId} is too large to return");
|
||||
|
||||
public static bool IsKnown(string code) => Table.ContainsKey(code);
|
||||
|
||||
public static int StatusOf(string code) => Table[code].Status;
|
||||
|
|
|
|||
|
|
@ -189,6 +189,10 @@ public static class DeskEndpoints
|
|||
{
|
||||
await WriteJsonAsync(http, 200, IsDecider(context) ? entry : DeskNotes.Strip(entry));
|
||||
}
|
||||
else if (found is DeskReadOutcome.ForkTooLarge(var largeFork))
|
||||
{
|
||||
await WriteJsonAsync(http, DeskRefusals.ForkTooLargeStatus, DeskRefusals.ForkTooLargeDocument(largeFork));
|
||||
}
|
||||
else if (found is DeskReadOutcome.NotFound(var readCode) && DoorMayRefuse(readCode) && readCode != DeskRefusals.RequestIdConflict)
|
||||
{
|
||||
await WriteRefusalAsync(http, ReadListCode(readCode));
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ public abstract record DeskReadOutcome
|
|||
public sealed record Found(ForkEntry Entry) : DeskReadOutcome;
|
||||
|
||||
public sealed record NotFound(string Code) : DeskReadOutcome;
|
||||
|
||||
// The fork is too large to return: permanent, and nothing to page, so no order or cursor.
|
||||
public sealed record ForkTooLarge(string ForkId) : DeskReadOutcome;
|
||||
}
|
||||
|
||||
// The list request the desk's query string stands for. Mind is the route's, resolved against the configured list.
|
||||
|
|
@ -47,7 +50,7 @@ public abstract record DeskListOutcome
|
|||
public sealed record NotListed(string Code) : DeskListOutcome;
|
||||
|
||||
// The next fork is too large for any page: the page holds nothing past the cursor. The client continues with
|
||||
// cursor c<Order>; at Order 0 it has reached the end. List only: no other call can be refused this way.
|
||||
// cursor c<Order>; at Order 0 it has reached the end. A read of such a fork has its own outcome (no order).
|
||||
public sealed record ForkTooLarge(string ForkId, int Order) : DeskListOutcome;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ public sealed class DeskReadTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task fork_too_large_is_list_only_elsewhere_the_door_saying_it_is_unavailable()
|
||||
public async Task fork_too_large_as_a_bare_door_code_is_unavailable_only_the_typed_outcomes_are_the_refusal()
|
||||
{
|
||||
using var factory = new DeskWebApplicationFactory();
|
||||
await factory.EnsureAccountAsync(DeskWebApplicationFactory.Alice, true);
|
||||
|
|
@ -164,6 +164,24 @@ public sealed class DeskReadTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task A_read_of_an_oversize_fork_is_the_same_422_naming_the_fork_with_no_order_or_cursor()
|
||||
{
|
||||
using var factory = new DeskWebApplicationFactory();
|
||||
await factory.EnsureAccountAsync(DeskWebApplicationFactory.Alice, true);
|
||||
factory.Door.ReadScript = (_, id) => new DeskReadOutcome.ForkTooLarge(id);
|
||||
|
||||
var reply = await factory.SendAsync("GET", DeskReplay.Target("read", "nibu", "nibu:question:huge"), null, ReadToken(factory));
|
||||
|
||||
var doc = JsonNode.Parse(reply.Body)!;
|
||||
Assert.Equal(422, reply.Status);
|
||||
Assert.Equal("fork_too_large", (string?)doc["code"]);
|
||||
var error = (string)doc["error"]!;
|
||||
Assert.Contains("nibu:question:huge", error);
|
||||
Assert.DoesNotContain("order", error);
|
||||
Assert.DoesNotContain("cursor", error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task A_short_page_with_a_cursor_below_its_last_entry_passes_through_unchanged()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue