RDF Messages Tests

Living Document,

This version:
https://w3c-cg.github.io/rsp/spec/messages-tests
Issue Tracking:
GitHub
Editors:
Pieter Colpaert
Piotr Sowiński (NeverBlink)

Abstract

Tests for parsers and serializers with message support in various RDF serializations.

1. RDF Messages Interoperability Tests

This document proposes interoperability tests for implementations that support RDF Message Logs and RDF Message live streams for different serializations.

Implementations of parsers, serializers, and live stream adapters MUST provide conformance tests that verify message-level behavior.

An RDF Message Log parser MUST expose a message-level interface that emits one RDF Dataset per completed message.

A message is completed when a message delimiter or the end of the input is encountered. Empty messages MUST be preserved when they occur before the first triple or quad, or between two delimiters. A trailing delimiter after a non-empty message MUST finalize that message and MUST not by itself create an additional empty trailing message.

Blank node identifiers in RDF Message Logs MUST be scoped to the message in which they occur. Therefore, if the same blank node label appears in two different messages in the same input stream, the parser MUST produce two distinct blank nodes. This requirement applies even when the entire RDF Message Log is parsed from one continuous input string or stream by one parser instance.

Message delimiters are message-level syntax. They MUST only occur where the underlying RDF syntax permits directives or top-level statements, and MUST not occur inside an open graph block. A delimiter encountered inside a graph block MUST be a parse error.

Serializers should produce RDF Message Logs that round-trip to the same message sequence and the same quads per message. Conformance tests should not require a serializer to choose a specific delimiter spelling when more than one delimiter spelling is supported by the target syntax.

1.1. Parsing Tests for Turtle, TriG, N-Triples, and N-Quads

1.1.1. Single Message Without Delimiter

Input:

VERSION "1.2-messages"
<http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

Expected messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

1.1.2. Two Messages With MESSAGE

Input:

VERSION "1.2-messages"
<http://example.org/s1> <http://example.org/p> <http://example.org/o1> .
MESSAGE
<http://example.org/s2> <http://example.org/p> <http://example.org/o2> .

Expected messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

Message 2:
  <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .

1.1.3. Two Messages With @message .

Input:

@version "1.2-messages" .
@prefix ex: <http://example.org/> .

ex:s1 ex:p ex:o1 .
@message .
ex:s2 ex:p ex:o2 .

Expected messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

Message 2:
  <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .

1.1.4. Empty First Message

Input:

VERSION "1.2-messages"
MESSAGE
<http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

Expected messages:

Message 1:
  empty

Message 2:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

1.1.5. Empty Message Between Non-Empty Messages

Input:

VERSION "1.2-messages"
<http://example.org/s1> <http://example.org/p> <http://example.org/o1> .
MESSAGE
MESSAGE
<http://example.org/s2> <http://example.org/p> <http://example.org/o2> .

Expected messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

Message 2:
  empty

Message 3:
  <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .

1.1.6. Final Delimiter Does Not Create Extra Empty Message

Input:

VERSION "1.2-messages"
<http://example.org/s1> <http://example.org/p> <http://example.org/o1> .
MESSAGE

Expected messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

1.1.7. N-Quads Messages Preserve Graph Names

Input:

VERSION "1.2-messages"
<http://example.org/s1> <http://example.org/p> <http://example.org/o1> <http://example.org/g1> .
MESSAGE
<http://example.org/s2> <http://example.org/p> <http://example.org/o2> <http://example.org/g2> .

Expected messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> <http://example.org/g1> .

Message 2:
  <http://example.org/s2> <http://example.org/p> <http://example.org/o2> <http://example.org/g2> .

1.1.8. Message With Default Graph And Named Graph Quads

Input:

VERSION "1.2-messages"
PREFIX ex: <http://example.org/>

ex:s1 ex:p ex:o1 .
ex:g {
  ex:s2 ex:p ex:o2 .
  ex:s3 ex:p ex:o3 .
}
MESSAGE
ex:s4 ex:p ex:o4 .

Expected messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .
  <http://example.org/s2> <http://example.org/p> <http://example.org/o2> <http://example.org/g> .
  <http://example.org/s3> <http://example.org/p> <http://example.org/o3> <http://example.org/g> .

Message 2:
  <http://example.org/s4> <http://example.org/p> <http://example.org/o4> .

