File size: 6,693 Bytes
95b671e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
import { strict as assert } from "node:assert";
import { test } from "node:test";
import {
  PoisonMessageError,
  describeCollectorFailure,
  encodeIngestMessage,
  getIngestQueueConfig,
  isPermanentCollectorFailure,
  isPoisonMessageError,
  parseIngestMessage,
  queueDeliveryMetricFromParsedMessage,
} from "./ingest-queue.js";

const baseInput = {
  path: "/v1/logs",
  projectId: "project-1",
  contentType: "application/x-protobuf",
  body: Buffer.from("hello"),
};

test("getIngestQueueConfig leaves direct forwarding enabled by default", () => {
  assert.equal(getIngestQueueConfig({}), null);
});

test("getIngestQueueConfig reads bounded consumer concurrency", () => {
  const config = getIngestQueueConfig({
    INGEST_QUEUE_URL: "https://sqs.us-west-2.amazonaws.com/123/superlog-test-ingest",
    INGEST_QUEUE_CONSUMER_CONCURRENCY: "99",
  });

  assert.equal(config?.consumerConcurrency, 32);
});

test("encodeIngestMessage stores small payloads inline", () => {
  const encoded = encodeIngestMessage(
    baseInput,
    {
      maxMessageBytes: 240_000,
      oversizePrefix: "otlp-oversize",
    },
    new Date("2026-05-24T00:00:00.000Z"),
    "payload-1",
  );

  assert.equal(encoded.storage, "inline");
  assert.equal(encoded.s3Object, undefined);

  const message = JSON.parse(encoded.messageBody);
  assert.equal(message.body.storage, "inline");
  assert.equal(Buffer.from(message.body.base64, "base64").toString("utf8"), "hello");
});

test("encodeIngestMessage offloads payloads that would exceed the SQS envelope budget", () => {
  const encoded = encodeIngestMessage(
    { ...baseInput, body: Buffer.alloc(32, 7), contentEncoding: "gzip" },
    {
      maxMessageBytes: 10,
      oversizeBucket: "superlog-ingest-oversize",
      oversizePrefix: "/otlp-oversize/",
    },
    new Date("2026-05-24T12:34:56.000Z"),
    "payload-2",
  );

  assert.equal(encoded.storage, "s3");
  assert.equal(encoded.s3Object?.bucket, "superlog-ingest-oversize");
  assert.equal(encoded.s3Object?.key, "otlp-oversize/2026/05/24/payload-2.otlp");
  assert.equal(encoded.s3Object?.body.byteLength, 32);

  const message = JSON.parse(encoded.messageBody);
  assert.equal(message.body.storage, "s3");
  assert.equal(message.body.bucket, "superlog-ingest-oversize");
  assert.equal(message.body.key, "otlp-oversize/2026/05/24/payload-2.otlp");
  assert.equal(message.contentEncoding, "gzip");
});

test("describeCollectorFailure includes bounded collector response body", () => {
  const failure = describeCollectorFailure(400, "bad request: invalid OTLP payload");

  assert.equal(failure.message, "collector returned 400: bad request: invalid OTLP payload");
  assert.equal(failure.status, 400);
  assert.equal(failure.body, "bad request: invalid OTLP payload");
});

test("isPermanentCollectorFailure drops 4xx the collector can never accept on retry", () => {
  // A real prod incident: a client sent http.response_content_length above uint64 max,
  // the collector 400s the whole batch, and the consumer cycled the same message every
  // 900s (visibility timeout) for ~12.5h before the DLQ — pinning oldest-message-age into
  // a sawtooth. Re-sending identical bytes can never succeed, so 4xx must be dropped.
  assert.equal(isPermanentCollectorFailure(400), true);
  assert.equal(isPermanentCollectorFailure(401), true);
  assert.equal(isPermanentCollectorFailure(403), true);
  assert.equal(isPermanentCollectorFailure(404), true);
  assert.equal(isPermanentCollectorFailure(413), true);
  assert.equal(isPermanentCollectorFailure(422), true);
});

test("isPermanentCollectorFailure keeps retryable statuses on the queue", () => {
  // 408/429 are backpressure/timeout signals and 5xx are transient — the same payload can
  // succeed once the collector recovers, so these stay in the queue for redelivery.
  assert.equal(isPermanentCollectorFailure(408), false);
  assert.equal(isPermanentCollectorFailure(429), false);
  assert.equal(isPermanentCollectorFailure(500), false);
  assert.equal(isPermanentCollectorFailure(502), false);
  assert.equal(isPermanentCollectorFailure(503), false);
  assert.equal(isPermanentCollectorFailure(504), false);
  // Not a failure status at all — defensively never treated as a permanent drop.
  assert.equal(isPermanentCollectorFailure(200), false);
});

test("parseIngestMessage round-trips a well-formed inline message", () => {
  const encoded = encodeIngestMessage(
    baseInput,
    { maxMessageBytes: 240_000, oversizePrefix: "otlp-oversize" },
    new Date("2026-05-24T00:00:00.000Z"),
    "payload-ok",
  );

  const parsed = parseIngestMessage(encoded.messageBody);
  assert.equal(parsed.path, "/v1/logs");
  assert.equal(parsed.body.storage, "inline");
});

test("parseIngestMessage flags an empty inline body as a poison message", () => {
  // An empty OTLP HTTP body base64-encodes to "" — there is nothing to forward and
  // no retry can ever succeed, so it must be classified as poison (delete, not cycle).
  const emptyBody = JSON.stringify({
    version: 1,
    kind: "otlp",
    path: "/v1/logs",
    projectId: "project-1",
    contentType: "application/json",
    receivedAt: "2026-05-29T00:00:00.000Z",
    body: { storage: "inline", base64: "" },
  });

  assert.throws(() => parseIngestMessage(emptyBody), PoisonMessageError);
  try {
    parseIngestMessage(emptyBody);
  } catch (err) {
    assert.equal(isPoisonMessageError(err), true);
  }
});

test("parseIngestMessage flags non-JSON message bodies as poison", () => {
  assert.throws(() => parseIngestMessage("not json at all"), PoisonMessageError);
});

test("parseIngestMessage flags valid JSON with malformed envelope fields as poison", () => {
  // Valid JSON, but `path` is a number — assertIngestMessage's `.startsWith` would throw a
  // TypeError. A structurally-broken envelope can never succeed on retry, so it must be poison.
  const malformed = JSON.stringify({
    version: 1,
    kind: "otlp",
    path: 123,
    projectId: "project-1",
    contentType: "application/json",
    body: { storage: "inline", base64: "aGVsbG8=" },
  });

  assert.throws(() => parseIngestMessage(malformed), PoisonMessageError);
});

test("isPoisonMessageError discriminates transient errors", () => {
  assert.equal(isPoisonMessageError(new Error("collector returned 503")), false);
  assert.equal(isPoisonMessageError(new PoisonMessageError("bad")), true);
});

test("queueDeliveryMetricFromParsedMessage ignores malformed parsed payloads", () => {
  assert.equal(
    queueDeliveryMetricFromParsedMessage(
      { path: "/v1/logs", projectId: "project-1", body: {} },
      "delivery_error",
      undefined,
      12,
      34,
    ),
    null,
  );
});