Compare commits

...

117 Commits
master ... v6.2

Author SHA1 Message Date
Maddie Zechar
4a20978382 SERVER-73735 Fail more gracefully if telemetry store configuration is attempted and telemetry store is disabled 2023-03-21 15:38:45 +00:00
Alyssa Wagenmaker
eb23c1b873 SERVER-72833 implement setProfilingFilterGlobally command 2023-03-17 18:41:24 +00:00
Miguel Angel Nieto
e3c738c4da SERVER-74690: Change Atlas Real variants to use "2022-11" workload client 2023-03-15 17:16:13 +00:00
Luke Chen
faaa2c6964 Import wiredtiger: 49bf5b56d0fad5660a5ff0054b55ab67b4b3047a from branch mongodb-6.2
ref: 658d4f5020..49bf5b56d0
for: 6.2.2

WT-10512 Fix not inserting an out of order timestamp into the history store
2023-03-13 15:32:37 +11:00
Luke Chen
8b2023a654 Import wiredtiger: 658d4f50200860d037e47408b8c43258a1c596f6 from branch mongodb-6.2
ref: 9ea2e3c4b8..658d4f5020
for: 6.2.2

WT-10575 Fix checkpoint cursor to return only stable data
2023-03-13 15:32:37 +11:00
Luke Chen
3668b2376b Import wiredtiger: 9ea2e3c4b8bc41c18e5a18026904bd4fa32d3fbf from branch mongodb-6.2
ref: c4af3d0916..9ea2e3c4b8
for: 6.2.2

WT-10449 Do not save update chain when there are no updates to be written to the history store
2023-03-13 15:32:37 +11:00
Jawwad Asghar
cea384d8e7 SERVER-72520 Removing deprecated performance project perf.yml file 2023-03-10 16:49:41 +00:00
Jawwad Asghar
af4f6f1457 SERVER-72519 Add arm and intel Microbenchmark test variants to Sys Perf 2023-03-06 22:52:37 +00:00
Denis Grebennicov
10fd84b685 SERVER-73833 Make the server to ignore and automatically remove unsupported 'recordPreImages' collection option 2023-02-17 14:08:55 +00:00
Luke Chen
78ba288ddc Import wiredtiger: c4af3d09161e47fa77cab8cdd322a976a16db3e8 from branch mongodb-6.2
ref: 20a34076e3..c4af3d0916
for: 6.2.1

WT-10584 Add missing read barriers in __cursor_skip_prev
2023-02-16 15:15:55 +11:00
Kevin Cherkauer
5a20629d20 SERVER-73822 Time-series $group rewrite ignores certain accumulators
(cherry picked from commit f9fd648140)
(cherry picked from commit c7f9aac258688e06e07919d713d919cd58e9125c)
2023-02-13 18:32:46 +00:00
Gregory Wlodarek
f1c2fc508f SERVER-73745 Zero initialize IndexKeyBucket struct
(cherry picked from commit ceb331a747)
2023-02-11 20:12:25 +00:00
Dan Larkin-York
4852124956 SERVER-72512 SERVER-73636 Ensure validate surfaces index key inconsistencies if they exist
(cherry picked from commit c0e1438cad)
(cherry picked from commit 2d90115a22)
2023-02-11 20:08:20 +00:00
Dan Larkin-York
1239081e30 SERVER-72677 Surface index validation errors arising from WT::verify
(cherry picked from commit 40c93f028e)
2023-02-11 19:36:49 +00:00
Luke Chen
a2cc20bf8b Import wiredtiger: 20a34076e3a41123776ed31332711770680a7514 from branch mongodb-6.2
ref: 6f2040328b..20a34076e3
for: 6.2.1

WT-10461 Fix key out of order in skip list on weakly ordered architecture
2023-02-09 13:52:11 +11:00
dalyd
a1b048ca66 SERVER-73719 Comment out legacy sys-perf buildvariants v6.2 2023-02-08 22:47:08 +00:00
dalyd
f3ff7049ba SERVER-71969 Change sys-perf dsi compile-variant expansion v6.2 2023-02-08 21:53:39 +00:00
Aaron Morand
4fa7a897ed SERVER-70677 Update the FCV constant in the logkeeper snapshot workload for 6.2 2023-01-20 00:20:40 +00:00
Tural Farhadov
290112ef13 SERVER-70819: Reverting Barque test config added by SERVER-70805
(cherry picked from commit d5b298034e)
2023-01-12 21:43:04 +00:00
Aaron Morand
153ecfe425 SERVER-72695 Fixes the push_arch name for Ubuntu 22.04 arm64 variants 2023-01-12 15:31:43 +00:00
Jacob Evans
7676045db7 SERVER-72639 Wait for startup_log in ftdc jstest 2023-01-10 22:02:53 +00:00
Alyssa Wagenmaker
35832bd3cb SERVER-71691 handle paused execution in setWindowFields 2023-01-10 19:21:55 +00:00
Jeff Zambory
0f8ed3b2ae SERVER-71726: Increase timeout of server_discovery_and_monitoring_json_test
(cherry picked from commit 62645f4595)
2023-01-10 18:49:09 +00:00
Yuhong Zhang
ef0e913ce7 SERVER-72495 Return warnings about CodeWScope correctly in checkBSONConformance mode for validate
(cherry picked from commit 58bf88893c)
2023-01-09 17:29:01 +00:00
Pierlauro Sciarelli
d90c776681 SERVER-72290 deleteRangeDeletionTasksForRename must not deregister tasks for the target collection 2023-01-09 16:28:34 +00:00
Antonio Fuschetto
a31c4c6c4b SERVER-69890 Concurrent movePrimary and removeShard can move database to a no-longer existent shard 2023-01-09 15:55:44 +00:00
Matthew Russotto
718bf390c8 SERVER-72422 FCBIS may never truncate the oplog (tests) 2023-01-06 17:21:28 +00:00
Arun Banala
eb8910b86a SERVER-72416 Find and findAndModify commands' ExpressionContext should inherit collection level collation
(cherry picked from commit 2f1b039897)
2023-01-05 18:45:49 +00:00
Hana Pearlman
2db2ccc12b SERVER-71588: Reenable type bracketing tests for CQF 2023-01-05 18:18:14 +00:00
Luke Chen
3be9114472 Import wiredtiger: 6f2040328bf9d20a0c01544394bc9d42d09c09b6 from branch mongodb-6.2
ref: 9a33bcf39f..6f2040328b
for: 6.2.0-rc5

WT-10291 Only run test format failure configs once
2023-01-05 02:26:30 +00:00
Luke Chen
465b6878c2 Import wiredtiger: 9a33bcf39fe9ce430729ad16865b149838fbff07 from branch mongodb-6.2
ref: 659bbb26d9..9a33bcf39f
for: 6.2.0-rc5