1.1.9. Blank Node Labels Are Scoped Per Message

Input:

VERSION "1.2-messages"
_:b0 <http://example.org/p> <http://example.org/o1> .
MESSAGE
_:b0 <http://example.org/p> <http://example.org/o2> .

Expected result:

Message 1 contains one quad whose subject is a blank node.
Message 2 contains one quad whose subject is a blank node.
The two blank nodes must not be the same RDF term.

This test must be performed on one continuous input string or stream, not by creating two independent parser instances.

1.1.10. Repeated Prefixes Across Messages

Input:

VERSION "1.2-messages"
PREFIX ex: <http://example.org/one/>
ex:s ex:p ex:o .
MESSAGE
PREFIX ex: <http://example.org/two/>
ex:s ex:p ex:o .

Expected messages:

Message 1:
  <http://example.org/one/s> <http://example.org/one/p> <http://example.org/one/o> .

Message 2:
  <http://example.org/two/s> <http://example.org/two/p> <http://example.org/two/o> .

1.1.11. Message Boundary After A Graph Block

Input:

VERSION "1.2-messages"
<http://example.org/g> {
  <http://example.org/a> <http://example.org/b> <http://example.org/c> .
}
MESSAGE
<http://example.org/d> <http://example.org/e> <http://example.org/f> .

Expected messages:

Message 1:
  <http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/g> .

Message 2:
  <http://example.org/d> <http://example.org/e> <http://example.org/f> .

1.2. Parsing Tests for NDJSON-LD

In these tests, each input line is one JSON object. Context messages update parser state but do not emit RDF messages. A parser maintains an active context that is updated by context messages.

1.2.1. Context Message Followed By Data Message

Input:

{"@context": "https://schema.org/"}
{"@type": "Product", "name": "Hairdryer DRY 2000", "color": "red"}

Expected messages:

Message 1:
  RDF dataset obtained by interpreting the second JSON object with @context = "https://schema.org/".

1.2.2. Empty Message Does Not Change Active Context

Input:

{"@context": "https://schema.org/"}
{}
{"@type": "Product", "name": "27-inch 4K Monitor 2700P", "color": "black"}

Expected messages:

Message 1:
  empty

Message 2:
  RDF dataset obtained by interpreting the third JSON object with @context = "https://schema.org/".

1.2.3. Context Switch Applies To Subsequent Data Messages

Input:

{"@context": "https://schema.org/"}
{"@type": "Product", "name": "Hairdryer DRY 2000", "color": "red"}
{"@context": "https://example.org/other-vocab/"}
{"@type": "OtherType", "name": "Piotr"}

Expected messages:

Message 1:
  RDF dataset obtained by interpreting the second JSON object with @context = "https://schema.org/".

Message 2:
  RDF dataset obtained by interpreting the fourth JSON object with @context = "https://example.org/other-vocab/".

1.2.4. Data Message With Local @context Is Wrapped With Active Context

Input:

{"@context": {"ex": "https://example.org/base/", "name": "ex:baseName"}}
{"@context": {"label": "ex:label"}, "@type": "ex:Thing", "name": "Alice", "label": "A"}
{"@type": "ex:Thing", "name": "Bob"}

Expected messages:

Message 1:
  RDF dataset obtained by processing the effective JSON-LD document:
  {"@context": {"ex": "https://example.org/base/", "name": "ex:baseName"}, "@graph": {"@context": {"label": "ex:label"}, "@type": "ex:Thing", "name": "Alice", "label": "A"}}

Message 2:
  RDF dataset obtained by processing the effective JSON-LD document:
  {"@context": {"ex": "https://example.org/base/", "name": "ex:baseName"}, "@graph": {"@type": "ex:Thing", "name": "Bob"}}
  The local @context from line 2 does not change the active context C for subsequent messages.

1.2.5. Data Message Without Prior Context Is Allowed

Input:

{"@id": "https://example.org/p1", "@type": "https://example.org/Product"}

Expected messages:

Message 1:
  RDF dataset obtained by interpreting the JSON object as regular JSON-LD, without a stream-level active context.

1.3. Parsing Tests for RDF/XML

These tests apply to parsers of RDF Message Logs in the RDF/XML serialization. In all tests, the rdfm prefix refers to https://w3c-cg.github.io/rsp/spec/messages#.

