outbox must be an OrderedCollection

Description

This rule checks whether the outbox property of an object appears to be an OrderedCollection

Table of Contents

Identifiers

Use these identifiers to refer to this Test.

URI

urn:uuid:4af549f4-3797-4d99-a151-67c3d8feaa46

slug

This slug is memorable, but it is not guaranteed to be globally unique like a URI.

outbox-must-be-an-orderedcollection

Input

This describes the input that each test run will use to select test targets.

input.object

the object whose `outbox` property will be tested

required
true
range
https://www.w3.org/ns/activitystreams#Actor

input.object as json
{
  "help": "the object whose `outbox` property will be tested",
  "required": true,
  "rangeIncludes": [
    "https://www.w3.org/ns/activitystreams#Actor"
  ]
}

input.time

amount of time allowed to run test, as IETF RFC3339 dur-time time duration. This is meant to configure the limit for how long this test will wait for network requests.

required
true
type
rfc3339:dur-time, TimeLimit
constraints
[
  {
    "content": " MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)",
    "mediaType": "test/markdown"
  }
]

input.time as json
{
  "help": "amount of time allowed to run test, as IETF RFC3339 dur-time time duration. This is meant to configure the limit for how long this test will wait for network requests.",
  "required": true,
  "default": "T5S",
  "type": [
    "rfc3339:dur-time",
    "TimeLimit"
  ],
  "constraints": [
    {
      "content": " MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)",
      "mediaType": "test/markdown"
    }
  ]
}

Input as JSON
{
  "object": {
    "help": "the object whose `outbox` property will be tested",
    "required": true,
    "rangeIncludes": [
      "https://www.w3.org/ns/activitystreams#Actor"
    ]
  },
  "time": {
    "help": "amount of time allowed to run test, as IETF RFC3339 dur-time time duration. This is meant to configure the limit for how long this test will wait for network requests.",
    "required": true,
    "default": "T5S",
    "type": [
      "rfc3339:dur-time",
      "TimeLimit"
    ],
    "constraints": [
      {
        "content": " MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)",
        "mediaType": "test/markdown"
      }
    ]
  }
}

Requirement Mapping

This Test has been derived from these specified requirements.

  • urn:uuid:003a3be2-fb58-4812-a3a3-795067254327

    content
    The outbox MUST be an OrderedCollection.
    origin
    {
      "source": "https://www.w3.org/TR/activitypub/",
      "section": {
        "id": "https://www.w3.org/TR/activitypub/#outbox",
        "branch": [
          5,
          1
        ]
      },
      "selector": {
        "type": "TextQuoteSelector",
        "exact": "The outbox MUST be an OrderedCollection.\n",
        "prefix": "The outbox is discovered through the outbox property of an actor's profile. \n",
        "suffix": "The outbox stream contains activities the user has published, subject to the ability of the requestor to retrieve the activity\n"
      }
    }
    JSON
    {
      "id": "urn:uuid:003a3be2-fb58-4812-a3a3-795067254327",
      "type": "Behavior",
      "uuid": "003a3be2-fb58-4812-a3a3-795067254327",
      "content": "The outbox MUST be an OrderedCollection.",
      "tag": [
        {
          "name": "ActivityPubServer",
          "id": "https://socialweb.coop/tag/ActivityPubServer"
        }
      ],
      "origin": {
        "source": "https://www.w3.org/TR/activitypub/",
        "section": {
          "id": "https://www.w3.org/TR/activitypub/#outbox",
          "branch": [
            5,
            1
          ]
        },
        "selector": {
          "type": "TextQuoteSelector",
          "exact": "The outbox MUST be an OrderedCollection.\n",
          "prefix": "The outbox is discovered through the outbox property of an actor's profile. \n",
          "suffix": "The outbox stream contains activities the user has published, subject to the ability of the requestor to retrieve the activity\n"
        }
      },
      "@context": [
        "https://www.w3.org/ns/activitystreams",
        "https://socialweb.coop/ns/testing/context.json"
      ]
    }

Part of

This test is part of the following Test Suites:

JSON