WT-10250 Remove certain Evergreen builders for release branches
2023-01-05 02:26:30 +00:00
Yuhong Zhang
3dc6cd2613 SERVER-70139 Check a view's property before returning it as a time-series collection in the listCollections result
(cherry picked from commit 6fc43f3993)
2023-01-03 23:29:44 +00:00
james-hippler
f058a17e0c SERVER-72021 Fix Enterprise SLES 12 Patch Failure 2023-01-03 21:59:06 +00:00
Aaron Morand
7fbabf32d9
SERVER-72276 Removing outdated entries for multiversion tests (#1516)
* SERVER-72276 Removing outdated entries for multiversion tests

* SERVER-72276 Corrected which js files are to be omitted.
2022-12-22 17:35:43 -05:00
Paolo Polato
e86b8c099e SERVER-72065 Fix refresh of sessions cache in CSRS secondary nodes 2022-12-19 15:26:18 +00:00
Samy Lanka
f037f034bb SERVER-67213 Wait for all nodes to install config before doing a force reconfig in reconfig.js
(cherry picked from commit e5e5f384e9)
2022-12-16 21:26:37 +00:00
Gregory Noma
4b44c24078 SERVER-72005 Run TSBS on 2022-11 sys-perf variants 2022-12-15 16:08:49 +00:00
Yu Jin Kang Park
5f3ed635a7 SERVER-61909 Fix transaction_too_large_for_cache.js to requires_fcv_62 2022-12-12 18:22:26 +00:00
Trevor Guidry
d4108459eb SERVER-71982 set directConnection=True in standalone.py
this is for multiversion testing with pymongo v4
2022-12-09 20:25:41 +00:00
dalyd
ae174ad93c SERVER-70594 Add updated build variants to sys-perf @dalyd 2022-12-09 17:44:28 +00:00
Jason Chan
d8c83636e6 SERVER-71685 Remove sampling of connAcquisitionToWire metrics
(cherry picked from commit 8cefa36fdd)
2022-12-09 17:14:31 +00:00
Jacob Evans
be31f3772c SERVER-71838 Remove deprecated collStats in ftdc 2022-12-08 21:13:20 +00:00
Jacob Evans
194a588a57 SERVER-71961 Don't expect absent collection ftdc 2022-12-08 20:42:33 +00:00
Allison Easton
84cb06c4db SERVER-71756 Defragmentation policy should issue dataSize commands with estimate true
(cherry picked from commit 49c71b3699)
2022-12-07 21:37:36 +00:00
Suganthi Mani
6b55bbebb1 SERVER-71683 Tenant collection cloner reads the next batch from socket buffer only after writing all the documents in the current batch to storage
(cherry picked from commit 5fee6fff13)
2022-12-07 17:09:48 +00:00
Ryan Egesdahl
135dee6512 SERVER-71902 Remove test_packages_complete task 2022-12-06 20:53:02 +00:00
Tausif Rahman
6f196e05ce SERVER-68500 multiversion tag files are not correctly excluding tests in CI
(cherry picked from commit f4dae67839)
2022-12-06 18:01:19 +00:00
Dan Larkin-York
6161d31622 SERVER-71723 Store WriteBatch measurements using small_vector
(cherry picked from commit 7ca2aafe45)
2022-12-06 17:22:19 +00:00
Tausif Rahman
f2a5b9e9bf Revert "SERVER-68500 multiversion tag files are not correctly excluding tests in CI"
This reverts commit ba23c18841.
2022-12-06 17:18:59 +00:00
Dan Larkin-York
0bb9d60967 SERVER-71721 Avoid extra string copy in NamespaceString constructor
(cherry picked from commit 1bca070739)
2022-12-06 16:50:10 +00:00
Dan Larkin-York
490ac76661 SERVER-71720 Move WriteBatch shared_ptr instead of copying
(cherry picked from commit e2fc105891)
2022-12-06 16:21:42 +00:00
Dan Larkin-York
9b96ed3f33 SERVER-71719 Check if we have bucket to reopen before calling rehydrateBucket
(cherry picked from commit 31be4c3818)
2022-12-06 16:19:41 +00:00
Dan Larkin-York
9d78ef337b SERVER-71718 Refactor extractTimeAndMeta to branch earlier and iterate document once
(cherry picked from commit 88d18f93e8)
2022-12-06 15:47:15 +00:00
Allison Easton
89b2e659a2 SERVER-71788 Defragmentation should handle ChunkTooBig errors
(cherry picked from commit 76d4cb7bd5)
2022-12-05 18:11:12 +00:00
Pierlauro Sciarelli
d3fab9c982 SERVER-71787 Balancer needs to attach forceJumbo to moveRange command 2022-12-05 12:11:43 +00:00
Tommaso Tocci
a7c27ed890 SERVER-71759 dataSize command doesn't yield
(cherry picked from commit 44d81c74e5)
2022-12-03 15:26:48 +00:00
Tausif Rahman
ba23c18841 SERVER-68500 multiversion tag files are not correctly excluding tests in CI
(cherry picked from commit 7a6f90b2bb)
2022-12-03 00:42:57 +00:00
Yu Jin Kang Park
cb651c8d8e SERVER-71750 Revert writeConflictRetry refactor into handleWriteConflictException
(cherry picked from commit 552afb106b)
2022-12-02 14:46:29 +00:00
Yu Jin Kang Park
7e8d18a464 SERVER-71751 Skip core/transaction_too_large_for_cache.js in non-WT storage engines
(cherry picked from commit 761037636e)
2022-12-02 14:46:29 +00:00
Yu Jin Kang Park
9ca8158531 SERVER-61909 Abort operation if it cannot ever fit in WT cache
(cherry picked from commit 9ddbd35120)
2022-12-02 14:46:29 +00:00
Yuhong Zhang
f90b35cf6c SERVER-71360 Avoid signed promotion on the value of the subtype before casting to BinDataType (cherry picked from commit d69c4bd59c) 2022-12-01 20:05:46 +00:00
Jess Balint
7382e1a20f SERVER-65790 create telemetry feature flag 2022-12-01 06:17:59 +00:00
Pierlauro Sciarelli
63d6350c8a SERVER-71666 Reduce number of scanned index entries on chunk migration commit
(cherry picked from commit 591bce5984)
2022-11-30 22:15:28 +00:00
Mindaugas Malinauskas
e62af19b57 SERVER-71568 Fix race condition related to access to ChangeStreamOptions
(cherry picked from commit 92d8c8e3aa)
2022-11-30 13:11:40 +00:00
Tausif Rahman
e7b8e61a29 SERVER-71506 Refactor tooling metrics
(cherry picked from commit b06927da23)
2022-11-29 18:58:50 +00:00
Yu Jin Kang Park
8045c4a777 SERVER-68739 Do not reset WT session stats when fetching op stats 2022-11-29 18:03:30 +00:00
Pol Pinol Castuera
923b5fd65a SERVER-68576 Added number of sharded collections to serverStatus command. 2022-11-29 08:28:01 +00:00
Tausif Rahman
b6ff8ad7ad SERVER-71411 Replace asyncio with explicit timeouts in metrics collection
(cherry picked from commit 93b1775dd9)
2022-11-28 16:34:37 +00:00
Luke Chen
833d66db10 Import wiredtiger: 659bbb26d9e357b714a782755442c78e05ddca7a from branch mongodb-6.2
ref: 9a35c70af8..659bbb26d9
for: 6.2.0-rc2

WT-10192 Fix bug in cursor_prev_skip statistics
2022-11-28 06:24:32 +00:00
Allison Easton
7cc81eb7c8 SERVER-71486 Fix config settings schema modification during fcv upgrade and downgrade
(cherry picked from commit e8d15ab156)
2022-11-24 14:50:18 +00:00
Alya Berciu
67ecf18ff9 SERVER-71445 Update cover_null_queries.js fcv 2022-11-24 12:35:55 +00:00
Pol Pinol Castuera
ad2b7e93f1 SERVER-71477 Check '_internalAllCollectionStatsSpec.getStats()' exists before calling 'makeStatsForNs' 2022-11-24 08:07:57 +00:00
Maddie Zechar
b75695e4e1 SERVER-71529 Add serverStatus metric for classic and SBE plan cache size 2022-11-24 00:10:34 +00:00
Pierlauro Sciarelli
71c42004e0 SERVER-71122 Get rid of the WaitForCleanCorrectEvenAfterClearFollowedBySetFilteringMetadata unit test 2022-11-23 22:26:10 +00:00
Maddie Zechar
141ff826fd SERVER-71386 Telemetry collection fails for queries with non-object fields 2022-11-23 21:36:18 +00:00
Ivan Fefer
bb0c1608a1 SERVER-71270 In timeseries collections prevent match pushdown before project that can affect it 2022-11-23 16:21:46 +00:00
Tommaso Tocci
fa551f7ae3 SERVER-71297 Coverity analysis defect 134120: Fix VersionType::currentVersion parsing
(cherry picked from commit 32bb6bed25)
2022-11-23 13:43:33 +00:00
Milena Ivanova
94323d60eb SERVER-71370 Disable test failing on MacOs
(cherry picked from commit 6e0c9c3b24)
2022-11-23 12:29:33 +00:00
Jeff Zambory
0743b9dbdb SERVER-71473: Begin using the new test stats location
(cherry picked from commit 81b9c1abbc)
2022-11-23 10:08:03 +00:00
Alexander Neben
b57d0f80d3 SERVER-71534 Fixed fuzzer linting scripts
(cherry picked from commit abb9e21146)
2022-11-23 00:21:15 +00:00
Benety Goh
8b1d7be7ab SERVER-71498 QueryStageBatchedDeleteTest initializes TickSourceMock once
(cherry picked from commit a5341aa27e)
2022-11-22 17:35:23 +00:00
Mikhail Shchatko
7726d54b47 SERVER-71518 Use S3 test stats in mongo-task-generator
(cherry picked from commit f590e94413)
2022-11-21 18:54:05 +00:00
Alexander Neben
61620c0d61 SERVER-71471 Fixed deployment process for jstestfuzz
(cherry picked from commit 45400e2540)
2022-11-21 16:44:22 +00:00
Alexander Neben
4f8c870d1e SERVER-71424 Excluded third_party js files from linting
(cherry picked from commit be0adb109b)
2022-11-21 16:44:22 +00:00
Pierlauro Sciarelli
abcdf5a80b SERVER-71435 Increse verbosity level for range-deleter in resmoke 2022-11-21 14:35:37 +00:00
Luke Chen
d21a749138 Import wiredtiger: 9a35c70af8a4e8c67b850d7982a77d5260fb5f08 from branch mongodb-6.2
ref: 2cb2316c04..9a35c70af8
for: 6.2.0-rc2

WT-9773 Fix mirrored table bulk load fail on cache pressure
2022-11-21 03:50:48 +00:00
Luke Chen
eff237c48a Import wiredtiger: 2cb2316c04ed3eb46a983338c3db2dc690e26f32 from branch mongodb-6.2
ref: 185cb65902..2cb2316c04
for: 6.2.0-rc2

WT-9102 Update macOS variant to version 11.00
2022-11-21 03:50:48 +00:00
Luke Chen
80003a2abe Import wiredtiger: 185cb659029fc4e5213783c5d290aa0fab5ab043 from branch mongodb-6.2
ref: 47951efac1..185cb65902
for: 6.2.0-rc2

WT-10164 Split apart the rollback to stable implementation into multiple files
2022-11-21 03:50:48 +00:00
Luke Chen
866c9351be Import wiredtiger: 47951efac16fbf8e5d44230ad18fce1b18858cda from branch mongodb-6.2
ref: 9a23ed36e1..47951efac1
for: 6.2.0-rc2

WT-7492 Ignore the evict drain wait msg in stdout.txt for test_cursor_random
2022-11-21 03:50:48 +00:00
Luke Chen
77dd7f8d28 Import wiredtiger: 9a23ed36e160f47df4068de05795d9c1f4f12e78 from branch mongodb-6.2
ref: de945280b9..9a23ed36e1
for: 6.2.0-rc2

WT-10139 Add record count field for table
2022-11-21 03:50:48 +00:00
Luke Chen
3c16cf3c39 Import wiredtiger: de945280b9fe413f00134ab1f1eeea9c15a05383 from branch mongodb-6.2
ref: b412563e92..de945280b9
for: 6.2.0-rc2

WT-10140 Add a new API to retrieve record count of a table
2022-11-21 03:50:48 +00:00
Luke Chen
5a1c2ba98e Import wiredtiger: b412563e92786caa4e9a36b7430468c2e8d3e649 from branch mongodb-6.2
ref: 147ed016d0..b412563e92
for: 6.2.0-rc2

WT-10159 Disable truncate operation when prepare is enabled in non-stanadlone build
2022-11-21 03:50:48 +00:00
Luke Chen
ac43d305a8 Import wiredtiger: 147ed016d0a3256903b9c9e62453e2bf8f5a3d7f from branch mongodb-6.2
ref: bcbfad0e77..147ed016d0
for: 6.2.0-rc2

WT-10165 Fix wording of 'all committed' in test_timestamp14
2022-11-21 03:50:48 +00:00
Luke Chen
901d618860 Import wiredtiger: bcbfad0e770ce83f9a571ce4115ae76fe0e0817f from branch mongodb-6.2
ref: 6e9fb75859..bcbfad0e77
for: 6.2.0-rc2

WT-10133 Make some non-transactional non-modifying cursor operation retryable.
2022-11-21 03:50:48 +00:00
Luke Chen
14c4127600 Import wiredtiger: 6e9fb75859897ebd99a5db9ce767f27ee5a134d8 from branch mongodb-6.2
ref: 3fdcbdde0e..6e9fb75859
for: 6.2.0-rc2

WT-10152 Add a home directory option to the cppsuite
2022-11-21 03:50:48 +00:00
Luke Chen
dc25f5f142 Import wiredtiger: 3fdcbdde0e500d84b0d4d49c6409274f0d78c74e from branch mongodb-6.2
ref: 35c033d896..3fdcbdde0e
for: 6.2.0-rc2

WT-10131 Upload stack traces to Evergreen for cpp suite tests and fix the executable path
2022-11-21 03:50:48 +00:00
Luke Chen
cc020142b7 Import wiredtiger: 35c033d8964524e2027f3b019ab9d0f657ce0edd from branch mongodb-6.2
ref: 5eee10d1ce..35c033d896
for: 6.2.0-rc2

WT-9834 Wait for a block to be unused before removing it
2022-11-21 03:50:48 +00:00
Luke Chen
1255f157c1 Import wiredtiger: 5eee10d1ceb365e632cdb355612b62eff1ab1b93 from branch mongodb-6.2
ref: 7559c709cc..5eee10d1ce
for: 6.2.0-rc2

WT-10137 Create a feature flag to enable/disable stats in page header
2022-11-21 03:50:47 +00:00
Luke Chen
ddbe563959 Import wiredtiger: 7559c709ccc03ce9c0e6538e421aadd61f650990 from branch mongodb-6.2
ref: 0efbb249a0..7559c709cc
for: 6.2.0-rc2

WT-10155 Move unit-test-long-bucket04 onto a larger Evergreen distro
2022-11-21 03:50:47 +00:00
Luke Chen
168b40f0ff Import wiredtiger: 0efbb249a0a79f504cf3be03129973e2fbb6f428 from branch mongodb-6.2
ref: 5ade1afb83..0efbb249a0
for: 6.2.0-rc2

WT-10062 Fix checkpoint cleanup not to skip internal pages
2022-11-21 03:50:47 +00:00
Steve Tarzia
39881664f2 SERVER-71452 hint _id index and lengthen timeout in allow_partial_results_with_maxTimeMS.js 2022-11-18 19:49:48 +00:00
Yuhong Zhang
fc05e34ea4 Revert "SERVER-65078 Report schema violations as errors when the validation level is 'error' in testing"
This reverts commit d63bf9dfa2.
2022-11-18 15:39:59 +00:00
Yuhong Zhang
efa7a19284 Revert "SERVER-71226 Skip collections with explicitly set conflicting validators in the background validation hook"
This reverts commit 2ef0ee3153.
2022-11-18 15:39:59 +00:00
Trevor Guidry
ee271f84ba SERVER-63104 add resmoke argument for generating all_feature_flags.txt locally
(cherry picked from commit 22f38cf147)
2022-11-16 23:41:36 +00:00
Abdul Qadeer
24ea1d6cd7 SERVER-71383 Add cleanup executor for scoped executor shutdown
(cherry picked from commit 92b2f2d4bf)
2022-11-16 22:35:52 +00:00
Steve Tarzia
29296c1ed9 SERVER-71372 fix getMore of partial results from find on sharded cluster 2022-11-16 17:28:42 +00:00
dylrich
931838789d SERVER-71404: remove .publish_crypt task distro overide for amazon 2022 2022-11-16 16:29:29 +00:00
Mikhail Shchatko
e0c820476e SERVER-70674 Add more required variants to etc/evergreen_nightly.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
ac930ff992 SERVER-70674 Change references to "v6.2" in etc/perf.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
f1c4d43ce0 SERVER-70674 Remove all feature flags variants from etc/system_perf.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
0df7825a8b SERVER-70674 Remove renew_ssl_cert from etc/system_perf.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
3e7effc73a SERVER-70674 Change references to "v6.2" in etc/system_perf.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
c3cec02457 SERVER-70674 Update suffixes in generate_version_expansions.py 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
dfa1355e07 SERVER-70674 Moved required variants to etc/evergreen_nightly.yml 2022-11-16 13:55:39 +00:00
Mikhail Shchatko
6507c32ebc SERVER-70674 Remove wtdevelop variants from etc/evergreen.yml 2022-11-16 13:55:38 +00:00
Mikhail Shchatko
1840ac24bb SERVER-70674 Change references to "v6.2" in etc/evergreen_yml_components/definitions.yml 2022-11-16 13:55:38 +00:00
Aaron Morand
28d3fe9a1a SERVER-71395 Initial commit into the 6.2 branch 2022-11-15 19:21:00 -05:00
298 changed files with 10753 additions and 7928 deletions

View File

@ -90,3 +90,4 @@ Welcome to MongoDB!
October 16, 2018, including patch fixes for prior versions, are published
under the [Server Side Public License (SSPL) v1](LICENSE-Community.txt).
See individual files for details.

View File

@ -22,6 +22,10 @@ from pkg_resources import parse_version
import SCons
import SCons.Script
from buildscripts.metrics.metrics_datatypes import SConsToolingMetrics
from buildscripts.metrics.tooling_exit_hook import initialize_exit_hook
from buildscripts.metrics.tooling_metrics_utils import register_metrics_collection_atexit
from site_scons.mongo import build_profiles
# This must be first, even before EnsureSConsVersion, if
# we are to avoid bulk loading all tools in the DefaultEnvironment.
@ -52,8 +56,6 @@ SCons.Node.FS.File.release_target_info = release_target_info_noop
from buildscripts import utils
from buildscripts import moduleconfig
from buildscripts.metrics.scons_tooling_metrics import setup_scons_metrics_collection_atexit
import psutil
scons_invocation = '{} {}'.format(sys.executable, ' '.join(sys.argv))
@ -1551,10 +1553,17 @@ env = Environment(variables=env_vars, **envDict)
del envDict
env.AddMethod(lambda env, name, **kwargs: add_option(name, **kwargs), 'AddOption')
# Setup atexit method to store tooling metrics
# The placement of this is intentional. We should only register this function atexit after
# env, env_vars and the parser have been properly initialized.
setup_scons_metrics_collection_atexit(utc_starttime, env_vars, env, _parser, sys.argv)
# The placement of this is intentional. Here we setup an atexit method to store tooling metrics.
# We should only register this function after env, env_vars and the parser have been properly initialized.
register_metrics_collection_atexit(
SConsToolingMetrics.generate_metrics, {
"utc_starttime": datetime.utcnow(),
"env_vars": env_vars,
"env": env,
"parser": _parser,
"args": sys.argv,
"exit_hook": initialize_exit_hook(),
})
if get_option('build-metrics'):
env['BUILD_METRICS_ARTIFACTS_DIR'] = '$BUILD_ROOT/$VARIANT_DIR'

View File

@ -7,7 +7,7 @@ import math
import os
import shlex
import sys
from datetime import datetime, timedelta
from datetime import timedelta
from pathlib import Path
from typing import Dict, List, Optional
@ -19,7 +19,7 @@ from evergreen import EvergreenApi, RetryingEvergreenApi
from buildscripts.ciconfig.evergreen import (EvergreenProjectConfig, parse_evergreen_file)
from buildscripts.resmoke_proxy.resmoke_proxy import ResmokeProxyService
from buildscripts.timeouts.timeout_service import (TimeoutParams, TimeoutService, TimeoutSettings)
from buildscripts.timeouts.timeout_service import (TimeoutParams, TimeoutService)
from buildscripts.util.cmdutils import enable_logging
from buildscripts.util.taskname import determine_task_base_name
@ -372,9 +372,6 @@ def main():
options = parser.parse_args()
end_date = datetime.now()
start_date = end_date - HISTORY_LOOKBACK
timeout_override = timedelta(seconds=options.timeout) if options.timeout else None
exec_timeout_override = timedelta(
seconds=options.exec_timeout) if options.exec_timeout else None
@ -389,7 +386,6 @@ def main():
binder.bind(
EvergreenApi,
RetryingEvergreenApi.get_api(config_file=os.path.expanduser(options.evg_api_config)))
binder.bind(TimeoutSettings, TimeoutSettings(start_date=start_date, end_date=end_date))
binder.bind(TimeoutOverrides, timeout_overrides)
binder.bind(EvergreenProjectConfig,
parse_evergreen_file(os.path.expanduser(options.evg_project_config)))

View File

@ -61,8 +61,8 @@ def generate_version_expansions():
raise ValueError("Unable to parse version from stdin and no version.json provided")
if version_parts[0]:
expansions["suffix"] = "latest"
expansions["src_suffix"] = "latest"
expansions["suffix"] = "v6.2-latest"
expansions["src_suffix"] = "v6.2-latest"
expansions["is_release"] = "false"
else:
expansions["suffix"] = version_line

View File

@ -30,7 +30,6 @@ Generate a file containing a list of disabled feature flags.
Used by resmoke.py to run only feature flag tests.
"""
import argparse
import os
import sys
@ -43,6 +42,7 @@ sys.path.append(os.path.normpath(os.path.join(os.path.abspath(__file__), '../../
# pylint: disable=wrong-import-position
import buildscripts.idl.lib as lib
from buildscripts.idl.idl import parser
def is_third_party_idl(idl_path: str) -> bool:
@ -56,13 +56,14 @@ def is_third_party_idl(idl_path: str) -> bool:
return False
def gen_all_feature_flags(idl_dir: str, import_dirs: List[str]):
def gen_all_feature_flags(idl_dir: str = os.getcwd()):
"""Generate a list of all feature flags."""
all_flags = []
for idl_path in sorted(lib.list_idls(idl_dir)):
if is_third_party_idl(idl_path):
continue
for feature_flag in lib.parse_idl(idl_path, import_dirs).spec.feature_flags:
doc = parser.parse_file(open(idl_path), idl_path)
for feature_flag in doc.spec.feature_flags:
if feature_flag.default.literal != "true":
all_flags.append(feature_flag.name)
@ -72,18 +73,16 @@ def gen_all_feature_flags(idl_dir: str, import_dirs: List[str]):
return list(set(all_flags) - set(force_disabled_flags))
def gen_all_feature_flags_file(filename: str = lib.ALL_FEATURE_FLAG_FILE):
flags = gen_all_feature_flags()
with open(filename, "w") as output_file:
output_file.write("\n".join(flags))
print("Generated: ", os.path.realpath(output_file.name))
def main():
"""Run the main function."""
arg_parser = argparse.ArgumentParser(description=__doc__)
arg_parser.add_argument("--import-dir", dest="import_dirs", type=str, action="append",
help="Directory to search for IDL import files")
args = arg_parser.parse_args()
flags = gen_all_feature_flags(os.getcwd(), args.import_dirs)
with open(lib.ALL_FEATURE_FLAG_FILE, "w") as output_file:
for flag in flags:
output_file.write("%s\n" % flag)
gen_all_feature_flags_file()
if __name__ == '__main__':

View File

@ -1023,7 +1023,7 @@ def _propagate_globals(spec):
idltype.cpp_type = _prefix_with_namespace(cpp_namespace, idltype.cpp_type)
def _parse(stream, error_file_name):
def parse_file(stream, error_file_name):
# type: (Any, str) -> syntax.IDLParsedSpec
"""
Parse a YAML document into an idl.syntax tree.
@ -1125,7 +1125,7 @@ def parse(stream, input_file_name, resolver):
input_file_name: a file name for error messages to use, and to help resolve imported files.
"""
root_doc = _parse(stream, input_file_name)
root_doc = parse_file(stream, input_file_name)
if root_doc.errors:
return root_doc
@ -1162,7 +1162,7 @@ def parse(stream, input_file_name, resolver):
# Parse imported file
with resolver.open(resolved_file_name) as file_stream:
parsed_doc = _parse(file_stream, resolved_file_name)
parsed_doc = parse_file(file_stream, resolved_file_name)
# Check for errors
if parsed_doc.errors:

View File

@ -5,12 +5,13 @@ import multiprocessing
import os
import socket
import sys
import traceback
from typing import Any, Dict, List, Optional
import distro
import git
from pydantic import BaseModel
from buildscripts.metrics.tooling_exit_hook import _ExitHook
# pylint: disable=bare-except
SCONS_ENV_FILE = "scons_env.env"
@ -20,6 +21,12 @@ SCONS_SECTION_HEADER = "SCONS_ENV"
class BaseMetrics(BaseModel):
"""Base class for an metrics object."""
@classmethod
@abstractmethod
def generate_metrics(cls, **kwargs):
"""Generate metrics."""
raise NotImplementedError
@abstractmethod
def is_malformed(self) -> bool:
"""Confirm whether this instance has all expected fields."""
@ -35,14 +42,14 @@ class BuildInfo(BaseMetrics):
artifact_dir: Optional[str]
@classmethod
def get_scons_build_info(
def generate_metrics(
cls,
utc_starttime: datetime,
env_vars: "SCons.Variables.Variables",
env: "SCons.Script.SConscript.SConsEnvironment",
parser: "SCons.Script.SConsOptions.SConsOptionParser",
args: List[str],
):
): # pylint: disable=arguments-differ
"""Get SCons build info to the best of our ability."""
artifact_dir = cls._get_scons_artifact_dir(env)
return cls(
@ -59,19 +66,22 @@ class BuildInfo(BaseMetrics):
) -> Optional[Dict[str, Any]]:
"""Get the environment variables options that can be set by users."""
artifact_dir = BuildInfo._get_scons_artifact_dir(env)
artifact_dir = artifact_dir if artifact_dir else '.'
scons_env_filepath = f'{artifact_dir}/{SCONS_ENV_FILE}'
try:
# Use SCons built-in method to save environment variables to a file
env_vars.Save(SCONS_ENV_FILE, env)
env_vars.Save(scons_env_filepath, env)
# Add a section header to the file so we can easily parse with ConfigParser
with open(SCONS_ENV_FILE, 'r') as original:
with open(scons_env_filepath, 'r') as original:
data = original.read()
with open(SCONS_ENV_FILE, 'w') as modified:
with open(scons_env_filepath, 'w') as modified:
modified.write(f"[{SCONS_SECTION_HEADER}]\n" + data)
# Parse file using config parser
config = configparser.ConfigParser()
config.read(SCONS_ENV_FILE)
config.read(scons_env_filepath)
str_dict = dict(config[SCONS_SECTION_HEADER])
return {key: eval(val) for key, val in str_dict.items()} # pylint: disable=eval-used
except:
@ -118,52 +128,27 @@ class BuildInfo(BaseMetrics):
return None in [self.artifact_dir, self.env, self.options, self.build_artifacts]
class ExitInfo(BaseMetrics):
"""Class to store tooling exit information."""
exit_code: Optional[int]
exception: Optional[str]
stacktrace: Optional[str]
@classmethod
def get_resmoke_exit_info(cls):
"""Get the current exit info."""
exc = sys.exc_info()[1]
return cls(
exit_code=0 if not exc else exc.code if exc.__class__ == SystemExit else 1,
exception=exc.__class__.__name__ if exc else None,
stacktrace=traceback.format_exc() if exc else None,
)
@classmethod
def get_scons_exit_info(cls, exit_code):
"""Get the current exit info using the given exit code."""
return cls(
exit_code=exit_code if isinstance(exit_code, int) else None,
exception=None,
stacktrace=None,
)
def is_malformed(self):
"""Return True if this object is missing an exit code."""
return self.exit_code is None
class HostInfo(BaseMetrics):
"""Class to store host information."""
ip_address: Optional[str]
host_os: str
num_cores: int
memory: Optional[float]
@classmethod
def get_host_info(cls):
def generate_metrics(cls): # pylint: disable=arguments-differ
"""Get the host info to the best of our ability."""
try:
ip_address = socket.gethostbyname(socket.gethostname())
except:
ip_address = None
try:
memory = cls._get_memory()
except:
memory = None
return cls(
ip_address=ip_address,
host_os=distro.name(pretty=True),
num_cores=multiprocessing.cpu_count(),
memory=memory,
@ -174,9 +159,9 @@ class HostInfo(BaseMetrics):
"""Get total memory of the host system."""
return os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') / (1024.**3)
def is_malformed(self):
def is_malformed(self) -> bool:
"""Confirm whether this instance has all expected fields."""
return self.memory is None
return None in [self.memory, self.ip_address]
class GitInfo(BaseMetrics):
@ -188,7 +173,7 @@ class GitInfo(BaseMetrics):
repo_name: Optional[str]
@classmethod
def get_git_info(cls, filepath: str):
def generate_metrics(cls, filepath: str): # pylint: disable=arguments-differ
"""Get the git info for a repo to the best of our ability."""
try:
commit_hash = git.Repo(filepath).head.commit.hexsha
@ -212,7 +197,7 @@ class GitInfo(BaseMetrics):
repo_name=repo_name,
)
def is_malformed(self):
def is_malformed(self) -> bool:
"""Confirm whether this instance has all expected fields."""
return None in [self.commit_hash, self.branch_name, self.repo_name]
@ -225,7 +210,7 @@ def _get_modules_git_info():
module_git_info = []
try:
module_git_info = [
GitInfo.get_git_info(os.path.join(MODULES_FILEPATH, module))
GitInfo.generate_metrics(os.path.join(MODULES_FILEPATH, module))
for module in os.listdir(MODULES_FILEPATH)
if os.path.isdir(os.path.join(MODULES_FILEPATH, module))
]
@ -234,73 +219,79 @@ def _get_modules_git_info():
return module_git_info
class ToolingMetrics(BaseMetrics):
"""Class to store tooling metrics."""
class ResmokeToolingMetrics(BaseMetrics):
"""Class to store resmoke tooling metrics."""
source: str
utc_starttime: datetime
utc_endtime: datetime
host_info: HostInfo
git_info: GitInfo
exit_info: ExitInfo
build_info: Optional[BuildInfo]
exit_code: Optional[int]
command: List[str]
module_info: List[GitInfo]
ip_address: Optional[str]
@classmethod
def get_resmoke_metrics(
def generate_metrics(
cls,
utc_starttime: datetime,
):
exit_hook: _ExitHook,
): # pylint: disable=arguments-differ
"""Get resmoke metrics to the best of our ability."""
try:
ip_address = socket.gethostbyname(socket.gethostname())
except:
ip_address = None
return cls(
source='resmoke',
utc_starttime=utc_starttime,
utc_endtime=datetime.utcnow(),
host_info=HostInfo.get_host_info(),
git_info=GitInfo.get_git_info('.'),
exit_info=ExitInfo.get_resmoke_exit_info(),
build_info=None,
module_info=_get_modules_git_info(),
host_info=HostInfo.generate_metrics(),
git_info=GitInfo.generate_metrics('.'),
exit_code=exit_hook.exit_code if isinstance(exit_hook.exit_code, int) else None,
command=sys.argv,
ip_address=ip_address,
module_info=_get_modules_git_info(),
)
def is_malformed(self) -> bool:
"""Confirm whether this instance has all expected fields."""
sub_metrics = self.module_info + [self.git_info] + [self.host_info]
return self.exit_code is None or any(metrics.is_malformed() for metrics in sub_metrics)
class SConsToolingMetrics(BaseMetrics):
"""Class to store scons tooling metrics."""
source: str
utc_starttime: datetime
utc_endtime: datetime
host_info: HostInfo
git_info: GitInfo
exit_code: Optional[int]
build_info: BuildInfo
command: List[str]
module_info: List[GitInfo]
@classmethod
def get_scons_metrics(
def generate_metrics(
cls,
utc_starttime: datetime,
env_vars: "SCons.Variables.Variables",
env: "SCons.Script.SConscript.SConsEnvironment",
parser: "SCons.Script.SConsOptions.SConsOptionParser",
args: List[str],
exit_code: int,
):
exit_hook: _ExitHook,
): # pylint: disable=arguments-differ
"""Get scons metrics to the best of our ability."""
try:
ip_address = socket.gethostbyname(socket.gethostname())
except:
ip_address = None
return cls(
source='scons',
utc_starttime=utc_starttime,
utc_endtime=datetime.utcnow(),
host_info=HostInfo.get_host_info(),
git_info=GitInfo.get_git_info('.'),
exit_info=ExitInfo.get_scons_exit_info(exit_code),
build_info=BuildInfo.get_scons_build_info(utc_starttime, env_vars, env, parser, args),
module_info=_get_modules_git_info(),
host_info=HostInfo.generate_metrics(),
git_info=GitInfo.generate_metrics('.'),
build_info=BuildInfo.generate_metrics(utc_starttime, env_vars, env, parser, args),
exit_code=exit_hook.exit_code if isinstance(exit_hook.exit_code, int) else None,
command=sys.argv,
ip_address=ip_address,
module_info=_get_modules_git_info(),
)
def is_malformed(self):
def is_malformed(self) -> bool:
"""Confirm whether this instance has all expected fields."""
sub_metrics = [self.build_info] if self.source == 'scons' else []
sub_metrics += self.module_info + [self.git_info] + [self.host_info] + [self.exit_info]
return self.ip_address is None or any(metrics.is_malformed() for metrics in sub_metrics)
sub_metrics = self.module_info + [self.git_info] + [self.host_info] + [self.build_info]
return self.exit_code is None or any(metrics.is_malformed() for metrics in sub_metrics)

View File

@ -1,19 +0,0 @@
from datetime import datetime
import logging
from buildscripts.metrics.metrics_datatypes import ToolingMetrics
from buildscripts.metrics.tooling_metrics_utils import save_tooling_metrics, should_collect_metrics
logger = logging.getLogger('resmoke_tooling_metrics')
def save_resmoke_tooling_metrics(utc_starttime: datetime):
try:
if not should_collect_metrics():
return
tooling_metrics = ToolingMetrics.get_resmoke_metrics(utc_starttime)
save_tooling_metrics(tooling_metrics)
except Exception as exc: # pylint: disable=broad-except
logger.warning(
"%s\nResmoke Metrics Collection Failed -- this is a non-issue.\nIf this message persists, feel free to reach out to #server-development-platform",
exc)

View File

@ -1,71 +0,0 @@
import atexit
import datetime
import logging
import sys
from typing import List
from buildscripts.metrics.metrics_datatypes import ToolingMetrics
from buildscripts.metrics.tooling_metrics_utils import save_tooling_metrics, should_collect_metrics
logger = logging.getLogger('scons_tooling_metrics')
class SConsExitHook(object):
"""Plumb all sys.exit through this object so that we can access the exit code in atexit."""
def __init__(self):
self.exit_code = None
self._orig_exit = sys.exit
def __del__(self):
sys.exit = self._orig_exit
def initialize(self):
sys.exit = self.exit
def exit(self, code=0):
self.exit_code = code
self._orig_exit(code)
# This method should only be used when registered on atexit
def _save_scons_tooling_metrics(
utc_starttime: datetime,
env_vars: "SCons.Variables.Variables",
env: "SCons.Script.SConscript.SConsEnvironment",
parser: "SCons.Script.SConsOptions.SConsOptionParser",
args: List[str],
exit_hook: SConsExitHook,
):
"""Save SCons tooling metrics to atlas cluster."""
try:
if not should_collect_metrics():
return
tooling_metrics = ToolingMetrics.get_scons_metrics(utc_starttime, env_vars, env, parser,
args, exit_hook.exit_code)
save_tooling_metrics(tooling_metrics)
except Exception as exc: # pylint: disable=broad-except
logger.warning(
"%sSCons Metrics Collection Failed -- this is a non-issue.\nIf this message persists, feel free to reach out to #server-development-platform",
exc)
def setup_scons_metrics_collection_atexit(
utc_starttime: datetime,
env_vars: "SCons.Variables.Variables",
env: "SCons.Script.SConscript.SConsEnvironment",
parser: "SCons.Script.SConsOptions.SConsOptionParser",
args: List[str],
) -> None:
"""Register an atexit method for scons metrics collection."""
scons_exit_hook = SConsExitHook()
scons_exit_hook.initialize()
atexit.register(
_save_scons_tooling_metrics,
utc_starttime,
env_vars,
env,
parser,
args,
scons_exit_hook,
)

View File

@ -0,0 +1,36 @@
import sys
# pylint: disable=invalid-name
# pylint: disable=redefined-outer-name
# DO NOT INITIALIZE DIRECTLY -- This is intended to be a singleton.
class _ExitHook(object):
"""Plumb all sys.exit through this object so that we can access the exit code in atexit."""
def __init__(self):
self.exit_code = 0
self._orig_exit = sys.exit
sys.exit = self.exit
def __del__(self):
sys.exit = self._orig_exit
def exit(self, code=0):
self.exit_code = code
self._orig_exit(code)
SINGLETON_TOOLING_METRICS_EXIT_HOOK = None
# Always use this method when initializing _ExitHook -- This guarantees you are using the singleton
# initialize the exit hook as early as possible to ensure we capture the error.
def initialize_exit_hook() -> None:
"""Initialize the exit hook."""
try:
if not SINGLETON_TOOLING_METRICS_EXIT_HOOK:
SINGLETON_TOOLING_METRICS_EXIT_HOOK = _ExitHook()
except UnboundLocalError as _:
SINGLETON_TOOLING_METRICS_EXIT_HOOK = _ExitHook()
return SINGLETON_TOOLING_METRICS_EXIT_HOOK

View File

@ -1,20 +1,17 @@
import atexit
import logging
import os
import asyncio
from typing import Optional
from git import Repo
from typing import Any, Callable, Dict
import pymongo
from buildscripts.metrics.metrics_datatypes import ToolingMetrics
logger = logging.getLogger('tooling_metrics_utils')
logger = logging.getLogger('tooling_metrics')
INTERNAL_TOOLING_METRICS_HOSTNAME = "mongodb+srv://dev-metrics-pl-0.kewhj.mongodb.net"
INTERNAL_TOOLING_METRICS_USERNAME = "internal_tooling_user"
INTERNAL_TOOLING_METRICS_PASSWORD = "internal_tooling_user"
def _get_internal_tooling_metrics_client():
def _get_internal_tooling_metrics_client() -> pymongo.MongoClient:
"""Retrieve client for internal MongoDB tooling metrics cluster."""
return pymongo.MongoClient(
host=INTERNAL_TOOLING_METRICS_HOSTNAME,
@ -24,28 +21,20 @@ def _get_internal_tooling_metrics_client():
serverSelectionTimeoutMS=1000,
connectTimeoutMS=1000,
waitQueueTimeoutMS=1000,
retryWrites=False,
)
EXPECTED_TOOLCHAIN_LOCATION = "/opt/mongodbtoolchain"
def _toolchain_exists() -> bool:
"""Check if the internal MongoDB toolchain exists."""
return os.path.exists(EXPECTED_TOOLCHAIN_LOCATION)
def _git_user_exists() -> Optional[str]:
"""Check if a git user email exists."""
try:
return Repo('.').config_reader().get_value("user", "email", None)
except Exception: # pylint: disable=broad-except
return None
MONGOD_INTENRAL_DISTRO_FILEPATH = '/etc/mongodb-distro-name'
def _is_virtual_workstation() -> bool:
"""Detect whether this is a MongoDB internal virtual workstation."""
return _toolchain_exists() and _git_user_exists()
try:
with open(MONGOD_INTENRAL_DISTRO_FILEPATH, 'r') as file:
return file.read().strip() == 'ubuntu1804-workstation'
except Exception as _: # pylint: disable=broad-except
return False
TOOLING_METRICS_OPT_OUT = "TOOLING_METRICS_OPT_OUT"
@ -56,26 +45,32 @@ def _has_metrics_opt_out() -> bool:
return os.environ.get(TOOLING_METRICS_OPT_OUT, None) == '1'
def should_collect_metrics() -> bool:
def _should_collect_metrics() -> bool:
"""Determine whether to collect tooling metrics."""
return _is_virtual_workstation() and not _has_metrics_opt_out()
async def _save_metrics(metrics: ToolingMetrics) -> None:
"""Save tooling metrics data."""
client = _get_internal_tooling_metrics_client()
client.metrics.tooling_metrics.insert_one(metrics.dict())
def save_tooling_metrics(tooling_metrics: ToolingMetrics) -> None:
"""Persist tooling metrics data to MongoDB Internal Atlas Cluster."""
# DO NOT USE DIRECTLY -- This is only to be used when metrics collection is registered atexit
def _save_metrics(
generate_metrics_function: Callable,
generate_metrics_args: Dict[str, Any],
) -> None:
"""Save metrics to the atlas cluster."""
try:
asyncio.run(asyncio.wait_for(_save_metrics(tooling_metrics), timeout=1.0))
except asyncio.TimeoutError as exc:
logger.warning(
"%s\nTimeout: Tooling metrics collection is not available -- this is a non-issue.\nIf this message persists, feel free to reach out to #server-development-platform",
exc)
client = _get_internal_tooling_metrics_client()
metrics = generate_metrics_function(**generate_metrics_args)
client.metrics.tooling_metrics.insert_one(metrics.dict())
except Exception as exc: # pylint: disable=broad-except
logger.warning(
"%s\nUnexpected: Tooling metrics collection is not available -- this is a non-issue.\nIf this message persists, feel free to reach out to #server-development-platform",
"%s\n\nInternal Metrics Collection Failed -- this is a non-issue.\nIf this message persists, feel free to reach out to #server-dev-platform",
exc)
# This is the only util that should be used externally
def register_metrics_collection_atexit(
generate_metrics_function: Callable,
generate_metrics_args: Dict[str, Any],
) -> None:
"""Register metrics collection on atexit."""
if _should_collect_metrics():
atexit.register(_save_metrics, generate_metrics_function, generate_metrics_args)

View File

@ -3,7 +3,6 @@
import json
import sys
from collections import namedtuple
from datetime import datetime, timedelta
from statistics import mean
from typing import Dict, List
@ -13,7 +12,8 @@ import structlog
from buildscripts.resmokelib.testing.report import TestInfo, TestReport
from buildscripts.resmokelib.utils import get_task_name_without_suffix
from buildscripts.util.cmdutils import enable_logging
from evergreen import RetryingEvergreenApi, TestStats
from buildscripts.util.teststats import HistoricTaskData, HistoricalTestInformation
LOGGER = structlog.get_logger("buildscripts.resmoke_tests_runtime_validate")
@ -34,17 +34,12 @@ def parse_resmoke_report(report_file: str) -> List[TestInfo]:
return [test_info for test_info in test_report.test_infos if "jstests" in test_info.test_file]
def get_historic_stats(evg_api_config: str, project_id: str, test_files: List[str], task_name: str,
build_variant: str) -> List[TestStats]:
def get_historic_stats(project_id: str, task_name: str,
build_variant: str) -> List[HistoricalTestInformation]:
"""Get historic test stats."""
evg_api = RetryingEvergreenApi.get_api(config_file=evg_api_config)
before_date = datetime.today()
after_date = before_date - timedelta(days=LOOK_BACK_NUM_DAYS)
base_task_name = get_task_name_without_suffix(task_name, build_variant).replace(
BURN_IN_PREFIX, "")
return evg_api.test_stats_by_project(project_id=project_id, after_date=after_date,
before_date=before_date, tests=test_files,
tasks=[base_task_name], variants=[build_variant])
return HistoricTaskData.get_stats_from_s3(project_id, base_task_name, build_variant)
def make_stats_map(stats: List[_TestData]) -> Dict[str, List[float]]:
@ -63,13 +58,10 @@ def make_stats_map(stats: List[_TestData]) -> Dict[str, List[float]]:
@click.command()
@click.option("--resmoke-report-file", type=str, required=True,
help="Location of resmoke's report JSON file.")
@click.option("--evg-api-config", type=str, required=True,
help="Location of evergreen api configuration.")
@click.option("--project-id", type=str, required=True, help="Evergreen project id.")
@click.option("--build-variant", type=str, required=True, help="Evergreen build variant name.")
@click.option("--task-name", type=str, required=True, help="Evergreen task name.")
def main(resmoke_report_file: str, evg_api_config: str, project_id: str, build_variant: str,
task_name: str) -> None:
def main(resmoke_report_file: str, project_id: str, build_variant: str, task_name: str) -> None:
"""Compare resmoke tests runtime with historic stats."""
enable_logging(verbose=False)
@ -79,10 +71,9 @@ def main(resmoke_report_file: str, evg_api_config: str, project_id: str, build_v
for test_info in current_test_infos
])
historic_stats = get_historic_stats(evg_api_config, project_id, list(current_stats_map.keys()),
task_name, build_variant)
historic_stats = get_historic_stats(project_id, task_name, build_variant)
historic_stats_map = make_stats_map([
_TestData(test_stats.test_file, test_stats.avg_duration_pass)
_TestData(test_stats.test_name, test_stats.avg_duration_pass)
for test_stats in historic_stats
])

View File

@ -21,6 +21,7 @@
- jstests/core/find_and_modify.js
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/project_with_collation.js
# Stepdown commands during fsync lock will fail.
- jstests/core/currentop.js
@ -82,6 +83,7 @@
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_pipeline_update.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/project_with_collation.js
# These test run commands using legacy queries, which are not supported on sessions.
- jstests/core/comment_field.js

View File

@ -222,6 +222,7 @@ selector:
- jstests/core/find_and_modify.js
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/project_with_collation.js
# Does not support tojson of command objects.
- jstests/core/SERVER-23626.js

View File

@ -30,6 +30,7 @@ selector:
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_pipeline_update.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/project_with_collation.js
# These test run commands using legacy queries, which are not supported on sessions.
- jstests/core/comment_field.js

View File

@ -23,6 +23,7 @@ selector:
- jstests/core/find_and_modify.js
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/project_with_collation.js
# Stepdown commands during fsync lock will fail.
- jstests/core/currentop.js

View File

@ -29,6 +29,7 @@ selector:
- jstests/core/find_and_modify_pipeline_update.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/fts_find_and_modify.js
- jstests/core/project_with_collation.js
# These tests rely on the assumption that an update command is run only once.
- jstests/core/find_and_modify_metrics.js

View File

@ -22,6 +22,7 @@ selector:
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/fts_find_and_modify.js
- jstests/core/project_with_collation.js
# Stepdown commands during fsync lock will fail.
- jstests/core/currentop.js

View File

@ -43,6 +43,7 @@ selector:
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/fts_find_and_modify.js
- jstests/core/project_with_collation.js
# Stepdown commands during fsync lock will fail.
- jstests/core/currentop.js

View File

@ -43,6 +43,7 @@ selector:
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/fts_find_and_modify.js
- jstests/core/project_with_collation.js
# Stepdown commands during fsync lock will fail.
- jstests/core/currentop.js

View File

@ -43,6 +43,7 @@ selector:
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/fts_find_and_modify.js
- jstests/core/project_with_collation.js
# Stepdown commands during fsync lock will fail.
- jstests/core/currentop.js

View File

@ -23,6 +23,7 @@ selector:
- jstests/core/find_and_modify.js
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/project_with_collation.js
# Stepdown commands during fsync lock will fail.
- jstests/core/currentop.js

View File

@ -42,6 +42,7 @@ selector:
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/fts_find_and_modify.js
- jstests/core/project_with_collation.js
# Stepdown commands during fsync lock will fail.
- jstests/core/currentop.js

View File

@ -41,6 +41,7 @@ selector:
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/fts_find_and_modify.js
- jstests/core/project_with_collation.js
# Stepdown commands during fsync lock will fail.
- jstests/core/currentop.js

View File

@ -41,6 +41,7 @@ selector:
- jstests/core/find_and_modify2.js
- jstests/core/find_and_modify_server6865.js
- jstests/core/fts_find_and_modify.js
- jstests/core/project_with_collation.js
# Stepdown commands during fsync lock will fail.
- jstests/core/currentop.js

View File

@ -4,7 +4,9 @@ from datetime import datetime
import time
import os
import psutil
from buildscripts.metrics.resmoke_tooling_metrics import save_resmoke_tooling_metrics
from buildscripts.metrics.metrics_datatypes import ResmokeToolingMetrics
from buildscripts.metrics.tooling_exit_hook import initialize_exit_hook
from buildscripts.metrics.tooling_metrics_utils import register_metrics_collection_atexit
from buildscripts.resmokelib import parser
@ -25,7 +27,8 @@ def main(argv):
"For example: resmoke.py run -h\n"
"Note: bisect and setup-multiversion subcommands have been moved to db-contrib-tool (https://github.com/10gen/db-contrib-tool#readme).\n"
)
try:
subcommand.execute()
finally:
save_resmoke_tooling_metrics(datetime.utcfromtimestamp(__start_time))
register_metrics_collection_atexit(ResmokeToolingMetrics.generate_metrics, {
"utc_starttime": datetime.utcfromtimestamp(__start_time),
"exit_hook": initialize_exit_hook()
})
subcommand.execute()

View File

@ -92,8 +92,9 @@ DEFAULTS = {
"report_failure_status": "fail",
"report_file": None,
"run_all_feature_flag_tests": False,
"run_all_feature_flags_no_tests": False,
"run_no_feature_flag_tests": False,
"additional_feature_flags": None,
"additional_feature_flags_file": None,
"seed": int(time.time() * 256), # Taken from random.py code in Python 2.7.
"service_executor": None,
"shell_conn_string": None,
@ -379,8 +380,11 @@ INSTALL_DIR = None
# Whether to run tests for feature flags.
RUN_ALL_FEATURE_FLAG_TESTS = None
# Whether to run the server with feature flags. Defaults to true if `RUN_ALL_FEATURE_FLAG_TESTS` is true.
RUN_ALL_FEATURE_FLAGS = None
# Whether to run the tests with enabled feature flags
RUN_NO_FEATURE_FLAG_TESTS = None
# the path to a file containing feature flags
ADDITIONAL_FEATURE_FLAGS_FILE = None
# List of enabled feature flags.
ENABLED_FEATURE_FLAGS = []

View File

@ -15,6 +15,7 @@ import shlex
import pymongo.uri_parser
from buildscripts.idl import gen_all_feature_flag_list
from buildscripts.idl.lib import ALL_FEATURE_FLAG_FILE
from buildscripts.resmokelib import config as _config
@ -52,14 +53,9 @@ def _validate_options(parser, args):
"Cannot use --replayFile with additional test files listed on the command line invocation."
)
if args.run_all_feature_flag_tests or args.run_all_feature_flags_no_tests:
if not os.path.isfile(ALL_FEATURE_FLAG_FILE):
parser.error(
"To run tests with all feature flags, the %s file must exist and be placed in"
" your working directory. The file can be downloaded from the artifacts tarball"
" in Evergreen. Alternatively, if you know which feature flags you want to enable,"
" you can use the --additionalFeatureFlags command line argument" %
ALL_FEATURE_FLAG_FILE)
if args.additional_feature_flags_file and not os.path.isfile(
args.additional_feature_flags_file):
parser.error("The specified additional feature flags file does not exist.")
def get_set_param_errors(process_params):
agg_set_params = collections.defaultdict(list)
@ -185,28 +181,36 @@ be invoked as either:
- buildscripts/resmoke.py --installDir {shlex.quote(user_config['install_dir'])}""")
raise RuntimeError(err)
def process_feature_flag_file(path):
with open(path) as fd:
return fd.read().split()
def setup_feature_flags():
_config.RUN_ALL_FEATURE_FLAG_TESTS = config.pop("run_all_feature_flag_tests")
_config.RUN_ALL_FEATURE_FLAGS = config.pop("run_all_feature_flags_no_tests")
_config.RUN_NO_FEATURE_FLAG_TESTS = config.pop("run_no_feature_flag_tests")
_config.ADDITIONAL_FEATURE_FLAGS_FILE = config.pop("additional_feature_flags_file")
# Running all feature flag tests implies running the fixtures with feature flags.
if _config.RUN_ALL_FEATURE_FLAG_TESTS:
_config.RUN_ALL_FEATURE_FLAGS = True
print("Generating: ", ALL_FEATURE_FLAG_FILE)
gen_all_feature_flag_list.gen_all_feature_flags_file()
all_ff = []
enabled_feature_flags = []
try:
with open(ALL_FEATURE_FLAG_FILE) as fd:
all_ff = fd.read().split()
all_ff = process_feature_flag_file(ALL_FEATURE_FLAG_FILE)
except FileNotFoundError:
# If we ask resmoke to run with all feature flags, the feature flags file
# needs to exist.
if _config.RUN_ALL_FEATURE_FLAGS:
if _config.RUN_ALL_FEATURE_FLAG_TESTS or _config.RUN_NO_FEATURE_FLAG_TESTS:
raise
if _config.RUN_ALL_FEATURE_FLAGS:
if _config.RUN_ALL_FEATURE_FLAG_TESTS:
enabled_feature_flags = all_ff[:]
if _config.ADDITIONAL_FEATURE_FLAGS_FILE:
enabled_feature_flags.extend(
process_feature_flag_file(_config.ADDITIONAL_FEATURE_FLAGS_FILE))
# Specify additional feature flags from the command line.
# Set running all feature flag tests to True if this options is specified.
additional_feature_flags = _tags_from_list(config.pop("additional_feature_flags"))
@ -231,7 +235,7 @@ be invoked as either:
_config.EXCLUDE_WITH_ANY_TAGS.extend(
utils.default_if_none(_tags_from_list(config.pop("exclude_with_any_tags")), []))
if _config.RUN_ALL_FEATURE_FLAGS and not _config.RUN_ALL_FEATURE_FLAG_TESTS:
if _config.RUN_NO_FEATURE_FLAG_TESTS:
# Don't run any feature flag tests.
_config.EXCLUDE_WITH_ANY_TAGS.extend(all_feature_flags)
else:

View File

