Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c645ed1adf
|
||
|
|
87234d9f76
|
||
|
|
0d5eb3343a | ||
|
|
52ad11f0af | ||
|
|
71b6eb3a08 | ||
|
|
5cb62a1155 | ||
|
|
867537dd01 | ||
|
|
487880fd19 | ||
|
|
3b29cece0c | ||
|
|
c1bb0b6db6 | ||
|
|
a04b20a58f | ||
|
|
2b2ce550d4 | ||
|
|
87293d3434 | ||
|
|
7b0d200262 | ||
|
|
d1d037a030 | ||
|
|
c37a62b0a2 | ||
|
|
cff1577d19 | ||
|
|
efa50d4877 | ||
|
|
067eb2f143 | ||
|
|
4e8e51751d | ||
|
|
ae0b94de12 | ||
|
|
2c24483c06 | ||
|
|
221d5cbd08 | ||
|
|
62ce1019b1 | ||
|
|
ef9934e3ed | ||
|
|
e78eaffb58 | ||
|
|
370b1586c5 | ||
|
|
1f8d160296 | ||
|
|
3656ebd1c4 | ||
|
|
e3a7406b9e | ||
|
|
4847e59e25 | ||
|
|
b6fa806add | ||
|
|
5394f00550 | ||
|
|
9a48b7132c | ||
|
|
4cea93524d | ||
|
|
3cd4554d87 | ||
|
|
2e6ca25078 | ||
|
|
901a8f6030 | ||
|
|
b1feb6377d | ||
|
|
3fd8c982a5 | ||
|
|
c05de8bdea | ||
|
|
d97f2612b8 | ||
|
|
6d8e86b774 | ||
|
|
7a117e768d | ||
|
|
bfd1650ee2 | ||
|
|
d9a14c883e | ||
|
|
2b652dae20 | ||
|
|
6631594402 | ||
|
|
c5f69fe962 | ||
|
|
a65042d381 | ||
|
|
24981ad991 | ||
|
|
2078f859f3 | ||
|
|
16670ff34f | ||
|
|
b994d18792 | ||
|
|
4ea90be4aa | ||
|
|
3770c1e4eb | ||
|
|
5fd75c160a | ||
|
|
c60131a69c | ||
|
|
b4eda04f37 | ||
|
|
6e2d3affd9 | ||
|
|
2cbf8cac53 | ||
|
|
b933b1f365 | ||
|
|
96d34a4615 | ||
|
|
1a5a6ec3c3 | ||
|
|
997c02f379 | ||
|
|
2412bf3595 | ||
|
|
20697b6b74 | ||
|
|
cb18c69dcc | ||
|
|
e99a07db05 | ||
|
|
b1189f2594 | ||
|
|
783d39086c | ||
|
|
c87f9e3c18 | ||
|
|
e5615b35ca | ||
|
|
327a8fb759 | ||
|
|
319128c43f | ||
|
|
bccd6276dd | ||
|
|
1b5913f2bf | ||
|
|
66f9bc149d | ||
|
|
f06bf851a9 | ||
|
|
c891abbdf6 | ||
|
|
f65c7b643a | ||
|
|
bc0e9128e3 | ||
|
|
e1ea96acf4 | ||
|
|
f64490cf94 | ||
|
|
5a05644fed | ||
|
|
9a45f6bc26 | ||
|
|
d9d3a9f8dd | ||
|
|
91feb6e54a | ||
|
|
fc1ec1ad61 | ||
|
|
b1afd1f15a | ||
|
|
746c84a0d6 | ||
|
|
2936407d35 | ||
|
|
07449f2391 | ||
|
|
c62a0ec6ba | ||
|
|
9ae0a666e9 | ||
|
|
13b36b44ef | ||
|
|
1916b89173 | ||
|
|
d558f38ee8 | ||
|
|
7eacf8cefc | ||
|
|
d6245127ac | ||
|
|
f23e436f39 | ||
|
|
a630f68a9f | ||
|
|
7f7072c83a | ||
|
|
f248bb1356 | ||
|
|
b4bd17b678 | ||
|
|
2f974ee36e | ||
|
|
cec3175583 | ||
|
|
969cf59ef3 | ||
|
|
169e5d3800 | ||
|
|
1618cf7b19 | ||
|
|
0d84f2c324 | ||
|
|
871f60d169 | ||
|
|
e66693f38b | ||
|
|
30bdf62714 | ||
|
|
c4b9de7f45 | ||
|
|
211b1348a5 | ||
|
|
eb59f61d73 | ||
|
|
d539b13641 | ||
|
|
117d335fa3 | ||
|
|
0dc0844eb3 | ||
|
|
c58bcdb8e8 | ||
|
|
c765a2fb06 | ||
|
|
89eb76043c | ||
|
|
84f3b9cf7c | ||
|
|
51335dc57f | ||
|
|
0ad2ad90fa | ||
|
|
a3132614c4 | ||
|
|
761df3603b | ||
|
|
6adbbf8847 | ||
|
|
e089a11124 | ||
|
|
14f728e94c | ||
|
|
7a8bb089ad | ||
|
|
b16ee73b52 | ||
|
|
416c6384fa | ||
|
|
a6c9a8e731 | ||
|
|
74448bee91 | ||
|
|
7fdf7b333a | ||
|
|
e10e211fb7 | ||
|
|
1c8b3650a3 | ||
|
|
41a3a30976 | ||
|
|
6a3bb8b22d | ||
|
|
04255c2385 | ||
|
|
77d1db5833 | ||
|
|
6231d4efe7 | ||
|
|
f68073e012 | ||
|
|
92e1c5de00 | ||
|
|
7add88cda3 | ||
|
|
639484df81 | ||
|
|
a6364fc036 | ||
|
|
a313e974ff | ||
|
|
21aeda399f | ||
|
|
cb89e5e021 | ||
|
|
2095a33886 | ||
|
|
7222581d61 | ||
|
|
968d8e5600 | ||
|
|
a2369501ef | ||
|
|
0858ca0c3b | ||
|
|
14feeaaf71 | ||
|
|
5a94d0f11c | ||
|
|
4757a853ce | ||
|
|
21fa2fa078 | ||
|
|
7a4dbf27fd |
No files matched your search
@@ -4,4 +4,7 @@
|
||||
*.webp filter=lfs diff=lfs merge=lfs -text
|
||||
*.gif filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
*.go diff=golang
|
||||
.gitea/CODEOWNERS linguist-detectable=false
|
||||
@@ -0,0 +1,3 @@
|
||||
# Pull requests request review from the eligible staff team(s).
|
||||
# One approval from either an Admin or Developer satisfies branch protection.
|
||||
* @trueog/Admins @trueog/Developers
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
||||
# Order is important; the last matching pattern takes the most precedence.
|
||||
# Order is important; the last matching pattern has the highest precedence.
|
||||
|
||||
* @AlekSi @chilagrow
|
||||
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
2. Update DocumentDB image tags to point to release in:
|
||||
- [eval image](../build/ferretdb/eval.Dockerfile);
|
||||
- [eval-dev image](../build/ferretdb/eval-dev.Dockerfile);
|
||||
- [local image](../build/deps/postgres-documentdb.Dockerfile).
|
||||
- [local image](../build/deps/postgres-documentdb.Dockerfile);
|
||||
- [bw image](../build/ferretdb-bw/Dockerfile).
|
||||
3. Update constants in [`documentdb.go`](../build/version/documentdb.go).
|
||||
4. Check DocumentDB images tags in documentation (where we specify full tags).
|
||||
4. Check DocumentDB images/tags in documentation (where we specify full tags).
|
||||
5. Re-run tests, linters.
|
||||
6. Check issues and pull requests, update milestones and labels.
|
||||
7. Check if there are breaking changes or anything that should be reflected in the changelog and/or user documentation.
|
||||
@@ -63,8 +64,8 @@
|
||||
1. Publish and announce blog post.
|
||||
2. Add link to blog post to `CHANGELOG.md` and release page.
|
||||
3. Bump the latest version on https://beacon.ferretdb.com and https://beacon.ferretdb.io.
|
||||
4. Update DocumentDB image tags to point back to development version.
|
||||
5. Update DocumentDB images tags in the current documentation (where we specify full tags)
|
||||
4. Update DocumentDB images/tags in Dockerfiles to point back to development version.
|
||||
5. Update DocumentDB images/tags in the current documentation (where we specify full tags)
|
||||
to point to the next (non-existing) version.
|
||||
6. Update URLs with `/refs/tags/` in them in the current documentation
|
||||
to point to the next (non-existing) version.
|
||||
+26
-1
@@ -30,7 +30,32 @@ flag_management:
|
||||
|
||||
# https://docs.codecov.com/docs/pull-request-comments
|
||||
comment:
|
||||
layout: reach,diff,files,flags
|
||||
layout: reach,diff,files,flags,components
|
||||
|
||||
# https://docs.codecov.com/docs/components
|
||||
component_management:
|
||||
default_rules:
|
||||
statuses:
|
||||
- type: project
|
||||
target: auto
|
||||
threshold: 1%
|
||||
individual_components:
|
||||
- component_id: clientconn
|
||||
name: "clientconn"
|
||||
paths:
|
||||
- internal/clientconn/**
|
||||
- component_id: dataapi
|
||||
name: "dataapi"
|
||||
paths:
|
||||
- internal/dataapi/**
|
||||
- component_id: documentdb
|
||||
name: "documentdb"
|
||||
paths:
|
||||
- internal/documentdb/**
|
||||
- component_id: handler
|
||||
name: "handler"
|
||||
paths:
|
||||
- internal/handler/**
|
||||
|
||||
# https://docs.codecov.com/docs/github-checks
|
||||
# Annotations may be hidden by pressing the "a" key or by unselecting "Show annotations" in the top right of the file.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
version: 2
|
||||
|
||||
# Most configurations are duplicated to add main-v1 branch.
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
@@ -17,6 +18,19 @@ updates:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
- package-ecosystem: "github-actions"
|
||||
target-branch: "main-v1"
|
||||
directory: "/"
|
||||
labels: ["deps", "not ready"]
|
||||
assignees: [AlekSi]
|
||||
open-pull-requests-limit: 20
|
||||
groups:
|
||||
github-actions-v1:
|
||||
patterns: ["*"]
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/build/ferretdb"
|
||||
@@ -30,6 +44,20 @@ updates:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
- package-ecosystem: "docker"
|
||||
target-branch: "main-v1"
|
||||
directory: "/build/ferretdb"
|
||||
labels: ["deps", "not ready"]
|
||||
assignees: [AlekSi]
|
||||
open-pull-requests-limit: 20
|
||||
groups:
|
||||
build-docker-v1:
|
||||
patterns: ["*"]
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/build/deps"
|
||||
labels: ["deps", "not ready"]
|
||||
@@ -42,6 +70,19 @@ updates:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
- package-ecosystem: "docker"
|
||||
target-branch: "main-v1"
|
||||
directory: "/build/deps"
|
||||
labels: ["deps", "not ready"]
|
||||
assignees: [AlekSi]
|
||||
open-pull-requests-limit: 20
|
||||
groups:
|
||||
build-deps-v1:
|
||||
patterns: ["*"]
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
@@ -55,6 +96,20 @@ updates:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
- package-ecosystem: "gomod"
|
||||
target-branch: "main-v1"
|
||||
directory: "/"
|
||||
labels: ["deps", "not ready"]
|
||||
assignees: [AlekSi]
|
||||
open-pull-requests-limit: 20
|
||||
groups:
|
||||
ferretdb-v1:
|
||||
patterns: ["*"]
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/integration"
|
||||
labels: ["deps", "not ready"]
|
||||
@@ -67,6 +122,20 @@ updates:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
- package-ecosystem: "gomod"
|
||||
target-branch: "main-v1"
|
||||
directory: "/integration"
|
||||
labels: ["deps", "not ready"]
|
||||
assignees: [AlekSi]
|
||||
open-pull-requests-limit: 20
|
||||
groups:
|
||||
integration-v1:
|
||||
patterns: ["*"]
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/tools"
|
||||
labels: ["deps", "not ready"]
|
||||
@@ -79,6 +148,20 @@ updates:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
- package-ecosystem: "gomod"
|
||||
target-branch: "main-v1"
|
||||
directory: "/tools"
|
||||
labels: ["deps", "not ready"]
|
||||
assignees: [AlekSi]
|
||||
open-pull-requests-limit: 20
|
||||
groups:
|
||||
tools-v1:
|
||||
patterns: ["*"]
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/tools/golangci"
|
||||
labels: ["deps", "not ready"]
|
||||
@@ -91,7 +174,35 @@ updates:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
- package-ecosystem: "gomod"
|
||||
target-branch: "main-v1"
|
||||
directory: "/tools/golangci"
|
||||
labels: ["deps", "not ready"]
|
||||
assignees: [AlekSi]
|
||||
open-pull-requests-limit: 20
|
||||
groups:
|
||||
golangci-v1:
|
||||
patterns: ["*"]
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
|
||||
# no mcphost in main-v1
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/tools/mcphost"
|
||||
labels: ["deps", "not ready"]
|
||||
assignees: [AlekSi]
|
||||
open-pull-requests-limit: 20
|
||||
groups:
|
||||
mcphost:
|
||||
patterns: ["*"]
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "01:42"
|
||||
|
||||
# no submodules in main-v1
|
||||
- package-ecosystem: "gitsubmodule"
|
||||
directory: "/"
|
||||
labels: ["deps", "not ready"]
|
||||
|
||||
@@ -30,6 +30,9 @@ labels:
|
||||
- name: area/cursors
|
||||
color: "#D93F0B"
|
||||
description: Issues about cursors
|
||||
- name: area/dataapi
|
||||
color: "#D98F93"
|
||||
description: Issues about Data API
|
||||
- name: area/diag
|
||||
color: "#909BA6"
|
||||
description: Issues about diagnostic commands
|
||||
@@ -42,6 +45,9 @@ labels:
|
||||
- name: area/indexes
|
||||
color: "#006B75"
|
||||
description: Issues about indexes
|
||||
- name: area/mcp
|
||||
color: "#95921F"
|
||||
description: Issues about MCP
|
||||
- name: area/observability
|
||||
color: "#E04D33"
|
||||
description: Issues about metrics, logs, traces, pprof, etc
|
||||
|
||||
@@ -12,10 +12,6 @@ on:
|
||||
shard_total:
|
||||
required: true
|
||||
type: number
|
||||
coveralls:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
test_timeout:
|
||||
required: false
|
||||
type: string
|
||||
@@ -24,6 +20,10 @@ on:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
skip_flaky_check:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
env:
|
||||
GOPATH: /home/runner/go
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
@@ -77,6 +77,14 @@ jobs:
|
||||
- name: Run init
|
||||
run: bin/task init
|
||||
|
||||
- name: Setup Ollama and MCPHost
|
||||
run: |
|
||||
mkdir -p tmp/logs
|
||||
curl -fsSL https://ollama.com/install.sh | sh
|
||||
sudo systemctl stop ollama
|
||||
bin/task ollama > tmp/logs/ollama.log 2>&1 &
|
||||
bin/task mcphost > tmp/logs/mcphost.log 2>&1 &
|
||||
|
||||
- name: Wait for and setup environment
|
||||
run: bin/task env-setup
|
||||
|
||||
@@ -95,22 +103,53 @@ jobs:
|
||||
- name: Collect logs
|
||||
if: failure()
|
||||
run: |
|
||||
mkdir -p /tmp/logs
|
||||
bin/task env-logs-collect > /tmp/logs/compose-logs.txt
|
||||
cp -v integration/*.json.tmp integration/*.txt.tmp /tmp/logs/
|
||||
bin/task env-logs-collect
|
||||
cp -v integration/*.json.tmp integration/*.txt.tmp tmp/logs/
|
||||
|
||||
- name: Compress logs before upload
|
||||
if: failure()
|
||||
run: zip -r -q -9 logs.zip /tmp/logs
|
||||
run: zip -r -q -9 logs.zip tmp/logs
|
||||
|
||||
- name: Upload logs
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: logs-${{ inputs.task }}-${{ inputs.shard_index }}-${{ inputs.shard_total }}
|
||||
path: logs.zip
|
||||
retention-days: 3
|
||||
|
||||
- name: Upload coverage information to codecov
|
||||
if: always()
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: ./integration/integration-${{ inputs.task }}.txt
|
||||
flags: integration,${{ inputs.task }},${{ inputs.task }}-${{ inputs.shard_index }}
|
||||
disable_file_fixes: true
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
|
||||
- name: Upload coverage information to coveralls
|
||||
if: always()
|
||||
uses: coverallsapp/github-action@v2
|
||||
with:
|
||||
file: ./integration/integration-${{ inputs.task }}.txt
|
||||
flag-name: integration-${{ inputs.task }}-${{ inputs.shard_index }}
|
||||
parallel: true
|
||||
|
||||
- name: Convert test results to JUnit XML format
|
||||
if: always() && !inputs.skip_flaky_check
|
||||
run: >
|
||||
./bin/go-junit-report -parser=gojson
|
||||
-in ./integration/*.json.tmp
|
||||
-out ./integration/${{ inputs.task }}.xml
|
||||
|
||||
- name: Upload test results to Codecov
|
||||
if: always()
|
||||
uses: codecov/test-results-action@v1
|
||||
with:
|
||||
flags: integration,${{ inputs.task }},${{ inputs.task }}-${{ inputs.shard_index }}
|
||||
file: ./integration/${{ inputs.task }}.xml
|
||||
|
||||
# we don't want them on CI
|
||||
- name: Clean test and fuzz caches
|
||||
if: always()
|
||||
|
||||
@@ -18,9 +18,12 @@ jobs:
|
||||
name: Cleanup
|
||||
runs-on: server
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
|
||||
@@ -7,11 +7,11 @@ on:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- main-*
|
||||
- releases/*
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- main-*
|
||||
- releases/*
|
||||
|
||||
env:
|
||||
GOPATH: /home/runner/go
|
||||
@@ -29,10 +29,13 @@ jobs:
|
||||
|
||||
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'not ready')
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
|
||||
@@ -34,10 +34,13 @@ jobs:
|
||||
# comment out to enable this job
|
||||
if: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
|
||||
@@ -37,10 +37,13 @@ jobs:
|
||||
|
||||
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'not ready')
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: true
|
||||
@@ -87,7 +90,7 @@ jobs:
|
||||
|
||||
# it has to be exactly "docs.tar" for actions/deploy-pages below
|
||||
- name: Upload archive artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: docs
|
||||
path: tmp/docs.tar
|
||||
|
||||
@@ -36,10 +36,13 @@ jobs:
|
||||
|
||||
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'not ready')
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
|
||||
@@ -36,10 +36,13 @@ jobs:
|
||||
|
||||
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'not ready')
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
@@ -93,10 +96,13 @@ jobs:
|
||||
|
||||
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'not ready')
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
@@ -117,6 +123,16 @@ jobs:
|
||||
run: go generate -x
|
||||
working-directory: tools
|
||||
|
||||
# install.sh starts ollama service, stop it since we want to run with `bin/task ollama` with environment variables
|
||||
- name: Setup Ollama
|
||||
run: |
|
||||
curl -fsSL https://ollama.com/install.sh | sudo -E sh
|
||||
sudo systemctl stop ollama
|
||||
|
||||
- name: Start Ollama in the background
|
||||
run: |
|
||||
bin/task ollama &
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
@@ -127,6 +143,10 @@ jobs:
|
||||
- name: Start environment
|
||||
run: bin/task env-up-detach
|
||||
|
||||
- name: Pull and load Ollama model
|
||||
run: |
|
||||
bin/task ollama-model
|
||||
|
||||
- name: Run init
|
||||
run: bin/task init
|
||||
|
||||
@@ -136,6 +156,7 @@ jobs:
|
||||
- name: Regenerate and reformat
|
||||
run: bin/task gen
|
||||
env:
|
||||
# must be a SUPERUSER to ensure parameter_default is set
|
||||
DOCUMENTDB_GEN_URL: postgres://username:password@127.0.0.1:5432/postgres
|
||||
|
||||
- name: Build bin/ferretdb
|
||||
@@ -147,6 +168,38 @@ jobs:
|
||||
GOFLAGS: ${{ runner.debug == '1' && '-v' || '' }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # for tools
|
||||
|
||||
- name: Upload coverage information to codecov
|
||||
if: always()
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: ./cover.txt
|
||||
flags: unit
|
||||
disable_file_fixes: true
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
|
||||
- name: Upload coverage information to coveralls
|
||||
if: always()
|
||||
uses: coverallsapp/github-action@v2
|
||||
with:
|
||||
file: ./cover.txt
|
||||
flag-name: unit
|
||||
parallel: true
|
||||
|
||||
- name: Convert test results to JUnit XML format
|
||||
if: always()
|
||||
run: >
|
||||
./bin/go-junit-report
|
||||
-in ./unit.txt
|
||||
-out ./unit.xml
|
||||
|
||||
- name: Upload test results to Codecov
|
||||
if: always()
|
||||
uses: codecov/test-results-action@v1
|
||||
with:
|
||||
flags: unit
|
||||
file: ./unit.xml
|
||||
|
||||
# we don't want them on CI
|
||||
- name: Clean test and fuzz caches
|
||||
if: always()
|
||||
@@ -174,18 +227,19 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
task: [postgresql]
|
||||
task: [postgresql, yugabytedb]
|
||||
shard_index: [1, 2, 3, 4, 5]
|
||||
shard_total: [5]
|
||||
include:
|
||||
- { task: "mongodb", shard_index: 1, shard_total: 1 }
|
||||
- { task: "yugabytedb", skip_flaky_check: true } # Too many failures for now
|
||||
|
||||
uses: ./.github/workflows/_integration.yml
|
||||
with:
|
||||
task: ${{ matrix.task }}
|
||||
shard_index: ${{ matrix.shard_index }}
|
||||
shard_total: ${{ matrix.shard_total }}
|
||||
coveralls: true
|
||||
skip_flaky_check: ${{ matrix.skip_flaky_check || false }}
|
||||
|
||||
integration-no-xfail:
|
||||
name: postgresql no-xfail
|
||||
@@ -217,8 +271,11 @@ jobs:
|
||||
if: always() && (github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'not ready'))
|
||||
|
||||
steps:
|
||||
- name: Do nothing
|
||||
run: echo 'nothing'
|
||||
- name: Submit coveralls
|
||||
if: always()
|
||||
uses: coverallsapp/github-action@v2
|
||||
with:
|
||||
parallel-finished: true
|
||||
|
||||
env-data:
|
||||
name: env-data
|
||||
@@ -232,10 +289,13 @@ jobs:
|
||||
|
||||
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'not ready')
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
@@ -295,7 +355,7 @@ jobs:
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `golangci-lint run --new` to work
|
||||
lfs: false # LFS is used only by website
|
||||
|
||||
@@ -26,7 +26,7 @@ on:
|
||||
tags:
|
||||
- "*"
|
||||
schedule:
|
||||
- cron: "10 1 * * 1" # after cleanup
|
||||
- cron: "10 1 * * 1" # after cleanup and DocumentDB
|
||||
|
||||
# Do not run this workflow in parallel for any PR change or branch/tag push
|
||||
# to prevent concurrent pushes for the same Docker image tag
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
if: github.event_name != 'pull_request_target'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout pull request code
|
||||
if: github.event_name == 'pull_request_target'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
@@ -156,7 +156,7 @@ jobs:
|
||||
run: bin/task build-development
|
||||
|
||||
- name: Upload development binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: bin-dev
|
||||
path: tmp/bin-dev/
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
run: bin/task build-production
|
||||
|
||||
- name: Upload production binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: bin
|
||||
path: tmp/bin/
|
||||
@@ -178,7 +178,7 @@ jobs:
|
||||
run: bin/task packages
|
||||
|
||||
- name: Upload .deb packages
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: debs
|
||||
path: tmp/debs/
|
||||
@@ -186,7 +186,7 @@ jobs:
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload .rpm packages
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: rpms
|
||||
path: tmp/rpms/
|
||||
|
||||
@@ -36,10 +36,13 @@ jobs:
|
||||
|
||||
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'not ready')
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
|
||||
@@ -39,10 +39,13 @@ jobs:
|
||||
|
||||
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'not ready')
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for `git describe` to work
|
||||
lfs: false # LFS is used only by website
|
||||
@@ -103,7 +106,7 @@ jobs:
|
||||
|
||||
- name: Upload FerretDB log
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: ferretdb-log
|
||||
path: ferretdb-log.zip
|
||||
|
||||
@@ -39,10 +39,13 @@ jobs:
|
||||
name: cloudflare-dev-blog
|
||||
url: ${{ steps.extract.outputs.extracted_url }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for wrangler to work
|
||||
lfs: true
|
||||
@@ -102,6 +105,9 @@ jobs:
|
||||
name: cloudflare-dev-docs
|
||||
url: ${{ steps.extract.outputs.extracted_url }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
# We can't easily download build results from the Docs workflow:
|
||||
# https://github.com/actions/download-artifact/issues/172
|
||||
@@ -110,7 +116,7 @@ jobs:
|
||||
|
||||
# TODO https://github.com/FerretDB/github-actions/issues/211
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # for wrangler to work
|
||||
lfs: true
|
||||
|
||||
+1
-2
@@ -2,8 +2,6 @@
|
||||
# Please use global .gitignore file for .DS_Store, .idea/, go.work, .envrc, etc.
|
||||
# See https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files#configuring-ignored-files-for-all-repositories-on-your-computer
|
||||
|
||||
docker-compose.override.yml
|
||||
|
||||
state.json
|
||||
telemetry.json
|
||||
|
||||
@@ -15,6 +13,7 @@ telemetry.json
|
||||
*.tmp
|
||||
*.txt
|
||||
!website/static/*.txt
|
||||
*.xml
|
||||
|
||||
.task/
|
||||
bin/
|
||||
|
||||
+2
-1
@@ -53,6 +53,7 @@ linters-settings:
|
||||
- "!**/internal/documentdb/**.go"
|
||||
- "!**/internal/driver/*.go"
|
||||
- "!**/internal/handler/**.go"
|
||||
- "!**/internal/mcp/*.go"
|
||||
- "!**/internal/mongoerrors/*.go"
|
||||
- "!**/internal/util/logging/*.go"
|
||||
- "!**/internal/util/scram/*.go"
|
||||
@@ -179,7 +180,7 @@ linters-settings:
|
||||
alias: otelsdkresource
|
||||
- pkg: go.opentelemetry.io/otel/sdk/trace
|
||||
alias: otelsdktrace
|
||||
- pkg: go.opentelemetry.io/otel/semconv/v1.21.0
|
||||
- pkg: go.opentelemetry.io/otel/semconv/v1.34.0
|
||||
alias: otelsemconv
|
||||
# ineffassign
|
||||
lll:
|
||||
|
||||
+277
@@ -2,6 +2,283 @@
|
||||
|
||||
<!-- markdownlint-disable MD024 MD034 -->
|
||||
|
||||
## [v2.7.0](https://github.com/FerretDB/FerretDB/releases/tag/v2.7.0) (2025-11-10)
|
||||
|
||||
(We skipped v2.6.0 to align DocumentDB and FerretDB version numbers.)
|
||||
|
||||
This version works best with
|
||||
[DocumentDB v0.107.0-ferretdb-2.7.0](https://github.com/FerretDB/documentdb/releases/tag/v0.107.0-ferretdb-2.7.0).
|
||||
|
||||
### Breaking changes
|
||||
|
||||
There are some changes in our Prometheus metrics and OpenTelemetry traces.
|
||||
Please note that they are
|
||||
[not stable yet](https://docs.ferretdb.io/v2.7/configuration/observability/).
|
||||
|
||||
### What's Changed
|
||||
|
||||
#### Basic MCP server
|
||||
|
||||
This release adds basic MCP server support.
|
||||
Future release will bring additional functionality.
|
||||
|
||||
#### Connectivity improvements
|
||||
|
||||
PostgreSQL connections are now reused, often yielding modest performance gains.
|
||||
|
||||
### New Features 🎉
|
||||
|
||||
- Add basic MCP server by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5279
|
||||
- Implement DataAPI graceful shutdown and add OpenAPI spec endpoint by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5357
|
||||
- Improve proxy mode observability by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5440
|
||||
- Add tracing of SQL queries by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5514
|
||||
|
||||
### Enhancements 🛠
|
||||
|
||||
- Add `PostgreSQL` metrics by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5427
|
||||
- Rename OpenTelemetry spans by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5512
|
||||
|
||||
### Documentation 📄
|
||||
|
||||
- Add blog post on Formio by @Fashander in https://github.com/FerretDB/FerretDB/pull/5395
|
||||
- Document cloud instance deployment and setup by @Fashander in https://github.com/FerretDB/FerretDB/pull/5424
|
||||
- Update content guide by @Fashander in https://github.com/FerretDB/FerretDB/pull/5441
|
||||
- Update compatible apps by @Fashander in https://github.com/FerretDB/FerretDB/pull/5442
|
||||
- Add documentation page stub for MCP server by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5451
|
||||
- Add FerretDB Cloud blog post by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5461
|
||||
- Update cloud installation docs by @Fashander in https://github.com/FerretDB/FerretDB/pull/5466
|
||||
|
||||
### Other Changes 🤖
|
||||
|
||||
- Use middleware by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5377
|
||||
- Use generated structs in Data API by @noisersup in https://github.com/FerretDB/FerretDB/pull/5382
|
||||
- Upload YugabyteDB log files by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5401
|
||||
- Update documentation to point to the next release by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5423
|
||||
- Bump YugabyteDB to stable version by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5428
|
||||
- Use QEMU on arm64 for Yugabyte for now by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5429
|
||||
- Add comments to supervisord config by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5430
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5431
|
||||
- Make `Run` wait for all `Handle` calls to finish by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5434
|
||||
- Tweak `conninfo` by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5435
|
||||
- Add middleware by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5437
|
||||
- Update expected PostgreSQL version by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5438
|
||||
- Avoid hijacking connections from the pool and immediately closing them by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5443
|
||||
- Remove flaky test by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5444
|
||||
- Add TODO comment about Debian 13 Trixie by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5450
|
||||
- Add MCP tools by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5452
|
||||
- Bump deps by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5455
|
||||
- Update `wire` dependency by @noisersup in https://github.com/FerretDB/FerretDB/pull/5465
|
||||
- Add helpers for lazy logging by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5467
|
||||
- Move to `documentdb/documentdb` by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5468
|
||||
- Update dependencies by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5479
|
||||
- Add a test for `*documentdb.Conn` finalizing by @noisersup in https://github.com/FerretDB/FerretDB/pull/5484
|
||||
- Finalize PostgreSQL metrics by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5485
|
||||
- Fix spelling in `.go` files by @jsoref in https://github.com/FerretDB/FerretDB/pull/5492
|
||||
- Fix `CODEOWNERS` grammar by @jsoref in https://github.com/FerretDB/FerretDB/pull/5495
|
||||
- Use Go 1.25.1 by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5508
|
||||
- Bump deps by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5509
|
||||
- Minor observability cleanup by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5511
|
||||
- Bump dependencies by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5519
|
||||
- Use Go 1.25.3 by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5525
|
||||
- Skip flaky test for now by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5526
|
||||
- Use forked lazyerrors by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5527
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5528
|
||||
- Use Go 1.25.4 by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5534
|
||||
- Bump DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5536
|
||||
- Bump deps by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5537
|
||||
|
||||
### New Contributors
|
||||
|
||||
- @jsoref made their first contribution in https://github.com/FerretDB/FerretDB/pull/5486
|
||||
|
||||
[All closed issues and pull requests](https://github.com/FerretDB/FerretDB/milestone/80?closed=1).
|
||||
[All commits](https://github.com/FerretDB/FerretDB/compare/v2.5.0...v2.7.0).
|
||||
|
||||
## [v2.5.0](https://github.com/FerretDB/FerretDB/releases/tag/v2.5.0) (2025-08-12)
|
||||
|
||||
This version works best with
|
||||
[DocumentDB v0.106.0-ferretdb-2.5.0](https://github.com/FerretDB/documentdb/releases/tag/v0.106.0-ferretdb-2.5.0).
|
||||
|
||||
### Breaking changes
|
||||
|
||||
#### Metric names
|
||||
|
||||
We changed Prometheus metric names and `HELP` texts to highlight the fact that they are
|
||||
[not stable yet](https://docs.ferretdb.io/configuration/observability/#metrics).
|
||||
We plan to promote most of them to stable in the next release.
|
||||
|
||||
### What's Changed
|
||||
|
||||
#### RPM packages for DocumentDB
|
||||
|
||||
DocumentDB `.rpm` packages for Red Hat Enterprise Linux are
|
||||
[now available](https://docs.ferretdb.io/installation/documentdb/rpm/)!
|
||||
|
||||
### Documentation 📄
|
||||
|
||||
- Enable full visibility for images on zoom by @Fashander in https://github.com/FerretDB/FerretDB/pull/5346
|
||||
- Add Vault blog post by @Fashander in https://github.com/FerretDB/FerretDB/pull/5368
|
||||
- Add WeKan blog post by @Fashander in https://github.com/FerretDB/FerretDB/pull/5381
|
||||
|
||||
### Other Changes 🤖
|
||||
|
||||
- Add YugabyteDB integration tests by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5274
|
||||
- Run all YugabyteDB integration tests by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5283
|
||||
- Refactor normal and error responses by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5326
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5353
|
||||
- Use Codecov for flaky integration tests detection by @noisersup in https://github.com/FerretDB/FerretDB/pull/5361
|
||||
- Make accessing YugabyteDB logs easier by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5362
|
||||
- Add components in codecov by @noisersup in https://github.com/FerretDB/FerretDB/pull/5364
|
||||
- Skip YugabyteDB setup for `arm64` by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5372
|
||||
- Tweak Ollama and MCPHost setup by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5375
|
||||
- Simplify flags handling by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5378
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5380
|
||||
- Extract wiring into a separate package by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5383
|
||||
- Small cleanup by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5388
|
||||
- Encapsulate PostgreSQL pool in the Handler by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5389
|
||||
- Bump DocumentDB version by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5392
|
||||
- Test flaky tests detection by @noisersup in https://github.com/FerretDB/FerretDB/pull/5393
|
||||
- Small tweaks by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5394
|
||||
- Make a resource.Untrack thread-safe by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5396
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5398
|
||||
- Enable MongoDB test commands by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5400
|
||||
- Update Prometheus metrics by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5403
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5411
|
||||
|
||||
[All closed issues and pull requests](https://github.com/FerretDB/FerretDB/milestone/79?closed=1).
|
||||
[All commits](https://github.com/FerretDB/FerretDB/compare/v2.4.0...v2.5.0).
|
||||
|
||||
## [v2.4.0](https://github.com/FerretDB/FerretDB/releases/tag/v2.4.0) (2025-07-16)
|
||||
|
||||
This version works best with
|
||||
[DocumentDB v0.105.0-ferretdb-2.4.0](https://github.com/FerretDB/documentdb/releases/tag/v0.105.0-ferretdb-2.4.0).
|
||||
|
||||
### New Features 🎉
|
||||
|
||||
- Allow `clusterAdmin` users to perform user management commands by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5314
|
||||
|
||||
### Enhancements 🛠
|
||||
|
||||
- Use debug-level log messages for continuations by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5266
|
||||
|
||||
### Documentation 📄
|
||||
|
||||
- Add blog post on setting up LibreChat with FerretDB by @Fashander in https://github.com/FerretDB/FerretDB/pull/4999
|
||||
- Add blog post for Payload CMS by @Fashander in https://github.com/FerretDB/FerretDB/pull/5257
|
||||
- Add blog post on using Compass GUI by @Fashander in https://github.com/FerretDB/FerretDB/pull/5263
|
||||
- Fix social links by @Fashander in https://github.com/FerretDB/FerretDB/pull/5264
|
||||
- Add PayloadCMS to compatible apps by @Fashander in https://github.com/FerretDB/FerretDB/pull/5270
|
||||
- Add Compass to compatible apps by @Fashander in https://github.com/FerretDB/FerretDB/pull/5275
|
||||
- Wrap long lines in a blog post by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5280
|
||||
- Add NodeBB compatibility blog post by @Fashander in https://github.com/FerretDB/FerretDB/pull/5285
|
||||
- Add Librechat to compatibility section by @Fashander in https://github.com/FerretDB/FerretDB/pull/5286
|
||||
- Add NodeBB to compatible apps by @Fashander in https://github.com/FerretDB/FerretDB/pull/5293
|
||||
- Cleanup NodeBB blog post by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5294
|
||||
- Add Growthbook blogpost by @Fashander in https://github.com/FerretDB/FerretDB/pull/5304
|
||||
- Add Heyform compatibility blog post by @Fashander in https://github.com/FerretDB/FerretDB/pull/5316
|
||||
- Add GrowthBook to compatible apps by @Fashander in https://github.com/FerretDB/FerretDB/pull/5319
|
||||
- Add DBeaver compatibility blogpost by @Fashander in https://github.com/FerretDB/FerretDB/pull/5321
|
||||
- Add HyperDX blog post by @Fashander in https://github.com/FerretDB/FerretDB/pull/5334
|
||||
- Add compatible applications by @Fashander in https://github.com/FerretDB/FerretDB/pull/5335
|
||||
- Prepare v2.4.0 release by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5344
|
||||
|
||||
### Other Changes 🤖
|
||||
|
||||
- Add YugabyteDB to local setup by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5258
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5261
|
||||
- Remove skipping of `bypassEmptyTsReplacement` by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5267
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5268
|
||||
- Bring back Codecov and Coveralls integration by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5276
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5282
|
||||
- Add `mcphost` as tool by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5287
|
||||
- Refactor requests handling by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5292
|
||||
- Add Dependabot configuration for mcphost by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5296
|
||||
- Extend middleware requests and responses by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5301
|
||||
- Minor refactoring of Data API by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5302
|
||||
- Bump deps by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5307
|
||||
- Refactor responses handling by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5310
|
||||
- Add authentication test for client reconnecting by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5311
|
||||
- Do not use deprecated method by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5312
|
||||
- Update TODO URLs by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5317
|
||||
- Remove `must.NotFail(wire[bson].NewXXX(` pattern by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5318
|
||||
- Update TODO URL for `dropUsers` test by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5324
|
||||
- Avoid extra marshaling by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5327
|
||||
- Split command handling and handlers by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5328
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5342
|
||||
|
||||
### New Contributors
|
||||
|
||||
[All closed issues and pull requests](https://github.com/FerretDB/FerretDB/milestone/77?closed=1).
|
||||
[All commits](https://github.com/FerretDB/FerretDB/compare/v2.3.1...v2.4.0).
|
||||
|
||||
## [v2.3.1](https://github.com/FerretDB/FerretDB/releases/tag/v2.3.1) (2025-06-12)
|
||||
|
||||
Hotfix release to restore compatibility with various tools such as `mongoimport` and `mongorestore`.
|
||||
|
||||
### Fixed Bugs 🐛
|
||||
|
||||
- Revert "Remove hack for `bypassEmptyTsReplacement` (#5217)" by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5256
|
||||
|
||||
[All closed issues and pull requests](https://github.com/FerretDB/FerretDB/milestone/78?closed=1).
|
||||
[All commits](https://github.com/FerretDB/FerretDB/compare/v2.3.0...v2.3.1).
|
||||
|
||||
## [v2.3.0](https://github.com/FerretDB/FerretDB/releases/tag/v2.3.0) (2025-06-11)
|
||||
|
||||
This version works best with
|
||||
[DocumentDB v0.104.0-ferretdb-2.3.0](https://github.com/FerretDB/documentdb/releases/tag/v0.104.0-ferretdb-2.3.0).
|
||||
|
||||
### New Features 🎉
|
||||
|
||||
- Add telemetry configuration for embedded FerretDB by @jyz0309 in https://github.com/FerretDB/FerretDB/pull/5109
|
||||
- Use DocumentDB's support for `bypassEmptyTsReplacement` by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5217
|
||||
- Use DocumentDB's `compat` command by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5242
|
||||
|
||||
### Documentation 📄
|
||||
|
||||
- Enable `onInlineAuthors` in blog settings by @Balou9 in https://github.com/FerretDB/FerretDB/pull/5079
|
||||
- Create compatible apps section by @Fashander in https://github.com/FerretDB/FerretDB/pull/5108
|
||||
- Improve insert operations in guides by @Fashander in https://github.com/FerretDB/FerretDB/pull/5131
|
||||
- Update versions to point to the next release by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5144
|
||||
- Update Docker tags in docs by @Fashander in https://github.com/FerretDB/FerretDB/pull/5156
|
||||
- Update Docker tags for next release by @Fashander in https://github.com/FerretDB/FerretDB/pull/5157
|
||||
- Do not format MDX as Markdown by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5186
|
||||
- Add blog post on Mongo Express compatibility by @Fashander in https://github.com/FerretDB/FerretDB/pull/5194
|
||||
- Add blog post for Novu compatibility by @Fashander in https://github.com/FerretDB/FerretDB/pull/5195
|
||||
- Update CTS tool to wrap long lines by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5202
|
||||
- Disable Markdownlint rule that clashes with MDX by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5210
|
||||
- Small documentation tweaks by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5218
|
||||
- Prepare v2.3.0 release by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5254
|
||||
|
||||
### Other Changes 🤖
|
||||
|
||||
- Use `runtime.Cleanup` for resource tracking by @sahinakyol in https://github.com/FerretDB/FerretDB/pull/5077
|
||||
- Add Dependabot configuration for `main-v1` by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5098
|
||||
- Bump deps by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5159
|
||||
- Make `conninfo` a resource by @chilagrow in https://github.com/FerretDB/FerretDB/pull/5166
|
||||
- Revert "Update CODEOWNERS" by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5169
|
||||
- Bump deps by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5170
|
||||
- Add `permissions` to GitHub Actions workflows by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5182
|
||||
- Bump deps by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5184
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5197
|
||||
- Add test for inserting zero timestamp by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5199
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5201
|
||||
- Refactor resource tracking tests by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5208
|
||||
- Unskip test by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5211
|
||||
- Use Ollama in local setup by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5215
|
||||
- Update TODO comments by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5223
|
||||
- Bump Go and deps by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5236
|
||||
- Update DocumentDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5240
|
||||
- Build production Docker images for PRs by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5251
|
||||
- Improve telemetry configuration for embedded FerretDB by @AlekSi in https://github.com/FerretDB/FerretDB/pull/5252
|
||||
|
||||
### New Contributors
|
||||
|
||||
- @sahinakyol made their first contribution in https://github.com/FerretDB/FerretDB/pull/5077
|
||||
- @Balou9 made their first contribution in https://github.com/FerretDB/FerretDB/pull/5079
|
||||
|
||||
[All closed issues and pull requests](https://github.com/FerretDB/FerretDB/milestone/74?closed=1).
|
||||
[All commits](https://github.com/FerretDB/FerretDB/compare/v2.2.0...v2.3.0).
|
||||
|
||||
## [v2.2.0](https://github.com/FerretDB/FerretDB/releases/tag/v2.2.0) (2025-05-09)
|
||||
|
||||
This version works best with
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ On macOS and Windows, [Docker Desktop](https://www.docker.com/products/docker-de
|
||||
On Windows, it should be [configured to use WSL 2](https://docs.docker.com/desktop/windows/wsl/) without any distro;
|
||||
all commands should be run on the host.
|
||||
|
||||
You will need Go 1.24 or later on the host.
|
||||
You will need Go 1.25 or later on the host.
|
||||
If your package manager doesn't provide it yet,
|
||||
please install it from [go.dev](https://go.dev/dl/).
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
FerretDB database system (https://www.ferretdb.com/).
|
||||
Copyright 2021 FerretDB Inc.
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
FerretDB is an open-source alternative to MongoDB.
|
||||
It is a proxy that converts MongoDB 5.0+ wire protocol queries to SQL
|
||||
and uses PostgreSQL with [DocumentDB extension](https://github.com/microsoft/documentdb) as a database engine.
|
||||
and uses PostgreSQL with [DocumentDB extension](https://github.com/documentdb/documentdb) as a database engine.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@@ -116,7 +116,5 @@ See [there](https://pkg.go.dev/github.com/FerretDB/FerretDB/v2/build/version) fo
|
||||
- [Slack chat](https://slack.ferretdb.io/) for quick questions.
|
||||
- [GitHub Discussions](https://github.com/FerretDB/FerretDB/discussions) for longer topics.
|
||||
- [GitHub Issues](https://github.com/FerretDB/FerretDB/issues) for bugs and missing features.
|
||||
- [Open Office Hours meeting](https://calendar.google.com/calendar/event?action=TEMPLATE&tmeid=NGhrZTA5dXZ0MzQzN2gyaGVtZmx2aWxmN2pfMjAyNDA0MDhUMTcwMDAwWiBjX24zN3RxdW9yZWlsOWIwMm0wNzQwMDA3MjQ0QGc&tmsrc=c_n37tquoreil9b02m0740007244%40group.calendar.google.com&scp=ALL)
|
||||
every Monday at 17:00 UTC at [Google Meet](https://meet.google.com/mcb-arhw-qbq).
|
||||
|
||||
If you want to contact FerretDB Inc., please use [this form](https://www.ferretdb.com/contact/).
|
||||
+119
-7
@@ -16,7 +16,9 @@ vars:
|
||||
RACE_FLAG: -race={{and (ne OS "windows") (ne ARCH "arm") (ne ARCH "riscv64")}}
|
||||
BUILD_TAGS: ferretdb_dev
|
||||
MODE: diff-normal
|
||||
SERVICES: postgres mongodb mongodb-secure jaeger
|
||||
SERVICES: jaeger mongodb mongodb-secure postgres yugabytedb
|
||||
LLM: qwen3:0.6b # sync with code
|
||||
LLM_CONTEXT: 40960 # https://ollama.com/library/qwen3:0.6b
|
||||
|
||||
tasks:
|
||||
# invoked when `task` is run without arguments
|
||||
@@ -47,6 +49,13 @@ tasks:
|
||||
- go mod verify
|
||||
- go generate -x
|
||||
|
||||
init-tools-mcphost:
|
||||
dir: tools/mcphost
|
||||
cmds:
|
||||
- go mod tidy
|
||||
- go mod verify
|
||||
- go generate -x
|
||||
|
||||
init-integration:
|
||||
dir: integration
|
||||
cmds:
|
||||
@@ -55,7 +64,7 @@ tasks:
|
||||
|
||||
init:
|
||||
desc: "Install development tools"
|
||||
deps: [init-tools, init-tools-golangci, init-integration]
|
||||
deps: [init-tools, init-tools-golangci, init-tools-mcphost, init-integration]
|
||||
cmds:
|
||||
- go mod tidy
|
||||
- go mod verify
|
||||
@@ -106,9 +115,13 @@ tasks:
|
||||
- docker compose logs --follow
|
||||
|
||||
env-logs-collect:
|
||||
desc: "Collect logs from Docker and save them to tmp/logs"
|
||||
cmds:
|
||||
- docker compose ps --all
|
||||
- docker compose logs
|
||||
- bin/envtool{{exeExt}} shell mkdir tmp/logs
|
||||
- docker compose ps --all > tmp/logs/compose-ps.txt
|
||||
- docker compose logs > tmp/logs/compose-logs.txt
|
||||
- docker compose exec yugabytedb sh -c "bin/yugabyted collect_logs --stdout | gunzip | tar -xf - --one-top-level=/tmp/logs"
|
||||
- docker compose cp yugabytedb:/tmp/logs tmp/logs/yugabytedb
|
||||
|
||||
env-up:
|
||||
desc: "Start development environment"
|
||||
@@ -187,7 +200,7 @@ tasks:
|
||||
desc: "Run all unit tests"
|
||||
cmds:
|
||||
- go test -c -o /dev/null ./...
|
||||
- go test -count=1 -timeout={{.TEST_TIMEOUT}} {{.RACE_FLAG}} -tags={{.BUILD_TAGS}} -shuffle=on -coverprofile=cover.txt ./...
|
||||
- go test -v -count=1 -timeout={{.TEST_TIMEOUT}} {{.RACE_FLAG}} -tags={{.BUILD_TAGS}} -shuffle=on -coverprofile=cover.txt ./... | tee unit.txt
|
||||
- go test -count=1 -timeout={{.TEST_TIMEOUT}} {{.RACE_FLAG}} -tags={{.BUILD_TAGS}} -shuffle=on -bench=. -benchtime=1x ./...
|
||||
- bin/task{{exeExt}} -d tools tools-test
|
||||
|
||||
@@ -251,6 +264,47 @@ tasks:
|
||||
-target-backend=mongodb
|
||||
-no-xfail={{.NO_XFAIL}}
|
||||
|
||||
test-integration-yugabytedb:
|
||||
desc: "Run integration tests for FerretDB with YugabyteDB sequentially"
|
||||
vars:
|
||||
# DPanic on InternalError stops execution of remaining tests,
|
||||
# ensure to complete all tests by not setting development build tag and without race detector.
|
||||
# TODO https://github.com/FerretDB/FerretDB/issues/5397
|
||||
BUILD_TAGS: ""
|
||||
RACE_FLAG: -race=false
|
||||
deps:
|
||||
- task: gen-version
|
||||
vars:
|
||||
BUILD_TAGS:
|
||||
ref: .BUILD_TAGS
|
||||
RACE_FLAG:
|
||||
ref: .RACE_FLAG
|
||||
- task: test-integration-build
|
||||
dir: integration
|
||||
cmds:
|
||||
- >
|
||||
../bin/envtool{{exeExt}} tests run
|
||||
--shard-index={{.SHARD_INDEX}}
|
||||
--shard-total={{.SHARD_TOTAL}}
|
||||
--run='{{.TEST_RUN}}'
|
||||
--skip='{{.TEST_SKIP}}'
|
||||
--raw-prefix=yugabytedb-{{.SHARD_INDEX}}-{{.SHARD_TOTAL}}
|
||||
--
|
||||
-count=1
|
||||
-parallel=1
|
||||
-p=1
|
||||
-timeout={{.TEST_TIMEOUT}}
|
||||
{{.RACE_FLAG}}
|
||||
-tags={{.BUILD_TAGS}}
|
||||
-shuffle=on
|
||||
-coverpkg=../...
|
||||
-coverprofile=integration-yugabytedb.txt
|
||||
./...
|
||||
-target-backend=ferretdb-yugabytedb
|
||||
-postgresql-url='postgres://pg-user:pg-pass@127.0.0.1:5433/yugabyte'
|
||||
-compat-url='mongodb://username:password@127.0.0.1:47017/?replicaSet=rs0'
|
||||
-no-xfail={{.NO_XFAIL}}
|
||||
|
||||
bench-unit:
|
||||
desc: "Run unit benchmarks"
|
||||
cmds:
|
||||
@@ -268,6 +322,7 @@ tasks:
|
||||
--no-auth
|
||||
--listen-addr=:27017
|
||||
--listen-data-api-addr=127.0.0.1:8899
|
||||
--listen-mcp-addr=127.0.0.1:8081
|
||||
--proxy-addr=127.0.0.1:37017
|
||||
--postgresql-url='postgres://username:password@127.0.0.1:5432/postgres'
|
||||
--otel-traces-url=http://127.0.0.1:4318/v1/traces
|
||||
@@ -282,12 +337,45 @@ tasks:
|
||||
--mode={{.MODE}}
|
||||
--listen-addr=:27017
|
||||
--listen-data-api-addr=127.0.0.1:8899
|
||||
--listen-mcp-addr=127.0.0.1:8081
|
||||
--proxy-addr=127.0.0.1:47017
|
||||
--postgresql-url='postgres://username:password@127.0.0.1:5432/postgres'
|
||||
--otel-traces-url=http://127.0.0.1:4318/v1/traces
|
||||
--dev-repl-set-name=rs0
|
||||
--dev-records-dir=tmp/records
|
||||
|
||||
run-yugabytedb:
|
||||
desc: "Run FerretDB with YugabyteDB without auth"
|
||||
deps: [build-host]
|
||||
cmds:
|
||||
- >
|
||||
bin/ferretdb{{exeExt}}
|
||||
--mode={{.MODE}}
|
||||
--no-auth
|
||||
--listen-addr=:27017
|
||||
--listen-data-api-addr=127.0.0.1:8899
|
||||
--listen-mcp-addr=127.0.0.1:8081
|
||||
--proxy-addr=127.0.0.1:37017
|
||||
--postgresql-url='postgres://username:password@127.0.0.1:5433/yugabyte'
|
||||
--otel-traces-url=http://127.0.0.1:4318/v1/traces
|
||||
--dev-records-dir=tmp/records
|
||||
|
||||
run-yugabytedb-secure:
|
||||
desc: "Run FerretDB with YugabyteDB with auth"
|
||||
deps: [build-host]
|
||||
cmds:
|
||||
- >
|
||||
bin/ferretdb{{exeExt}}
|
||||
--mode={{.MODE}}
|
||||
--listen-addr=:27017
|
||||
--listen-data-api-addr=127.0.0.1:8899
|
||||
--listen-mcp-addr=127.0.0.1:8081
|
||||
--proxy-addr=127.0.0.1:47017
|
||||
--postgresql-url='postgres://username:password@127.0.0.1:5433/yugabyte'
|
||||
--otel-traces-url=http://127.0.0.1:4318/v1/traces
|
||||
--dev-repl-set-name=rs0
|
||||
--dev-records-dir=tmp/records
|
||||
|
||||
# invoked by FerretDB/github-actions/linters action
|
||||
lint:
|
||||
desc: "Run linters"
|
||||
@@ -317,18 +405,42 @@ tasks:
|
||||
|
||||
security-trivy:
|
||||
cmds:
|
||||
- docker compose run --rm trivy --config=./build/trivy.yml filesystem .
|
||||
- docker compose run --rm trivy --config=./build/trivy.yml filesystem --ignorefile=./build/.trivyignore .
|
||||
|
||||
godocs:
|
||||
desc: "Serve Go code documentation"
|
||||
cmds:
|
||||
- bin/pkgsite{{exeExt}} -http=127.0.0.1:6060 -open
|
||||
|
||||
ollama:
|
||||
desc: "Run local Ollama server"
|
||||
cmds:
|
||||
- ollama serve
|
||||
env:
|
||||
OLLAMA_CONTEXT_LENGTH: "{{.LLM_CONTEXT}}"
|
||||
OLLAMA_DEBUG: 2
|
||||
|
||||
ollama-model:
|
||||
desc: "Pull and load Ollama model"
|
||||
cmds:
|
||||
- ollama pull {{.LLM}}
|
||||
- ollama run --think=false {{.LLM}} 'Hi!'
|
||||
|
||||
mcphost:
|
||||
desc: "Run MCPHost for local Ollama server"
|
||||
cmds:
|
||||
- bin/mcphost --config=build/mcphost.json --model=ollama:{{.LLM}}
|
||||
|
||||
psql:
|
||||
desc: "Run psql"
|
||||
cmds:
|
||||
- docker compose exec postgres psql -p 5432 -U username -d postgres
|
||||
|
||||
ysqlsh:
|
||||
desc: "Run YugabyteDB SQL shell"
|
||||
cmds:
|
||||
- docker compose exec yugabytedb ./bin/ysqlsh postgres://username:password@host.docker.internal:5433/yugabyte
|
||||
|
||||
mongosh:
|
||||
desc: "Run MongoDB shell (`mongosh`)"
|
||||
cmds:
|
||||
@@ -738,7 +850,7 @@ tasks:
|
||||
# TODO --print-width 120 (https://github.com/FerretDB/FerretDB/issues/4636)
|
||||
- >
|
||||
docker compose run --rm prettier --write --single-quote --trailing-comma none --no-semi
|
||||
--parser markdown "**/*.md" "**/*.mdx"
|
||||
"**/*.md" "**/*.mdx"
|
||||
|
||||
- >
|
||||
docker compose run --rm markdownlint --config "build/.markdownlint.yml"
|
||||
|
||||
@@ -11,4 +11,7 @@ MD006: false # deprecated
|
||||
MD013: false # we use https://sembr.org that could lead to long lines
|
||||
MD026: { punctuation: ".,;:。,;:" } # default is .,;:!。,;:!
|
||||
MD029: { style: ordered }
|
||||
MD033: false # for MDX
|
||||
MD034: false # autolink tags <link> no longer supported by MDX
|
||||
MD037: false # clashes with MDX comments
|
||||
MD059: false # not yet
|
||||
@@ -0,0 +1,7 @@
|
||||
# https://github.com/cloudwego/eino#dependencies
|
||||
# TODO https://github.com/cloudwego/eino/issues/291
|
||||
CVE-2025-30153
|
||||
|
||||
# https://nvd.nist.gov/vuln/detail/CVE-2025-51471
|
||||
# https://github.com/ollama/ollama/pull/10750
|
||||
CVE-2025-51471
|
||||
@@ -1 +1 @@
|
||||
FROM ghcr.io/ferretdb/ferretdb-prettier:3.5.3-1
|
||||
FROM ghcr.io/ferretdb/ferretdb-prettier:3.6.2-1
|
||||
@@ -1 +1 @@
|
||||
FROM ghcr.io/ferretdb/ferretdb-textlint:14.6.0-1
|
||||
FROM ghcr.io/ferretdb/ferretdb-textlint:15.2.0-1
|
||||
@@ -1 +1 @@
|
||||
FROM ghcr.io/ferretdb/ferretdb-wrangler:4.7.1-1
|
||||
FROM ghcr.io/ferretdb/ferretdb-wrangler:4.24.0-1
|
||||
@@ -1 +1 @@
|
||||
FROM jaegertracing/all-in-one:1.68.0
|
||||
FROM jaegertracing/all-in-one:1.74.0
|
||||
@@ -1 +1 @@
|
||||
FROM davidanson/markdownlint-cli2:v0.17.2
|
||||
FROM davidanson/markdownlint-cli2:v0.18.1
|
||||
@@ -1,5 +1,5 @@
|
||||
# Use production image and full tag close to the release.
|
||||
FROM ghcr.io/ferretdb/postgres-documentdb:17-0.103.0-ferretdb-2.2.0
|
||||
# Use development image and full tag close to the release.
|
||||
FROM ghcr.io/ferretdb/postgres-documentdb-dev:17-0.107.0-ferretdb-2.7.0
|
||||
|
||||
# Use moving development image during development.
|
||||
# FROM ghcr.io/ferretdb/postgres-documentdb-dev:17-ferretdb
|
||||
@@ -1,2 +1,2 @@
|
||||
FROM aquasec/trivy:0.61.0
|
||||
FROM aquasec/trivy:0.67.2
|
||||
WORKDIR /workdir
|
||||
@@ -0,0 +1 @@
|
||||
FROM yugabytedb/yugabyte:2025.1.1.0-b197
|
||||
@@ -1,4 +1,8 @@
|
||||
FROM --platform=linux/amd64 ghcr.io/ferretdb/postgres-documentdb-dev:17-ferretdb
|
||||
# Use production image and full tag close to the release.
|
||||
FROM --platform=linux/amd64 ghcr.io/ferretdb/postgres-documentdb:17-0.107.0-ferretdb-2.7.0
|
||||
|
||||
# Use moving development image during development.
|
||||
# FROM --platform=linux/amd64 ghcr.io/ferretdb/postgres-documentdb-dev:17-ferretdb
|
||||
|
||||
RUN --mount=type=cache,target=/var/cache/apt <<EOF
|
||||
|
||||
@@ -11,9 +15,9 @@ apt update
|
||||
apt install -y git-lfs mongodb-mongosh tmux nano
|
||||
|
||||
cd /tmp
|
||||
curl -OJL https://go.dev/dl/go1.24.3.linux-amd64.tar.gz
|
||||
tar -xf go1.24.3.linux-amd64.tar.gz
|
||||
rm go1.24.3.linux-amd64.tar.gz
|
||||
curl -OJL https://go.dev/dl/go1.25.4.linux-amd64.tar.gz
|
||||
tar -xf go1.25.4.linux-amd64.tar.gz
|
||||
rm go1.25.4.linux-amd64.tar.gz
|
||||
mv go /usr/local/
|
||||
ln -s /usr/local/go/bin/* /usr/local/bin/
|
||||
go version
|
||||
|
||||
@@ -12,7 +12,8 @@ ARG LABEL_COMMIT
|
||||
|
||||
# prepare stage
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:1.24.3 AS development-prepare
|
||||
# TODO https://github.com/FerretDB/FerretDB/issues/5449
|
||||
FROM --platform=$BUILDPLATFORM golang:1.25.4-bookworm AS development-prepare
|
||||
|
||||
# use a single directory for all Go caches to simplify RUN --mount commands below
|
||||
ENV GOPATH=/cache/gopath
|
||||
@@ -36,7 +37,8 @@ EOF
|
||||
|
||||
# build stage
|
||||
|
||||
FROM golang:1.24.3 AS development-build
|
||||
# TODO https://github.com/FerretDB/FerretDB/issues/5449
|
||||
FROM golang:1.25.4-bookworm AS development-build
|
||||
|
||||
ARG TARGETARCH
|
||||
|
||||
@@ -103,7 +105,8 @@ COPY --from=development-build /src/bin/ferretdb /ferretdb
|
||||
|
||||
# final stage
|
||||
|
||||
FROM golang:1.24.3 AS development
|
||||
# TODO https://github.com/FerretDB/FerretDB/issues/5449
|
||||
FROM golang:1.25.4-bookworm AS development
|
||||
|
||||
ENV GOCOVERDIR=/tmp/cover
|
||||
ENV GORACE=halt_on_error=1,history_size=2
|
||||
|
||||
@@ -12,7 +12,8 @@ ARG LABEL_COMMIT
|
||||
|
||||
# prepare stage
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:1.24.3 AS eval-dev-prepare
|
||||
# TODO https://github.com/FerretDB/FerretDB/issues/5449
|
||||
FROM --platform=$BUILDPLATFORM golang:1.25.4-bookworm AS eval-dev-prepare
|
||||
|
||||
# use a single directory for all Go caches to simplify RUN --mount commands below
|
||||
ENV GOPATH=/cache/gopath
|
||||
@@ -36,7 +37,8 @@ EOF
|
||||
|
||||
# build stage
|
||||
|
||||
FROM golang:1.24.3 AS eval-dev-build
|
||||
# TODO https://github.com/FerretDB/FerretDB/issues/5449
|
||||
FROM golang:1.25.4-bookworm AS eval-dev-build
|
||||
|
||||
ARG TARGETARCH
|
||||
|
||||
@@ -97,7 +99,7 @@ EOF
|
||||
# final stage
|
||||
|
||||
# Use development image and full tag close to the release.
|
||||
FROM ghcr.io/ferretdb/postgres-documentdb-dev:17-0.103.0-ferretdb-2.2.0 AS eval-dev
|
||||
FROM ghcr.io/ferretdb/postgres-documentdb-dev:17-0.107.0-ferretdb-2.7.0 AS eval-dev
|
||||
|
||||
# Use moving development image during development.
|
||||
# FROM ghcr.io/ferretdb/postgres-documentdb-dev:17-ferretdb AS eval-dev
|
||||
|
||||
@@ -12,7 +12,8 @@ ARG LABEL_COMMIT
|
||||
|
||||
# prepare stage
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:1.24.3 AS eval-prepare
|
||||
# TODO https://github.com/FerretDB/FerretDB/issues/5449
|
||||
FROM --platform=$BUILDPLATFORM golang:1.25.4-bookworm AS eval-prepare
|
||||
|
||||
# use a single directory for all Go caches to simplify RUN --mount commands below
|
||||
ENV GOPATH=/cache/gopath
|
||||
@@ -36,7 +37,8 @@ EOF
|
||||
|
||||
# build stage
|
||||
|
||||
FROM golang:1.24.3 AS eval-build
|
||||
# TODO https://github.com/FerretDB/FerretDB/issues/5449
|
||||
FROM golang:1.25.4-bookworm AS eval-build
|
||||
|
||||
ARG TARGETARCH
|
||||
|
||||
@@ -89,7 +91,7 @@ EOF
|
||||
# final stage
|
||||
|
||||
# Use production image and full tag close to the release.
|
||||
FROM ghcr.io/ferretdb/postgres-documentdb:17-0.103.0-ferretdb-2.2.0 AS eval
|
||||
FROM ghcr.io/ferretdb/postgres-documentdb:17-0.107.0-ferretdb-2.7.0 AS eval
|
||||
|
||||
# Use moving development image during development.
|
||||
# FROM ghcr.io/ferretdb/postgres-documentdb-dev:17-ferretdb AS eval
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
; https://supervisord.org/configuration.html
|
||||
|
||||
; https://supervisord.org/configuration.html#supervisord-section-values
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
loglevel=info
|
||||
logfile=/dev/stderr
|
||||
logfile_maxbytes=0
|
||||
|
||||
; https://supervisord.org/configuration.html#program-x-section-values
|
||||
[program:postgres]
|
||||
command=/usr/local/bin/docker-entrypoint.sh postgres
|
||||
; lower priority postgres starts before ferretdb (default priority 999)
|
||||
@@ -16,6 +16,7 @@ stdout_logfile=/dev/stderr
|
||||
stdout_logfile_maxbytes=0
|
||||
redirect_stderr=true
|
||||
|
||||
; https://supervisord.org/configuration.html#program-x-section-values
|
||||
[program:ferretdb]
|
||||
command=/usr/local/bin/ferretdb
|
||||
stdout_logfile=/dev/stderr
|
||||
|
||||
@@ -12,7 +12,8 @@ ARG LABEL_COMMIT
|
||||
|
||||
# prepare stage
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:1.24.3 AS production-prepare
|
||||
# TODO https://github.com/FerretDB/FerretDB/issues/5449
|
||||
FROM --platform=$BUILDPLATFORM golang:1.25.4-bookworm AS production-prepare
|
||||
|
||||
# use a single directory for all Go caches to simplify RUN --mount commands below
|
||||
ENV GOPATH=/cache/gopath
|
||||
@@ -36,7 +37,8 @@ EOF
|
||||
|
||||
# build stage
|
||||
|
||||
FROM golang:1.24.3 AS production-build
|
||||
# TODO https://github.com/FerretDB/FerretDB/issues/5449
|
||||
FROM golang:1.25.4-bookworm AS production-build
|
||||
|
||||
ARG TARGETARCH
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"FerretDB": {
|
||||
"type": "remote",
|
||||
"url": "http://127.0.0.1:8081/mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
setParameter:
|
||||
enableTestCommands: 1 # for sleep
|
||||
|
||||
net:
|
||||
port: 47017 # matches host's port for replica set to work
|
||||
bindIpAll: true
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
setParameter:
|
||||
enableTestCommands: 1 # for sleep
|
||||
|
||||
net:
|
||||
port: 37017 # matches host's port for replica set to work
|
||||
bindIpAll: true
|
||||
|
||||
Submodule build/postgres-documentdb/documentdb updated: 7514232876...e63835403d.
@@ -14,19 +14,35 @@
|
||||
|
||||
package version
|
||||
|
||||
const (
|
||||
// PostgreSQL is a version of PostgreSQL this version of FerretDB is compatible with.
|
||||
PostgreSQL = "PostgreSQL 17.5 (Debian 17.5-1.pgdg120+1) on x86_64-pc-linux-gnu, " +
|
||||
"compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit"
|
||||
import "runtime"
|
||||
|
||||
const (
|
||||
// DocumentDB is a version of DocumentDB this version of FerretDB is compatible with.
|
||||
DocumentDB = "0.103.0 gitref: HEAD sha:7514232 buildId:0"
|
||||
DocumentDB = "0.107.0 gitref: HEAD sha:e63835403d buildId:0"
|
||||
|
||||
// DocumentDBURL points to the release page of the DocumentDB version above.
|
||||
DocumentDBURL = "https://github.com/FerretDB/documentdb/releases/tag/v0.103.0-ferretdb-2.2.0"
|
||||
DocumentDBURL = "https://github.com/FerretDB/documentdb/releases/tag/v0.107.0-ferretdb-2.7.0"
|
||||
)
|
||||
|
||||
// DocumentDBSafeToUpdate represents versions of DocumentDB that FerretDB can update.
|
||||
var DocumentDBSafeToUpdate = []string{
|
||||
"0.102.0 gitref: HEAD sha:80462f5 buildId:0", // v2.1.0
|
||||
"0.102.0 gitref: HEAD sha:80462f5 buildId:0", // v2.1.0
|
||||
"0.103.0 gitref: HEAD sha:7514232 buildId:0", // v2.2.0
|
||||
"0.104.0 gitref: HEAD sha:2045d0e buildId:0", // v2.3.0, v2.3.1
|
||||
"0.105.0 gitref: HEAD sha:8453d93b buildId:0", // v2.4.0
|
||||
"0.106.0 gitref: HEAD sha:beb9d25d98 buildId:0", // v2.5.0
|
||||
// FerretDB v2.6.0 wasn't released
|
||||
}
|
||||
|
||||
// PostgreSQLTest is a version of PostgreSQL used by tests.
|
||||
var PostgreSQLTest string
|
||||
|
||||
func init() {
|
||||
arch := "x86_64-pc-linux-gnu"
|
||||
if runtime.GOARCH == "arm64" {
|
||||
arch = "aarch64-unknown-linux-gnu"
|
||||
}
|
||||
|
||||
PostgreSQLTest = "PostgreSQL 17.6 (Debian 17.6-2.pgdg12+1) on " + arch + ", " +
|
||||
"compiled by gcc (Debian 12.2.0-14+deb12u1) 12.2.0, 64-bit"
|
||||
}
|
||||
@@ -93,7 +93,7 @@ const ferretdbModule = "github.com/FerretDB/FerretDB/v2"
|
||||
// semVerTag is a https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string,
|
||||
// but with a leading `v`.
|
||||
//
|
||||
//nolint:lll // for readibility
|
||||
//nolint:lll // for readability
|
||||
var semVerTag = regexp.MustCompile(`^v(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`)
|
||||
|
||||
// Get returns current build's info.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
CREATE EXTENSION IF NOT EXISTS documentdb CASCADE;
|
||||
@@ -261,7 +261,7 @@ func main() {
|
||||
|
||||
switch cmd {
|
||||
case "setup":
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
err = setup(ctx, logger)
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/lazyerrors"
|
||||
"github.com/AlekSi/lazyerrors"
|
||||
)
|
||||
|
||||
// copyFile copies a file from src to dst, overwriting dst if it exists.
|
||||
|
||||
+94
-2
@@ -23,12 +23,16 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/AlekSi/lazyerrors"
|
||||
"github.com/FerretDB/wire/wirebson"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/internal/documentdb"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/ctxutil"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/debug"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/lazyerrors"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/logging"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/state"
|
||||
)
|
||||
|
||||
// setupMongoDB configures MongoDB containers.
|
||||
@@ -68,6 +72,84 @@ func setupMongoDB(ctx context.Context, logger *slog.Logger, uri, name string) er
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
// setupUser waits for the given PostgreSQL URI to become available, and creates
|
||||
// an admin user with fixed credentials `username:password` using DocumentDB API.
|
||||
func setupUser(ctx context.Context, uri string, l *slog.Logger) error {
|
||||
sp, err := state.NewProvider("")
|
||||
if err != nil {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
pool, err := documentdb.NewPool(uri, l, sp)
|
||||
if err != nil {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
defer pool.Close()
|
||||
|
||||
var retry int64
|
||||
|
||||
createUser := wirebson.MustDocument(
|
||||
"createUser", "username",
|
||||
"pwd", "password",
|
||||
"roles", wirebson.MustArray(
|
||||
wirebson.MustDocument(
|
||||
"role", "clusterAdmin",
|
||||
"db", "admin",
|
||||
),
|
||||
wirebson.MustDocument(
|
||||
"role", "readWriteAnyDatabase",
|
||||
"db", "admin",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
var res wirebson.RawDocument
|
||||
|
||||
for ctx.Err() == nil {
|
||||
err = pool.WithConn(func(conn *pgx.Conn) error {
|
||||
res, err = documentdb.CreateUser(ctx, conn, l, createUser)
|
||||
return err
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
l.InfoContext(ctx, "Waiting for DocumentDB extension to be created")
|
||||
|
||||
retry++
|
||||
ctxutil.SleepWithJitter(ctx, time.Second, retry)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
d, err := res.Decode()
|
||||
if err != nil {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
switch ok := d.Get("ok").(type) {
|
||||
case float64:
|
||||
if ok != float64(1) {
|
||||
return lazyerrors.Errorf("Failed to create user: %s", d.LogMessage())
|
||||
}
|
||||
case int32:
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/5313
|
||||
if ok != int32(1) {
|
||||
return lazyerrors.Errorf("Failed to create user: %s", d.LogMessage())
|
||||
}
|
||||
default:
|
||||
panic("unexpected type")
|
||||
}
|
||||
|
||||
l.InfoContext(ctx, "User created", slog.String("response", d.LogMessage()))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setup runs all setup commands.
|
||||
func setup(ctx context.Context, logger *slog.Logger) error {
|
||||
h, err := debug.Listen(&debug.ListenOpts{
|
||||
@@ -79,12 +161,22 @@ func setup(ctx context.Context, logger *slog.Logger) error {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
go h.Serve(ctx)
|
||||
go h.Run(ctx)
|
||||
|
||||
if err = setupMongoDB(ctx, logger, "mongodb://username:password@127.0.0.1:47017/", "mongodb-secure"); err != nil {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
uri := "postgres://pg-user:pg-pass@127.0.0.1:5432/postgres"
|
||||
if err = setupUser(ctx, uri, logging.WithName(logger, "postgres")); err != nil {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
uri = "postgres://pg-user:pg-pass@127.0.0.1:5433/yugabyte"
|
||||
if err = setupUser(ctx, uri, logging.WithName(logger, "yugabytedb")); err != nil {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
logger.InfoContext(ctx, "Done")
|
||||
return nil
|
||||
}
|
||||
@@ -31,12 +31,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AlekSi/lazyerrors"
|
||||
"go.opentelemetry.io/otel"
|
||||
otelattribute "go.opentelemetry.io/otel/attribute"
|
||||
otelcodes "go.opentelemetry.io/otel/codes"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/lazyerrors"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/must"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/observability"
|
||||
)
|
||||
@@ -72,7 +72,7 @@ type testResult struct {
|
||||
// listTestFuncs returns a sorted slice of all top-level test functions (tests, benchmarks, examples, fuzz functions)
|
||||
// matching given regular expression in the specified directory and subdirectories.
|
||||
func listTestFuncs(ctx context.Context, dir, re string, logger *slog.Logger) ([]string, error) {
|
||||
ctx, span := otel.Tracer("").Start(ctx, "listTestFuncs")
|
||||
ctx, span := otel.Tracer("").Start(ctx, "envtool.listTestFuncs")
|
||||
defer span.End()
|
||||
|
||||
var buf bytes.Buffer
|
||||
@@ -158,7 +158,7 @@ func shardTestFuncs(index, total uint, testFuncs []string) ([]string, error) {
|
||||
|
||||
// testArgs handles `envtool tests run` arguments and returns a slice of `go test` arguments.
|
||||
func testArgs(ctx context.Context, dir string, index, total uint, run, skip string, logger *slog.Logger) ([]string, uint, error) {
|
||||
ctx, span := otel.Tracer("").Start(ctx, "testArgs")
|
||||
ctx, span := otel.Tracer("").Start(ctx, "envtool.testArgs")
|
||||
defer span.End()
|
||||
|
||||
listRE := "."
|
||||
@@ -309,7 +309,7 @@ func runGoTest(runCtx context.Context, opts *runGoTestOpts) (resErr error) {
|
||||
totalTests = strconv.Itoa(int(opts.total))
|
||||
}
|
||||
|
||||
runCtx, runSpan := otel.Tracer("").Start(runCtx, "run")
|
||||
runCtx, runSpan := otel.Tracer("").Start(runCtx, "envtool.runGoTest")
|
||||
runSpan.SetAttributes(otelattribute.String("db.ferretdb.envtool.total_tests", totalTests))
|
||||
defer runSpan.End()
|
||||
|
||||
@@ -377,7 +377,6 @@ func runGoTest(runCtx context.Context, opts *runGoTestOpts) (resErr error) {
|
||||
key = resultKey(event.Package, parentTest(event.Test))
|
||||
parent := results[key]
|
||||
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/4465
|
||||
if parent == nil {
|
||||
panic(fmt.Sprintf(
|
||||
"no parent test found: package=%q, test=%q, key=%q", event.Package, event.Test, key,
|
||||
@@ -585,14 +584,14 @@ func testsRun(ctx context.Context, params *TestsRunParams, logger *slog.Logger)
|
||||
|
||||
ot, err := observability.NewOTelTraceExporter(&observability.OTelTraceExporterOpts{
|
||||
Logger: logger,
|
||||
Service: "envtool-tests",
|
||||
URL: "http://127.0.0.1:4318/v1/traces",
|
||||
Service: "envtool-tests",
|
||||
})
|
||||
if err != nil {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
ctx, span := otel.Tracer("").Start(ctx, "testsRun")
|
||||
ctx, span := otel.Tracer("").Start(ctx, "envtool.testsRun")
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
done := make(chan struct{})
|
||||
|
||||
+62
-108
@@ -12,17 +12,16 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package main is the entry point for FerretDB server.
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"expvar"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
runtimedebug "runtime/debug"
|
||||
@@ -34,15 +33,11 @@ import (
|
||||
"github.com/alecthomas/kong"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/expfmt"
|
||||
"go.uber.org/automaxprocs/maxprocs"
|
||||
_ "golang.org/x/crypto/x509roots/fallback" // register root TLS certificates for production Docker image
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/build/version"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/clientconn"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/clientconn/connmetrics"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/dataapi"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/documentdb"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/handler"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/handler/middleware"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/ctxutil"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/debug"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/devbuild"
|
||||
@@ -50,6 +45,7 @@ import (
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/logging"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/must"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/observability"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/setup"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/state"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/telemetry"
|
||||
)
|
||||
@@ -78,6 +74,7 @@ var cli struct {
|
||||
TLSKeyFile string `default:"" help:"TLS key file path."`
|
||||
TLSCaFile string `default:"" help:"TLS CA file path."`
|
||||
DataAPIAddr string `default:"" help:"Listen TCP address for HTTP Data API."`
|
||||
MCPAddr string `default:"" help:"Listen TCP address for HTTP MCP server."`
|
||||
} `embed:"" prefix:"listen-" group:"Interfaces"`
|
||||
|
||||
Proxy struct {
|
||||
@@ -102,7 +99,8 @@ var cli struct {
|
||||
MetricsUUID bool `default:"false" help:"Add instance UUID to all metrics." group:"Miscellaneous" negatable:""`
|
||||
|
||||
OTel struct {
|
||||
Traces struct {
|
||||
ServiceName string `default:"ferretdb" help:"OpenTelemetry service name."`
|
||||
Traces struct {
|
||||
URL string `default:"" help:"OpenTelemetry OTLP/HTTP traces endpoint URL (e.g. 'http://host:4318/v1/traces')."`
|
||||
} `embed:"" prefix:"traces-"`
|
||||
} `embed:"" prefix:"otel-" group:"Miscellaneous"`
|
||||
@@ -137,14 +135,14 @@ var (
|
||||
kongOptions = []kong.Option{
|
||||
kong.Vars{
|
||||
"default_log_level": defaultLogLevel().String(),
|
||||
"default_mode": clientconn.AllModes[0],
|
||||
"default_mode": middleware.AllModes[0],
|
||||
|
||||
"enum_log_format": strings.Join(logFormats, ","),
|
||||
"enum_mode": strings.Join(clientconn.AllModes, ","),
|
||||
"enum_mode": strings.Join(middleware.AllModes, ","),
|
||||
|
||||
"help_log_format": fmt.Sprintf("Log format: '%s'.", strings.Join(logFormats, "', '")),
|
||||
"help_log_level": fmt.Sprintf("Log level: '%s'.", strings.Join(logLevels, "', '")),
|
||||
"help_mode": fmt.Sprintf("Operation mode: '%s'.", strings.Join(clientconn.AllModes, "', '")),
|
||||
"help_mode": fmt.Sprintf("Operation mode: '%s'.", strings.Join(middleware.AllModes, "', '")),
|
||||
"help_telemetry": "Enable or disable basic telemetry reporting. See https://beacon.ferretdb.com.",
|
||||
},
|
||||
kong.DefaultEnvars("FERRETDB"),
|
||||
@@ -248,7 +246,23 @@ func setupDefaultLogger(format string, uuid string) *slog.Logger {
|
||||
}
|
||||
|
||||
// checkFlags checks that CLI flags are not self-contradictory and produces warnings if needed.
|
||||
// It also replaces "-" with "" for some flags to make it easier to configure FerretDB with environment variables.
|
||||
func checkFlags(logger *slog.Logger) {
|
||||
// keep in sync with documentation
|
||||
for _, p := range []*string{
|
||||
&cli.Listen.Addr,
|
||||
&cli.Listen.Unix,
|
||||
&cli.Listen.TLS,
|
||||
&cli.Listen.DataAPIAddr,
|
||||
&cli.Listen.MCPAddr,
|
||||
&cli.DebugAddr,
|
||||
&cli.OTel.Traces.URL,
|
||||
} {
|
||||
if *p == "-" {
|
||||
*p = ""
|
||||
}
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
if devbuild.Enabled {
|
||||
@@ -262,6 +276,13 @@ func checkFlags(logger *slog.Logger) {
|
||||
if !cli.Auth {
|
||||
logger.WarnContext(ctx, "Authentication is disabled; the server will accept any connection")
|
||||
}
|
||||
|
||||
if cli.Auth && cli.Listen.MCPAddr != "" {
|
||||
logger.Log(
|
||||
ctx, logging.LevelFatal,
|
||||
"MCP server does not support authentication; please disable authentication or MCP server",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// dumpMetrics dumps all Prometheus metrics to stderr.
|
||||
@@ -352,19 +373,6 @@ func run() {
|
||||
|
||||
checkFlags(logger)
|
||||
|
||||
maxprocsOpts := []maxprocs.Option{
|
||||
maxprocs.Min(2),
|
||||
maxprocs.RoundQuotaFunc(func(v float64) int {
|
||||
return int(math.Ceil(v))
|
||||
}),
|
||||
maxprocs.Logger(func(format string, a ...any) {
|
||||
logger.Info(fmt.Sprintf(format, a...))
|
||||
}),
|
||||
}
|
||||
if _, err = maxprocs.Set(maxprocsOpts...); err != nil {
|
||||
logger.Warn("Failed to set GOMAXPROCS", logging.Error(err))
|
||||
}
|
||||
|
||||
ctx, stop := ctxutil.SigTerm(context.Background())
|
||||
|
||||
go func() {
|
||||
@@ -380,7 +388,7 @@ func run() {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
if cmp.Or(cli.DebugAddr, "-") != "-" {
|
||||
if cli.DebugAddr != "" {
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
@@ -409,11 +417,11 @@ func run() {
|
||||
l.LogAttrs(ctx, logging.LevelFatal, "Failed to create debug handler", logging.Error(e))
|
||||
}
|
||||
|
||||
h.Serve(ctx)
|
||||
h.Run(ctx)
|
||||
}()
|
||||
}
|
||||
|
||||
if cmp.Or(cli.OTel.Traces.URL, "-") != "-" {
|
||||
if cli.OTel.Traces.URL != "" {
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
@@ -423,9 +431,8 @@ func run() {
|
||||
|
||||
ot, e := observability.NewOTelTraceExporter(&observability.OTelTraceExporterOpts{
|
||||
Logger: l,
|
||||
Service: "ferretdb",
|
||||
Version: version.Get().Version,
|
||||
URL: cli.OTel.Traces.URL,
|
||||
Service: cli.OTel.ServiceName,
|
||||
})
|
||||
if e != nil {
|
||||
l.LogAttrs(ctx, logging.LevelFatal, "Failed to create Otel tracer", logging.Error(e))
|
||||
@@ -435,7 +442,7 @@ func run() {
|
||||
}()
|
||||
}
|
||||
|
||||
lm := connmetrics.NewListenerMetrics()
|
||||
mm := middleware.NewMetrics()
|
||||
|
||||
{
|
||||
wg.Add(1)
|
||||
@@ -452,7 +459,7 @@ func run() {
|
||||
DNT: os.Getenv("DO_NOT_TRACK"),
|
||||
ExecName: os.Args[0],
|
||||
P: stateProvider,
|
||||
ConnMetrics: lm.ConnMetrics,
|
||||
Metrics: mm,
|
||||
L: l,
|
||||
UndecidedDelay: cli.Dev.Telemetry.UndecidedDelay,
|
||||
ReportInterval: cli.Dev.Telemetry.ReportInterval,
|
||||
@@ -465,97 +472,44 @@ func run() {
|
||||
}()
|
||||
}
|
||||
|
||||
p, err := documentdb.NewPool(cli.PostgreSQLURL, logging.WithName(logger, "pool"), stateProvider)
|
||||
if err != nil {
|
||||
logger.LogAttrs(ctx, logging.LevelFatal, "Failed to construct pool", logging.Error(err))
|
||||
}
|
||||
|
||||
tcpAddr := cli.Listen.Addr
|
||||
if cmp.Or(tcpAddr, "-") == "-" {
|
||||
tcpAddr = ""
|
||||
}
|
||||
|
||||
unixAddr := cli.Listen.Unix
|
||||
if cmp.Or(unixAddr, "-") == "-" {
|
||||
unixAddr = ""
|
||||
}
|
||||
|
||||
tlsAddr := cli.Listen.TLS
|
||||
if cmp.Or(tlsAddr, "-") == "-" {
|
||||
tlsAddr = ""
|
||||
}
|
||||
|
||||
handlerOpts := &handler.NewOpts{
|
||||
Pool: p,
|
||||
Auth: cli.Auth,
|
||||
|
||||
TCPHost: tcpAddr,
|
||||
ReplSetName: cli.Dev.ReplSetName,
|
||||
|
||||
L: logging.WithName(logger, "handler"),
|
||||
ConnMetrics: lm.ConnMetrics,
|
||||
//exhaustruct:enforce
|
||||
res := setup.Setup(ctx, &setup.SetupOpts{
|
||||
Logger: logger,
|
||||
StateProvider: stateProvider,
|
||||
}
|
||||
Metrics: mm,
|
||||
|
||||
h, err := handler.New(handlerOpts)
|
||||
if err != nil {
|
||||
p.Close()
|
||||
handlerOpts.L.LogAttrs(ctx, logging.LevelFatal, "Failed to construct handler", logging.Error(err))
|
||||
}
|
||||
PostgreSQLURL: cli.PostgreSQLURL,
|
||||
Auth: cli.Auth,
|
||||
ReplSetName: cli.Dev.ReplSetName,
|
||||
SessionCleanupInterval: 0,
|
||||
|
||||
lis, err := clientconn.Listen(&clientconn.ListenerOpts{
|
||||
Handler: h,
|
||||
Metrics: lm,
|
||||
Logger: logger,
|
||||
|
||||
TCP: tcpAddr,
|
||||
Unix: unixAddr,
|
||||
|
||||
TLS: tlsAddr,
|
||||
TLSCertFile: cli.Listen.TLSCertFile,
|
||||
TLSKeyFile: cli.Listen.TLSKeyFile,
|
||||
TLSCAFile: cli.Listen.TLSCaFile,
|
||||
|
||||
Mode: clientconn.Mode(cli.Mode),
|
||||
ProxyAddr: cli.Proxy.Addr,
|
||||
ProxyTLSCertFile: cli.Proxy.TLSCertFile,
|
||||
ProxyTLSKeyFile: cli.Proxy.TLSKeyFile,
|
||||
ProxyTLSCAFile: cli.Proxy.TLSCaFile,
|
||||
|
||||
TCPAddr: cli.Listen.Addr,
|
||||
UnixAddr: cli.Listen.Unix,
|
||||
TLSAddr: cli.Listen.TLS,
|
||||
TLSCertFile: cli.Listen.TLSCertFile,
|
||||
TLSKeyFile: cli.Listen.TLSKeyFile,
|
||||
TLSCAFile: cli.Listen.TLSCaFile,
|
||||
Mode: middleware.Mode(cli.Mode),
|
||||
TestRecordsDir: cli.Dev.RecordsDir,
|
||||
|
||||
DataAPIAddr: cli.Listen.DataAPIAddr,
|
||||
|
||||
MCPAddr: cli.Listen.MCPAddr,
|
||||
})
|
||||
if err != nil {
|
||||
p.Close()
|
||||
logger.LogAttrs(ctx, logging.LevelFatal, "Failed to construct listener", logging.Error(err))
|
||||
if res == nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if cmp.Or(cli.Listen.DataAPIAddr, "-") != "-" {
|
||||
wg.Add(1)
|
||||
listener.Store(res.WireListener)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
metricsRegisterer.MustRegister(res)
|
||||
|
||||
l := logging.WithName(logger, "dataapi")
|
||||
|
||||
lis, e := dataapi.Listen(&dataapi.ListenOpts{
|
||||
TCPAddr: cli.Listen.DataAPIAddr,
|
||||
L: l,
|
||||
Handler: h,
|
||||
})
|
||||
if e != nil {
|
||||
p.Close()
|
||||
l.LogAttrs(ctx, logging.LevelFatal, "Failed to construct DataAPI listener", logging.Error(e))
|
||||
}
|
||||
|
||||
lis.Run(ctx)
|
||||
}()
|
||||
}
|
||||
|
||||
listener.Store(lis)
|
||||
|
||||
metricsRegisterer.MustRegister(lis)
|
||||
|
||||
lis.Run(ctx)
|
||||
res.Run(ctx)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestVersion(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(testutil.Ctx(t), 5*time.Second)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
bin := filepath.Join("..", "..", "bin", "ferretdb")
|
||||
bin := filepath.Join(testutil.BinDir, "ferretdb")
|
||||
|
||||
cmd := exec.CommandContext(ctx, bin, "--version")
|
||||
b, err := cmd.Output()
|
||||
|
||||
+10
-5
@@ -15,7 +15,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
@@ -39,7 +38,7 @@ type ReadyZ struct {
|
||||
func (r *ReadyZ) Probe(ctx context.Context) bool {
|
||||
var urls []string
|
||||
|
||||
if cmp.Or(cli.Listen.Addr, "-") != "-" {
|
||||
if cli.Listen.Addr != "" {
|
||||
host, port, err := net.SplitHostPort(cli.Listen.Addr)
|
||||
if err != nil {
|
||||
r.l.ErrorContext(ctx, "Getting host and port failed", logging.Error(err))
|
||||
@@ -59,12 +58,12 @@ func (r *ReadyZ) Probe(ctx context.Context) bool {
|
||||
urls = append(urls, u.String())
|
||||
}
|
||||
|
||||
if cmp.Or(cli.Listen.TLS, "-") != "-" {
|
||||
if cli.Listen.TLS != "" {
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/4427
|
||||
r.l.WarnContext(ctx, "TLS ping is not implemented yet")
|
||||
}
|
||||
|
||||
if cmp.Or(cli.Listen.Unix, "-") != "-" {
|
||||
if cli.Listen.Unix != "" {
|
||||
urls = append(urls, "mongodb://"+url.PathEscape(cli.Listen.Unix))
|
||||
}
|
||||
|
||||
@@ -76,7 +75,13 @@ func (r *ReadyZ) Probe(ctx context.Context) bool {
|
||||
for _, u := range urls {
|
||||
r.l.DebugContext(ctx, fmt.Sprintf("Pinging %s", u))
|
||||
|
||||
conn, err := wireclient.Connect(ctx, u, r.l)
|
||||
cleanUri, _, _, _, err := wireclient.Credentials(u)
|
||||
if err != nil {
|
||||
r.l.ErrorContext(ctx, "Getting credentials failed", logging.Error(err))
|
||||
return false
|
||||
}
|
||||
|
||||
conn, err := wireclient.Connect(ctx, cleanUri, r.l)
|
||||
if err != nil {
|
||||
r.l.ErrorContext(ctx, "Connection failed", logging.Error(err))
|
||||
return false
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
services:
|
||||
postgres:
|
||||
platform: linux/amd64
|
||||
+28
-2
@@ -20,12 +20,38 @@ services:
|
||||
environment:
|
||||
# UTC−03:30/−02:30. Set to catch timezone problems.
|
||||
- TZ=America/St_Johns
|
||||
- POSTGRES_USER=username
|
||||
- POSTGRES_PASSWORD=password
|
||||
- POSTGRES_USER=pg-user
|
||||
- POSTGRES_PASSWORD=pg-pass
|
||||
- POSTGRES_DB=postgres
|
||||
volumes:
|
||||
- ./build/testscripts:/testscripts
|
||||
|
||||
yugabytedb:
|
||||
build:
|
||||
context: ./build/deps
|
||||
dockerfile: yugabytedb.Dockerfile
|
||||
container_name: ferretdb_yugabytedb
|
||||
platform: linux/amd64 # TODO https://github.com/FerretDB/FerretDB/issues/5369
|
||||
# postgresql.conf is populated by "ysql_pg_conf_csv" flag
|
||||
# https://docs.yugabyte.com/preview/reference/configuration/yugabyted/#pass-additional-flags-to-yb-master-and-yb-tserver
|
||||
command: >
|
||||
bin/yugabyted start
|
||||
--background=false
|
||||
--initial_scripts_dir=/yugabytedb
|
||||
--ysql_enable_auth=true
|
||||
--master_flags="allowed_preview_flags_csv=ysql_enable_documentdb,ysql_enable_documentdb=true,enable_pg_cron=true,ysql_pg_conf_csv={documentdb.enableUserCrud = true,documentdb.maxUserLimit = 100}"
|
||||
--tserver_flags="allowed_preview_flags_csv=ysql_enable_documentdb,ysql_enable_documentdb=true,enable_pg_cron=true,ysql_pg_conf_csv={documentdb.enableUserCrud = true,documentdb.maxUserLimit = 100}"
|
||||
ports:
|
||||
- 5433:5433
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
environment:
|
||||
- YSQL_USER=pg-user # this user cannot authenticate against FerretDB
|
||||
- YSQL_PASSWORD=pg-pass
|
||||
- YSQL_DB=yugabyte # DocumentDB extension is installed in yugabyte database
|
||||
volumes:
|
||||
- ./build/yugabytedb/init.sql:/yugabytedb/init.sql
|
||||
|
||||
mongodb:
|
||||
build:
|
||||
context: ./build/deps
|
||||
|
||||
+47
-58
@@ -17,14 +17,11 @@
|
||||
// See [`build/version` package documentation]
|
||||
// for information about Go build tags that affect this package.
|
||||
//
|
||||
// # Telemetry
|
||||
//
|
||||
// Please note that the current version of the embeddable package does not allow [telemetry] configuration –
|
||||
// it is always set to the `undecided` state. That limitation will be removed [in the future].
|
||||
// See [telemetry documentation] for basic anonymous usage data we collect.
|
||||
// You can set [Config]'s Telemetry field to disable or explicitly enable it.
|
||||
//
|
||||
// [`build/version` package documentation]: https://pkg.go.dev/github.com/FerretDB/FerretDB/v2/build/version
|
||||
// [telemetry]: https://docs.ferretdb.io/telemetry/
|
||||
// [in the future]: https://github.com/FerretDB/FerretDB/issues/4750
|
||||
// [telemetry documentation]: https://docs.ferretdb.io/telemetry/
|
||||
package ferretdb
|
||||
|
||||
import (
|
||||
@@ -38,11 +35,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/build/version"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/clientconn"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/clientconn/connmetrics"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/documentdb"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/handler"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/handler/middleware"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/logging"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/setup"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/state"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/telemetry"
|
||||
)
|
||||
@@ -67,26 +62,24 @@ type Config struct {
|
||||
|
||||
// Defaults to [io.Discard], effectively disabling logging.
|
||||
LogOutput io.Writer
|
||||
|
||||
// Defaults to undecided.
|
||||
// Set to `true` to enable telemetry, `false` to disable it.
|
||||
// See https://docs.ferretdb.io/telemetry/.
|
||||
Telemetry *bool
|
||||
}
|
||||
|
||||
// FerretDB represents an instance of embedded FerretDB implementation.
|
||||
type FerretDB struct {
|
||||
tl *telemetry.Reporter
|
||||
lis *clientconn.Listener
|
||||
tr *telemetry.Reporter
|
||||
res *setup.SetupResult
|
||||
}
|
||||
|
||||
// New creates a new instance of embedded FerretDB implementation.
|
||||
func New(config *Config) (*FerretDB, error) {
|
||||
version.Get().Package = "embedded"
|
||||
|
||||
sp, err := state.NewProviderDir(config.StateDir)
|
||||
if err == nil {
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/4750
|
||||
err = sp.Update(func(s *state.State) {
|
||||
s.TelemetryLocked = true
|
||||
})
|
||||
}
|
||||
|
||||
stateProvider, err := state.NewProviderDir(config.StateDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to set up state provider: %w", err)
|
||||
}
|
||||
@@ -111,16 +104,16 @@ func New(config *Config) (*FerretDB, error) {
|
||||
}
|
||||
logger := logging.WithName(logging.Logger(logOutput, lOpts, ""), "ferretdb")
|
||||
|
||||
lm := connmetrics.NewListenerMetrics()
|
||||
mm := middleware.NewMetrics()
|
||||
|
||||
tr, err := telemetry.NewReporter(&telemetry.NewReporterOpts{
|
||||
URL: "https://beacon.ferretdb.com/",
|
||||
Dir: config.StateDir,
|
||||
F: new(telemetry.Flag),
|
||||
F: telemetry.NewFlag(config.Telemetry),
|
||||
DNT: os.Getenv("DO_NOT_TRACK"),
|
||||
ExecName: os.Args[0],
|
||||
P: sp,
|
||||
ConnMetrics: lm.ConnMetrics,
|
||||
P: stateProvider,
|
||||
Metrics: mm,
|
||||
L: logging.WithName(logger, "telemetry"),
|
||||
UndecidedDelay: time.Hour,
|
||||
ReportInterval: 24 * time.Hour,
|
||||
@@ -129,46 +122,42 @@ func New(config *Config) (*FerretDB, error) {
|
||||
return nil, fmt.Errorf("failed to create telemetry reporter: %w", err)
|
||||
}
|
||||
|
||||
p, err := documentdb.NewPool(config.PostgreSQLURL, logging.WithName(logger, "pool"), sp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct pool: %w", err)
|
||||
}
|
||||
//exhaustruct:enforce
|
||||
res := setup.Setup(context.TODO(), &setup.SetupOpts{
|
||||
Logger: logger,
|
||||
StateProvider: stateProvider,
|
||||
Metrics: mm,
|
||||
|
||||
handlerOpts := &handler.NewOpts{
|
||||
Pool: p,
|
||||
Auth: false,
|
||||
PostgreSQLURL: config.PostgreSQLURL,
|
||||
Auth: false,
|
||||
ReplSetName: "",
|
||||
SessionCleanupInterval: 0,
|
||||
|
||||
TCPHost: "",
|
||||
ReplSetName: "",
|
||||
ProxyAddr: "",
|
||||
ProxyTLSCertFile: "",
|
||||
ProxyTLSKeyFile: "",
|
||||
ProxyTLSCAFile: "",
|
||||
|
||||
L: logging.WithName(logger, "handler"),
|
||||
ConnMetrics: lm.ConnMetrics,
|
||||
StateProvider: sp,
|
||||
}
|
||||
TCPAddr: config.ListenAddr,
|
||||
UnixAddr: "",
|
||||
TLSAddr: "",
|
||||
TLSCertFile: "",
|
||||
TLSKeyFile: "",
|
||||
TLSCAFile: "",
|
||||
Mode: middleware.NormalMode,
|
||||
TestRecordsDir: "",
|
||||
|
||||
h, err := handler.New(handlerOpts)
|
||||
if err != nil {
|
||||
p.Close()
|
||||
return nil, fmt.Errorf("failed to construct handler: %w", err)
|
||||
}
|
||||
DataAPIAddr: "",
|
||||
|
||||
lis, err := clientconn.Listen(&clientconn.ListenerOpts{
|
||||
Handler: h,
|
||||
Metrics: lm,
|
||||
Logger: logger,
|
||||
|
||||
TCP: config.ListenAddr,
|
||||
|
||||
Mode: clientconn.NormalMode,
|
||||
MCPAddr: "",
|
||||
})
|
||||
if err != nil {
|
||||
p.Close()
|
||||
return nil, fmt.Errorf("failed to construct listener: %w", err)
|
||||
if res == nil {
|
||||
return nil, fmt.Errorf("failed to create FerretDB")
|
||||
}
|
||||
|
||||
return &FerretDB{
|
||||
tl: tr,
|
||||
lis: lis,
|
||||
tr: tr,
|
||||
res: res,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -185,14 +174,14 @@ func (f *FerretDB) Run(ctx context.Context) {
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
f.tl.Run(ctx)
|
||||
f.tr.Run(ctx)
|
||||
}()
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
f.lis.Run(ctx)
|
||||
f.res.Run(ctx)
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
@@ -202,7 +191,7 @@ func (f *FerretDB) Run(ctx context.Context) {
|
||||
func (f *FerretDB) MongoDBURI() string {
|
||||
u := &url.URL{
|
||||
Scheme: "mongodb",
|
||||
Host: f.lis.TCPAddr().String(),
|
||||
Host: f.res.WireListener.TCPAddr().String(),
|
||||
Path: "/",
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ func TestFerretDB(t *testing.T) {
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
StateDir: t.TempDir(),
|
||||
LogLevel: slog.LevelDebug,
|
||||
LogOutput: testutil.NewLogWriter(t),
|
||||
LogOutput: t.Output(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -1,68 +1,73 @@
|
||||
module github.com/FerretDB/FerretDB/v2
|
||||
|
||||
go 1.24
|
||||
go 1.25
|
||||
|
||||
toolchain go1.24.3
|
||||
toolchain go1.25.4
|
||||
|
||||
// replace github.com/FerretDB/wire => ../wire
|
||||
|
||||
require (
|
||||
github.com/AlekSi/lazyerrors v0.0.0-20251102120325-67e66cc79778
|
||||
github.com/AlekSi/pointer v1.2.0
|
||||
github.com/FerretDB/wire v0.0.24
|
||||
github.com/alecthomas/kong v1.10.0
|
||||
github.com/arl/statsviz v0.6.0
|
||||
github.com/FerretDB/wire v0.1.7
|
||||
github.com/alecthomas/kong v1.12.1
|
||||
github.com/arl/statsviz v0.7.2
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438
|
||||
github.com/jackc/pgx/v5 v5.7.4
|
||||
github.com/oapi-codegen/runtime v1.1.1
|
||||
github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6
|
||||
github.com/jackc/pgx/v5 v5.7.6
|
||||
github.com/modelcontextprotocol/go-sdk v0.2.0
|
||||
github.com/oapi-codegen/runtime v1.1.2
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/prometheus/client_golang v1.21.1
|
||||
github.com/prometheus/client_model v0.6.1
|
||||
github.com/prometheus/common v0.63.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/prometheus/client_model v0.6.2
|
||||
github.com/prometheus/common v0.67.2
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/xdg-go/scram v1.1.2
|
||||
go.mongodb.org/mongo-driver/v2 v2.2.0
|
||||
go.opentelemetry.io/otel v1.35.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0
|
||||
go.opentelemetry.io/otel/sdk v1.35.0
|
||||
go.opentelemetry.io/otel/trace v1.35.0
|
||||
go.uber.org/automaxprocs v1.6.0
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250406160420-959f8f3db0fb
|
||||
golang.org/x/net v0.39.0
|
||||
golang.org/x/sys v0.32.0
|
||||
golang.org/x/term v0.31.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0
|
||||
go.opentelemetry.io/otel v1.38.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0
|
||||
go.opentelemetry.io/otel/sdk v1.38.0
|
||||
go.opentelemetry.io/otel/trace v1.38.0
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20251028130051-c0531f9c3451
|
||||
golang.org/x/net v0.46.0
|
||||
golang.org/x/sys v0.38.0
|
||||
golang.org/x/term v0.36.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.3 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.4 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
google.golang.org/grpc v1.71.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
golang.org/x/crypto v0.43.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/grpc v1.75.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -1,31 +1,33 @@
|
||||
github.com/AlekSi/lazyerrors v0.0.0-20251102120325-67e66cc79778 h1:Hv1Z0ZnUWI1NYHXKUE16SWUcv+VyFARJHQ6dGkd2TIM=
|
||||
github.com/AlekSi/lazyerrors v0.0.0-20251102120325-67e66cc79778/go.mod h1:S8uLHjY/2pJvG9qkWwDX1AVYYknPI92r2qh/f0uysr0=
|
||||
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
|
||||
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
|
||||
github.com/FerretDB/wire v0.0.24 h1:UI4K50cSlfTO2uXnUuX+9OVRRoWUSVdbBbECTS2FRKU=
|
||||
github.com/FerretDB/wire v0.0.24/go.mod h1:TGo7jrzJkJjug8KVSOc3W/eyEUzcBym81D3MOEnyzOc=
|
||||
github.com/FerretDB/wire v0.1.7 h1:yh6tL0rU8ub+KuKqiqTlFJGpdfL4V7kg/8PBPDX0sBE=
|
||||
github.com/FerretDB/wire v0.1.7/go.mod h1:KjV8URsECCZWwJBBzlTvyl9LEXvnE362tL4tg52VHXI=
|
||||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/kong v1.10.0 h1:8K4rGDpT7Iu+jEXCIJUeKqvpwZHbsFRoebLbnzlmrpw=
|
||||
github.com/alecthomas/kong v1.10.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
|
||||
github.com/alecthomas/kong v1.12.1 h1:iq6aMJDcFYP9uFrLdsiZQ2ZMmcshduyGv4Pek0MQPW0=
|
||||
github.com/alecthomas/kong v1.12.1/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||
github.com/arl/statsviz v0.6.0 h1:jbW1QJkEYQkufd//4NDYRSNBpwJNrdzPahF7ZmoGdyE=
|
||||
github.com/arl/statsviz v0.6.0/go.mod h1:0toboo+YGSUXDaS4g1D5TVS4dXs7S7YYT5J/qnW2h8s=
|
||||
github.com/arl/statsviz v0.7.2 h1:xnuIfRiXE4kvxEcfGL+IE3mKH1BXNHuE+eJELIh7oOA=
|
||||
github.com/arl/statsviz v0.7.2/go.mod h1:XlrbiT7xYT03xaW9JMMfD8KFUhBOESJwfyNJu83PbB0=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
@@ -36,137 +38,141 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438 h1:Dj0L5fhJ9F82ZJyVOmBx6msDp/kfd1t9GRfny/mfJA0=
|
||||
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
|
||||
github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6 h1:D/V0gu4zQ3cL2WKeVNVM4r2gLxGGf6McLwgXzRTo2RQ=
|
||||
github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
|
||||
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
|
||||
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
||||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||
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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/modelcontextprotocol/go-sdk v0.2.0 h1:PESNYOmyM1c369tRkzXLY5hHrazj8x9CY1Xu0fLCryM=
|
||||
github.com/modelcontextprotocol/go-sdk v0.2.0/go.mod h1:0sL9zUKKs2FTTkeCCVnKqbLJTw5TScefPAzojjU459E=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
|
||||
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||
github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI=
|
||||
github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
||||
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
|
||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyAEN8=
|
||||
github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
|
||||
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||
go.mongodb.org/mongo-driver/v2 v2.2.0 h1:WwhNgGrijwU56ps9RtIsgKfGLEZeypxqbEYfThrBScM=
|
||||
go.mongodb.org/mongo-driver/v2 v2.2.0/go.mod h1:qQkDMhCGWl3FN509DfdPd4GRBLU/41zqF/k8eTRceps=
|
||||
go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
|
||||
go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0 h1:Oq6BmUAAFTzMeh6AonuDlgZMuAuEiUxoAD1koK5MuFo=
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
||||
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250406160420-959f8f3db0fb h1:Iu0p/klM0SM7atONioa/bPhLS7cjhnip99x1OIGibwg=
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250406160420-959f8f3db0fb/go.mod h1:lxN5T34bK4Z/i6cMaU7frUU57VkDXFD4Kamfl/cp9oU=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20251028130051-c0531f9c3451 h1:ntT/VrHMoSyusO9qDIYKxtkMfluoOkLrr6AJfVRROsE=
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20251028130051-c0531f9c3451/go.mod h1:MEIPiCnxvQEjA4astfaKItNwEVZA5Ki+3+nyGbJ5N18=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
|
||||
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
|
||||
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
|
||||
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -107,7 +107,7 @@ linters-settings:
|
||||
alias: otelsdkresource
|
||||
- pkg: go.opentelemetry.io/otel/sdk/trace
|
||||
alias: otelsdktrace
|
||||
- pkg: go.opentelemetry.io/otel/semconv/v1.21.0
|
||||
- pkg: go.opentelemetry.io/otel/semconv/v1.34.0
|
||||
alias: otelsemconv
|
||||
# ineffassign
|
||||
lll:
|
||||
|
||||
@@ -1619,12 +1619,14 @@ func TestAggregateCompatSort(t *testing.T) {
|
||||
}}}},
|
||||
},
|
||||
|
||||
"DotNotationIndex": {
|
||||
pipeline: bson.A{bson.D{{"$sort", bson.D{
|
||||
{"v.0", 1},
|
||||
{"_id", 1}, // sort by _id when v is the same.
|
||||
}}}},
|
||||
},
|
||||
// TODO https://github.com/FerretDB/FerretDB-DocumentDB/issues/355
|
||||
// "DotNotationIndex": {
|
||||
// pipeline: bson.A{bson.D{{"$sort", bson.D{
|
||||
// {"v.0", 1},
|
||||
// {"_id", 1}, // sort by _id when v is the same.
|
||||
// }}}},
|
||||
// },
|
||||
|
||||
"DotNotationNonExistent": {
|
||||
pipeline: bson.A{bson.D{{"$sort", bson.D{
|
||||
{"invalid.foo", 1},
|
||||
|
||||
@@ -1327,6 +1327,7 @@ func TestAggregateCommandCursor(t *testing.T) {
|
||||
Name: "FailedToParse",
|
||||
Message: "The 'cursor' option is required, except for aggregate with the explain argument",
|
||||
},
|
||||
altMessage: "The 'cursor' option is required, except for aggregate with explain",
|
||||
},
|
||||
"Empty": {
|
||||
cursor: bson.D{},
|
||||
|
||||
@@ -148,10 +148,10 @@ func TestCreateUserCommand(t *testing.T) {
|
||||
},
|
||||
"MissingPwdOrExternal": {
|
||||
payload: bson.D{
|
||||
{"createUser", "mising_pwd_or_external"},
|
||||
{"createUser", "missing_pwd_or_external"},
|
||||
{"roles", bson.A{}},
|
||||
},
|
||||
user: "mising_pwd_or_external",
|
||||
user: "missing_pwd_or_external",
|
||||
err: &mongo.CommandError{
|
||||
Code: 2,
|
||||
Name: "BadValue",
|
||||
@@ -178,7 +178,7 @@ func TestCreateUserCommand(t *testing.T) {
|
||||
{Key: "serverKey"},
|
||||
}},
|
||||
},
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/939",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5313",
|
||||
},
|
||||
"SuccessWithSCRAMSHA256": {
|
||||
payload: bson.D{
|
||||
@@ -200,7 +200,7 @@ func TestCreateUserCommand(t *testing.T) {
|
||||
{Key: "serverKey"},
|
||||
}},
|
||||
},
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/939",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5313",
|
||||
},
|
||||
"WithComment": {
|
||||
payload: bson.D{
|
||||
@@ -222,7 +222,7 @@ func TestCreateUserCommand(t *testing.T) {
|
||||
{Key: "serverKey"},
|
||||
}},
|
||||
},
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/939",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5313",
|
||||
},
|
||||
"MissingRoles": {
|
||||
payload: bson.D{
|
||||
|
||||
@@ -57,14 +57,14 @@ func TestDropUserCommand(t *testing.T) {
|
||||
Name: "UserNotFound",
|
||||
Message: fmt.Sprintf("User 'not_found_user@%s' not found", db.Name()),
|
||||
},
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/942",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5323",
|
||||
},
|
||||
"Success": {
|
||||
username: "a_user",
|
||||
expected: bson.D{
|
||||
{"ok", float64(1)},
|
||||
},
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/939",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5313",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ func TestUpdateUserCommand(t *testing.T) {
|
||||
}}},
|
||||
{"ok", float64(1)},
|
||||
},
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/939",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5313",
|
||||
},
|
||||
"PasswordChange": {
|
||||
username: "a_user",
|
||||
@@ -165,7 +165,7 @@ func TestUpdateUserCommand(t *testing.T) {
|
||||
}}},
|
||||
{"ok", float64(1)},
|
||||
},
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/939",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5313",
|
||||
},
|
||||
"PasswordChangeWithSCRAMMechanism": {
|
||||
username: "a_user_with_scram_mechanism",
|
||||
@@ -241,7 +241,7 @@ func TestUpdateUserCommand(t *testing.T) {
|
||||
}}},
|
||||
{"ok", float64(1)},
|
||||
},
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/939",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5313",
|
||||
},
|
||||
"InvalidRoles": {
|
||||
username: "invalid_roles",
|
||||
|
||||
@@ -205,7 +205,7 @@ func TestUsersInfoCommand(t *testing.T) {
|
||||
// TODO https://github.com/FerretDB/FerretDB-DocumentDB/issues/864
|
||||
// TODO https://github.com/FerretDB/FerretDB-DocumentDB/issues/961
|
||||
// TODO https://github.com/FerretDB/FerretDB-DocumentDB/issues/962
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/939",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5313",
|
||||
},
|
||||
"WithSCRAMSHA256": {
|
||||
dbName: dbNames.E,
|
||||
@@ -234,7 +234,7 @@ func TestUsersInfoCommand(t *testing.T) {
|
||||
}},
|
||||
{"ok", float64(1)},
|
||||
},
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/939",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5313",
|
||||
},
|
||||
"FromSameDatabase": {
|
||||
dbName: dbNames.B,
|
||||
@@ -467,7 +467,7 @@ func TestUsersInfoCommand(t *testing.T) {
|
||||
}},
|
||||
{"ok", float64(1)},
|
||||
},
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/939",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB/issues/5313",
|
||||
},
|
||||
"SingleDatabaseLong": {
|
||||
dbName: "no_users",
|
||||
|
||||
+100
-97
@@ -272,12 +272,12 @@ func TestSASLContinueErrors(t *testing.T) {
|
||||
conv := client.NewConversation()
|
||||
payload := must.NotFail(conv.Step(""))
|
||||
|
||||
msg := must.NotFail(wire.NewOpMsg(must.NotFail(must.NotFail(wirebson.NewDocument(
|
||||
msg := wire.MustOpMsg(
|
||||
"saslStart", int32(1),
|
||||
"mechanism", "SCRAM-SHA-256",
|
||||
"payload", wirebson.Binary{B: []byte(payload)},
|
||||
"$db", "admin",
|
||||
)).Encode())))
|
||||
)
|
||||
|
||||
var resBody wire.MsgBody
|
||||
_, resBody, err = conn.Request(ctx, msg)
|
||||
@@ -296,23 +296,23 @@ func TestSASLContinueErrors(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"conversationId", int32(1),
|
||||
"done", false,
|
||||
"payload", wirebson.Binary{},
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
|
||||
payload = "invalid"
|
||||
|
||||
msg = must.NotFail(wire.NewOpMsg(must.NotFail(must.NotFail(wirebson.NewDocument(
|
||||
msg = wire.MustOpMsg(
|
||||
"saslContinue", int32(1),
|
||||
"conversationId", int32(1),
|
||||
"payload", wirebson.Binary{B: []byte(payload)},
|
||||
"$db", "admin",
|
||||
)).Encode())))
|
||||
)
|
||||
|
||||
_, resBody, err = conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
@@ -322,21 +322,21 @@ func TestSASLContinueErrors(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expected = must.NotFail(wirebson.NewDocument(
|
||||
expected = wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Authentication failed.",
|
||||
"code", int32(18),
|
||||
"codeName", "AuthenticationFailed",
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
|
||||
msg = must.NotFail(wire.NewOpMsg(must.NotFail(must.NotFail(wirebson.NewDocument(
|
||||
msg = wire.MustOpMsg(
|
||||
"saslContinue", int32(1),
|
||||
"conversationId", int32(1),
|
||||
"payload", wirebson.Binary{},
|
||||
"$db", "admin",
|
||||
)).Encode())))
|
||||
)
|
||||
|
||||
_, resBody, err = conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
@@ -346,21 +346,21 @@ func TestSASLContinueErrors(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expected = must.NotFail(wirebson.NewDocument(
|
||||
expected = wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "No SASL session state found",
|
||||
"code", int32(17),
|
||||
"codeName", "ProtocolError",
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
})
|
||||
|
||||
t.Run("NoAuthenticatedUser", func(t *testing.T) {
|
||||
msg := must.NotFail(wire.NewOpMsg(must.NotFail(must.NotFail(wirebson.NewDocument(
|
||||
msg := wire.MustOpMsg(
|
||||
"connectionStatus", int64(1),
|
||||
"$db", testutil.DatabaseName(t),
|
||||
)).Encode())))
|
||||
)
|
||||
|
||||
var resBody wire.MsgBody
|
||||
_, resBody, err = conn.Request(ctx, msg)
|
||||
@@ -372,23 +372,23 @@ func TestSASLContinueErrors(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
"authInfo", must.NotFail(wirebson.NewDocument(
|
||||
"authenticatedUsers", wirebson.MakeArray(0),
|
||||
"authenticatedUserRoles", wirebson.MakeArray(0),
|
||||
)),
|
||||
expected := wirebson.MustDocument(
|
||||
"authInfo", wirebson.MustDocument(
|
||||
"authenticatedUsers", wirebson.MustArray(),
|
||||
"authenticatedUserRoles", wirebson.MustArray(),
|
||||
),
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
})
|
||||
|
||||
t.Run("FindFails", func(t *testing.T) {
|
||||
msg := must.NotFail(wire.NewOpMsg(must.NotFail(must.NotFail(wirebson.NewDocument(
|
||||
msg := wire.MustOpMsg(
|
||||
"find", "values",
|
||||
"filter", must.NotFail(wirebson.NewDocument()),
|
||||
"filter", wirebson.MustDocument(),
|
||||
"$db", testutil.DatabaseName(t),
|
||||
)).Encode())))
|
||||
)
|
||||
|
||||
var resBody wire.MsgBody
|
||||
_, resBody, err = conn.Request(ctx, msg)
|
||||
@@ -400,12 +400,12 @@ func TestSASLContinueErrors(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Command find requires authentication",
|
||||
"code", int32(13),
|
||||
"codeName", "Unauthorized",
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
})
|
||||
@@ -420,12 +420,12 @@ func TestSASLContinueNoConversation(t *testing.T) {
|
||||
|
||||
ctx, conn := s.Ctx, s.WireConn
|
||||
|
||||
msg := must.NotFail(wire.NewOpMsg(must.NotFail(must.NotFail(wirebson.NewDocument(
|
||||
msg := wire.MustOpMsg(
|
||||
"saslContinue", int32(1),
|
||||
"conversationId", int32(1),
|
||||
"payload", wirebson.Binary{},
|
||||
"$db", "admin",
|
||||
)).Encode())))
|
||||
)
|
||||
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
@@ -435,12 +435,12 @@ func TestSASLContinueNoConversation(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "No SASL session state found",
|
||||
"code", int32(17),
|
||||
"codeName", "ProtocolError",
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
}
|
||||
@@ -551,12 +551,12 @@ func TestHelloIsMasterOpQuerySpeculative(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expectedComparable := must.NotFail(wirebson.NewDocument(
|
||||
expectedComparable := wirebson.MustDocument(
|
||||
"conversationId", int32(1),
|
||||
"done", true,
|
||||
"payload", serverPayload,
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expectedComparable, res)
|
||||
|
||||
@@ -585,12 +585,12 @@ func TestHelloIsMasterOpQuerySpeculative(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "No SASL session state found",
|
||||
"code", int32(17),
|
||||
"codeName", "ProtocolError",
|
||||
))
|
||||
)
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
})
|
||||
})
|
||||
@@ -729,28 +729,28 @@ func TestHelloSpeculative(t *testing.T) {
|
||||
// as is request sent by legacy Mongo shell
|
||||
msg := wire.MustOpMsg(
|
||||
"hello", int32(1),
|
||||
"speculativeAuthenticate", must.NotFail(wirebson.NewDocument(
|
||||
"speculativeAuthenticate", wirebson.MustDocument(
|
||||
"saslStart", int32(1),
|
||||
"mechanism", "SCRAM-SHA-256",
|
||||
"payload", wirebson.Binary{B: []byte(clientPayload)},
|
||||
"db", "admin",
|
||||
)),
|
||||
),
|
||||
"saslSupportedMechs", "admin."+username,
|
||||
"client", must.NotFail(wirebson.NewDocument(
|
||||
"application", must.NotFail(wirebson.NewDocument(
|
||||
"client", wirebson.MustDocument(
|
||||
"application", wirebson.MustDocument(
|
||||
"name", "MongoDB Shell",
|
||||
)),
|
||||
"driver", must.NotFail(wirebson.NewDocument(
|
||||
),
|
||||
"driver", wirebson.MustDocument(
|
||||
"name", "MongoDB Internal Client",
|
||||
"version", "7.0.8",
|
||||
)),
|
||||
"os", must.NotFail(wirebson.NewDocument(
|
||||
),
|
||||
"os", wirebson.MustDocument(
|
||||
"type", "Linux",
|
||||
"name", "Ubuntu",
|
||||
"architecture", "x86_64",
|
||||
"version", "22.04",
|
||||
)),
|
||||
)),
|
||||
),
|
||||
),
|
||||
"$db", "admin",
|
||||
)
|
||||
|
||||
@@ -794,7 +794,7 @@ func TestHelloSpeculative(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expectedComparable := must.NotFail(wirebson.NewDocument(
|
||||
expectedComparable := wirebson.MustDocument(
|
||||
"isWritablePrimary", true,
|
||||
"maxBsonObjectSize", int32(16777216),
|
||||
"maxMessageSizeBytes", int32(48000000),
|
||||
@@ -806,13 +806,13 @@ func TestHelloSpeculative(t *testing.T) {
|
||||
"maxWireVersion", int32(21),
|
||||
"readOnly", false,
|
||||
"saslSupportedMechs", saslSupportedMechs,
|
||||
"speculativeAuthenticate", must.NotFail(wirebson.NewDocument(
|
||||
"speculativeAuthenticate", wirebson.MustDocument(
|
||||
"conversationId", int32(1),
|
||||
"done", false,
|
||||
"payload", serverPayload,
|
||||
)),
|
||||
),
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expectedComparable, res)
|
||||
|
||||
@@ -833,7 +833,7 @@ func TestHelloSpeculative(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
var res *wirebson.Document
|
||||
res, err = must.NotFail(resBody.(*wire.OpMsg).RawDocument()).Decode()
|
||||
res, err = must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
serverPayload, ok := res.Get("payload").(wirebson.Binary)
|
||||
@@ -841,12 +841,12 @@ func TestHelloSpeculative(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expectedComparable := must.NotFail(wirebson.NewDocument(
|
||||
expectedComparable := wirebson.MustDocument(
|
||||
"conversationId", int32(1),
|
||||
"done", false,
|
||||
"payload", serverPayload,
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expectedComparable, res)
|
||||
|
||||
@@ -869,7 +869,7 @@ func TestHelloSpeculative(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
var res *wirebson.Document
|
||||
res, err = must.NotFail(resBody.(*wire.OpMsg).RawDocument()).Decode()
|
||||
res, err = must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
serverPayload, ok := res.Get("payload").(wirebson.Binary)
|
||||
@@ -877,12 +877,12 @@ func TestHelloSpeculative(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expectedComparable := must.NotFail(wirebson.NewDocument(
|
||||
expectedComparable := wirebson.MustDocument(
|
||||
"conversationId", int32(1),
|
||||
"done", true,
|
||||
"payload", serverPayload,
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expectedComparable, res)
|
||||
})
|
||||
@@ -900,17 +900,17 @@ func TestHelloSpeculative(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
var res *wirebson.Document
|
||||
res, err = must.NotFail(resBody.(*wire.OpMsg).RawDocument()).Decode()
|
||||
res, err = must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "No SASL session state found",
|
||||
"code", int32(17),
|
||||
"codeName", "ProtocolError",
|
||||
))
|
||||
)
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
})
|
||||
}
|
||||
@@ -1000,7 +1000,7 @@ func TestHelloOpQuerySASLSupportedMechs(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expectedComparable := must.NotFail(wirebson.NewDocument(
|
||||
expectedComparable := wirebson.MustDocument(
|
||||
"isWritablePrimary", true,
|
||||
"maxBsonObjectSize", int32(16777216),
|
||||
"maxMessageSizeBytes", int32(48000000),
|
||||
@@ -1010,13 +1010,13 @@ func TestHelloOpQuerySASLSupportedMechs(t *testing.T) {
|
||||
"maxWireVersion", int32(21),
|
||||
"readOnly", false,
|
||||
"saslSupportedMechs", saslSupportedMechs,
|
||||
"speculativeAuthenticate", must.NotFail(wirebson.NewDocument(
|
||||
"speculativeAuthenticate", wirebson.MustDocument(
|
||||
"conversationId", int32(1),
|
||||
"done", false,
|
||||
"payload", payloadAny,
|
||||
)),
|
||||
),
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expectedComparable, res)
|
||||
}
|
||||
@@ -1048,62 +1048,62 @@ func TestSASLStartOpQueryErrors(t *testing.T) {
|
||||
failsForFerretDB string
|
||||
}{
|
||||
"WrongAuthDB": {
|
||||
query: must.NotFail(wirebson.NewDocument(
|
||||
query: wirebson.MustDocument(
|
||||
"saslStart", int32(1),
|
||||
"mechanism", "SCRAM-SHA-256",
|
||||
"payload", wirebson.Binary{B: []byte(payload)},
|
||||
)),
|
||||
),
|
||||
fullCollectionName: "wrong-auth-db.$cmd",
|
||||
reply: must.NotFail(wirebson.NewDocument(
|
||||
reply: wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Authentication failed.",
|
||||
"code", int32(18),
|
||||
"codeName", "AuthenticationFailed",
|
||||
)),
|
||||
),
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/932",
|
||||
},
|
||||
"NotAllowed$db": {
|
||||
query: must.NotFail(wirebson.NewDocument(
|
||||
query: wirebson.MustDocument(
|
||||
"saslStart", int32(1),
|
||||
"mechanism", "SCRAM-SHA-256",
|
||||
"payload", wirebson.Binary{B: []byte(payload)},
|
||||
"$db", "admin",
|
||||
)),
|
||||
),
|
||||
fullCollectionName: "admin.$cmd",
|
||||
reply: must.NotFail(wirebson.NewDocument(
|
||||
reply: wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "$db is not allowed in OP_QUERY requests",
|
||||
"code", int32(40621),
|
||||
"codeName", "Location40621",
|
||||
)),
|
||||
),
|
||||
},
|
||||
"InvalidPayload": {
|
||||
query: must.NotFail(wirebson.NewDocument(
|
||||
query: wirebson.MustDocument(
|
||||
"saslStart", int32(1),
|
||||
"mechanism", "SCRAM-SHA-256",
|
||||
"payload", wirebson.Binary{B: []byte("invalid")},
|
||||
)),
|
||||
),
|
||||
fullCollectionName: "admin.$cmd",
|
||||
reply: must.NotFail(wirebson.NewDocument(
|
||||
reply: wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Authentication failed.",
|
||||
"code", int32(18),
|
||||
"codeName", "AuthenticationFailed",
|
||||
)),
|
||||
),
|
||||
},
|
||||
"UnsupportedMechanism": {
|
||||
query: must.NotFail(wirebson.NewDocument(
|
||||
query: wirebson.MustDocument(
|
||||
"saslStart", int32(1),
|
||||
"mechanism", "UNKNOWN-MECHANISM",
|
||||
"payload", wirebson.Binary{B: []byte(payload)},
|
||||
)),
|
||||
),
|
||||
fullCollectionName: "admin.$cmd",
|
||||
reply: must.NotFail(wirebson.NewDocument(
|
||||
reply: wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Received authentication for mechanism UNKNOWN-MECHANISM which is not enabled",
|
||||
"code", int32(334),
|
||||
"codeName", "MechanismUnavailable",
|
||||
)),
|
||||
),
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(tt *testing.T) {
|
||||
@@ -1156,45 +1156,45 @@ func TestSASLStartErrors(t *testing.T) {
|
||||
res *wirebson.Document
|
||||
}{
|
||||
"InvalidOptions": {
|
||||
msg: must.NotFail(wirebson.NewDocument(
|
||||
msg: wirebson.MustDocument(
|
||||
"saslStart", int32(1),
|
||||
"mechanism", "SCRAM-SHA-256",
|
||||
"payload", wirebson.Binary{B: []byte(payload)},
|
||||
"options", "invalid",
|
||||
"$db", "admin",
|
||||
)),
|
||||
res: must.NotFail(wirebson.NewDocument(
|
||||
),
|
||||
res: wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'saslStart.options' is the wrong type 'string', expected type 'object'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
)),
|
||||
),
|
||||
},
|
||||
"InvalidOptionsSkipEmptyExchange": {
|
||||
msg: must.NotFail(wirebson.NewDocument(
|
||||
msg: wirebson.MustDocument(
|
||||
"saslStart", int32(1),
|
||||
"mechanism", "SCRAM-SHA-256",
|
||||
"payload", wirebson.Binary{B: []byte(payload)},
|
||||
"options", wirebson.MustDocument("skipEmptyExchange", "invalid"),
|
||||
"$db", "admin",
|
||||
)),
|
||||
res: must.NotFail(wirebson.NewDocument(
|
||||
),
|
||||
res: wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Authentication failed.",
|
||||
"code", int32(18),
|
||||
"codeName", "AuthenticationFailed",
|
||||
)),
|
||||
),
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
q := must.NotFail(wire.NewOpMsg(must.NotFail(tc.msg.Encode())))
|
||||
q := must.NotFail(wire.NewOpMsg(tc.msg))
|
||||
|
||||
var resBody wire.MsgBody
|
||||
_, resBody, err = conn.Request(ctx, q)
|
||||
require.NoError(t, err)
|
||||
|
||||
var res *wirebson.Document
|
||||
res, err = must.NotFail(resBody.(*wire.OpMsg).RawDocument()).Decode()
|
||||
res, err = must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
FixCluster(t, res)
|
||||
@@ -1218,33 +1218,33 @@ func TestSASLContinueOpQueryErrors(t *testing.T) {
|
||||
reply *wirebson.Document
|
||||
}{
|
||||
"AuthenticationError": {
|
||||
query: must.NotFail(wirebson.NewDocument(
|
||||
query: wirebson.MustDocument(
|
||||
"saslContinue", int32(1),
|
||||
"conversationId", int32(1),
|
||||
"payload", wirebson.Binary{},
|
||||
)),
|
||||
),
|
||||
fullCollectionName: "wrong-auth-db.$cmd",
|
||||
reply: must.NotFail(wirebson.NewDocument(
|
||||
reply: wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Authentication failed.",
|
||||
"code", int32(18),
|
||||
"codeName", "AuthenticationFailed",
|
||||
)),
|
||||
),
|
||||
},
|
||||
"NotAllowed$db": {
|
||||
query: must.NotFail(wirebson.NewDocument(
|
||||
query: wirebson.MustDocument(
|
||||
"saslContinue", int32(1),
|
||||
"conversationId", int32(1),
|
||||
"payload", wirebson.Binary{},
|
||||
"$db", "admin",
|
||||
)),
|
||||
),
|
||||
fullCollectionName: "admin.$cmd",
|
||||
reply: must.NotFail(wirebson.NewDocument(
|
||||
reply: wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "$db is not allowed in OP_QUERY requests",
|
||||
"code", int32(40621),
|
||||
"codeName", "Location40621",
|
||||
)),
|
||||
),
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
@@ -1266,7 +1266,10 @@ func TestSASLContinueOpQueryErrors(t *testing.T) {
|
||||
q.FullCollectionName = "admin.$cmd"
|
||||
q.NumberToReturn = -1
|
||||
|
||||
conn, err := wireclient.Connect(ctx, s.MongoDBURI, testutil.Logger(t))
|
||||
cleanUri, _, _, _, err := wireclient.Credentials(s.MongoDBURI)
|
||||
require.NoError(t, err)
|
||||
|
||||
conn, err := wireclient.Connect(ctx, cleanUri, testutil.Logger(t))
|
||||
require.NoError(t, err)
|
||||
|
||||
_, resBody, err := conn.Request(ctx, q)
|
||||
@@ -1280,12 +1283,12 @@ func TestSASLContinueOpQueryErrors(t *testing.T) {
|
||||
err = res.Replace("payload", wirebson.Binary{})
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedComparable := must.NotFail(wirebson.NewDocument(
|
||||
expectedComparable := wirebson.MustDocument(
|
||||
"conversationId", int32(1),
|
||||
"done", false,
|
||||
"payload", wirebson.Binary{},
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expectedComparable, res)
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ func TestInsertFind(t *testing.T) {
|
||||
func TestFindOtelComment(t *testing.T) {
|
||||
ctx, collection := setup.Setup(t, shareddata.Scalars)
|
||||
|
||||
ctx, span := otel.Tracer("").Start(ctx, "TestOtelComment")
|
||||
ctx, span := otel.Tracer("").Start(ctx, "TestFindOtelComment")
|
||||
defer span.End()
|
||||
|
||||
comment, err := observability.CommentFromSpanContext(span.SpanContext())
|
||||
@@ -580,7 +580,7 @@ func TestDebugCommandErrors(t *testing.T) {
|
||||
}
|
||||
AssertMatchesCommandError(t, expected, res.Err())
|
||||
|
||||
msg := `(InternalError) [msg_ferretdebugerror.go:68 handler.(*Handler).msgFerretDebugError] lazy error`
|
||||
msg := `(InternalError) msg_ferretdebugerror.go:59 (handler.(*Handler).msgFerretDebugError): lazy error`
|
||||
assert.EqualError(t, res.Err(), msg)
|
||||
|
||||
var doc bson.D
|
||||
|
||||
@@ -1887,7 +1887,7 @@ func TestServerStatusCommand(t *testing.T) {
|
||||
{"gitVersion", info.Commit},
|
||||
{"debug", true},
|
||||
{"package", info.Package},
|
||||
{"postgresql", version.PostgreSQL},
|
||||
{"postgresql", version.PostgreSQLTest},
|
||||
{"documentdb", version.DocumentDB},
|
||||
}
|
||||
AssertEqualDocuments(t, expected, ferretdb)
|
||||
@@ -2157,7 +2157,7 @@ func TestServerStatusCommandMetrics(t *testing.T) {
|
||||
{"gitVersion", info.Commit},
|
||||
{"debug", true},
|
||||
{"package", info.Package},
|
||||
{"postgresql", version.PostgreSQL},
|
||||
{"postgresql", version.PostgreSQLTest},
|
||||
{"documentdb", version.DocumentDB},
|
||||
}},
|
||||
{"freeMonitoring", bson.D{{"state", "undecided"}}},
|
||||
@@ -2339,7 +2339,7 @@ func TestServerStatusCommandFreeMonitoring(t *testing.T) {
|
||||
{"gitVersion", info.Commit},
|
||||
{"debug", true},
|
||||
{"package", info.Package},
|
||||
{"postgresql", version.PostgreSQL},
|
||||
{"postgresql", version.PostgreSQLTest},
|
||||
{"documentdb", version.DocumentDB},
|
||||
}},
|
||||
{"freeMonitoring", bson.D{{"state", tc.expectedStatus}}},
|
||||
@@ -2412,152 +2412,80 @@ func TestServerStatusCommandStress(t *testing.T) {
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestCompactCommandForce(t *testing.T) {
|
||||
func TestCompactCommand(t *testing.T) {
|
||||
// don't run in parallel as parallel `VACUUM FULL ANALYZE` may result in deadlock
|
||||
s := setup.SetupWithOpts(t, &setup.SetupOpts{
|
||||
DatabaseName: "admin",
|
||||
Providers: []shareddata.Provider{shareddata.DocumentsStrings},
|
||||
})
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
force any // optional, defaults to unset
|
||||
dr, err := s.Collection.DeleteMany(s.Ctx, bson.D{})
|
||||
require.NoError(t, err)
|
||||
assert.Positive(t, dr.DeletedCount)
|
||||
|
||||
err *mongo.CommandError // optional
|
||||
altMessage string // optional, alternative error message
|
||||
skipForMongoDB string // optional, skip test for mongoDB with a specific reason
|
||||
}{
|
||||
"True": {
|
||||
force: true,
|
||||
},
|
||||
"False": {
|
||||
force: false,
|
||||
skipForMongoDB: "Only {force:true} can be run on active replica set primary",
|
||||
},
|
||||
"Int32": {
|
||||
force: int32(1),
|
||||
},
|
||||
"Int32Zero": {
|
||||
force: int32(0),
|
||||
skipForMongoDB: "Only {force:true} can be run on active replica set primary",
|
||||
},
|
||||
"Int64": {
|
||||
force: int64(1),
|
||||
},
|
||||
"Int64Zero": {
|
||||
force: int64(0),
|
||||
skipForMongoDB: "Only {force:true} can be run on active replica set primary",
|
||||
},
|
||||
"Double": {
|
||||
force: float64(1),
|
||||
},
|
||||
"DoubleZero": {
|
||||
force: float64(0),
|
||||
skipForMongoDB: "Only {force:true} can be run on active replica set primary",
|
||||
},
|
||||
"Unset": {
|
||||
skipForMongoDB: "Only {force:true} can be run on active replica set primary",
|
||||
},
|
||||
"String": {
|
||||
force: "foo",
|
||||
err: &mongo.CommandError{
|
||||
Code: 14,
|
||||
Name: "TypeMismatch",
|
||||
Message: "BSON field 'force' is the wrong type 'string', expected types '[bool, long, int, decimal, double]'",
|
||||
},
|
||||
skipForMongoDB: "force is FerretDB specific field",
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if tc.skipForMongoDB != "" {
|
||||
setup.SkipForMongoDB(t, tc.skipForMongoDB)
|
||||
}
|
||||
|
||||
command := bson.D{{"compact", s.Collection.Name()}}
|
||||
if tc.force != nil {
|
||||
command = append(command, bson.E{Key: "force", Value: tc.force})
|
||||
}
|
||||
|
||||
var res bson.D
|
||||
err := s.Collection.Database().RunCommand(
|
||||
s.Ctx,
|
||||
command,
|
||||
).Decode(&res)
|
||||
|
||||
if tc.err != nil {
|
||||
AssertEqualAltCommandError(t, *tc.err, tc.altMessage, err)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := bson.D{
|
||||
{"bytesFreed", int32(0)},
|
||||
{"ok", float64(1)},
|
||||
}
|
||||
|
||||
AssertEqualDocuments(t, expected, res)
|
||||
})
|
||||
command := bson.D{
|
||||
{"compact", s.Collection.Name()},
|
||||
{"force", true},
|
||||
}
|
||||
|
||||
var res bson.D
|
||||
err = s.Collection.Database().RunCommand(s.Ctx, command).Decode(&res)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, bf := RemoveKey(t, res, "bytesFreed")
|
||||
assert.Zero(t, bf)
|
||||
AssertEqualDocuments(t, bson.D{{"ok", float64(1)}}, res)
|
||||
}
|
||||
|
||||
func TestCompactCommandErrors(tt *testing.T) {
|
||||
tt.Parallel()
|
||||
func TestCompactCommandNonExistent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
dbName string
|
||||
force any // optional, defaults to unset
|
||||
|
||||
err *mongo.CommandError // required
|
||||
altMessage string // optional, alternative error message
|
||||
skipForMongoDB string // optional, skip test for MongoDB backend with a specific reason
|
||||
failsForFerretDB string
|
||||
err *mongo.CommandError // required
|
||||
altMessage string // optional, alternative error message
|
||||
}{
|
||||
"NonExistentDB": {
|
||||
force: true,
|
||||
dbName: "non-existent",
|
||||
err: &mongo.CommandError{
|
||||
Code: 26,
|
||||
Name: "NamespaceNotFound",
|
||||
Message: "database does not exist",
|
||||
},
|
||||
altMessage: "Invalid namespace specified 'non-existent.non-existent'",
|
||||
|
||||
skipForMongoDB: "Only {force:true} can be run on active replica set primary",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/286",
|
||||
altMessage: "ns does not exist: non-existent.non-existent",
|
||||
},
|
||||
"NonExistentCollection": {
|
||||
force: true,
|
||||
dbName: "admin",
|
||||
err: &mongo.CommandError{
|
||||
Code: 26,
|
||||
Name: "NamespaceNotFound",
|
||||
Message: "collection does not exist",
|
||||
},
|
||||
altMessage: "Invalid namespace specified 'admin.non-existent'",
|
||||
skipForMongoDB: "Only {force:true} can be run on active replica set primary",
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/286",
|
||||
altMessage: "ns does not exist: admin.non-existent",
|
||||
},
|
||||
} {
|
||||
tt.Run(name, func(tt *testing.T) {
|
||||
tt.Parallel()
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var t testing.TB = tt
|
||||
if tc.failsForFerretDB != "" {
|
||||
t = setup.FailsForFerretDB(tt, tc.failsForFerretDB)
|
||||
}
|
||||
require.Error(t, tc.err)
|
||||
|
||||
if tc.skipForMongoDB != "" {
|
||||
setup.SkipForMongoDB(t, tc.skipForMongoDB)
|
||||
}
|
||||
|
||||
require.NotNil(t, tc.err, "err must not be nil")
|
||||
|
||||
s := setup.SetupWithOpts(tt, &setup.SetupOpts{
|
||||
s := setup.SetupWithOpts(t, &setup.SetupOpts{
|
||||
DatabaseName: tc.dbName,
|
||||
})
|
||||
|
||||
command := bson.D{
|
||||
{"compact", "non-existent"},
|
||||
}
|
||||
if tc.force != nil {
|
||||
command = append(command, bson.E{Key: "force", Value: tc.force})
|
||||
}
|
||||
|
||||
var res bson.D
|
||||
err := s.Collection.Database().RunCommand(
|
||||
s.Ctx,
|
||||
bson.D{{"compact", "non-existent"}},
|
||||
).Decode(&res)
|
||||
err := s.Collection.Database().RunCommand(s.Ctx, command).Decode(&res)
|
||||
|
||||
AssertEqualAltCommandError(t, *tc.err, tc.altMessage, err)
|
||||
})
|
||||
|
||||
@@ -269,48 +269,48 @@ func TestHostInfoCommand(t *testing.T) {
|
||||
for _, elem := range a {
|
||||
switch elem.Key {
|
||||
case "system":
|
||||
var elemForComparsion bson.D
|
||||
var elemForComparison bson.D
|
||||
|
||||
for _, subElem := range elem.Value.(bson.D) {
|
||||
switch subElem.Key {
|
||||
case "currentTime":
|
||||
assert.IsType(t, primitive.DateTime(0), subElem.Value)
|
||||
elemForComparsion = append(elemForComparsion, bson.E{"currentTime", primitive.DateTime(0)})
|
||||
elemForComparison = append(elemForComparison, bson.E{"currentTime", primitive.DateTime(0)})
|
||||
|
||||
case "hostname", "cpuArch":
|
||||
assert.IsType(t, "", subElem.Value)
|
||||
elemForComparsion = append(elemForComparsion, bson.E{subElem.Key, ""})
|
||||
elemForComparison = append(elemForComparison, bson.E{subElem.Key, ""})
|
||||
|
||||
case "cpuAddrSize", "numCores":
|
||||
assert.IsType(t, int32(0), subElem.Value)
|
||||
elemForComparsion = append(elemForComparsion, bson.E{subElem.Key, int32(0)})
|
||||
elemForComparison = append(elemForComparison, bson.E{subElem.Key, int32(0)})
|
||||
|
||||
case "numPhysicalCores", "numCpuSockets", "numNumaNodes", "numaEnabled", "memSizeMB", "memLimitMB":
|
||||
// not implemented in FerretDB, do nothing
|
||||
// TODO https://github.com/FerretDB/FerretDB-DocumentDB/issues/587
|
||||
|
||||
default:
|
||||
elemForComparsion = append(elemForComparsion, subElem)
|
||||
elemForComparison = append(elemForComparison, subElem)
|
||||
}
|
||||
}
|
||||
|
||||
actualComparable = append(actualComparable, bson.E{"system", elemForComparsion})
|
||||
actualComparable = append(actualComparable, bson.E{"system", elemForComparison})
|
||||
|
||||
case "os":
|
||||
var elemForComparsion bson.D
|
||||
var elemForComparison bson.D
|
||||
|
||||
for _, subElem := range elem.Value.(bson.D) {
|
||||
switch subElem.Key {
|
||||
case "type", "name", "version":
|
||||
assert.IsType(t, "", subElem.Value)
|
||||
elemForComparsion = append(elemForComparsion, bson.E{subElem.Key, ""})
|
||||
elemForComparison = append(elemForComparison, bson.E{subElem.Key, ""})
|
||||
|
||||
default:
|
||||
elemForComparsion = append(elemForComparsion, subElem)
|
||||
elemForComparison = append(elemForComparison, subElem)
|
||||
}
|
||||
}
|
||||
|
||||
actualComparable = append(actualComparable, bson.E{"os", elemForComparsion})
|
||||
actualComparable = append(actualComparable, bson.E{"os", elemForComparison})
|
||||
|
||||
case "extra":
|
||||
assert.IsType(t, bson.D{}, elem.Value)
|
||||
@@ -349,7 +349,7 @@ func TestListCommandsCommand(t *testing.T) {
|
||||
err := collection.Database().RunCommand(ctx, bson.D{{"listCommands", 42}}).Decode(&res)
|
||||
require.NoError(t, err)
|
||||
|
||||
var actualForComparsion bson.D
|
||||
var actualForComparison bson.D
|
||||
|
||||
for _, v := range res {
|
||||
switch v.Key {
|
||||
@@ -383,10 +383,10 @@ func TestListCommandsCommand(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
actualForComparsion = append(actualForComparsion, bson.E{"commands", commandsComparable})
|
||||
actualForComparison = append(actualForComparison, bson.E{"commands", commandsComparable})
|
||||
|
||||
default:
|
||||
actualForComparsion = append(actualForComparsion, v)
|
||||
actualForComparison = append(actualForComparison, v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ func TestListCommandsCommand(t *testing.T) {
|
||||
{"ok", float64(1)},
|
||||
}
|
||||
|
||||
AssertEqualDocuments(t, expected, actualForComparsion)
|
||||
AssertEqualDocuments(t, expected, actualForComparison)
|
||||
}
|
||||
|
||||
func TestValidateCommand(t *testing.T) {
|
||||
|
||||
@@ -17,8 +17,9 @@ const _CompatTestCaseResultType_name = "NonEmptyResultEmptyResult"
|
||||
var _CompatTestCaseResultType_index = [...]uint8{0, 14, 25}
|
||||
|
||||
func (i CompatTestCaseResultType) String() string {
|
||||
if i < 0 || i >= CompatTestCaseResultType(len(_CompatTestCaseResultType_index)-1) {
|
||||
idx := int(i) - 0
|
||||
if i < 0 || idx >= len(_CompatTestCaseResultType_index)-1 {
|
||||
return "CompatTestCaseResultType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _CompatTestCaseResultType_name[_CompatTestCaseResultType_index[i]:_CompatTestCaseResultType_index[i+1]]
|
||||
return _CompatTestCaseResultType_name[_CompatTestCaseResultType_index[idx]:_CompatTestCaseResultType_index[idx+1]]
|
||||
}
|
||||
@@ -170,6 +170,9 @@ func TestCurrentOpGetMore(tt *testing.T) {
|
||||
}
|
||||
|
||||
func TestCurrentOpExplain(tt *testing.T) {
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/4871
|
||||
tt.Skip("https://github.com/FerretDB/FerretDB/issues/4871")
|
||||
|
||||
tt.Parallel()
|
||||
|
||||
s := setup.SetupWithOpts(tt, new(setup.SetupOpts))
|
||||
|
||||
@@ -249,15 +249,14 @@ func TestFindCommandSingleBatch(t *testing.T) {
|
||||
func TestFindCommandExhausted(tt *testing.T) {
|
||||
tt.Parallel()
|
||||
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB-DocumentDB/issues/270")
|
||||
|
||||
s := setup.SetupWithOpts(tt, &setup.SetupOpts{PoolSize: 1})
|
||||
|
||||
collection, ctx := s.Collection, s.Ctx
|
||||
|
||||
arr := integration.GenerateDocuments(1, 3)
|
||||
_, err := collection.InsertMany(ctx, arr)
|
||||
require.NoError(t, err)
|
||||
require.NoError(tt, err)
|
||||
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB/issues/5445")
|
||||
|
||||
var res bson.D
|
||||
err = collection.Database().RunCommand(ctx, bson.D{
|
||||
|
||||
@@ -28,6 +28,8 @@ import (
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/ctxutil"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/integration"
|
||||
"github.com/FerretDB/FerretDB/v2/integration/setup"
|
||||
"github.com/FerretDB/FerretDB/v2/integration/shareddata"
|
||||
@@ -310,8 +312,8 @@ func TestGetMoreCommand(t *testing.T) {
|
||||
|
||||
// Do not run subtests in t.Parallel() to eliminate the occurrence
|
||||
// of session error.
|
||||
// Supporting session would help us understand fix it
|
||||
// https://github.com/FerretDB/FerretDB/issues/153.
|
||||
// Supporting session would help us understand fix it.
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/153
|
||||
//
|
||||
// > Location50738
|
||||
// > Cannot run getMore on cursor 2053655655200551971,
|
||||
@@ -467,6 +469,11 @@ func TestGetMoreCommandBatchSize(t *testing.T) {
|
||||
require.Equal(t, i-1, cursor.RemainingBatchLength())
|
||||
}
|
||||
|
||||
if setup.IsYugabyteDB(t) {
|
||||
// TODO https://github.com/yugabyte/yugabyte-db/issues/27989
|
||||
t.Skip("https://github.com/yugabyte/yugabyte-db/issues/27989")
|
||||
}
|
||||
|
||||
// get rest of documents from the cursor to ensure cursor is exhausted
|
||||
var res bson.D
|
||||
err = cursor.All(ctx, &res)
|
||||
@@ -563,8 +570,8 @@ func TestGetMoreCommandConnection(t *testing.T) {
|
||||
t.Run("SameClient", func(t *testing.T) {
|
||||
// Do not run subtests in t.Parallel() to eliminate the occurrence
|
||||
// of session error.
|
||||
// Supporting session would help us understand fix it
|
||||
// https://github.com/FerretDB/FerretDB/issues/153.
|
||||
// Supporting session would help us understand fix it.
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/153
|
||||
//
|
||||
// > Location50738
|
||||
// > Cannot run getMore on cursor 2053655655200551971,
|
||||
@@ -826,16 +833,15 @@ func TestGetMoreCommandMaxTimeMSErrors(t *testing.T) {
|
||||
|
||||
func TestGetMoreCommandExhausted(tt *testing.T) {
|
||||
s := setup.SetupWithOpts(tt, nil)
|
||||
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB-DocumentDB/issues/270")
|
||||
|
||||
collection := s.Collection
|
||||
db, ctx := collection.Database(), s.Ctx
|
||||
|
||||
arr := integration.GenerateDocuments(0, 10)
|
||||
|
||||
_, err := collection.InsertMany(ctx, arr)
|
||||
require.NoError(t, err)
|
||||
require.NoError(tt, err)
|
||||
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB/issues/5445")
|
||||
|
||||
var res bson.D
|
||||
err = db.RunCommand(ctx, bson.D{
|
||||
@@ -1130,10 +1136,11 @@ func TestFindCommandFirstBatchMaxTimeMS(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run("GetMore", func(tt *testing.T) {
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB-DocumentDB/issues/270")
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB/issues/5445")
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
ctxutil.Sleep(ctx, 100*time.Millisecond)
|
||||
|
||||
var res bson.D
|
||||
err = collection.Database().RunCommand(ctx, getMoreCmd).Decode(&res)
|
||||
require.NoError(t, err)
|
||||
@@ -1153,9 +1160,10 @@ func TestFindCommandFirstBatchMaxTimeMS(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetMoreEmpty", func(tt *testing.T) {
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB-DocumentDB/issues/270")
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB/issues/5445")
|
||||
|
||||
ctxutil.Sleep(ctx, 100*time.Millisecond)
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
var res bson.D
|
||||
err = collection.Database().RunCommand(ctx, getMoreCmd).Decode(&res)
|
||||
require.NoError(t, err)
|
||||
@@ -1225,7 +1233,7 @@ func TestGetMoreCommandAfterInsertion(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run("GetMore", func(tt *testing.T) {
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB-DocumentDB/issues/270")
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB/issues/5445")
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
var res bson.D
|
||||
@@ -1247,7 +1255,7 @@ func TestGetMoreCommandAfterInsertion(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetMoreEmpty", func(tt *testing.T) {
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB-DocumentDB/issues/270")
|
||||
t := setup.FailsForFerretDB(tt, "https://github.com/FerretDB/FerretDB/issues/5445")
|
||||
|
||||
var res bson.D
|
||||
err = collection.Database().RunCommand(ctx, getMoreCmd).Decode(&res)
|
||||
|
||||
@@ -86,7 +86,6 @@ func TestDelete(t *testing.T) {
|
||||
},
|
||||
"ValidString": {
|
||||
deletes: bson.A{bson.D{{"q", bson.D{{"v", "foo"}}}, {"limit", "1"}}},
|
||||
skip: "https://github.com/FerretDB/FerretDB/issues/1089",
|
||||
},
|
||||
"InvalidFloat": {
|
||||
deletes: bson.A{bson.D{{"q", bson.D{{"v", "foo"}}}, {"limit", 42.13}}},
|
||||
|
||||
@@ -39,9 +39,10 @@ type explainCompatTestCase struct {
|
||||
// testExplainCompatError tests explain compatibility test cases.
|
||||
// This test does not work for successful aggregate pipeline tests,
|
||||
// due to compat requiring cursor option.
|
||||
// If you see following error, use `testAggregateStagesCompat` test instead.
|
||||
// If you see one of following errors, use `testAggregateStagesCompat` test instead.
|
||||
//
|
||||
// `(FailedToParse) The 'cursor' option is required, except for aggregate with the explain argument`
|
||||
// `(FailedToParse) The 'cursor' option is required, except for aggregate with the explain argument`.
|
||||
// `(FailedToParse) The 'cursor' option is required, except for aggregate with explain`.
|
||||
func testExplainCompatError(tt *testing.T, testCases map[string]explainCompatTestCase) {
|
||||
tt.Helper()
|
||||
|
||||
|
||||
+43
-35
@@ -1,68 +1,76 @@
|
||||
module github.com/FerretDB/FerretDB/v2/integration
|
||||
|
||||
go 1.24
|
||||
go 1.25
|
||||
|
||||
toolchain go1.24.3
|
||||
toolchain go1.25.4
|
||||
|
||||
replace github.com/FerretDB/FerretDB/v2 => ../
|
||||
|
||||
// replace github.com/FerretDB/wire => ../../wire
|
||||
|
||||
require (
|
||||
github.com/AlekSi/lazyerrors v0.0.0-20251102120325-67e66cc79778
|
||||
github.com/AlekSi/pointer v1.2.0
|
||||
github.com/FerretDB/FerretDB/v2 v2.0.0-00010101000000-000000000000
|
||||
github.com/FerretDB/wire v0.0.24
|
||||
github.com/FerretDB/wire v0.1.7
|
||||
github.com/FerretDB/xfail v0.1.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/prometheus/client_golang v1.21.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/xdg-go/scram v1.1.2
|
||||
go.mongodb.org/mongo-driver v1.17.3
|
||||
go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.60.0
|
||||
go.opentelemetry.io/otel v1.35.0
|
||||
go.mongodb.org/mongo-driver v1.17.6
|
||||
go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.63.0
|
||||
go.opentelemetry.io/otel v1.38.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/arl/statsviz v0.6.0 // indirect
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/arl/statsviz v0.7.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
|
||||
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.4 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.6 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/modelcontextprotocol/go-sdk v0.2.0 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/oapi-codegen/runtime v1.1.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.63.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.67.2 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.2.0 // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/term v0.31.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
google.golang.org/grpc v1.71.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
golang.org/x/crypto v0.43.0 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/grpc v1.75.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
+90
-72
@@ -1,23 +1,29 @@
|
||||
github.com/AlekSi/lazyerrors v0.0.0-20251102120325-67e66cc79778 h1:Hv1Z0ZnUWI1NYHXKUE16SWUcv+VyFARJHQ6dGkd2TIM=
|
||||
github.com/AlekSi/lazyerrors v0.0.0-20251102120325-67e66cc79778/go.mod h1:S8uLHjY/2pJvG9qkWwDX1AVYYknPI92r2qh/f0uysr0=
|
||||
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
|
||||
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
|
||||
github.com/FerretDB/wire v0.0.24 h1:UI4K50cSlfTO2uXnUuX+9OVRRoWUSVdbBbECTS2FRKU=
|
||||
github.com/FerretDB/wire v0.0.24/go.mod h1:TGo7jrzJkJjug8KVSOc3W/eyEUzcBym81D3MOEnyzOc=
|
||||
github.com/FerretDB/wire v0.1.7 h1:yh6tL0rU8ub+KuKqiqTlFJGpdfL4V7kg/8PBPDX0sBE=
|
||||
github.com/FerretDB/wire v0.1.7/go.mod h1:KjV8URsECCZWwJBBzlTvyl9LEXvnE362tL4tg52VHXI=
|
||||
github.com/FerretDB/xfail v0.1.0 h1:NmwdtwCmQ12X4VutLL+XilG/vbLRbG6RUVQabnI1JiQ=
|
||||
github.com/FerretDB/xfail v0.1.0/go.mod h1:u34yzRVZdvuc/fjegLYi+FztscWts9pP9ZUJ7wY9OyE=
|
||||
github.com/arl/statsviz v0.6.0 h1:jbW1QJkEYQkufd//4NDYRSNBpwJNrdzPahF7ZmoGdyE=
|
||||
github.com/arl/statsviz v0.6.0/go.mod h1:0toboo+YGSUXDaS4g1D5TVS4dXs7S7YYT5J/qnW2h8s=
|
||||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||
github.com/arl/statsviz v0.7.2 h1:xnuIfRiXE4kvxEcfGL+IE3mKH1BXNHuE+eJELIh7oOA=
|
||||
github.com/arl/statsviz v0.7.2/go.mod h1:XlrbiT7xYT03xaW9JMMfD8KFUhBOESJwfyNJu83PbB0=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
@@ -28,20 +34,21 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
|
||||
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438 h1:Dj0L5fhJ9F82ZJyVOmBx6msDp/kfd1t9GRfny/mfJA0=
|
||||
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
|
||||
github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6 h1:D/V0gu4zQ3cL2WKeVNVM4r2gLxGGf6McLwgXzRTo2RQ=
|
||||
github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
|
||||
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
|
||||
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
||||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||
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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
@@ -50,107 +57,118 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/modelcontextprotocol/go-sdk v0.2.0 h1:PESNYOmyM1c369tRkzXLY5hHrazj8x9CY1Xu0fLCryM=
|
||||
github.com/modelcontextprotocol/go-sdk v0.2.0/go.mod h1:0sL9zUKKs2FTTkeCCVnKqbLJTw5TScefPAzojjU459E=
|
||||
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI=
|
||||
github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
||||
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
|
||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyAEN8=
|
||||
github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
|
||||
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||
go.mongodb.org/mongo-driver/v2 v2.2.0 h1:WwhNgGrijwU56ps9RtIsgKfGLEZeypxqbEYfThrBScM=
|
||||
go.mongodb.org/mongo-driver/v2 v2.2.0/go.mod h1:qQkDMhCGWl3FN509DfdPd4GRBLU/41zqF/k8eTRceps=
|
||||
go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss=
|
||||
go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0 h1:Oq6BmUAAFTzMeh6AonuDlgZMuAuEiUxoAD1koK5MuFo=
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.60.0 h1:Nmavg2ogJX6gCgtYT8Ar0y5DAGG8t3xdMPTNHEDpNMQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.60.0/go.mod h1:OIEXGIR8h+AY2jl/9UN1R5wz2O1vlpH0C3RbtubBsGM=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.63.0 h1:6IOE2J+3fFJKJ/8riwf6XrazdEr261L8TEY6T0uSjEM=
|
||||
go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.63.0/go.mod h1:kbPDiVJGSE06bBx6sJlDMXFQ15/gnY4MA1ppkso9LYE=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
||||
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
|
||||
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
|
||||
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
|
||||
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -475,7 +475,7 @@ func TestCreateIndexesCompatUnique(t *testing.T) {
|
||||
insertDoc: bson.D{{"v", "value"}},
|
||||
new: true,
|
||||
// This test case passes only because of our hack for
|
||||
// TODO https://github.com/FerretDB/FerretDB-DocumentDB/issues/1147
|
||||
// TODO https://github.com/documentdb/documentdb/issues/25
|
||||
// failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/296",
|
||||
},
|
||||
"NotExistingFieldIndex": {
|
||||
@@ -515,7 +515,7 @@ func TestCreateIndexesCompatUnique(t *testing.T) {
|
||||
},
|
||||
insertDoc: bson.D{{"v", int32(42)}},
|
||||
// This test case passes only because of our hack for
|
||||
// TODO https://github.com/FerretDB/FerretDB-DocumentDB/issues/1147
|
||||
// TODO https://github.com/documentdb/documentdb/issues/25
|
||||
// failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/296",
|
||||
},
|
||||
} {
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/must"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/testutil"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/integration/setup"
|
||||
@@ -46,7 +45,7 @@ func TestOpQuery(t *testing.T) {
|
||||
_, resBody, err := conn.Request(ctx, q)
|
||||
require.NoError(t, err)
|
||||
|
||||
resMsg, err := resBody.(*wire.OpReply).RawDocument().Decode()
|
||||
resMsg, err := resBody.(*wire.OpReply).DocumentRaw().Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
ok := resMsg.Get("ok")
|
||||
@@ -68,7 +67,7 @@ func TestOpQuery(t *testing.T) {
|
||||
_, resBody, err := conn.Request(ctx, q)
|
||||
require.NoError(t, err)
|
||||
|
||||
resMsg, err := resBody.(*wire.OpReply).RawDocument().Decode()
|
||||
resMsg, err := resBody.(*wire.OpReply).DocumentRaw().Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
ok := resMsg.Get("ok")
|
||||
@@ -90,17 +89,17 @@ func TestOpQuery(t *testing.T) {
|
||||
_, resBody, err := conn.Request(ctx, q)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := resBody.(*wire.OpReply).RawDocument().Decode()
|
||||
res, err := resBody.(*wire.OpReply).DocumentRaw().Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Bad numberToReturn (0) for $cmd type ns - can only be 1 or -1",
|
||||
"code", int32(16979),
|
||||
"codeName", "Location16979",
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
})
|
||||
@@ -132,7 +131,7 @@ func TestOpQueryIsMaster(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.NotZero(t, resHeader.RequestID)
|
||||
|
||||
res, err := resBody.(*wire.OpReply).RawDocument().Decode()
|
||||
res, err := resBody.(*wire.OpReply).DocumentRaw().Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
connectionID := res.Get("connectionId")
|
||||
@@ -156,7 +155,7 @@ func TestOpQueryIsMaster(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expectedComparable := must.NotFail(wirebson.NewDocument(
|
||||
expectedComparable := wirebson.MustDocument(
|
||||
"ismaster", true,
|
||||
"maxBsonObjectSize", int32(16777216),
|
||||
"maxMessageSizeBytes", int32(48000000),
|
||||
@@ -166,7 +165,7 @@ func TestOpQueryIsMaster(t *testing.T) {
|
||||
"maxWireVersion", int32(21),
|
||||
"readOnly", false,
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
testutil.AssertEqual(t, expectedComparable, res)
|
||||
})
|
||||
}
|
||||
@@ -201,7 +200,7 @@ func TestOpQueryIsMasterHelloOk(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.NotZero(t, resHeader.RequestID)
|
||||
|
||||
res, err := resBody.(*wire.OpReply).RawDocument().Decode()
|
||||
res, err := resBody.(*wire.OpReply).DocumentRaw().Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
connectionID := res.Get("connectionId")
|
||||
@@ -225,7 +224,7 @@ func TestOpQueryIsMasterHelloOk(t *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expectedComparable := must.NotFail(wirebson.NewDocument(
|
||||
expectedComparable := wirebson.MustDocument(
|
||||
"helloOk", true,
|
||||
"ismaster", true,
|
||||
"maxBsonObjectSize", int32(16777216),
|
||||
@@ -236,7 +235,7 @@ func TestOpQueryIsMasterHelloOk(t *testing.T) {
|
||||
"maxWireVersion", int32(21),
|
||||
"readOnly", false,
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
testutil.AssertEqual(t, expectedComparable, res)
|
||||
})
|
||||
}
|
||||
@@ -262,7 +261,7 @@ func TestOpQueryHello(tt *testing.T) {
|
||||
_, resBody, err := conn.Request(ctx, q)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := resBody.(*wire.OpReply).RawDocument().Decode()
|
||||
res, err := resBody.(*wire.OpReply).DocumentRaw().Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
connectionID := res.Get("connectionId")
|
||||
@@ -286,7 +285,7 @@ func TestOpQueryHello(tt *testing.T) {
|
||||
|
||||
FixCluster(t, res)
|
||||
|
||||
expectedComparable := must.NotFail(wirebson.NewDocument(
|
||||
expectedComparable := wirebson.MustDocument(
|
||||
"isWritablePrimary", true,
|
||||
"maxBsonObjectSize", int32(16777216),
|
||||
"maxMessageSizeBytes", int32(48000000),
|
||||
@@ -296,6 +295,6 @@ func TestOpQueryHello(tt *testing.T) {
|
||||
"maxWireVersion", int32(21),
|
||||
"readOnly", false,
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
testutil.AssertEqual(t, expectedComparable, res)
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright 2021 FerretDB Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package query
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/FerretDB/wire"
|
||||
"github.com/FerretDB/wire/wirebson"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/integration/setup"
|
||||
)
|
||||
|
||||
func TestInsertZeroTimestamp(tt *testing.T) {
|
||||
tt.Parallel()
|
||||
|
||||
var t testing.TB = tt
|
||||
|
||||
s := setup.SetupWithOpts(t, &setup.SetupOpts{WireConn: setup.WireConnAuth})
|
||||
|
||||
_, resp, err := s.WireConn.Request(s.Ctx, wire.MustOpMsg(
|
||||
"insert", s.Collection.Name(),
|
||||
"documents", wirebson.MustArray(
|
||||
wirebson.MustDocument(
|
||||
"_id", "id",
|
||||
"v", wirebson.Timestamp(0),
|
||||
"d", wirebson.MustDocument(
|
||||
"dv", wirebson.Timestamp(0),
|
||||
),
|
||||
),
|
||||
),
|
||||
"$db", s.Collection.Database().Name(),
|
||||
))
|
||||
require.NoError(t, err)
|
||||
|
||||
actual, err := resp.(*wire.OpMsg).Document()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1.0, actual.Get("ok"))
|
||||
|
||||
_, resp, err = s.WireConn.Request(s.Ctx, wire.MustOpMsg(
|
||||
"find", s.Collection.Name(),
|
||||
"$db", s.Collection.Database().Name(),
|
||||
))
|
||||
require.NoError(t, err)
|
||||
|
||||
actual, err = resp.(*wire.OpMsg).DocumentDeep()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1.0, actual.Get("ok"))
|
||||
|
||||
batch := actual.Get("cursor").(*wirebson.Document).Get("firstBatch").(*wirebson.Array)
|
||||
|
||||
d := batch.Get(0).(*wirebson.Document).Get("d").(*wirebson.Document)
|
||||
assert.Equal(t, wirebson.Timestamp(0), d.Get("dv"))
|
||||
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/1608
|
||||
t = setup.FailsForFerretDB(t, "https://github.com/FerretDB/FerretDB/issues/1608")
|
||||
|
||||
v := batch.Get(0).(*wirebson.Document).Get("v").(wirebson.Timestamp)
|
||||
assert.NotEqual(t, wirebson.Timestamp(0), v)
|
||||
assert.NotZero(t, v.I())
|
||||
assert.InDelta(t, time.Now().Unix(), v.T(), 5.0)
|
||||
}
|
||||
|
||||
func TestInsertZeroTimestampBypass(tt *testing.T) {
|
||||
tt.Parallel()
|
||||
|
||||
var t testing.TB = tt
|
||||
|
||||
s := setup.SetupWithOpts(t, &setup.SetupOpts{WireConn: setup.WireConnAuth})
|
||||
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/5073
|
||||
t = setup.FailsForMongoDB(t, "https://github.com/FerretDB/FerretDB/issues/5073")
|
||||
|
||||
_, resp, err := s.WireConn.Request(s.Ctx, wire.MustOpMsg(
|
||||
"insert", s.Collection.Name(),
|
||||
"documents", wirebson.MustArray(
|
||||
wirebson.MustDocument(
|
||||
"_id", "id",
|
||||
"v", wirebson.Timestamp(0),
|
||||
"d", wirebson.MustDocument(
|
||||
"dv", wirebson.Timestamp(0),
|
||||
),
|
||||
),
|
||||
),
|
||||
"bypassEmptyTsReplacement", true,
|
||||
"$db", s.Collection.Database().Name(),
|
||||
))
|
||||
require.NoError(t, err)
|
||||
|
||||
actual, err := resp.(*wire.OpMsg).Document()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1.0, actual.Get("ok"))
|
||||
|
||||
_, resp, err = s.WireConn.Request(s.Ctx, wire.MustOpMsg(
|
||||
"find", s.Collection.Name(),
|
||||
"$db", s.Collection.Database().Name(),
|
||||
))
|
||||
require.NoError(t, err)
|
||||
|
||||
actual, err = resp.(*wire.OpMsg).DocumentDeep()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1.0, actual.Get("ok"))
|
||||
|
||||
batch := actual.Get("cursor").(*wirebson.Document).Get("firstBatch").(*wirebson.Array)
|
||||
|
||||
d := batch.Get(0).(*wirebson.Document).Get("d").(*wirebson.Document)
|
||||
assert.Equal(t, wirebson.Timestamp(0), d.Get("dv"))
|
||||
|
||||
v := batch.Get(0).(*wirebson.Document).Get("v").(wirebson.Timestamp)
|
||||
assert.Equal(t, wirebson.Timestamp(0), v)
|
||||
}
|
||||
@@ -116,10 +116,10 @@ func TestQueryArrayCompatDotNotation(t *testing.T) {
|
||||
"FieldArrayIndex": {
|
||||
filter: bson.D{{"v.foo[0]", int32(42)}},
|
||||
},
|
||||
"FieldArrayAsterix": {
|
||||
"FieldArrayAsterisk": {
|
||||
filter: bson.D{{"v.foo[*]", int32(42)}},
|
||||
},
|
||||
"FieldAsterix": {
|
||||
"FieldAsterisk": {
|
||||
filter: bson.D{{"v.*", int32(42)}},
|
||||
},
|
||||
"FieldAt": {
|
||||
|
||||
@@ -125,14 +125,14 @@ func testQueryCompatWithProviders(t *testing.T, providers shareddata.Providers,
|
||||
t = setup.FailsForFerretDB(tt, tc.failsForFerretDB)
|
||||
}
|
||||
|
||||
targetIdx, tagetErr := targetCollection.Indexes().CreateOne(ctx, mongo.IndexModel{
|
||||
targetIdx, targetErr := targetCollection.Indexes().CreateOne(ctx, mongo.IndexModel{
|
||||
Keys: bson.D{{"v", 1}},
|
||||
})
|
||||
compatIdx, compatErr := compatCollection.Indexes().CreateOne(ctx, mongo.IndexModel{
|
||||
Keys: bson.D{{"v", 1}},
|
||||
})
|
||||
|
||||
require.NoError(t, tagetErr)
|
||||
require.NoError(t, targetErr)
|
||||
require.NoError(t, compatErr)
|
||||
require.Equal(t, compatIdx, targetIdx)
|
||||
|
||||
@@ -283,10 +283,13 @@ func TestQueryCompatSort(t *testing.T) {
|
||||
resultType: EmptyResult,
|
||||
failsForFerretDB: "https://github.com/FerretDB/FerretDB-DocumentDB/issues/241",
|
||||
},
|
||||
"DotNotationIndex": {
|
||||
filter: bson.D{},
|
||||
sort: bson.D{{"v.0", 1}, {"_id", 1}},
|
||||
},
|
||||
|
||||
// TODO https://github.com/FerretDB/FerretDB-DocumentDB/issues/355
|
||||
// "DotNotationIndex": {
|
||||
// filter: bson.D{},
|
||||
// sort: bson.D{{"v.0", 1}, {"_id", 1}},
|
||||
// },
|
||||
|
||||
"DotNotationNonExistent": {
|
||||
filter: bson.D{},
|
||||
sort: bson.D{{"invalid.foo", 1}, {"_id", 1}},
|
||||
|
||||
@@ -680,6 +680,11 @@ func TestQueryShowRecordID(t *testing.T) {
|
||||
cursor, err := tc.collection.Find(ctx, bson.D{}, opts)
|
||||
require.NoError(t, err)
|
||||
|
||||
if setup.IsYugabyteDB(t) {
|
||||
// TODO https://github.com/yugabyte/yugabyte-db/issues/27989
|
||||
t.Skip("https://github.com/yugabyte/yugabyte-db/issues/27989")
|
||||
}
|
||||
|
||||
var res []bson.D
|
||||
err = cursor.All(ctx, &res)
|
||||
require.NoError(t, cursor.Close(ctx))
|
||||
|
||||
@@ -130,12 +130,12 @@ func TestEndSessionsImmediateCleanup(t *testing.T) {
|
||||
|
||||
time.Sleep(10 * cleanupInterval)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
}
|
||||
@@ -152,12 +152,12 @@ func TestEndSessionsErrors(t *testing.T) {
|
||||
|
||||
t.Run("NotArray", func(t *testing.T) {
|
||||
sessions := "invalid"
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'endSessions.endSessions' is the wrong type 'string', expected type 'array'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
endSessions(t, ctx, conn, dbName, sessions, expectedErr)
|
||||
})
|
||||
@@ -179,17 +179,17 @@ func TestEndSessionsUnauthenticated(t *testing.T) {
|
||||
))
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Command endSessions requires authentication",
|
||||
"code", int32(13),
|
||||
"codeName", "Unauthorized",
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
}
|
||||
@@ -205,7 +205,7 @@ func endSessions(t testing.TB, ctx context.Context, conn *wireclient.Conn, dbNam
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -216,9 +216,8 @@ func endSessions(t testing.TB, ctx context.Context, conn *wireclient.Conn, dbNam
|
||||
return
|
||||
}
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(1),
|
||||
))
|
||||
|
||||
)
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
}
|
||||
@@ -79,12 +79,12 @@ func TestKillAllSessions(t *testing.T) {
|
||||
|
||||
killAllSessions(t, ctx, user1Conn, dbName, users, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user1CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user1SessionID, user1CursorID, expectedErr)
|
||||
|
||||
@@ -107,21 +107,21 @@ func TestKillAllSessions(t *testing.T) {
|
||||
|
||||
killAllSessions(t, ctx, user1Conn, dbName, users, nil)
|
||||
|
||||
expectedErr1 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr1 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user1CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user1SessionID, user1CursorID, expectedErr1)
|
||||
|
||||
expectedErr2 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr2 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user2CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user2SessionID, user2CursorID, expectedErr2)
|
||||
})
|
||||
@@ -139,21 +139,21 @@ func TestKillAllSessions(t *testing.T) {
|
||||
|
||||
killAllSessions(t, ctx, user1Conn, dbName, users, nil)
|
||||
|
||||
expectedErr1 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr1 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID1),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID1, cursorID1, expectedErr1)
|
||||
|
||||
expectedErr2 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr2 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID2),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID2, cursorID2, expectedErr2)
|
||||
})
|
||||
@@ -173,12 +173,12 @@ func TestKillAllSessions(t *testing.T) {
|
||||
|
||||
killSessions(t, ctx, user1Conn, dbName, sessions, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
@@ -222,12 +222,12 @@ func TestKillAllSessionsErrors(t *testing.T) {
|
||||
t.Run("NotArrayUsers", func(t *testing.T) {
|
||||
users := "invalid"
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsCmd.killAllSessions' is the wrong type 'string', expected type 'array'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessions(t, ctx, conn, dbName, users, expectedErr)
|
||||
})
|
||||
@@ -235,12 +235,12 @@ func TestKillAllSessionsErrors(t *testing.T) {
|
||||
t.Run("NotDocumentUser", func(t *testing.T) {
|
||||
users := wirebson.MustArray("invalid")
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsCmd.killAllSessions.0' is the wrong type 'string', expected type 'object'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessions(t, ctx, conn, dbName, users, expectedErr)
|
||||
})
|
||||
@@ -248,12 +248,12 @@ func TestKillAllSessionsErrors(t *testing.T) {
|
||||
t.Run("MissingDB", func(t *testing.T) {
|
||||
users := wirebson.MustArray(wirebson.MustDocument("user", "foo"))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsCmd.killAllSessions.db' is missing but a required field",
|
||||
"code", int32(40414),
|
||||
"codeName", "Location40414",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessions(t, ctx, conn, dbName, users, expectedErr)
|
||||
})
|
||||
@@ -261,12 +261,12 @@ func TestKillAllSessionsErrors(t *testing.T) {
|
||||
t.Run("BoolDB", func(t *testing.T) {
|
||||
users := wirebson.MustArray(wirebson.MustDocument("db", true, "user", "foo"))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsCmd.killAllSessions.db' is the wrong type 'bool', expected type 'string'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessions(t, ctx, conn, dbName, users, expectedErr)
|
||||
})
|
||||
@@ -274,12 +274,12 @@ func TestKillAllSessionsErrors(t *testing.T) {
|
||||
t.Run("MissingUser", func(t *testing.T) {
|
||||
users := wirebson.MustArray(wirebson.MustDocument("db", "bar"))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsCmd.killAllSessions.user' is missing but a required field",
|
||||
"code", int32(40414),
|
||||
"codeName", "Location40414",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessions(t, ctx, conn, dbName, users, expectedErr)
|
||||
})
|
||||
@@ -287,12 +287,12 @@ func TestKillAllSessionsErrors(t *testing.T) {
|
||||
t.Run("BoolUser", func(t *testing.T) {
|
||||
users := wirebson.MustArray(wirebson.MustDocument("db", "bar", "user", false))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsCmd.killAllSessions.user' is the wrong type 'bool', expected type 'string'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessions(t, ctx, conn, dbName, users, expectedErr)
|
||||
})
|
||||
@@ -341,21 +341,21 @@ func TestKillAllSessionsAllUsers(t *testing.T) {
|
||||
|
||||
killAllSessions(t, ctx, user1Conn, dbName, users, nil)
|
||||
|
||||
expectedErr1 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr1 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user1CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user1SessionID, user1CursorID, expectedErr1)
|
||||
|
||||
expectedErr2 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr2 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user2CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user2SessionID, user2CursorID, expectedErr2)
|
||||
}
|
||||
@@ -371,7 +371,7 @@ func killAllSessions(t testing.TB, ctx context.Context, conn *wireclient.Conn, d
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -382,9 +382,9 @@ func killAllSessions(t testing.TB, ctx context.Context, conn *wireclient.Conn, d
|
||||
return
|
||||
}
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package session
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/FerretDB/wire"
|
||||
@@ -84,12 +85,12 @@ func TestKillAllSessionsByPattern(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
@@ -110,12 +111,12 @@ func TestKillAllSessionsByPattern(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user2Conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
@@ -163,20 +164,20 @@ func TestKillAllSessionsByPattern(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, nil)
|
||||
|
||||
expectedErr1 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr1 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID1),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, session1ID, cursorID1, expectedErr1)
|
||||
|
||||
expectedErr2 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr2 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID2),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, session2ID, cursorID2, expectedErr2)
|
||||
})
|
||||
|
||||
@@ -197,12 +198,12 @@ func TestKillAllSessionsByPattern(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user1CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID, user1CursorID, expectedErr)
|
||||
|
||||
getMore(t, ctx, user2Conn, dbName, cName, sessionID, user2CursorID, nil)
|
||||
@@ -223,20 +224,20 @@ func TestKillAllSessionsByPattern(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, nil)
|
||||
|
||||
expectedErr1 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr1 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID1),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID, cursorID1, expectedErr1)
|
||||
|
||||
expectedErr2 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr2 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID2),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID, cursorID2, expectedErr2)
|
||||
})
|
||||
|
||||
@@ -251,12 +252,12 @@ func TestKillAllSessionsByPattern(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
@@ -272,12 +273,12 @@ func TestKillAllSessionsByPattern(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user2Conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
@@ -329,20 +330,20 @@ func TestKillAllSessionsByPattern(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, nil)
|
||||
|
||||
expectedErr1 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr1 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user1CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user1SessionID, user1CursorID, expectedErr1)
|
||||
|
||||
expectedErr2 := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr2 := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user2CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user2SessionID, user2CursorID, expectedErr2)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user1NotKillSessionID, user1NotKillCursorID, nil)
|
||||
@@ -387,12 +388,12 @@ func TestKillAllSessionsByPatternAllUsers(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user2Conn, dbName, pattern, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
@@ -407,12 +408,12 @@ func TestKillAllSessionsByPatternAllUsers(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, emptyUsersPattern, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
|
||||
@@ -430,12 +431,12 @@ func TestKillAllSessionsByPatternAllUsers(t *testing.T) {
|
||||
|
||||
// user1 does not match the pattern, but the cursor of user1 is deleted unexpectedly
|
||||
// and FerretDB exhibits the same behavior for the compatibility
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user1CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user1SessionID, user1CursorID, expectedErr)
|
||||
})
|
||||
|
||||
@@ -451,12 +452,12 @@ func TestKillAllSessionsByPatternAllUsers(t *testing.T) {
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, user1Pattern, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
|
||||
@@ -474,12 +475,12 @@ func TestKillAllSessionsByPatternAllUsers(t *testing.T) {
|
||||
|
||||
// sessions of user2 was killed, not user1, but the cursor of user1 is deleted unexpectedly
|
||||
// and FerretDB exhibits the same behavior for the compatibility
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user1CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user1SessionID, user1CursorID, expectedErr)
|
||||
})
|
||||
}
|
||||
@@ -504,12 +505,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
t.Run("NonArrayPatterns", func(t *testing.T) {
|
||||
pattern := "invalid"
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern' is the wrong type 'string', expected type 'array'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -517,12 +518,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
t.Run("StringPattern", func(t *testing.T) {
|
||||
pattern := wirebson.MustArray("invalid")
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.0' is the wrong type 'string', expected type 'object'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -532,12 +533,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
|
||||
pattern := wirebson.MustArray(wirebson.MustDocument("invalid", "foo"))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.invalid' is an unknown field.",
|
||||
"code", int32(40415),
|
||||
"codeName", "Location40415",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -545,12 +546,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
t.Run("LsidString", func(t *testing.T) {
|
||||
pattern := wirebson.MustArray(wirebson.MustDocument("lsid", "invalid"))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.lsid' is the wrong type 'string', expected type 'object'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -558,12 +559,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
t.Run("LsidMissingID", func(t *testing.T) {
|
||||
pattern := wirebson.MustArray(wirebson.MustDocument("lsid", wirebson.MustDocument()))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.lsid.id' is missing but a required field",
|
||||
"code", int32(40414),
|
||||
"codeName", "Location40414",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -571,12 +572,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
t.Run("LsidStringID", func(t *testing.T) {
|
||||
pattern := wirebson.MustArray(wirebson.MustDocument("lsid", wirebson.MustDocument("id", "invalid")))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.lsid.id' is the wrong type 'string', expected type 'binData'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -586,12 +587,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
"id", wirebson.Binary{Subtype: wirebson.BinaryFunction},
|
||||
)))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.lsid.id' is the wrong binData type 'function', expected type 'UUID'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -601,12 +602,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
"id", wirebson.Binary{Subtype: wirebson.BinaryUUID},
|
||||
)))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "uuid must be a 16-byte binary field with UUID (4) subtype",
|
||||
"code", int32(207),
|
||||
"codeName", "InvalidUUID",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -618,12 +619,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
"id", wirebson.Binary{B: randomUUID[:], Subtype: wirebson.BinaryUUID},
|
||||
)))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.lsid.uid' is missing but a required field",
|
||||
"code", int32(40414),
|
||||
"codeName", "Location40414",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -636,12 +637,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
"uid", "invalid",
|
||||
)))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.lsid.uid' is the wrong type 'string', expected type 'binData'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -654,12 +655,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
"uid", wirebson.Binary{},
|
||||
)))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Unsupported SHA256Block hash length: 0",
|
||||
"code", int32(12),
|
||||
"codeName", "UnsupportedFormat",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -672,12 +673,12 @@ func TestKillAllSessionsByPatternErrors(t *testing.T) {
|
||||
"uid", wirebson.Binary{Subtype: wirebson.BinaryFunction},
|
||||
)))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.lsid.uid' is the wrong binData type 'function', expected type 'general'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -705,12 +706,12 @@ func TestKillAllSessionsByPatternUIDErrors(t *testing.T) {
|
||||
wirebson.MustDocument("uid", "invalid"),
|
||||
)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.uid' is the wrong type 'string', expected type 'binData'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -720,12 +721,12 @@ func TestKillAllSessionsByPatternUIDErrors(t *testing.T) {
|
||||
wirebson.MustDocument("uid", wirebson.Binary{}),
|
||||
)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "Unsupported SHA256Block hash length: 0",
|
||||
"code", int32(12),
|
||||
"codeName", "UnsupportedFormat",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -735,12 +736,12 @@ func TestKillAllSessionsByPatternUIDErrors(t *testing.T) {
|
||||
wirebson.MustDocument("uid", wirebson.Binary{Subtype: wirebson.BinaryFunction}),
|
||||
)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.uid' is the wrong binData type 'function', expected type 'general'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -766,12 +767,12 @@ func TestKillAllSessionsByPatternUsersErrors(t *testing.T) {
|
||||
t.Run("NotArrayUsers", func(t *testing.T) {
|
||||
pattern := wirebson.MustArray(wirebson.MustDocument("users", "invalid"))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.users' is the wrong type 'string', expected type 'array'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -781,12 +782,12 @@ func TestKillAllSessionsByPatternUsersErrors(t *testing.T) {
|
||||
"users", wirebson.MustArray("invalid"),
|
||||
))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.users.0' is the wrong type 'string', expected type 'object'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -796,12 +797,12 @@ func TestKillAllSessionsByPatternUsersErrors(t *testing.T) {
|
||||
"users", wirebson.MustArray(wirebson.MustDocument("user", "foo")),
|
||||
))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.users.db' is missing but a required field",
|
||||
"code", int32(40414),
|
||||
"codeName", "Location40414",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -811,12 +812,12 @@ func TestKillAllSessionsByPatternUsersErrors(t *testing.T) {
|
||||
"users", wirebson.MustArray(wirebson.MustDocument("db", true, "user", "foo")),
|
||||
))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.users.db' is the wrong type 'bool', expected type 'string'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -826,12 +827,12 @@ func TestKillAllSessionsByPatternUsersErrors(t *testing.T) {
|
||||
"users", wirebson.MustArray(wirebson.MustDocument("db", "bar")),
|
||||
))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.users.user' is missing but a required field",
|
||||
"code", int32(40414),
|
||||
"codeName", "Location40414",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -841,12 +842,12 @@ func TestKillAllSessionsByPatternUsersErrors(t *testing.T) {
|
||||
"users", wirebson.MustArray(wirebson.MustDocument("db", "bar", "user", false)),
|
||||
))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'KillAllSessionsByPatternCmd.killAllSessionsByPattern.users.user' is the wrong type 'bool', expected type 'string'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killAllSessionsByPattern(t, ctx, user1Conn, dbName, pattern, expectedErr)
|
||||
})
|
||||
@@ -890,14 +891,17 @@ func createKillSessionUser(t *testing.T, ctx context.Context, db *mongo.Database
|
||||
}).Err()
|
||||
require.NoError(t, err)
|
||||
|
||||
conn, err := wireclient.Connect(ctx, mongoDBURI, testutil.Logger(t))
|
||||
clearUri, _, _, authMechanism, err := wireclient.Credentials(mongoDBURI)
|
||||
require.NoError(t, err)
|
||||
|
||||
conn, err := wireclient.Connect(ctx, clearUri, testutil.Logger(t))
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, conn.Close())
|
||||
})
|
||||
|
||||
err = conn.Login(ctx, username, password, db.Name())
|
||||
err = conn.Login(ctx, url.UserPassword(username, password), db.Name(), authMechanism)
|
||||
require.NoError(t, err)
|
||||
|
||||
return conn
|
||||
@@ -914,7 +918,7 @@ func killAllSessionsByPattern(t testing.TB, ctx context.Context, conn *wireclien
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -925,9 +929,9 @@ func killAllSessionsByPattern(t testing.TB, ctx context.Context, conn *wireclien
|
||||
return
|
||||
}
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
}
|
||||
@@ -121,12 +121,12 @@ func TestKillSessions(t *testing.T) {
|
||||
|
||||
killSessions(t, ctx, conn, dbName, sessions, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
@@ -142,12 +142,12 @@ func TestKillSessions(t *testing.T) {
|
||||
|
||||
refreshSessions(t, ctx, conn, dbName, nil, sessions, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
@@ -163,12 +163,12 @@ func TestKillSessions(t *testing.T) {
|
||||
|
||||
endSessions(t, ctx, conn, dbName, sessions, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, conn, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
@@ -176,12 +176,12 @@ func TestKillSessions(t *testing.T) {
|
||||
t.Run("EmptyUUIDSessionID", func(t *testing.T) {
|
||||
sessions := wirebson.MustArray(wirebson.MustDocument("id", wirebson.Binary{Subtype: wirebson.BinaryUUID}))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "uuid must be a 16-byte binary field with UUID (4) subtype",
|
||||
"code", int32(207),
|
||||
"codeName", "InvalidUUID",
|
||||
))
|
||||
)
|
||||
|
||||
killSessions(t, ctx, conn, dbName, sessions, expectedErr)
|
||||
})
|
||||
@@ -245,12 +245,12 @@ func TestKillSessionsDifferentUser(t *testing.T) {
|
||||
|
||||
getMore(t, ctx, user1Conn, dbName, cName, user1SessionID, user1CursorID, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", user2CursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
getMore(t, ctx, user2Conn, dbName, cName, user2SessionID, user2CursorID, expectedErr)
|
||||
})
|
||||
}
|
||||
@@ -266,7 +266,7 @@ func killSessions(t testing.TB, ctx context.Context, conn *wireclient.Conn, dbNa
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -277,9 +277,9 @@ func killSessions(t testing.TB, ctx context.Context, conn *wireclient.Conn, dbNa
|
||||
return
|
||||
}
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
}
|
||||
@@ -87,12 +87,12 @@ func TestRefreshSessionsErrors(t *testing.T) {
|
||||
|
||||
t.Run("NotArray", func(t *testing.T) {
|
||||
sessions := "invalid"
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'refreshSessions.refreshSessions' is the wrong type 'string', expected type 'array'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
refreshSessions(t, ctx, conn, dbName, nil, sessions, expectedErr)
|
||||
})
|
||||
@@ -100,12 +100,12 @@ func TestRefreshSessionsErrors(t *testing.T) {
|
||||
t.Run("NotSessionDocument", func(t *testing.T) {
|
||||
sessions := wirebson.MustArray("invalid")
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'refreshSessions.refreshSessionsFromClient.0' is the wrong type 'string', expected type 'object'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
refreshSessions(t, ctx, conn, dbName, nil, sessions, expectedErr)
|
||||
})
|
||||
@@ -113,12 +113,12 @@ func TestRefreshSessionsErrors(t *testing.T) {
|
||||
t.Run("MissingID", func(t *testing.T) {
|
||||
sessions := wirebson.MustArray(wirebson.MustDocument())
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'refreshSessions.refreshSessionsFromClient.id' is missing but a required field",
|
||||
"code", int32(40414),
|
||||
"codeName", "Location40414",
|
||||
))
|
||||
)
|
||||
|
||||
refreshSessions(t, ctx, conn, dbName, nil, sessions, expectedErr)
|
||||
})
|
||||
@@ -126,12 +126,12 @@ func TestRefreshSessionsErrors(t *testing.T) {
|
||||
t.Run("WrongIDType", func(t *testing.T) {
|
||||
sessions := wirebson.MustArray(wirebson.MustDocument("id", "invalid"))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'refreshSessions.refreshSessionsFromClient.id' is the wrong type 'string', expected type 'binData'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
refreshSessions(t, ctx, conn, dbName, nil, sessions, expectedErr)
|
||||
})
|
||||
@@ -139,12 +139,12 @@ func TestRefreshSessionsErrors(t *testing.T) {
|
||||
t.Run("WrongIDSubtype", func(t *testing.T) {
|
||||
sessions := wirebson.MustArray(wirebson.MustDocument("id", wirebson.Binary{Subtype: wirebson.BinaryFunction}))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'refreshSessions.refreshSessionsFromClient.id' is the wrong binData type 'function', expected type 'UUID'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
refreshSessions(t, ctx, conn, dbName, nil, sessions, expectedErr)
|
||||
})
|
||||
@@ -152,12 +152,12 @@ func TestRefreshSessionsErrors(t *testing.T) {
|
||||
t.Run("NotUUID", func(t *testing.T) {
|
||||
sessions := wirebson.MustArray(wirebson.MustDocument("id", wirebson.Binary{Subtype: wirebson.BinaryUUID}))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "uuid must be a 16-byte binary field with UUID (4) subtype",
|
||||
"code", int32(207),
|
||||
"codeName", "InvalidUUID",
|
||||
))
|
||||
)
|
||||
|
||||
refreshSessions(t, ctx, conn, dbName, nil, sessions, expectedErr)
|
||||
})
|
||||
@@ -166,12 +166,12 @@ func TestRefreshSessionsErrors(t *testing.T) {
|
||||
lsid := wirebson.Binary{Subtype: wirebson.BinaryUUID}
|
||||
sessions := wirebson.MustArray(wirebson.MustDocument("id", wirebson.Binary{Subtype: wirebson.BinaryUUID}))
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "uuid must be a 16-byte binary field with UUID (4) subtype",
|
||||
"code", int32(207),
|
||||
"codeName", "InvalidUUID",
|
||||
))
|
||||
)
|
||||
|
||||
refreshSessions(t, ctx, conn, dbName, lsid, sessions, expectedErr)
|
||||
})
|
||||
@@ -196,7 +196,7 @@ func refreshSessions(t testing.TB, ctx context.Context, conn *wireclient.Conn, d
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -207,9 +207,9 @@ func refreshSessions(t testing.TB, ctx context.Context, conn *wireclient.Conn, d
|
||||
return
|
||||
}
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/FerretDB/wire"
|
||||
@@ -43,14 +44,17 @@ func TestSessionConnection(t *testing.T) {
|
||||
ctx, collection, db, conn1 := s.Ctx, s.Collection, s.Collection.Database(), s.WireConn
|
||||
cName, dbName := collection.Name(), db.Name()
|
||||
|
||||
conn2, err := wireclient.Connect(ctx, s.MongoDBURI, testutil.Logger(t))
|
||||
clearUri, _, _, authMechanism, err := wireclient.Credentials(s.MongoDBURI)
|
||||
require.NoError(t, err)
|
||||
|
||||
conn2, err := wireclient.Connect(ctx, clearUri, testutil.Logger(t))
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, conn2.Close())
|
||||
})
|
||||
|
||||
err = conn2.Login(ctx, "username", "password", "admin")
|
||||
err = conn2.Login(ctx, url.UserPassword("username", "password"), "admin", authMechanism)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = collection.InsertMany(ctx, bson.A{
|
||||
@@ -122,10 +126,15 @@ func TestSessionConnection(t *testing.T) {
|
||||
|
||||
t.Run("CloseConnection", func(t *testing.T) {
|
||||
var anotherConn *wireclient.Conn
|
||||
anotherConn, err = wireclient.Connect(ctx, s.MongoDBURI, testutil.Logger(t))
|
||||
var creds *url.Userinfo
|
||||
|
||||
clearUri, creds, _, authMechanism, err = wireclient.Credentials(s.MongoDBURI)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = anotherConn.Login(ctx, "username", "password", "admin")
|
||||
anotherConn, err = wireclient.Connect(ctx, clearUri, testutil.Logger(t))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = anotherConn.Login(ctx, creds, "admin", authMechanism)
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionID := startSession(t, ctx, anotherConn)
|
||||
@@ -185,12 +194,12 @@ func TestSessionConnection(t *testing.T) {
|
||||
|
||||
killCursors(t, ctx, conn1, dbName, cName, cursorID, sessionID, nil)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", fmt.Sprintf("cursor id %d not found", cursorID),
|
||||
"code", int32(43),
|
||||
"codeName", "CursorNotFound",
|
||||
))
|
||||
)
|
||||
|
||||
getMore(t, ctx, conn1, dbName, cName, sessionID, cursorID, expectedErr)
|
||||
})
|
||||
@@ -202,12 +211,12 @@ func TestSessionConnection(t *testing.T) {
|
||||
|
||||
invalidSessionID := "invalid"
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
"errmsg", "BSON field 'OperationSessionInfo.lsid.id' is the wrong type 'string', expected type 'binData'",
|
||||
"code", int32(14),
|
||||
"codeName", "TypeMismatch",
|
||||
))
|
||||
)
|
||||
|
||||
killCursors(t, ctx, conn1, dbName, cName, cursorID, invalidSessionID, expectedErr)
|
||||
|
||||
@@ -235,7 +244,7 @@ func TestFindLsidErrors(t *testing.T) {
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -260,7 +269,7 @@ func TestFindLsidErrors(t *testing.T) {
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -285,7 +294,7 @@ func TestFindLsidErrors(t *testing.T) {
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -310,7 +319,7 @@ func TestFindLsidErrors(t *testing.T) {
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -335,7 +344,7 @@ func TestFindLsidErrors(t *testing.T) {
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -380,14 +389,17 @@ func TestSessionConnectionDifferentUser(t *testing.T) {
|
||||
}).Err()
|
||||
require.NoError(t, err)
|
||||
|
||||
userConn, err := wireclient.Connect(ctx, s.MongoDBURI, testutil.Logger(t))
|
||||
clearUri, _, _, authMechanism, err := wireclient.Credentials(s.MongoDBURI)
|
||||
require.NoError(t, err)
|
||||
|
||||
userConn, err := wireclient.Connect(ctx, clearUri, testutil.Logger(t))
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, userConn.Close())
|
||||
})
|
||||
|
||||
err = userConn.Login(ctx, user, pass, dbName)
|
||||
err = userConn.Login(ctx, url.UserPassword(user, pass), "admin", authMechanism)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
@@ -484,14 +496,14 @@ func TestSessionConnectionDifferentUser(t *testing.T) {
|
||||
|
||||
cursorID := find(t, ctx, adminConn, dbName, cName, sessionID)
|
||||
|
||||
expectedErr := must.NotFail(wirebson.NewDocument(
|
||||
expectedErr := wirebson.MustDocument(
|
||||
"ok", float64(0),
|
||||
// errmsg field is not compared, because as it is difficult produce exact format of document as below
|
||||
// `not authorized on admin to execute command{ killCursors: "test", cursors: [ 8541858944752455730 ],
|
||||
// lsid: { id: UUID("363dad0b-d9b8-406f-9575-b11a3779faa0") }, $db: "admin" }`
|
||||
"code", int32(13),
|
||||
"codeName", "Unauthorized",
|
||||
))
|
||||
)
|
||||
|
||||
killCursors(t, ctx, userConn, dbName, cName, cursorID, sessionID, expectedErr)
|
||||
|
||||
@@ -510,7 +522,7 @@ func startSession(t testing.TB, ctx context.Context, conn *wireclient.Conn) wire
|
||||
require.NoError(t, err)
|
||||
|
||||
var res *wirebson.Document
|
||||
res, err = must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err = must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -553,7 +565,7 @@ func killCursors(t testing.TB, ctx context.Context, conn *wireclient.Conn, dbNam
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -569,13 +581,13 @@ func killCursors(t testing.TB, ctx context.Context, conn *wireclient.Conn, dbNam
|
||||
return
|
||||
}
|
||||
|
||||
expected := must.NotFail(wirebson.NewDocument(
|
||||
expected := wirebson.MustDocument(
|
||||
"cursorsKilled", wirebson.MustArray(cursorID),
|
||||
"cursorsNotFound", wirebson.MakeArray(0),
|
||||
"cursorsAlive", wirebson.MakeArray(0),
|
||||
"cursorsUnknown", wirebson.MakeArray(0),
|
||||
"cursorsNotFound", wirebson.MustArray(),
|
||||
"cursorsAlive", wirebson.MustArray(),
|
||||
"cursorsUnknown", wirebson.MustArray(),
|
||||
"ok", float64(1),
|
||||
))
|
||||
)
|
||||
|
||||
testutil.AssertEqual(t, expected, res)
|
||||
}
|
||||
@@ -602,7 +614,7 @@ func find(t testing.TB, ctx context.Context, conn *wireclient.Conn, db, coll str
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
@@ -665,7 +677,7 @@ func getMore(t testing.TB, ctx context.Context, conn *wireclient.Conn, db, coll
|
||||
_, resBody, err := conn.Request(ctx, msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).RawDocument()).DecodeDeep()
|
||||
res, err := must.NotFail(resBody.(*wire.OpMsg).DocumentRaw()).DecodeDeep()
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.FixCluster(t, res)
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/AlekSi/lazyerrors"
|
||||
"github.com/FerretDB/wire/wireclient"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
@@ -29,7 +30,6 @@ import (
|
||||
"go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo"
|
||||
"go.opentelemetry.io/otel"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/lazyerrors"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/testutil"
|
||||
)
|
||||
|
||||
@@ -95,7 +95,7 @@ func makeClient(ctx context.Context, uri string, disableOtel bool) (*mongo.Clien
|
||||
func setupClient(tb testing.TB, ctx context.Context, uri string, disableOtel bool) *mongo.Client {
|
||||
tb.Helper()
|
||||
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setupClient")
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setup.setupClient")
|
||||
defer span.End()
|
||||
|
||||
u, err := url.Parse(uri)
|
||||
@@ -137,7 +137,7 @@ func setupClient(tb testing.TB, ctx context.Context, uri string, disableOtel boo
|
||||
func setupWireConn(tb testing.TB, ctx context.Context, uri string, l *slog.Logger) *wireclient.Conn {
|
||||
tb.Helper()
|
||||
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setupWireConn")
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setup.setupWireConn")
|
||||
defer span.End()
|
||||
|
||||
conn, err := wireclient.Connect(ctx, uri, l)
|
||||
|
||||
@@ -17,8 +17,6 @@ package setup
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -38,6 +36,15 @@ func IsMongoDB(tb testing.TB) bool {
|
||||
return *targetBackendF == "mongodb"
|
||||
}
|
||||
|
||||
// IsYugabyteDB returns true if the current test is running for `ferretdb-yugabytedb` backend.
|
||||
//
|
||||
// This function should not be used lightly.
|
||||
func IsYugabyteDB(tb testing.TB) bool {
|
||||
tb.Helper()
|
||||
|
||||
return *targetBackendF == "ferretdb-yugabytedb"
|
||||
}
|
||||
|
||||
// ensureIssueURL panics if URL is not a valid FerretDB issue URL.
|
||||
func ensureIssueURL(url string) {
|
||||
ferretDB := strings.HasPrefix(url, "https://github.com/FerretDB/FerretDB/issues/")
|
||||
@@ -98,17 +105,6 @@ func SkipForMongoDB(tb testing.TB, reason string) {
|
||||
}
|
||||
}
|
||||
|
||||
// Dir returns the absolute directory of this package.
|
||||
func Dir(tb testing.TB) string {
|
||||
tb.Helper()
|
||||
|
||||
_, file, _, ok := runtime.Caller(0)
|
||||
require.True(tb, ok)
|
||||
require.True(tb, filepath.IsAbs(file))
|
||||
|
||||
return filepath.Dir(file)
|
||||
}
|
||||
|
||||
// Main is the entry point for all integration test packages.
|
||||
// It should be called from main_test.go in each package.
|
||||
func Main(m *testing.M) {
|
||||
|
||||
@@ -19,18 +19,16 @@ import (
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/internal/clientconn"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/documentdb"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/handler"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/logging"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/handler/middleware"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/setup"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/state"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/testutil"
|
||||
)
|
||||
|
||||
// ListenerOpts represents setup options for in-process FerretDB listener.
|
||||
@@ -85,13 +83,13 @@ func listenerMongoDBURI(tb testing.TB, hostPort, unixSocketPath string) string {
|
||||
func setupListener(tb testing.TB, ctx context.Context, opts *ListenerOpts, logger *slog.Logger) string {
|
||||
tb.Helper()
|
||||
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setupListener")
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setup.setupListener")
|
||||
defer span.End()
|
||||
|
||||
require.Empty(tb, *targetURLF, "-target-url must be empty for in-process FerretDB")
|
||||
|
||||
switch *targetBackendF {
|
||||
case "ferretdb":
|
||||
case "ferretdb", "ferretdb-yugabytedb":
|
||||
require.NotEmpty(tb, *postgreSQLURLF, "-postgresql-url must be set for %q", *targetBackendF)
|
||||
|
||||
case "mongodb":
|
||||
@@ -109,59 +107,58 @@ func setupListener(tb testing.TB, ctx context.Context, opts *ListenerOpts, logge
|
||||
opts = new(ListenerOpts)
|
||||
}
|
||||
|
||||
p, err := documentdb.NewPool(*postgreSQLURLF, logging.WithName(logger, "pool"), sp)
|
||||
require.NoError(tb, err)
|
||||
|
||||
handlerOpts := &handler.NewOpts{
|
||||
Pool: p,
|
||||
Auth: true,
|
||||
|
||||
// TODO https://github.com/FerretDB/FerretDB-DocumentDB/issues/566
|
||||
TCPHost: "",
|
||||
ReplSetName: "",
|
||||
|
||||
L: logging.WithName(logger, "handler"),
|
||||
ConnMetrics: listenerMetrics.ConnMetrics,
|
||||
//exhaustruct:enforce
|
||||
wireOpts := &setup.SetupOpts{
|
||||
Logger: logger,
|
||||
StateProvider: sp,
|
||||
Metrics: middleware.NewMetrics(),
|
||||
|
||||
PostgreSQLURL: *postgreSQLURLF,
|
||||
Auth: true,
|
||||
ReplSetName: "", // TODO https://github.com/FerretDB/FerretDB-DocumentDB/issues/566
|
||||
SessionCleanupInterval: opts.SessionCleanupInterval,
|
||||
}
|
||||
|
||||
h, err := handler.New(handlerOpts)
|
||||
require.NoError(tb, err)
|
||||
ProxyAddr: "",
|
||||
ProxyTLSCertFile: "",
|
||||
ProxyTLSKeyFile: "",
|
||||
ProxyTLSCAFile: "",
|
||||
|
||||
listenerOpts := clientconn.ListenerOpts{
|
||||
Handler: h,
|
||||
Metrics: listenerMetrics,
|
||||
Logger: logger,
|
||||
Mode: clientconn.NormalMode,
|
||||
ProxyAddr: *targetProxyAddrF,
|
||||
TestRecordsDir: filepath.Join(Dir(tb), "..", "..", "tmp", "records"),
|
||||
}
|
||||
TCPAddr: "",
|
||||
UnixAddr: "",
|
||||
TLSAddr: "",
|
||||
TLSCertFile: "",
|
||||
TLSKeyFile: "",
|
||||
TLSCAFile: "",
|
||||
Mode: middleware.NormalMode,
|
||||
TestRecordsDir: testutil.TmpRecordsDir,
|
||||
|
||||
if *targetProxyAddrF != "" {
|
||||
listenerOpts.Mode = clientconn.DiffNormalMode
|
||||
DataAPIAddr: "",
|
||||
}
|
||||
|
||||
switch {
|
||||
case *targetUnixSocketF:
|
||||
listenerOpts.Unix = unixSocketPath(tb)
|
||||
wireOpts.UnixAddr = unixSocketPath(tb)
|
||||
default:
|
||||
listenerOpts.TCP = "127.0.0.1:0"
|
||||
wireOpts.TCPAddr = "127.0.0.1:0"
|
||||
}
|
||||
|
||||
l, err := clientconn.Listen(&listenerOpts)
|
||||
require.NoError(tb, err)
|
||||
if *targetProxyAddrF != "" {
|
||||
wireOpts.Mode = middleware.DiffNormalMode
|
||||
wireOpts.ProxyAddr = *targetProxyAddrF
|
||||
}
|
||||
|
||||
res := setup.Setup(ctx, wireOpts)
|
||||
require.NotNil(tb, res)
|
||||
|
||||
runDone := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(runDone)
|
||||
|
||||
runCtx, runSpan := otel.Tracer("").Start(ctx, "setupListener.Run")
|
||||
runCtx, runSpan := otel.Tracer("").Start(ctx, "setup.setupListener.Run")
|
||||
defer runSpan.End()
|
||||
|
||||
l.Run(runCtx)
|
||||
res.Run(runCtx)
|
||||
}()
|
||||
|
||||
// ensure that all listener's and handler's logs are written before test ends
|
||||
@@ -173,9 +170,9 @@ func setupListener(tb testing.TB, ctx context.Context, opts *ListenerOpts, logge
|
||||
|
||||
switch {
|
||||
case *targetUnixSocketF:
|
||||
unixSocketPath = l.UnixAddr().String()
|
||||
unixSocketPath = res.WireListener.UnixAddr().String()
|
||||
default:
|
||||
hostPort = l.TCPAddr().String()
|
||||
hostPort = res.WireListener.TCPAddr().String()
|
||||
}
|
||||
|
||||
uri := listenerMongoDBURI(tb, hostPort, unixSocketPath)
|
||||
|
||||
+61
-17
@@ -41,7 +41,7 @@ import (
|
||||
// Flags.
|
||||
var (
|
||||
targetURLF = flag.String("target-url", "", "target system's URL; if empty, in-process FerretDB is used")
|
||||
targetBackendF = flag.String("target-backend", "", "target system's backend: '%s'"+strings.Join(allBackends, "', '"))
|
||||
targetBackendF = flag.String("target-backend", "", "target system's backend: "+strings.Join(allBackends, ", "))
|
||||
|
||||
postgreSQLURLF = flag.String("postgresql-url", "", "in-process FerretDB: PostgreSQL URL")
|
||||
targetUnixSocketF = flag.Bool("target-unix-socket", false, "in-process FerretDB: use Unix domain socket")
|
||||
@@ -62,7 +62,7 @@ var (
|
||||
|
||||
// Other globals.
|
||||
var (
|
||||
allBackends = []string{"ferretdb", "mongodb"}
|
||||
allBackends = []string{"ferretdb", "ferretdb-yugabytedb", "mongodb"}
|
||||
)
|
||||
|
||||
// WireConn defines if and how wire client connection is established.
|
||||
@@ -147,7 +147,7 @@ func SetupWithOpts(tb testing.TB, opts *SetupOpts) *SetupResult {
|
||||
|
||||
ctx, cancel := context.WithCancel(testutil.Ctx(tb))
|
||||
|
||||
setupCtx, span := otel.Tracer("").Start(ctx, "SetupWithOpts")
|
||||
setupCtx, span := otel.Tracer("").Start(ctx, "setup.SetupWithOpts")
|
||||
defer span.End()
|
||||
|
||||
if opts == nil {
|
||||
@@ -204,7 +204,10 @@ func SetupWithOpts(tb testing.TB, opts *SetupOpts) *SetupResult {
|
||||
var conn *wireclient.Conn
|
||||
|
||||
if opts.WireConn != WireConnNoConn {
|
||||
conn = setupWireConn(tb, setupCtx, uri, testutil.Logger(tb))
|
||||
clearUri, creds, _, authMechanism, err := wireclient.Credentials(uri)
|
||||
require.NoError(tb, err)
|
||||
|
||||
conn = setupWireConn(tb, setupCtx, clearUri, testutil.Logger(tb))
|
||||
|
||||
if opts.WireConn == WireConnAuth {
|
||||
u, err := url.Parse(uri)
|
||||
@@ -216,7 +219,7 @@ func SetupWithOpts(tb testing.TB, opts *SetupOpts) *SetupResult {
|
||||
pass, _ := u.User.Password()
|
||||
require.NotEmpty(tb, pass)
|
||||
|
||||
require.NoError(tb, conn.Login(ctx, user, pass, "admin"))
|
||||
require.NoError(tb, conn.Login(ctx, creds, "admin", authMechanism))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +248,7 @@ func Setup(tb testing.TB, providers ...shareddata.Provider) (context.Context, *m
|
||||
func setupCollection(tb testing.TB, ctx context.Context, client *mongo.Client, opts *SetupOpts) *mongo.Collection {
|
||||
tb.Helper()
|
||||
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setupCollection")
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setup.setupCollection")
|
||||
defer span.End()
|
||||
|
||||
var ownDatabase bool
|
||||
@@ -261,10 +264,10 @@ func setupCollection(tb testing.TB, ctx context.Context, client *mongo.Client, o
|
||||
collection := database.Collection(collectionName)
|
||||
|
||||
// drop remnants of the previous failed run
|
||||
_ = collection.Drop(ctx)
|
||||
if ownDatabase {
|
||||
_ = database.RunCommand(ctx, bson.D{{"dropAllUsersFromDatabase", 1}})
|
||||
_ = database.Drop(ctx)
|
||||
cleanupDatabase(tb, ctx, database)
|
||||
} else {
|
||||
cleanupCollection(tb, ctx, collection)
|
||||
}
|
||||
|
||||
// drop collection and (possibly) database unless test failed
|
||||
@@ -274,16 +277,13 @@ func setupCollection(tb testing.TB, ctx context.Context, client *mongo.Client, o
|
||||
return
|
||||
}
|
||||
|
||||
err := collection.Drop(ctx)
|
||||
require.NoError(tb, err)
|
||||
|
||||
if ownDatabase {
|
||||
err = database.RunCommand(ctx, bson.D{{"dropAllUsersFromDatabase", 1}}).Err()
|
||||
require.NoError(tb, err)
|
||||
cleanupDatabase(tb, ctx, database)
|
||||
|
||||
err = database.Drop(ctx)
|
||||
require.NoError(tb, err)
|
||||
return
|
||||
}
|
||||
|
||||
cleanupCollection(tb, ctx, collection)
|
||||
})
|
||||
|
||||
var inserted bool
|
||||
@@ -309,7 +309,7 @@ func setupCollection(tb testing.TB, ctx context.Context, client *mongo.Client, o
|
||||
func InsertProviders(tb testing.TB, ctx context.Context, collection *mongo.Collection, providers ...shareddata.Provider) (inserted bool) {
|
||||
tb.Helper()
|
||||
|
||||
ctx, span := otel.Tracer("").Start(ctx, "InsertProviders")
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setup.InsertProviders")
|
||||
defer span.End()
|
||||
|
||||
for _, provider := range providers {
|
||||
@@ -342,3 +342,47 @@ func insertBenchmarkProvider(tb testing.TB, ctx context.Context, collection *mon
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// cleanupCollection deletes all documents in the collection for ferretdb-yugabytedb backend
|
||||
// or drops the collection for other backends.
|
||||
func cleanupCollection(tb testing.TB, ctx context.Context, collection *mongo.Collection) {
|
||||
tb.Helper()
|
||||
|
||||
if IsYugabyteDB(tb) {
|
||||
// dropping collection or database fails for ferretdb-yugabytedb
|
||||
// TODO https://github.com/yugabyte/yugabyte-db/issues/27698
|
||||
_, err := collection.DeleteMany(ctx, bson.D{})
|
||||
require.NoError(tb, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err := collection.Drop(ctx)
|
||||
require.NoError(tb, err)
|
||||
}
|
||||
|
||||
// cleanupDatabase drops all users, then deletes all collections in the database
|
||||
// for ferretdb-yugabytedb backend or drops the database for other backends.
|
||||
func cleanupDatabase(tb testing.TB, ctx context.Context, database *mongo.Database) {
|
||||
tb.Helper()
|
||||
|
||||
err := database.RunCommand(ctx, bson.D{{"dropAllUsersFromDatabase", 1}}).Err()
|
||||
require.NoError(tb, err)
|
||||
|
||||
if IsYugabyteDB(tb) {
|
||||
// dropping collection or database fails for ferretdb-yugabytedb
|
||||
// TODO https://github.com/yugabyte/yugabyte-db/issues/27698
|
||||
var collections []string
|
||||
collections, err = database.ListCollectionNames(ctx, bson.D{})
|
||||
require.NoError(tb, err)
|
||||
|
||||
for _, collection := range collections {
|
||||
cleanupCollection(tb, ctx, database.Collection(collection))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = database.Drop(ctx)
|
||||
require.NoError(tb, err)
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.opentelemetry.io/otel"
|
||||
|
||||
@@ -66,7 +65,7 @@ func SetupCompatWithOpts(tb testing.TB, opts *SetupCompatOpts) *SetupCompatResul
|
||||
|
||||
ctx, cancel := context.WithCancel(testutil.Ctx(tb))
|
||||
|
||||
setupCtx, span := otel.Tracer("").Start(ctx, "SetupCompatWithOpts")
|
||||
setupCtx, span := otel.Tracer("").Start(ctx, "setup.SetupCompatWithOpts")
|
||||
defer span.End()
|
||||
|
||||
if opts == nil {
|
||||
@@ -130,14 +129,13 @@ func SetupCompat(tb testing.TB) (context.Context, []*mongo.Collection, []*mongo.
|
||||
func setupCompatCollections(tb testing.TB, ctx context.Context, client *mongo.Client, opts *SetupCompatOpts, backend string) []*mongo.Collection {
|
||||
tb.Helper()
|
||||
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setupCompatCollections")
|
||||
ctx, span := otel.Tracer("").Start(ctx, "setup.setupCompatCollections")
|
||||
defer span.End()
|
||||
|
||||
database := client.Database(opts.databaseName)
|
||||
|
||||
// drop remnants of the previous failed run
|
||||
_ = database.RunCommand(ctx, bson.D{{"dropAllUsersFromDatabase", 1}})
|
||||
_ = database.Drop(ctx)
|
||||
cleanupDatabase(tb, ctx, database)
|
||||
|
||||
// drop database unless test failed
|
||||
tb.Cleanup(func() {
|
||||
@@ -145,11 +143,7 @@ func setupCompatCollections(tb testing.TB, ctx context.Context, client *mongo.Cl
|
||||
return
|
||||
}
|
||||
|
||||
err := database.RunCommand(ctx, bson.D{{"dropAllUsersFromDatabase", 1}}).Err()
|
||||
require.NoError(tb, err)
|
||||
|
||||
err = database.Drop(ctx)
|
||||
require.NoError(tb, err)
|
||||
cleanupDatabase(tb, ctx, database)
|
||||
})
|
||||
|
||||
providers := slices.Clone(opts.Providers)
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/internal/clientconn/connmetrics"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/debug"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/logging"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/observability"
|
||||
@@ -35,9 +34,6 @@ import (
|
||||
"github.com/FerretDB/FerretDB/v2/integration/shareddata"
|
||||
)
|
||||
|
||||
// listenerMetrics are shared between tests.
|
||||
var listenerMetrics = connmetrics.NewListenerMetrics()
|
||||
|
||||
// shutdown cancels context passed to startup components.
|
||||
var shutdown context.CancelFunc
|
||||
|
||||
@@ -63,8 +59,6 @@ func Startup() {
|
||||
*debugSetupF = true
|
||||
}
|
||||
|
||||
prometheus.DefaultRegisterer.MustRegister(listenerMetrics)
|
||||
|
||||
ctx, shutdown = context.WithCancel(ctx)
|
||||
|
||||
startupWG.Add(1)
|
||||
@@ -82,7 +76,7 @@ func Startup() {
|
||||
l.LogAttrs(ctx, logging.LevelFatal, "Failed to create debug handler", logging.Error(err))
|
||||
}
|
||||
|
||||
h.Serve(ctx)
|
||||
h.Run(ctx)
|
||||
}()
|
||||
|
||||
if *otelTracesURLF != "" {
|
||||
@@ -93,8 +87,8 @@ func Startup() {
|
||||
|
||||
ot, err := observability.NewOTelTraceExporter(&observability.OTelTraceExporterOpts{
|
||||
Logger: logging.WithName(l, "otel"),
|
||||
Service: "integration-tests",
|
||||
URL: *otelTracesURLF,
|
||||
Service: "integration-tests",
|
||||
})
|
||||
if err != nil {
|
||||
l.LogAttrs(ctx, logging.LevelFatal, "Failed to create Otel tracer", logging.Error(err))
|
||||
|
||||
@@ -1446,7 +1446,7 @@ func TestUpdateFieldCompatSet(t *testing.T) {
|
||||
doublesProvider := []shareddata.Provider{shareddata.Doubles}
|
||||
|
||||
testCases := map[string]updateCompatTestCase{
|
||||
"SetNullInExisingField": {
|
||||
"SetNullInExistingField": {
|
||||
update: bson.D{{"$set", bson.D{{"v", nil}}}},
|
||||
},
|
||||
"DuplicateKeys": {
|
||||
|
||||
+35
-507
@@ -29,110 +29,24 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/AlekSi/lazyerrors"
|
||||
"github.com/FerretDB/wire"
|
||||
"github.com/FerretDB/wire/wirebson"
|
||||
"github.com/pmezard/go-difflib/difflib"
|
||||
"go.opentelemetry.io/otel"
|
||||
otelattribute "go.opentelemetry.io/otel/attribute"
|
||||
otelcodes "go.opentelemetry.io/otel/codes"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/FerretDB/FerretDB/v2/internal/clientconn/conninfo"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/clientconn/connmetrics"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/handler"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/handler/middleware"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/handler/proxy"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/mongoerrors"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/lazyerrors"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/logging"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/must"
|
||||
"github.com/FerretDB/FerretDB/v2/internal/util/observability"
|
||||
)
|
||||
|
||||
// Mode represents FerretDB mode of operation.
|
||||
type Mode string
|
||||
|
||||
const (
|
||||
// NormalMode only handles requests.
|
||||
NormalMode Mode = "normal"
|
||||
// ProxyMode only proxies requests to another wire protocol compatible service.
|
||||
ProxyMode Mode = "proxy"
|
||||
// DiffNormalMode both handles requests and proxies them, then logs the diff.
|
||||
// Only the FerretDB response is sent to the client.
|
||||
DiffNormalMode Mode = "diff-normal"
|
||||
// DiffProxyMode both handles requests and proxies them, then logs the diff.
|
||||
// Only the proxy response is sent to the client.
|
||||
DiffProxyMode Mode = "diff-proxy"
|
||||
)
|
||||
|
||||
// AllModes includes all operation modes, with the first one being the default.
|
||||
var AllModes = []string{
|
||||
string(NormalMode),
|
||||
string(ProxyMode),
|
||||
string(DiffNormalMode),
|
||||
string(DiffProxyMode),
|
||||
}
|
||||
|
||||
// conn represents client connection.
|
||||
type conn struct {
|
||||
netConn net.Conn
|
||||
mode Mode
|
||||
l *slog.Logger
|
||||
h *handler.Handler
|
||||
m *connmetrics.ConnMetrics
|
||||
proxy *proxy.Handler
|
||||
lastRequestID atomic.Int32
|
||||
m *middleware.Middleware
|
||||
testRecordsDir string // if empty, no records are created
|
||||
}
|
||||
|
||||
// newConnOpts represents newConn options.
|
||||
type newConnOpts struct {
|
||||
netConn net.Conn
|
||||
mode Mode
|
||||
l *slog.Logger
|
||||
handler *handler.Handler
|
||||
connMetrics *connmetrics.ConnMetrics
|
||||
|
||||
proxyAddr string
|
||||
proxyTLSCertFile string
|
||||
proxyTLSKeyFile string
|
||||
proxyTLSCAFile string
|
||||
|
||||
testRecordsDir string // if empty, no records are created
|
||||
}
|
||||
|
||||
// newConn creates a new client connection for given net.Conn.
|
||||
func newConn(opts *newConnOpts) (*conn, error) {
|
||||
if opts.mode == "" {
|
||||
panic("mode required")
|
||||
}
|
||||
if opts.handler == nil {
|
||||
panic("handler required")
|
||||
}
|
||||
|
||||
var p *proxy.Handler
|
||||
if opts.mode != NormalMode {
|
||||
var err error
|
||||
if p, err = proxy.New(opts.proxyAddr, opts.proxyTLSCertFile, opts.proxyTLSKeyFile, opts.proxyTLSCAFile); err != nil {
|
||||
return nil, lazyerrors.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
return &conn{
|
||||
netConn: opts.netConn,
|
||||
mode: opts.mode,
|
||||
l: opts.l,
|
||||
h: opts.handler,
|
||||
m: opts.connMetrics,
|
||||
proxy: p,
|
||||
testRecordsDir: opts.testRecordsDir,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// run runs the client connection until ctx is canceled, client disconnects,
|
||||
// or fatal error or panic is encountered.
|
||||
//
|
||||
@@ -140,51 +54,32 @@ func newConn(opts *newConnOpts) (*conn, error) {
|
||||
//
|
||||
// The caller is responsible for closing the underlying net.Conn.
|
||||
func (c *conn) run(ctx context.Context) (err error) {
|
||||
ctx, cancel := context.WithCancelCause(ctx)
|
||||
defer func() {
|
||||
cancel(lazyerrors.Errorf("run exits: %w", err))
|
||||
}()
|
||||
|
||||
connInfo := conninfo.New()
|
||||
if c.netConn.RemoteAddr().Network() != "unix" {
|
||||
connInfo.Peer, err = netip.ParseAddrPort(c.netConn.RemoteAddr().String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx = conninfo.Ctx(ctx, connInfo)
|
||||
|
||||
// That's not the best – it makes proxy handler very different from the main handler.
|
||||
// Instead, proxy handler should map connections based on connInfo.
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/4965
|
||||
if c.proxy != nil {
|
||||
go c.proxy.Run(ctx)
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
// handle ctx cancellation
|
||||
go func() {
|
||||
select {
|
||||
case <-done:
|
||||
// nothing, let goroutine exit
|
||||
case <-ctx.Done():
|
||||
// unblocks ReadMessage below; any non-zero past value will do
|
||||
if e := c.netConn.SetDeadline(time.Unix(0, 0)); e != nil {
|
||||
c.l.WarnContext(ctx, fmt.Sprintf("Failed to set deadline: %s", e))
|
||||
}
|
||||
}
|
||||
}()
|
||||
ci := conninfo.New()
|
||||
ctx, cancel := context.WithCancelCause(conninfo.Ctx(ctx, ci))
|
||||
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
c.l.LogAttrs(ctx, logging.LevelDPanic, fmt.Sprint(p), logging.Error(err))
|
||||
err = errors.New("panic")
|
||||
err = lazyerrors.New("panic")
|
||||
}
|
||||
|
||||
// let goroutine above exit
|
||||
close(done)
|
||||
cancel(lazyerrors.Errorf("run exits: %w", err))
|
||||
ci.Close()
|
||||
}()
|
||||
|
||||
if c.netConn.RemoteAddr().Network() != "unix" {
|
||||
ci.Peer, err = netip.ParseAddrPort(c.netConn.RemoteAddr().String())
|
||||
if err != nil {
|
||||
err = lazyerrors.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
|
||||
// unblocks ReadMessage in the processRequest below; any non-zero past value will do
|
||||
_ = c.netConn.SetDeadline(time.Unix(0, 0))
|
||||
}()
|
||||
|
||||
bufr := bufio.NewReader(c.netConn)
|
||||
@@ -215,323 +110,43 @@ func (c *conn) run(ctx context.Context) (err error) {
|
||||
|
||||
bufw := bufio.NewWriter(c.netConn)
|
||||
|
||||
defer func() {
|
||||
if e := bufw.Flush(); err == nil {
|
||||
err = e
|
||||
}
|
||||
|
||||
// c.netConn is closed by the caller
|
||||
}()
|
||||
|
||||
for {
|
||||
if err = c.processMessage(ctx, bufr, bufw); err != nil {
|
||||
if err = c.processRequest(ctx, bufr, bufw); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// processMessage reads the request, routes the request based on the operation mode
|
||||
// and writes the response.
|
||||
// processRequest reads the request, passes it to the middleware, and writes the response.
|
||||
//
|
||||
// Any error returned indicates the connection should be closed.
|
||||
func (c *conn) processMessage(ctx context.Context, bufr *bufio.Reader, bufw *bufio.Writer) error {
|
||||
func (c *conn) processRequest(ctx context.Context, bufr *bufio.Reader, bufw *bufio.Writer) error {
|
||||
reqHeader, reqBody, err := wire.ReadMessage(bufr)
|
||||
if err != nil {
|
||||
return err
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
if c.l.Enabled(ctx, slog.LevelDebug) {
|
||||
c.l.DebugContext(ctx, "Request header: "+reqHeader.String())
|
||||
c.l.DebugContext(ctx, "Request message:\n"+reqBody.StringIndent())
|
||||
req, err := middleware.RequestWire(reqHeader, reqBody)
|
||||
if err != nil {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
// diffLogLevel provides the level of logging for the diff between the "normal" and "proxy" responses.
|
||||
// It is set to the highest level of logging used to log response.
|
||||
diffLogLevel := slog.LevelDebug
|
||||
|
||||
// send request to proxy first (unless we are in normal mode)
|
||||
// because FerretDB's handling could modify reqBody's documents,
|
||||
// creating a data race
|
||||
var proxyHeader *wire.MsgHeader
|
||||
var proxyBody wire.MsgBody
|
||||
|
||||
if c.mode != NormalMode {
|
||||
if c.proxy == nil {
|
||||
panic("proxy addr was nil")
|
||||
}
|
||||
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/1997
|
||||
var resp *middleware.Response
|
||||
resp, err = c.proxy.Handle(ctx, middleware.RequestWire(reqHeader, reqBody))
|
||||
must.NoError(err)
|
||||
|
||||
proxyHeader = resp.WireHeader()
|
||||
|
||||
switch {
|
||||
case resp.OpMsg != nil:
|
||||
proxyBody = resp.OpMsg
|
||||
case resp.OpReply != nil:
|
||||
proxyBody = resp.OpReply
|
||||
default:
|
||||
panic("response body is nil")
|
||||
}
|
||||
resp := c.m.Handle(ctx, req)
|
||||
if resp == nil {
|
||||
return lazyerrors.New("middleware returned nil response")
|
||||
}
|
||||
|
||||
// handle request unless we are in proxy mode
|
||||
var resCloseConn bool
|
||||
var resHeader *wire.MsgHeader
|
||||
var resBody wire.MsgBody
|
||||
|
||||
if c.mode != ProxyMode {
|
||||
resHeader, resBody, resCloseConn = c.route(ctx, reqHeader, reqBody)
|
||||
if level := c.logResponse(ctx, "Response", resHeader, resBody, resCloseConn); level > diffLogLevel {
|
||||
diffLogLevel = level
|
||||
}
|
||||
}
|
||||
|
||||
// log proxy response after the normal response to make it less confusing
|
||||
if c.mode != NormalMode {
|
||||
if level := c.logResponse(ctx, "Proxy response", proxyHeader, proxyBody, false); level > diffLogLevel {
|
||||
diffLogLevel = level
|
||||
}
|
||||
}
|
||||
|
||||
// diff in diff mode
|
||||
if c.l.Enabled(ctx, diffLogLevel) && (c.mode == DiffNormalMode || c.mode == DiffProxyMode) {
|
||||
if err = c.logDiff(ctx, resHeader, proxyHeader, resBody, proxyBody, diffLogLevel); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// replace response with one from proxy in proxy and diff-proxy modes
|
||||
if c.mode == ProxyMode || c.mode == DiffProxyMode {
|
||||
resHeader = proxyHeader
|
||||
resBody = proxyBody
|
||||
}
|
||||
|
||||
if resHeader == nil || resBody == nil {
|
||||
panic("no response to send to client")
|
||||
}
|
||||
|
||||
if err = wire.WriteMessage(bufw, resHeader, resBody); err != nil {
|
||||
c.l.DebugContext(ctx, "Failed to write message", logging.Error(err))
|
||||
|
||||
return err
|
||||
if err = wire.WriteMessage(bufw, resp.WireHeader(), resp.WireBody()); err != nil {
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
if err = bufw.Flush(); err != nil {
|
||||
c.l.DebugContext(ctx, "Failed to flush buffer", logging.Error(err))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if resCloseConn {
|
||||
err = errors.New("fatal error")
|
||||
|
||||
c.l.DebugContext(ctx, "Connection closed unexpectedly", logging.Error(err))
|
||||
|
||||
return err
|
||||
return lazyerrors.Error(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// route sends request to a handler's command based on the op code provided in the request header.
|
||||
//
|
||||
// The passed context is canceled when the client disconnects.
|
||||
//
|
||||
// Handlers to which it routes, should not panic on bad input, but may do so in "impossible" cases.
|
||||
// They also should not use recover(). That allows us to use fuzzing.
|
||||
//
|
||||
// Returned resBody can be nil.
|
||||
func (c *conn) route(connCtx context.Context, reqHeader *wire.MsgHeader, reqBody wire.MsgBody) (resHeader *wire.MsgHeader, resBody wire.MsgBody, closeConn bool) { //nolint:lll // argument list is too long
|
||||
var span oteltrace.Span
|
||||
|
||||
var command, result, argument string
|
||||
defer func() {
|
||||
if result == "" {
|
||||
result = "panic"
|
||||
}
|
||||
|
||||
if argument == "" {
|
||||
argument = "unknown"
|
||||
}
|
||||
|
||||
c.m.Responses.WithLabelValues(resHeader.OpCode.String(), command, argument, result).Inc()
|
||||
|
||||
must.NotBeZero(span)
|
||||
|
||||
if result != "ok" {
|
||||
span.SetStatus(otelcodes.Error, result)
|
||||
}
|
||||
|
||||
span.SetName(command)
|
||||
span.SetAttributes(
|
||||
otelattribute.String("db.ferretdb.opcode", resHeader.OpCode.String()),
|
||||
otelattribute.Int("db.ferretdb.request_id", int(resHeader.ResponseTo)),
|
||||
otelattribute.String("db.ferretdb.argument", argument),
|
||||
)
|
||||
span.End()
|
||||
}()
|
||||
|
||||
resHeader = new(wire.MsgHeader)
|
||||
|
||||
var err error
|
||||
switch reqHeader.OpCode {
|
||||
case wire.OpCodeMsg:
|
||||
msg := reqBody.(*wire.OpMsg)
|
||||
|
||||
resHeader.OpCode = wire.OpCodeMsg
|
||||
|
||||
var doc *wirebson.Document
|
||||
if doc, err = msg.Section0(); err == nil {
|
||||
command = doc.Command()
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
comment, _ := doc.Get("comment").(string)
|
||||
|
||||
spanCtx, e := observability.SpanContextFromComment(comment)
|
||||
if e == nil {
|
||||
connCtx = oteltrace.ContextWithRemoteSpanContext(connCtx, spanCtx)
|
||||
} else {
|
||||
c.l.DebugContext(connCtx, "Failed to extract span context from comment", logging.Error(e))
|
||||
}
|
||||
}
|
||||
|
||||
connCtx, span = otel.Tracer("").Start(connCtx, "")
|
||||
|
||||
if err == nil {
|
||||
var res *middleware.Response
|
||||
if res, err = c.h.Handle(connCtx, middleware.RequestWire(reqHeader, msg)); res != nil {
|
||||
resBody = res.OpMsg
|
||||
}
|
||||
}
|
||||
|
||||
case wire.OpCodeQuery:
|
||||
query := reqBody.(*wire.OpQuery)
|
||||
|
||||
resHeader.OpCode = wire.OpCodeReply
|
||||
|
||||
var q *wirebson.Document
|
||||
if q, err = query.Query(); err == nil {
|
||||
command = q.Command()
|
||||
}
|
||||
|
||||
connCtx, span = otel.Tracer("").Start(connCtx, "")
|
||||
|
||||
if err == nil {
|
||||
var res *middleware.Response
|
||||
if res, err = c.h.Handle(connCtx, middleware.RequestWire(reqHeader, query)); res != nil {
|
||||
resBody = res.OpReply
|
||||
}
|
||||
}
|
||||
|
||||
case wire.OpCodeReply:
|
||||
fallthrough
|
||||
case wire.OpCodeUpdate:
|
||||
fallthrough
|
||||
case wire.OpCodeInsert:
|
||||
fallthrough
|
||||
case wire.OpCodeGetByOID:
|
||||
fallthrough
|
||||
case wire.OpCodeGetMore:
|
||||
fallthrough
|
||||
case wire.OpCodeDelete:
|
||||
fallthrough
|
||||
case wire.OpCodeKillCursors:
|
||||
fallthrough
|
||||
case wire.OpCodeCompressed:
|
||||
connCtx, span = otel.Tracer("").Start(connCtx, "")
|
||||
err = lazyerrors.Errorf("unhandled OpCode %s", reqHeader.OpCode)
|
||||
|
||||
default:
|
||||
connCtx, span = otel.Tracer("").Start(connCtx, "")
|
||||
err = lazyerrors.Errorf("unexpected OpCode %s", reqHeader.OpCode)
|
||||
}
|
||||
|
||||
if command == "" {
|
||||
command = "unknown"
|
||||
}
|
||||
|
||||
c.m.Requests.WithLabelValues(reqHeader.OpCode.String(), command).Inc()
|
||||
|
||||
// set body for error
|
||||
if err != nil {
|
||||
switch resHeader.OpCode {
|
||||
case wire.OpCodeMsg:
|
||||
protoErr := mongoerrors.Make(connCtx, err, "", c.l)
|
||||
resBody = protoErr.Msg()
|
||||
result = protoErr.Name
|
||||
argument = protoErr.Argument
|
||||
|
||||
case wire.OpCodeReply:
|
||||
protoErr := mongoerrors.Make(connCtx, err, "", c.l)
|
||||
resBody = protoErr.Reply()
|
||||
result = protoErr.Name
|
||||
argument = protoErr.Argument
|
||||
|
||||
case wire.OpCodeQuery:
|
||||
fallthrough
|
||||
case wire.OpCodeUpdate:
|
||||
fallthrough
|
||||
case wire.OpCodeInsert:
|
||||
fallthrough
|
||||
case wire.OpCodeGetByOID:
|
||||
fallthrough
|
||||
case wire.OpCodeGetMore:
|
||||
fallthrough
|
||||
case wire.OpCodeDelete:
|
||||
fallthrough
|
||||
case wire.OpCodeKillCursors:
|
||||
fallthrough
|
||||
case wire.OpCodeCompressed:
|
||||
// do not panic to make fuzzing easier
|
||||
closeConn = true
|
||||
result = "unhandled"
|
||||
|
||||
c.l.ErrorContext(
|
||||
connCtx,
|
||||
"Handler error for unhandled response opcode",
|
||||
logging.Error(err),
|
||||
slog.Any("opcode", resHeader.OpCode),
|
||||
)
|
||||
return
|
||||
|
||||
default:
|
||||
// do not panic to make fuzzing easier
|
||||
closeConn = true
|
||||
result = "unexpected"
|
||||
|
||||
c.l.ErrorContext(
|
||||
connCtx,
|
||||
"Handler error for unexpected response opcode",
|
||||
logging.Error(err),
|
||||
slog.Any("opcode", resHeader.OpCode),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Don't call MarshalBinary there. Fix header in the caller?
|
||||
// TODO https://github.com/FerretDB/FerretDB/issues/273
|
||||
b, err := resBody.MarshalBinary()
|
||||
if err != nil {
|
||||
result = ""
|
||||
panic(err)
|
||||
}
|
||||
resHeader.MessageLength = int32(wire.MsgHeaderLen + len(b))
|
||||
|
||||
resHeader.RequestID = c.lastRequestID.Add(1)
|
||||
resHeader.ResponseTo = reqHeader.RequestID
|
||||
|
||||
if result == "" {
|
||||
result = "ok"
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// renamePartialFile takes over an open file `f` and closes it.
|
||||
// It uses the given error to check if the connection was closed by the client,
|
||||
// if so the given file is renamed to a name generated by hash,
|
||||
@@ -566,90 +181,3 @@ func (c *conn) renamePartialFile(ctx context.Context, f *os.File, h hash.Hash, e
|
||||
c.l.WarnContext(ctx, "Failed to rename file", logging.Error(e))
|
||||
}
|
||||
}
|
||||
|
||||
// logResponse logs response's header and body and returns the log level that was used.
|
||||
//
|
||||
// The param `who` will be used in logs and should represent the type of the response,
|
||||
// for example "Response" or "Proxy Response".
|
||||
func (c *conn) logResponse(ctx context.Context, who string, resHeader *wire.MsgHeader, resBody wire.MsgBody, closeConn bool) slog.Level { //nolint:lll // for readability
|
||||
level := slog.LevelDebug
|
||||
|
||||
if resHeader.OpCode == wire.OpCodeMsg {
|
||||
msg := resBody.(*wire.OpMsg)
|
||||
|
||||
doc, _ := msg.Section0()
|
||||
|
||||
var ok bool
|
||||
|
||||
if doc != nil {
|
||||
switch v := doc.Get("ok").(type) {
|
||||
case float64:
|
||||
ok = v == 1
|
||||
case int32:
|
||||
ok = v == 1
|
||||
case int64:
|
||||
ok = v == 1
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
level = slog.LevelWarn
|
||||
}
|
||||
}
|
||||
|
||||
if closeConn {
|
||||
level = slog.LevelError
|
||||
}
|
||||
|
||||
if c.l.Enabled(ctx, level) {
|
||||
c.l.Log(ctx, level, who+" header: "+resHeader.String())
|
||||
c.l.Log(ctx, level, who+" message:\n"+resBody.StringIndent())
|
||||
}
|
||||
|
||||
return level
|
||||
}
|
||||
|
||||
// logDiff logs the diff between the response and the proxy response.
|
||||
func (c *conn) logDiff(ctx context.Context, resHeader, proxyHeader *wire.MsgHeader, resBody, proxyBody wire.MsgBody, logLevel slog.Level) error { //nolint:lll // for readability
|
||||
diffHeader, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
|
||||
A: difflib.SplitLines(resHeader.String()),
|
||||
FromFile: "res header",
|
||||
B: difflib.SplitLines(proxyHeader.String()),
|
||||
ToFile: "proxy header",
|
||||
Context: 1,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// resBody can be nil if we got a message we could not handle at all, like unsupported OpQuery.
|
||||
var resBodyString, proxyBodyString string
|
||||
|
||||
if resBody != nil {
|
||||
resBodyString = resBody.StringIndent()
|
||||
}
|
||||
|
||||
if proxyBody != nil {
|
||||
proxyBodyString = proxyBody.StringIndent()
|
||||
}
|
||||
|
||||
diffBody, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
|
||||
A: difflib.SplitLines(resBodyString),
|
||||
FromFile: "res body",
|
||||
B: difflib.SplitLines(proxyBodyString),
|
||||
ToFile: "proxy body",
|
||||
Context: 1,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(diffBody) > 0 {
|
||||
// the diff control lines (those with ---, +++, or @@) are created with a trailing newline
|
||||
diffBody = "\n" + strings.TrimSpace(diffBody)
|
||||
}
|
||||
|
||||
c.l.Log(ctx, logLevel, "Header diff:\n"+diffHeader+"\nBody diff:"+diffBody)
|
||||
|
||||
return nil
|
||||
}
|
||||
Loaded 100 of 685 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user