<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.6.15 (Ruby 3.1.2) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-dcook-ppm-dap-interop-test-design-00" category="info" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.13.1 -->
  <front>
    <title>DAP Interoperation Test Design</title>
    <seriesInfo name="Internet-Draft" value="draft-dcook-ppm-dap-interop-test-design-00"/>
    <author fullname="David Cook">
      <organization>ISRG</organization>
      <address>
        <email>dcook@letsencrypt.org</email>
      </address>
    </author>
    <date year="2022" month="August" day="04"/>
    <area>Security</area>
    <workgroup>Privacy Preserving Measurement</workgroup>
    <abstract>
      <t>This document defines a common test interface for implementations of the Distributed Aggregation Protocol for Privacy Preserving Measurement (DAP-PPM) and describes how this test interface can be used to perform interoperation testing between the implementations. Tests are orchestrated with containers, and new test-only APIs are introduced to provision DAP-PPM tasks and initiate processing.</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        The latest revision of this draft can be found at <eref target="https://divergentdave.github.io/draft-dcook-ppm-dap-interop-test-design/draft-dcook-ppm-dap-interop-test-design.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-dcook-ppm-dap-interop-test-design/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        Privacy Preserving Measurement Working Group mailing list (<eref target="mailto:ppm@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/ppm/"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/ppm/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/divergentdave/draft-dcook-ppm-dap-interop-test-design"/>.</t>
    </note>
  </front>
  <middle>
    <section anchor="introduction">
      <name>Introduction</name>
      <t>This document defines a common test interface for implementations of the Distributed Aggregation Protocol for Privacy Preserving Measurement <xref target="DAP-PPM"/>. This test interface facilitates interoperation tests between different participating DAP-PPM implementations. As DAP-PPM has four distinct protocol roles, (client, leader aggregator, helper aggregator, and collector) manual interoperation testing between all combinations of even a small number of DAP-PPM implementations could be taxing. The goal of this document's common test interface is to enable automation of these interoperation tests, so that different participating implementations can be exchanged for each other, and the same test suite can be re-run on different combinations of implementations. Simplifying interoperation testing will aid in identifying errors in implementations, identifying ambiguities in the protocol specification, and reducing regressions in implementations.</t>
      <t>Taking inspiration from QuicInteropRunner <xref target="SI2020"/>, each participating implementation provides one or more container images adhering to a common interface. A test runner will start one container for each protocol participant, configure networking between the containers, and send various HTTP API requests. As part of this common testing interface, the HTTP servers in the containers will support some new test-only HTTP APIs, which will allow the test runner to provision shared task parameters and secrets, as well as trigger the start of different sub-protocols.</t>
    </section>
    <section anchor="conventions-and-definitions">
      <name>Conventions and Definitions</name>
      <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