@ -832,15 +832,19 @@ class RunPlugin(PluginInterface):
)
parser.add_argument(
"--runAllFeatureFlagsNoTests", dest="run_all_feature_flags_no_tests",
action="store_true", help=
"Run MongoDB servers with all feature flags enabled but don't run any tests tagged with these feature flags; used for multiversion suites"
)
"--runNoFeatureFlagTests", dest="run_no_feature_flag_tests", action="store_true",
help=("Do not run any tests tagged with enabled feature flags."
" This argument has precedence over --runAllFeatureFlagTests"
"; used for multiversion suites"))
parser.add_argument("--additionalFeatureFlags", dest="additional_feature_flags",
action="append", metavar="featureFlag1, featureFlag2, ...",
help="Additional feature flags")
parser.add_argument("--additionalFeatureFlagsFile", dest="additional_feature_flags_file",
action="store", metavar="FILE",
help="The path to a file with feature flags, delimited by newlines.")
parser.add_argument("--maxTestQueueSize", type=int, dest="max_test_queue_size",
help=argparse.SUPPRESS)
@ -1188,15 +1192,6 @@ def to_local_args(input_args=None):
if origin_suite is not None:
setattr(parsed_args, "suite_files", origin_suite)
# Replace --runAllFeatureFlagTests with an explicit list of feature flags. The former relies on
# all_feature_flags.txt which may not exist in the local dev environment.
run_all_feature_flag_tests = getattr(parsed_args, "run_all_feature_flag_tests", None)
if run_all_feature_flag_tests is not None:
setattr(parsed_args, "additional_feature_flags", config.ENABLED_FEATURE_FLAGS)
del parsed_args.run_all_feature_flag_tests
del parsed_args.run_all_feature_flags_no_tests
# The top-level parser has one subparser that contains all subcommand parsers.
command_subparser = [
action for action in parser._actions # pylint: disable=protected-access

View File

@ -181,7 +181,7 @@ class MongoDFixture(interface.Fixture):
def get_driver_connection_url(self):
"""Return the driver connection URL."""
return "mongodb://" + self.get_internal_connection_string()
return "mongodb://" + self.get_internal_connection_string() + "/?directConnection=true"
# The below parameters define the default 'logComponentVerbosity' object passed to mongod processes
@ -193,15 +193,16 @@ class MongoDFixture(interface.Fixture):
# The default verbosity setting for any tests that are not started with an Evergreen task id. This
# will apply to any tests run locally.
DEFAULT_MONGOD_LOG_COMPONENT_VERBOSITY = {
"replication": {"rollback": 2}, "sharding": {"migration": 2}, "transaction": 4,
"tenantMigration": 4
"replication": {"rollback": 2}, "sharding": {"migration": 2, "rangeDeleter": 2},
"transaction": 4, "tenantMigration": 4
}
# The default verbosity setting for any mongod processes running in Evergreen i.e. started with an
# Evergreen task id.
DEFAULT_EVERGREEN_MONGOD_LOG_COMPONENT_VERBOSITY = {
"replication": {"election": 4, "heartbeats": 2, "initialSync": 2, "rollback": 2},
"sharding": {"migration": 2}, "storage": {"recovery": 2}, "transaction": 4, "tenantMigration": 4
"replication": {"election": 4, "heartbeats": 2, "initialSync": 2,
"rollback": 2}, "sharding": {"migration": 2, "rangeDeleter": 2},
"storage": {"recovery": 2}, "transaction": 4, "tenantMigration": 4
}

View File

@ -1,41 +1,42 @@
"""Unit tests for timeout_service.py."""
import random
import unittest
from datetime import datetime, timedelta
from unittest.mock import MagicMock
from unittest.mock import MagicMock, patch
from requests.exceptions import HTTPError
from evergreen import EvergreenApi
import buildscripts.timeouts.timeout_service as under_test
from buildscripts.resmoke_proxy.resmoke_proxy import ResmokeProxyService
from buildscripts.util.teststats import HistoricTaskData
from buildscripts.util.teststats import HistoricTaskData, HistoricTestInfo
# pylint: disable=invalid-name,protected-access
NS = "buildscripts.timeouts.timeout_service"
def build_mock_service(evg_api=None, resmoke_proxy=None):
end_date = datetime.now()
start_date = end_date - timedelta(weeks=2)
timeout_settings = under_test.TimeoutSettings(
end_date=end_date,
start_date=start_date,
)
def ns(relative_name): # pylint: disable=invalid-name
"""Return a full name from a name relative to the test module"s name space."""
return NS + "." + relative_name
def build_mock_service(resmoke_proxy=None):
return under_test.TimeoutService(
evg_api=evg_api if evg_api else MagicMock(spec_set=EvergreenApi),
resmoke_proxy=resmoke_proxy if resmoke_proxy else MagicMock(spec_set=ResmokeProxyService),
timeout_settings=timeout_settings)
resmoke_proxy=resmoke_proxy if resmoke_proxy else MagicMock(spec_set=ResmokeProxyService))
def tst_stat_mock(file, duration, pass_count):
return MagicMock(test_file=file, avg_duration_pass=duration, num_pass=pass_count)
return MagicMock(test_name=file, avg_duration_pass=duration, num_pass=pass_count, hooks=[])
def tst_runtime_mock(file, duration, pass_count):
return MagicMock(test_name=file, avg_duration_pass=duration, num_pass=pass_count)
class TestGetTimeoutEstimate(unittest.TestCase):
def test_no_stats_should_return_default_timeout(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
mock_evg_api.test_stats_by_project.return_value = []
timeout_service = build_mock_service(evg_api=mock_evg_api)
@patch(ns("HistoricTaskData.from_s3"))
def test_no_stats_should_return_default_timeout(self, from_s3_mock: MagicMock):
timeout_service = build_mock_service()
from_s3_mock.return_value = []
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -48,13 +49,17 @@ class TestGetTimeoutEstimate(unittest.TestCase):
self.assertFalse(timeout.is_specified())
def test_a_test_with_missing_history_should_cause_a_default_timeout(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
test_stats = [tst_stat_mock(f"test_{i}.js", 60, 1) for i in range(30)]
mock_evg_api.test_stats_by_project.return_value = test_stats
@patch(ns("HistoricTaskData.from_s3"))
def test_a_test_with_missing_history_should_cause_a_default_timeout(
self, from_s3_mock: MagicMock):
test_stats = [
HistoricTestInfo(test_name=f"test_{i}.js", avg_duration=60, num_pass=1, hooks=[])
for i in range(30)
]
from_s3_mock.return_value = HistoricTaskData(test_stats)
mock_resmoke_proxy = MagicMock(spec_set=ResmokeProxyService)
mock_resmoke_proxy.list_tests.return_value = ["test_with_no_stats.js"]
timeout_service = build_mock_service(evg_api=mock_evg_api, resmoke_proxy=mock_resmoke_proxy)
timeout_service = build_mock_service(resmoke_proxy=mock_resmoke_proxy)
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -67,14 +72,19 @@ class TestGetTimeoutEstimate(unittest.TestCase):
self.assertFalse(timeout.is_specified())
def test_a_test_with_zero_runtime_history_should_cause_a_default_timeout(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
test_stats = [tst_stat_mock(f"test_{i}.js", 60, 1) for i in range(30)]
test_stats.append(tst_stat_mock("zero.js", 0.0, 1))
mock_evg_api.test_stats_by_project.return_value = test_stats
@patch(ns("HistoricTaskData.from_s3"))
def test_a_test_with_zero_runtime_history_should_cause_a_default_timeout(
self, from_s3_mock: MagicMock):
test_stats = [
HistoricTestInfo(test_name=f"test_{i}.js", avg_duration=60, num_pass=1, hooks=[])
for i in range(30)
]
test_stats.append(
HistoricTestInfo(test_name="zero.js", avg_duration=0.0, num_pass=1, hooks=[]))
from_s3_mock.return_value = HistoricTaskData(test_stats)
mock_resmoke_proxy = MagicMock(spec_set=ResmokeProxyService)
mock_resmoke_proxy.list_tests.return_value = [ts.test_file for ts in test_stats]
timeout_service = build_mock_service(evg_api=mock_evg_api, resmoke_proxy=mock_resmoke_proxy)
mock_resmoke_proxy.list_tests.return_value = [ts.test_name for ts in test_stats]
timeout_service = build_mock_service(resmoke_proxy=mock_resmoke_proxy)
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -87,15 +97,19 @@ class TestGetTimeoutEstimate(unittest.TestCase):
self.assertFalse(timeout.is_specified())
def test_all_tests_with_runtime_history_should_use_custom_timeout(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
@patch(ns("HistoricTaskData.from_s3"))
def test_all_tests_with_runtime_history_should_use_custom_timeout(self,
from_s3_mock: MagicMock):
n_tests = 30
test_runtime = 600
test_stats = [tst_stat_mock(f"test_{i}.js", test_runtime, 1) for i in range(n_tests)]
mock_evg_api.test_stats_by_project.return_value = test_stats
test_stats = [
HistoricTestInfo(test_name=f"test_{i}.js", avg_duration=test_runtime, num_pass=1,
hooks=[]) for i in range(n_tests)
]
from_s3_mock.return_value = HistoricTaskData(test_stats)
mock_resmoke_proxy = MagicMock(spec_set=ResmokeProxyService)
mock_resmoke_proxy.list_tests.return_value = [ts.test_file for ts in test_stats]
timeout_service = build_mock_service(evg_api=mock_evg_api, resmoke_proxy=mock_resmoke_proxy)
mock_resmoke_proxy.list_tests.return_value = [ts.test_name for ts in test_stats]
timeout_service = build_mock_service(resmoke_proxy=mock_resmoke_proxy)
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -149,10 +163,10 @@ class TestGetTaskHookOverhead(unittest.TestCase):
class TestLookupHistoricStats(unittest.TestCase):
def test_no_stats_from_evergreen_should_return_none(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
mock_evg_api.test_stats_by_project.return_value = []
timeout_service = build_mock_service(evg_api=mock_evg_api)
@patch(ns("HistoricTaskData.from_s3"))
def test_no_stats_from_evergreen_should_return_none(self, from_s3_mock: MagicMock):
from_s3_mock.return_value = None
timeout_service = build_mock_service()
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -165,10 +179,10 @@ class TestLookupHistoricStats(unittest.TestCase):
self.assertIsNone(stats)
def test_errors_from_evergreen_should_return_none(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
mock_evg_api.test_stats_by_project.side_effect = HTTPError("failed to connect")
timeout_service = build_mock_service(evg_api=mock_evg_api)
@patch(ns("HistoricTaskData.from_s3"))
def test_errors_from_evergreen_should_return_none(self, from_s3_mock: MagicMock):
from_s3_mock.side_effect = HTTPError("failed to connect")
timeout_service = build_mock_service()
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",
@ -181,11 +195,11 @@ class TestLookupHistoricStats(unittest.TestCase):
self.assertIsNone(stats)
def test_stats_from_evergreen_should_return_the_stats(self):
mock_evg_api = MagicMock(spec_set=EvergreenApi)
@patch(ns("HistoricTaskData.from_s3"))
def test_stats_from_evergreen_should_return_the_stats(self, from_s3_mock: MagicMock):
test_stats = [tst_stat_mock(f"test_{i}.js", 60, 1) for i in range(100)]
mock_evg_api.test_stats_by_project.return_value = test_stats
timeout_service = build_mock_service(evg_api=mock_evg_api)
from_s3_mock.return_value = HistoricTaskData(test_stats)
timeout_service = build_mock_service()
timeout_params = under_test.TimeoutParams(
evg_project="my project",
build_variant="bv",

View File

@ -1,5 +1,7 @@
"""Unit tests for metrics_datatypes.py."""
from datetime import datetime
import os
import sys
import unittest
from unittest.mock import patch
@ -9,6 +11,12 @@ import buildscripts.metrics.metrics_datatypes as under_test
# pylint: disable=unused-argument
# Metrics collection is not supported for Windows
if os.name == "nt":
sys.exit()
MOCK_EXIT_HOOK = MagicMock(exit_code=0)
@patch("buildscripts.metrics.metrics_datatypes.BuildInfo._get_scons_artifact_dir",
return_value='/test')
@ -18,94 +26,89 @@ class TestBuildInfo(unittest.TestCase):
@patch("buildscripts.metrics.metrics_datatypes.BuildInfo._get_scons_options_dict",
return_value={'opt': 'opt'})
def test_build_info_valid(self, mock_env, mock_options, mock_artifact_dir):
build_info = under_test.BuildInfo.get_scons_build_info(datetime.utcnow(), MagicMock(),
MagicMock(), MagicMock(),
MagicMock())
build_info = under_test.BuildInfo.generate_metrics(datetime.utcnow(), MagicMock(),
MagicMock(), MagicMock(), MagicMock())
assert not build_info.is_malformed()
def test_build_info_malformed(self, mock_artifact_dir):
build_info = under_test.BuildInfo.get_scons_build_info(datetime.utcnow(), MagicMock(),
MagicMock(), MagicMock(),
MagicMock())
build_info = under_test.BuildInfo.generate_metrics(datetime.utcnow(), MagicMock(),
MagicMock(), MagicMock(), MagicMock())
assert build_info.is_malformed()
class TestExitInfo(unittest.TestCase):
@patch("sys.exc_info", return_value=(None, None, None))
def test_resmoke_no_exc_info(self, mock_exc_info):
exit_info = under_test.ExitInfo.get_resmoke_exit_info()
assert not exit_info.is_malformed()
@patch("sys.exc_info", return_value=(None, ValueError(), None))
def test_resmoke_with_exc_info(self, mock_exc_info):
exit_info = under_test.ExitInfo.get_resmoke_exit_info()
assert not exit_info.is_malformed()
def test_scons_exit_info_valid(self):
exit_info = under_test.ExitInfo.get_scons_exit_info(0)
assert not exit_info.is_malformed()
def test_scons_exit_info_malformed(self):
exit_info = under_test.ExitInfo.get_scons_exit_info('string')
assert exit_info.is_malformed()
class TestHostInfo(unittest.TestCase):
@patch("buildscripts.metrics.metrics_datatypes.HostInfo._get_memory", side_effect=Exception())
def test_host_info_with_exc(self, mock_get_memory):
host_info = under_test.HostInfo.get_host_info()
host_info = under_test.HostInfo.generate_metrics()
assert host_info.is_malformed()
# Mock this so that it passes when running the 'buildscripts_test' suite on Windows
@patch("buildscripts.metrics.metrics_datatypes.HostInfo._get_memory", return_value=30)
def test_host_info_no_exc(self, mock_get_memory):
host_info = under_test.HostInfo.get_host_info()
host_info = under_test.HostInfo.generate_metrics()
assert not host_info.is_malformed()
class TestGitInfo(unittest.TestCase):
@patch("git.Repo", side_effect=Exception())
def test_git_info_with_exc(self, mock_repo):
git_info = under_test.GitInfo.get_git_info('.')
git_info = under_test.GitInfo.generate_metrics('.')
assert git_info.is_malformed()
def test_git_info_no_exc(self):
git_info = under_test.GitInfo.get_git_info('.')
git_info = under_test.GitInfo.generate_metrics('.')
assert not git_info.is_malformed()
@patch("git.refs.symbolic.SymbolicReference.is_detached", True)
def test_git_info_detached_head(self):
git_info = under_test.GitInfo.get_git_info('.')
git_info = under_test.GitInfo.generate_metrics('.')
assert not git_info.is_malformed()
# Mock this so that it passes when running the 'buildscripts_test' suite on Windows
@patch("buildscripts.metrics.metrics_datatypes.HostInfo._get_memory", return_value=30)
class TestToolingMetrics(unittest.TestCase):
class TestResmokeToolingMetrics(unittest.TestCase):
@patch("socket.gethostname", side_effect=Exception())
def test_resmoke_tooling_metrics_with_exc(self, mock_gethostname, mock_get_memory):
tooling_metrics = under_test.ToolingMetrics.get_resmoke_metrics(datetime.utcnow())
def test_resmoke_tooling_metrics_valid(self, mock_gethostname):
tooling_metrics = under_test.ResmokeToolingMetrics.generate_metrics(
datetime.utcnow(),
MOCK_EXIT_HOOK,
)
assert tooling_metrics.is_malformed()
def test_resmoke_tooling_metrics_no_exc(self, mock_get_memory):
tooling_metrics = under_test.ToolingMetrics.get_resmoke_metrics(datetime.utcnow())
def test_resmoke_tooling_metrics_malformed(self):
tooling_metrics = under_test.ResmokeToolingMetrics.generate_metrics(
datetime.utcnow(),
MOCK_EXIT_HOOK,
)
assert not tooling_metrics.is_malformed()
class TestSConsToolingMetrics(unittest.TestCase):
@patch("buildscripts.metrics.metrics_datatypes.BuildInfo._get_scons_artifact_dir",
return_value='/test')
@patch("buildscripts.metrics.metrics_datatypes.BuildInfo._get_scons_env_vars_dict",
return_value={'env': 'env'})
@patch("buildscripts.metrics.metrics_datatypes.BuildInfo._get_scons_options_dict",
return_value={'opt': 'opt'})
def test_scons_tooling_metrics_valid(self, mock_options, mock_env, mock_artifact_dir,
mock_get_memory):
def test_scons_tooling_metrics_valid(self, mock_options, mock_env, mock_artifact_dir):
parser = MagicMock()
parser.parse_args = MagicMock(return_value={"opt1": "val1"})
tooling_metrics = under_test.ToolingMetrics.get_scons_metrics(
datetime.utcnow(), {'env': 'env'}, {'opts': 'opts'}, parser, ['test1', 'test2'], 0)
tooling_metrics = under_test.SConsToolingMetrics.generate_metrics(
datetime.utcnow(),
{'env': 'env'},
{'opts': 'opts'},
parser,
['test1', 'test2'],
MOCK_EXIT_HOOK,
)
assert not tooling_metrics.is_malformed()
def test_scons_tooling_metrics_malformed(self, mock_get_memory):
tooling_metrics = under_test.ToolingMetrics.get_scons_metrics(
datetime.utcnow(), {'env': 'env'}, {'opts': 'opts'}, None, [], 0)
def test_scons_tooling_metrics_malformed(self):
tooling_metrics = under_test.SConsToolingMetrics.generate_metrics(
datetime.utcnow(),
{'env': 'env'},
{'opts': 'opts'},
None,
[],
MOCK_EXIT_HOOK,
)
assert tooling_metrics.is_malformed()

View File

@ -3,11 +3,8 @@ import os
import sys
import unittest
from unittest.mock import patch
import mongomock
import pymongo
import buildscripts.metrics.resmoke_tooling_metrics as under_test
from buildscripts.resmoke import entrypoint as resmoke_entrypoint
import buildscripts.resmoke as under_test
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME = 'mongodb://testing:27017'
CURRENT_DATE_TIME = datetime(2022, 10, 4)
@ -19,37 +16,32 @@ if os.name == "nt":
sys.exit()
@patch("buildscripts.metrics.tooling_metrics_utils.INTERNAL_TOOLING_METRICS_HOSTNAME",
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
@patch("buildscripts.resmokelib.logging.flush._FLUSH_THREAD", None)
class TestResmokeMetricsCollection(unittest.TestCase):
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.resmoke_tooling_metrics.should_collect_metrics", return_value=True)
@patch("atexit.register")
class TestResmokeAtExitMetricsCollection(unittest.TestCase):
@patch("sys.argv", ['buildscripts/resmoke.py', 'list-suites'])
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=True)
def test_resmoke_at_exit_metrics_collection(self, mock_should_collect_metrics,
mock_atexit_register):
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_metrics" in atexit_functions
@patch("sys.argv", ['buildscripts/resmoke.py', 'list-suites'])
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=False)
def test_no_resmoke_at_exit_metrics_collection(self, mock_should_collect_metrics,
mock_atexit_register):
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_metrics" not in atexit_functions
@patch("sys.argv", ['buildscripts/resmoke.py', 'run', '--suite', 'buildscripts_test'])
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=True)
@patch("buildscripts.resmokelib.testing.executor.TestSuiteExecutor._run_tests",
side_effect=Exception())
def test_resmoke_metrics_collection_exc(self, mock_executor_run, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
with self.assertRaises(SystemExit):
resmoke_entrypoint()
assert client.metrics.tooling_metrics.find_one()
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.resmoke_tooling_metrics.should_collect_metrics", return_value=True)
@patch("sys.argv", ['buildscripts/resmoke.py', 'list-suites'])
def test_resmoke_metrics_collection(self, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
resmoke_entrypoint()
assert client.metrics.tooling_metrics.find_one()
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.resmoke_tooling_metrics.should_collect_metrics",
return_value=False)
@patch("sys.argv", ['buildscripts/resmoke.py', 'list-suites'])
def test_no_resmoke_metrics_collection(self, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
resmoke_entrypoint()
assert not client.metrics.tooling_metrics.find_one()
def test_resmoke_at_exit_metrics_collection_exc(
self, mock_exc_method, mock_should_collect_metrics, mock_atexit_register):
with self.assertRaises(SystemExit) as _:
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_metrics" in atexit_functions

View File

@ -1,15 +1,8 @@
from datetime import datetime
import os
import sys
import unittest
from unittest.mock import MagicMock, patch
import mongomock
import pymongo
import buildscripts.metrics.scons_tooling_metrics as under_test
from buildscripts.scons import entrypoint as scons_entrypoint
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME = 'mongodb://testing:27017'
CURRENT_DATE_TIME = datetime(2022, 10, 4)
from unittest.mock import patch
import buildscripts.scons as under_test
# pylint: disable=unused-argument
# pylint: disable=protected-access
@ -23,52 +16,29 @@ if os.name == "nt":
'buildscripts/scons.py', "CC=/opt/mongodbtoolchain/v3/bin/gcc",
"CXX=/opt/mongodbtoolchain/v3/bin/g++", "NINJA_PREFIX=test_success", "--ninja"
])
@patch("buildscripts.metrics.scons_tooling_metrics.should_collect_metrics", return_value=True)
@patch("atexit.register")
class TestSconsAtExitMetricsCollection(unittest.TestCase):
def test_scons_at_exit_metrics_collection(self, mock_atexit_register,
mock_should_collect_metrics):
with self.assertRaises(SystemExit) as context:
scons_entrypoint()
assert context.exception.code == 0
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=True)
def test_scons_at_exit_metrics_collection(self, mock_should_collect_metrics,
mock_atexit_register):
with self.assertRaises(SystemExit) as _:
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_scons_tooling_metrics" in atexit_functions
assert "_save_metrics" in atexit_functions
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=False)
def test_no_scons_at_exit_metrics_collection(self, mock_should_collect_metrics,
mock_atexit_register):
with self.assertRaises(SystemExit) as _:
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_metrics" not in atexit_functions
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=True)
@patch("buildscripts.moduleconfig.get_module_sconscripts", side_effect=Exception())
def test_scons_at_exit_metrics_collection_exc(self, mock_method, mock_atexit_register,
mock_should_collect_metrics):
with self.assertRaises(SystemExit) as context:
scons_entrypoint()
assert context.exception.code == 2
def test_scons_at_exit_metrics_collection_exc(
self, mock_exc_method, mock_should_collect_metrics, mock_atexit_register):
with self.assertRaises(SystemExit) as _:
under_test.entrypoint()
atexit_functions = [call[0][0].__name__ for call in mock_atexit_register.call_args_list]
assert "_save_scons_tooling_metrics" in atexit_functions
@patch("buildscripts.metrics.tooling_metrics_utils.INTERNAL_TOOLING_METRICS_HOSTNAME",
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
class TestSconsMetricsCollection(unittest.TestCase):
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.scons_tooling_metrics.should_collect_metrics", return_value=True)
def test_scons_metrics_collection_success(self, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
under_test._save_scons_tooling_metrics(CURRENT_DATE_TIME, None, None, None, None,
MagicMock(exit_code=0))
assert client.metrics.tooling_metrics.find_one()
@patch("buildscripts.metrics.scons_tooling_metrics.should_collect_metrics", return_value=True)
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
def test_scons_metrics_collection_fail(self, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
under_test._save_scons_tooling_metrics(None, None, None, None, None, None)
assert not client.metrics.tooling_metrics.find_one()
@patch("buildscripts.metrics.scons_tooling_metrics.should_collect_metrics", return_value=False)
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
def test_no_scons_metrics_collection(self, mock_should_collect_metrics):
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
under_test._save_scons_tooling_metrics(CURRENT_DATE_TIME, None, None, None, None,
MagicMock(exit_code=0))
assert not client.metrics.tooling_metrics.find_one()
assert "_save_metrics" in atexit_functions

View File

@ -1,81 +1,75 @@
"""Unit tests for tooling_metrics.py."""
import asyncio
from datetime import datetime
import os
import sys
import unittest
from unittest.mock import patch
from unittest.mock import mock_open, patch
from mock import MagicMock
import mongomock
import pymongo
from buildscripts.metrics.metrics_datatypes import ToolingMetrics
from buildscripts.metrics.metrics_datatypes import ResmokeToolingMetrics, SConsToolingMetrics
import buildscripts.metrics.tooling_metrics_utils as under_test
# pylint: disable=unused-argument
# pylint: disable=protected-access
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME = 'mongodb://testing:27017'
CURRENT_DATE_TIME = datetime(2022, 10, 4)
async def extended_sleep(arg):
await asyncio.sleep(2)
RESMOKE_METRICS_ARGS = {
"utc_starttime": datetime(2022, 10, 4),
"exit_hook": MagicMock(exit_code=0),
}
# Metrics collection is not supported for Windows
if os.name == "nt":
sys.exit()
@patch("atexit.register")
class TestRegisterMetricsCollectionAtExit(unittest.TestCase):
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=True)
def test_register_metrics_collection(self, mock_should_collect_metrics, mock_atexit):
under_test.register_metrics_collection_atexit(ResmokeToolingMetrics.generate_metrics,
RESMOKE_METRICS_ARGS)
atexit_functions = [call[0][0].__name__ for call in mock_atexit.call_args_list]
assert "_save_metrics" in atexit_functions
@patch("buildscripts.metrics.tooling_metrics_utils._should_collect_metrics", return_value=False)
def test_no_register_metrics_collection(self, mock_should_collect_metrics, mock_atexit):
under_test.register_metrics_collection_atexit(ResmokeToolingMetrics.generate_metrics,
RESMOKE_METRICS_ARGS)
atexit_functions = [call[0][0].__name__ for call in mock_atexit.call_args_list]
assert "_save_metrics" not in atexit_functions
@patch("buildscripts.metrics.tooling_metrics_utils.INTERNAL_TOOLING_METRICS_HOSTNAME",
TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
class TestSaveToolingMetrics(unittest.TestCase):
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
def test_on_virtual_workstation(self):
under_test.save_tooling_metrics(ToolingMetrics.get_resmoke_metrics(CURRENT_DATE_TIME))
def test_save_resmoke_metrics(self):
under_test._save_metrics(ResmokeToolingMetrics.generate_metrics, RESMOKE_METRICS_ARGS)
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert client.metrics.tooling_metrics.find_one()
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.tooling_metrics_utils._save_metrics",
side_effect=pymongo.errors.WriteError(error="Error Information"))
def test_exception_caught(self, mock_save_metrics):
with self.assertLogs('tooling_metrics_utils') as cm:
under_test.save_tooling_metrics(ToolingMetrics.get_resmoke_metrics(CURRENT_DATE_TIME))
@patch("buildscripts.metrics.tooling_metrics_utils._get_internal_tooling_metrics_client",
side_effect=pymongo.errors.ServerSelectionTimeoutError(message="Error Information"))
def test_save_metrics_with_exc(self, mock_save_metrics):
with self.assertLogs('tooling_metrics') as cm:
under_test._save_metrics(ResmokeToolingMetrics.generate_metrics, RESMOKE_METRICS_ARGS)
assert "Error Information" in cm.output[0]
assert "Unexpected: Tooling metrics collection is not available" in cm.output[0]
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
@mongomock.patch(servers=((TEST_INTERNAL_TOOLING_METRICS_HOSTNAME), ))
@patch("buildscripts.metrics.tooling_metrics_utils._save_metrics", side_effect=extended_sleep)
def test_timeout_caught(self, mock_save_metrics):
with self.assertLogs('tooling_metrics_utils') as cm:
under_test.save_tooling_metrics(ToolingMetrics.get_resmoke_metrics(CURRENT_DATE_TIME))
assert "Timeout: Tooling metrics collection is not available" in cm.output[0]
assert "Internal Metrics Collection Failed" in cm.output[0]
client = pymongo.MongoClient(host=TEST_INTERNAL_TOOLING_METRICS_HOSTNAME)
assert not client.metrics.tooling_metrics.find_one()
class TestIsVirtualWorkstation(unittest.TestCase):
@patch("buildscripts.metrics.tooling_metrics_utils._toolchain_exists", return_value=False)
@patch("buildscripts.metrics.tooling_metrics_utils._git_user_exists", return_value=True)
def test_no_toolchain_has_email(self, mock_git_user_exists, mock_toolchain_exists):
assert not under_test._is_virtual_workstation()
@patch("builtins.open", mock_open(read_data="ubuntu1804-workstation"))
def test_is_virtual_workstation(self):
assert under_test._is_virtual_workstation() is True
@patch("buildscripts.metrics.tooling_metrics_utils._toolchain_exists", return_value=True)
@patch("buildscripts.metrics.tooling_metrics_utils._git_user_exists", return_value=True)
def test_has_toolchain_has_email(self, mock_git_user_exists, mock_toolchain_exists):
assert under_test._is_virtual_workstation()
@patch("buildscripts.metrics.tooling_metrics_utils._toolchain_exists", return_value=True)
@patch("buildscripts.metrics.tooling_metrics_utils._git_user_exists", return_value=False)
def test_has_toolchain_no_email(self, mock_git_user_exists, mock_toolchain_exists):
assert not under_test._is_virtual_workstation()
@patch("buildscripts.metrics.tooling_metrics_utils._toolchain_exists", return_value=False)
@patch("buildscripts.metrics.tooling_metrics_utils._git_user_exists", return_value=False)
def test_no_toolchain_no_email(self, mock_git_user_exists, mock_toolchain_exists):
assert not under_test._is_virtual_workstation()
@patch("builtins.open", mock_open(read_data="test"))
def test_is_not_virtual_workstation(self):
assert under_test._is_virtual_workstation() is False
class TestHasMetricsOptOut(unittest.TestCase):
@ -92,9 +86,9 @@ class TestShouldCollectMetrics(unittest.TestCase):
@patch("buildscripts.metrics.tooling_metrics_utils._is_virtual_workstation", return_value=True)
@patch("buildscripts.metrics.tooling_metrics_utils._has_metrics_opt_out", return_value=False)
def test_should_collect_metrics(self, mock_opt_out, mock_is_virtual_env):
assert under_test.should_collect_metrics()
assert under_test._should_collect_metrics()
@patch("buildscripts.metrics.tooling_metrics_utils._is_virtual_workstation", return_value=True)
@patch("buildscripts.metrics.tooling_metrics_utils._has_metrics_opt_out", return_value=True)
def test_no_collect_metrics_opt_out(self, mock_opt_out, mock_is_virtual_env):
assert not under_test.should_collect_metrics()
assert not under_test._should_collect_metrics()

View File

@ -78,7 +78,7 @@ class TestHistoricTaskData(unittest.TestCase):
@staticmethod
def _make_evg_result(test_file="dir/test1.js", num_pass=0, duration=0):
return Mock(
test_file=test_file,
test_name=test_file,
task_name="task1",
variant="variant1",
distro="distro1",

View File

@ -1,5 +1,4 @@
"""Service for determining task timeouts."""
from datetime import datetime
from typing import Any, Dict, NamedTuple, Optional
import inject
@ -31,29 +30,17 @@ class TimeoutParams(NamedTuple):
is_asan: bool
class TimeoutSettings(NamedTuple):
"""Settings for determining timeouts."""
start_date: datetime
end_date: datetime
class TimeoutService:
"""A service for determining task timeouts."""
@inject.autoparams()
def __init__(self, evg_api: EvergreenApi, resmoke_proxy: ResmokeProxyService,
timeout_settings: TimeoutSettings) -> None:
def __init__(self, resmoke_proxy: ResmokeProxyService) -> None:
"""
Initialize the service.
:param evg_api: Evergreen API client.
:param resmoke_proxy: Proxy to query resmoke.
:param timeout_settings: Settings for how timeouts are calculated.
"""
self.evg_api = evg_api
self.resmoke_proxy = resmoke_proxy
self.timeout_settings = timeout_settings
def get_timeout_estimate(self, timeout_params: TimeoutParams) -> TimeoutEstimate:
"""
@ -137,10 +124,8 @@ class TimeoutService:
:return: Historic test results if they exist.
"""
try:
evg_stats = HistoricTaskData.from_evg(
self.evg_api, timeout_params.evg_project, self.timeout_settings.start_date,
self.timeout_settings.end_date, timeout_params.task_name,
timeout_params.build_variant)
evg_stats = HistoricTaskData.from_s3(
timeout_params.evg_project, timeout_params.task_name, timeout_params.build_variant)
if not evg_stats:
LOGGER.warning("No historic runtime information available")
return None

View File

@ -1,15 +1,31 @@
"""Utility to support parsing a TestStat."""
from collections import defaultdict
from dataclasses import dataclass
from datetime import datetime
from itertools import chain
from typing import NamedTuple, List, Callable, Optional
from evergreen import EvergreenApi, TestStats
import requests
from requests.adapters import HTTPAdapter, Retry
from buildscripts.util.testname import split_test_hook_name, is_resmoke_hook, get_short_name_from_test_file
TASK_LEVEL_HOOKS = {"CleanEveryN"}
TESTS_STATS_S3_LOCATION = "https://mongo-test-stats.s3.amazonaws.com"
class HistoricalTestInformation(NamedTuple):
"""
Container for information about the historical runtime of a test.
test_name: Name of test.
avg_duration_pass: Average of runtime of test that passed.
num_pass: Number of times the test has passed.
num_fail: Number of times the test has failed.
"""
test_name: str
num_pass: int
num_fail: int
avg_duration_pass: float
class TestRuntime(NamedTuple):
@ -74,9 +90,9 @@ class HistoricHookInfo(NamedTuple):
avg_duration: float
@classmethod
def from_test_stats(cls, test_stats: TestStats) -> "HistoricHookInfo":
def from_test_stats(cls, test_stats: HistoricalTestInformation) -> "HistoricHookInfo":
"""Create an instance from a test_stats object."""
return cls(hook_id=test_stats.test_file, num_pass=test_stats.num_pass,
return cls(hook_id=test_stats.test_name, num_pass=test_stats.num_pass,
avg_duration=test_stats.avg_duration_pass)
def test_name(self) -> str:
@ -101,10 +117,10 @@ class HistoricTestInfo(NamedTuple):
hooks: List[HistoricHookInfo]
@classmethod
def from_test_stats(cls, test_stats: TestStats,
def from_test_stats(cls, test_stats: HistoricalTestInformation,
hooks: List[HistoricHookInfo]) -> "HistoricTestInfo":
"""Create an instance from a test_stats object."""
return cls(test_name=test_stats.test_file, num_pass=test_stats.num_pass,
return cls(test_name=test_stats.test_name, num_pass=test_stats.num_pass,
avg_duration=test_stats.avg_duration_pass, hooks=hooks)
def normalized_test_name(self) -> str:
@ -137,45 +153,56 @@ class HistoricTaskData(object):
"""Initialize the TestStats with raw results from the Evergreen API."""
self.historic_test_results = historic_test_results
@classmethod
def from_evg(cls, evg_api: EvergreenApi, project: str, start_date: datetime, end_date: datetime,
task: str, variant: str) -> "HistoricTaskData":
@staticmethod
def get_stats_from_s3(project: str, task: str, variant: str) -> List[HistoricalTestInformation]:
"""
Retrieve test stats from evergreen for a given task.
Retrieve test stats from s3 for a given task.
:param project: Project to query.
:param task: Task to query.
:param variant: Build variant to query.
:return: A list of the Test stats for the specified task.
"""
session = requests.Session()
retries = Retry(total=5, backoff_factor=1, status_forcelist=[502, 503, 504])
session.mount('https://', HTTPAdapter(max_retries=retries))
response = session.get(f"{TESTS_STATS_S3_LOCATION}/{project}/{variant}/{task}")
data = response.json()
return [HistoricalTestInformation(**item) for item in data]
@classmethod
def from_s3(cls, project: str, task: str, variant: str) -> "HistoricTaskData":
"""
Retrieve test stats from s3 for a given task.
:param evg_api: Evergreen API client.
:param project: Project to query.
:param start_date: Start date to query.
:param end_date: End date to query.
:param task: Task to query.
:param variant: Build variant to query.
:return: Test stats for the specified task.
"""
days = (end_date - start_date).days
historic_stats = evg_api.test_stats_by_project(
project, after_date=start_date, before_date=end_date, tasks=[task], variants=[variant],
group_by="test", group_num_days=days)
return cls.from_stats_list(historic_stats)
historical_test_data = cls.get_stats_from_s3(project, task, variant)
return cls.from_stats_list(historical_test_data)
@classmethod
def from_stats_list(cls, historic_stats: List[TestStats]) -> "HistoricTaskData":
def from_stats_list(
cls, historical_test_data: List[HistoricalTestInformation]) -> "HistoricTaskData":
"""
Build historic task data from a list of historic stats.
:param historic_stats: List of historic stats to build from.
:param historical_test_data: A list of information about the runtime of a test.
:return: Historic task data from the list of stats.
"""
hooks = defaultdict(list)
for hook in [stat for stat in historic_stats if is_resmoke_hook(stat.test_file)]:
for hook in [stat for stat in historical_test_data if is_resmoke_hook(stat.test_name)]:
historical_hook = HistoricHookInfo.from_test_stats(hook)
hooks[historical_hook.test_name()].append(historical_hook)
return cls([
HistoricTestInfo.from_test_stats(stat,
hooks[get_short_name_from_test_file(stat.test_file)])
for stat in historic_stats if not is_resmoke_hook(stat.test_file)
hooks[get_short_name_from_test_file(stat.test_name)])
for stat in historical_test_data if not is_resmoke_hook(stat.test_name)
])
def get_tests_runtimes(self) -> List[TestRuntime]:

View File

@ -272,8 +272,18 @@ last-continuous:
ticket: SERVER-70190
- test_file: jstests/core/cover_null_queries.js
ticket: SERVER-70436
- test_file: jstests/sharding/prepare_transaction_then_migrate.js
ticket: SERVER-68361
- test_file: jstests/sharding/all_collection_stats.js
ticket: SERVER-71477
- test_file: jstests/core/project_with_collation.js
ticket: SERVER-72416
- test_file: jstests/core/collation.js
ticket: SERVER-72416
- test_file: jstests/core/or_to_in.js
ticket: SERVER-72416
- test_file: src/mongo/db/modules/enterprise/jstests/fcbis/oplog_rollover.js
ticket: SERVER-72422
- test_file: jstests/core/timeseries/timeseries_groupby_reorder.js
ticket: SERVER-73822
suites: null
last-lts:
all:
@ -621,6 +631,16 @@ last-lts:
ticket: SERVER-70190
- test_file: jstests/core/cover_null_queries.js
ticket: SERVER-70436
- test_file: jstests/sharding/prepare_transaction_then_migrate.js
ticket: SERVER-68361
- test_file: jstests/sharding/all_collection_stats.js
ticket: SERVER-71477
- test_file: jstests/core/project_with_collation.js
ticket: SERVER-72416
- test_file: jstests/core/collation.js
ticket: SERVER-72416
- test_file: jstests/core/or_to_in.js
ticket: SERVER-72416
- test_file: src/mongo/db/modules/enterprise/jstests/fcbis/oplog_rollover.js
ticket: SERVER-72422
- test_file: jstests/core/timeseries/timeseries_groupby_reorder.js
ticket: SERVER-73822
suites: null

View File

@ -248,7 +248,6 @@ variables:
- ubuntu2004-package
- name: selinux_rhel7_enterprise
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
@ -310,34 +309,6 @@ buildvariants:
- name: sharding_gen
- name: sharding_opportunistic_secondary_targeting_gen
- <<: *linux-64-debug-required-template
name: &linux-64-debug-wtdevelop linux-64-debug-wtdevelop
display_name: "~ Linux DEBUG WiredTiger develop"
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
modules:
- wtdevelop
depends_on:
- name: archive_dist_test
variant: &linux_x86_dynamic_debug_wtdevelop_compile_variant_name linux-x86-dynamic-debug-wtdevelop-compile
- name: version_gen
variant: generate-tasks-for-version
expansions:
use_wt_develop: true
resmoke_jobs_factor: 0.5 # Avoid starting too many mongod's
compile_flags: >-
--dbg=on
--opt=on
-j$(grep -c ^processor /proc/cpuinfo)
--variables-files=etc/scons/mongodbtoolchain_v3_gcc.vars
--enable-free-mon=on
--enable-http-client=on
--link-model=dynamic
scons_cache_mode: all
scons_cache_scope: shared
num_scons_link_jobs_available: 0.99
test_flags: --excludeWithAnyTags=requires_http_client
compile_variant: *linux_x86_dynamic_debug_wtdevelop_compile_variant_name
- name: &tla-plus tla-plus
display_name: TLA+
run_on:
@ -987,7 +958,7 @@ buildvariants:
# To force disable feature flags even on the all feature flags variant, please use this file:
# buildscripts/resmokeconfig/fully_disabled_feature_flags.yml
test_flags: >-
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
--excludeWithAnyTags=incompatible_with_windows_tls
--excludeWithAnyTags=incompatible_with_shard_merge
external_auth_jobs_max: 1
@ -1577,7 +1548,7 @@ buildvariants:
# To force disable feature flags even on the all feature flags variant, please use this file:
# buildscripts/resmokeconfig/fully_disabled_feature_flags.yml
test_flags: >-
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
--excludeWithAnyTags=incompatible_with_shard_merge
tasks:
- name: cqf
@ -1873,7 +1844,7 @@ buildvariants:
<<: *linux-x86-multiversion-expansions-template
# No feature flag tests since they aren't compatible with the older binaries.
test_flags: >-
--runAllFeatureFlagsNoTests
--runNoFeatureFlagTests
--excludeWithAnyTags=incompatible_with_shard_merge
- <<: *linux-x86-multiversion-template
@ -2251,7 +2222,7 @@ buildvariants:
# buildscripts/resmokeconfig/fully_disabled_feature_flags.yml
large_distro_name: rhel80-build
test_flags: >-
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
--excludeWithAnyTags=incompatible_with_shard_merge
separate_debug: off
tasks:
@ -2433,7 +2404,7 @@ buildvariants:
test_flags: >-
--excludeWithAnyTags=requires_ocsp_stapling
--excludeWithAnyTags=incompatible_with_shard_merge
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
multiversion_platform: rhel80
multiversion_edition: enterprise
resmoke_jobs_factor: 0.3 # Avoid starting too many mongod's under UBSAN build.
@ -2616,7 +2587,7 @@ buildvariants:
test_flags: >-
--excludeWithAnyTags=requires_ocsp_stapling
--excludeWithAnyTags=incompatible_with_shard_merge
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
tasks:
- name: jsCore
- name: jsCore_txns
@ -3328,7 +3299,7 @@ buildvariants:
target_resmoke_time: 30
max_sub_suites: 3
test_flags: >-
--runAllFeatureFlagTests
--additionalFeatureFlagsFile all_feature_flags.txt
--excludeWithAnyTags=resource_intensive
--excludeWithAnyTags=incompatible_with_shard_merge
@ -3388,18 +3359,6 @@ buildvariants:
- windows-vsCurrent-large
- name: .benchmarks !benchmarks_orphaned
- <<: *enterprise-windows-nopush-template
name: &enterprise-windows-wtdevelop enterprise-windows-wtdevelop
display_name: "~ Enterprise Windows WiredTiger develop"
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
modules:
- enterprise
- wtdevelop
expansions:
<<: *enterprise-windows-nopush-expansions-template
use_wt_develop: true
compile_variant: *enterprise-windows-wtdevelop
### QO & QE Patch-Specific Build Variants ###
- <<: *enterprise-windows-nopush-template
name: &windows-compile-query-patch-only windows-compile-query-patch-only

View File

@ -6,16 +6,336 @@ include:
- filename: etc/evergreen_yml_components/variants/atlas.yml
- filename: etc/evergreen_yml_components/variants/misc_release.yml
### Comment out when using this file for a LTS or Rapid release branch. ###
- filename: etc/evergreen_yml_components/variants/ibm.yml
# - filename: etc/evergreen_yml_components/variants/ibm.yml
### Uncomment when using this file for a LTS release branch. ###
# - filename: etc/evergreen_yml_components/variants/in_memory.yml
### Uncomment when using this file for a LTS or Rapid release branch. ###
# - filename: etc/evergreen_yml_components/variants/sanitizer.yml
- filename: etc/evergreen_yml_components/variants/sanitizer.yml
### Uncomment when using this file for a LTS or Rapid release branch. ###
# - filename: etc/evergreen_yml_components/variants/ninja.yml
- filename: etc/evergreen_yml_components/variants/ninja.yml
- filename: etc/evergreen_yml_components/variants/compile_static_analysis.yml
parameters:
- key: evergreen_config_file_path
value: "etc/evergreen_nightly.yml"
description: "path to this file"
variables:
# Common compile variant dependency specifications.
- &linux_x86_dynamic_compile_variant_dependency
depends_on:
- name: archive_dist_test_debug
variant: &linux_x86_dynamic_compile_variant_name linux-x86-dynamic-compile-required
- name: version_gen
variant: generate-tasks-for-version
- &linux_x86_dynamic_debug_compile_variant_dependency
depends_on:
- name: archive_dist_test_debug
variant: &linux_x86_dynamic_debug_compile_variant_name linux-x86-dynamic-debug-compile-required
- name: version_gen
variant: generate-tasks-for-version
- &linux_debug_aubsan_compile_variant_dependency
depends_on:
- name: archive_dist_test_debug
variant: &linux_debug_aubsan_compile_variant_name linux-debug-aubsan-compile-required
- name: version_gen
variant: generate-tasks-for-version
- &windows_compile_variant_dependency
depends_on:
- name: archive_dist_test_debug
variant: &windows_compile_variant_name windows-compile-required
- name: version_gen
variant: generate-tasks-for-version
- &linux_x86_generic_expansions
multiversion_platform: rhel80
multiversion_edition: enterprise
repo_edition: enterprise
large_distro_name: rhel80-medium
num_scons_link_jobs_available: 0.99
compile_variant: *linux_x86_dynamic_compile_variant_name
buildvariants:
- &linux-64-debug-required-template
<<: *linux_x86_dynamic_debug_compile_variant_dependency
name: &linux-64-debug-required linux-64-debug-required
display_name: "! Linux x86 Shared Library DEBUG"
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
run_on:
- rhel80-medium
expansions:
resmoke_jobs_factor: 0.5 # Avoid starting too many mongod's
test_flags: --excludeWithAnyTags=requires_http_client
target_resmoke_time: 15
max_sub_suites: 5
large_distro_name: rhel80-medium
compile_variant: *linux_x86_dynamic_debug_compile_variant_name
tasks:
- name: .aggregation !.encrypt !.feature_flag_guarded
- name: .auth !.audit !.multiversion
- name: .causally_consistent !.wo_snapshot
- name: .change_streams !.secondary_reads
- name: .clustered_collections
- name: .misc_js
- name: disk_wiredtiger
- name: free_monitoring
- name: .jscore .common
- name: jsCore_txns_large_txns_format
- name: json_schema
- name: query_golden_classic
- name: libunwind_tests
- name: .multi_shard
- name: multi_stmt_txn_jscore_passthrough_with_migration_gen
- name: .ocsp
- name: .read_write_concern
- name: .replica_sets !.encrypt !.ignore_non_generated_replica_sets_jscore_passthrough !.fcbis
- name: replica_sets_jscore_passthrough_gen
- name: replica_sets_reconfig_jscore_passthrough_gen
- name: replica_sets_reconfig_jscore_stepdown_passthrough_gen
- name: .retry
- name: .read_only
- name: session_jscore_passthrough
- name: sharded_multi_stmt_txn_jscore_passthrough
- name: .sharding .jscore !.wo_snapshot
- name: sharding_gen
- name: sharding_opportunistic_secondary_targeting_gen
- &enterprise-windows-required-template
<<: *windows_compile_variant_dependency
name: &enterprise-windows-required enterprise-windows-required
display_name: "! Enterprise Windows"
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
modules:
- enterprise
run_on:
- windows-vsCurrent-small
expansions: &windows_required_expansions
compile_variant: *windows_compile_variant_name
burn_in_tests_build_variant: enterprise-windows-required
exe: ".exe"
content_type: application/zip
python: '/cygdrive/c/python/python37/python.exe'
ext: zip
multiversion_platform: windows
multiversion_edition: enterprise
jstestfuzz_num_generated_files: 35
target_resmoke_time: 20
max_sub_suites: 5
large_distro_name: windows-vsCurrent-large
push_path: windows
push_bucket: downloads.10gen.com
push_name: windows
push_arch: x86_64-enterprise
test_flags: &windows_common_test_excludes --excludeWithAnyTags=incompatible_with_windows_tls
external_auth_jobs_max: 1
tasks:
# - name: burn_in_tests_gen
- name: audit
- name: auth_audit_gen
- name: causally_consistent_jscore_txns_passthrough
distros:
- windows-vsCurrent-large
- name: .encrypt !.aggregation !.replica_sets !.sharding !.jscore
- name: external_auth
- name: external_auth_aws
- name: external_auth_windows
distros:
- windows-2016-dc
- name: .jscore .common !.sharding
- name: jsCore_auth
- name: jsCore_ese
- name: jsCore_txns_large_txns_format
- name: .jstestfuzz .common
- name: mqlrun
- name: noPassthrough_gen
- name: noPassthroughWithMongod_gen
- name: .replica_sets .common !.ignore_non_generated_replica_sets_jscore_passthrough
- name: .replica_sets .multi_oplog !.ignore_non_generated_replica_sets_jscore_passthrough
- name: replica_sets_jscore_passthrough_gen
distros:
- windows-vsCurrent-large
- name: replica_sets_ese_gen
- name: sasl
- name: .sharding .txns
- name: sharding_auth_gen
- name: sharding_auth_audit_gen
- name: sharding_ese_gen
- &enterprise-rhel-80-64-bit-dynamic-required-template
<<: *linux_x86_dynamic_compile_variant_dependency
name: &enterprise-rhel-80-64-bit-dynamic-required enterprise-rhel-80-64-bit-dynamic-required
display_name: "! Shared Library Enterprise RHEL 8.0"
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
modules:
- enterprise
run_on:
- rhel80-small
expansions: &enterprise-rhel-80-64-bit-dynamic-expansions
<<: *linux_x86_generic_expansions
scons_cache_scope: shared
scons_cache_mode: all
has_packages: false
jstestfuzz_num_generated_files: 40
jstestfuzz_concurrent_num_files: 10
target_resmoke_time: 10
max_sub_suites: 5
idle_timeout_factor: 1.5
exec_timeout_factor: 1.5
large_distro_name: rhel80-medium
burn_in_tag_buildvariants: >-
enterprise-rhel-80-64-bit-inmem
enterprise-rhel-80-64-bit-multiversion
burn_in_tag_compile_task_group_name: compile_and_archive_dist_test_TG
burn_in_tag_compile_distro: rhel80-xlarge
depends_on:
- name: archive_dist_test
variant: *linux_x86_dynamic_compile_variant_name
- name: version_gen
variant: generate-tasks-for-version
- name: version_burn_in_gen
variant: generate-tasks-for-version
tasks:
# - name: burn_in_tests_gen
- name: .aggfuzzer !.feature_flag_guarded
- name: .aggregation !.feature_flag_guarded
- name: audit
- name: .auth
- name: unittest_shell_hang_analyzer_gen
- name: .causally_consistent !.sharding
- name: .change_streams
- name: .change_stream_fuzzer
- name: .misc_js
- name: .concurrency !.large !.ubsan !.no_txns !.debug_only
- name: .concurrency .large !.ubsan !.no_txns !.debug_only
distros:
- rhel80-medium
- name: disk_wiredtiger
- name: .encrypt
- name: idl_tests
- name: initial_sync_fuzzer_gen
- name: jsCore
distros:
- rhel80-xlarge
- name: .jscore .common !jsCore
- name: jsCore_minimum_batch_size
- name: jsCore_txns_large_txns_format
- name: json_schema
- name: .jstestfuzz !.flow_control # Flow control jstestfuzz take longer.
- name: libunwind_tests
- name: mqlrun
- name: .multi_shard
- name: multi_stmt_txn_jscore_passthrough_with_migration_gen
- name: multiversion_gen
- name: .query_fuzzer
- name: .random_multiversion_ds
- name: .read_write_concern .large
distros:
- rhel80-medium
- name: .read_write_concern !.large
- name: .replica_sets !.encrypt !.auth
distros:
- rhel80-xlarge
- name: replica_sets_api_version_jscore_passthrough_gen
- name: replica_sets_reconfig_jscore_passthrough_gen
- name: replica_sets_reconfig_jscore_stepdown_passthrough_gen
distros:
- rhel80-xlarge
- name: replica_sets_reconfig_kill_primary_jscore_passthrough_gen
distros:
- rhel80-xlarge
- name: retryable_writes_jscore_passthrough_gen
- name: retryable_writes_jscore_stepdown_passthrough_gen
distros:
- rhel80-medium
- name: .read_only
- name: .rollbackfuzzer
- name: sasl
- name: search
- name: search_auth
- name: search_ssl
- name: session_jscore_passthrough
- name: .sharding .jscore !.wo_snapshot !.multi_stmt
- name: sharding_api_version_jscore_passthrough_gen
- name: .sharding .txns
- name: .sharding .common
- name: .updatefuzzer
- name: secondary_reads_passthrough_gen
- name: .serverless
distros:
- rhel80-xlarge
- &rhel80-debug-aubsan-lite-required-template
<<: *linux_debug_aubsan_compile_variant_dependency
name: &rhel80-debug-aubsan-lite-required rhel80-debug-aubsan-lite-required
display_name: "! Shared Library {A,UB}SAN Enterprise RHEL 8.0 DEBUG"
cron: "0 */4 * * *" # From the ${project_required_suggested_cron} parameter
modules:
- enterprise
run_on:
- rhel80-build
expansions: &aubsan-lite-required-expansions
compile_variant: *linux_debug_aubsan_compile_variant_name
lang_environment: LANG=C
# If you add anything to san_options, make sure the appropriate changes are
# also made to SConstruct.
san_options: >-
UBSAN_OPTIONS="print_stacktrace=1:external_symbolizer_path=/opt/mongodbtoolchain/v3/bin/llvm-symbolizer"
LSAN_OPTIONS="suppressions=etc/lsan.suppressions:report_objects=1"
ASAN_OPTIONS="detect_leaks=1:check_initialization_order=true:strict_init_order=true:abort_on_error=1:disable_coredump=0:handle_abort=1:strict_string_checks=true:detect_invalid_pointer_pairs=1:external_symbolizer_path=/opt/mongodbtoolchain/v3/bin/llvm-symbolizer"
test_flags: --excludeWithAnyTags=requires_ocsp_stapling
resmoke_jobs_factor: 0.3 # Avoid starting too many mongod's under {A,UB}SAN build.
hang_analyzer_dump_core: false
max_sub_suites: 3
num_scons_link_jobs_available: 0.99
large_distro_name: rhel80-build
tasks:
- name: jsCore
- name: jsCore_txns
- <<: *enterprise-rhel-80-64-bit-dynamic-required-template
name: &commit-queue commit-queue
display_name: "~ Commit Queue"
cron: "0 4 * * 0" # From the ${project_weekly_cron} parameter
stepback: false
expansions:
<<: *linux_x86_generic_expansions
scons_cache_scope: shared
scons_cache_mode: all
has_packages: false
compile_flags: >-
--ssl
MONGO_DISTMOD=rhel80
-j$(grep -c ^processor /proc/cpuinfo)
--variables-files=etc/scons/mongodbtoolchain_v3_gcc.vars
--link-model=dynamic
crypt_task_compile_flags: >-
SHLINKFLAGS_EXTRA="-Wl,-Bsymbolic
-Wl,--no-gnu-unique"
CCFLAGS="-fno-gnu-unique"
clang_tidy_toolchain: v3
compile_variant: *commit-queue
depends_on: []
tasks:
- name: compile_test_and_package_parallel_core_stream_TG
distros:
- rhel80-xlarge-commitqueue
- name: compile_test_and_package_parallel_unittest_stream_TG
distros:
- rhel80-xlarge-commitqueue
- name: compile_test_and_package_parallel_dbtest_stream_TG
distros:
- rhel80-xlarge-commitqueue
- name: jsCore
distros:
- rhel80-xlarge-commitqueue
- name: .lint
- name: test_api_version_compatibility
- name: validate_commit_message
- name: check_feature_flag_tags
- name: compile_venv_deps_check

View File

@ -10,6 +10,10 @@
# in alphabetical order.
overrides:
amazon-linux2-arm64-compile:
- task: server_discovery_and_monitoring_json_test
exec_timeout: 30 # 30 min.
enterprise-amazon2-arm64:
- task: config_fuzzer_replica_sets_jscore_passthrough
exec_timeout: 150 # 2.5 hours.
@ -68,6 +72,10 @@ overrides:
- task: auth
exec_timeout: 60 # 1 hour.
linux-x86-dynamic-compile-required:
- task: server_discovery_and_monitoring_json_test
exec_timeout: 30 # 30 min.
linux-64-debug-repeated-execution:
- task: run_unittests
exec_timeout: 120 # 2 hours.

View File

@ -66,7 +66,7 @@ modules:
- name: enterprise
repo: git@github.com:10gen/mongo-enterprise-modules.git
prefix: src/mongo/db/modules
branch: master
branch: v6.2
- name: wtdevelop
repo: git@github.com:wiredtiger/wiredtiger.git
@ -608,7 +608,7 @@ functions:
"get buildnumber": &get_buildnumber
command: keyval.inc
params:
key: "${build_variant}_master"
key: "${build_variant}_v6.2"
destination: "builder_num"
"run diskstats": &run_diskstats
@ -5017,7 +5017,9 @@ tasks:
- func: "run tests"
vars:
suite: core
resmoke_args: --fuzzMongodConfigs
resmoke_args: >-
--fuzzMongodConfigs
--excludeWithAnyTags=does_not_support_config_fuzzer
- <<: *task_template
name: config_fuzzer_concurrency
@ -5027,7 +5029,9 @@ tasks:
- func: "run tests"
vars:
suite: concurrency
resmoke_args: --fuzzMongodConfigs
resmoke_args: >-
--fuzzMongodConfigs
--excludeWithAnyTags=does_not_support_config_fuzzer
- <<: *task_template
name: config_fuzzer_simulate_crash_concurrency_replication
@ -5037,7 +5041,9 @@ tasks:
- func: "run tests"
vars:
suite: simulate_crash_concurrency_replication
resmoke_args: --fuzzMongodConfigs
resmoke_args: >-
--fuzzMongodConfigs
--excludeWithAnyTags=does_not_support_config_fuzzer
- <<: *task_template
name: config_fuzzer_concurrency_replication
@ -5047,7 +5053,9 @@ tasks:
- func: "run tests"
vars:
suite: concurrency_replication
resmoke_args: --fuzzMongodConfigs
resmoke_args: >-
--fuzzMongodConfigs
--excludeWithAnyTags=does_not_support_config_fuzzer
- <<: *task_template
name: config_fuzzer_replica_sets_jscore_passthrough
@ -5057,7 +5065,9 @@ tasks:
- func: "run tests"
vars:
suite: replica_sets_jscore_passthrough
resmoke_args: --fuzzMongodConfigs
resmoke_args: >-
--fuzzMongodConfigs
--excludeWithAnyTags=does_not_support_config_fuzzer
- <<: *task_template
name: jsCore_ese
@ -6173,6 +6183,7 @@ tasks:
- func: "generate resmoke tasks"
vars:
use_large_distro: "true"
multiversion_exclude_tags_version: last_lts
- <<: *gen_task_template
name: sharding_opportunistic_secondary_targeting_gen
@ -6827,19 +6838,6 @@ tasks:
- *set_up_venv
- func: "run package test"
- name: test_packages_complete
tags: []
depends_on:
- name: package
commands:
- command: manifest.load
- func: "git get project and add git tag"
- *f_expansions_write
- *kill_processes
- *cleanup_environment
- *set_up_venv
- func: "run complete package test"
- name: package
tags: []
depends_on:
@ -7019,42 +7017,6 @@ tasks:
args:
- "./src/evergreen/packages_publish.sh"
- name: publish_packages_test
run_on: rhel80-small
tags: ["publish_test"]
# This should prevent this task from running in patch builds, where we
# don't want to publish packages.
patchable: false
stepback: false
# Same dependencies as "push" below
depends_on:
- name: package
- name: jsCore
- name: run_dbtest
- name: replica_sets_jscore_passthrough
commands:
- command: manifest.load
- func: "git get project and add git tag"
- func: "get and apply version expansions"
- func: "f_expansions_write"
- func: "kill processes"
- func: "cleanup environment"
- func: "set up venv"
- func: "fetch packages"
- func: "generate compile expansions"
- func: "apply compile expansions"
- func: "set up remote credentials"
vars:
aws_key_remote: ${repo_aws_key}
aws_secret_remote: ${repo_aws_secret}
- func: "set up notary client credentials"
- *f_expansions_write
- command: subprocess.exec
params:
binary: bash
args:
- "./src/evergreen/packages_publish_test.sh"
- name: push
run_on: rhel80-small
tags: ["publish"]

View File

@ -88,17 +88,6 @@ buildvariants:
- name: generate_buildid_to_debug_symbols_mapping
- name: .integration !.audit
- <<: *generic_linux_compile_params
name: &linux-x86-dynamic-debug-wtdevelop-compile linux-x86-dynamic-debug-wtdevelop-compile
display_name: "~ Linux WiredTiger develop DEBUG Compile"
activate: false
modules:
- wtdevelop
expansions:
<<: *linux_debug_compile_expansions
use_wt_develop: true
compile_variant: *linux-x86-dynamic-debug-wtdevelop-compile
- <<: *generic_linux_compile_params
name: &linux-debug-aubsan-compile-required linux-debug-aubsan-compile-required
display_name: "! Linux x86 Shared Library {A,UB}SAN Compile"

View File

@ -177,7 +177,6 @@ buildvariants:
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-amazon2
@ -244,7 +243,6 @@ buildvariants:
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: amazon2-arm64
@ -298,7 +296,6 @@ buildvariants:
distros:
- ubuntu1804-arm64-build
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-amazon2-arm64
@ -427,7 +424,6 @@ buildvariants:
distros:
- ubuntu1804-arm64-build
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: amazon2022-arm64
@ -477,7 +473,6 @@ buildvariants:
distros:
- ubuntu2204-arm64-large
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-amazon2022-arm64
@ -590,8 +585,6 @@ buildvariants:
distros:
- amazon2022-arm64-large
- name: .publish_crypt
distros:
- amazon2022-arm64-large
- name: secondary_reads_passthrough_gen
- name: server_discovery_and_monitoring_json_test_TG
- name: .serverless
@ -604,7 +597,6 @@ buildvariants:
distros:
- ubuntu2204-arm64-large
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: debian10
@ -660,7 +652,6 @@ buildvariants:
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-debian10-64
@ -724,7 +715,6 @@ buildvariants:
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: debian11
@ -780,7 +770,6 @@ buildvariants:
distros:
- ubuntu2204-large
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-debian11-64
@ -842,7 +831,6 @@ buildvariants:
distros:
- ubuntu2204-large
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: rhel70
@ -898,7 +886,6 @@ buildvariants:
- ubuntu2004-package
- name: selinux_rhel7_org
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
# This variant compiles on RHEL 7.0 and runs tests on RHEL 7.6
@ -999,7 +986,6 @@ buildvariants:
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-rhel-80-64-bit
@ -1125,7 +1111,6 @@ buildvariants:
- ubuntu2004-package
- name: selinux_rhel8_enterprise
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: rhel-82-arm64
@ -1177,7 +1162,6 @@ buildvariants:
distros:
- ubuntu1804-arm64-build
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-rhel-82-arm64
@ -1246,7 +1230,6 @@ buildvariants:
distros:
- ubuntu1804-arm64-build
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: rhel90
@ -1298,7 +1281,6 @@ buildvariants:
- ubuntu2204-large
- name: selinux_rhel9_org
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-rhel-90-64-bit
@ -1375,7 +1357,6 @@ buildvariants:
- ubuntu2204-large
- name: selinux_rhel9_enterprise
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: suse12
@ -1433,7 +1414,6 @@ buildvariants:
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-suse12-64
@ -1485,12 +1465,13 @@ buildvariants:
- name: sharding_auth_gen
- name: .stitch
- name: .crypt
distros:
- suse12-sp5-large
- name: .publish_crypt
- name: test_packages
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-suse15-64
@ -1542,7 +1523,6 @@ buildvariants:
- name: .crypt
- name: .publish_crypt
- name: .publish
- name: .publish_test
- name: test_packages
distros:
- ubuntu2004-package
@ -1597,7 +1577,6 @@ buildvariants:
- name: .ssl
- name: .stitch
- name: .publish
- name: .publish_test
- name: test_packages
distros:
- ubuntu2004-package
@ -1664,7 +1643,6 @@ buildvariants:
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-ubuntu1804-64
@ -1747,7 +1725,6 @@ buildvariants:
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-ubuntu1804-arm64
@ -1813,7 +1790,6 @@ buildvariants:
distros:
- ubuntu1804-arm64-build
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: ubuntu1804-arm64
@ -1853,7 +1829,6 @@ buildvariants:
distros:
- ubuntu1804-arm64-build
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: ubuntu2204
@ -1909,7 +1884,6 @@ buildvariants:
distros:
- ubuntu2204-large
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: ubuntu2004
@ -1965,7 +1939,6 @@ buildvariants:
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-ubuntu2004-64
@ -2031,7 +2004,6 @@ buildvariants:
distros:
- ubuntu2004-package
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-ubuntu2204-64
@ -2097,11 +2069,7 @@ buildvariants:
- name: test_packages
distros:
- ubuntu2204-large
- name: test_packages_complete
distros:
- ubuntu2204-large
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: enterprise-ubuntu2004-arm64
@ -2163,7 +2131,6 @@ buildvariants:
distros:
- ubuntu1804-arm64-build
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: ubuntu2004-arm64
@ -2201,7 +2168,6 @@ buildvariants:
distros:
- ubuntu1804-arm64-build
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
@ -2217,7 +2183,7 @@ buildvariants:
push_path: linux
push_bucket: downloads.10gen.com
push_name: linux
push_arch: arm64-enterprise-ubuntu2204
push_arch: aarch64-enterprise-ubuntu2204
compile_flags: --ssl MONGO_DISTMOD=ubuntu2204 -j$(grep -c ^processor /proc/cpuinfo) --variables-files=etc/scons/mongodbtoolchain_v3_gcc.vars
crypt_task_compile_flags: SHLINKFLAGS_EXTRA="-Wl,-Bsymbolic -Wl,--no-gnu-unique" CCFLAGS="-fno-gnu-unique"
resmoke_jobs_max: 4 # Avoid starting too many mongod's on ARM test servers
@ -2256,11 +2222,7 @@ buildvariants:
- name: test_packages
distros:
- ubuntu2204-arm64-large
- name: test_packages_complete
distros:
- ubuntu2204-arm64-large
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: ubuntu2204-arm64
@ -2272,7 +2234,7 @@ buildvariants:
push_path: linux
push_bucket: downloads.mongodb.org
push_name: linux
push_arch: arm64-ubuntu2204
push_arch: aarch64-ubuntu2204
compile_flags: --ssl MONGO_DISTMOD=ubuntu2204 -j$(grep -c ^processor /proc/cpuinfo) --variables-files=etc/scons/mongodbtoolchain_v3_gcc.vars
resmoke_jobs_max: 8 # Avoid starting too many mongod's on ARM test servers
has_packages: true
@ -2294,7 +2256,6 @@ buildvariants:
distros:
- ubuntu2204-arm64-large
- name: .publish
- name: .publish_test
- name: generate_buildid_to_debug_symbols_mapping
- name: windows

View File

@ -1,882 +0,0 @@
command_type: system
stepback: false
## Parameters for parameterized builds (see https://github.com/evergreen-ci/evergreen/wiki/Parameterized-Builds)
parameters:
- key: patch_compile_flags
description: "Additional SCons flags to be applied during scons compile invocations in this patch"
variables:
###
# Leave this section uncommented to enable compile.
_real_remote_file: &_remote_file
${project_dir}/${version_id}/${revision}/${platform}/mongodb${compile-variant|}-${version_id}.tar.gz
_real_compile: &_compile
- variant: linux-wt-standalone
name: compile
_real_expansions: &_expansion_updates
[]
###
###
# **Or**: Leave this section uncommented to bypass/skip compile.
# This file ↓ came from a microbenchmarks waterfall run.
# https://evergreen.mongodb.com/version/performance_c0a8cbe58cc46253a94130d2cb64cdd8089b3551
# Artifacts eventually expire. If this fails, grab the compile artifacts url and update this.
# _skip_remote_file: &_remote_file
# /perf/performance_c0a8cbe58cc46253a94130d2cb64cdd8089b3551/c0a8cbe58cc46253a94130d2cb64cdd8089b3551/linux/mongodb-performance_c0a8cbe58cc46253a94130d2cb64cdd8089b3551.tar.gz
# _skip_compile: &_compile
# []
# _skip_expansions: &_expansion_updates
# - key: mdb_binary_for_server
# value: https://mciuploads.s3.amazonaws.com/perf/performance_c0a8cbe58cc46253a94130d2cb64cdd8089b3551/c0a8cbe58cc46253a94130d2cb64cdd8089b3551/linux/mongodb-performance_c0a8cbe58cc46253a94130d2cb64cdd8089b3551.tar.gz
# - key: mdb_binary_for_client
# value: https://mciuploads.s3.amazonaws.com/perf/performance_c0a8cbe58cc46253a94130d2cb64cdd8089b3551/c0a8cbe58cc46253a94130d2cb64cdd8089b3551/linux/mongodb-performance_c0a8cbe58cc46253a94130d2cb64cdd8089b3551.tar.gz
###
_src_dir: &src_dir src/mongo
_modules: &modules
- enterprise
- mongo-tools
- dsi
- genny
- workloads
- linkbench
- linkbench2
- mongo-perf
- YCSB
- benchmarks
- py-tpcc
modules:
###
# Same in every DSI project. Ensure that this block is synchronized with
# evergreen-dsitest.yml, atlas/system_perf_atlas.yml, and src/dsi/onboarding.py
# (search update-repos-here) in this repo, and etc/system_perf.yml and
# etc/perf.yml in mongodb/mongo
- name: dsi
repo: git@github.com:10gen/dsi.git
prefix: ${workdir}/src
branch: master
- name: genny
repo: git@github.com:10gen/genny.git
prefix: ${workdir}/src
branch: microbenchmarks-stable
- name: workloads
repo: git@github.com:10gen/workloads.git
prefix: ${workdir}/src
branch: master
- name: linkbench
repo: git@github.com:10gen/linkbench.git
prefix: ${workdir}/src
branch: master
- name: linkbench2
repo: git@github.com:10gen/linkbench2.git
prefix: ${workdir}/src
branch: master
- name: mongo-perf
repo: git@github.com:mongodb/mongo-perf.git
prefix: ${workdir}/src
branch: master
- name: YCSB
repo: git@github.com:mongodb-labs/YCSB.git
prefix: ${workdir}/src
branch: production
- name: benchmarks
repo: git@github.com:mongodb-labs/benchmarks.git
prefix: ${workdir}/src
branch: master
- name: py-tpcc
repo: git@github.com:mongodb-labs/py-tpcc.git
prefix: ${workdir}/src
branch: production
###
# - name: mongo
# repo: git@github.com:mongodb/mongo.git
# prefix: ${workdir}/src
# branch: master
- name: enterprise
repo: git@github.com:10gen/mongo-enterprise-modules.git
prefix: src/mongo/db/modules
branch: master
- name: mongo-tools
repo: git@github.com:mongodb/mongo-tools.git
prefix: mongo-tools/src/github.com/mongodb
branch: master
###
# Same in every DSI project
pre:
- func: f_other_pre_ops
- func: f_dsi_pre_run
post:
- func: f_dsi_post_run
- func: f_other_post_ops
timeout:
- func: f_dsi_timeout
- func: f_other_timeout
###
functions:
###
# Same in every DSI project
f_dsi_pre_run:
- command: manifest.load
- command: expansions.update
params:
updates: *_expansion_updates
f_run_dsi_workload:
- command: git.get_project
params:
directory: *src_dir
revisions:
dsi: ${dsi_rev}
genny: ${genny_rev}
linkbench: ${linkbench_rev}
linkbench2: ${linkbench2_rev}
workloads: ${workloads_rev}
mongo-perf: ${mongo-perf_rev}
YCSB: ${YCSB_rev}
benchmarks: ${benchmarks_rev}
py-tpcc: ${py-tpcc_rev}
- command: expansions.write
params:
file: ./expansions.yml
- command: shell.exec
params:
script: ./src/dsi/run-dsi run_workload
- command: shell.exec
type: system
params:
script: ./src/dsi/run-dsi determine_failure -m SYSTEM
- command: shell.exec
type: setup
params:
script: ./src/dsi/run-dsi determine_failure -m SETUP
- command: shell.exec
type: test
params:
script: ./src/dsi/run-dsi determine_failure -m TEST
f_dsi_post_run:
- command: shell.exec
params:
script: ./src/dsi/run-dsi post_run
- command: perf.send
params:
file: ./build/CedarReports/cedar_report.json
aws_key: ${terraform_key}
aws_secret: ${terraform_secret}
bucket: genny-metrics
region: us-east-1
prefix: ${task_id}_${execution}
- command: attach.results
params:
file_location: ./build/EvergreenResultsJson/results.json
- command: s3.put
params:
aws_key: ${aws_key}
aws_secret: ${aws_secret}
local_file: ./build/Artifacts/DSIArtifacts.tgz
remote_file: ${project_dir}/${build_variant}/${revision}/${task_id}/${version_id}/logs/dsi-artifacts-${task_name}-${build_id}-${execution}.tgz
bucket: mciuploads
permissions: public-read
content_type: application/x-gzip
display_name: DSI Artifacts - Execution ${execution}
- command: s3.put
params:
aws_key: ${aws_key}
aws_secret: ${aws_secret}
local_file: ./build/Documentation/index.html
remote_file: ${project_dir}/${build_variant}/${revision}/${task_id}/${version_id}/logs/${task_name}-${build_id}-index.html
bucket: mciuploads
permissions: public-read
content_type: text/html
display_name: Documentation
f_dsi_timeout:
- command: shell.exec
params:
script: ./src/dsi/run-dsi on_timeout
###
f_other_post_ops:
- command: shell.exec
params:
working_dir: src
script: |
# removes files from the (local) scons cache when it's over a
# threshold, to the $prune_ratio percentage. Ideally override
# these default values in the distro config in evergreen.
if [ -d "${scons_cache_path}" ]; then
/opt/mongodbtoolchain/v3/bin/python3 buildscripts/scons_cache_prune.py --cache-dir ${scons_cache_path} --cache-size ${scons_cache_size|200} --prune-ratio ${scons_prune_ratio|0.8}
fi
f_other_pre_ops:
- &f_other_pre_ops
command: shell.exec
params:
silent: true
script: |
for PS in mongo{,d,s,import,export,dump,restore,stat,files,top,bridge} resmoke.py python{,2} lldb _test; do
pkill -9 "$PS"
done
f_other_timeout:
# Can't be empty so just `echo`.
- command: shell.exec
params: {script: "echo"}
###
# Compile
compile mongodb:
# We create a virtual environment with the Python dependencies for compiling the server
# installed.
- command: shell.exec
params:
working_dir: src
script: |
set -o errexit
set -o verbose
mkdir -p mongodb/bin
/opt/mongodbtoolchain/v3/bin/virtualenv --python /opt/mongodbtoolchain/v3/bin/python3 "${workdir}/compile_venv"
source "${workdir}/compile_venv/bin/activate"
python -m pip install -r etc/pip/compile-requirements.txt
- command: expansions.write
params:
file: expansions.yml
redacted: true
- command: shell.exec
params:
working_dir: src
script: |
set -o errexit
set -o verbose
source "${workdir}/compile_venv/bin/activate"
# We get the raw version string (r1.2.3-45-gabcdef) from git
export MONGO_VERSION=$(git describe --abbrev=7)
# If this is a patch build, we add the patch version id to the version string so we know
# this build was a patch, and which evergreen task it came from
if [ "${is_patch|false}" = "true" ]; then
MONGO_VERSION="$MONGO_VERSION-patch-${version_id}"
fi
# This script handles sanitizing the version string for use during SCons build
# and when pushing artifacts up to S3.
IS_PATCH=${is_patch|false} IS_COMMIT_QUEUE=${is_commit_queue|false} \
buildscripts/generate_version_expansions.py --out version_expansions.yml
- command: expansions.update
params:
file: src/version_expansions.yml
- command: shell.exec
params:
working_dir: src
script: |
set -o errexit
set -o verbose
# This script handles whether the SCons cache should be used
source "${workdir}/compile_venv/bin/activate"
SCONS_CACHE_MODE=${scons_cache_mode|} USE_SCONS_CACHE=${use_scons_cache|false} \
IS_PATCH=${is_patch|false} IS_COMMIT_QUEUE=${is_commit_queue|false} \
python buildscripts/generate_compile_expansions.py --out compile_expansions.yml
- command: expansions.update
params:
file: src/compile_expansions.yml
- command: shell.exec
params:
working_dir: src/mongo-tools/src/github.com/mongodb/mongo-tools
script: |
set -o verbose
set -o errexit
# make sure newlines in the scripts are handled correctly by windows
if [ "Windows_NT" = "$OS" ]; then
set -o igncr
fi;
# set_goenv provides set_goenv(), print_ldflags() and print_tags() used below
. ./set_goenv.sh
GOROOT="" set_goenv || exit
go version
build_tools="bsondump mongostat mongofiles mongoexport mongoimport mongorestore mongodump mongotop"
if [ "${build_mongoreplay}" = "true" ]; then
build_tools="$build_tools mongoreplay"
fi
for i in $build_tools; do
go build -ldflags "$(print_ldflags)" ${args} -tags "$(print_tags ${tooltags})" -o "../../../../../mongodb/bin/$i${exe|}" $i/main/$i.go
"../../../../../mongodb/bin/$i${exe|}" --version
done
- command: shell.exec
params:
working_dir: src
script: |
set -o errexit
set -o verbose
source "${workdir}/compile_venv/bin/activate"
python ./buildscripts/idl/gen_all_feature_flag_list.py --import-dir src --import-dir src/mongo/db/modules/enterprise/src
mkdir -p mongodb/feature_flags
cp ./all_feature_flags.txt mongodb/feature_flags
- command: shell.exec
params:
working_dir: src
script: |
set -o errexit
set -o verbose
source "${workdir}/compile_venv/bin/activate"
python ./buildscripts/scons.py ${compile_flags|} ${scons_cache_args|} $extra_args install-core install-jstestshell SPLIT_DWARF=0 MONGO_VERSION=${version} DESTDIR=$(pwd)/mongodb ${patch_compile_flags|}
mkdir -p mongodb/jstests/hooks
if [ -d jstests/hooks ]
then
echo "Fetching JS test DB correctness checks from directory jstests"
cp -a jstests/* mongodb/jstests
echo "Now adding our own special run_validate_collections.js wrapper"
mv mongodb/jstests/hooks/run_validate_collections.js mongodb/jstests/hooks/run_validate_collections.actual.js
cat << EOF > mongodb/jstests/hooks/run_validate_collections.js
print("NOTE: run_validate_collections.js will skip the oplog!");
TestData = { skipValidationNamespaces: ['local.oplog.rs'] };
load('jstests/hooks/run_validate_collections.actual.js');
EOF
fi
tar czf mongodb${compile-variant|}.tar.gz mongodb
- command: s3.put
params:
aws_key: ${aws_key}
aws_secret: ${aws_secret}
local_file: src/mongodb${compile-variant|}.tar.gz
remote_file: ${project_dir}/${version_id}/${revision}/${platform}/mongodb${compile-variant|}-${version_id}.tar.gz
bucket: mciuploads
permissions: public-read
content_type: ${content_type|application/x-gzip}
display_name: mongodb${compile-variant|}.tar.gz
###
## Schedule Tasks ##
f_schedule_tasks:
- command: git.get_project
params:
directory: *src_dir
revisions:
dsi: ${dsi_rev}
genny: ${genny_rev}
linkbench: ${linkbench_rev}
linkbench2: ${linkbench2_rev}
workloads: ${workloads_rev}
mongo-perf: ${mongo-perf_rev}
YCSB: ${YCSB_rev}
benchmarks: ${benchmarks_rev}
py-tpcc: ${py-tpcc_rev}
- command: expansions.write
params:
file: ./expansions.yml
- command: shell.exec
params:
script: ./src/dsi/run-dsi schedule_tasks --tasks=${tasks}
- command: generate.tasks
params:
files:
- build/TaskJSON/Tasks.json
tasks:
###
# Same in every DSI project
- name: schedule_global_auto_tasks
priority: 5
commands:
- func: f_schedule_tasks
vars:
tasks: all_tasks
- name: schedule_variant_auto_tasks
priority: 5
commands:
- func: f_schedule_tasks
vars:
tasks: variant_tasks
- name: schedule_patch_auto_tasks
priority: 5
commands:
- func: f_schedule_tasks
vars:
tasks: patch_tasks
- name: smoke_test
priority: 5
commands:
- func: f_run_dsi_workload
vars:
test_control: short
- name: smoke_test_ssl
priority: 5
commands:
- func: f_run_dsi_workload
vars:
test_control: short
mongodb_setup: replica-ssl
infrastructure_provisioning: replica
- name: smoke_test_standalone_auth
priority: 5
commands:
- func: f_run_dsi_workload
vars:
test_control: short
mongodb_setup: standalone-auth
infrastructure_provisioning: single
- name: smoke_test_replset_auth
priority: 5
commands:
- func: f_run_dsi_workload
vars:
test_control: short
mongodb_setup: replica-auth
infrastructure_provisioning: replica
- name: smoke_test_shard_lite_auth
priority: 5
commands:
- func: f_run_dsi_workload
vars:
test_control: short
mongodb_setup: shard-lite-auth
infrastructure_provisioning: shard-lite
- name: dsi_integ_test_run_command_simple
priority: 5
commands:
- func: f_run_dsi_workload
vars:
test_control: run_command_simple
###
- name: compile
commands:
- command: manifest.load
- command: git.get_project
params:
directory: src
revisions:
enterprise: ${enterprise_rev}
mongo-tools: ${mongo-tools_rev}
- func: "compile mongodb"
- name: genny_execution_UserAcquisition
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: auto_genny_workload
auto_workload_path: ./src/genny/dist/etc/genny/workloads/execution/UserAcquisition.yml
- name: genny_scale_InsertRemove
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: auto_genny_workload
auto_workload_path: ./src/genny/dist/etc/genny/workloads/scale/InsertRemove.yml
- name: query_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: query,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: query_read_commands_large_dataset
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: query_large_dataset,
include_filter_2: regression,
exclude_filter: none,
threads: "1 4",
read_cmd: 'true',
share_dataset: 'true'}
- name: big_collection
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: query,
include_filter_2: getmore,
exclude_filter: none,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: views-query
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: query_identityview,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: views-aggregation
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: aggregation_identityview,
include_filter_2: regression,
exclude_filter: none,
threads: "1",
read_cmd: 'true'}
- name: where_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: where,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: update_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: update,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: insert_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: insert,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: wildcard-index-read_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: wildcard_read,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: wildcard-index-write_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: wildcard_write,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: geo_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: geo,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: misc_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: command multi remove mixed,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: misc_custom_filter_default_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
mongodb_setup: microbenchmarks_standalone_custom_filter_default
test_control_params: |
{include_filter_1: command multi remove mixed,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: misc_custom_filter_slow_or_sample_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
mongodb_setup: microbenchmarks_standalone_custom_filter_slow_or_sample
test_control_params: |
{include_filter_1: command multi remove mixed,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: misc_custom_filter_complex_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
mongodb_setup: microbenchmarks_standalone_custom_filter_complex
test_control_params: |
{include_filter_1: command multi remove mixed,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: misc_custom_filter_whole_doc_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
mongodb_setup: microbenchmarks_standalone_custom_filter_whole_doc
test_control_params: |
{include_filter_1: command multi remove mixed,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: misc_slowms_everything_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
mongodb_setup: microbenchmarks_standalone_slowms_everything
test_control_params: |
{include_filter_1: command multi remove mixed,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: singleThreaded_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: single_threaded,
include_filter_2: core regression,
exclude_filter: none,
threads: "1",
read_cmd: 'true'}
- name: aggregation_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: aggregation,
include_filter_2: regression,
exclude_filter: js,
threads: "1",
read_cmd: 'true'}
- name: aggregation_read_commands_large_dataset
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: aggregation_large_dataset,
include_filter_2: regression,
exclude_filter: js,
threads: "1 4",
read_cmd: 'true',
share_dataset: 'true'}
- name: agg-query-comparison_read_commands
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: agg_query_comparison,
include_filter_2: core regression,
exclude_filter: single_threaded,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: pipeline-updates
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: pipeline-updates,
include_filter_2: regression,
exclude_filter: none,
threads: "1 2 4 8",
read_cmd: 'true'}
- name: javascript
depends_on: *_compile
commands:
- func: f_run_dsi_workload
vars:
test_control: microbenchmarks
test_control_params: |
{include_filter_1: js,
include_filter_2: aggregation,
exclude_filter: none,
threads: "1 2 4 8",
read_cmd: 'true'}
microbenchmark-buildvariants:
_linux-wt-standalone: &linux-wt-standalone
name: linux-wt-standalone
display_name: Standalone Linux inMemory
cron: "0 */4 * * *" # Every 4 hours starting at midnight
modules: *modules
expansions:
# We are explicitly tracking the rhel62 variant compile options from evergreen.yml for
# microbenchmarks, since they run on the centos6 boxes. If we can get proper artifacts directly
# from that project, we should do that and remove the compile tasks.
compile_flags: >-
--ssl
--separate-debug MONGO_DISTMOD=rhel62
-j$(grep -c ^processor /proc/cpuinfo)
--release
--variables-files=etc/scons/mongodbtoolchain_v3_gcc.vars
mongod_exec_wrapper: &exec_wrapper "numactl --physcpubind=4,5,6,7 -i 1"
perf_exec_wrapper: &perf_wrapper "numactl --physcpubind=1,2,3 -i 0"
use_scons_cache: true
platform: linux
infrastructure_provisioning: microbenchmarks
mongodb_setup: microbenchmarks_standalone
canaries: none
storageEngine: inMemory
project_dir: &project_dir perf
run_on:
- "centos6-perf"
tasks:
- name: compile
distros:
- rhel62-large
- name: big_collection
- name: genny_scale_InsertRemove
- name: genny_execution_UserAcquisition
- name: aggregation_read_commands
- name: aggregation_read_commands_large_dataset
- name: agg-query-comparison_read_commands
- name: query_read_commands
- name: query_read_commands_large_dataset
- name: views-aggregation
- name: views-query
- name: where_read_commands
- name: update_read_commands
- name: insert_read_commands
- name: wildcard-index-read_read_commands
- name: wildcard-index-write_read_commands
- name: geo_read_commands
- name: misc_read_commands
- name: misc_custom_filter_default_read_commands
- name: misc_custom_filter_slow_or_sample_read_commands
- name: misc_custom_filter_complex_read_commands
- name: misc_custom_filter_whole_doc_read_commands
- name: misc_slowms_everything_read_commands
- name: singleThreaded_read_commands
- name: pipeline-updates
- name: javascript
_linux-wt-repl: &linux-wt-repl
name: linux-wt-repl
display_name: 1-Node ReplSet Linux inMemory
cron: "0 */4 * * *" # Every 4 hours starting at midnight
modules: *modules
expansions:
mongod_exec_wrapper: *exec_wrapper
perf_exec_wrapper: *perf_wrapper
platform: linux
infrastructure_provisioning: microbenchmarks
mongodb_setup: microbenchmarks_replica
canaries: none
storageEngine: inMemory
project_dir: *project_dir
run_on:
- "centos6-perf"
tasks:
- name: genny_scale_InsertRemove
- name: update_read_commands
- name: insert_read_commands
- name: misc_read_commands
- name: singleThreaded_read_commands
- name: wildcard-index-write_read_commands
- name: pipeline-updates
buildvariants:
- *linux-wt-standalone
- *linux-wt-repl
- <<: *linux-wt-standalone
name: linux-wt-standalone-all-feature-flags
display_name: Standalone Linux inMemory (all feature flags)
cron: "0 0 * * *" # Every day starting at 00:00
expansions:
mongodb_setup: microbenchmarks_standalone-all-feature-flags
- <<: *linux-wt-standalone
name: linux-wt-standalone-classic-query-engine
display_name: Standalone Linux inMemory (Classic Query Engine)
# Will make it less frequent when the current SBE perf improvement is finished (SERVER-69799).
cron: "0 0 * * 0,2,3,4,5" # Run it every day except Saturday and Monday.
expansions:
mongodb_setup: microbenchmarks_standalone-classic-query-engine
- <<: *linux-wt-standalone
name: linux-wt-standalone-sbe
display_name: Standalone Linux inMemory (SBE)
# Will make it less frequent when the current SBE perf improvement is finished (SERVER-69799).
cron: "0 0 * * 0,2,3,4,5" # Run it every day except Saturday and Monday.
expansions:
mongodb_setup: microbenchmarks_standalone-sbe
- <<: *linux-wt-repl
name: linux-wt-repl-all-feature-flags
display_name: 1-Node ReplSet Linux inMemory (all feature flags)
cron: "0 0 * * *" # Every day starting at 00:00
expansions:
mongodb_setup: microbenchmarks_replica-all-feature-flags

View File

@ -1,532 +0,0 @@
templates:
deb:
org: |
Origin: mongodb
Label: mongodb
Suite: {{ .CodeName }}
Codename: {{ .CodeName }}/mongodb-org
Architectures: {{ .Architectures }}
Components: {{ .Component }}
Description: MongoDB packages
enterprise: |
Origin: mongodb
Label: mongodb
Suite: {{ .CodeName }}
Codename: {{ .CodeName }}/mongodb-enterprise
Architectures: {{ .Architectures }}
Components: {{ .Component }}
Description: MongoDB packages
index_page: |
<!DOCTYPE html>
<html>
<head>
<title>{{ .Title }}</title>
</head>
<body>
<table>
<tr><td>
<h1>{{ .Title }}</h1>
</td></tr>
<tr><td>
<hr>
</td></tr>
<tr><td>
<a href='..'>Parent Directory</a>
</td></tr>
{{ range $fn := .Files }}
<tr><td>
<a href='{{ $fn }}'>{{ $fn }}</a>
</td></tr>
{{ end }}
<tr><td>
<hr>
</td></tr>
<tr><td>
<address>{{ .RepoName }}</address>
</td></tr>
</table>
</body>
</html>
repos:
####################
#
# Community Repos:
#
####################
- name: rhel70
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- yum/redhat/7/mongodb-org
- yum/redhat/7Server/mongodb-org
- name: rhel72
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- yum/redhat/7/mongodb-org
- yum/redhat/7Server/mongodb-org
- name: rhel80
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- yum/redhat/8/mongodb-org
- yum/redhat/8Server/mongodb-org
- name: rhel82
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- yum/redhat/8/mongodb-org
- yum/redhat/8Server/mongodb-org
- name: rhel83
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- yum/redhat/8/mongodb-org
- yum/redhat/8Server/mongodb-org
- name: rhel90
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- yum/redhat/9/mongodb-org
- yum/redhat/9Server/mongodb-org
- name: amazon
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- yum/amazon/2013.03/mongodb-org
- name: amazon2
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- yum/amazon/2/mongodb-org
- name: amazon2022
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- yum/amazon/2022/mongodb-org
- name: suse11
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- zypper/suse/11/mongodb-org
- name: suse12
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- zypper/suse/12/mongodb-org
- name: suse15
type: rpm
edition: org
bucket: test.repo.mongodb.org
repos:
- zypper/suse/15/mongodb-org
- name: debian81
type: deb
code_name: "jessie"
bucket: test.repo.mongodb.org
edition: org
component: main
architectures:
- amd64
- i386
repos:
- apt/debian/dists/jessie/mongodb-org
- name: debian92
type: deb
code_name: "stretch"
bucket: test.repo.mongodb.org
edition: org
component: main
architectures:
- amd64
repos:
- apt/debian/dists/stretch/mongodb-org
- name: debian10
type: deb
code_name: "buster"
bucket: test.repo.mongodb.org
edition: org
component: main
architectures:
- amd64
repos:
- apt/debian/dists/buster/mongodb-org
- name: debian11
type: deb
code_name: "bullseye"
bucket: test.repo.mongodb.org
edition: org
component: main
architectures:
- amd64
repos:
- apt/debian/dists/bullseye/mongodb-org
- name: debian71
type: deb
code_name: "wheezy"
bucket: test.repo.mongodb.org
edition: org
component: main
architectures:
- amd64
- i386
repos:
- apt/debian/dists/wheezy/mongodb-org
- name: ubuntu1204
type: deb
code_name: "precise"
edition: org
bucket: test.repo.mongodb.org
component: multiverse
architectures:
- amd64
- i386
repos:
- apt/ubuntu/dists/precise/mongodb-org
- name: ubuntu1404
type: deb
code_name: "trusty"
edition: org
bucket: test.repo.mongodb.org
component: multiverse
architectures:
- amd64
- i386
repos:
- apt/ubuntu/dists/trusty/mongodb-org
- name: ubuntu1804
type: deb
code_name: "bionic"
edition: org
bucket: test.repo.mongodb.org
component: multiverse
architectures:
- amd64
- i386
- s390x
- arm64
repos:
- apt/ubuntu/dists/bionic/mongodb-org
- name: ubuntu2004
type: deb
code_name: "focal"
edition: org
bucket: test.repo.mongodb.org
component: multiverse
architectures:
- amd64
- s390x
- arm64
repos:
- apt/ubuntu/dists/focal/mongodb-org
- name: ubuntu2204
type: deb
code_name: "jammy"
edition: org
bucket: test.repo.mongodb.org
component: multiverse
architectures:
- amd64
- arm64
repos:
- apt/ubuntu/dists/jammy/mongodb-org
####################
#
# Enterprise Repos:
#
####################
- name: rhel62
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/redhat/6/mongodb-enterprise
- yum/redhat/6Server/mongodb-enterprise
- name: rhel67
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/redhat/6/mongodb-enterprise
- yum/redhat/6Server/mongodb-enterprise
- name: rhel70
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/redhat/7/mongodb-enterprise
- yum/redhat/7Server/mongodb-enterprise
- name: rhel71
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/redhat/7/mongodb-enterprise
- yum/redhat/7Server/mongodb-enterprise
- name: rhel72
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/redhat/7/mongodb-enterprise
- yum/redhat/7Server/mongodb-enterprise
- name: rhel80
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/redhat/8/mongodb-enterprise
- yum/redhat/8Server/mongodb-enterprise
- name: rhel81
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/redhat/8/mongodb-enterprise
- yum/redhat/8Server/mongodb-enterprise
- name: rhel82
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/redhat/8/mongodb-enterprise
- yum/redhat/8Server/mongodb-enterprise
- name: rhel83
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/redhat/8/mongodb-enterprise
- yum/redhat/8Server/mongodb-enterprise
- name: rhel90
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/redhat/9/mongodb-enterprise
- yum/redhat/9Server/mongodb-enterprise
- name: amazon
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/amazon/2013.03/mongodb-enterprise
- name: amazon2
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/amazon/2/mongodb-enterprise
- name: amazon2022
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- yum/amazon/2022/mongodb-enterprise
- name: suse11
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- zypper/suse/11/mongodb-enterprise
- name: suse12
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- zypper/suse/12/mongodb-enterprise
- name: suse15
type: rpm
edition: enterprise
bucket: test.repo.mongodb.com
repos:
- zypper/suse/15/mongodb-enterprise
- name: debian10
type: deb
edition: enterprise
code_name: "buster"
bucket: test.repo.mongodb.com
component: main
architectures:
- amd64
repos:
- apt/debian/dists/buster/mongodb-enterprise
- name: debian11
type: deb
edition: enterprise
code_name: "bullseye"
bucket: test.repo.mongodb.com
component: main
architectures:
- amd64
repos:
- apt/debian/dists/bullseye/mongodb-enterprise
- name: debian92
type: deb
edition: enterprise
code_name: "stretch"
bucket: test.repo.mongodb.com
component: main
architectures:
- amd64
repos:
- apt/debian/dists/stretch/mongodb-enterprise
- name: debian81
type: deb
edition: enterprise
code_name: "jessie"
bucket: test.repo.mongodb.com
component: main
architectures:
- amd64
- ppc64el
- s390x
- i386
repos:
- apt/debian/dists/jessie/mongodb-enterprise
- name: debian71
type: deb
code_name: "wheezy"
edition: enterprise
bucket: test.repo.mongodb.com
component: main
architectures:
- amd64
- ppc64el
- s390x
- i386
repos:
- apt/debian/dists/wheezy/mongodb-enterprise
- name: ubuntu1204
type: deb
code_name: "precise"
edition: enterprise
bucket: test.repo.mongodb.com
component: multiverse
architectures:
- amd64
- ppc64el
- s390x
- i386
repos:
- apt/ubuntu/dists/precise/mongodb-enterprise
- name: ubuntu1404
type: deb
code_name: "trusty"
edition: enterprise
bucket: test.repo.mongodb.com
component: multiverse
architectures:
- amd64
- ppc64el
- s390x
- i386
repos:
- apt/ubuntu/dists/trusty/mongodb-enterprise
- name: ubuntu1804
type: deb
code_name: "bionic"
edition: enterprise
bucket: test.repo.mongodb.com
component: multiverse
architectures:
- amd64
- ppc64el
- i386
- s390x
- arm64
repos:
- apt/ubuntu/dists/bionic/mongodb-enterprise
- name: ubuntu2004
type: deb
code_name: "focal"
edition: enterprise
bucket: test.repo.mongodb.com
component: multiverse
architectures:
- amd64
- ppc64el
- s390x
- arm64
repos:
- apt/ubuntu/dists/focal/mongodb-enterprise
- name: ubuntu2204
type: deb
code_name: "jammy"
edition: enterprise
bucket: test.repo.mongodb.com
component: multiverse
architectures:
- amd64
- arm64
repos:
- apt/ubuntu/dists/jammy/mongodb-enterprise

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@ enterprise_path="src/mongo/db/modules/enterprise"
diff_file_name="with_base_upstream.diff"
# get the list of feature flags from the patched version
$python buildscripts/idl/gen_all_feature_flag_list.py --import-dir src --import-dir "$enterprise_path"/src
$python buildscripts/idl/gen_all_feature_flag_list.py
mv all_feature_flags.txt patch_all_feature_flags.txt
# get the list of feature flags from the base commit
@ -29,7 +29,7 @@ if [ -s "$diff_file_name" ]; then
fi
popd
$python buildscripts/idl/gen_all_feature_flag_list.py --import-dir src --import-dir "$enterprise_path"/src
$python buildscripts/idl/gen_all_feature_flag_list.py
mv all_feature_flags.txt base_all_feature_flags.txt
# print out the list of tests that previously had feature flag tag, that was

View File

@ -6,4 +6,4 @@ cd src
set -o errexit
set -o verbose
activate_venv
$python buildscripts/idl/gen_all_feature_flag_list.py --import-dir src --import-dir src/mongo/db/modules/enterprise/src
$python buildscripts/idl/gen_all_feature_flag_list.py

View File

@ -13,4 +13,5 @@ PATH=$PATH:$HOME:/ ./mongo-task-generator \
--evg-auth-file ./.evergreen.yml \
--evg-project-file ${evergreen_config_file_path} \
--generate-sub-tasks-config etc/generate_subtasks_config.yml \
--s3-test-stats-endpoint https://mongo-test-stats.s3.amazonaws.com \
$@

View File

@ -13,5 +13,6 @@ PATH=$PATH:$HOME:/ ./mongo-task-generator \
--evg-auth-file ./.evergreen.yml \
--evg-project-file ${evergreen_config_file_path} \
--generate-sub-tasks-config etc/generate_subtasks_config.yml \
--s3-test-stats-endpoint https://mongo-test-stats.s3.amazonaws.com \
--burn-in \
$@

View File

@ -6,8 +6,6 @@ cd src/jstestfuzz
set -o errexit
set -o verbose
add_nodejs_to_path
if [ -f "../minimizer-outputs.json" ]; then
eval npm run ${npm_command} -- -j "../minimizer-outputs.json"
eval ./src/scripts/npm_run.sh ${npm_command} -- -j "../minimizer-outputs.json"
fi

View File

@ -1,13 +1,10 @@
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)"
. "$DIR/prelude.sh"
set -evo pipefail
cd src/jstestfuzz
set -o errexit
set -o verbose
add_nodejs_to_path
in_patch_build_flag=""
if [[ "${is_patch}" = "true" ]]; then
case "${npm_command}" in
@ -17,4 +14,4 @@ if [[ "${is_patch}" = "true" ]]; then
esac
fi
eval npm run "${npm_command}" -- "${jstestfuzz_vars}" "${in_patch_build_flag}" --branch "${branch_name}"
./src/scripts/npm_run.sh ${npm_command} -- ${jstestfuzz_vars} ${in_patch_build_flag} --branch ${branch_name}

View File

@ -6,11 +6,4 @@ cd src
set -o errexit
set -o verbose
add_nodejs_to_path
git clone git@github.com:10gen/jstestfuzz.git
pushd jstestfuzz
npm install
npm run prepare
popd

View File

@ -1,17 +1,22 @@
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)"
. "$DIR/prelude.sh"
cd src
cd src/jstestfuzz
set -o pipefail
set -o verbose
add_nodejs_to_path
# Run first with help which will do the install
# Then we can run it in parallel
./src/scripts/npm_run.sh --help
# Run parse-jsfiles on 50 files at a time with 32 processes in parallel.
find "$PWD/jstests" "$PWD/src/mongo/db/modules/enterprise" -name "*.js" -print | xargs -P 32 -L 50 npm run --prefix jstestfuzz parse-jsfiles -- | tee lint_fuzzer_sanity.log
# Skip javascript files in third_party directory
find "$PWD/../jstests" "$PWD/../src/mongo/db/modules/enterprise" -path "$PWD/../jstests/third_party" -prune -o -name "*.js" -print | xargs -P 32 -L 50 ./src/scripts/npm_run.sh parse-jsfiles -- | tee lint_fuzzer_sanity.log
exit_code=$?
# Exit out of the jstestfuzz directory
cd ..
activate_venv
$python ./buildscripts/simple_report.py --test-name lint_fuzzer_sanity_all --log-file lint_fuzzer_sanity.log --exit-code $exit_code
$python ./buildscripts/simple_report.py --test-name lint_fuzzer_sanity_all --log-file jstestfuzz/lint_fuzzer_sanity.log --exit-code $exit_code
exit $exit_code

View File

@ -7,15 +7,17 @@ set -o pipefail
set -o verbose
activate_venv
add_nodejs_to_path
mkdir -p jstestfuzzinput jstestfuzzoutput
indir="$(pwd)/jstestfuzzinput"
outdir="$(pwd)/jstestfuzzoutput"
# We need to be the jstestfuzz repo for node to install/run
cd jstestfuzz
indir="$(pwd)/../jstestfuzzinput"
outdir="$(pwd)/../jstestfuzzoutput"
# Grep all the js files from modified_and_created_patch_files.txt and put them into $indir.
(grep -v "\.tpl\.js$" modified_and_created_patch_files.txt | grep ".*jstests/.*\.js$" | xargs -I {} cp {} $indir || true)
(grep -v "\.tpl\.js$" ../modified_and_created_patch_files.txt | grep ".*jstests/.*\.js$" | xargs -I {} cp {} $indir || true)
# Count the number of files in $indir.
if [[ "$(ls -A $indir)" ]]; then
@ -26,10 +28,13 @@ if [[ "$(ls -A $indir)" ]]; then
num_files=50
fi
npm run --prefix jstestfuzz jstestfuzz -- --jsTestsDir $indir --out $outdir --numSourceFiles $num_files --numGeneratedFiles 50
./src/scripts/npm_run.sh jstestfuzz -- --jsTestsDir $indir --out $outdir --numSourceFiles $num_files --numGeneratedFiles 50
# Run parse-jsfiles on 50 files at a time with 32 processes in parallel.
ls -1 -d $outdir/* | xargs -P 32 -L 50 npm run --prefix jstestfuzz parse-jsfiles -- | tee lint_fuzzer_sanity.log
ls -1 -d $outdir/* | xargs -P 32 -L 50 ./src/scripts/npm_run.sh parse-jsfiles -- | tee lint_fuzzer_sanity.log
exit_code=$?
$python ./buildscripts/simple_report.py --test-name lint_fuzzer_sanity_patch --log-file lint_fuzzer_sanity.log --exit-code $exit_code
# Exit out of the jstestfuzz directory
cd ..
$python ./buildscripts/simple_report.py --test-name lint_fuzzer_sanity_patch --log-file jstestfuzz/lint_fuzzer_sanity.log --exit-code $exit_code
fi

View File

@ -1,14 +0,0 @@
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)"
. "$DIR/prelude.sh"
cd src
. ./notary_env.sh
set -o errexit
set -o verbose
CURATOR_RELEASE=${curator_release}
curl -L -O http://boxes.10gen.com/build/curator/curator-dist-rhel70-$CURATOR_RELEASE.tar.gz
tar -zxvf curator-dist-rhel70-$CURATOR_RELEASE.tar.gz
NOTARY_KEY_NAME=${signing_key_name_test} NOTARY_TOKEN=${signing_auth_token_test} BARQUE_API_KEY=${barque_api_key_test} BARQUE_USERNAME=${barque_user_test} ./curator repo submit --service ${barque_url_test} --config ./etc/repo_config_test.yaml --distro ${packager_distro} --edition ${repo_edition} --version ${version} --arch ${packager_arch} --packages https://s3.amazonaws.com/mciuploads/${project}/${build_variant}/${revision}/artifacts/${build_id}-packages.tgz

View File

@ -32,21 +32,6 @@ unset expansions_default_yaml
unset script
unset evergreen_dir
function add_nodejs_to_path {
# Add node and npm binaries to PATH
if [ "Windows_NT" = "$OS" ]; then
# An "npm" directory might not have been created in %APPDATA% by the Windows installer.
# Work around the issue by specifying a different %APPDATA% path.
# See: https://github.com/nodejs/node-v0.x-archive/issues/8141
export APPDATA=${workdir}/npm-app-data
export PATH="$PATH:/cygdrive/c/Program Files (x86)/nodejs" # Windows location
# TODO: this is to work around BUILD-8652
cd "$(pwd -P | sed 's,cygdrive/c/,cygdrive/z/,')"
else
export PATH="$PATH:/opt/node/bin"
fi
}
function posix_workdir {
if [ "Windows_NT" = "$OS" ]; then
echo $(cygpath -u "${workdir}")

View File

@ -1,6 +1,6 @@
function setup_mongo_task_generator {
if [ ! -f mongo-task-generator ]; then
curl -L https://github.com/mongodb/mongo-task-generator/releases/download/v0.6.6/mongo-task-generator --output mongo-task-generator
curl -L https://github.com/mongodb/mongo-task-generator/releases/download/v0.6.7/mongo-task-generator --output mongo-task-generator
chmod +x mongo-task-generator
fi
}

View File

@ -8,7 +8,7 @@ from pydantic import ValidationError
if __name__ == "__main__" and __package__ is None:
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from buildscripts.metrics.metrics_datatypes import ToolingMetrics
from buildscripts.metrics.metrics_datatypes import ResmokeToolingMetrics, SConsToolingMetrics
from buildscripts.metrics.tooling_metrics_utils import _get_internal_tooling_metrics_client
from evergreen.api import RetryingEvergreenApi
@ -20,43 +20,56 @@ except Exception as exc:
print("Could not connect to Atlas cluster")
raise exc
try:
# Get metrics for the last week
one_week_ago_datetime = datetime.datetime.utcnow() - datetime.timedelta(days=7)
last_week_metrics = client.metrics.tooling_metrics.find(
{"utc_starttime": {"$gt": one_week_ago_datetime}})
malformed_metrics = []
invalid_metrics = []
total_docs = 0
def get_metrics_data(source, MetricsClass, lookback=7):
try:
# Get SCons metrics for the lookback period
lookback_datetime = datetime.datetime.utcnow() - datetime.timedelta(days=lookback)
last_week_metrics = client.metrics.tooling_metrics.find({
"source": source,
"utc_starttime": {"$gt": lookback_datetime},
})
# Find any malformed/invalid documents in the cluster
for doc in last_week_metrics:
total_docs += 1
try:
metrics = ToolingMetrics(**doc)
if metrics.is_malformed():
malformed_metrics.append(doc['_id'])
except ValidationError:
invalid_metrics.append(doc['_id'])
malformed_metrics = []
invalid_metrics = []
total_docs = 0
metrics_detailed = ("METRICS DETAILED:\n"
f"malformed_metrics_last_week: {malformed_metrics}\n"
f"invalid_metrics_last_week: {invalid_metrics}\n"
f"total_docs_last_week: {total_docs}")
metrics_overview = (
"METRICS OVERVIEW:\n"
f"malformed_metrics_last_week: {len(malformed_metrics)} ({len(malformed_metrics)/total_docs*100:.2f}%)\n"
f"invalid_metrics_last_week: {len(invalid_metrics)} ({len(invalid_metrics)/total_docs*100:.2f}%)\n"
f"total_docs_last_week: {total_docs}")
# Find any malformed/invalid documents in the cluster
for doc in last_week_metrics:
total_docs += 1
try:
metrics = MetricsClass(**doc)
if metrics.is_malformed():
malformed_metrics.append(doc['_id'])
except ValidationError:
invalid_metrics.append(doc['_id'])
print(metrics_overview)
print(metrics_detailed)
metrics_detailed = (f"METRICS DETAILED ({source}):\n"
f"malformed_metrics_last_week: {malformed_metrics}\n"
f"invalid_metrics_last_week: {invalid_metrics}\n"
f"total_docs_last_week: {total_docs}\n")
metrics_overview = (
f"METRICS OVERVIEW ({source}):\n"
f"malformed_metrics_last_week: {len(malformed_metrics)} ({len(malformed_metrics)/total_docs*100:.2f}%)\n"
f"invalid_metrics_last_week: {len(invalid_metrics)} ({len(invalid_metrics)/total_docs*100:.2f}%)\n"
f"total_docs_last_week: {total_docs}\n")
# Publish metrics to SDP Slack Channel
evg_api = RetryingEvergreenApi.get_api(config_file="./.evergreen.yml")
evg_api.send_slack_message(target="#server-sdp-bfs", msg=metrics_overview)
print(metrics_overview)
print(metrics_detailed)
except Exception as exc:
print("Unexpected failure while getting metrics")
raise exc
return metrics_overview
except Exception as exc:
print("Unexpected failure while getting metrics")
raise exc
scons_metrics_overview = get_metrics_data("scons", SConsToolingMetrics)
resmoke_metrics_overview = get_metrics_data("resmoke", ResmokeToolingMetrics)
# Publish metrics to SDP Slack Channel
evg_api = RetryingEvergreenApi.get_api(config_file="./.evergreen.yml")
evg_api.send_slack_message(
target="#server-sdp-bfs",
msg=scons_metrics_overview + resmoke_metrics_overview,
)

View File

@ -9,7 +9,6 @@ set -o errexit
activate_venv
$python buildscripts/resmoke_tests_runtime_validate.py \
--resmoke-report-file ./report.json \
--evg-api-config ./.evergreen.yml \
--project-id ${project_id} \
--build-variant ${build_variant} \
--task-name ${task_name}

View File

@ -0,0 +1,30 @@
// Regression test for SERVER-71270.
(function() {
"use strict";
load('jstests/aggregation/extras/utils.js'); // For assertArrayEq.
const doc = {
_id: 0,
time: new Date('2019-01-18T13:24:15.443Z'),
tag: {},
};
db.ts.drop();
db.coll.drop();
db.createCollection('ts', {timeseries: {timeField: 'time', metaField: 'tag'}});
db.createCollection('coll');
db.ts.insertOne(doc);
db.coll.insertOne(doc);
const pipeline = [
{$project: {'time': 0}},
{$match: {'time': {$lte: new Date('2019-02-13T11:36:03.481Z')}}},
];
const ts = db.ts.aggregate(pipeline).toArray();
const vanilla = db.coll.aggregate(pipeline).toArray();
assertArrayEq({
actual: ts,
expected: vanilla,
});
}());

View File

@ -0,0 +1,77 @@
// Test that $setWindowFields inside $facet correctly propagates its state when it encounters paused
// execution.
(function() {
"use strict";
const coll = db.window_inside_facet;
coll.drop();
assert.commandWorked(coll.insert([
{_id: 'a', n: 0},
{_id: 'b', n: 1},
{_id: 'c', n: 2},
{_id: 'd', n: 3},
{_id: 'e', n: 4},
{_id: 'f', n: 5}
]));
// Test window with a sort within $facet alongside another pipeline that will cause it to pause
// execution. The sort will cause the window to hit paused execution immediately, before an advance.
let result =
coll.aggregate({
$facet: {
facet1: [{
$setWindowFields: {
output: {prevId: {$shift: {by: -1, default: null, output: "$_id"}}},
sortBy: {_id: 1}
}
}],
facet2: [{$count: "count"}]
}
})
.toArray()[0];
let expected = {
facet1: [
{_id: 'a', n: 0, prevId: null},
{_id: 'b', n: 1, prevId: 'a'},
{_id: 'c', n: 2, prevId: 'b'},
{_id: 'd', n: 3, prevId: 'c'},
{_id: 'e', n: 4, prevId: 'd'},
{_id: 'f', n: 5, prevId: 'e'}
],
facet2: [{count: 6}]
};
assert.docEq(expected, result, "$setWindowFields with sort failed.");
// Test window with no sort within $facet alongside another pipeline that will cause it to pause
// execution. Having no sort will cause the window to hit paused execution after advancing.
result = coll.aggregate({
$facet: {
facet1: [
{
$setWindowFields: {
output: {
min: {$min: "$n"},
max: {$max: "$n"},
}
}
},
{$sort: {_id: 1}}
],
facet2: [{$count: "count"}]
}
})
.toArray()[0];
expected = {
facet1: [
{_id: 'a', n: 0, min: 0, max: 5},
{_id: 'b', n: 1, min: 0, max: 5},
{_id: 'c', n: 2, min: 0, max: 5},
{_id: 'd', n: 3, min: 0, max: 5},
{_id: 'e', n: 4, min: 0, max: 5},
{_id: 'f', n: 5, min: 0, max: 5}
],
facet2: [{count: 6}]
};
assert.docEq(expected, result, "$setWindowFields without sort failed.");
}());

View File

@ -5893,6 +5893,26 @@ var authCommandsLib = {
{runOnDb: secondDbName, roles: {}}
]
},
{
testname: "setProfilingFilterGlobally",
command: {setProfilingFilterGlobally: 1, filter: {nreturned: 0}},
testcases: [
{
runOnDb: firstDbName,
roles: roles_dbAdminAny,
privileges: [{resource: {db: "", collection: ""}, actions: ["enableProfiler"]}],
expectFail:
true /* the command will fail because the query knob is not turned on */
},
{
runOnDb: firstDbName,
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["enableProfiler"]}
],
expectAuthzFailure: true
}
]
},
{
testname: "setParameter",
command: {setParameter: 1, quiet: 1},

View File

@ -34,7 +34,6 @@ load("jstests/libs/doc_validation_utils.js");
const dbName = 'bypass_document_validation';
const collName = 'bypass_document_validation';
const outputCollName = 'bypass_output_coll';
const myDb = db.getSiblingDB(dbName);
const coll = myDb[collName];
@ -65,6 +64,7 @@ function runBypassDocumentValidationTest(validator) {
}
// Test the aggregation command with a $out stage.
const outputCollName = 'bypass_output_coll';
const outputColl = myDb[outputCollName];
outputColl.drop();
assert.commandWorked(myDb.createCollection(outputCollName, {validator: validator}));
@ -199,8 +199,4 @@ runBypassDocumentValidationTest({a: {$exists: true}});
// Run the test again with an equivalent JSON Schema validator.
runBypassDocumentValidationTest({$jsonSchema: {required: ['a']}});
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(myDb.runCommand({collMod: collName, validationAction: "warn"}));
assert.commandWorked(myDb.runCommand({collMod: outputCollName, validationAction: "warn"}));
})();