1.3.1. Two Messages

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/">
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s1">
      <ex:p rdf:resource="http://example.org/o1"/>
    </rdf:Description>
  </rdf:RDF>
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s2">
      <ex:p rdf:resource="http://example.org/o2"/>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

Message 2:
  <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .

1.3.2. Empty Log

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#"/>

Expected result:

No messages.

1.3.3. Empty Message Between Non-Empty Messages

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/">
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s1">
      <ex:p rdf:resource="http://example.org/o1"/>
    </rdf:Description>
  </rdf:RDF>
  <rdf:RDF/>
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s2">
      <ex:p rdf:resource="http://example.org/o2"/>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

Message 2:
  (empty)

Message 3:
  <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .

1.3.4. Blank Node Identifiers Are Scoped Per Message

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/">
  <rdf:RDF>
    <rdf:Description rdf:nodeID="b0">
      <ex:p rdf:resource="http://example.org/o1"/>
    </rdf:Description>
  </rdf:RDF>
  <rdf:RDF>
    <rdf:Description rdf:nodeID="b0">
      <ex:p rdf:resource="http://example.org/o2"/>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected result:

Message 1 contains one quad whose subject is a blank node.
Message 2 contains one quad whose subject is a blank node.
The two blank nodes must not be the same RDF term.

This test must be performed on one continuous input string or stream, not by splitting the input and creating two independent parser instances.

1.3.5. Blank Node Identifier Reused Within One Message

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/">
  <rdf:RDF>
    <rdf:Description rdf:nodeID="b0">
      <ex:p rdf:resource="http://example.org/o1"/>
    </rdf:Description>
    <rdf:Description rdf:nodeID="b0">
      <ex:p rdf:resource="http://example.org/o2"/>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected result:

Message 1 contains two quads whose subjects are blank nodes.
The two blank nodes must be the same RDF term.

1.3.6. Namespaces Declared On The Log Element

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/one/">
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s">
      <ex:p rdf:resource="http://example.org/o"/>
    </rdf:Description>
  </rdf:RDF>
  <rdf:RDF xmlns:ex="http://example.org/two/">
    <rdf:Description rdf:about="http://example.org/s">
      <ex:p rdf:resource="http://example.org/o"/>
    </rdf:Description>
  </rdf:RDF>
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s">
      <ex:p rdf:resource="http://example.org/o"/>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected messages:

Message 1:
  <http://example.org/s> <http://example.org/one/p> <http://example.org/o> .

Message 2:
  <http://example.org/s> <http://example.org/two/p> <http://example.org/o> .

Message 3:
  <http://example.org/s> <http://example.org/one/p> <http://example.org/o> .

The namespace declared on the second <rdf:RDF> element applies only to that message.

1.3.7. Base IRI Declared On The Log Element

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/" xml:base="http://example.org/one/">
  <rdf:RDF>
    <rdf:Description rdf:about="s">
      <ex:p rdf:resource="o"/>
    </rdf:Description>
  </rdf:RDF>
  <rdf:RDF xml:base="http://example.org/two/">
    <rdf:Description rdf:about="s">
      <ex:p rdf:resource="o"/>
    </rdf:Description>
  </rdf:RDF>
  <rdf:RDF>
    <rdf:Description rdf:about="s">
      <ex:p rdf:resource="o"/>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected messages:

Message 1:
  <http://example.org/one/s> <http://example.org/p> <http://example.org/one/o> .

Message 2:
  <http://example.org/two/s> <http://example.org/p> <http://example.org/two/o> .

Message 3:
  <http://example.org/one/s> <http://example.org/p> <http://example.org/one/o> .

1.3.8. Language Tag Declared On The Log Element

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/" xml:lang="en">
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s">
      <ex:p>hello</ex:p>
    </rdf:Description>
  </rdf:RDF>
  <rdf:RDF xml:lang="pl">
    <rdf:Description rdf:about="http://example.org/s">
      <ex:p>czesc</ex:p>
    </rdf:Description>
  </rdf:RDF>
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s">
      <ex:p>bye</ex:p>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected messages:

Message 1:
  <http://example.org/s> <http://example.org/p> "hello"@en .

Message 2:
  <http://example.org/s> <http://example.org/p> "czesc"@pl .

