InventoryEndpointStartupTests.cs 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. using System.Net.Http.Json;
  2. using RackPeek.Domain.Api;
  3. using Xunit.Abstractions;
  4. namespace Tests.Api;
  5. /// <summary>
  6. /// The inventory API is reached without a browser — by scripts, by CI, and by
  7. /// <c>rpk discover --push</c> on a timer. It therefore has to work on a server that
  8. /// nobody has opened a page on yet.
  9. /// </summary>
  10. [Collection("Process-wide static state")]
  11. public class InventoryEndpointStartupTests(ITestOutputHelper output) : ApiTestBase(output) {
  12. private const string _existingConfig = """
  13. version: 3
  14. resources:
  15. - kind: Server
  16. name: hand-written-server
  17. notes: documented by hand years ago
  18. connections: []
  19. """;
  20. [Fact]
  21. public async Task The_first_request_after_a_restart_does_not_destroy_the_existing_inventory() {
  22. var configPath = Path.Combine(TempDir, "config.yaml");
  23. await File.WriteAllTextAsync(configPath, _existingConfig);
  24. // The very first thing to touch this server is an API call, with no Blazor
  25. // circuit having ever initialised and therefore no implicit load.
  26. HttpClient client = CreateClient(true);
  27. HttpResponseMessage response = await client.PostAsJsonAsync("/api/inventory", new {
  28. yaml = """
  29. version: 3
  30. resources:
  31. - kind: Server
  32. name: newly-discovered-box
  33. """,
  34. mode = "Merge"
  35. });
  36. response.EnsureSuccessStatusCode();
  37. var stored = await File.ReadAllTextAsync(configPath);
  38. Assert.Contains("hand-written-server", stored);
  39. Assert.Contains("documented by hand years ago", stored);
  40. Assert.Contains("newly-discovered-box", stored);
  41. }
  42. [Fact]
  43. public async Task An_existing_resource_is_updated_rather_than_re_added_on_a_cold_server() {
  44. await File.WriteAllTextAsync(Path.Combine(TempDir, "config.yaml"), _existingConfig);
  45. HttpClient client = CreateClient(true);
  46. HttpResponseMessage response = await client.PostAsJsonAsync("/api/inventory", new {
  47. yaml = """
  48. version: 3
  49. resources:
  50. - kind: Server
  51. name: hand-written-server
  52. notes: updated
  53. """,
  54. mode = "Merge"
  55. });
  56. ImportYamlResponse? result = await response.Content.ReadFromJsonAsync<ImportYamlResponse>();
  57. Assert.Empty(result!.Added);
  58. Assert.Equal(["hand-written-server"], result.Updated);
  59. }
  60. [Fact]
  61. public async Task An_unreadable_config_does_not_stop_the_server_starting() {
  62. // The web UI is how someone fixes a broken config, so it has to come up.
  63. await File.WriteAllTextAsync(
  64. Path.Combine(TempDir, "config.yaml"),
  65. "version: 3\nresources:\n - kind: Server\n name: [unterminated\n");
  66. HttpClient client = CreateClient();
  67. HttpResponseMessage response = await client.GetAsync("/health");
  68. response.EnsureSuccessStatusCode();
  69. Assert.Equal("rackpeek", await response.Content.ReadAsStringAsync());
  70. }
  71. }