Test Case as JSON
{
  "description": "This rule checks whether the outbox property of an object appears to be an OrderedCollection",
  "failedCases": [
    {
      "name": "test case when the value of the outbox property is null",
      "input": {
        "object": {
          "outbox": null
        }
      },
      "result": {
        "outcome": "failed"
      }
    },
    {
      "name": "test case when outbox is an object without type OrderedCollection",
      "input": {
        "object": "{\"outbox\":{\"type\":[\"Person\"]}}"
      },
      "result": {
        "outcome": "failed"
      }
    },
    {
      "name": "inputs.object has outbox url to a non-collection",
      "input": {
        "object": "{\"outbox\":\"https://bengo.is/actor.json\"}"
      },
      "result": {
        "outcome": "failed"
      }
    }
  ],
  "inapplicableCases": [
    {
      "name": "test case when the outbox property is missing",
      "input": {
        "object": "{}"
      },
      "result": {
        "outcome": "inapplicable"
      }
    },
    {
      "name": "test case where the value of inputs.object is not JSON",
      "input": {
        "object": "\u0000x123abc_intentionallyNotJson"
      },
      "result": {
        "outcome": "inapplicable"
      }
    },
    {
      "name": "test case where the value of of the outbox property is an array of length 2",
      "input": {
        "object": "{\"outbox\":[\"https://example.com\",\"https://example.com\"]}"
      },
      "result": {
        "outcome": "inapplicable"
      }
    },
    {
      "name": "test case where outbox property value is a URL that 404s when fetched",
      "input": {
        "authorization": "foo",
        "object": "{\"outbox\":\"https://bengo.is/404\"}"
      },
      "result": {
        "outcome": "inapplicable"
      }
    },
    {
      "name": "object is null",
      "input": {
        "object": "null"
      },
      "result": {
        "outcome": "inapplicable"
      }
    }
  ],
  "input": {
    "object": {
      "help": "the object whose `outbox` property will be tested",
      "required": true,
      "rangeIncludes": [
        "https://www.w3.org/ns/activitystreams#Actor"
      ]
    },
    "time": {
      "help": "amount of time allowed to run test, as IETF RFC3339 dur-time time duration. This is meant to configure the limit for how long this test will wait for network requests.",
      "required": true,
      "default": "T5S",
      "type": [
        "rfc3339:dur-time",
        "TimeLimit"
      ],
      "constraints": [
        {
          "content": " MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)",
          "mediaType": "test/markdown"
        }
      ]
    }
  },
  "markdown": "---\ntype:\n- TestCase\nstatus: draft\nname: outbox must be an OrderedCollection\ndescription: |\n  This rule checks whether the outbox property of an object appears to be an OrderedCollection\nuuid: 4af549f4-3797-4d99-a151-67c3d8feaa46\nattributedTo:\n- https://bengo.is\n\"@context\":\n- TestCase:\n    \"@id\": http://www.w3.org/ns/earl#:TestCase\n\nrespec:\n  config:\n    editors:\n    - name: bengo\n      url: \"https://bengo.is\"\n      w3cid: 49026\n---\n\n# outbox must be an OrderedCollection\n\n## Background\n\n[ActivityPub](https://www.w3.org/TR/activitypub/) [ยง 5.1 Outbox](https://www.w3.org/TR/activitypub/#outbox):\n> The outbox is discovered through the outbox property of an actor's profile. The outbox MUST be an OrderedCollection.\n\n## About this Test\n\nThis is a Test Case describing a rule to determine whether an ActivityPub object has an outbox property that meets this requirement to 'be an OrderedCollection', meeting requirement [3b925cdf-89fe-4f51-b41f-26df23f58e0c](https://socialweb.coop/activitypub/behaviors/3b925cdf-89fe-4f51-b41f-26df23f58e0c)\n\n### Identifier\n\nThe identifier of this test is `urn:uuid:4af549f4-3797-4d99-a151-67c3d8feaa46\n`.\n\n## Test Subject\n\nThe subject of this test is any data claiming to conform to the specification of an ActivityPub Actor Object.\n\nThis test is *not* inherently applicable to an ActivityPub Server. An ActivityPub Server serves 0 or more Actor Objects. An ActivityPub Server for a big community might serve hundreds of ActivityPub Actor Objects. An ActivityPub Server for a single human may serve only that person's ActivityPub Actor Object.\n\nThis test is *not* inherently applicable to a URL of an Actor Object. The URL is not the same as the Actor Object. The URL may resolve to different Actor Objects in different contexts.\n\n## Inputs\n\nThis test requires the following [inputs](https://www.w3.org/TR/act-rules-format/#input):\n\n1. `object` - the object whose `outbox` property will be tested\n    * type: binary\n    * constraints\n        * will be interpreted as JSON\n\n2. `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.\n    * required: yes\n    * example: `T0.0021S`\n    * type: binary\n    * constraints\n        * MUST be an [RFC3339 `dur-time`](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A)\n\n## Applicability\n\nThis test applies to outbox objects linked to from the `object` input. Usually an actor will have one outbox, but there may be multiple.\n\nThis test does not apply to objects with more than one outbox . If the input `object` has an outbox property whose value is an array of length >= 2, outcome is `inapplicable`.\n(See issue #5102 below to track expanding the applicability)\n\nIf `object` is not parseable as JSON to a JSON object, outcome is `inapplicable`.\n\nIf `object` is a JSON object, but it does not contain a property named `outbox`, outcome is `inapplicable`. The rationale is that there is already a test `acaacb5f-8f7e-4f28-8d81-c7955070a767` that can be used to determine if input `object` has an outbox property at all.\n\n### Test Targets\n\n* `outbox` - the value of the `outbox` property in the input `object` object\n    * since the `object` object must be JSON for this test's applicability, the value of `JSON.parse(actor).outbox` must also be JSON\n    * how to derive `outbox` from inputs\n        1. let `outboxValue` be\n            * if `inputs.actor.outbox` is a JSON string, `outboxValue` is that string\n            * if `inputs.actor.outbox` is a JSON object, `outboxValue` is that object\n            * if `inputs.actor.outbox` is an Array of length 1, `outboxValue` is the item in that array\n            * if `inputs.actor.outbox` is an Array of length greater than 1, the test outcome is `inapplicable` (covered in 'Applicability' above)\n              * see issue #5102 below to track expanding the applicability to support outbox property values that are arrays with length greater than 1\n        2. let `outboxObject` be\n            * if `outboxValue` is a JSON object, `outboxObject` is that object\n            * if `outboxValue` is a JSON string, `outboxObject` is the result of interpreting that string as an ActivityPub Object Identifier and fetching the corresponding ActivityPub Object (e.g. `GET https://...`).\n        3. test target `outbox` is `outboxObject`\n\n## Expectations\n\n1. `outbox` is a JSON object\n2. `outbox` has a property named `type``\n3. the values of the outbox's `type` property must contain `\"OrderedCollection\"`, as determined by\n    * if value of `outbox`'s `type` property is a string, it MUST be `\"OrderedCollection\"`\n    * if value of `outbox`'s `type` property is an Array, it MUST contain an entry identical to `\"OrderedCollection\"`\n\n## Assumptions\n\n### Interpreting \"MUST be an OrderedCollection\"\n\nRevisiting the background from above,\n[ActivityPub](https://www.w3.org/TR/activitypub/) [says](https://www.w3.org/TR/activitypub/#outbox)\n> The outbox is discovered through the outbox property of an actor's profile. The outbox MUST be an OrderedCollection.\n\n\"MUST be an OrderedCollection\" is open to some interpretation here.\n\nThis test chose to interpret 'be an' to include 'indicate its type as'. The rationale is that it's easy to check and easy to implement.\n\n## Test Cases\n\n### object has simple valid outbox\n\ninputs\n\n* `object`\n\n    ```json\n    {\n      \"outbox\": {\n        \"id\": \"http://example.org/blog/\",\n        \"type\": \"OrderedCollection\",\n        \"name\": \"Martin's Blog\"\n      }\n    }\n    ```\n\n    * note: this OrderedCollection is from [Example 5 in activitystreams-core](https://www.w3.org/TR/activitystreams-core/#ex2-jsonld)\n\ntest targets\n\n* `outbox`\n    * value:\n\n        ```json\n        {\n          \"id\": \"http://example.org/blog/\",\n          \"type\": \"OrderedCollection\",\n          \"name\": \"Martin's Blog\"\n        }\n        ```\n\n    * outcome: `passed`\n\n### object outbox is null\n\ninputs\n\n* `object`\n\n    ```json\n    {\n      \"outbox\": null\n    }\n    ```\n\ntest targets\n\n* `outbox`\n    * value:\n\n      ```json\n      null\n      ```\n\n    * outcome: `failed`\n        * rationale: outbox is obviously not an OrderedCollection\n\n### object outbox type array contains Person\n\ninputs\n\n* `object`\n\n    ```json\n    {\n      \"outbox\": {\n        \"type\": [\"Person\"]\n      }\n    }\n    ```\n\ntest targets\n\n* `outbox`\n    * value:\n\n      ```json\n      {\n        \"type\": [\"Person\"]\n      }\n      ```\n\n    * outcome: `failed`\n        * rationale: outbox type is not OrderedCollection\n\n### inapplicable because outbox has many values\n\ninputs\n\n* `object`\n\n  ```json\n  {\n    \"outbox\": [\"https://example.com\", \"https://example.com\"]\n  }\n  ```\n\ntest targest\n\n* `outbox`\n    * value:\n\n      ```json\n      [\"https://example.com\", \"https://example.com\"]\n      ```\n\n    * outcome: `inapplicable`\n        * rationale: outbox values that are arrays of length greater than 1 are not covered by this test's applicability. See issue #5102 below to track expanding the applicability\n\nresult\n\n* outcome: `inapplicable`\n\n### object is empty object\n\ninputs\n\n* `object`\n\n    ```json\n    {}\n    ```\n\nresult\n\n* outcome: `inapplicable`\n\n### object is not JSON\n\ninputs\n\n* `object`\n\n    ```text\n    \\0x123abc_intentionallyNotJson\n    ```\n\nresult\n\n* outcome: `inapplicable`\n\n## Glossary\n\n### `outcome`\n\nAn outcome is a conclusion that comes from evaluating a test on a test subject. An outcome can be one of the three following types:\n\n* `inapplicable`: No part of the test subject matches the applicability\n* `passed`: A test target meets all expectations\n* `failed`: A test target does not meet all expectations\n\n## Requirements Mapping\n\n* [ActivityPub Requirement 003a3be2-fb58-4812-a3a3-795067254327](https://socialweb.coop/activitypub/behaviors/003a3be2-fb58-4812-a3a3-795067254327) - The outbox MUST be an OrderedCollection\n    * Required for Conformance to [ActivityPub][activitypub]\n    * Outcome Mapping\n        * when test target `outbox` has outcome `passed`, requirement is satisfied\n        * when test target `outbox` has outcome `failed`, requirement is not satisfied\n        * when test target `outbox` has outcome `inapplicable`, further testing is needed to determine requirement satisfaction\n\n## Change Log\n\n* 2023-11-22T05:12:58.454Z - first draft, heavily copy from ../inbox-must-be-an-orderedcollection/inbox-must-be-an-orderedcollection.md\n* 2023-12-29T22:46:03.806Z - reformat test cases to give each one its own heading\n\n## Issues\n\nRequired\n\n* add a test case where outbox is a URI that is resolved to an OrderedCollection an the outcome is \"passed\"\n    * decide what the URL will be. Does it need to publicly resolve for a long time? maybe <https://socialweb.coop/actors/empty-outbox.json>\n        * if that's not feasible, the test case could have the `outbox` test target stubbed out so at least that part could be checked\n\nNice to Have\n\n* #01d2: resolving outbox url should use inputs.time and timeout\n* #5102: expand applicability to handle cases where there are multiple outboxes\n\n[activitypub]: https://www.w3.org/TR/activitypub/\n",
  "name": "outbox must be an OrderedCollection",
  "passedCases": [
    {
      "name": "test case when outbox is an OrderedCollection",
      "input": {
        "object": "{\"outbox\":{\"id\":\"http://example.org/blog/\",\"type\":\"OrderedCollection\",\"name\":\"Martin's Blog\"}}"
      },
      "result": {
        "outcome": "passed"
      }
    }
  ],
  "slug": "outbox-must-be-an-orderedcollection",
  "uuid": "4af549f4-3797-4d99-a151-67c3d8feaa46",
  "isPartOf": [
    "https://socialweb.coop/activitypub/test-cases/"
  ],
  "requirementReference": [
    {
      "id": "urn:uuid:003a3be2-fb58-4812-a3a3-795067254327",
      "url": "https://socialweb.coop/activitypub/behaviors/003a3be2-fb58-4812-a3a3-795067254327"
    }
  ]
}