"<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>
    </section>
    <section anchor="container-interface">
      <name>Container Interface</name>
      <t>Each participating DAP implementation may provide one or more container images, one for each protocol role it implements. (client, leader, helper, and collector) A list of available container images will be maintained for each role. Implementations may want to submit a single aggregator image in both the leader list and helper list. The test runner will fetch each container using the given repository, image name, and tag.</t>
      <t>When the container's entry point executable is run, it <bcp14>SHALL</bcp14> start up an HTTP server listening on port 8080. In all cases, the container will serve the endpoints described in <xref target="test-api"/> (particularly, the subsection appropriate to its protocol role). In the case of a helper or leader container, it <bcp14>SHALL</bcp14> also serve the endpoints specified by <xref target="DAP-PPM"/> on the same port, at some relative path. The container should run indefinitely, and the test runner will terminate the container on completion of the test case. (While DAP-PPM requires HTTPS connections, only using HTTP between containers simplifies test setup. Putting TLS client/server interop out-of-scope for these tests is acceptable, as it's not of interest.)</t>
      <t>Log output <bcp14>SHOULD</bcp14> be captured into the directory "/logs" inside the container. This will be copied out to the host for inspection on completion of the test case.</t>
      <t>No environment variables or volume mounts will be provided to the containers.</t>
    </section>
    <section anchor="test-api">
      <name>Interoperation Test API</name>
      <t>Each container will have an HTTP server listening on port 8080 for commands from the test runner. Requests and responses for each endpoint listed below <bcp14>SHALL</bcp14> be encoded JSON objects <xref target="RFC8729"/>, with media type <tt>application/json</tt>. All binary blobs (i.e. task IDs, HPKE configurations, and verification keys) <bcp14>SHALL</bcp14> be encoded as strings with base64url <xref target="RFC4648"/>, inside the JSON objects.</t>
      <t>Each of these test APIs should return a status code of 200 OK if the command was received, recognized, and parsed successfully, regardless of whether any underlying DAP-PPM request succeeded or failed. The DAP-level success or failure will be included in the test API response body. If a request is made to an endpoint starting with "/internal/test/", but not listed here, a status code of 404 Not Found <bcp14>SHOULD</bcp14> be returned, to simplify the introduction of new test APIs.</t>
      <section anchor="common-structures">
        <name>Common Structures</name>
        <t>In multiple APIs defined below, the test runner will send the name of a VDAF, along with the parameters necessary to fully specify the VDAF. These will be stored in a nested object, with the following attributes (new <tt>type</tt> values and new keys will be added as new VDAFs are defined).</t>
        <table anchor="vdaf-object">
          <name>VDAF JSON object structure</name>
          <thead>
            <tr>
              <th align="left">Key</th>
              <th align="left">Value</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="left">
                <tt>type</tt></td>
              <td align="left">One of <tt>"Prio3Aes128Count"</tt>, <tt>"Prio3Aes128Sum"</tt>, or <tt>"Prio3Aes128Histogram"</tt></td>
            </tr>
            <tr>
              <td align="left">
                <tt>bits</tt> (only present if <tt>type</tt> is <tt>"Prio3Aes128Sum"</tt>)</td>
              <td align="left">The bit width of the integers being summed, (as a number) used to parameterize the Prio3Aes128Sum VDAF.</td>
            </tr>
            <tr>
              <td align="left">
                <tt>buckets</tt> (only present if <tt>type</tt> is <tt>"Prio3Aes128Histogram"</tt>)</td>
              <td align="left">An array of histogram bucket boundaries, (as numbers) used to parameterize the Prio3Aes128Histogram VDAF.</td>
            </tr>
          </tbody>
        </table>
      </section>
      <section anchor="client">
        <name>Client</name>
        <section anchor="upload">
          <name><tt>/internal/test/upload</tt></name>
          <t>Upon receipt of this command, the client container will construct a DAP-PPM report with the given configuration and measurement, and submit it. The client container will send its response to the test runner once report submission has either succeeded or permanently failed.</t>
          <table>
            <name>Request JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>taskId</tt></td>
                <td align="left">A base64url-encoded DAP-PPM <tt>TaskId</tt>.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>leader</tt></td>
                <td align="left">The leader's endpoint URL.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>helper</tt></td>
                <td align="left">The helper's endpoint URL.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>vdaf</tt></td>
                <td align="left">An object, with the layout given in {vdaf-object}. This determines the VDAF to be used when constructing a report.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>measurement</tt></td>
                <td align="left">If the VDAF's <tt>type</tt> is <tt>"Prio3Aes128Count"</tt>: 0 or 1. If the VDAF's <tt>type</tt> is <tt>"Prio3Aes128Sum"</tt>: a number (should be an integer). If the VDAF's <tt>type</tt> is <tt>"Prio3Aes128Histogram"</tt>: a number (should be an integer).</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>nonceTime</tt> (optional)</td>
                <td align="left">If present, this provides a substitute time value that should be used when constructing the report. If not present, the current system time should be used, as per normal. The time is represented as a number, with a value of the number of seconds since the UNIX epoch.</td>
              </tr>
            </tbody>
          </table>
          <table>
            <name>Response JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>status</tt></td>
                <td align="left">
                  <tt>"success"</tt> if the report was submitted to the leader successfully, or <tt>"error"</tt> otherwise.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>error</tt> (optional)</td>
                <td align="left">An optional error message, to assist in troubleshooting. This will be included in the test runner logs.</td>
              </tr>
            </tbody>
          </table>
        </section>
      </section>
      <section anchor="aggregator-leader-or-helper">
        <name>Aggregator (Leader or Helper)</name>
        <section anchor="endpoint-for-task">
          <name><tt>/internal/test/endpoint_for_task</tt></name>
          <t>Request the base URL for DAP-PPM endpoints for a new task. This API will be invoked immediately before <tt>/internal/test/add_task</tt> (see <xref target="aggregator-add-task"/>), to determine the endpoint URLs of the aggregators. If the aggregator uses a common set of DAP-PPM endpoints for all tasks, it could always return the same value, such as the relative URL <tt>/</tt>. Alternately, implementations may wish to generate new endpoints for each task, derive the endpoint based on the <tt>TaskId</tt>, etc.</t>
          <t>The test runner will provide the hostname and port at which the aggregator is externally reachable. If the aggregator returns a relative URL, the test runner will combine it with the hostname and port into an absolute URL. Otherwise, the aggregator can incorporate the hostname and port into an absolute URL and return that.</t>
          <table>
            <name>Request JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>taskId</tt></td>
                <td align="left">A base64url-encoded DAP-PPM <tt>TaskId</tt></td>
              </tr>
              <tr>
                <td align="left">
                  <tt>aggregatorId</tt></td>
                <td align="left">0 if this aggregator is the leader, or 1 if this aggregator is the helper.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>hostnameAndPort</tt></td>
                <td align="left">This aggregator's hostname and port in the interoperation test environment. This may optionally be used in constructing the endpoint URL as an absolute URL.</td>
              </tr>
            </tbody>
          </table>
          <table>
            <name>Response JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>status</tt></td>
                <td align="left">
                  <tt>"success"</tt> if the endpoint was successfully selected or set up, or <tt>"error"</tt> otherwise.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>error</tt> (optional)</td>
                <td align="left">An optional error message, to assist in troubleshooting. This will be included in the test runner logs.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>endpoint</tt></td>
                <td align="left">A relative or absolute URL, specifying the DAP-PPM aggregator endpoint that should be used for this task. If the test runner receives a relative URL, it will transform it into an absolute URL before performing the next phase of task setup.</td>
              </tr>
            </tbody>
          </table>
        </section>
        <section anchor="aggregator-add-task">
          <name><tt>/internal/test/add_task</tt></name>
          <t>Register a task with the aggregator, with the given configuration and secrets.</t>
          <t>The HPKE keypair generated for this task should use the mandatory-to-implement algorithms in section 6 of <xref target="DAP-PPM"/>, for broad compatibility.</t>
          <table>
            <name>Request JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>taskId</tt></td>
                <td align="left">A base64url-encoded DAP-PPM <tt>TaskId</tt>.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>leader</tt></td>
                <td align="left">The leader's endpoint URL. The test runner will ensure this is an absolute URL.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>helper</tt></td>
                <td align="left">The helper's endpoint URL. The test runner will ensure this is an absolute URL.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>vdaf</tt></td>
                <td align="left">An object, with the layout given in {vdaf-object}. This determines the task's VDAF.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>leaderAuthenticationToken</tt></td>
                <td align="left">The authentication bearer token that is shared with the other aggregator, as a string. This string must be safe for use as an HTTP header value.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>collectorAuthenticationToken</tt> (only present if <tt>aggregatorId</tt> is 0)</td>
                <td align="left">The authentication bearer token that is shared between the leader and collector, as a string. This string must be safe for use as an HTTP header value.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>aggregatorId</tt></td>
                <td align="left">0 if this aggregator is the leader, or 1 if this aggregator is the helper.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>verifyKey</tt></td>
                <td align="left">The verification key shared by the two aggregators, encoded with base64url.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>maxBatchLifetime</tt></td>
                <td align="left">A number, providing the maximum number of times any report can be included in a collect request.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>minBatchSize</tt></td>
                <td align="left">A number, providing the minimum number of reports that must be in a batch for it to be collected.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>minBatchDuration</tt></td>
                <td align="left">A number, providing the minimum number of seconds that can be in a batch's interval. The batch interval will always be a multiple of this value.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>collectorHpkeConfig</tt></td>
                <td align="left">The collector's HPKE configuration, encoded in base64url, for encryption of aggregate shares.</td>
              </tr>
            </tbody>
          </table>
          <table>
            <name>Response JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>status</tt></td>
                <td align="left">
                  <tt>"success"</tt> if the task was successfully set up, or <tt>"error"</tt> otherwise. (for example, if the VDAF was not supported)</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>error</tt> (optional)</td>
                <td align="left">An optional error message, to assist in troubleshooting. This will be included in the test runner logs.</td>
              </tr>
            </tbody>
          </table>
        </section>
      </section>
      <section anchor="collector">
        <name>Collector</name>
        <section anchor="collector-add-task">
          <name><tt>/internal/test/add_task</tt></name>
          <t>Register a task with the collector, with the given configuration. Returns the collector's HPKE configuration for this task.</t>
          <table>
            <name>Request JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>taskId</tt></td>
                <td align="left">A base64url-encoded DAP-PPM <tt>TaskId</tt>.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>leader</tt></td>
                <td align="left">The leader's endpoint URL.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>vdaf</tt></td>
                <td align="left">An object, with the layout given in {vdaf-object}. This determines the task's VDAF.</td>
              </tr>
            </tbody>
          </table>
          <table>
            <name>Response JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>status</tt></td>
                <td align="left">
                  <tt>"success"</tt> if the task was successfully set up, or <tt>"error"</tt> otherwise. (for example, if the VDAF was not supported)</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>error</tt> (optional)</td>
                <td align="left">An optional error message, to assist in troubleshooting. This will be included in the test runner logs.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>collectorHpkeConfig</tt> (if successful)</td>
                <td align="left">The collector's HPKE configuration, encoded in base64url, for encryption of aggregate shares.</td>
              </tr>
            </tbody>
          </table>
        </section>
        <section anchor="collect-start">
          <name><tt>/internal/test/collect_start</tt></name>
          <t>Send a collect request to the leader with the provided parameters, and return a handle to the test runner identifying this collect request. The test runner will provide this handle to the collector in subsequent <tt>/internal/test/collect_poll</tt> requests (see <xref target="collect-poll"/>).</t>
          <table>
            <name>Request JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>taskId</tt></td>
                <td align="left">A base64url-encoded DAP-PPM <tt>TaskId</tt>.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>aggParam</tt></td>
                <td align="left">A base64url-encoded aggregation parameter.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>batchIntervalStart</tt></td>
                <td align="left">The start of the batch interval, represented as a number equal to the number of seconds since the UNIX epoch.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>batchIntervalDuration</tt></td>
                <td align="left">The duration of the batch interval in seconds, as a number.</td>
              </tr>
            </tbody>
          </table>
          <table>
            <name>Response JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>status</tt></td>
                <td align="left">
                  <tt>"success"</tt> if the collect request succeeded, or <tt>"error"</tt> otherwise.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>error</tt> (optional)</td>
                <td align="left">An optional error message, to assist in troubleshooting. This will be included in the test runner logs.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>handle</tt> (if successful)</td>
                <td align="left">A handle produced by the collector to refer to this collect request. This must be a string.</td>
              </tr>
            </tbody>
          </table>
        </section>
        <section anchor="collect-poll">
          <name><tt>/internal/test/collect_poll</tt></name>
          <t>Upon receiving this command, the collector will poll the leader's collect URL for the collect job associated with the provided handle, and provide the status and result to the test runner.</t>
          <table>
            <name>Request JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>handle</tt></td>
                <td align="left">The handle for a collect request from a previous invocation of <tt>/internal/test/collect_start</tt>. (see <xref target="collect-start"/>)</td>
              </tr>
            </tbody>
          </table>
          <table>
            <name>Response JSON object structure</name>
            <thead>
              <tr>
                <th align="left">Key</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>status</tt></td>
                <td align="left">Either <tt>"complete"</tt> if the result was returned, <tt>"in progress"</tt> if the result was not yet ready, or <tt>"error"</tt> if an error occurred.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>error</tt> (optional)</td>
                <td align="left">An optional error message, to assist in troubleshooting. This will be included in the test runner logs.</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>result</tt> (if complete)</td>
                <td align="left">The result of the aggregation. If the VDAF is of type Prio3Aes128Count or Prio3Aes128Sum, this will be a number. If the VDAF is of type Prio3Aes128Histogram, this will be an array of numbers.</td>
              </tr>
            </tbody>
          </table>
        </section>
        <section anchor="heavy-hitters">
          <name>Heavy Hitters</name>
          <t>Once Poplar1 reaches a future draft of <xref target="DAP-PPM"/>, additional test APIs for collector containers should be introduced to perform an entire Heavy Hitters computation on a given Poplar1 task and collection interval, encompassing multiple collect flows automatically initiated by the collector.</t>
        </section>
      </section>
      <section anchor="test-cases">
        <name>Test Cases</name>
        <t>Test cases could be written to cover the following scenarios.</t>
        <ul spacing="normal">
          <li>Test successful aggregations with each VDAF.</li>
          <li>Test an aggregation over a few hundred or thousand reports, to exercise the aggregators' division of reports into aggregation jobs.</li>
          <li>Test that uploading a report with a time far in the future is rejected.</li>
          <li>Confirm that leaders and helpers reject requests with respective authentication tokens that are incorrect.</li>
          <li>Test enforcement of <tt>max_batch_lifetime</tt> by making overlapping collect requests.</li>
          <li>Perform an entire aggregation and collect flow, attempt to upload a late report that falls into the same collect interval, and test that performing the collect request a second time yields the same result.</li>
          <li>Attempt to upload a canned report from the test runner more than once, and confirm that anti-replay measures were effective by inspecting the aggregation result.</li>
        </ul>
      </section>
      <section anchor="other-test-considerations">
        <name>Other Test Considerations</name>
        <t>All test cases should automatically fail after a generous timeout.</t>
        <t>It is the responsibility of the test runner to wait for all containers to start up and listen on their ports before sending any commands.</t>
        <t>Aggregator URLs will be constructed by the test runner with hostnames that resolve to the respective containers within the container network.</t>
        <t>Once a future <xref target="DAP-PPM"/> draft solves the issue of retries in the aggregate flow, a reverse proxy could be introduced in front of each aggregator to inject failures when sending requests or responses, to test the protocol's resilience. (It is known such a test would fail based on the current protocol.)</t>
      </section>
      <section anchor="test-runner-operation">
        <name>Test Runner Operation</name>
        <t>The following sequence outlines how the test runner will use the above APIs on port 8080 of each container to perform a typical integration test, executing a successful aggregation.</t>
        <ol spacing="normal" type="1"><li>Create and start containers.</li>
          <li>Set up networking between containers.</li>
          <li>Try opening a TCP connection to each container's port, and retry until it succeeds.</li>
          <li>Generate a random <tt>TaskId</tt>, random authentication tokens, and a VDAF verification key.</li>
          <li>Send a <tt>/internal/test/endpoint_for_task</tt> request (<xref target="endpoint-for-task"/>) to the leader.</li>
          <li>Send a <tt>/internal/test/endpoint_for_task</tt> request to the helper.</li>
          <li>Construct aggregator URLs using the above responses.</li>
          <li>Send a <tt>/internal/test/add_task</tt> request (<xref target="collector-add-task"/>) to the collector. (the collector generates an HPKE key pair as a side-effect)</li>
          <li>Send a <tt>/internal/test/add_task</tt> request (<xref target="aggregator-add-task"/>) to the leader.</li>
          <li>Send a <tt>/internal/test/add_task</tt> request (<xref target="aggregator-add-task"/>) to the helper.</li>
          <li>Send one or more <tt>/internal/test/upload</tt> requests (<xref target="upload"/>) to the client.</li>
          <li>Send a <tt>/internal/test/collect_start</tt> request (<xref target="collect-start"/>) to the collector. (this provides a handle for use in the next step)</li>
          <li>Send <tt>/internal/test/collect_poll</tt> requests (<xref target="collect-poll"/>) to the collector, polling until it is completed. (the collector will provide the calculated aggregate result)</li>
          <li>Stop containers.</li>
          <li>Copy logs out of each container.</li>
          <li>Delete containers, and clean up container networking resources.</li>
        </ol>
      </section>
    </section>
    <section anchor="implementation-status">
      <name>Implementation Status</name>
      <t>This document has not yet been implemented at time of writing. There are two open source DAP-PPM implementations, <xref target="Janus"/> from Divvi Up and <xref target="Daphne"/> from Cloudflare Research, which could be extended with this testing interface.</t>
      <t>The TypeScript <xref target="divviup-ts"/> library could readily be turned into a client-only test participant.</t>
      <t>Both divviup-ts and the VDAF proof of concept implementation <xref target="VDAF-POC"/> could be used as the VDAF core of a non-production DAP-PPM implementation, to provide diversity of VDAF implementations in interoperation tests.</t>
      <t>Additional DAP-PPM implementations would be warmly welcomed.</t>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>Any DAP-PPM implementation that adopts this testing interface should ensure that the test-only APIs described herein are only present in software used for testing purposes, and not in production systems.</t>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>
  </middle>
  <back>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>
        <reference anchor="DAP-PPM" target="https://datatracker.ietf.org/doc/html/draft-ietf-ppm-dap-01">
          <front>
            <title>Distributed Aggregation Protocol for Privacy Preserving Measurement</title>
            <author initials="T." surname="Geoghegan">
              <organization/>
            </author>
            <author initials="C." surname="Patton">
              <organization/>
            </author>
            <author initials="E." surname="Rescorla">
              <organization/>
            </author>
            <author initials="C. A." surname="Wood">
              <organization/>
            </author>
            <date year="2022" month="July" day="11"/>
          </front>
        </reference>
        <reference anchor="RFC2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author fullname="S. Bradner" initials="S." surname="Bradner">
              <organization/>
            </author>
            <date month="March" year="1997"/>
            <abstract>
              <t>In many standards track documents several words are used to signify the requirements in the specification.  These words are often capitalized. This document defines these words as they should be interpreted in IETF documents.  This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>
        <reference anchor="RFC8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author fullname="B. Leiba" initials="B." surname="Leiba">
              <organization/>
            </author>
            <date month="May" year="2017"/>
            <abstract>
              <t>RFC 2119 specifies common key words that may be used in protocol  specifications.  This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the  defined special meanings.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
        <reference anchor="RFC8729">
          <front>
            <title>The RFC Series and RFC Editor</title>
            <author fullname="R. Housley" initials="R." role="editor" surname="Housley">
              <organization/>
            </author>
            <author fullname="L. Daigle" initials="L." role="editor" surname="Daigle">
              <organization/>
            </author>
            <date month="February" year="2020"/>
            <abstract>
              <t>This document describes the framework for an RFC Series and an RFC Editor function that incorporate the principles of organized community involvement and accountability that has become necessary as the Internet technical community has grown, thereby enabling the RFC Series to continue to fulfill its mandate. This document obsoletes RFC 4844.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="8729"/>
          <seriesInfo name="DOI" value="10.17487/RFC8729"/>
        </reference>
        <reference anchor="RFC4648">
          <front>
            <title>The Base16, Base32, and Base64 Data Encodings</title>
            <author fullname="S. Josefsson" initials="S." surname="Josefsson">
              <organization/>
            </author>
            <date month="October" year="2006"/>
            <abstract>
              <t>This document describes the commonly used base 64, base 32, and base 16 encoding schemes.  It also discusses the use of line-feeds in encoded data, use of padding in encoded data, use of non-alphabet characters in encoded data, use of different encoding alphabets, and canonical encodings.  [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="4648"/>
          <seriesInfo name="DOI" value="10.17487/RFC4648"/>
        </reference>
      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="SI2020" target="https://research.protocol.ai/publications/automating-quic-interoperability-testing/seemann2020.pdf">
          <front>
            <title>Automating QUIC Interoperability Testing</title>
            <author initials="M." surname="Seemann">
              <organization/>
            </author>
            <author initials="J." surname="Iyengar">
              <organization/>
            </author>
            <date year="2020" month="August" day="10"/>
          </front>
        </reference>
        <reference anchor="Janus" target="https://github.com/divviup/janus">
          <front>
            <title>Experimental implementation of the DAP-PPM specification</title>
            <author>
              <organization/>
            </author>
            <date year="2022" month="July" day="26"/>
          </front>
        </reference>
        <reference anchor="Daphne" target="https://github.com/cloudflare/daphne">
          <front>
            <title>Implementation of DAP</title>
            <author>
              <organization/>
            </author>
            <date year="2022" month="July" day="27"/>
          </front>
        </reference>
        <reference anchor="divviup-ts" target="https://github.com/divviup/divviup-ts">
          <front>
            <title>TypeScript client for https://divviup.org</title>
            <author>
              <organization/>
            </author>
            <date year="2022" month="July" day="27"/>
          </front>
        </reference>
        <reference anchor="VDAF-POC" target="https://github.com/cfrg/draft-irtf-cfrg-vdaf/tree/main/poc">
          <front>
            <title>VDAF reference implementations</title>
            <author>
              <organization/>
            </author>
            <date year="2022" month="July" day="11"/>
          </front>
        </reference>
      </references>
    </references>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>Thanks to Brandon Pitman and Christopher Patton for feedback and contributions.</t>
    </section>
  </back>
  <!-- ##markdown-source:
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
gHkxXJ5j/ahPH8QdnqxdpxRE520lZgL3mLp3e8T5CEidxB4JjbtZ7dsumnxS
22lcukkGqW+6EdNbIGbsuENHpQXelJHFtdy4EPvHqgHZxRg1bknl3WVSOkAu
Xu5TvkPL5hpBfyeFSlPaLXGVC1VihsjF6S5NlJ4hUWPghdW9CgeJLQ/1jOBU
xkLV2ZSrxFvBa6jwhSSZYlhKSdC8AJK4Dt7jIkhbvWYhgmAtUoWZ8RDDmVWO
XEPLkRtCad77obJhdFTbVFGBAHBYzhxk4TUNOBXPgk2P+yRkhNmZsfB2KL7c
blSfIHthy/ofcu74fEsVXjhgNMPSSYe3LYgRbh2+5zF2/RwR+CUdl/kZLAhD
g84rd9zgqmOw3NtHS2sf3sJRSQMukkGzm9IDTiq1TXIlPXH9Ol4hzsp+ocV/
sHSsLXPQhlbfVL9VlwCT+1WgWkWjQUBKGDgOCWNgeNC2REUiN4ZiC67foRYR
gp/Ot+jx5Ypt0yXrRHC0snTcX3GD+XjI920YgdQSsENUS1/UpXoP1yA/2h9u
e7vWm7z5bMiRoJtbYLEBHRhNHYEm3fr/YArid/U8rFKlCrLpSmob4bvH4yCA
xjECYYKEk20mtZlEdwAeZmEszL6i/ctQK/8cORUr1mMaeWYhA6MSJpDF3WP/
jORjeL8D+1Vxgw9Xq4fM/TYZyycP/YumOcgzoCym/MyG4wbulbWvOl5AdFPy
UmTnBqi8tLQ7fKXYZyDNfns4UmW4lJf2mlBmQAVLTxX/IVYNsAPrP3LORXfU
HwZUKgYvOQqkCITIjdtoQxQPlC06LgmJPdj72HWl+/uhtSbd0Psll/drelCq
K2/AgFiy/TJzXC5X6eprk0ab41h67tabOReWr7+UdbZ8rOcKky20yJBbcQgW
wBGe1KtmlWRX+Lyjuq9PenzzTOpLZGB2qMryrLqkWc/1j++bUZe9GXkex2IO
EqJZZjgcb6TUvhTgJ1Z5Z8oHHiw/ZtqQRtK0cZFhVtpMIrBfh7SVqQnXQrMG
ReiYqbe13FCXGrCSR9WVOiF4Z6HHGzTf9hZEK2bcIA5CZkT2jdu+5hx0Q7He
9NO9XyrmYSe2He+8N8YRu0Tva4l+ZxyGogIPDoV1Bd8mo/K9/2M58kmQ4Icj
hCjsWwUICZ69Lz7A/TXOeepb6FMvEPsnVQ9/RYf5/zr+SUH/ECCJXSC6XfJe
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
AAA=

-->

</rfc>