View File

@ -24,7 +24,6 @@ load("jstests/libs/index_catalog_helpers.js");
load("jstests/concurrency/fsm_workload_helpers/server_types.js");
// For isReplSet
load("jstests/libs/fixture_helpers.js");
load("jstests/libs/sbe_explain_helpers.js"); // For engineSpecificAssertion.
// For areAllCollectionsClustered.
load("jstests/libs/clustered_collections/clustered_collection_util.js");
@ -755,9 +754,7 @@ if (!isClustered) {
assert.commandWorked(testDb.createCollection(coll.getName(), {collation: {locale: "en_US"}}));
explainRes = coll.explain("executionStats").find({_id: "foo"}).finish();
assert.commandWorked(explainRes);
let classicAssert = null !== getPlanStage(getWinningPlan(explainRes.queryPlanner), "IDHACK");
let sbeAssert = null !== getPlanStage(getWinningPlan(explainRes.queryPlanner), "IXSCAN");
engineSpecificAssertion(classicAssert, sbeAssert, testDb, explainRes);
assert.neq(null, getPlanStage(explainRes.executionStats.executionStages, "IDHACK"), explainRes);
// Find on _id should use idhack stage when explicitly given query collation matches
// collection default.

View File

@ -3,7 +3,7 @@
* @tags: [
* assumes_unsharded_collection,
* requires_non_retryable_writes,
* requires_fcv_60,
* requires_fcv_62,
* # This test could produce unexpected explain output if additional indexes are created.
* assumes_no_implicit_index_creation,
* # TODO SERVER-67506: Dotted path equality to null matches non-object array elements in CQF.

View File

@ -15,48 +15,41 @@ const encryptedBinDataElement = BinData(6, "AAAAAAAAAAAAAAAAAAAAAAAAAAAA");
const nonEncryptedBinDataElement = BinData(0, "AAAAAAAAAAAAAAAAAAAAAAAAAAAA");
// Only elements of type BinData with subtype '6' should match.
assertSchemaMatch(coll, {properties: {bin: {encrypt: {}}}}, {bin: encryptedBinDataElement}, true);
assertSchemaMatch(coll, {properties: {bin: {encrypt: {}}}}, {bin: {}}, false);
assertSchemaMatch(
coll, {properties: {bin: {encrypt: {}}}}, {bin: encryptedBinDataElement}, true, true);
assertSchemaMatch(coll, {properties: {bin: {encrypt: {}}}}, {bin: {}}, false, true);
assertSchemaMatch(
coll, {properties: {bin: {encrypt: {}}}}, {bin: nonEncryptedBinDataElement}, false, true);
coll, {properties: {bin: {encrypt: {}}}}, {bin: nonEncryptedBinDataElement}, false);
// Nested in object.
assertSchemaMatch(coll,
{properties: {obj: {type: 'object', properties: {a: {encrypt: {}}}}}},
{obj: {a: encryptedBinDataElement}},
true,
true);
assertSchemaMatch(coll,
{properties: {obj: {type: 'object', properties: {a: {encrypt: {}}}}}},
{obj: {a: {}}},
false,
true);
false);
assertSchemaMatch(coll,
{properties: {obj: {type: 'object', properties: {a: {encrypt: {}}}}}},
{obj: {a: nonEncryptedBinDataElement}},
false,
true);
false);
// Nested in array.
assertSchemaMatch(coll,
{properties: {arr: {type: 'array', items: {encrypt: {}}}}},
{arr: [encryptedBinDataElement, encryptedBinDataElement]},
true,
true);
assertSchemaMatch(
coll, {properties: {arr: {type: 'array', items: {encrypt: {}}}}}, {arr: [{}, {}]}, false, true);
coll, {properties: {arr: {type: 'array', items: {encrypt: {}}}}}, {arr: [{}, {}]}, false);
assertSchemaMatch(coll,
{properties: {arr: {type: 'array', items: {encrypt: {}}}}},
{arr: [encryptedBinDataElement, nonEncryptedBinDataElement]},
false,
true);
false);
// If array is not specified, should not traverse array of encrypted BinData's.
assertSchemaMatch(coll,
{properties: {bin: {encrypt: {}}}},
{bin: [encryptedBinDataElement, encryptedBinDataElement]},
false,
true);
false);
// Encrypt alongside type/bsontype should fail to parse.
assert.commandFailedWithCode(

View File

@ -25,19 +25,25 @@ function compareValues(v1, v2) {
}
// Check that 'expectedQuery' and 'actualQuery' have the same plans, and produce the same result.
function assertEquivPlanAndResult(expectedQuery, actualQuery) {
function assertEquivPlanAndResult(expectedQuery, actualQuery, supportWithCollation) {
const expectedExplain = coll.find(expectedQuery).explain("queryPlanner");
const actualExplain = coll.find(actualQuery).explain("queryPlanner");
// The queries must be rewritten into the same form.
assert.docEq(expectedExplain.parsedQuery, actualExplain.parsedQuery);
assert.docEq(expectedExplain.queryPlanner.parsedQuery, actualExplain.queryPlanner.parsedQuery);
// Check if the test queries produce the same plans with collations
const expectedExplainColln =
// We are always running these queries to ensure a server crash is not triggered.
// TODO SERVER-72450: Add appropriate assertions for the output.
const expectedExplainCollation =
coll.find(expectedQuery).sort({f1: 1}).collation({locale: 'en_US'}).explain("queryPlanner");
const actualExplainColln =
const actualExplainCollation =
coll.find(actualQuery).sort({f1: 1}).collation({locale: 'en_US'}).explain("queryPlanner");
assert.docEq(expectedExplainColln.parsedQuery, actualExplainColln.parsedQuery);
if (supportWithCollation) {
// Check if the test queries produce the same plans with collations.
assert.docEq(expectedExplainCollation.queryPlanner.parsedQuery,
actualExplainCollation.queryPlanner.parsedQuery);
}
// Make sure both queries have the same access plan.
const expectedPlan = getWinningPlan(expectedExplain.queryPlanner);
@ -51,12 +57,13 @@ function assertEquivPlanAndResult(expectedQuery, actualQuery) {
const actualRes = coll.find(actualQuery).toArray();
assert(arrayEq(expectedRes, actualRes, false, compareValues),
`expected=${expectedRes}, actual=${actualRes}`);
// also with collation
const expectedResColln =
const expectedResCollation =
coll.find(expectedQuery).sort({f1: 1}).collation({locale: 'en_US'}).toArray();
const actualResColln =
const actualResCollation =
coll.find(actualQuery).sort({f1: 1}).collation({locale: 'en_US'}).toArray();
assert(arrayEq(expectedResColln, actualResColln, false, compareValues),
assert(arrayEq(expectedResCollation, actualResCollation, false, compareValues),
`expected=${expectedRes}, actual=${actualRes}`);
}
@ -94,32 +101,71 @@ assert.commandWorked(coll.insert(data));
// Pairs of queries where the first one is expressed via OR (which is supposed to be
// rewritten as IN), and the second one is an equivalent query using IN.
//
// The third element of the array is optional, if present, implies that the rewrite is not
// supported when there is a collation involved.
//
// TODO SERVER-72450: Remove or update this logic related to collation, and enforce stronger
// assertions.
const positiveTestQueries = [
[{$or: [{f1: 5}, {f1: 3}, {f1: 7}]}, {f1: {$in: [7, 3, 5]}}],
[{$or: [{f1: {$eq: 5}}, {f1: {$eq: 3}}, {f1: {$eq: 7}}]}, {f1: {$in: [7, 3, 5]}}],
[{$or: [{f1: 42}, {f1: NaN}, {f1: 99}]}, {f1: {$in: [42, NaN, 99]}}],
[{$or: [{f1: /^x/}, {f1: "ab"}]}, {f1: {$in: [/^x/, "ab"]}}],
[{$or: [{f1: /^x/}, {f1: "^a"}]}, {f1: {$in: [/^x/, "^a"]}}],
[{$or: [{f1: 42}, {f1: null}, {f1: 99}]}, {f1: {$in: [42, 99, null]}}],
[{$or: [{f1: 1}, {f2: 9}, {f1: 99}]}, {$or: [{f2: 9}, {f1: {$in: [1, 99]}}]}],
[{$or: [{f1: {$regex: /^x/}}, {f1: {$regex: /ab/}}]}, {f1: {$in: [/^x/, /ab/]}}],
[
{$and: [{$or: [{f1: 7}, {f1: 3}, {f1: 5}]}, {$or: [{f1: 1}, {f1: 2}, {f1: 3}]}]},
{$and: [{f1: {$in: [7, 3, 5]}}, {f1: {$in: [1, 2, 3]}}]}
],
[
{$or: [{$or: [{f1: 7}, {f1: 3}, {f1: 5}]}, {$or: [{f1: 1}, {f1: 2}, {f1: 3}]}]},
{$or: [{f1: {$in: [7, 3, 5]}}, {f1: {$in: [1, 2, 3]}}]}
],
[
{$or: [{$and: [{f1: 7}, {f2: 7}, {f1: 5}]}, {$or: [{f1: 1}, {f1: 2}, {f1: 3}]}]},
{$or: [{$and: [{f1: 7}, {f2: 7}, {f1: 5}]}, {f1: {$in: [1, 2, 3]}}]},
],
[{$or: [{f2: [32, 52]}, {f2: [42, [13, 11]]}]}, {f2: {$in: [[32, 52], [42, [13, 11]]]}}],
[{$or: [{f2: 52}, {f2: 13}]}, {f2: {$in: [52, 13]}}],
[{$or: [{f2: [11]}, {f2: [23]}]}, {f2: {$in: [[11], [23]]}}],
[{$or: [{f1: 42}, {f1: null}]}, {f1: {$in: [42, null]}}],
[{$or: [{f1: "a"}, {f1: "b"}, {f1: /c/}]}, {f1: {$in: ["a", "b", /c/]}}],
{actualQuery: {$or: [{f1: 5}, {f1: 3}, {f1: 7}]}, expectedQuery: {f1: {$in: [7, 3, 5]}}},
{
actualQuery: {$or: [{f1: {$eq: 5}}, {f1: {$eq: 3}}, {f1: {$eq: 7}}]},
expectedQuery: {f1: {$in: [7, 3, 5]}}
},
{
actualQuery: {$or: [{f1: 42}, {f1: NaN}, {f1: 99}]},
expectedQuery: {f1: {$in: [42, NaN, 99]}}
},
{
actualQuery: {$or: [{f1: /^x/}, {f1: "ab"}]},
expectedQuery: {f1: {$in: [/^x/, "ab"]}},
cannotRewriteWithCollation: true
},
{
actualQuery: {$or: [{f1: /^x/}, {f1: "^a"}]},
expectedQuery: {f1: {$in: [/^x/, "^a"]}},
cannotRewriteWithCollation: true
},
{
actualQuery: {$or: [{f1: 42}, {f1: null}, {f1: 99}]},
expectedQuery: {f1: {$in: [42, 99, null]}}
},
{
actualQuery: {$or: [{f1: 1}, {f2: 9}, {f1: 99}]},
expectedQuery: {$or: [{f2: 9}, {f1: {$in: [1, 99]}}]}
},
{
actualQuery: {$or: [{f1: {$regex: /^x/}}, {f1: {$regex: /ab/}}]},
expectedQuery: {f1: {$in: [/^x/, /ab/]}}
},
{
actualQuery:
{$and: [{$or: [{f1: 7}, {f1: 3}, {f1: 5}]}, {$or: [{f1: 1}, {f1: 2}, {f1: 3}]}]},
expectedQuery: {$and: [{f1: {$in: [7, 3, 5]}}, {f1: {$in: [1, 2, 3]}}]}
},
{
actualQuery:
{$or: [{$or: [{f1: 7}, {f1: 3}, {f1: 5}]}, {$or: [{f1: 1}, {f1: 2}, {f1: 3}]}]},
expectedQuery: {$or: [{f1: {$in: [7, 3, 5]}}, {f1: {$in: [1, 2, 3]}}]}
},
{
actualQuery:
{$or: [{$and: [{f1: 7}, {f2: 7}, {f1: 5}]}, {$or: [{f1: 1}, {f1: 2}, {f1: 3}]}]},
expectedQuery: {$or: [{$and: [{f1: 7}, {f2: 7}, {f1: 5}]}, {f1: {$in: [1, 2, 3]}}]},
},
{
actualQuery: {$or: [{f2: [32, 52]}, {f2: [42, [13, 11]]}]},
expectedQuery: {f2: {$in: [[32, 52], [42, [13, 11]]]}}
},
{actualQuery: {$or: [{f2: 52}, {f2: 13}]}, expectedQuery: {f2: {$in: [52, 13]}}},
{actualQuery: {$or: [{f2: [11]}, {f2: [23]}]}, expectedQuery: {f2: {$in: [[11], [23]]}}},
{actualQuery: {$or: [{f1: 42}, {f1: null}]}, expectedQuery: {f1: {$in: [42, null]}}},
{
actualQuery: {$or: [{f1: "a"}, {f1: "b"}, {f1: /c/}]},
expectedQuery: {f1: {$in: ["a", "b", /c/]}},
cannotRewriteWithCollation: true
},
];
// These $or queries should not be rewritten into $in because of different semantics.
@ -133,22 +179,27 @@ for (const query of negativeTestQueries) {
assertOrNotRewrittenToIn(query);
}
function testOrToIn(queries) {
function testOrToIn(queries, usesCollation) {
for (const queryPair of queries) {
assertEquivPlanAndResult(queryPair[0], queryPair[1]);
if (usesCollation && queryPair.cannotRewriteWithCollation) {
continue;
}
assertEquivPlanAndResult(
queryPair.actualQuery, queryPair.expectedQuery, !queryPair.cannotRewriteWithCollation);
}
}
testOrToIn(positiveTestQueries); // test without indexes
testOrToIn(positiveTestQueries, false /* usesCollation */); // test without indexes
assert.commandWorked(coll.createIndex({f1: 1}));
testOrToIn(positiveTestQueries); // single index
testOrToIn(positiveTestQueries, false /* usesCollation */); // single index
assert.commandWorked(coll.createIndex({f2: 1}));
assert.commandWorked(coll.createIndex({f1: 1, f2: 1}));
testOrToIn(positiveTestQueries); // three indexes, requires multiplanning
testOrToIn(positiveTestQueries,
false /* usesCollation */); // three indexes, requires multiplanning
// Test with a collection that has a collation, and that collation is the same as the query
// collation
@ -156,12 +207,12 @@ coll.drop();
assert.commandWorked(db.createCollection("orToIn", {collation: {locale: 'en_US'}}));
coll = db.orToIn;
assert.commandWorked(coll.insert(data));
testOrToIn(positiveTestQueries);
testOrToIn(positiveTestQueries, true /* usesCollation */);
// Test with a collection that has a collation, and that collation is different from the query
// collation
coll.drop();
assert.commandWorked(db.createCollection("orToIn", {collation: {locale: 'de'}}));
coll = db.orToIn;
assert.commandWorked(coll.insert(data));
testOrToIn(positiveTestQueries);
testOrToIn(positiveTestQueries, true /* usesCollation */);
}());

View File

@ -0,0 +1,183 @@
// Tests to verify the behavior of find command's project in the presence of collation.
//
// @tags: [
// assumes_no_implicit_collection_creation_after_drop,
// ]
(function() {
'use strict';
const collation = {
locale: "en_US",
strength: 2
};
const withCollationCollName = jsTestName() + "_collation";
const noCollationCollName = jsTestName() + "_noCollation";
function setupCollection(withCollation) {
const insertCollName = withCollation ? withCollationCollName : noCollationCollName;
db[insertCollName].drop();
if (withCollation) {
assert.commandWorked(db.createCollection(insertCollName, {collation: withCollation}));
}
const insertColl = db[insertCollName];
assert.commandWorked(insertColl.insert(
{_id: 0, str: "a", array: [{str: "b"}, {str: "A"}, {str: "B"}, {str: "a"}]}));
assert.commandWorked(insertColl.insert({_id: 1, str: "a", elemMatch: [{str: "A"}, "ignored"]}));
assert.commandWorked(insertColl.insert({_id: 2, str: "A", elemMatch: ["ignored", {str: "a"}]}));
assert.commandWorked(insertColl.insert({_id: 3, str: "B"}));
return insertColl;
}
function runQueryWithCollation(testColl, collationToUse) {
let findCmd =
testColl.find({str: 'A', elemMatch: {$elemMatch: {str: "a"}}}, {_id: 1, 'elemMatch.$': 1});
if (collationToUse) {
findCmd = findCmd.collation(collationToUse);
}
const elemMatchOutput = findCmd.toArray();
assert.sameMembers(elemMatchOutput,
[{_id: 1, elemMatch: [{str: "A"}]}, {_id: 2, elemMatch: [{str: "a"}]}]);
findCmd =
testColl.find({str: 'A'}, {sortedArray: {$sortArray: {input: "$array", sortBy: {str: 1}}}});
if (collationToUse) {
findCmd = findCmd.collation(collationToUse);
}
const sortArrayOutput = findCmd.toArray();
assert.sameMembers(sortArrayOutput, [
{_id: 0, sortedArray: [{str: "A"}, {str: "a"}, {str: "b"}, {str: "B"}]},
{_id: 1, sortedArray: null},
{_id: 2, sortedArray: null}
]);
const findAndUpdateOutput = testColl.findAndModify({
query: {_id: 1, str: 'A', elemMatch: {$elemMatch: {str: "a"}}},
fields: {_id: 1, 'elemMatch.$': 1, updated: 1},
update: {$set: {updated: true}},
collation: collationToUse
});
assert.docEq(findAndUpdateOutput, {_id: 1, elemMatch: [{str: "A"}]});
const findAndUpdateWithSortArrayOutput = testColl.findAndModify({
query: {_id: 0, str: 'A'},
fields: {_id: 1, str: 1, sortedArray: {$sortArray: {input: "$array", sortBy: {str: 1}}}},
update: {$set: {updated: true}},
collation: collationToUse,
new: true
});
assert.docEq(findAndUpdateWithSortArrayOutput,
{_id: 0, str: "a", sortedArray: [{str: "A"}, {str: "a"}, {str: "b"}, {str: "B"}]});
const findAndRemoveOutput = testColl.findAndModify({
query: {_id: 1, str: 'A', elemMatch: {$elemMatch: {str: "a"}}},
fields: {_id: 1, 'elemMatch.$': 1, updated: 1},
remove: true,
collation: collationToUse,
});
assert.docEq(findAndRemoveOutput, {_id: 1, elemMatch: [{str: "A"}], updated: true});
const findAndRemoveWithSortArrayOutput = testColl.findAndModify({
query: {_id: 0, str: 'A'},
fields: {_id: 1, str: 1, sortedArray: {$sortArray: {input: "$array", sortBy: {str: 1}}}},
remove: true,
collation: collationToUse
});
assert.docEq(findAndRemoveWithSortArrayOutput,
{_id: 0, str: "a", sortedArray: [{str: "A"}, {str: "a"}, {str: "b"}, {str: "B"}]});
}
// The output for the below two tests should not depend on the collection level collation.
let collWithCollation = setupCollection({locale: "en_US"});
runQueryWithCollation(collWithCollation, collation);
let noCollationColl = setupCollection(false);
runQueryWithCollation(noCollationColl, collation);
// Tests to verify that the projection code inherits collection level collation in the absence of
// query level collation.
collWithCollation = setupCollection(collation);
runQueryWithCollation(collWithCollation, null);
// The output of this should not depend on the collection level collation and simple collation
// should be applied always.
function queryWithSimpleCollation(testColl) {
const elemMatchOutput =
testColl.find({str: 'A', elemMatch: {$elemMatch: {str: "a"}}}, {_id: 1, 'elemMatch.$': 1})
.collation({locale: "simple"})
.toArray();
assert.sameMembers(elemMatchOutput, [{_id: 2, elemMatch: [{str: "a"}]}]);
const sortArrayOutput =
testColl.find({str: 'a'}, {sortedArray: {$sortArray: {input: "$array", sortBy: {str: 1}}}})
.collation({locale: "simple"})
.toArray();
assert.sameMembers(sortArrayOutput, [
{_id: 0, sortedArray: [{str: "A"}, {str: "B"}, {str: "a"}, {str: "b"}]},
{_id: 1, sortedArray: null}
]);
// Test findAndModify command with 'update'. Ensure that simple collation is always honored.
const findAndUpdateOutput = testColl.findAndModify({
query: {str: 'A', elemMatch: {$elemMatch: {str: "a"}}},
fields: {_id: 1, 'elemMatch.$': 1, updated: 1},
update: {$set: {updated: true}},
collation: {locale: "simple"}
});
assert.docEq(findAndUpdateOutput, {_id: 2, elemMatch: [{str: "a"}]});
const findAndUpdateWithSortArrayOutput = testColl.findAndModify({
query: {_id: 0, str: 'a'},
fields: {_id: 1, str: 1, sortedArray: {$sortArray: {input: "$array", sortBy: {str: 1}}}},
update: {$set: {updated: true}},
collation: {locale: "simple"},
new: true
});
assert.docEq(findAndUpdateWithSortArrayOutput,
{_id: 0, str: "a", sortedArray: [{str: "A"}, {str: "B"}, {str: "a"}, {str: "b"}]});
// Test findAndModify command with remove:true. Ensure that simple collation is always honored.
const findAndRemoveOutput = testColl.findAndModify({
query: {_id: 2, str: 'A', elemMatch: {$elemMatch: {str: "a"}}},
fields: {_id: 1, 'elemMatch.$': 1, updated: 1},
remove: true,
collation: {locale: "simple"},
});
assert.docEq(findAndRemoveOutput, {_id: 2, elemMatch: [{str: "a"}], updated: true});
const findAndRemoveWithSortArrayOutput = testColl.findAndModify({
query: {_id: 0, str: 'a'},
fields: {_id: 1, str: 1, sortedArray: {$sortArray: {input: "$array", sortBy: {str: 1}}}},
remove: true,
collation: {locale: "simple"}
});
assert.docEq(findAndRemoveWithSortArrayOutput,
{_id: 0, str: "a", sortedArray: [{str: "A"}, {str: "B"}, {str: "a"}, {str: "b"}]});
}
noCollationColl = setupCollection(false);
queryWithSimpleCollation(noCollationColl);
collWithCollation = setupCollection(collation);
queryWithSimpleCollation(collWithCollation);
// Test with views.
(function viewWithCollation() {
collWithCollation = setupCollection(collation);
db[jsTestName() + "_view"].drop();
assert.commandWorked(
db.createView(jsTestName() + "_view", withCollationCollName, [], {collation: collation}));
const viewColl = db[jsTestName() + "_view"];
const sortArrayOutput =
viewColl.find({str: 'A'}, {sortedArray: {$sortArray: {input: "$array", sortBy: {str: 1}}}})
.toArray();
assert.sameMembers(sortArrayOutput, [
{_id: 0, sortedArray: [{str: "A"}, {str: "a"}, {str: "b"}, {str: "B"}]},
{_id: 1, sortedArray: null},
{_id: 2, sortedArray: null}
]);
})();
})();

View File

@ -37,7 +37,18 @@ if (!isMongos(db)) {
});
}
const res = coll.aggregate([{$group: {_id: '$meta', accmin: {$min: '$b'}, accmax: {$max: '$c'}}}])
.toArray();
assert.docEq(res, [{"_id": null, "accmin": 1, "accmax": 3}]);
let res = coll.aggregate([{$group: {_id: '$meta', accmin: {$min: '$b'}, accmax: {$max: '$c'}}}])
.toArray();
assert.docEq([{"_id": null, "accmin": 1, "accmax": 3}], res);
// Test SERVER-73822 fix: complex $min and $max (i.e. not just straight field refs) work correctly.
res = coll.aggregate([{
$group: {
_id: '$meta',
accmin: {$min: {$add: ["$b", "$c"]}},
accmax: {$max: {$add: ["$b", "$c"]}}
}
}])
.toArray();
assert.docEq([{"_id": null, "accmin": 2, "accmax": 6}], res);
})();

