---

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.
requirementReference:
- 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

* <div id="AP-ec50">AP-ec50: clarify how to verify response body is an "ActivityStreams object representation"</div>
* 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/
