Revert "SERVER-115077 Implement a test extension that uses ViewPolicy… (#46967)

GitOrigin-RevId: b279a40b3a19b069872232d891c7f9244fca204d
This commit is contained in:
Finley Lau
2026-01-26 14:00:29 -05:00
committed by MongoDB Bot
parent f54e1e6565
commit d7806ebc14
4 changed files with 0 additions and 452 deletions

View File

@@ -1,93 +0,0 @@
/**
* This test verifies that the $addViewName extension stage correctly passes the view name
* through the extension boundary (AstNode -> LogicalStage -> ExecAggStage) and adds
* it as a field in output documents.
*
* This test also verifies that the $disallowViews extension stage correctly uasserts when
* used in a view context.
*
* @tags: [featureFlagExtensionsAPI]
*/
const coll = db[jsTestName()];
coll.drop();
assert.commandWorked(coll.insertMany([{x: 1}, {x: 2}, {x: 3}]));
function createView(viewName, viewPipeline) {
assert.commandWorked(db.createView(viewName, jsTestName(), viewPipeline));
return {
view: db[viewName],
viewName,
viewNss: `${db.getName()}.${viewName}`,
};
}
function dropView(viewName) {
assert.commandWorked(db.runCommand({drop: viewName}));
}
function verifyViewName(results, expectedViewNss) {
results.forEach((doc, index) => {
assert(doc.hasOwnProperty("viewName"), `Document ${index} should have viewName field: ${tojson(doc)}`);
assert.eq(
doc.viewName,
expectedViewNss,
`Document ${index} should have viewName field equal to "${expectedViewNss}": ${tojson(doc)}`,
);
});
}
function testViewNameOnView(view, pipeline, expectedViewNss) {
const result = view.view.aggregate(pipeline).toArray();
verifyViewName(result, expectedViewNss);
}
function testViewNameWithTemporaryView(viewName, viewPipeline, pipeline, expectedViewNss) {
const testView = createView(viewName, viewPipeline);
testViewNameOnView(testView, pipeline, expectedViewNss);
dropView(testView.viewName);
}
const viewPipeline = [{$sort: {_id: 1}}];
const view = createView("test_view", viewPipeline);
// Tests that the view name is present at execution time.
testViewNameOnView(view, [{$addViewName: {}}], view.viewNss);
// Tests that the view name is present if the view is on an extension stage.
testViewNameWithTemporaryView("foo_view", [{$testFoo: {}}], [{$addViewName: {}}], `${db.getName()}.foo_view`);
// Tests view name is empty if the $addViewName stage is in the view.
testViewNameWithTemporaryView("add_foo_view", [{$addViewName: {}}], [{$testFoo: {}}], "");
// Tests that view name is added if the $addViewName stage is later on in the pipeline.
testViewNameOnView(view, [{$sort: {_id: -1}}, {$addViewName: {}}], view.viewNss);
// Tests that the view name is added if the $addViewName is desugared into.
testViewNameOnView(view, [{$sort: {_id: 1}}, {$desugarAddViewName: {}}], view.viewNss);
function testDisallowViewsFails(viewName, pipeline) {
assert.commandFailedWithCode(
db.runCommand({
aggregate: viewName,
pipeline: pipeline,
cursor: {},
}),
11507700,
);
}
// Test that $disallowViews stage uasserts when run on a view.
testDisallowViewsFails(view.viewName, [{$disallowViews: {}}]);
// Test that $disallowViews stage uasserts when run on a view, even when not the first stage in a pipeline.
testDisallowViewsFails(view.viewName, [{$project: {_id: 0}}, {$disallowViews: {}}]);
{
// Test that $disallowViews stage works correctly on a regular collection.
coll.aggregate([{$disallowViews: {}}]);
// Test that $disallowViews stage can be used inside a view pipeline
const viewWithDisallowViews = createView("new_view", [{$disallowViews: {}}]);
viewWithDisallowViews.view.aggregate([{$project: {_id: 1}}]);
dropView(viewWithDisallowViews.viewName);
}

