From 525359f7c523e906dbd6213cdec4c8ece15a4720 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Fri, 17 Nov 2023 05:43:40 +0100 Subject: [PATCH] Add api tests for image endpoints (#4150) * Add api tests for image endpoints (fixes #4105) * curl instead of wget * add missing files * revert cargo update * simplify setup * use const * rename to image.spec.ts * adjust to client changes * update client lib * remove todos, move import * try to fix ci --------- Co-authored-by: SleeplessOne1917 --- .gitignore | 2 + Cargo.lock | 16 ++++---- api_tests/package.json | 8 ++-- api_tests/prepare-drone-federation-test.sh | 11 ++++++ api_tests/run-federation-test.sh | 2 + api_tests/src/comment.spec.ts | 16 ++++---- api_tests/src/community.spec.ts | 12 +++--- api_tests/src/follow.spec.ts | 8 ++-- api_tests/src/image.spec.ts | 44 +++++++++++++++++++++ api_tests/src/post.spec.ts | 36 +++++++++-------- api_tests/src/private_message.spec.ts | 4 +- api_tests/src/shared.ts | 12 +++--- api_tests/src/user.spec.ts | 4 +- api_tests/test.png | Bin 0 -> 28211 bytes api_tests/yarn.lock | 13 ++++-- 15 files changed, 126 insertions(+), 62 deletions(-) create mode 100644 api_tests/src/image.spec.ts create mode 100644 api_tests/test.png diff --git a/.gitignore b/.gitignore index 186713e1f..6883b4eca 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ query_testing/**/reports/*.json api_tests/node_modules api_tests/.yalc api_tests/yalc.lock +api_tests/test.png +api_tests/pict-rs # pictrs data pictrs/ diff --git a/Cargo.lock b/Cargo.lock index bfbedd64c..66b91dbac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1997,9 +1997,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "js-sys", @@ -3306,9 +3306,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -3338,9 +3338,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" dependencies = [ "cc", "libc", @@ -5356,9 +5356,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", diff --git a/api_tests/package.json b/api_tests/package.json index 17ac9f7be..653d57e32 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -9,22 +9,24 @@ "scripts": { "lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check 'src/**/*.ts'", "fix": "prettier --write src && eslint --fix src", - "api-test": "jest -i follow.spec.ts && jest -i post.spec.ts && jest -i comment.spec.ts && jest -i private_message.spec.ts && jest -i user.spec.ts && jest -i community.spec.ts", + "api-test": "jest -i follow.spec.ts && jest -i post.spec.ts && jest -i comment.spec.ts && jest -i private_message.spec.ts && jest -i user.spec.ts && jest -i community.spec.ts && jest -i image.spec.ts", "api-test-comment": "jest -i comment.spec.ts", "api-test-post": "jest -i post.spec.ts", "api-test-user": "jest -i user.spec.ts", "api-test-community": "jest -i community.spec.ts", - "api-test-private-message": "jest -i private_message.spec.ts" + "api-test-private-message": "jest -i private_message.spec.ts", + "api-test-image": "jest -i image.spec.ts" }, "devDependencies": { "@types/jest": "^29.5.8", "@types/node": "^20.9.0", "@typescript-eslint/eslint-plugin": "^6.10.0", "@typescript-eslint/parser": "^6.10.0", + "download-file-sync": "^1.0.4", "eslint": "^8.53.0", "eslint-plugin-prettier": "^5.0.1", "jest": "^29.5.0", - "lemmy-js-client": "0.19.0-rc.12", + "lemmy-js-client": "0.19.0-alpha.18", "prettier": "^3.0.0", "ts-jest": "^29.1.0", "typescript": "^5.0.4" diff --git a/api_tests/prepare-drone-federation-test.sh b/api_tests/prepare-drone-federation-test.sh index 4044ba0dd..0b623f6d2 100755 --- a/api_tests/prepare-drone-federation-test.sh +++ b/api_tests/prepare-drone-federation-test.sh @@ -8,6 +8,17 @@ export RUST_LOG="warn,lemmy_server=debug,lemmy_federate=debug,lemmy_api=debug,le export LEMMY_TEST_FAST_FEDERATION=1 # by default, the persistent federation queue has delays in the scale of 30s-5min +# pictrs setup +if ! [ -f "pict-rs" ]; then + curl "https://git.asonix.dog/asonix/pict-rs/releases/download/v0.5.0-beta.2/pict-rs-linux-amd64" -o api_tests/pict-rs + chmod +x api_tests/pict-rs +fi +./api_tests/pict-rs \ + run -a 0.0.0.0:8080 \ + --danger-dummy-mode \ + filesystem -p /tmp/pictrs/files \ + sled -p /tmp/pictrs/sled-repo 2>&1 & + for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do echo "DB URL: ${LEMMY_DATABASE_URL} INSTANCE: $INSTANCE" psql "${LEMMY_DATABASE_URL}/lemmy" -c "DROP DATABASE IF EXISTS $INSTANCE" diff --git a/api_tests/run-federation-test.sh b/api_tests/run-federation-test.sh index 3042fd344..609cd473e 100755 --- a/api_tests/run-federation-test.sh +++ b/api_tests/run-federation-test.sh @@ -14,6 +14,8 @@ yarn yarn api-test || true killall -s1 lemmy_server || true +killall -s1 pict-rs || true for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do psql "$LEMMY_DATABASE_URL" -c "DROP DATABASE $INSTANCE" done +rm -r /tmp/pictrs diff --git a/api_tests/src/comment.spec.ts b/api_tests/src/comment.spec.ts index 951641d78..7ab8db335 100644 --- a/api_tests/src/comment.spec.ts +++ b/api_tests/src/comment.spec.ts @@ -54,8 +54,8 @@ beforeAll(async () => { } }); -afterAll(async () => { - await unfollows(); +afterAll(() => { + unfollows(); }); function assertCommentFederation( @@ -94,7 +94,9 @@ test("Create a comment", async () => { }); test("Create a comment in a non-existent post", async () => { - await expect(createComment(alpha, -1)).rejects.toBe("couldnt_find_post"); + await expect(createComment(alpha, -1)).rejects.toStrictEqual( + Error("couldnt_find_post"), + ); }); test("Update a comment", async () => { @@ -143,7 +145,7 @@ test("Delete a comment", async () => { await waitUntil( () => resolveComment(gamma, commentRes.comment_view.comment).catch(e => e), - r => r !== "couldnt_find_object", + r => r.message !== "couldnt_find_object", ) ).comment; if (!gammaComment) { @@ -160,13 +162,13 @@ test("Delete a comment", async () => { // Make sure that comment is undefined on beta await waitUntil( () => resolveComment(beta, commentRes.comment_view.comment).catch(e => e), - e => e === "couldnt_find_object", + e => e.message == "couldnt_find_object", ); // Make sure that comment is undefined on gamma after delete await waitUntil( () => resolveComment(gamma, commentRes.comment_view.comment).catch(e => e), - e => e === "couldnt_find_object", + e => e.message === "couldnt_find_object", ); // Test undeleting the comment @@ -181,7 +183,7 @@ test("Delete a comment", async () => { let betaComment2 = ( await waitUntil( () => resolveComment(beta, commentRes.comment_view.comment).catch(e => e), - e => e !== "couldnt_find_object", + e => e.message !== "couldnt_find_object", ) ).comment; expect(betaComment2?.comment.deleted).toBe(false); diff --git a/api_tests/src/community.spec.ts b/api_tests/src/community.spec.ts index 2f3a410f6..a16802e08 100644 --- a/api_tests/src/community.spec.ts +++ b/api_tests/src/community.spec.ts @@ -34,9 +34,7 @@ import { } from "./shared"; import { EditSite, LemmyHttp } from "lemmy-js-client"; -beforeAll(async () => { - await setupLogins(); -}); +beforeAll(setupLogins); function assertCommunityFederation( communityOne?: CommunityView, @@ -66,8 +64,8 @@ test("Create community", async () => { // A dupe check let prevName = communityRes.community_view.community.name; - await expect(createCommunity(alpha, prevName)).rejects.toBe( - "community_already_exists", + await expect(createCommunity(alpha, prevName)).rejects.toStrictEqual( + Error("community_already_exists"), ); // Cache the community on beta, make sure it has the other fields @@ -333,8 +331,8 @@ test("Get community for different casing on domain", async () => { // A dupe check let prevName = communityRes.community_view.community.name; - await expect(createCommunity(alpha, prevName)).rejects.toBe( - "community_already_exists", + await expect(createCommunity(alpha, prevName)).rejects.toStrictEqual( + Error("community_already_exists"), ); // Cache the community on beta, make sure it has the other fields diff --git a/api_tests/src/follow.spec.ts b/api_tests/src/follow.spec.ts index a0b43989b..89d078848 100644 --- a/api_tests/src/follow.spec.ts +++ b/api_tests/src/follow.spec.ts @@ -10,12 +10,10 @@ import { waitUntil, } from "./shared"; -beforeAll(async () => { - await setupLogins(); -}); +beforeAll(setupLogins); -afterAll(async () => { - await unfollowRemotes(alpha); +afterAll(() => { + unfollowRemotes(alpha); }); test("Follow federated community", async () => { diff --git a/api_tests/src/image.spec.ts b/api_tests/src/image.spec.ts new file mode 100644 index 000000000..73d020872 --- /dev/null +++ b/api_tests/src/image.spec.ts @@ -0,0 +1,44 @@ +jest.setTimeout(120000); + +import { UploadImage, DeleteImage } from "lemmy-js-client"; +import { alpha, setupLogins, unfollowRemotes } from "./shared"; +import fs = require("fs"); +const downloadFileSync = require("download-file-sync"); + +beforeAll(setupLogins); + +afterAll(() => { + unfollowRemotes(alpha); +}); + +test("Upload image and delete it", async () => { + // upload test image + const upload_image = fs.readFileSync("test.png"); + const upload_form: UploadImage = { + image: upload_image, + }; + const upload = await alpha.uploadImage(upload_form); + console.log(upload); + expect(upload.files![0].file).toBeDefined(); + expect(upload.files![0].delete_token).toBeDefined(); + expect(upload.url).toBeDefined(); + expect(upload.delete_url).toBeDefined(); + + // ensure that image download is working. theres probably a better way to do this + const content = downloadFileSync(upload.url); + expect(content.length).toBeGreaterThan(0); + + // delete image + const delete_form: DeleteImage = { + token: upload.files![0].delete_token, + filename: upload.files![0].file, + }; + const delete_ = await alpha.deleteImage(delete_form); + expect(delete_).toBe(true); + + // ensure that image is deleted + const content2 = downloadFileSync(upload.url); + expect(content2).toBe(""); +}); + +// TODO: add tests for image purging diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts index 1d6e90c72..d79a536cb 100644 --- a/api_tests/src/post.spec.ts +++ b/api_tests/src/post.spec.ts @@ -50,8 +50,8 @@ beforeAll(async () => { await unfollows(); }); -afterAll(async () => { - await unfollows(); +afterAll(() => { + unfollows(); }); function assertPostFederation(postOne?: PostView, postTwo?: PostView) { @@ -96,18 +96,20 @@ test("Create a post", async () => { assertPostFederation(betaPost, postRes.post_view); // Delta only follows beta, so it should not see an alpha ap_id - await expect(resolvePost(delta, postRes.post_view.post)).rejects.toBe( - "couldnt_find_object", - ); + await expect( + resolvePost(delta, postRes.post_view.post), + ).rejects.toStrictEqual(Error("couldnt_find_object")); // Epsilon has alpha blocked, it should not see the alpha post - await expect(resolvePost(epsilon, postRes.post_view.post)).rejects.toBe( - "couldnt_find_object", - ); + await expect( + resolvePost(epsilon, postRes.post_view.post), + ).rejects.toStrictEqual(Error("couldnt_find_object")); }); test("Create a post in a non-existent community", async () => { - await expect(createPost(alpha, -2)).rejects.toBe("couldnt_find_community"); + await expect(createPost(alpha, -2)).rejects.toStrictEqual( + Error("couldnt_find_community"), + ); }); test("Unlike a post", async () => { @@ -157,8 +159,8 @@ test("Update a post", async () => { assertPostFederation(betaPost, updatedPost.post_view); // Make sure lemmy beta cannot update the post - await expect(editPost(beta, betaPost.post)).rejects.toBe( - "no_post_edit_allowed", + await expect(editPost(beta, betaPost.post)).rejects.toStrictEqual( + Error("no_post_edit_allowed"), ); }); @@ -226,7 +228,9 @@ test("Lock a post", async () => { ); // Try to make a new comment there, on alpha - await expect(createComment(alpha, alphaPost1.post.id)).rejects.toBe("locked"); + await expect(createComment(alpha, alphaPost1.post.id)).rejects.toStrictEqual( + Error("locked"), + ); // Unlock a post let unlockedPost = await lockPost(beta, false, betaPost1.post); @@ -281,8 +285,8 @@ test("Delete a post", async () => { assertPostFederation(betaPost2, undeletedPost.post_view); // Make sure lemmy beta cannot delete the post - await expect(deletePost(beta, true, betaPost2.post)).rejects.toBe( - "no_post_edit_allowed", + await expect(deletePost(beta, true, betaPost2.post)).rejects.toStrictEqual( + Error("no_post_edit_allowed"), ); }); @@ -483,12 +487,12 @@ test.skip("Enforce community ban for federated user", async () => { // ensure that the post by alpha got removed await expect(getPost(alpha, searchBeta1.posts[0].post.id)).rejects.toBe( - "unknown", + Error("unknown"), ); // Alpha tries to make post on beta, but it fails because of ban await expect(createPost(alpha, betaCommunity.community.id)).rejects.toBe( - "banned_from_community", + Error("banned_from_community"), ); // Unban alpha diff --git a/api_tests/src/private_message.spec.ts b/api_tests/src/private_message.spec.ts index 081bb8d8d..08c519df7 100644 --- a/api_tests/src/private_message.spec.ts +++ b/api_tests/src/private_message.spec.ts @@ -20,8 +20,8 @@ beforeAll(async () => { recipient_id = 3; }); -afterAll(async () => { - await unfollowRemotes(alpha); +afterAll(() => { + unfollowRemotes(alpha); }); test("Create a private message", async () => { diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index 8d1a4744c..5a6a82ed2 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -10,6 +10,7 @@ import { InstanceId, LemmyHttp, PostView, + SuccessResponse, } from "lemmy-js-client"; import { CreatePost } from "lemmy-js-client/dist/types/CreatePost"; import { DeletePost } from "lemmy-js-client/dist/types/DeletePost"; @@ -58,7 +59,6 @@ import { Register } from "lemmy-js-client/dist/types/Register"; import { SaveUserSettings } from "lemmy-js-client/dist/types/SaveUserSettings"; import { DeleteAccount } from "lemmy-js-client/dist/types/DeleteAccount"; import { GetSiteResponse } from "lemmy-js-client/dist/types/GetSiteResponse"; -import { DeleteAccountResponse } from "lemmy-js-client/dist/types/DeleteAccountResponse"; import { PrivateMessagesResponse } from "lemmy-js-client/dist/types/PrivateMessagesResponse"; import { GetPrivateMessages } from "lemmy-js-client/dist/types/GetPrivateMessages"; import { PostReportResponse } from "lemmy-js-client/dist/types/PostReportResponse"; @@ -637,7 +637,7 @@ export async function loginUser( export async function saveUserSettingsBio( api: LemmyHttp, -): Promise { +): Promise { let form: SaveUserSettings = { show_nsfw: true, blur_nsfw: false, @@ -655,7 +655,7 @@ export async function saveUserSettingsBio( export async function saveUserSettingsFederated( api: LemmyHttp, -): Promise { +): Promise { let avatar = "https://image.flaticon.com/icons/png/512/35/35896.png"; let banner = "https://image.flaticon.com/icons/png/512/36/35896.png"; let bio = "a changed bio"; @@ -679,7 +679,7 @@ export async function saveUserSettingsFederated( export async function saveUserSettings( api: LemmyHttp, form: SaveUserSettings, -): Promise { +): Promise { return api.saveUserSettings(form); } export async function getPersonDetails( @@ -692,9 +692,7 @@ export async function getPersonDetails( return api.getPersonDetails(form); } -export async function deleteUser( - api: LemmyHttp, -): Promise { +export async function deleteUser(api: LemmyHttp): Promise { let form: DeleteAccount = { delete_content: true, password, diff --git a/api_tests/src/user.spec.ts b/api_tests/src/user.spec.ts index 70fad1a66..d71827f89 100644 --- a/api_tests/src/user.spec.ts +++ b/api_tests/src/user.spec.ts @@ -22,9 +22,7 @@ import { import { LemmyHttp, SaveUserSettings } from "lemmy-js-client"; import { GetPosts } from "lemmy-js-client/dist/types/GetPosts"; -beforeAll(async () => { - await setupLogins(); -}); +beforeAll(setupLogins); let apShortname: string; diff --git a/api_tests/test.png b/api_tests/test.png new file mode 100644 index 0000000000000000000000000000000000000000..b01d868e9e417e3a232ee9708cced7165d77f9a6 GIT binary patch literal 28211 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 P$^c68YI5Z=rXl|YDI|on literal 0 HcmV?d00001 diff --git a/api_tests/yarn.lock b/api_tests/yarn.lock index d00a78380..9a272efee 100644 --- a/api_tests/yarn.lock +++ b/api_tests/yarn.lock @@ -1270,6 +1270,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +download-file-sync@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/download-file-sync/-/download-file-sync-1.0.4.tgz#d3e3c543f836f41039455b9034c72e355b036019" + integrity sha512-vH92qNH508jZZA12HQNq/aiMDfagr4JvjFiI17Bi8oYjsxwv5ZVIi7iHkYmUXxOQUr90tcVX+8EPePjAqG1Y0w== + electron-to-chromium@^1.4.535: version "1.4.537" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.537.tgz#aac4101db53066be1e49baedd000a26bc754adc9" @@ -2281,10 +2286,10 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -lemmy-js-client@0.19.0-rc.12: - version "0.19.0-rc.12" - resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.19.0-rc.12.tgz#e3bd4e21b1966d583ab790ef70ece8394b012b48" - integrity sha512-1iu2fW9vlb3TrI+QR/ODP3+5pWZB0rUqL1wH09IzomDXohCqoQvfmXpwArmgF4Eq8GZgjkcfeMDC2gMrfw/i7Q== +lemmy-js-client@0.19.0-alpha.18: + version "0.19.0-alpha.18" + resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.19.0-alpha.18.tgz#f94841681cabdf9d5c4ce7048eacb57557f68724" + integrity sha512-cKJfKKnjK+ijk0Yd6ydtne3Y4FILp2RbQg05pCru9n6PCyPAa85eQL4QxPB1PPed20ckSZRcHLcnr/bYFDgpaw== dependencies: cross-fetch "^3.1.5" form-data "^4.0.0"