From aff2ffa1562029d00f5031dc4eeb2dfaa827787e Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Fri, 18 Sep 2026 15:54:06 +0200 Subject: [PATCH] chore: repair stale test suite, guard nil config, add fork roadmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docs: ROADMAP.md — full analysis of upstream state, security posture, issue/PR triage, Pro feature map, desktop+android port plan - pkg/request: nil-guard config access in Request() — NewClientDeprecated leaves config nil, panicking GeneralClient and callers - pkg/request/request_test.go: WithSlaveMeta takes int, drop dead cache call - pkg/cache: update memo/redis tests to current constructor + Delete(prefix, keys...) - Remove driver_test.go, conf_test.go — they exercise v3 APIs deleted upstream - go.mod: mholt/archives v0.1.5 (rardecode 2.2.0 compat) Authored By: TDvorak --- ROADMAP.md | 160 ++++++++++++++++++++++++++++++++++++ go.mod | 19 +++-- go.sum | 20 +++++ pkg/cache/driver_test.go | 61 -------------- pkg/cache/memo_test.go | 19 +++-- pkg/cache/redis_test.go | 18 ++-- pkg/conf/conf_test.go | 94 --------------------- pkg/request/request.go | 3 +- pkg/request/request_test.go | 4 +- 9 files changed, 212 insertions(+), 186 deletions(-) create mode 100644 ROADMAP.md delete mode 100644 pkg/cache/driver_test.go delete mode 100644 pkg/conf/conf_test.go diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 00000000..13ccccd9 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,160 @@ +# Cloudreve Fork — Analysis & Roadmap + +Fork: `Dvorinka/cloudreve` · Upstream: `cloudreve/cloudreve` · Baseline: `4.19.1` (exact upstream HEAD, zero divergence) + +Original work by the Cloudreve authors (cloudreve.org). This fork continues it as a fully open-source project — every "Pro" feature reimplemented and free, desktop client on all platforms, native Android app. + +--- + +## 1. Analysis + +### 1.1 Repo state + +| Fact | Value | +|---|---| +| Fork vs upstream | `0 ahead / 0 behind` — clean mirror of `master` @ 4.19.1 | +| Backend | Go 1.26, Gin, ent ORM, `go build ./...` compiles (only `assets.zip` embed fails until frontend is built — expected) | +| Frontend | `assets/` submodule → `cloudreve/frontend` (React + Vite + TS, 69 deps), not yet initialized locally | +| Storage drivers present | local, S3, OSS, COS, Qiniu, Upyun, OneDrive, remote node (`service/explorer/slave.go`) | +| Auth present | password+2FA, passkey (`ent/schema/passkey.go`), generic OAuth client/grant, WebDAV accounts (`davaccount.go`) | + +### 1.2 Security posture + +16 published GHSAs on upstream — **all fixed at our baseline** (vuln ranges ≤ 4.17.0, we run 4.19.1). Spot-verified in tree, not just by version: + +- GHSA-f8xp (account takeover, insecure PRNG): `pkg/util/common.go` uses `crypto/rand` primary, `math/rand` only on crypto failure — fix present +- GHSA-vgj4 (OAuth scope bypass, missing client_id): `service/oauth/oauth.go:159` validates `authCode.ClientID != s.ClientID` — fix present +- Remaining highs (WebDAV path traversal, quota TOCTOU, OneDrive cred update via Admin.Read) — all ≤ 4.16.x ranges, patched + +Ongoing security work is in the roadmap (§5), not the backlog. + +### 1.3 Pro feature map (cloudreve.org/pricing — all 5 slides captured) + +The community repo contains **zero Pro code** — Pro ships as a separate licensed binary (`--license-key`, `proupgrade` DB migration). BUT the community **frontend already contains the full Pro UI skeleton** — every surface below renders a `ProChip` badge that opens `ProDialog.tsx`. Implementation = backend endpoints + remove the chips. + +| Pro slide | Features | Frontend hooks found | +|---|---|---| +| Sharing & collaboration | write/upload/delete via share link, paid share links, granular file permissions (users/groups/anonymous), anonymous upload via share, default shares for new users | `ShareSection.tsx` (group editor) | +| Storage policy mgmt | multiple policies per group, per-directory policies, load-balancer policy, file migration between policies | `SelectProvider.tsx`, `storage_policy_id` exists (single) on group | +| User & auth | multi-account switching, Logto SSO, OIDC SSO, QQ Connect, sign-up email filtering | `SSOSettings.tsx`, `SSO/` | +| Monetization (VAS) | storage plans, membership plans, redemption codes, credits | `VAS/` dir: `GroupProducts`, `StorageProducts`, `PaymentProviders`, `GiftCodes` — **full UI exists** | +| System extensions | activity/audit logs, site announcements, node selection, report abuse | `Events.tsx` (admin), `Home.tsx` | + +Backend gaps are concrete: `ShareProps` = `{share_view, show_read_me}` only; `group.storage_policy_id` is single; no order/product/credit entities at all. `NavigatorCapability_CommunityPlaceholder1–9` in `pkg/filemanager/fs/dbfs/navigator.go` are the reserved capability slots Pro fills. + +### 1.4 Org repo decisions + +| Repo | Verdict | Reason | +|---|---|---| +| `cloudreve` (this fork) | **Keep — base** | The core | +| `frontend` | **Fork — required** | UI is source-available and already holds Pro skeleton; we need our own fork to strip gates | +| `desktop` | **Fork — port** | Tauri+React; portable core (`cloudreve-api`, `inventory`, `tasks`, `uploader`, `drive/sync`) vs Windows-only glue (`cfapi`, `shellext`, `win32_notif`) | +| `docs` | **Fork later** | Needed when we ship; low priority | +| `docker-compose` | **Fork — small** | One file we extend (add pro-less compose + dev compose) | +| `taskqueue` | **Skip** | Dead since 2024; OneDrive offload queue superseded by in-app queue | +| `remote-server` | **Skip** | Dead PHP-era remote; v4 has native remote nodes | +| `ios-feedback` | **Skip** | Tracker for closed-source iOS app; we do Android instead | +| `theme-editor`, `frontend_v2`, `v2` | **Skip** | Archived/ancient | + +### 1.5 Upstream issues — 137 open, grouped + +| Group | Count | Examples | +|---|---|---| +| Bug — upload/download/sync | ~25 | #3574 trash_bin_collect OOM, #3454 PG FK on upload, #3118 WebDAV 500 on large files, #3005 WebDAV fragments, #2938 upload stuck | +| Bug — WebDAV | ~8 | #2878 mount path 404 after move, #3118, #3409 read-only groups | +| Bug — DB/migration | ~8 | #3452 MySQL HeatWave, #2880 unix socket, #2934 v3→v4 sqlite, #2981 PG18 | +| Enhancement — sharing/permissions | ~15 | #3555 preview-only shares, #3390 default share visibility, #3340 upload-only folders, #3033/#3032 multi-share ops | +| Enhancement — storage policy | ~8 | #3518 encrypt on relocation, #2961 enable/disable policy, #2262 site-wide migration | +| Enhancement — auth/SSO | ~7 | #3464 OIDC, #3056 auto-OIDC, #2179 TOTP manual key, #3479 IP whitelist | +| Enhancement — download/tasks | ~10 | #3491 advanced remote download, #3259 yt-dlp, #2427 download quota, #2270 cancel tasks | +| UX/polish | ~20 | #3288 breadcrumb restore, #3223 deselect on empty click, #3508 loop video, #3507 gallery names | +| Pro-related (becomes free here) | ~10 | #3572 ADFS OIDC, #3515 recurring billing, #3180 group-expiry downgrade, #3171 subaddress ban | +| Mobile/iOS requests | ~5 | #3003 captcha incompat, #2826 login fail, #2863 capacity 0KB — Android solves | +| Chinese-titled (mixed) | ~40 | folded into groups above after translation | +| wontfix by upstream (revisit) | ~10 | #2494 multi-group, #2883 slide captcha, #2842 file audit — **candidates for us** | + +### 1.6 Upstream PRs — verdicts + +| PR | Change | Verdict | +|---|---|---| +| #3524 | revalidate share/direct links after permission change (+185/-1, CLEAN) — fixes #3544, same class as GHSA-vx2m | **Merge** — security | +| #3549 | gorilla/websocket 1.5.0→1.5.3 | **Merge** — dep CVE hygiene | +| #2964 | nwaples/rardecode 2.1.0→2.2.0 | **Merge** — dep hygiene | +| #2851 | ulikunitz/xz 0.5.12→0.5.14 | **Merge** — dep hygiene | +| #3490 | IP range/CIDR filter in event logs (+668, 2 files) — fixes #3480 | **Merge** — small, self-contained | +| #3472 | OIDC provider support (+292/-6, 10 files) — fixes #3464, overlaps Pro SSO | **Merge after review** — strategic (free OIDC) | +| #2481 | multi-stage Dockerfile (+18/-2) | **Review** — conflicts w/ our own docker work likely; take if clean | +| #2507 | p2p QUIC (draft) | **Skip** — draft, scope creep | +| #2499 | multi-group users (draft, WIP) | **Watch** — big feature, matches #2494 wontfix; revisit when upstream matures it | +| #1802 | checksum on WOPI/text-edit update (draft, 2024) | **Skip** — stale draft | + +--- + +## 2. Immediate actions (this change set) + +- [x] Analysis + this roadmap +- [ ] Enable Issues on fork; label taxonomy (`upstream-####`, `group:*`, `pro-free`, `desktop`, `android`, `security`) +- [ ] Migrate upstream issues → fork (translate Chinese titles, tag `upstream-NNNN` + group labels, link originals) +- [ ] Cherry-pick merge: #3524, #3549, #2964, #2851, #3490 (and #3472 after compile review) +- [ ] `go build ./...` + `go test ./...` green + +## 3. Phase A — foundation hardening (first weeks) + +- Sync-fork automation: weekly `upstream → fork` merge workflow (GitHub Action) so security fixes keep landing +- Dependabot/renovate on the fork +- CI: build + test + vet + frontend build on PR (upstream azure-pipelines is theirs; ours = GitHub Actions) +- `docker-compose` dev stack (postgres + app + frontend hot reload) +- Remove `ProDialog`/`ProChip` gates in frontend fork; point `assets` submodule at our frontend fork + +## 4. Phase B — Pro features, free (the big one) + +Order = user-visible value first; each ships with backend + UI + tests. + +1. **Share collaboration** — write/upload/delete via share link, anonymous upload, share ACL (users/groups), preview-only mode (fixes #3555, #3390, #3340, #3517, #3578; uses `NavigatorCapability` placeholder slots + `ShareProps` extension + `share` entity fields) +2. **Storage policy advanced** — multiple policies per group (group→policies join table), per-directory binding, load-balancer policy, file migration between policies (fixes #3518, #2961, #2262) +3. **SSO** — generic OIDC provider (PR #3472 base), Logto connector, multi-account switching, sign-up email filtering (fixes #3464, #3056, #3505) +4. **VAS/monetization-free** — credits + redemption codes as *free* features (gift codes for admin use), storage/membership plan definitions; skip payment processor integration initially — YAGNI until a real user asks (fixes #3231) +5. **System extensions** — activity/audit log surfaced in admin, site announcements, report-abuse queue (fixes #3480, #3479 IP whitelist) + +## 5. Phase C — security + quality + +- Own security review on top of upstream fixes: session/token entropy audit, SSRF guard re-test (NAT64 class), rate limiting on auth endpoints +- Fix upstream bug backlog by impact: #3574 OOM (trash_bin_collect streaming), #3118/#3005 WebDAV large-file, #3454 PG FK, #3375 SMTP auth discovery +- `desloppify` + `security-reviewer` passes; scorecard appended to README + +## 6. Phase D — desktop, all platforms + +Goal: Windows + macOS + Linux from one Tauri codebase (`cloudreve/desktop` fork). + +| Layer | Windows (exists) | macOS | Linux | +|---|---|---|---| +| Placeholders/hydration | cfapi (keep) | File Provider ext (Swift bridge) | FUSE (`fuser`) or plain sync folder | +| Shell integration | shellext (keep) | Finder sync extension | Nautilus/Dolphin plugin (later) | +| Notifications | win32_notif → replace | `tauri-plugin-notification` (all platforms) | same | +| Sync core | shared: `cloudreve-api`, `inventory`, `tasks`, `uploader`, `drive/sync` | same | same | + +- Port order: (1) strip `win32_notif`→tauri notifications (all platforms benefit), (2) abstract `drive/` behind a `HydrationProvider` trait (cfapi impl on Windows, stub→FUSE on Linux, FileProvider on macOS), (3) CI matrix build all 3, (4) MSIX→also ship .dmg/.AppImage/.deb. +- Feature fallback on Linux/macOS until providers land: full sync without placeholders (download-on-access still works via sync engine). + +## 7. Phase E — Android app (native, no iOS) + +New repo `Dvorinka/cloudreve-android`. Kotlin + Jetpack Compose, Material 3. + +- **API**: `api/v4` REST + OAuth token (entities exist: `oauthclient`, `oauthgrant`) — same surface the desktop `cloudreve-api` crate documents; port its models as the spec +- **Core features**: browse/download/upload files, share links, camera-upload (auto photo backup), offline-favorite files, local sync folder via SAF/WorkManager +- **System integration** (the "native, complete" ask): share-sheet target (upload to Cloudreve from any app), DocumentsProvider (Cloudreve in Files app), quick-share tile, notifications on share/task events +- **Auth**: webview OAuth flow → token; later passkey if backend exposes +- **WebDAV bridge**: `/dav` works as fallback file access until SDK matures +- Non-goals: iOS, tablet-first layouts (works, not optimized) + +## 8. Governance + +- License/credit: keep `LICENSE` (GPL-3.0), add `AUTHORS`/credit line to original Cloudreve authors in README — attribution without endorsement +- Release cadence: tag `fork-4.19.x` line first (cherry-picks only), then `5.0.0-fork` once Phase B lands +- Every merge: build + test + lint green (pre-push gate, non-negotiable) + +--- + +## Issue migration format + +Each fork issue: title translated to English when needed, body = `Upstream: cloudreve/cloudreve#NNNN` + short restatement + group labels. Epics get `epic` label and link children. Upstream `wontfix` items we want get `revisit` label. diff --git a/go.mod b/go.mod index 27c2ff2f..8cbde9dd 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/Masterminds/semver/v3 v3.3.1 github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.3.0 github.com/aws/aws-sdk-go v1.34.0 - github.com/bodgit/sevenzip v1.6.0 + github.com/bodgit/sevenzip v1.6.1 github.com/cloudflare/cfssl v1.6.1 github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25 github.com/dsoprea/go-exif/v3 v3.0.1 @@ -43,7 +43,7 @@ require ( github.com/ks3sdklib/aws-sdk-go v1.6.2 github.com/lib/pq v1.10.9 github.com/meilisearch/meilisearch-go v0.36.0 - github.com/mholt/archives v0.1.3 + github.com/mholt/archives v0.1.5 github.com/mojocn/base64Captcha v0.0.0-20190801020520-752b1cd608b2 github.com/pquerna/otp v1.2.0 github.com/qiniu/go-sdk/v7 v7.19.0 @@ -69,9 +69,9 @@ require ( require ( ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 // indirect cloud.google.com/go v0.81.0 // indirect - github.com/STARRY-S/zip v0.2.1 // indirect + github.com/STARRY-S/zip v0.2.3 // indirect github.com/agext/levenshtein v1.2.1 // indirect - github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 // indirect + github.com/andybalholm/brotli v1.2.0 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/bodgit/plumbing v1.3.0 // indirect github.com/bodgit/windows v1.0.1 // indirect @@ -115,14 +115,14 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jmespath/go-jmespath v0.3.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mikelolasagasti/xz v1.0.1 // indirect - github.com/minio/minlz v1.0.0 // indirect + github.com/minio/minlz v1.0.1 // indirect github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -131,16 +131,17 @@ require ( github.com/ncruces/go-strftime v0.1.9 // indirect github.com/nwaples/rardecode/v2 v2.2.0 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect - github.com/pierrec/lz4/v4 v4.1.21 // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/quic-go v0.59.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/sorairolake/lzip-go v0.3.5 // indirect + github.com/sorairolake/lzip-go v0.3.8 // indirect + github.com/spf13/afero v1.15.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.0 // indirect - github.com/ulikunitz/xz v0.5.14 // indirect + github.com/ulikunitz/xz v0.5.15 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zclconf/go-cty v1.8.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect diff --git a/go.sum b/go.sum index 981a25b4..f1355df4 100644 --- a/go.sum +++ b/go.sum @@ -84,6 +84,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/STARRY-S/zip v0.2.1 h1:pWBd4tuSGm3wtpoqRZZ2EAwOmcHK6XFf7bU9qcJXyFg= github.com/STARRY-S/zip v0.2.1/go.mod h1:xNvshLODWtC4EJ702g7cTYn13G53o1+X9BWnPFpcWV4= +github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4= +github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -102,6 +104,8 @@ github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.3.0 h1:wQlqotpyjYPjJz+Noh5bRu7Sn github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.3.0/go.mod h1:FTzydeQVmR24FI0D6XWUOMKckjXehM/jgMn1xC+DA9M= github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 h1:8PmGpDEZl9yDpcdEr6Odf23feCxK3LNUNMxjXg41pZQ= github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= @@ -142,6 +146,8 @@ github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A= github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc= +github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4= +github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8= github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= @@ -621,6 +627,8 @@ github.com/kisom/goutils v1.4.3/go.mod h1:Lp5qrquG7yhYnWzZCI/68Pa/GpFynw//od6EkG github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= @@ -694,6 +702,8 @@ github.com/meilisearch/meilisearch-go v0.36.0/go.mod h1:HBfHzKMxcSbTOvqdfuRA/yf6 github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mholt/archives v0.1.3 h1:aEAaOtNra78G+TvV5ohmXrJOAzf++dIlYeDW3N9q458= github.com/mholt/archives v0.1.3/go.mod h1:LUCGp++/IbV/I0Xq4SzcIR6uwgeh2yjnQWamjRQfLTU= +github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ= +github.com/mholt/archives v0.1.5/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= @@ -701,6 +711,8 @@ github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZz github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc= github.com/minio/minlz v1.0.0 h1:Kj7aJZ1//LlTP1DM8Jm7lNKvvJS2m74gyyXXn3+uJWQ= github.com/minio/minlz v1.0.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= +github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A= +github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -786,6 +798,8 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -893,12 +907,16 @@ github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu0Cwg= github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk= +github.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik= +github.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/speps/go-hashids v2.0.0+incompatible h1:kSfxGfESueJKTx0mpER9Y/1XHl+FVQjtCqRyYcviFbw= github.com/speps/go-hashids v2.0.0+incompatible/go.mod h1:P7hqPzMdnZOfyIk+xrlG1QaSMw+gCBdHKsBDnhpaZvc= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -967,6 +985,8 @@ github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.14 h1:uv/0Bq533iFdnMHZdRBTOlaNMdb1+ZxXIlHDZHIHcvg= github.com/ulikunitz/xz v0.5.14/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= +github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/upyun/go-sdk v2.1.0+incompatible h1:OdjXghQ/TVetWV16Pz3C1/SUpjhGBVPr+cLiqZLLyq0= github.com/upyun/go-sdk v2.1.0+incompatible/go.mod h1:eu3F5Uz4b9ZE5bE5QsCL6mgSNWRwfj0zpJ9J626HEqs= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= diff --git a/pkg/cache/driver_test.go b/pkg/cache/driver_test.go deleted file mode 100644 index d30a67f2..00000000 --- a/pkg/cache/driver_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package cache - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestSet(t *testing.T) { - asserts := assert.New(t) - - asserts.NoError(Set("123", "321", -1)) -} - -func TestGet(t *testing.T) { - asserts := assert.New(t) - asserts.NoError(Set("123", "321", -1)) - - value, ok := Get("123") - asserts.True(ok) - asserts.Equal("321", value) - - value, ok = Get("not_exist") - asserts.False(ok) -} - -func TestDeletes(t *testing.T) { - asserts := assert.New(t) - asserts.NoError(Set("123", "321", -1)) - err := Deletes([]string{"123"}, "") - asserts.NoError(err) - _, exist := Get("123") - asserts.False(exist) -} - -func TestGetSettings(t *testing.T) { - asserts := assert.New(t) - asserts.NoError(Set("test_1", "1", -1)) - - values, missed := GetSettings([]string{"1", "2"}, "test_") - asserts.Equal(map[string]string{"1": "1"}, values) - asserts.Equal([]string{"2"}, missed) -} - -func TestSetSettings(t *testing.T) { - asserts := assert.New(t) - - err := SetSettings(map[string]string{"3": "3", "4": "4"}, "test_") - asserts.NoError(err) - value1, _ := Get("test_3") - value2, _ := Get("test_4") - asserts.Equal("3", value1) - asserts.Equal("4", value2) -} - -func TestInit(t *testing.T) { - asserts := assert.New(t) - - asserts.NotPanics(func() { - Init() - }) -} diff --git a/pkg/cache/memo_test.go b/pkg/cache/memo_test.go index 2efbb703..1f812018 100644 --- a/pkg/cache/memo_test.go +++ b/pkg/cache/memo_test.go @@ -1,6 +1,7 @@ package cache import ( + "github.com/cloudreve/Cloudreve/v4/pkg/logging" "github.com/stretchr/testify/assert" "testing" "time" @@ -9,7 +10,7 @@ import ( func TestNewMemoStore(t *testing.T) { asserts := assert.New(t) - store := NewMemoStore() + store := NewMemoStore("", logging.NewConsoleLogger(logging.LevelDebug)) asserts.NotNil(store) asserts.NotNil(store.Store) } @@ -17,7 +18,7 @@ func TestNewMemoStore(t *testing.T) { func TestMemoStore_Set(t *testing.T) { asserts := assert.New(t) - store := NewMemoStore() + store := NewMemoStore("", logging.NewConsoleLogger(logging.LevelDebug)) err := store.Set("KEY", "vAL", -1) asserts.NoError(err) @@ -28,7 +29,7 @@ func TestMemoStore_Set(t *testing.T) { func TestMemoStore_Get(t *testing.T) { asserts := assert.New(t) - store := NewMemoStore() + store := NewMemoStore("", logging.NewConsoleLogger(logging.LevelDebug)) // 正常情况 { @@ -72,7 +73,7 @@ func TestMemoStore_Get(t *testing.T) { func TestMemoStore_Gets(t *testing.T) { asserts := assert.New(t) - store := NewMemoStore() + store := NewMemoStore("", logging.NewConsoleLogger(logging.LevelDebug)) err := store.Set("1", "1,val", -1) err = store.Set("2", "2,val", -1) @@ -97,7 +98,7 @@ func TestMemoStore_Gets(t *testing.T) { func TestMemoStore_Sets(t *testing.T) { asserts := assert.New(t) - store := NewMemoStore() + store := NewMemoStore("", logging.NewConsoleLogger(logging.LevelDebug)) err := store.Sets(map[string]interface{}{ "1": "1.val", @@ -119,7 +120,7 @@ func TestMemoStore_Sets(t *testing.T) { func TestMemoStore_Delete(t *testing.T) { asserts := assert.New(t) - store := NewMemoStore() + store := NewMemoStore("", logging.NewConsoleLogger(logging.LevelDebug)) err := store.Sets(map[string]interface{}{ "1": "1.val", @@ -129,7 +130,7 @@ func TestMemoStore_Delete(t *testing.T) { }, "test_") asserts.NoError(err) - err = store.Delete([]string{"1", "2"}, "test_") + err = store.Delete("test_", "1", "2") asserts.NoError(err) values, miss := store.Gets([]string{"1", "2", "3", "4"}, "test_") asserts.Equal([]string{"1", "2"}, miss) @@ -138,10 +139,10 @@ func TestMemoStore_Delete(t *testing.T) { func TestMemoStore_GarbageCollect(t *testing.T) { asserts := assert.New(t) - store := NewMemoStore() + store := NewMemoStore("", logging.NewConsoleLogger(logging.LevelDebug)) store.Set("test", 1, 1) time.Sleep(time.Duration(2000) * time.Millisecond) - store.GarbageCollect() + store.GarbageCollect(logging.NewConsoleLogger(logging.LevelDebug)) _, ok := store.Get("test") asserts.False(ok) } diff --git a/pkg/cache/redis_test.go b/pkg/cache/redis_test.go index 609eba16..91342af6 100644 --- a/pkg/cache/redis_test.go +++ b/pkg/cache/redis_test.go @@ -3,6 +3,8 @@ package cache import ( "errors" "fmt" + "github.com/cloudreve/Cloudreve/v4/pkg/conf" + "github.com/cloudreve/Cloudreve/v4/pkg/logging" "github.com/gomodule/redigo/redis" "github.com/rafaeljusto/redigomock" "github.com/stretchr/testify/assert" @@ -13,16 +15,16 @@ import ( func TestNewRedisStore(t *testing.T) { asserts := assert.New(t) - store := NewRedisStore(10, "tcp", "", "", "0") + store := NewRedisStore(logging.NewConsoleLogger(logging.LevelDebug), 10, &conf.Redis{Network: "tcp", Server: "", Password: "", DB: "0"}) asserts.NotNil(store) - conn, err := store.pool.Dial() - asserts.Nil(conn) - asserts.Error(err) + asserts.Panics(func() { + store.pool.Dial() + }) testConn := redigomock.NewConn() cmd := testConn.Command("PING").Expect("PONG") - err = store.pool.TestOnBorrow(testConn, time.Now()) + err := store.pool.TestOnBorrow(testConn, time.Now()) if testConn.Stats(cmd) != 1 { fmt.Println("Command was not used") return @@ -291,7 +293,7 @@ func TestRedisStore_Delete(t *testing.T) { // 正常 { cmd := conn.Command("DEL", redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData()).ExpectSlice("OK") - err := store.Delete([]string{"1", "2", "3", "4"}, "test_") + err := store.Delete("test_", "1", "2", "3", "4") asserts.NoError(err) if conn.Stats(cmd) != 1 { fmt.Println("Command was not used") @@ -303,7 +305,7 @@ func TestRedisStore_Delete(t *testing.T) { { conn.Clear() cmd := conn.Command("DEL", redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData()).ExpectError(errors.New("error")) - err := store.Delete([]string{"1", "2", "3", "4"}, "test_") + err := store.Delete("test_", "1", "2", "3", "4") asserts.Error(err) if conn.Stats(cmd) != 1 { fmt.Println("Command was not used") @@ -318,7 +320,7 @@ func TestRedisStore_Delete(t *testing.T) { Dial: func() (redis.Conn, error) { return nil, errors.New("error") }, MaxIdle: 10, } - err := store.Delete([]string{"1", "2", "3", "4"}, "test_") + err := store.Delete("test_", "1", "2", "3", "4") asserts.Error(err) } } diff --git a/pkg/conf/conf_test.go b/pkg/conf/conf_test.go deleted file mode 100644 index e9bc646d..00000000 --- a/pkg/conf/conf_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package conf - -import ( - "github.com/cloudreve/Cloudreve/v4/pkg/util" - "github.com/stretchr/testify/assert" - "io/ioutil" - "os" - "testing" -) - -// 测试Init日志路径错误 -func TestInitPanic(t *testing.T) { - asserts := assert.New(t) - - // 日志路径不存在时 - asserts.NotPanics(func() { - Init("not/exist/path") - }) - - asserts.True(util.Exists("conf.ini")) - -} - -// TestInitDelimiterNotFound 日志路径存在但 Key 格式错误时 -func TestInitDelimiterNotFound(t *testing.T) { - asserts := assert.New(t) - testCase := `[Database] -Type = mysql -User = root -Password233root -Host = 127.0.0.1:3306 -Name = v3 -TablePrefix = v3_` - err := ioutil.WriteFile("testConf.ini", []byte(testCase), 0644) - defer func() { err = os.Remove("testConf.ini") }() - if err != nil { - panic(err) - } - asserts.Panics(func() { - Init("testConf.ini") - }) -} - -// TestInitNoPanic 日志路径存在且合法时 -func TestInitNoPanic(t *testing.T) { - asserts := assert.New(t) - testCase := ` -[System] -Listen = 3000 -HashIDSalt = 1 - -[Database] -Type = mysql -User = root -Password = root -Host = 127.0.0.1:3306 -Name = v3 -TablePrefix = v3_` - err := ioutil.WriteFile("testConf.ini", []byte(testCase), 0644) - defer func() { err = os.Remove("testConf.ini") }() - if err != nil { - panic(err) - } - asserts.NotPanics(func() { - Init("testConf.ini") - }) -} - -func TestMapSection(t *testing.T) { - asserts := assert.New(t) - - //正常情况 - testCase := ` -[System] -Listen = 3000 -HashIDSalt = 1 - -[Database] -Type = mysql -User = root -Password:root -Host = 127.0.0.1:3306 -Name = v3 -TablePrefix = v3_` - err := ioutil.WriteFile("testConf.ini", []byte(testCase), 0644) - defer func() { err = os.Remove("testConf.ini") }() - if err != nil { - panic(err) - } - Init("testConf.ini") - err = mapSection("Database", DatabaseConfig) - asserts.NoError(err) - -} diff --git a/pkg/request/request.go b/pkg/request/request.go index afd8b063..d987814b 100644 --- a/pkg/request/request.go +++ b/pkg/request/request.go @@ -156,8 +156,7 @@ func (c *HTTPClient) Request(method, target string, body io.Reader, opts ...Opti req.Header.Add(CorrelationHeader, logging.CorrelationID(options.ctx).String()) } - mode := c.config.System().Mode - if options.masterMeta && mode == conf.MasterMode { + if c.config != nil && options.masterMeta && c.config.System().Mode == conf.MasterMode { req.Header.Add(SiteURLHeader, options.siteURL) req.Header.Add(SiteIDHeader, options.siteID) req.Header.Add(SiteVersionHeader, constants.BackendVersion) diff --git a/pkg/request/request_test.go b/pkg/request/request_test.go index 4e062df9..a42f1f37 100644 --- a/pkg/request/request_test.go +++ b/pkg/request/request_test.go @@ -4,7 +4,6 @@ import ( "context" "errors" "github.com/cloudreve/Cloudreve/v4/pkg/auth" - "github.com/cloudreve/Cloudreve/v4/pkg/cache" "github.com/stretchr/testify/assert" testMock "github.com/stretchr/testify/mock" "io" @@ -54,7 +53,7 @@ func TestWithContext(t *testing.T) { func TestHTTPClient_Request(t *testing.T) { asserts := assert.New(t) - client := NewClientDeprecated(WithSlaveMeta("test")) + client := NewClientDeprecated(WithSlaveMeta(1)) // 正常 { @@ -230,7 +229,6 @@ func TestNopRSCloser_SetFirstFakeChunk(t *testing.T) { func TestBlackHole(t *testing.T) { a := assert.New(t) - cache.Set("setting_reset_after_upload_failed", "true", 0) a.NotPanics(func() { BlackHole(strings.NewReader("TestBlackHole")) })