View File

@@ -53,8 +53,6 @@ extensions_with_config(
":other_metrics_mongo_extension_signed_lib",
":sleep_mongo_extension_signed_lib",
":vector_search_optimization_mongo_extension_signed_lib",
":disallow_view_mongo_extension_signed_lib",
":desugar_add_view_name_mongo_extension_signed_lib",
#################### EXTENSIONS FOR NO-PASSTHROUGH TESTS ####################
# Any extension that is just loaded in a no-passthrough test MUST NOT have the
@@ -85,8 +83,6 @@ pkg_name = "//" + package_name() + "/"
"foo_v2",
"bar",
"read_n_documents",
"disallow_view",
"desugar_add_view_name",
]
]

View File

@@ -1,277 +0,0 @@
/**
* Copyright (C) 2026-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/extension/sdk/aggregation_stage.h"
#include "mongo/db/extension/sdk/extension_factory.h"
#include "mongo/db/extension/sdk/log_util.h"
#include "mongo/db/extension/sdk/test_extension_factory.h"
#include "mongo/db/extension/shared/get_next_result.h"
namespace sdk = mongo::extension::sdk;
using namespace mongo;
/**
* Test extension that desugars into $addViewName followed by a stage that returns
* FirstStageViewApplicationPolicy::kDoNothing.
*/
class AddViewNameExecStage : public sdk::ExecAggStageTransform {
public:
AddViewNameExecStage(std::string_view stageName,
const mongo::BSONObj& arguments,
std::string viewName)
: sdk::ExecAggStageTransform(stageName),
_arguments(arguments.getOwned()),
_viewName(std::move(viewName)) {}
mongo::extension::ExtensionGetNextResult getNext(
const mongo::extension::sdk::QueryExecutionContextHandle& execCtx,
::MongoExtensionExecAggStage* execStage) override {
auto input = _getSource()->getNext(execCtx.get());
if (input.code == mongo::extension::GetNextCode::kPauseExecution) {
return mongo::extension::ExtensionGetNextResult::pauseExecution();
}
if (input.code == mongo::extension::GetNextCode::kEOF) {
return mongo::extension::ExtensionGetNextResult::eof();
}
mongo::BSONObj inputDoc = input.resultDocument->getUnownedBSONObj();
mongo::BSONObjBuilder bob;
bob.appendElements(inputDoc);
bob.append("viewName", _viewName);
auto resultDoc = mongo::extension::ExtensionBSONObj::makeAsByteBuf(bob.done());
if (input.resultMetadata.has_value()) {
return mongo::extension::ExtensionGetNextResult::advanced(
std::move(resultDoc),
mongo::extension::ExtensionBSONObj::makeAsByteBuf(
input.resultMetadata->getUnownedBSONObj()));
} else {
return mongo::extension::ExtensionGetNextResult::advanced(std::move(resultDoc));
}
}
void open() override {}
void reopen() override {}
void close() override {}
mongo::BSONObj explain(::MongoExtensionExplainVerbosity verbosity) const override {
mongo::BSONObjBuilder bob;
bob.append("viewName", _viewName);
return bob.obj();
}
std::string getViewName() const {
return _viewName;
}
private:
const mongo::BSONObj _arguments;
const std::string _viewName;
};
class AddViewNameLogicalStage : public sdk::LogicalAggStage {
public:
AddViewNameLogicalStage(std::string_view stageName,
const mongo::BSONObj& arguments,
std::string viewName)
: sdk::LogicalAggStage(stageName),
_arguments(arguments.getOwned()),
_viewName(std::move(viewName)) {}
mongo::BSONObj serialize() const override {
mongo::BSONObjBuilder bob;
mongo::BSONObjBuilder stageBuilder;
stageBuilder.appendElements(_arguments);
// Include view name in serialization if it was set via bindViewInfo() so that the shard
// receives BSON with the view info after the view has been handled on the router.
if (!_viewName.empty()) {
stageBuilder.append("_viewName", _viewName);
}
bob.append(_name, stageBuilder.obj());
return bob.obj();
}
mongo::BSONObj explain(::MongoExtensionExplainVerbosity verbosity) const override {
mongo::BSONObjBuilder bob;
bob.append(_name, _arguments);
return bob.obj();
}
std::unique_ptr<sdk::ExecAggStageBase> compile() const override {
return std::make_unique<AddViewNameExecStage>(_name, _arguments, _viewName);
}
boost::optional<sdk::DistributedPlanLogic> getDistributedPlanLogic() const override {
return boost::none;
}
std::unique_ptr<sdk::LogicalAggStage> clone() const override {
return std::make_unique<AddViewNameLogicalStage>(_name, _arguments, _viewName);
}
private:
const mongo::BSONObj _arguments;
const std::string _viewName;
};
class AddViewNameAstNode : public sdk::AggStageAstNode {
public:
AddViewNameAstNode(std::string_view stageName, const mongo::BSONObj& arguments)
: sdk::AggStageAstNode(stageName), _arguments([&]() {
// Extract view name from BSON if it was serialized (e.g., when coming from mongos).
// Store the original arguments without _viewName (which is an internal field).
mongo::BSONObjBuilder argsBuilder;
for (auto elem : arguments) {
if (elem.fieldNameStringData() != "_viewName") {
argsBuilder.append(elem);
}
}
return argsBuilder.obj();
}()) {
// Extract _viewName separately if it exists.
auto elem = arguments.getField("_viewName");
if (!elem.eoo() && elem.type() == BSONType::string) {
_viewName = elem.str();
}
}
void bindViewInfo(std::string_view viewName) const override {
_viewName = std::string(viewName);
}
MongoExtensionFirstStageViewApplicationPolicy getFirstStageViewApplicationPolicy()
const override {
return MongoExtensionFirstStageViewApplicationPolicy::kDoNothing;
}
std::unique_ptr<sdk::LogicalAggStage> bind(
const ::MongoExtensionCatalogContext& catalogContext) const override {
return std::make_unique<AddViewNameLogicalStage>(getName(), _arguments, _viewName);
}
std::unique_ptr<sdk::AggStageAstNode> clone() const override {
auto cloned = std::make_unique<AddViewNameAstNode>(getName(), _arguments);
cloned->_viewName = _viewName;
return cloned;
}
private:
const mongo::BSONObj _arguments;
mutable std::string _viewName;
};
DEFAULT_PARSE_NODE(AddViewName)
using AddViewNameStageDescriptor =
sdk::TestStageDescriptor<"$addViewName", AddViewNameParseNode, false>;
DEFAULT_EXEC_STAGE(DoNothingViewPolicy)
DEFAULT_LOGICAL_STAGE(DoNothingViewPolicy)
class DoNothingViewPolicyAstNode : public sdk::AggStageAstNode {
public:
DoNothingViewPolicyAstNode(std::string_view stageName, const mongo::BSONObj& arguments)
: sdk::AggStageAstNode(stageName), _arguments(arguments.getOwned()) {}
MongoExtensionFirstStageViewApplicationPolicy getFirstStageViewApplicationPolicy()
const override {
return MongoExtensionFirstStageViewApplicationPolicy::kDoNothing;
}
std::unique_ptr<sdk::LogicalAggStage> bind(
const ::MongoExtensionCatalogContext& catalogContext) const override {
return std::make_unique<DoNothingViewPolicyLogicalStage>(getName(), _arguments);
}
std::unique_ptr<sdk::AggStageAstNode> clone() const override {
return std::make_unique<DoNothingViewPolicyAstNode>(getName(), _arguments);
}
private:
const mongo::BSONObj _arguments;
};
DEFAULT_PARSE_NODE(DoNothingViewPolicy)
using DoNothingViewPolicyStageDescriptor =
sdk::TestStageDescriptor<"$doNothingViewPolicy", DoNothingViewPolicyParseNode, true>;
class DesugarAddViewNameParseNode : public sdk::AggStageParseNode {
public:
DesugarAddViewNameParseNode(std::string_view stageName, const mongo::BSONObj& arguments)
: sdk::AggStageParseNode(stageName), _arguments(arguments.getOwned()) {}
size_t getExpandedSize() const override {
return 2;
}
std::vector<mongo::extension::VariantNodeHandle> expand() const override {
std::vector<mongo::extension::VariantNodeHandle> expanded;
expanded.reserve(2);
// First stage: $addViewName (as ExtensionAggStageParseNode)
expanded.emplace_back(new sdk::ExtensionAggStageParseNode(
std::make_unique<AddViewNameParseNode>("$addViewName", BSONObj())));
// Second stage: DoNothingViewPolicy stage that returns kDoNothing
expanded.emplace_back(new sdk::ExtensionAggStageAstNode(
std::make_unique<DoNothingViewPolicyAstNode>("$doNothingViewPolicy", _arguments)));
return expanded;
}
mongo::BSONObj getQueryShape(const sdk::QueryShapeOptsHandle& ctx) const override {
return BSON(_name << _arguments);
}
std::unique_ptr<sdk::AggStageParseNode> clone() const override {
return std::make_unique<DesugarAddViewNameParseNode>(_name, _arguments);
}
private:
const mongo::BSONObj _arguments;
};
using DesugarAddViewNameStageDescriptor =
sdk::TestStageDescriptor<"$desugarAddViewName", DesugarAddViewNameParseNode, true>;
class DesugarAddViewNameExtension : public sdk::Extension {
public:
void initialize(const sdk::HostPortalHandle& portal) override {
_registerStage<DesugarAddViewNameStageDescriptor>(portal);
_registerStage<DoNothingViewPolicyStageDescriptor>(portal);
_registerStage<AddViewNameStageDescriptor>(portal);
}
};
REGISTER_EXTENSION(DesugarAddViewNameExtension)
DEFINE_GET_EXTENSION()