Message 3:
  <http://example.org/s> <http://example.org/p> "bye"@en .

1.3.9. Comments And Processing Instructions Between Messages Are Ignored

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/">
  <!-- first message -->
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s1">
      <ex:p rdf:resource="http://example.org/o1"/>
    </rdf:Description>
  </rdf:RDF>
  <?example-pi some data?>
  <!-- second message -->
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s2">
      <ex:p rdf:resource="http://example.org/o2"/>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

Message 2:
  <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .

1.3.10. Multiline Literal

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/">
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s">
      <ex:p>line one
line two</ex:p>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected messages:

Message 1:
  <http://example.org/s> <http://example.org/p> "line one\nline two" .

1.4. Serialization Tests for Turtle, TriG, N-Triples, and N-Quads

Given a sequence of RDF Messages, a serializer should write a document that can be parsed back into the same sequence of messages and quads.

Serializers may choose the concrete message delimiter supported by their syntax. These tests should not assert whether @message . or MESSAGE was used.

Round-trip input messages:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

Message 2:
  empty

Message 3:
  <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .

Expected result after serializing and parsing the output:

Message 1:
  <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .

Message 2:
  empty

Message 3:
  <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .

Round-trip input messages with named graph quads:

Message 1:
  <http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/g> .

Message 2:
  <http://example.org/d> <http://example.org/e> <http://example.org/f> <http://example.org/g> .

Expected result after serializing and parsing the output:

Message 1:
  <http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/g> .

Message 2:
  <http://example.org/d> <http://example.org/e> <http://example.org/f> <http://example.org/g> .

1.5. Error Tests

1.5.1. Message Delimiter Without Message Support

If a parser is not in RDF Messages mode and encounters a message delimiter, it must reject the document.

Input:

<http://example.org/s> <http://example.org/p> <http://example.org/o> .
MESSAGE

Expected result:

Parse error.

1.5.2. @message Without Trailing Dot

Input:

VERSION "1.2-messages"
<http://example.org/s> <http://example.org/p> <http://example.org/o> .
@message <http://example.org/invalid>

Expected result:

Parse error.

1.5.3. Message Delimiter Inside An Open Graph Block

A message delimiter must not be accepted inside an open graph block. It must be rejected instead of being interpreted as splitting the graph block across two messages.

Input:

VERSION "1.2-messages"
<http://example.org/g> {
  <http://example.org/a> <http://example.org/b> <http://example.org/c> .
MESSAGE
  <http://example.org/d> <http://example.org/e> <http://example.org/f> .
}

Expected result:

Parse error.

1.5.4. RDF/XML Root Element Is Not rdfm:MessageLog

If a parser is reading an RDF/XML RDF Message Log, it must reject a document whose root element is not <rdfm:MessageLog>.

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:ex="http://example.org/">
  <rdf:Description rdf:about="http://example.org/s">
    <ex:p rdf:resource="http://example.org/o"/>
  </rdf:Description>
</rdf:RDF>

Expected result:

Parse error.

1.5.5. RDF/XML Node Element Directly Inside rdfm:MessageLog

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/">
  <rdf:Description rdf:about="http://example.org/s">
    <ex:p rdf:resource="http://example.org/o"/>
  </rdf:Description>
</rdfm:MessageLog>

Expected result:

Parse error.

1.5.6. RDF/XML Text Between Messages

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/">
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s1">
      <ex:p rdf:resource="http://example.org/o1"/>
    </rdf:Description>
  </rdf:RDF>
  some text
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s2">
      <ex:p rdf:resource="http://example.org/o2"/>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected result:

Parse error.

1.5.7. RDF/XML Log Read By A Parser Without Message Support

If a parser is not in RDF Messages mode and reads an RDF/XML RDF Message Log as a plain RDF/XML document, it must reject the document, because rdf:RDF is not allowed as a property element name.

Input:

<?xml version="1.0" encoding="utf-8"?>
<rdfm:MessageLog xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm="https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex="http://example.org/">
  <rdf:RDF>
    <rdf:Description rdf:about="http://example.org/s">
      <ex:p rdf:resource="http://example.org/o"/>
    </rdf:Description>
  </rdf:RDF>
</rdfm:MessageLog>

Expected result:

Parse error.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

References

Normative References

[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119