test(12.1-01): add failing four-provider contract suite and fixtures
- Create test_cloud_provider_contract.py with parametrized suite for Nextcloud, WebDAV, Google Drive, OneDrive - Assert canonical (connection_id, user_id, parent_ref=None, page_token=None) signature, CloudListing return type, trusted caller identity propagation, metadata normalization, pagination completeness, and forbidden-operation spies - Add synthetic credential-free fixtures: nextcloud_root.xml, webdav_root.xml, google_drive_pages.json, onedrive_pages.json - 9 tests fail for nextcloud (expected RED state — incompatible list_folder override) - All webdav, google_drive, onedrive contract tests pass
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"_comment": "Synthetic Google Drive fixture — no real credentials, tokens, or user data.",
|
||||
|
||||
"root_page1": {
|
||||
"nextPageToken": "page2token_synthetic",
|
||||
"files": [
|
||||
{
|
||||
"id": "synth_folder_a1b2c3",
|
||||
"name": "Projects",
|
||||
"mimeType": "application/vnd.google-apps.folder",
|
||||
"modifiedTime": "2024-06-10T12:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "synth_folder_d4e5f6",
|
||||
"name": "Archive",
|
||||
"mimeType": "application/vnd.google-apps.folder",
|
||||
"modifiedTime": "2024-06-11T08:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "synth_file_g7h8i9",
|
||||
"name": "report.pdf",
|
||||
"mimeType": "application/pdf",
|
||||
"size": "204800",
|
||||
"modifiedTime": "2024-06-12T14:00:00Z",
|
||||
"md5Checksum": "abc123synth"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"root_page2": {
|
||||
"files": [
|
||||
{
|
||||
"id": "synth_file_j0k1l2",
|
||||
"name": "notes.txt",
|
||||
"mimeType": "text/plain",
|
||||
"size": "1024",
|
||||
"modifiedTime": "2024-06-13T10:00:00Z",
|
||||
"md5Checksum": "def456synth"
|
||||
},
|
||||
{
|
||||
"id": "synth_native_m3n4o5",
|
||||
"name": "Meeting Notes",
|
||||
"mimeType": "application/vnd.google-apps.document",
|
||||
"modifiedTime": "2024-06-14T09:30:00Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"nested_folder": {
|
||||
"files": [
|
||||
{
|
||||
"id": "synth_nested_p6q7r8",
|
||||
"name": "sub-document.docx",
|
||||
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"size": "51200",
|
||||
"modifiedTime": "2024-06-15T11:00:00Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"trashed_excluded": {
|
||||
"files": [
|
||||
{
|
||||
"id": "synth_file_s9t0u1",
|
||||
"name": "visible.pdf",
|
||||
"mimeType": "application/pdf",
|
||||
"size": "10240",
|
||||
"modifiedTime": "2024-06-16T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"_note": "trashed=false query param ensures trashed items are not returned"
|
||||
},
|
||||
|
||||
"native_docs_nullable_size": {
|
||||
"files": [
|
||||
{
|
||||
"id": "synth_doc_v2w3x4",
|
||||
"name": "Spreadsheet",
|
||||
"mimeType": "application/vnd.google-apps.spreadsheet",
|
||||
"modifiedTime": "2024-06-17T13:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "synth_slides_y5z6a7",
|
||||
"name": "Presentation",
|
||||
"mimeType": "application/vnd.google-apps.presentation",
|
||||
"modifiedTime": "2024-06-18T14:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Synthetic Nextcloud Depth-1 PROPFIND fixture — no real credentials, hostnames, tokens, or user data.
|
||||
Root path: /remote.php/dav/files/testuser/
|
||||
Represents: 4 folders + 6 files directly in root.
|
||||
Covers: root self-entry filtering, absolute hrefs, encoded spaces/unicode, missing optional props.
|
||||
-->
|
||||
<d:multistatus xmlns:d="DAV:" xmlns:nc="http://nextcloud.org/ns" xmlns:oc="http://owncloud.org/ns">
|
||||
|
||||
<!-- Root self-entry — MUST be filtered out by the parser -->
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/files/testuser/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype><d:collection/></d:resourcetype>
|
||||
<d:displayname>testuser</d:displayname>
|
||||
<d:getlastmodified>Mon, 01 Jan 2024 00:00:00 GMT</d:getlastmodified>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- Folder: Documents -->
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/files/testuser/Documents/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype><d:collection/></d:resourcetype>
|
||||
<d:displayname>Documents</d:displayname>
|
||||
<d:getlastmodified>Mon, 10 Jun 2024 12:00:00 GMT</d:getlastmodified>
|
||||
<oc:size>0</oc:size>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- Folder: Photos -->
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/files/testuser/Photos/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype><d:collection/></d:resourcetype>
|
||||
<d:displayname>Photos</d:displayname>
|
||||
<d:getlastmodified>Tue, 11 Jun 2024 08:30:00 GMT</d:getlastmodified>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- Folder: My Work Files (contains spaces — encoded in href) -->
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/files/testuser/My%20Work%20Files/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype><d:collection/></d:resourcetype>
|
||||
<d:displayname>My Work Files</d:displayname>
|
||||
<d:getlastmodified>Wed, 12 Jun 2024 09:00:00 GMT</d:getlastmodified>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- Folder: Unicode name: Café Designs -->
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/files/testuser/Caf%C3%A9%20Designs/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype><d:collection/></d:resourcetype>
|
||||
<d:displayname>Café Designs</d:displayname>
|
||||
<d:getlastmodified>Thu, 13 Jun 2024 10:15:00 GMT</d:getlastmodified>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- File: report.pdf — all optional props present -->
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/files/testuser/report.pdf</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype/>
|
||||
<d:displayname>report.pdf</d:displayname>
|
||||
<d:getcontentlength>204800</d:getcontentlength>
|
||||
<d:getcontenttype>application/pdf</d:getcontenttype>
|
||||
<d:getlastmodified>Fri, 14 Jun 2024 14:00:00 GMT</d:getlastmodified>
|
||||
<d:getetag>"abc123etag"</d:getetag>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- File: notes.txt — missing content-type and etag -->
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/files/testuser/notes.txt</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype/>
|
||||
<d:displayname>notes.txt</d:displayname>
|
||||
<d:getcontentlength>1024</d:getcontentlength>
|
||||
<d:getlastmodified>Sat, 15 Jun 2024 10:00:00 GMT</d:getlastmodified>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- File: My Report Draft.docx — spaces in name -->
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/files/testuser/My%20Report%20Draft.docx</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype/>
|
||||
<d:displayname>My Report Draft.docx</d:displayname>
|
||||
<d:getcontentlength>51200</d:getcontentlength>
|
||||
<d:getcontenttype>application/vnd.openxmlformats-officedocument.wordprocessingml.document</d:getcontenttype>
|
||||
<d:getlastmodified>Sun, 16 Jun 2024 11:00:00 GMT</d:getlastmodified>
|
||||
<d:getetag>"docx456etag"</d:getetag>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- File: image.png — size absent (should be None) -->
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/files/testuser/image.png</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype/>
|
||||
<d:displayname>image.png</d:displayname>
|
||||
<d:getcontenttype>image/png</d:getcontenttype>
|
||||
<d:getlastmodified>Mon, 17 Jun 2024 12:30:00 GMT</d:getlastmodified>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- File: data.csv — all optional props absent (missing getcontenttype, getetag, size) -->
|
||||
<d:response>
|
||||
<d:href>/remote.php/dav/files/testuser/data.csv</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype/>
|
||||
<d:displayname>data.csv</d:displayname>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- File: archive.zip — relative href (no leading slash) -->
|
||||
<d:response>
|
||||
<d:href>remote.php/dav/files/testuser/archive.zip</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype/>
|
||||
<d:displayname>archive.zip</d:displayname>
|
||||
<d:getcontentlength>102400</d:getcontentlength>
|
||||
<d:getcontenttype>application/zip</d:getcontenttype>
|
||||
<d:getlastmodified>Tue, 18 Jun 2024 09:00:00 GMT</d:getlastmodified>
|
||||
<d:getetag>"zip789etag"</d:getetag>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
</d:multistatus>
|
||||
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"_comment": "Synthetic OneDrive fixture — no real credentials, tokens, drive IDs, or user data.",
|
||||
|
||||
"root_page1": {
|
||||
"value": [
|
||||
{
|
||||
"id": "synth_od_folder_a1b2",
|
||||
"name": "Projects",
|
||||
"folder": {"childCount": 3},
|
||||
"parentReference": {"driveId": "synth-drive-id", "id": "root"},
|
||||
"lastModifiedDateTime": "2024-06-10T12:00:00Z",
|
||||
"eTag": "etag_synth_folder_a1b2"
|
||||
},
|
||||
{
|
||||
"id": "synth_od_folder_c3d4",
|
||||
"name": "My Archive",
|
||||
"folder": {"childCount": 5},
|
||||
"parentReference": {"driveId": "synth-drive-id", "id": "root"},
|
||||
"lastModifiedDateTime": "2024-06-11T08:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "synth_od_file_e5f6",
|
||||
"name": "report.pdf",
|
||||
"file": {"mimeType": "application/pdf"},
|
||||
"size": 204800,
|
||||
"parentReference": {"driveId": "synth-drive-id", "id": "root"},
|
||||
"lastModifiedDateTime": "2024-06-12T14:00:00Z",
|
||||
"eTag": "etag_synth_file_e5f6"
|
||||
}
|
||||
],
|
||||
"@odata.nextLink": "https://graph.microsoft.com/v1.0/me/drive/root/children?$skip=3&$top=3"
|
||||
},
|
||||
|
||||
"root_page2": {
|
||||
"value": [
|
||||
{
|
||||
"id": "synth_od_file_g7h8",
|
||||
"name": "My Report Draft.docx",
|
||||
"file": {"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
|
||||
"size": 51200,
|
||||
"parentReference": {"driveId": "synth-drive-id", "id": "root"},
|
||||
"lastModifiedDateTime": "2024-06-13T10:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "synth_od_file_i9j0",
|
||||
"name": "notes.txt",
|
||||
"file": {"mimeType": "text/plain"},
|
||||
"size": 1024,
|
||||
"parentReference": {"driveId": "synth-drive-id", "id": "root"},
|
||||
"lastModifiedDateTime": "2024-06-14T09:00:00Z",
|
||||
"eTag": "etag_synth_file_i9j0"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"nested_children": {
|
||||
"value": [
|
||||
{
|
||||
"id": "synth_od_file_k1l2",
|
||||
"name": "sub-document.docx",
|
||||
"file": {"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
|
||||
"size": 25600,
|
||||
"parentReference": {"driveId": "synth-drive-id", "id": "synth_od_folder_a1b2"},
|
||||
"lastModifiedDateTime": "2024-06-15T11:00:00Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"nullable_metadata": {
|
||||
"value": [
|
||||
{
|
||||
"id": "synth_od_file_m3n4",
|
||||
"name": "unknown-file.bin",
|
||||
"file": {},
|
||||
"parentReference": {"driveId": "synth-drive-id", "id": "root"},
|
||||
"lastModifiedDateTime": "2024-06-16T10:00:00Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"encoded_names": {
|
||||
"value": [
|
||||
{
|
||||
"id": "synth_od_file_o5p6",
|
||||
"name": "Annual Report & Summary.pdf",
|
||||
"file": {"mimeType": "application/pdf"},
|
||||
"size": 102400,
|
||||
"parentReference": {"driveId": "synth-drive-id", "id": "root"},
|
||||
"lastModifiedDateTime": "2024-06-17T13:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Synthetic generic WebDAV Depth-1 PROPFIND fixture — no real credentials, hostnames, tokens.
|
||||
Root path: /dav/
|
||||
Represents: 2 folders + 3 files directly in root.
|
||||
Covers: absolute/relative hrefs, missing optional props, foreign href rejection.
|
||||
-->
|
||||
<d:multistatus xmlns:d="DAV:">
|
||||
|
||||
<!-- Root self-entry — MUST be filtered out -->
|
||||
<d:response>
|
||||
<d:href>/dav/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype><d:collection/></d:resourcetype>
|
||||
<d:displayname>root</d:displayname>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- Folder: Archive -->
|
||||
<d:response>
|
||||
<d:href>/dav/Archive/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype><d:collection/></d:resourcetype>
|
||||
<d:displayname>Archive</d:displayname>
|
||||
<d:getlastmodified>Mon, 10 Jun 2024 08:00:00 GMT</d:getlastmodified>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- Folder: Shared (relative href) -->
|
||||
<d:response>
|
||||
<d:href>dav/Shared/</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype><d:collection/></d:resourcetype>
|
||||
<d:displayname>Shared</d:displayname>
|
||||
<d:getlastmodified>Tue, 11 Jun 2024 09:00:00 GMT</d:getlastmodified>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- File: readme.txt — all optional props -->
|
||||
<d:response>
|
||||
<d:href>/dav/readme.txt</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype/>
|
||||
<d:displayname>readme.txt</d:displayname>
|
||||
<d:getcontentlength>512</d:getcontentlength>
|
||||
<d:getcontenttype>text/plain</d:getcontenttype>
|
||||
<d:getlastmodified>Wed, 12 Jun 2024 10:00:00 GMT</d:getlastmodified>
|
||||
<d:getetag>"readmeetag"</d:getetag>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- File: backup.tar.gz — missing optional props -->
|
||||
<d:response>
|
||||
<d:href>/dav/backup.tar.gz</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype/>
|
||||
<d:displayname>backup.tar.gz</d:displayname>
|
||||
<d:getcontentlength>10240</d:getcontentlength>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- File: project.pdf — encoded spaces in href -->
|
||||
<d:response>
|
||||
<d:href>/dav/project%20notes.pdf</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype/>
|
||||
<d:displayname>project notes.pdf</d:displayname>
|
||||
<d:getcontentlength>204800</d:getcontentlength>
|
||||
<d:getcontenttype>application/pdf</d:getcontenttype>
|
||||
<d:getlastmodified>Thu, 13 Jun 2024 11:00:00 GMT</d:getlastmodified>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
<!-- Foreign href — escapes configured root; MUST cause listing to be incomplete -->
|
||||
<d:response>
|
||||
<d:href>/other-root/escape.txt</d:href>
|
||||
<d:propstat>
|
||||
<d:prop>
|
||||
<d:resourcetype/>
|
||||
<d:displayname>escape.txt</d:displayname>
|
||||
<d:getcontentlength>100</d:getcontentlength>
|
||||
</d:prop>
|
||||
<d:status>HTTP/1.1 200 OK</d:status>
|
||||
</d:propstat>
|
||||
</d:response>
|
||||
|
||||
</d:multistatus>
|
||||
Reference in New Issue
Block a user