This is an automated email from the ASF dual-hosted git repository.

gavinchou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new d9730eb9348 [Feat](Snapshot) Implement begin_snapshot interface for 
snapshot (#55637)
d9730eb9348 is described below

commit d9730eb9348bf3f8947992031778c62d075342bd
Author: abmdocrt <[email protected]>
AuthorDate: Thu Sep 11 17:58:36 2025 +0800

    [Feat](Snapshot) Implement begin_snapshot interface for snapshot (#55637)
    
    This PR introduces a comprehensive snapshot interface for the meta
    service, enabling creation and management of database snapshots with
    proper validation, monitoring, and testing.
    
      Summary
    
    - Added snapshot interface implementation - New begin_snapshot RPC
    endpoint with comprehensive parameter validation including cloud unique
    ID, timeout, TTL, snapshot labels, and IP address format
      validation
    - Enhanced monitoring capabilities - Added bvar metrics for snapshot
    operations tracking and performance monitoring
    - Comprehensive test coverage - Created complete test suite
    (meta_service_snapshot_test.cpp) with 264+ lines of tests covering
    various snapshot scenarios
    - Infrastructure improvements - Updated resource management and CMake
    configuration to support the new snapshot functionality
    
      Key Features
    
    - Robust validation: Input parameter validation for timeout, TTL,
    snapshot labels, and IP addresses
    - Monitoring integration: Added bvar metrics for operational visibility
    - Resource management: Integration with existing instance and resource
    management systems
    - Error handling: Proper error codes and messaging for various failure
    scenarios
    
      Files Changed
    
    - src/meta-service/meta_service_snapshot.cpp: Core snapshot
    implementation (108 additions)
      - src/common/bvars.cpp/h: Added monitoring metrics (12 additions)
    - test/meta_service_snapshot_test.cpp: Comprehensive test suite (264
    additions)
      - test/CMakeLists.txt: Updated build configuration
    - src/meta-service/meta_service_resource.cpp: Resource management
    integration (2 changes)
---
 cloud/src/common/bvars.cpp                       |   7 +
 cloud/src/common/bvars.h                         |   5 +
 cloud/src/meta-service/meta_service_resource.cpp |   2 +-
 cloud/src/meta-service/meta_service_snapshot.cpp | 142 +++++++++++-
 cloud/test/CMakeLists.txt                        |   1 +
 cloud/test/meta_service_snapshot_test.cpp        | 272 +++++++++++++++++++++++
 6 files changed, 426 insertions(+), 3 deletions(-)

diff --git a/cloud/src/common/bvars.cpp b/cloud/src/common/bvars.cpp
index e495b5ea95b..959e06ce3d9 100644
--- a/cloud/src/common/bvars.cpp
+++ b/cloud/src/common/bvars.cpp
@@ -93,6 +93,7 @@ BvarLatencyRecorderWithTag g_bvar_ms_get_cluster_status("ms", 
"get_cluster_statu
 BvarLatencyRecorderWithTag g_bvar_ms_set_cluster_status("ms", 
"set_cluster_status");
 BvarLatencyRecorderWithTag g_bvar_ms_check_kv("ms", "check_kv");
 BvarLatencyRecorderWithTag g_bvar_ms_get_schema_dict("ms", "get_schema_dict");
+BvarLatencyRecorderWithTag g_bvar_ms_begin_snapshot("ms", "begin_snapshot");
 bvar::Adder<int64_t> g_bvar_update_delete_bitmap_fail_counter;
 bvar::Window<bvar::Adder<int64_t> > 
g_bvar_update_delete_bitmap_fail_counter_minute("ms", 
"update_delete_bitmap_fail", &g_bvar_update_delete_bitmap_fail_counter, 60);
 bvar::Adder<int64_t> g_bvar_get_delete_bitmap_fail_counter;
@@ -397,6 +398,9 @@ mBvarInt64Adder 
g_bvar_rpc_kv_clean_txn_label_put_counter("rpc_kv_clean_txn_labe
 mBvarInt64Adder 
g_bvar_rpc_kv_clean_txn_label_del_counter("rpc_kv_clean_txn_label_del_counter",{"instance_id"});
 // get_txn_id
 mBvarInt64Adder 
g_bvar_rpc_kv_get_txn_id_get_counter("rpc_kv_get_txn_id_get_counter",{"instance_id"});
+// begin snapshot
+mBvarInt64Adder 
g_bvar_rpc_kv_begin_snapshot_get_counter("rpc_kv_begin_snapshot_get_counter",{"instance_id"});
+mBvarInt64Adder 
g_bvar_rpc_kv_begin_snapshot_put_counter("rpc_kv_begin_snapshot_put_counter",{"instance_id"});
 // bytes
 // get_rowset
 mBvarInt64Adder 
g_bvar_rpc_kv_get_rowset_get_bytes("rpc_kv_get_rowset_get_bytes",{"instance_id"});
@@ -563,5 +567,8 @@ mBvarInt64Adder 
g_bvar_rpc_kv_get_txn_id_get_bytes("rpc_kv_get_txn_id_get_bytes"
 
 // meta ranges
 mBvarStatus<int64_t> g_bvar_fdb_kv_ranges_count("fdb_kv_ranges_count", 
{"category","instance_id", "sub_category"});
+// begin snapshot
+mBvarInt64Adder 
g_bvar_rpc_kv_begin_snapshot_get_bytes("rpc_kv_begin_snapshot_get_bytes",{"instance_id"});
+mBvarInt64Adder 
g_bvar_rpc_kv_begin_snapshot_put_bytes("rpc_kv_begin_snapshot_put_bytes",{"instance_id"});
 
 // clang-format on
diff --git a/cloud/src/common/bvars.h b/cloud/src/common/bvars.h
index 8fb5973249f..646fd3462df 100644
--- a/cloud/src/common/bvars.h
+++ b/cloud/src/common/bvars.h
@@ -255,6 +255,7 @@ extern BvarLatencyRecorderWithTag 
g_bvar_ms_reset_rl_progress;
 extern BvarLatencyRecorderWithTag g_bvar_ms_get_txn_id;
 extern BvarLatencyRecorderWithTag g_bvar_ms_check_kv;
 extern BvarLatencyRecorderWithTag g_bvar_ms_get_schema_dict;
+extern BvarLatencyRecorderWithTag g_bvar_ms_begin_snapshot;
 extern bvar::Adder<int64_t> g_bvar_update_delete_bitmap_fail_counter;
 extern bvar::Adder<int64_t> g_bvar_get_delete_bitmap_fail_counter;
 
@@ -492,6 +493,8 @@ extern mBvarInt64Adder 
g_bvar_rpc_kv_clean_txn_label_get_counter;
 extern mBvarInt64Adder g_bvar_rpc_kv_clean_txn_label_put_counter;
 extern mBvarInt64Adder g_bvar_rpc_kv_clean_txn_label_del_counter;
 extern mBvarInt64Adder g_bvar_rpc_kv_get_txn_id_get_counter;
+extern mBvarInt64Adder g_bvar_rpc_kv_begin_snapshot_get_counter;
+extern mBvarInt64Adder g_bvar_rpc_kv_begin_snapshot_put_counter;
 
 extern mBvarInt64Adder g_bvar_rpc_kv_get_rowset_get_bytes;
 extern mBvarInt64Adder g_bvar_rpc_kv_get_version_get_bytes;
@@ -604,6 +607,8 @@ extern mBvarInt64Adder 
g_bvar_rpc_kv_clean_txn_label_get_bytes;
 extern mBvarInt64Adder g_bvar_rpc_kv_clean_txn_label_put_bytes;
 extern mBvarInt64Adder g_bvar_rpc_kv_clean_txn_label_del_bytes;
 extern mBvarInt64Adder g_bvar_rpc_kv_get_txn_id_get_bytes;
+extern mBvarInt64Adder g_bvar_rpc_kv_begin_snapshot_get_bytes;
+extern mBvarInt64Adder g_bvar_rpc_kv_begin_snapshot_put_bytes;
 
 // meta ranges
 extern mBvarStatus<int64_t> g_bvar_fdb_kv_ranges_count;
diff --git a/cloud/src/meta-service/meta_service_resource.cpp 
b/cloud/src/meta-service/meta_service_resource.cpp
index a3ade5eef20..dfa528010f4 100644
--- a/cloud/src/meta-service/meta_service_resource.cpp
+++ b/cloud/src/meta-service/meta_service_resource.cpp
@@ -2117,7 +2117,7 @@ void 
MetaServiceImpl::alter_instance(google::protobuf::RpcController* controller
                 return std::make_pair(MetaServiceCode::PROTOBUF_SERIALIZE_ERR, 
msg);
             }
             LOG(INFO) << "put instance_id=" << request->instance_id()
-                      << "set instance normal json=" << 
proto_to_json(*instance);
+                      << "set instance snapshot property json=" << 
proto_to_json(*instance);
             return std::make_pair(MetaServiceCode::OK, ret);
         });
     } break;
diff --git a/cloud/src/meta-service/meta_service_snapshot.cpp 
b/cloud/src/meta-service/meta_service_snapshot.cpp
index 6211fba1958..e2c8e395a63 100644
--- a/cloud/src/meta-service/meta_service_snapshot.cpp
+++ b/cloud/src/meta-service/meta_service_snapshot.cpp
@@ -15,18 +15,156 @@
 // specific language governing permissions and limitations
 // under the License.
 
+#include <arpa/inet.h>
+#include <brpc/controller.h>
 #include <gen_cpp/cloud.pb.h>
 
 #include "meta-service/meta_service.h"
+#include "meta-service/meta_service_helper.h"
+#include "meta-store/versioned_value.h"
+#include "meta-store/versionstamp.h"
 
 namespace doris::cloud {
 
+static bool is_valid_ip_address(const std::string& ip) {
+    struct sockaddr_in sa;
+    struct sockaddr_in6 sa6;
+    return (inet_pton(AF_INET, ip.c_str(), &(sa.sin_addr)) == 1) ||
+           (inet_pton(AF_INET6, ip.c_str(), &(sa6.sin6_addr)) == 1);
+}
+
 void MetaServiceImpl::begin_snapshot(::google::protobuf::RpcController* 
controller,
                                      const BeginSnapshotRequest* request,
                                      BeginSnapshotResponse* response,
                                      ::google::protobuf::Closure* done) {
-    brpc::ClosureGuard done_guard(done);
-    controller->SetFailed("Method begin_snapshot() not implemented.");
+    RPC_PREPROCESS(begin_snapshot, get, put);
+
+    // Basic parameter validation
+    std::string cloud_unique_id = request->has_cloud_unique_id() ? 
request->cloud_unique_id() : "";
+    if (cloud_unique_id.empty()) {
+        code = MetaServiceCode::INVALID_ARGUMENT;
+        msg = "cloud unique id not set";
+        return;
+    }
+
+    // Validate timeout must be positive
+    if (request->timeout_seconds() <= 0) {
+        code = MetaServiceCode::INVALID_ARGUMENT;
+        msg = "timeout_seconds must be positive";
+        return;
+    }
+
+    // Validate TTL must be positive
+    if (request->ttl_seconds() <= 0) {
+        code = MetaServiceCode::INVALID_ARGUMENT;
+        msg = "ttl_seconds must be positive";
+        return;
+    }
+
+    // Validate snapshot label is not empty
+    if (request->snapshot_label().empty()) {
+        code = MetaServiceCode::INVALID_ARGUMENT;
+        msg = "snapshot_label cannot be empty";
+        return;
+    }
+
+    // Validate request IP format if provided
+    if (request->has_request_ip() && !request->request_ip().empty()) {
+        if (!is_valid_ip_address(request->request_ip())) {
+            code = MetaServiceCode::INVALID_ARGUMENT;
+            msg = "invalid request IP address format";
+            return;
+        }
+    }
+
+    // get instance id
+    instance_id = get_instance_id(resource_mgr_, cloud_unique_id);
+    if (instance_id.empty()) {
+        code = MetaServiceCode::INVALID_ARGUMENT;
+        msg = "empty instance_id";
+        LOG(INFO) << msg << ", cloud_unique_id=" << cloud_unique_id;
+        return;
+    }
+    RPC_RATE_LIMIT(begin_snapshot)
+
+    // get instance pb
+    InstanceKeyInfo key_info {instance_id};
+    std::string key;
+    std::string val;
+    instance_key(key_info, &key);
+
+    TxnErrorCode err = txn_kv_->create_txn(&txn);
+    if (err != TxnErrorCode::TXN_OK) {
+        code = cast_as<ErrCategory::CREATE>(err);
+        msg = "failed to create txn";
+        LOG(WARNING) << msg << " err=" << err;
+        return;
+    }
+    err = txn->get(key, &val);
+    LOG(INFO) << "get instance_key=" << hex(key);
+
+    if (err != TxnErrorCode::TXN_OK) {
+        code = cast_as<ErrCategory::READ>(err);
+        ss << "failed to get instance, instance_id=" << instance_id << " err=" 
<< err;
+        msg = ss.str();
+        return;
+    }
+
+    InstanceInfoPB instance;
+    if (!instance.ParseFromString(val)) {
+        code = MetaServiceCode::PROTOBUF_PARSE_ERR;
+        msg = "failed to parse InstanceInfoPB";
+        return;
+    }
+
+    // construct snapshot pb
+    versioned::SnapshotFullKeyInfo snapshot_full_info_key {instance_id};
+    std::string encoded_snapshot_full_key;
+    versioned::snapshot_full_key(snapshot_full_info_key, 
&encoded_snapshot_full_key);
+
+    SnapshotPB snapshot_pb;
+    snapshot_pb.set_status(SNAPSHOT_PREPARE);
+    snapshot_pb.set_type(SNAPSHOT_REFERENCE);
+    snapshot_pb.set_timeout_seconds(request->timeout_seconds());
+    snapshot_pb.set_instance_id(instance_id);
+    if (instance.has_source_snapshot_id()) {
+        snapshot_pb.set_snapshot_ancestor(instance.source_snapshot_id());
+    }
+    snapshot_pb.set_auto_(request->auto_snapshot());
+    snapshot_pb.set_ttl_seconds(request->ttl_seconds());
+    snapshot_pb.set_label(request->snapshot_label());
+
+    std::string snapshot_full_info_val = snapshot_pb.SerializeAsString();
+    if (snapshot_full_info_val.empty()) {
+        msg = "failed to serialize";
+        code = MetaServiceCode::PROTOBUF_SERIALIZE_ERR;
+        return;
+    }
+
+    versioned_put(txn.get(), encoded_snapshot_full_key, 
snapshot_full_info_val);
+    LOG_INFO("put versioned snapshot full key info")
+            .tag("encoded_snapshot_full_key", hex(encoded_snapshot_full_key))
+            .tag("instance_id", instance_id);
+
+    txn->enable_get_versionstamp();
+    err = txn->commit();
+    if (err != TxnErrorCode::TXN_OK) {
+        code = cast_as<ErrCategory::COMMIT>(err);
+        msg = fmt::format("failed to commit kv txn, err={}", err);
+        LOG(WARNING) << msg;
+    }
+
+    // get versionstamp
+    std::string version_stamp;
+    err = txn->get_versionstamp(&version_stamp);
+    if (err != TxnErrorCode::TXN_OK) {
+        code = cast_as<ErrCategory::COMMIT>(err);
+        msg = fmt::format("failed to get versionstamp, err={}", err);
+        LOG(WARNING) << msg;
+    }
+
+    response->set_image_url("/snapshot/" + version_stamp + "/");
+    response->set_snapshot_id(version_stamp);
 }
 
 void MetaServiceImpl::commit_snapshot(::google::protobuf::RpcController* 
controller,
diff --git a/cloud/test/CMakeLists.txt b/cloud/test/CMakeLists.txt
index a23d6639bb3..ffd768809b8 100644
--- a/cloud/test/CMakeLists.txt
+++ b/cloud/test/CMakeLists.txt
@@ -33,6 +33,7 @@ add_executable(meta_service_test
    meta_service_job_test.cpp
    meta_service_http_test.cpp
    meta_service_operation_log_test.cpp
+   meta_service_snapshot_test.cpp
    meta_service_tablet_stats_test.cpp
    meta_service_versioned_read_test.cpp
    schema_kv_test.cpp
diff --git a/cloud/test/meta_service_snapshot_test.cpp 
b/cloud/test/meta_service_snapshot_test.cpp
new file mode 100644
index 00000000000..9b6c8851910
--- /dev/null
+++ b/cloud/test/meta_service_snapshot_test.cpp
@@ -0,0 +1,272 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+#include <brpc/controller.h>
+#include <fmt/format.h>
+#include <gen_cpp/cloud.pb.h>
+#include <gen_cpp/olap_file.pb.h>
+#include <gtest/gtest.h>
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <string>
+
+#include "common/defer.h"
+#include "cpp/sync_point.h"
+#include "meta-service/meta_service.h"
+
+namespace doris::cloud {
+
+extern std::unique_ptr<MetaServiceProxy> get_meta_service(bool 
mock_resource_mgr);
+
+TEST(MetaServiceSnapshotTest, BeginSnapshotTest) {
+    auto meta_service = get_meta_service(true);
+    const char* const cloud_unique_id = "test_cloud_unique_id";
+
+    // Setup SyncPoint for encryption
+    auto sp = SyncPoint::get_instance();
+    sp->enable_processing();
+    sp->set_call_back("encrypt_ak_sk:get_encryption_key", [](auto&& args) {
+        auto* ret = try_any_cast<int*>(args[0]);
+        *ret = 0;
+        auto* key = try_any_cast<std::string*>(args[1]);
+        *key = "selectdbselectdbselectdbselectdb";
+        auto* key_id = try_any_cast<int64_t*>(args[2]);
+        *key_id = 1;
+    });
+
+    // Cleanup SyncPoint when test finishes
+    DORIS_CLOUD_DEFER {
+        sp->disable_processing();
+        sp->clear_all_call_backs();
+    };
+
+    // Create test instance first
+    {
+        brpc::Controller cntl;
+        CreateInstanceRequest req;
+        req.set_instance_id("test_instance");
+        req.set_user_id("test_user");
+        req.set_name("test_name");
+        ObjectStoreInfoPB obj;
+        obj.set_ak("123");
+        obj.set_sk("321");
+        obj.set_bucket("456");
+        obj.set_prefix("654");
+        obj.set_endpoint("789");
+        obj.set_region("987");
+        obj.set_external_endpoint("888");
+        obj.set_provider(ObjectStoreInfoPB::BOS);
+        req.mutable_obj_info()->CopyFrom(obj);
+
+        CreateInstanceResponse res;
+        
meta_service->create_instance(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                      &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+    }
+
+    // test invalid argument - empty cloud_unique_id
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::INVALID_ARGUMENT);
+    }
+
+    // test normal begin snapshot
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(3600);
+        req.set_auto_snapshot(true);
+        req.set_ttl_seconds(7200);
+        req.set_snapshot_label("test_snapshot");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+        ASSERT_FALSE(res.image_url().empty());
+        ASSERT_FALSE(res.snapshot_id().empty());
+        ASSERT_TRUE(res.image_url().find("/snapshot/") != std::string::npos);
+    }
+
+    // test begin snapshot with custom parameters
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(1800);
+        req.set_auto_snapshot(false);
+        req.set_ttl_seconds(14400);
+        req.set_snapshot_label("custom_snapshot");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+        ASSERT_FALSE(res.image_url().empty());
+        ASSERT_FALSE(res.snapshot_id().empty());
+    }
+
+    // test invalid timeout_seconds - zero
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(0);
+        req.set_ttl_seconds(7200);
+        req.set_snapshot_label("test_snapshot");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::INVALID_ARGUMENT);
+    }
+
+    // test invalid timeout_seconds - negative
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(-100);
+        req.set_ttl_seconds(7200);
+        req.set_snapshot_label("test_snapshot");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::INVALID_ARGUMENT);
+    }
+
+    // test invalid ttl_seconds - zero
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(3600);
+        req.set_ttl_seconds(0);
+        req.set_snapshot_label("test_snapshot");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::INVALID_ARGUMENT);
+    }
+
+    // test invalid ttl_seconds - negative
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(3600);
+        req.set_ttl_seconds(-500);
+        req.set_snapshot_label("test_snapshot");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::INVALID_ARGUMENT);
+    }
+
+    // test empty snapshot_label
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(3600);
+        req.set_ttl_seconds(7200);
+        req.set_snapshot_label("");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::INVALID_ARGUMENT);
+    }
+
+    // test valid IPv4 address
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(3600);
+        req.set_ttl_seconds(7200);
+        req.set_snapshot_label("test_snapshot");
+        req.set_request_ip("192.168.1.100");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+    }
+
+    // test valid IPv6 address
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(3600);
+        req.set_ttl_seconds(7200);
+        req.set_snapshot_label("test_snapshot");
+        req.set_request_ip("2001:db8::1");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+    }
+
+    // test invalid IP address format
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(3600);
+        req.set_ttl_seconds(7200);
+        req.set_snapshot_label("test_snapshot");
+        req.set_request_ip("invalid.ip.address");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::INVALID_ARGUMENT);
+    }
+
+    // test invalid IP address - out of range
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(3600);
+        req.set_ttl_seconds(7200);
+        req.set_snapshot_label("test_snapshot");
+        req.set_request_ip("256.256.256.256");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::INVALID_ARGUMENT);
+    }
+
+    // test empty IP address (should pass - IP is optional)
+    {
+        brpc::Controller cntl;
+        BeginSnapshotRequest req;
+        req.set_cloud_unique_id(cloud_unique_id);
+        req.set_timeout_seconds(3600);
+        req.set_ttl_seconds(7200);
+        req.set_snapshot_label("test_snapshot");
+        req.set_request_ip("");
+        BeginSnapshotResponse res;
+        
meta_service->begin_snapshot(reinterpret_cast<::google::protobuf::RpcController*>(&cntl),
+                                     &req, &res, nullptr);
+        ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+    }
+}
+} // namespace doris::cloud
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to