@@ -684,7 +684,10 @@ async fn test_raft_trigger_elect_does_not_panic() {
684684 // Give time for re-election to settle
685685 tokio:: time:: sleep ( Duration :: from_secs ( 2 ) ) . await ;
686686 // Single-node should eventually become leader again
687- assert ! ( mgr. is_leader( ) . await , "Should re-elect as leader after trigger" ) ;
687+ assert ! (
688+ mgr. is_leader( ) . await ,
689+ "Should re-elect as leader after trigger"
690+ ) ;
688691}
689692
690693// ---------------------------------------------------------------------------
@@ -734,3 +737,89 @@ async fn test_raft_bootstrap_with_unreachable_peers_does_not_block() {
734737 elapsed
735738 ) ;
736739}
740+
741+ // ---------------------------------------------------------------------------
742+ // Test 19: Vector replication uses ha_manager.master_node() in Raft mode
743+ // ---------------------------------------------------------------------------
744+
745+ /// Verifies that the HaManager's master_node() is accessible and returns
746+ /// None when the node is not a leader. This tests the code path that
747+ /// the vector insert handler uses to find the active master for replication.
748+ ///
749+ /// The bug was: upsert_points() only checked state.master_node (always None
750+ /// in Raft mode) and never checked ha_manager.master_node(). Collections
751+ /// replicated but vectors didn't.
752+ #[ tokio:: test]
753+ async fn test_ha_manager_master_node_accessible_for_replication ( ) {
754+ let store = Arc :: new ( VectorStore :: new ( ) ) ;
755+ let repl_config = ReplicationConfig :: default ( ) ;
756+
757+ let ha = HaManager :: new ( 1 , store. clone ( ) , repl_config) ;
758+
759+ // Before becoming leader, master_node() should be None
760+ assert ! (
761+ ha. master_node( ) . is_none( ) ,
762+ "master_node should be None before becoming leader"
763+ ) ;
764+
765+ // Become leader — MasterNode is created
766+ ha. on_become_leader ( ) . await ;
767+
768+ // After becoming leader, master_node() should return Some
769+ // (the MasterNode may fail to bind port 7001 in test env, but
770+ // the Arc should still be created)
771+ // Note: in test we can't guarantee bind succeeds, but the
772+ // ha_manager should have attempted to create it
773+ let _master = ha. master_node ( ) ; // Should not panic
774+
775+ // Become follower — master_node() should be None again
776+ ha. on_become_follower ( None ) . await ;
777+ assert ! (
778+ ha. master_node( ) . is_none( ) ,
779+ "master_node should be None after becoming follower"
780+ ) ;
781+ }
782+
783+ // ---------------------------------------------------------------------------
784+ // Test 20: Replication operation can be created for vector insert
785+ // ---------------------------------------------------------------------------
786+
787+ /// Verifies that VectorOperation::InsertVector can be constructed
788+ /// with the expected fields. This is the operation that gets replicated
789+ /// from leader to followers.
790+ #[ tokio:: test]
791+ async fn test_vector_replication_operation_construction ( ) {
792+ use vectorizer:: replication:: VectorOperation ;
793+
794+ let op = VectorOperation :: InsertVector {
795+ collection : "test-collection" . to_string ( ) ,
796+ id : "vec-1" . to_string ( ) ,
797+ vector : vec ! [ 0.1 , 0.2 , 0.3 , 0.4 ] ,
798+ payload : Some ( b"{\" key\" :\" value\" }" . to_vec ( ) ) ,
799+ owner_id : None ,
800+ } ;
801+
802+ // Verify the operation can be serialized (needed for replication log)
803+ let serialized = vectorizer:: codec:: serialize ( & op) ;
804+ assert ! ( serialized. is_ok( ) , "VectorOperation should serialize" ) ;
805+
806+ let deserialized: Result < VectorOperation , _ > =
807+ vectorizer:: codec:: deserialize ( & serialized. unwrap ( ) ) ;
808+ assert ! ( deserialized. is_ok( ) , "VectorOperation should deserialize" ) ;
809+
810+ match deserialized. unwrap ( ) {
811+ VectorOperation :: InsertVector {
812+ collection,
813+ id,
814+ vector,
815+ payload,
816+ ..
817+ } => {
818+ assert_eq ! ( collection, "test-collection" ) ;
819+ assert_eq ! ( id, "vec-1" ) ;
820+ assert_eq ! ( vector, vec![ 0.1 , 0.2 , 0.3 , 0.4 ] ) ;
821+ assert ! ( payload. is_some( ) ) ;
822+ }
823+ _ => panic ! ( "Expected InsertVector" ) ,
824+ }
825+ }
0 commit comments