View File

@ -0,0 +1,55 @@
/**
* Tests that an operation requiring more cache than available fails instead of retrying infinitely.
*
* @tags: [
* does_not_support_config_fuzzer,
* requires_fcv_62,
* requires_persistence,
* requires_non_retryable_writes,
* requires_wiredtiger,
* ]
*/
(function() {
load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
load("jstests/libs/storage_engine_utils.js");
// TODO (SERVER-39362): remove once parallel suite respects tags properly.
if (!storageEngineIsWiredTiger()) {
jsTestLog("Skipping test because storage engine is not WiredTiger.");
return;
}
const doc = {
x: []
};
for (var j = 0; j < 334000; j++) {
doc.x.push("" + Math.random() + Math.random());
}
const coll = db[jsTestName()];
coll.drop();
// Maximum amount of indexes is 64. _id is implicit, and sharded collections also have an index on
// the shard key.
assert.commandWorked(coll.createIndex({x: "text"}));
for (let i = 0; i < 61; i++) {
assert.commandWorked(coll.createIndex({x: 1, ["field" + i]: 1}));
}
// Retry the operation until we eventually hit the TransactionTooLargeForCache. Retry on
// WriteConflict or TemporarilyUnavailable errors, as those are expected to be returned if the
// threshold for TransactionTooLargeForCache is not reached, possibly due to concurrent operations.
assert.soon(() => {
let result;
try {
result = coll.insert(doc);
assert.commandFailedWithCode(result, ErrorCodes.TransactionTooLargeForCache);
return true;
} catch (e) {
assert.commandFailedWithCode(result,
[ErrorCodes.WriteConflict, ErrorCodes.TemporarilyUnavailable]);
return false;
}
}, "Expected operation to eventually fail with TransactionTooLargeForCache error.");
}());