View File

@@ -1,78 +0,0 @@
/**
* Copyright (C) 2026-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/bson/bsonobj.h"
#include "mongo/db/extension/sdk/aggregation_stage.h"
#include "mongo/db/extension/sdk/assert_util.h"
#include "mongo/db/extension/sdk/extension_factory.h"
#include "mongo/db/extension/sdk/test_extension_factory.h"
namespace sdk = mongo::extension::sdk;
using namespace mongo;
/**
* Test extension that disallows views by uasserting in its bindViewInfo implementation.
*/
DEFAULT_EXEC_STAGE(DisallowView)
DEFAULT_LOGICAL_STAGE(DisallowView)
class DisallowViewAstNode : public sdk::AggStageAstNode {
public:
DisallowViewAstNode(std::string_view stageName, const mongo::BSONObj& arguments)
: sdk::AggStageAstNode(stageName), _arguments(arguments.getOwned()) {}
void bindViewInfo(std::string_view viewName) const override {
std::string message = str::stream()
<< "Stage " << std::string(getName())
<< " does not support views. Attempted to use in view: " << std::string(viewName);
sdk_uasserted(11507700, message);
}
std::unique_ptr<sdk::LogicalAggStage> bind(
const ::MongoExtensionCatalogContext& catalogContext) const override {
return std::make_unique<DisallowViewLogicalStage>(getName(), _arguments);
}
std::unique_ptr<sdk::AggStageAstNode> clone() const override {
return std::make_unique<DisallowViewAstNode>(getName(), _arguments);
}
private:
const mongo::BSONObj _arguments;
};
DEFAULT_PARSE_NODE(DisallowView)
using DisallowViewStageDescriptor =
sdk::TestStageDescriptor<"$disallowViews", DisallowViewParseNode, true>;
DEFAULT_EXTENSION(DisallowView)
REGISTER_EXTENSION(DisallowViewExtension)
DEFINE_GET_EXTENSION()