type:
  - TestCase
description: This rule checks that URLs of ActivityPub objects can be resolved
  to a representation with well-known media type for further processing.
failedCases:
  - name: nginx 404 response body
    inputs:
      id: https://bengo.is/404
      time: T1M
    result:
      outcome: failed
    targets:
      response:
        httpVersion: "2.0"
        statusCodeValue: "404"
        headers:
          - - content-type
            - text/html; charset=UTF-8
          - - content-length
            - "153"
        body: "

          \      <html>

          \      <head><title>404 Not Found</title></head>

          \      <body>

          \      <center><h1>404 Not Found</h1></center>

          \      <hr><center>nginx/1.25.2</center>

          \      </body>

          \      </html>   \ 

          \      "
inapplicableCases:
  - name: non-URI input id
    inputs:
      id: bafybeib5mvfjatmpswc3jnh7ydz4zxe25cm63xp6aafpg3j2awakf63qma
      time: T1M
    result:
      outcome: inapplicable
  - name: non-RFC3339-duration input time
    inputs:
      id: https://bengo.is/actor.json
      time: 5 minutes
    result:
      outcome: inapplicable
inputs:
  id:
    help: identifier of an ActivityPub Object hosted at an ActivityPub Server
    type: xsd:anyUri
    rangeIncludes:
      - https://www.w3.org/ns/activitystreams#Actor
    required: true
  authorization:
    help: proof of authorization to retrieve the object identified by input `id`
  time:
    help: amount of time allowed to run test. This is meant to configure the limit
      for how long this test will wait for network requests. MUST be an [RFC3339
      `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)
    required: true
    type:
      - rfc3339:dur-time
      - TimeLimit
markdown: >
  ---


  uuid: e7ee491d-88d7-4e67-80c8-f74781bb247c

  type:

  - TestCase

  - ConformanceTestingRule

  ruleType: atomic

  name: |
    ActivityPub server serves an object in response to GET request for AS2 media type
  description: |
    This rule checks that URLs of ActivityPub objects can be resolved to a representation with well-known media type for further processing.
  testsRequirement:

  - id: urn:uuid:00330762-59a2-4072-8d93-87ee4c30411c
    url: https://socialweb.coop/activitypub/behaviors/08549639-2888-4ee2-a320-97fc7ee32e00/
  inputs:

  - name: URL of AS2 Object served by an ActivityPub Server
    type: URL

  # https://www.w3.org/QA/WG/2005/01/test-faq#review

  # *submitted, accepted, reviewed*, *returned for revision*, or *rejected*

  testCaseState: submitted


  eleventyComputed:
    title: "{{ name }}"

  respec:
    config:
      editors:
      - name: bengo
        url: "https://bengo.is"
        w3cid: 49026
  ---


  # ActivityPub Servers Must Serve Objects in Response to an HTTP GET Request Accepting ActivityStreams 2.0 Media Type


  ## Background


  [ActivityPub][activitypub] [§3.2 Retrieving Objects](https://www.w3.org/TR/activitypub/#retrieving-objects):

  > Servers... MUST present the ActivityStreams object representation in response to `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`


  ## About This Test


  This is a Test Case describing a rule to determine whether an ActivityPub Object is in partial conformance with the following behaviors required by [ActivityPub][activitypub].


  * [requirement 08549639-2888-4ee2-a320-97fc7ee32e00](https://socialweb.coop/activitypub/behaviors/08549639-2888-4ee2-a320-97fc7ee32e00/) - ActivityPub server must present object in response to GET request with AS2 Accept Header


  ### Identifier


  The identifier of this test is `urn:uuid:e7ee491d-88d7-4e67-80c8-f74781bb247c`.


  ## Test Subject


  The subject of this test is an ActivityPub Server.


  ActivityPub Servers host ActivityPub Objects and are responsible for serving them to clients that request a representation of them.


  The Test Subject can be identified by a URI for an ActivityPub Object. The ActivityPub Object can be requested via HTTP, and the ActivityPub Server is the system that is expected to respond to the HTTP request.


  ## Inputs


  This test requires the following [inputs](https://www.w3.org/TR/act-rules-format/#input):


  1. `id` - identifier of an ActivityPub Object hosted at an ActivityPub Server

      * required: yes
      * type: binary
          * constraints
              * MUST be a URI, i.e. an [ActivityPub Object Identifier](https://www.w3.org/TR/activitypub/#obj-id) that is not `null`

  2. `authorization` - proof of authorization to retrieve the object identified by input `id`

      * required: no
          * if this input is omitted, no `Authorization` will be provided in the HTTP request send by this test
      * type: binary
          * constraints
              * If present, this should be valid as the value of an HTTP `Authorization` header

  3. `time` - amount of time allowed to run test. This is meant to configure the limit for how long this test will wait for network requests.

      * required: yes
      * example: `T0.0021S`
      * type: binary
          * constraints
              * MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)

  ## Applicability


  This test applies to a server hosting the ActivityPub Object identified by input `id`.


  If input `id` is not a URI, outcome is `inapplicable`.


  If input `id` URI scheme is not `https` or `http`, outcome is `inapplicable`. (This test may be revised later to handle other URI schemes).


  If input `time` is not parseable as an RFC3339 `dur-time`, outcome is `inapplicable`.


  ### Test Targets


  * `response` - the HTTP response that is the result of retrieving the ActivityPub Object identified by input `id`.
      * how to derive `response` from inputs
      1. start a timer with duration from input `time`. If the timer reaches zero before this derivation is complete, the whole test outcome is `inapplicable` because we weren't able to determine the `response` test target within the required time.
      2. let `request` be a new HTTP Request whose URI is input `id`
      3. add an http request header to `request` whose name is `Accept` and whose value is `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`
      4. if input `authorization` was provided, add an http request header to `request` whose name is `Authorization` and whose value is input `authorization`
      5. send the HTTP request and await a response
      6. assign the HTTP response to the `response` test target

  ## Expectations


  * `response` body is parseable as JSON

  * `response` body parsed JSON is a JSON Object

  * `response` body must be an "ActivityStreams object representation"
      * see issue [AP-ec50](#AP-ec50) below

  ## Assumptions


  ## Implementation Considerations


  Though the spec only *requires* serving the object in response to this `Accept` header value, servers seeking to interop widely may also want to serve the same object in response to Accept header values like:


  * `application/ld+json` (but without the `profile=` parameter)

  * `application/activity+json`

  * `application/json`


  ## Test Cases


  These are test cases for this test itself.


  ### simple passed case


  outcome: `passed`


  inputs


  * `id`: `https://bengo.is/actor.json`

  * `time`: `T1M`


  test targets


  * `response`:

      ```http
      HTTP/2 200 
      content-type: application/json
      content-length: 484

      {
        "@context": [
          "https://www.w3.org/ns/activitystreams",
          "https://w3id.org/security/v1"
        ],
        "id": "https://bengo.is/",
        "type": "Person",
        "preferredUsername": "bengo",
        "name": "bengo",
        "url": "https://bengo.is/",
        "inbox": "https://mastodon.social/users/bengo/inbox",
        "attachments": [
          {
            "type": "PropertyValue",
            "name": "Website",
            "value": "https://bengo.is"
          }
        ],
        "outbox": "https://bengo.is/activitypub/actors/bengo/outbox.json"
      }
      ```

      * outcome: `passed`

  ### nginx 404 response body


  outcome: `failed`


  * rationale: test target `response` does not meet expectation of containing an ActivityPub Object representation in the response body


  inputs


  * `id`: `https://bengo.is/404`

  * `time`: `T1M`


  test targets


  * `response`:

    ```http
    HTTP/2 404 
    content-type: text/html; charset=UTF-8
    content-length: 153
    
    <html>
    <head><title>404 Not Found</title></head>
    <body>
    <center><h1>404 Not Found</h1></center>
    <hr><center>nginx/1.25.2</center>
    </body>
    </html>
    ```

      * outcome: `failed`

  ### non-URI input `id`


  outcome: `inapplicable`


  * rationale: input `id` is not a URI


  inputs


  * `id`: `bafybeib5mvfjatmpswc3jnh7ydz4zxe25cm63xp6aafpg3j2awakf63qma`

  * `time`: `T1M`


  test targets


  * `response` - undefined
      * irrelevant because `id` does not meet syntax requirements

  ### non-RFC3339-duration input `time`


  outcome: `inapplicable`


  * rationale: input `time` does not meet syntax requirements


  inputs


  * `id`: `https://bengo.is/actor.json`

  * `time`: `5 minutes`


  test targets


  * `response` - undefined
      * irrelevant because `time` input is malformed regardless of resolved `resposne`

  ## Glossary


  ### `outcome`


  An outcome is a conclusion that comes from evaluating a test on a test subject. An outcome can be one of the three following types:


  * `inapplicable`: No part of the test subject matches the applicability

  * `passed`: A test target meets all expectations

  * `failed`: A test target does not meet all expectations


  ## Requirements Mapping


  * [ActivityPub requirement 08549639-2888-4ee2-a320-97fc7ee32e00](https://socialweb.coop/activitypub/behaviors/08549639-2888-4ee2-a320-97fc7ee32e00/) - ActivityPub server must present object in response to GET request with AS2 Accept Header
      * Required for Conformance to [ActivityPub][activitypub]
      * Outcome Mapping
          * when test target `response` has outcome `passed`, requirement is satisfied
          * when test target `response` has outcome `failed`, requirement is not satisfied
          * when test target `response` has outcome `inapplicable`, further testing is needed to determine requirement satisfaction

  ## Change Log


  * (~) 2023-10-15T00:00:00Z - sketch as first test case

  * 2023-11-07T21:07:59.214Z - update to be internally consistent and a good first draft

  * 2023-12-29T21:08:32.432Z - clean up test case formatting


  ## Issues List


  * AP-ec50: clarify how to verify response body is an "ActivityStreams object representation" <a name="AP-ec50"></a>

  * When rendered to HTML and [published here](https://socialweb.coop/activitypub/test-cases/actor-must-serve-as2-object-to-get/#simple-passed-case), the `response` test targets HTTP response syntax highlighting separates the HTTP headers from the response body. This is a quirk of the rendering process.


  [activitypub]: https://www.w3.org/TR/activitypub/
name: ActivityPub Servers Must Serve Objects in Response to an HTTP GET Request
  Accepting ActivityStreams 2.0 Media Type
passedCases:
  - name: simple passed case
    inputs:
      id: https://bengo.is/actor.json
      time: T1M
    result:
      outcome: passed
    targets:
      response:
        httpVersion: "2"
        statusCodeValue: "200"
        headers:
          - - content-type
            - application/json
          - - content-length
            - "404"
        body: "

          \      {

          \        \"@context\": [

          \          \"https://www.w3.org/ns/activitystreams\",

          \          \"https://w3id.org/security/v1\"

          \        ],

          \        \"id\": \"https://bengo.is/\",

          \        \"type\": \"Person\",

          \        \"preferredUsername\": \"bengo\",

          \        \"name\": \"bengo\",

          \        \"url\": \"https://bengo.is/\",

          \        \"inbox\":
          \"https://mastodon.social/users/bengo/inbox\",

          \        \"attachments\": [

          \          {

          \            \"type\": \"PropertyValue\",

          \            \"name\": \"Website\",

          \            \"value\": \"https://bengo.is\"

          \          }

          \        ],

          \        \"outbox\":
          \"https://bengo.is/activitypub/actors/bengo/outbox.json\"

          \      }

          \      "
slug: actor-must-serve-as2-object-to-get
uuid: e7ee491d-88d7-4e67-80c8-f74781bb247c
isPartOf:
  - https://socialweb.coop/activitypub/test-cases/