View File

@ -0,0 +1,85 @@
/**
* Tests a multi-document transaction requiring more cache than available fails with the expected
* error code instead of a generic WriteConflictException.
*
* @tags: [
* does_not_support_config_fuzzer,
* requires_fcv_62,
* requires_persistence,
* requires_non_retryable_writes,
* requires_wiredtiger,
* uses_transactions,
* ]
*/
(function() {
load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
load('jstests/libs/transactions_util.js');
function getWtCacheSizeBytes() {
let serverStatus;
if (FixtureHelpers.isReplSet(db) || FixtureHelpers.isMongos(db)) {
serverStatus = FixtureHelpers.getPrimaries(db)[0].getDB('admin').serverStatus();
} else {
serverStatus = db.serverStatus();
}
assert.commandWorked(serverStatus);
return serverStatus.wiredTiger.cache["maximum bytes configured"];
}
const doc1 = {
x: []
};
for (var j = 0; j < 100000; j++) {
doc1.x.push("" + Math.random() + Math.random());
}
const session = db.getMongo().startSession();
const sessionDb = session.getDatabase(db.getName());
const coll = sessionDb[jsTestName()];
coll.drop();
// Scale the load in proportion to WT cache size, to reduce test run time.
// A single collection can only have up to 64 indexes. Cap at _id + 1 text index + 62 indexes.
const nIndexes = Math.min(Math.ceil(getWtCacheSizeBytes() * 2 / (1024 * 1024 * 1024)), 62);
assert.commandWorked(coll.createIndex({x: "text"}));
for (let i = 0; i < nIndexes; i++) {
assert.commandWorked(coll.createIndex({x: 1, ["field" + i]: 1}));
}
// Retry the transaction until we eventually hit the TransactionTooLargeForCache. Only retry on
// WriteConflict error, which is the only expected error besides TransactionTooLargeForCache.
assert.soon(() => {
session.startTransaction();
// Keep inserting documents in the transaction until we eventually hit the cache limit.
let insertCount = 0;
let result;
try {
while (true) {
try {
++insertCount;
result = coll.insert(doc1);
assert.commandWorked(result);
} catch (e) {
session.abortTransaction();
assert.commandFailedWithCode(result, ErrorCodes.TransactionTooLargeForCache);
break;
}
}
} catch (e) {
assert.commandFailedWithCode(result, ErrorCodes.WriteConflict);
return false;
}
// The error should not have a transient transaction error label. At this point the error must
// have been TransactionTooLargeForCache. We do this check here to avoid having to check
// exception types in the outermost catch, in case this assertion fires.
assert(!TransactionsUtil.isTransientTransactionError(result), result);
jsTestLog("Iterations until TransactionTooLargeForCache occured: " + insertCount);
return true;
}, "Expected a transaction to eventually fail with TransactionTooLargeForCache error.");
}());

View File

@ -134,4 +134,8 @@ if (checkCascadesOptimizerEnabled(db)) {
{filter: {a: {$gte: MaxKey()}}, expected: [docs[31]]},
{filter: {a: {$gt: MaxKey()}}, expected: []});
}
for (const testData of tests) {
runTest(testData.filter, testData.expected);
}
}());

View File

@ -113,8 +113,7 @@ function runTest(badViewDefinition) {
}
assert.commandWorked(
viewsDB.runCommand(
{collMod: "collection", validator: {x: {$type: "string"}}, validationAction: "warn"}),
viewsDB.runCommand({collMod: "collection", validator: {x: {$type: "string"}}}),
makeErrorMessage("collMod"));
const renameCommand = {

View File

@ -151,10 +151,6 @@ assert.commandWorked(viewsDB.runCommand({
assert.commandWorked(
viewsDB.runCommand({aggregate: "largeView", pipeline: [{$sort: {x: -1}}], cursor: {}}),
"Expected aggregate to succeed since 'allowDiskUse' is true by default");
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(
viewsDB.runCommand({collMod: validatedCollName, validationAction: "warn"}));
})();
// Test explain modes on a view.

View File

@ -626,6 +626,7 @@ let viewsCommandTests = {
setDefaultRWConcern: {skip: isUnrelated},
setFeatureCompatibilityVersion: {skip: isUnrelated},
setFreeMonitoring: {skip: isUnrelated},
setProfilingFilterGlobally: {skip: isUnrelated},
setParameter: {skip: isUnrelated},
setShardVersion: {skip: isUnrelated},
setChangeStreamState: {skip: isUnrelated},

View File

@ -55,6 +55,18 @@ assertArrayEq({
],
});
assertArrayEq({
actual: c.find({a: {$ne: null}}, {_id: 0}).toArray(),
expected: [
{a: 1},
{a: 2},
{a: ""},
{a: [1, 2]},
{a: [2, 3]},
{a: [[1, 2]]},
],
});
c.drop();
assert.commandWorked(c.insertMany([

View File

@ -45,28 +45,6 @@ const isIgnorableError = function ignorableError(codeName) {
*/
const validateCollectionsBackgroundThread = function validateCollectionsBackground(
host, isIgnorableErrorFunc) {
// Some tests explicitly mess with schema validation. We will skip running background validation
// on those collections.
const skippedCollections = new Set([
"collectionWithValidator",
"jstests_schema_encrypt",
"json_schema_additional_items",
"schema_allowed_properties",
"jstests_schema_bsontype",
"jstests_schema_dependencies",
"jstests_schema_encrypt",
"json_schema_items",
"jstests_json_schema",
"jstests_json_schema_logical",
"json_schema_min_max_items",
"jstests_schema_min_max_properties",
"schema_pattern_properties",
"jstests_schema_required",
"json_schema_unique_items",
"json_schema_test_corpus",
"jstests_json_schema_ignore_unsupported",
]);
// Calls 'func' with the print() function overridden to be a no-op.
const quietly = (func) => {
const printOriginal = print;
@ -128,9 +106,6 @@ const validateCollectionsBackgroundThread = function validateCollectionsBackgrou
});
for (let collectionName of collectionNames) {
if (dbName == "bypass_document_validation" || skippedCollections.has(collectionName)) {
continue;
}
let res = conn.getDB(dbName).getCollection(collectionName).runCommand({
"validate": collectionName,
background: true,

View File

@ -10,7 +10,7 @@
* Asserts that 'doc' matches 'schema' if and only if 'valid' is true. Drops 'coll' in the process,
* so do not pass a collection whose contents you wish to preserve.
*/
function assertSchemaMatch(coll, schema, doc, valid, removeValidator = false) {
function assertSchemaMatch(coll, schema, doc, valid) {
const errmsg = "Document " + tojson(doc) +
(valid ? " should have matched the schema " : " unexpectedly matched the schema ") +
tojson(schema);
@ -60,12 +60,4 @@ function assertSchemaMatch(coll, schema, doc, valid, removeValidator = false) {
ErrorCodes.DocumentValidationFailure,
errmsg + " during update document validation in strict mode");
}
if (removeValidator) {
// Remove the validator to avoid failing collection validation.
assert.commandWorked(coll.runCommand("collMod", {validator: {}}));
} else {
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(coll.runCommand("collMod", {validationAction: "warn"}));
}
}

View File

@ -67,7 +67,7 @@ Mongo.prototype.runCommand = function(dbName, cmdObj, options) {
}
cmdObj.pipeline = [
{$facet: {originalPipeline: originalPipeline}},
{$facet: {originalPipeline: originalPipeline, extraPipeline: [{$count: "count"}]}},
{$unwind: '$originalPipeline'},
{$replaceRoot: {newRoot: '$originalPipeline'}},
];

View File

@ -0,0 +1,69 @@
/**
* Verifies that the server ignores collection option "recordPreImages" on binary upgrade from the
* last LTS version to the current, as well as removes the option from collection attributes on
* FCV upgrade.
*/
(function() {
"use strict";
load('jstests/multiVersion/libs/multi_rs.js');
const lastLTSVersion = "last-lts";
const latestVersion = "latest";
// Setup a two-node replica set with last LTS binaries, so it is possible to create a collection
// with "recordPreImages" option.
const rst = new ReplSetTest(
{name: jsTestName(), nodes: [{binVersion: lastLTSVersion}, {binVersion: lastLTSVersion}]});
rst.startSet();
rst.initiate();
const testDB = rst.getPrimary().getDB("test");
const primaryNode = rst.getPrimary();
const secondaryNode = rst.getSecondary();
// Create the collection.
const collectionName = "coll";
assert.commandWorked(testDB.createCollection(collectionName, {recordPreImages: true}));
let coll = testDB[collectionName];
// Insert a test document which will be updated to trigger recording of change stream pre-images.
assert.commandWorked(coll.insert({_id: 1, a: 1}));
assert.commandWorked(coll.updateOne({_id: 1}, {$inc: {a: 1}}));
rst.awaitReplication();
// Upgrade the binary of the secondary node to the current version to setup a mixed binary cluster.
rst.upgradeMembers([secondaryNode], {binVersion: latestVersion});
// Make sure the primary node did not change.
rst.stepUp(primaryNode);
// Verify that recording of change stream pre-images succeeds.
assert.commandWorked(coll.updateOne({_id: 1}, {$inc: {a: 1}}));
rst.awaitReplication();
// Finally upgrade the binary of the primary node to the current version.
rst.upgradePrimary(rst.getPrimary(), {binVersion: latestVersion});
// Update a document on the collection with inactive "recordPreImages" collection option.
coll = rst.getPrimary().getDB("test")[collectionName];
assert.commandWorked(coll.updateOne({_id: 1}, {$inc: {a: 1}}));
rst.awaitReplication();
// Upgrade the FCV to the latest to trigger removal of "recordPreImages" collection option from
// persistent catalog entries.
assert.commandWorked(rst.getPrimary().adminCommand({setFeatureCompatibilityVersion: latestFCV}));
// To check the collection options, downgrade FCV to later replace the binary of the server with
// the last LTS binary version.
assert.commandWorked(rst.getPrimary().adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
rst.upgradeSet({binVersion: lastLTSVersion});
// Verify that collection option "recordPreImages" was removed.
const result =
assert.commandWorked(rst.getPrimary().getDB("test").runCommand({listCollections: 1}));
assert.eq(result.cursor.firstBatch[0].name, collectionName);
assert.docEq(
{},
result.cursor.firstBatch[0].options,
`Collection option "recordPreImages" was not removed. Got response: ${tojson(result)}`);
rst.stopSet();
})();

View File

@ -32,30 +32,30 @@ for (let i = 0; i < 5; i++) {
// The collection has not been checkpointed yet, so there is nothing to validate.
let res = assert.commandWorked(db.runCommand({validate: collName, background: true}));
assert.eq(true, res.valid);
assert.eq(false, res.hasOwnProperty("nrecords"));
assert.eq(false, res.hasOwnProperty("nIndexes"));
assert.eq(true, res.valid, res);
assert.eq(false, res.hasOwnProperty("nrecords"), res);
assert.eq(false, res.hasOwnProperty("nIndexes"), res);
forceCheckpoint();
res = assert.commandWorked(db.runCommand({validate: collName, background: true}));
assert.eq(true, res.valid);
assert.eq(true, res.hasOwnProperty("nrecords"));
assert.eq(true, res.hasOwnProperty("nIndexes"));
assert.eq(true, res.valid, res);
assert.eq(true, res.hasOwnProperty("nrecords"), res);
assert.eq(true, res.hasOwnProperty("nIndexes"), res);
assert.commandWorked(coll.createIndex({x: 1}));
// Shouldn't validate the newly created index here as it wasn't checkpointed yet.
res = assert.commandWorked(db.runCommand({validate: collName, background: true}));
assert.eq(true, res.valid);
assert.eq(1, res.nIndexes);
assert.eq(true, res.valid, res);
assert.eq(1, res.nIndexes, res);
forceCheckpoint();
// Validating after the checkpoint should validate the newly created index.
res = assert.commandWorked(db.runCommand({validate: collName, background: true}));
assert.eq(true, res.valid);
assert.eq(2, res.nIndexes);
assert.eq(true, res.valid, res);
assert.eq(2, res.nIndexes, res);
MongoRunner.stopMongod(conn);
}());

View File

@ -24,15 +24,19 @@ let adminDb = m.getDB('admin');
assert.eq(getParameter(adminDb, "diagnosticDataCollectionStatsNamespaces"), ["local.startup_log"]);
// Validate that collection stats are collected
let doc = verifyGetDiagnosticData(adminDb);
assert.eq(doc.collectionStats["local.startup_log"].ns, "local.startup_log");
let doc;
assert.soon(() => {
doc = verifyGetDiagnosticData(adminDb);
return doc.collectionStats["local.startup_log"].ns == "local.startup_log";
});
// Validate that incorrect changes have no effect
assert.commandFailed(setParameter(adminDb, {"diagnosticDataCollectionStatsNamespaces": ["local"]}));
assert.eq(getParameter(adminDb, "diagnosticDataCollectionStatsNamespaces"), ["local.startup_log"]);
// Validate that collection stats are collected for runtime collections
// Validate that collection stats are collected for runtime collections and that we do not crash
// for a non-existent collection
assert.commandWorked(setParameter(
adminDb,
{"diagnosticDataCollectionStatsNamespaces": ["admin.system.version", "admin.does_not_exist"]}));
@ -41,8 +45,7 @@ assert.soon(() => {
jsTestLog("Collected: " + tojson(result));
let collectionStats = result.data.collectionStats;
return collectionStats.hasOwnProperty("admin.system.version") &&
collectionStats["admin.system.version"].ns == "admin.system.version" &&
collectionStats["admin.does_not_exist"].ns == "admin.does_not_exist" != undefined;
collectionStats["admin.system.version"].ns == "admin.system.version";
});
// Validate that when it is disabled, we stop collecting

View File

@ -0,0 +1,281 @@
/*
* Test the usage and behavior of the 'setProfilingFilterGlobally' command.
*
* @tags: [requires_sharding, requires_replication]
*/
(function() {
load("jstests/libs/log.js"); // For findMatchingLogLine.
load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
load("jstests/noPassthrough/libs/server_parameter_helpers.js"); // For setParameter.
// Updates the global profiling filter to 'newFilter' and validates that 'oldFilter' is returned in
// the response and the change is logged correctly. If `newFilter' is null, unsets the filter.
function updateProfilingFilterGlobally(db, {oldFilter, newFilter}) {
const result = assert.commandWorked(
db.runCommand({setProfilingFilterGlobally: 1, filter: newFilter ? newFilter : "unset"}));
assert.eq(result.was, oldFilter ? oldFilter : "none");
const log = assert.commandWorked(db.adminCommand({getLog: "global"})).log;
assert(!!findMatchingLogLine(log, {
msg: "Profiler settings changed globally",
from: {filter: oldFilter ? oldFilter : "none"},
to: {filter: newFilter ? newFilter : "none"}
}),
"expected log line was not found");
}
(function testQueryKnobMustBeEnabledToUseCommand() {
// First make sure we can't run the command with the query knob turned off.
const conn = MongoRunner.runMongod({});
assert.commandFailedWithCode(
conn.adminCommand({setProfilingFilterGlobally: 1, filter: "unset"}), 7283301);
MongoRunner.stopMongod(conn);
})();
(function testCommandOverridesDefaultFromConfigFile() {
// Test that setting the global filter overrides the startup configuration.
const conn = MongoRunner.runMongod({
config: "jstests/libs/config_files/set_profiling_filter.json",
setParameter: {internalQueryGlobalProfilingFilter: 1}
});
updateProfilingFilterGlobally(conn.getDB("test"), {
oldFilter: {$expr: {$lt: [{$rand: {}}, {$const: 0.01}]}},
newFilter: {$expr: {$lt: [{$rand: {}}, {$const: 0.5}]}}
});
updateProfilingFilterGlobally(
conn.getDB("test"),
{oldFilter: {$expr: {$lt: [{$rand: {}}, {$const: 0.5}]}}, newFilter: null});
MongoRunner.stopMongod(conn);
})();
// Run a set of correctness tests for the setProfilingFilterGlobally command on the given
// connection.
function runCorrectnessTests(conn) {
// mongoS supports slow-query log lines but not profiling. So if we are talking to mongoS, we
// will avoid enabling profiling, or making assertions about profiling.
const db = conn.getDB("test");
const isMongos = FixtureHelpers.isMongos(db);
const dbs = [conn.getDB("db1"), conn.getDB("db2"), conn.getDB("db3")];
function initDatabase(db) {
db.c.drop();
db.c.insert([{x: 25}, {x: 50}]);
// Fully enable profiling to start.
db.setProfilingLevel(isMongos ? 0 : 1, {slowms: -1});
}
// Initialize each database with some basic data and set the profiling level.
for (const db of dbs) {
initDatabase(db);
}
// Test queries to run.
const queries = {
query1: {filter: {}, nreturned: 2},
query2: {filter: {x: 25}, nreturned: 1},
query3: {filter: {x: 1000}, nreturned: 0},
};
// Profile filters matching specific test queries.
const profileFilter1 = {filter: {nreturned: {$eq: 2}}, matchesQuery: "query1"};
const profileFilter2 = {filter: {nreturned: {$eq: 1}}, matchesQuery: "query2"};
// Verify that profile filters are applied as expected for both logging and profiling, if
// applicable. 'params' must specify three fields:
// 'desc': short test description
// 'globalFilter': expected global profiling filter setting
// 'dbFilters': expected database-specific filter settings
function verify(params) {
function verifyDatabase(db) {
// Create a unique comment for the query.
function queryComment(queryName) {
return `${params.desc}: ${db.getName()} -> ${queryName}`;
}
// Check the log for the query's profile entry, and system.profile if this is being run
// on mongod.
function assertQueryProfiled(name, shouldProfile) {
const log = assert.commandWorked(db.adminCommand({getLog: "global"})).log;
assert.eq(
!!findMatchingLogLine(log, {msg: "Slow query", comment: queryComment(name)}),
shouldProfile,
`expected query${shouldProfile ? "" : " not"} to be logged: ${
queryComment(name)}`);
if (!isMongos) {
assert.eq(!!db.system.profile.findOne({'command.comment': queryComment(name)}),
shouldProfile,
`expected query${shouldProfile ? "" : " not"} to be profiled: ${
queryComment(name)}`);
}
}
for (const [queryName, query] of Object.entries(queries)) {
// First, run the query on the database.
const comment = queryComment(queryName);
const results = db.c.find(query.filter).comment(comment).itcount();
assert.eq(results, query.nreturned, comment);
// Validate whether or not the query was profiled based on the database's
// profile filter. We should profile *unless* there is a filter applicable to
// this database that does not match the query.
let shouldProfile = true;
if (params.dbFilters.hasOwnProperty(db.getName())) {
// This database has a database specific filter, does it match the query?
shouldProfile = params.dbFilters[db.getName()].matchesQuery === queryName;
} else if (params.globalFilter) {
// No database filter, but there is a global filter, does it match the
// query?
shouldProfile = params.globalFilter.matchesQuery == queryName;
}
assertQueryProfiled(queryName, shouldProfile);
}
}
for (const db of dbs) {
verifyDatabase(db);
}
// Now create a new database and make sure the global settings are applied correctly.
const newDB = conn.getDB("newDB");
initDatabase(newDB);
verifyDatabase(newDB);
newDB.dropDatabase();
}
// Error cases (invalid filters or parameters).
assert.commandFailedWithCode(db.runCommand({setProfilingFilterGlobally: 1, filter: null}),
ErrorCodes.BadValue);
assert.commandFailedWithCode(
db.runCommand({setProfilingFilterGlobally: 1, filter: {noSuchField: 1}}), 4910200);
assert.commandFailedWithCode(
db.runCommand({setProfilingFilterGlobally: 1, filter: {}, writeConcern: {w: "majority"}}),
ErrorCodes.InvalidOptions);
assert.commandFailedWithCode(
db.runCommand(
{setProfilingFilterGlobally: 1, filter: {}, readConcern: {level: "majority"}}),
ErrorCodes.InvalidOptions);
// Make sure that behavior is as expected in the default/startup state.
(function testDefaultSettingIsNone() {
verify({desc: "default setting is none", globalFilter: null, dbFilters: {}});
})();
(function testEmptyFilter() {
updateProfilingFilterGlobally(db, {oldFilter: null, newFilter: {}});
// Empty filter is always true - effectively none.
verify({desc: "empty filter", globalFilter: null, dbFilters: {}});
})();
(function testGlobalFilterSettingAffectsAllDatabases() {
updateProfilingFilterGlobally(db, {oldFilter: {}, newFilter: profileFilter1.filter});
verify({
desc: "setting the global filter affects all databases",
globalFilter: profileFilter1,
dbFilters: {}
});
})();
(function testGlobalFilterUnsetClearsGlobalSetting() {
updateProfilingFilterGlobally(db, {oldFilter: profileFilter1.filter, newFilter: null});
verify({
desc: "unsetting the global filter clears the global setting",
globalFilter: null,
dbFilters: {}
});
})();
(function testGlobalFilterUnsetWhenAlreadyUnsetIsNoop() {
updateProfilingFilterGlobally(db, {oldFilter: null, newFilter: null});
verify({
desc: "unsetting the global filter when already unset is a noop",
globalFilter: null,
dbFilters: {}
});
})();
(function testGlobalFilterSettingOverridesDatabaseSpecificSettings() {
let result = assert.commandWorked(db.getSiblingDB("db1").runCommand(
{profile: isMongos ? 0 : 1, filter: profileFilter1.filter}));
assert(!result.filter);
result = assert.commandWorked(db.getSiblingDB("db2").runCommand(
{profile: isMongos ? 0 : 1, filter: profileFilter2.filter}));
assert(!result.filter);
verify({
desc: "setting the global filter overrides database specific settings (pre-validate)",
globalFilter: null,
dbFilters: {db1: profileFilter1, db2: profileFilter2}
});
updateProfilingFilterGlobally(db, {oldFilter: null, newFilter: profileFilter2.filter});
verify({
desc: "setting the global filter overrides database specific settings",
globalFilter: profileFilter2,
dbFilters: {}
});
})();
(function testGlobalFilterSettingOverridesDatabaseSpecificSettingsEvenWhenNoop() {
let result = assert.commandWorked(db.getSiblingDB("db1").runCommand(
{profile: isMongos ? 0 : 1, filter: profileFilter1.filter}));
assert.eq(result.filter, profileFilter2.filter);
verify({
desc:
"setting the global filter overrides database specific settings even when a noop (pre-validate)",
globalFilter: profileFilter2,
dbFilters: {db1: profileFilter1}
});
updateProfilingFilterGlobally(
db, {oldFilter: profileFilter2.filter, newFilter: profileFilter2.filter});
verify({
desc: "setting the global filter overrides database specific settings even when a noop",
globalFilter: profileFilter2,
dbFilters: {}
});
})();
(function testGlobalFilterUnsetOverridesDatabaseSpecificSettings() {
result = assert.commandWorked(db.getSiblingDB("db1").runCommand(
{profile: isMongos ? 0 : 1, filter: profileFilter1.filter}));
assert.eq(result.filter, profileFilter2.filter);
result = assert.commandWorked(db.getSiblingDB("db3").runCommand(
{profile: isMongos ? 0 : 1, filter: profileFilter2.filter}));
assert.eq(result.filter, profileFilter2.filter);
verify({
desc: "unsetting the global filter overrides database specific settings (pre-validate)",
globalFilter: profileFilter2,
dbFilters: {db1: profileFilter1, db3: profileFilter2}
});
updateProfilingFilterGlobally(db, {oldFilter: profileFilter2.filter, newFilter: null});
verify({
desc: "unsetting the global filter overrides database specific settings",
globalFilter: null,
dbFilters: {}
});
})();
}
{
// Run tests on mongod.
const conn = MongoRunner.runMongod({setParameter: {internalQueryGlobalProfilingFilter: 1}});
runCorrectnessTests(conn);
MongoRunner.stopMongod(conn);
}
{
// Run tests on mongos.
const st = ShardingTest({
shards: 1,
rs: {nodes: 1},
config: 1,
mongosOptions: {setParameter: {internalQueryGlobalProfilingFilter: 1}}
});
runCorrectnessTests(st);
st.stop();
}
})();

View File

@ -29,7 +29,7 @@ const collName = "collectionWithMalformedValidator";
assert.commandWorked(
testDB.runCommand({collMod: collName, validator: {email: {$regex: invalidRegex}}}));
MongoRunner.stopMongod(conn, null, {skipValidation: true});
MongoRunner.stopMongod(conn);
})();
(function startUpWithMalformedValidator() {
@ -48,6 +48,6 @@ const collName = "collectionWithMalformedValidator";
assert.commandWorked(testDB.someOtherCollection.insert({a: 1}));
assert.eq(testDB.someOtherCollection.find().itcount(), 1);
MongoRunner.stopMongod(conn, null, {skipValidation: true});
MongoRunner.stopMongod(conn);
})();
})();

View File

@ -253,8 +253,5 @@ bulkOp.find({$expr: {$eq: ["$x", 2]}}).update({$set: {x: 10}});
bulkOp.find({$expr: {$lt: ["$x", 1]}}).remove();
checkCounters(() => assert.commandWorked(bulkOp.execute()), {"$eq": 1, "$lt": 1});
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(testColl.runCommand("collMod", {validationAction: "warn"}));
MongoRunner.stopMongod(mongod);
})();

View File

@ -18,6 +18,10 @@ function getPlanCacheSize() {
return db.runCommand({serverStatus: 1}).metrics.query.planCacheTotalSizeEstimateBytes;
}
function getGlobalPlanCacheNumEntries() {
return db.runCommand({serverStatus: 1}).metrics.query.planCacheTotalQueryShapes;
}
/**
* Helper class that creates a collection, indexes on it, and makes a few queries to add entries to
* the plan cache.
@ -37,20 +41,21 @@ class TestCollection {
assert.gt(getPlanCacheSize(), 0);
this.nCacheEntries = this.getNumberOfPlanCacheEntries();
this.nCacheEntries = this.getNumberOfCollectionPlanCacheEntries();
assert.eq(2, this.nCacheEntries);
}
getNumberOfPlanCacheEntries() {
// The following three helper functions concern plan cache entries specific to a given
// collection, and not the entire/global plan cache
getNumberOfCollectionPlanCacheEntries() {
return this.coll.getPlanCache().list().length;
}
assertAllCollectionCacheEntriesRemoved() {
assert.eq(0, this.getNumberOfPlanCacheEntries());
assert.eq(0, this.getNumberOfCollectionPlanCacheEntries());
}
assertCacheEntriesNotRemoved() {
assert.eq(this.nCacheEntries, this.getNumberOfPlanCacheEntries());
assertCollectionCacheEntriesNotRemoved() {
assert.eq(this.nCacheEntries, this.getNumberOfCollectionPlanCacheEntries());
}
}
@ -59,23 +64,28 @@ class TestCollection {
const test = new TestCollection();
assert.gt(getPlanCacheSize(), initialPlanCacheSize);
assert.eq(getGlobalPlanCacheNumEntries(), 2);
assert(test.coll.drop());
assert.eq(getPlanCacheSize(), initialPlanCacheSize);
assert.eq(getGlobalPlanCacheNumEntries(), 0);
}());
(function cacheEntriesNotRemovedIfAnotherCollectedDropped() {
const test = new TestCollection("coll1");
const cacheSizeForOneTestCollection = getPlanCacheSize();
assert.eq(getGlobalPlanCacheNumEntries(), 2);
const anotherTest = new TestCollection("coll2");
const cacheSizeForTwoTestCollections = getPlanCacheSize();
assert.eq(getGlobalPlanCacheNumEntries(), 4);
assert.gt(cacheSizeForTwoTestCollections, cacheSizeForOneTestCollection);
assert(anotherTest.coll.drop());
assert.eq(cacheSizeForOneTestCollection, getPlanCacheSize());
test.assertCacheEntriesNotRemoved();
// Entries associated with anotherTest.coll are booted from the plan cache.
assert.eq(getGlobalPlanCacheNumEntries(), 2);
test.assertCollectionCacheEntriesNotRemoved();
}());
(function cacheEntriesRemovedIfANewIndexCreated() {
@ -107,14 +117,13 @@ class TestCollection {
db.runCommand({collMod: collectionName, validator: {text: {$type: "string"}}}));
assert.eq(getPlanCacheSize(), initialPlanCacheSize);
test.assertCacheEntriesNotRemoved();
test.assertCollectionCacheEntriesNotRemoved();
}());
(function cacheEntriesRemovedIfIndexChanged() {
const collectionName = "coll";
const test = new TestCollection(collectionName);
const initialPlanCacheSize = getPlanCacheSize();
assert.commandWorked(db.runCommand({
collMod: collectionName,
index: {
@ -122,7 +131,6 @@ class TestCollection {
hidden: true,
}
}));
assert.lt(getPlanCacheSize(), initialPlanCacheSize);
test.assertAllCollectionCacheEntriesRemoved();
}());
@ -143,16 +151,16 @@ class TestCollection {
(function oneCacheEntryRemovedOnClearPlanCacheWithQueryCommand() {
const collectionName = "coll";
const test = new TestCollection(collectionName);
const numberOfCacheEntries = test.getNumberOfPlanCacheEntries();
const numberOfCacheEntries = getGlobalPlanCacheNumEntries();
test.coll.find({a: 1, b: 2, c: 3, d: 4}).itcount();
assert.eq(numberOfCacheEntries + 1, test.getNumberOfPlanCacheEntries());
assert.eq(numberOfCacheEntries + 1, getGlobalPlanCacheNumEntries());
const planCacheSize = getPlanCacheSize();
assert.commandWorked(
db.runCommand({planCacheClear: collectionName, query: {a: 1, b: 2, c: 3, d: 4}}));
assert.lt(getPlanCacheSize(), planCacheSize);
assert.eq(numberOfCacheEntries, test.getNumberOfPlanCacheEntries());
assert.eq(numberOfCacheEntries, getGlobalPlanCacheNumEntries());
}());
MongoRunner.stopMongod(conn);

View File

@ -45,6 +45,9 @@ function getPlanCacheSize() {
return db.serverStatus().metrics.query.planCacheTotalSizeEstimateBytes;
}
function getPlanCacheNumEntries() {
return db.serverStatus().metrics.query.planCacheTotalQueryShapes;
}
function assertQueryInPlanCache(coll, query) {
const explainResult = assert.commandWorked(coll.explain().find(query).finish());
const queryHash = getQueryHashFromExplain(explainResult, db);
@ -65,7 +68,7 @@ assert.commandWorked(coll.createIndex({a: 1, b: 1}));
const initialPlanCacheSize = getPlanCacheSize();
// Plan cache must be empty.
assert.eq(0, coll.getPlanCache().list().length);
assert.eq(0, getPlanCacheNumEntries());
const sbeQuery = {
a: 1
@ -79,7 +82,7 @@ const classicQuery = {
assert.eq(1, coll.find(sbeQuery).itcount());
assertQueryInPlanCache(coll, sbeQuery);
// Plan Cache must contain exactly 1 entry.
assert.eq(1, coll.getPlanCache().list().length);
assert.eq(1, getPlanCacheNumEntries());
// Assert metric is incremented for new cache entry.
const afterSbePlanCacheSize = getPlanCacheSize();
@ -92,7 +95,7 @@ assert.commandWorked(
assert.eq(1, coll.find(classicQuery).itcount());
assertQueryInPlanCache(coll, classicQuery);
// Plan Cache must contain exactly 2 entries.
assert.eq(2, coll.getPlanCache().list().length);
assert.eq(2, getPlanCacheNumEntries());
// Assert metric is incremented for new cache entry.
const afterClassicPlanCacheSize = getPlanCacheSize();

View File

@ -4,6 +4,10 @@
(function() {
"use strict";
// Disable the testing proctor. When the testing proctor is enabled, 'validate' will only warn about
// non-compliant documents, even when the validation action is 'error'.
TestData.testingDiagnosticsEnabled = false;
const conn = MongoRunner.runMongod();
const dbName = "test";

View File

@ -25,44 +25,53 @@ function corruptIndex() {
coll = conn.getDB("test").getCollection("corrupt");
}
function checkValidate(errorPrefix, numMissingIndexEntries) {
conn.getDB("test").adminCommand({setParameter: 1, maxValidateMemoryUsageMB: 1});
function checkValidate(maxMemoryUsage, {minMissingKeys, maxMissingKeys}) {
conn.getDB("test").adminCommand({setParameter: 1, maxValidateMemoryUsageMB: maxMemoryUsage});
const res = coll.validate();
assert.commandWorked(res);
assert(!res.valid);
assert.containsPrefix(errorPrefix, res.errors);
assert.eq(res.missingIndexEntries.length, numMissingIndexEntries);
assert(!res.valid, tojson(res));
const notAllReportedPrefix =
"Not all index entry inconsistencies are reported due to memory limitations.";
assert.containsPrefix(notAllReportedPrefix, res.errors, tojson(res));
assert.gte(res.missingIndexEntries.length, minMissingKeys, tojson(res));
assert.lte(res.missingIndexEntries.length, maxMissingKeys, tojson(res));
}
function checkValidateRepair(expectRepair) {
function checkValidateRepair() {
const res = coll.validate({repair: true});
assert.commandWorked(res);
assert(!res.valid, printjson(res));
assert.eq(res.repaired, expectRepair, printjson(res));
assert(!res.valid, tojson(res));
assert(res.repaired, tojson(res));
}
const noneReportedPrefix =
"Unable to report index entry inconsistencies due to memory limitations.";
const notAllReportedPrefix =
"Not all index entry inconsistencies are reported due to memory limitations.";
// Insert a document with a key larger than maxValidateMemoryUsageMB so that validate does not
// report any missing index entries.
// Insert a document with a key larger than maxValidateMemoryUsageMB and test that we still report
// at least one inconsistency.
const indexKey = "a".repeat(kIndexKeyLength);
assert.commandWorked(coll.insert({_id: indexKey}));
corruptIndex();
checkValidate(noneReportedPrefix, 0);
checkValidate(1, {minMissingKeys: 1, maxMissingKeys: 1});
// Can't repair successfully if there aren't any index inconsistencies reported.
checkValidateRepair(false);
checkValidateRepair();
// Clear collection between tests.
coll.drop();
// Test that if we have keys distributed across many buckets, and would exceed
// maxValidateMemoryUsageMB, we report as many inconsistencies as we can.
for (let i = 0; i < 10; ++i) {
const indexKey = i.toString().repeat(kIndexKeyLength / 5);
assert.commandWorked(coll.insert({_id: indexKey}));
}
// Insert a document with a small key so that validate reports one missing index entry.
assert.commandWorked(coll.insert({_id: 1}));
corruptIndex();
checkValidate(notAllReportedPrefix, 1);
// If each key is maxMem/5, then we can keep 4 of them (the 5th would put us at the limit). However,
// each key is counted twice, so realistically we only expect to track 2 of them. However, there's
// a small chance we could get hash collisions that would lead to us reporting only 1.
checkValidate(1, {minMissingKeys: 1, maxMissingKeys: 2});
// Repair, but incompletely if only some inconsistencies are reported.
checkValidateRepair(true);
checkValidateRepair();
MongoRunner.stopMongod(conn, null, {skipValidation: true});
})();

View File

@ -0,0 +1,32 @@
/**
* Tests that the telemetry store can be resized if it is configured, and cannot be resized if it is
* disabled.
*/
(function() {
"use strict";
load("jstests/libs/feature_flag_util.js");
if (FeatureFlagUtil.isEnabled(db, "Telemetry")) {
// The feature flag is enabled - make sure the telemetry store can be configured.
const original = assert.commandWorked(
db.adminCommand({getParameter: 1, internalQueryConfigureTelemetryCacheSize: 1}));
assert(original.hasOwnProperty("internalQueryConfigureTelemetryCacheSize"), original);
const originalValue = original.internalQueryConfigureTelemetryCacheSize;
try {
assert.doesNotThrow(
() => db.adminCommand(
{setParameter: 1, internalQueryConfigureTelemetryCacheSize: '2MB'}));
// Other tests verify that resizing actually affects the data structure size.
} finally {
assert.doesNotThrow(
() => db.adminCommand(
{setParameter: 1, internalQueryConfigureTelemetryCacheSize: originalValue}));
}
} else {
// The feature flag is disabled - make sure the telemetry store *cannot* be configured.
assert.commandFailedWithCode(
db.adminCommand({setParameter: 1, internalQueryConfigureTelemetryCacheSize: '2MB'}),
7373500);
}
}());

View File

@ -0,0 +1,33 @@
/**
* Tests that the validate checkBSONConformance option works with various BSON types.
*/
(function() {
const coll = db.validate_bson_types;
assert.commandWorked(coll.insert({a: 1.0})); // double
assert.commandWorked(coll.insert({b: "abc"})); // string
assert.commandWorked(coll.insert({c: {x: 1}})); // object
assert.commandWorked(coll.insert({d: [1, 2, 3]})); // array
assert.commandWorked(coll.insert({
e: BinData(2, "KwAAAFRoZSBxdWljayBicm93biBmb3gganVtcHMgb3ZlciB0aGUgbGF6eSBkb2c=")
})); // binData
assert.commandWorked(coll.insert({f: undefined})); // undefined
assert.commandWorked(coll.insert({g: ObjectId("dbdbdbdbdbdbdbdbdbdbdbdb")})); // objectId
assert.commandWorked(coll.insert({h: true})); // boolean
assert.commandWorked(coll.insert({i: ISODate("2013-12-11T19:38:24.055Z")})); // UTC
assert.commandWorked(coll.insert({j: null})); // null
assert.commandWorked(coll.insert({k: RegExp("a")})); // regex
assert.commandWorked(
coll.insert({l: DBPointer("foo", ObjectId("bbbbbbbbbbbbbbbbbbbbbbbb"))})); // DBPointer
assert.commandWorked(coll.insert({m: Code("noScope")})); // code
assert.commandWorked(coll.insert({n: Code('function(){return 1;}', {})})); // code w/ scope
assert.commandWorked(coll.insert({o: 3})); // int
assert.commandWorked(coll.insert({p: Timestamp(1, 2)})); // timestamp
assert.commandWorked(coll.insert({q: NumberLong(6)})); // 64-bit int
assert.commandWorked(coll.insert({r: NumberDecimal("2.0")})); // decimal 128
assert.commandWorked(coll.insert({s: MinKey()})); // MinKey
assert.commandWorked(coll.insert({t: MaxKey()})); // MaxKey
assert.commandWorked(coll.validate({checkBSONConformance: true}));
})();

View File

@ -22,6 +22,8 @@ const fullNs = dbName + "." + collName;
// Pre-written reasons for skipping a test.
const isAnInternalCommand = "internal command";
const isDeprecated = "deprecated command";
// TODO SERVER-69753 some commands we didn't have time for. Other commands are new in recent
// releases and don't make sense to test here.
const isNotImplementedYet = "not implemented yet";
let _lsid = UUID();
@ -1097,6 +1099,7 @@ const allCommands = {
setIndexCommitQuorum: {skip: isNotImplementedYet},
setFeatureCompatibilityVersion: {skip: isNotImplementedYet},
setFreeMonitoring: {skip: isNotImplementedYet},
setProfilingFilterGlobally: {skip: isNotImplementedYet},
setParameter: {skip: isNotImplementedYet},
setShardVersion: {skip: isNotImplementedYet},
setChangeStreamState: {skip: isNotImplementedYet},

View File

@ -365,6 +365,7 @@ const allCommands = {
setIndexCommitQuorum: {skip: isPrimaryOnly},
setFeatureCompatibilityVersion: {skip: isPrimaryOnly},
setFreeMonitoring: {skip: isPrimaryOnly},
setProfilingFilterGlobally: {skip: isNotAUserDataRead},
setParameter: {skip: isNotAUserDataRead},
setShardVersion: {skip: isNotAUserDataRead},
setChangeStreamState: {skip: isNotAUserDataRead},

View File

@ -18,15 +18,12 @@ var coll = primary.getDB('test').getCollection(name);
assert.commandWorked(coll.insert({_id: 0, x: 1}));
assert.commandWorked(coll.runCommand("collMod", {"validator": {a: {$exists: true}}}));
secondary = replSet.restart(secondary, {startClean: true, skipValidation: true});
secondary = replSet.restart(secondary, {startClean: true});
replSet.awaitReplication();
replSet.awaitSecondaryNodes();
assert.eq(1, secondary.getDB("test")[name].count());
assert.docEq({_id: 0, x: 1}, secondary.getDB("test")[name].findOne());
// Set the validationAction to "warn" to avoid failing collection validation.
assert.commandWorked(coll.runCommand("collMod", {validationAction: "warn"}));
replSet.stopSet();
})();

View File

@ -0,0 +1,194 @@
/**
* Test that oplog (on both primary and secondary) rolls over when its size exceeds the configured
* maximum, with parameters for setting the initial sync method and the storage engine.
*/
"use strict";
load("jstests/libs/fail_point_util.js");
function oplogRolloverTest(storageEngine, initialSyncMethod) {
jsTestLog("Testing with storageEngine: " + storageEngine);
if (initialSyncMethod) {
jsTestLog(" and initial sync method: " + initialSyncMethod);
}
// Pause the oplog cap maintainer thread for this test until oplog truncation is needed. The
// truncation thread can hold a mutex for a short period of time which prevents new oplog stones
// from being created during an insertion if the mutex cannot be obtained immediately. Instead,
// the next insertion will attempt to create a new oplog stone, which this test does not do.
let parameters = {
logComponentVerbosity: tojson({storage: 2}),
'failpoint.hangOplogCapMaintainerThread': tojson({mode: 'alwaysOn'})
};
if (initialSyncMethod) {
parameters = Object.merge(parameters, {initialSyncMethod: initialSyncMethod});
}
const replSet = new ReplSetTest({
// Set the syncdelay to 1s to speed up checkpointing.
nodeOptions: {
syncdelay: 1,
setParameter: parameters,
},
nodes: [{}, {rsConfig: {priority: 0, votes: 0}}]
});
// Set max oplog size to 1MB.
replSet.startSet({storageEngine: storageEngine, oplogSize: 1});
replSet.initiate();
const primary = replSet.getPrimary();
const primaryOplog = primary.getDB("local").oplog.rs;
const secondary = replSet.getSecondary();
const secondaryOplog = secondary.getDB("local").oplog.rs;
// Verify that the oplog cap maintainer thread is paused.
assert.commandWorked(primary.adminCommand({
waitForFailPoint: "hangOplogCapMaintainerThread",
timesEntered: 1,
maxTimeMS: kDefaultWaitForFailPointTimeout
}));
assert.commandWorked(secondary.adminCommand({
waitForFailPoint: "hangOplogCapMaintainerThread",
timesEntered: 1,
maxTimeMS: kDefaultWaitForFailPointTimeout
}));
const coll = primary.getDB("test").foo;
// 400KB each so that oplog can keep at most two insert oplog entries.
const longString = new Array(400 * 1024).join("a");
function numInsertOplogEntry(oplog) {
print(`Oplog times for ${oplog.getMongo().host}: ${
tojsononeline(oplog.find().projection({ts: 1, t: 1, op: 1, ns: 1}).toArray())}`);
return oplog.find({op: "i", "ns": "test.foo"}).itcount();
}
// Insert the first document.
const firstInsertTimestamp =
assert
.commandWorked(coll.runCommand(
"insert", {documents: [{_id: 0, longString: longString}], writeConcern: {w: 2}}))
.operationTime;
jsTestLog("First insert timestamp: " + tojson(firstInsertTimestamp));
// Test that oplog entry of the first insert exists on both primary and secondary.
assert.eq(1, numInsertOplogEntry(primaryOplog));
assert.eq(1, numInsertOplogEntry(secondaryOplog));
// Insert the second document.
const secondInsertTimestamp =
assert
.commandWorked(coll.runCommand(
"insert", {documents: [{_id: 1, longString: longString}], writeConcern: {w: 2}}))
.operationTime;
jsTestLog("Second insert timestamp: " + tojson(secondInsertTimestamp));
// Test that oplog entries of both inserts exist on both primary and secondary.
assert.eq(2, numInsertOplogEntry(primaryOplog));
assert.eq(2, numInsertOplogEntry(secondaryOplog));
// Have a more fine-grained test for enableMajorityReadConcern=true to also test oplog
// truncation happens at the time we expect it to happen. When
// enableMajorityReadConcern=false the lastStableRecoveryTimestamp is not available, so
// switch to a coarser-grained mode to only test that oplog truncation will eventually
// happen when oplog size exceeds the configured maximum.
if (primary.getDB('admin').serverStatus().storageEngine.supportsCommittedReads) {
const awaitCheckpointer = function(timestamp) {
assert.soon(
() => {
const primaryTimestamp =
assert.commandWorked(primary.adminCommand({replSetGetStatus: 1}))
.lastStableRecoveryTimestamp;
const secondaryTimestamp =
assert.commandWorked(secondary.adminCommand({replSetGetStatus: 1}))
.lastStableRecoveryTimestamp;
jsTestLog("Awaiting last stable recovery timestamp " +
`(primary: ${tojson(primaryTimestamp)}, secondary: ${
tojson(secondaryTimestamp)}) ` +
`target: ${tojson(timestamp)}`);
return ((timestampCmp(primaryTimestamp, timestamp) >= 0) &&
(timestampCmp(secondaryTimestamp, timestamp) >= 0));
},
"Timeout waiting for checkpointing to catch up",
ReplSetTest.kDefaultTimeoutMS,
2000);
};
// Wait for checkpointing/stable timestamp to catch up with the second insert so oplog
// entry of the first insert is allowed to be deleted by the oplog cap maintainer thread
// when a new oplog stone is created. "inMemory" WT engine does not run checkpoint
// thread and lastStableRecoveryTimestamp is the stable timestamp in this case.
awaitCheckpointer(secondInsertTimestamp);
// Insert the third document which will trigger a new oplog stone to be created. The
// oplog cap maintainer thread will then be unblocked on the creation of the new oplog
// stone and will start truncating oplog entries. The oplog entry for the first
// insert will be truncated after the oplog cap maintainer thread finishes.
const thirdInsertTimestamp =
assert
.commandWorked(coll.runCommand(
"insert",
{documents: [{_id: 2, longString: longString}], writeConcern: {w: 2}}))
.operationTime;
jsTestLog("Third insert timestamp: " + tojson(thirdInsertTimestamp));
// There is a race between how we calculate the pinnedOplog and checkpointing. The timestamp
// of the pinnedOplog could be less than the actual stable timestamp used in a checkpoint.
// Wait for the checkpointer to run for another round to make sure the first insert oplog is
// not pinned.
awaitCheckpointer(thirdInsertTimestamp);
// Verify that there are three oplog entries while the oplog cap maintainer thread is
// paused.
assert.eq(3, numInsertOplogEntry(primaryOplog));
assert.eq(3, numInsertOplogEntry(secondaryOplog));
// Let the oplog cap maintainer thread start truncating the oplog.
assert.commandWorked(primary.adminCommand(
{configureFailPoint: "hangOplogCapMaintainerThread", mode: "off"}));
assert.commandWorked(secondary.adminCommand(
{configureFailPoint: "hangOplogCapMaintainerThread", mode: "off"}));
// Test that oplog entry of the initial insert rolls over on both primary and secondary.
// Use assert.soon to wait for oplog cap maintainer thread to run.
assert.soon(() => {
return numInsertOplogEntry(primaryOplog) === 2;
}, "Timeout waiting for oplog to roll over on primary");
assert.soon(() => {
return numInsertOplogEntry(secondaryOplog) === 2;
}, "Timeout waiting for oplog to roll over on secondary");
const res = primary.getDB("test").runCommand({serverStatus: 1});
assert.commandWorked(res);
assert.eq(res.oplogTruncation.truncateCount, 1, tojson(res.oplogTruncation));
assert.gt(res.oplogTruncation.totalTimeTruncatingMicros, 0, tojson(res.oplogTruncation));
} else {
// Let the oplog cap maintainer thread start truncating the oplog.
assert.commandWorked(primary.adminCommand(
{configureFailPoint: "hangOplogCapMaintainerThread", mode: "off"}));
assert.commandWorked(secondary.adminCommand(
{configureFailPoint: "hangOplogCapMaintainerThread", mode: "off"}));
// Only test that oplog truncation will eventually happen.
let numInserted = 2;
assert.soon(function() {
// Insert more documents.
assert.commandWorked(
coll.insert({_id: numInserted++, longString: longString}, {writeConcern: {w: 2}}));
const numInsertOplogEntryPrimary = numInsertOplogEntry(primaryOplog);
const numInsertOplogEntrySecondary = numInsertOplogEntry(secondaryOplog);
// Oplog has been truncated if the number of insert oplog entries is less than
// number of inserted.
if (numInsertOplogEntryPrimary < numInserted &&
numInsertOplogEntrySecondary < numInserted)
return true;
jsTestLog("Awaiting oplog truncation: number of oplog entries: " +
`(primary: ${tojson(numInsertOplogEntryPrimary)}, ` +
`secondary: ${tojson(numInsertOplogEntrySecondary)}) ` +
`number inserted: ${numInserted}`);
return false;
}, "Timeout waiting for oplog to roll over", ReplSetTest.kDefaultTimeoutMS, 1000);
}
replSet.stopSet();
}

View File

@ -5,188 +5,9 @@
(function() {
"use strict";
load("jstests/libs/fail_point_util.js");
load("jstests/replsets/libs/oplog_rollover_test.js");
function doTest(storageEngine) {
jsTestLog("Testing with storageEngine: " + storageEngine);
// Pause the oplog cap maintainer thread for this test until oplog truncation is needed. The
// truncation thread can hold a mutex for a short period of time which prevents new oplog stones
// from being created during an insertion if the mutex cannot be obtained immediately. Instead,
// the next insertion will attempt to create a new oplog stone, which this test does not do.
const replSet = new ReplSetTest({
// Set the syncdelay to 1s to speed up checkpointing.
nodeOptions: {
syncdelay: 1,
setParameter: {
logComponentVerbosity: tojson({storage: 2}),
'failpoint.hangOplogCapMaintainerThread': tojson({mode: 'alwaysOn'})
}
},
nodes: [{}, {rsConfig: {priority: 0, votes: 0}}]
});
// Set max oplog size to 1MB.
replSet.startSet({storageEngine: storageEngine, oplogSize: 1});
replSet.initiate();
const primary = replSet.getPrimary();
const primaryOplog = primary.getDB("local").oplog.rs;
const secondary = replSet.getSecondary();
const secondaryOplog = secondary.getDB("local").oplog.rs;
// Verify that the oplog cap maintainer thread is paused.
assert.commandWorked(primary.adminCommand({
waitForFailPoint: "hangOplogCapMaintainerThread",
timesEntered: 1,
maxTimeMS: kDefaultWaitForFailPointTimeout
}));
assert.commandWorked(secondary.adminCommand({
waitForFailPoint: "hangOplogCapMaintainerThread",
timesEntered: 1,
maxTimeMS: kDefaultWaitForFailPointTimeout
}));
const coll = primary.getDB("test").foo;
// 400KB each so that oplog can keep at most two insert oplog entries.
const longString = new Array(400 * 1024).join("a");
function numInsertOplogEntry(oplog) {
print(`Oplog times for ${oplog.getMongo().host}: ${
tojsononeline(oplog.find().projection({ts: 1, t: 1, op: 1, ns: 1}).toArray())}`);
return oplog.find({op: "i", "ns": "test.foo"}).itcount();
}
// Insert the first document.
const firstInsertTimestamp =
assert
.commandWorked(coll.runCommand(
"insert", {documents: [{_id: 0, longString: longString}], writeConcern: {w: 2}}))
.operationTime;
jsTestLog("First insert timestamp: " + tojson(firstInsertTimestamp));
// Test that oplog entry of the first insert exists on both primary and secondary.
assert.eq(1, numInsertOplogEntry(primaryOplog));
assert.eq(1, numInsertOplogEntry(secondaryOplog));
// Insert the second document.
const secondInsertTimestamp =
assert
.commandWorked(coll.runCommand(
"insert", {documents: [{_id: 1, longString: longString}], writeConcern: {w: 2}}))
.operationTime;
jsTestLog("Second insert timestamp: " + tojson(secondInsertTimestamp));
// Test that oplog entries of both inserts exist on both primary and secondary.
assert.eq(2, numInsertOplogEntry(primaryOplog));
assert.eq(2, numInsertOplogEntry(secondaryOplog));
// Have a more fine-grained test for enableMajorityReadConcern=true to also test oplog
// truncation happens at the time we expect it to happen. When
// enableMajorityReadConcern=false the lastStableRecoveryTimestamp is not available, so
// switch to a coarser-grained mode to only test that oplog truncation will eventually
// happen when oplog size exceeds the configured maximum.
if (primary.getDB('admin').serverStatus().storageEngine.supportsCommittedReads) {
const awaitCheckpointer = function(timestamp) {
assert.soon(
() => {
const primaryTimestamp =
assert.commandWorked(primary.adminCommand({replSetGetStatus: 1}))
.lastStableRecoveryTimestamp;
const secondaryTimestamp =
assert.commandWorked(secondary.adminCommand({replSetGetStatus: 1}))
.lastStableRecoveryTimestamp;
jsTestLog("Awaiting last stable recovery timestamp " +
`(primary: ${tojson(primaryTimestamp)}, secondary: ${
tojson(secondaryTimestamp)}) ` +
`target: ${tojson(timestamp)}`);
return ((timestampCmp(primaryTimestamp, timestamp) >= 0) &&
(timestampCmp(secondaryTimestamp, timestamp) >= 0));
},
"Timeout waiting for checkpointing to catch up",
ReplSetTest.kDefaultTimeoutMS,
2000);
};
// Wait for checkpointing/stable timestamp to catch up with the second insert so oplog
// entry of the first insert is allowed to be deleted by the oplog cap maintainer thread
// when a new oplog stone is created. "inMemory" WT engine does not run checkpoint
// thread and lastStableRecoveryTimestamp is the stable timestamp in this case.
awaitCheckpointer(secondInsertTimestamp);
// Insert the third document which will trigger a new oplog stone to be created. The
// oplog cap maintainer thread will then be unblocked on the creation of the new oplog
// stone and will start truncating oplog entries. The oplog entry for the first
// insert will be truncated after the oplog cap maintainer thread finishes.
const thirdInsertTimestamp =
assert
.commandWorked(coll.runCommand(
"insert",
{documents: [{_id: 2, longString: longString}], writeConcern: {w: 2}}))
.operationTime;
jsTestLog("Third insert timestamp: " + tojson(thirdInsertTimestamp));
// There is a race between how we calculate the pinnedOplog and checkpointing. The timestamp
// of the pinnedOplog could be less than the actual stable timestamp used in a checkpoint.
// Wait for the checkpointer to run for another round to make sure the first insert oplog is
// not pinned.
awaitCheckpointer(thirdInsertTimestamp);
// Verify that there are three oplog entries while the oplog cap maintainer thread is
// paused.
assert.eq(3, numInsertOplogEntry(primaryOplog));
assert.eq(3, numInsertOplogEntry(secondaryOplog));
// Let the oplog cap maintainer thread start truncating the oplog.
assert.commandWorked(primary.adminCommand(
{configureFailPoint: "hangOplogCapMaintainerThread", mode: "off"}));
assert.commandWorked(secondary.adminCommand(
{configureFailPoint: "hangOplogCapMaintainerThread", mode: "off"}));
// Test that oplog entry of the initial insert rolls over on both primary and secondary.
// Use assert.soon to wait for oplog cap maintainer thread to run.
assert.soon(() => {
return numInsertOplogEntry(primaryOplog) === 2;
}, "Timeout waiting for oplog to roll over on primary");
assert.soon(() => {
return numInsertOplogEntry(secondaryOplog) === 2;
}, "Timeout waiting for oplog to roll over on secondary");
const res = primary.getDB("test").runCommand({serverStatus: 1});
assert.commandWorked(res);
assert.eq(res.oplogTruncation.truncateCount, 1, tojson(res.oplogTruncation));
assert.gt(res.oplogTruncation.totalTimeTruncatingMicros, 0, tojson(res.oplogTruncation));
} else {
// Let the oplog cap maintainer thread start truncating the oplog.
assert.commandWorked(primary.adminCommand(
{configureFailPoint: "hangOplogCapMaintainerThread", mode: "off"}));
assert.commandWorked(secondary.adminCommand(
{configureFailPoint: "hangOplogCapMaintainerThread", mode: "off"}));
// Only test that oplog truncation will eventually happen.
let numInserted = 2;
assert.soon(function() {
// Insert more documents.
assert.commandWorked(
coll.insert({_id: numInserted++, longString: longString}, {writeConcern: {w: 2}}));
const numInsertOplogEntryPrimary = numInsertOplogEntry(primaryOplog);
const numInsertOplogEntrySecondary = numInsertOplogEntry(secondaryOplog);
// Oplog has been truncated if the number of insert oplog entries is less than
// number of inserted.
if (numInsertOplogEntryPrimary < numInserted &&
numInsertOplogEntrySecondary < numInserted)
return true;
jsTestLog("Awaiting oplog truncation: number of oplog entries: " +
`(primary: ${tojson(numInsertOplogEntryPrimary)}, ` +
`secondary: ${tojson(numInsertOplogEntrySecondary)}) ` +
`number inserted: ${numInserted}`);
return false;
}, "Timeout waiting for oplog to roll over", ReplSetTest.kDefaultTimeoutMS, 1000);
}
replSet.stopSet();
}
doTest("wiredTiger");
oplogRolloverTest("wiredTiger");
if (jsTest.options().storageEngine !== "inMemory") {
jsTestLog(
@ -194,5 +15,5 @@ if (jsTest.options().storageEngine !== "inMemory") {
return;
}
doTest("inMemory");
oplogRolloverTest("inMemory");
})();

View File

@ -5,6 +5,8 @@
(function() {
"use strict";
load("jstests/replsets/rslib.js");
// Skip db hash check because secondary is left with a different config.
TestData.skipCheckDBHashes = true;
@ -33,6 +35,10 @@ const lastOp = primaryOplog.find(expectedNoOp).sort({'$natural': -1}).limit(1).t
assert(lastOp.length > 0);
replTest.awaitReplication();
// Make sure that all nodes have installed the config before moving on.
replTest.waitForConfigReplication(primary, nodes);
assert.soonNoExcept(() => isConfigCommitted(primary));
jsTestLog("Invalid reconfig");
config.version++;
var badMember = {_id: numNodes, host: "localhost:12345", priority: "High"};

Some files were not shown because too many files have changed in this diff Show More