lte/gateway/c/session_manager/test/test_sessiond_integ.cpp
/**
 * End to end test.
 * 1) Create session, respond with 2 charging keys
 * 2) Report rule stats, charging key 1 goes over
 *    Expect update with charging key 1
 * 3) End Session for IMSI1
 * 4) Report rule stats without stats for IMSI1 (terminated)
 *    Expect update with terminated charging keys 1 and 2
 * One thing to note is that, even though the main thread is halted twice
 * to enforce the order of function calls to demo a simple case
 * creating session --> updating usage --> terminating session,
 * in reality, the order of those functions is not guaranteed
 * because of the following two reasons.
 * 1) All function calls to either feg or PipelineD are async calls.
 * 2) ReportRuleStats() is an GRPC invoked by PipelineD periodically no matter
 *    if we have any alive session or not. The invoking of ReportRuleStats()
 *    is completely independent of both CreateSession() and EndSession().
 */
End to end test.
1) Create session, respond with 2 charging keys
2) Report rule stats, charging key 1 goes over
Expect update with charging key 1
3) End Session for IMSI1
4) Report rule stats without stats for IMSI1 (terminated)
Expect update with terminated charging keys 1 and 2
One thing to note is that, even though the main thread is halted twice
to enforce the order of function calls to demo a simple case
creating session --> updating usage --> terminating session,
in reality, the order of those functions is not guaranteed
because of the following two reasons.
1) All function calls to either feg or PipelineD are async calls.
2) ReportRuleStats() is an GRPC invoked by PipelineD periodically no matter
if we have any alive session or not. The invoking of ReportRuleStats()
is completely independent of both CreateSession() and EndSession().
End to end test . 1 ) Create session respond with 2 charging keys 2 ) Report rule stats charging key 1 goes over Expect update with charging key 1 3 ) End Session for IMSI1 4 ) Report rule stats without stats for IMSI1 ( terminated ) Expect update with terminated charging keys 1 and 2 One thing to note is that even though the main thread is halted twice to enforce the order of function calls to demo a simple case creating session -- > updating usage -- > terminating session in reality the order of those functions is not guaranteed because of the following two reasons . 1 ) All function calls to either feg or PipelineD are async calls . 2 ) ReportRuleStats () is an GRPC invoked by PipelineD periodically no matter if we have any alive session or not . The invoking of ReportRuleStats () is completely independent of both CreateSession () and EndSession () .
TEST_F(SessiondTest, end_to_end_success) {
  std::promise<void> create_promise, tunnel_promise, update_promise;
  auto terminate_promise = std::make_shared<std::promise<void>>();
  std::promise<std::string> session_id_promise;
  std::string ipv4_addrs = "192.168.0.1";
  std::string ipv6_addrs = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
  uint32_t default_bearer = 5;
  uint32_t enb_teid = TEID_1_DL;
  uint32_t agw_teid = TEID_1_UL;
  auto channel = ServiceRegistrySingleton::Instance()->GetGrpcChannel(
      "sessiond", ServiceRegistrySingleton::LOCAL);
  auto stub = LocalSessionManager::NewStub(channel);
  send_empty_pipelined_table(stub);
  wait_for_setup_calls();
  {
    EXPECT_CALL(*controller_mock,
                CreateSession(testing::_,
                              CheckCreateSession(IMSI1, &session_id_promise),
                              testing::_))
        .Times(1)
        .WillOnce(testing::DoAll(SetCreateSessionResponse(1536, 1024),
                                 SetPromise(&create_promise),
                                 testing::Return(grpc::Status::OK)));
  }
  grpc::ClientContext create_context;
  LocalCreateSessionResponse create_resp;
  LocalCreateSessionRequest request;
  request.mutable_common_context()->mutable_sid()->set_id(IMSI1);
  request.mutable_common_context()->set_rat_type(RATType::TGPP_LTE);
  request.mutable_rat_specific_context()->mutable_lte_context()->set_bearer_id(
      default_bearer);
  request.mutable_common_context()->set_ue_ipv4(ipv4_addrs);
  request.mutable_common_context()->set_ue_ipv6(ipv6_addrs);
  Teids emptyTeids;
  emptyTeids.set_enb_teid(0);
  emptyTeids.set_agw_teid(0);
  request.mutable_common_context()->mutable_teids()->CopyFrom(emptyTeids);
  stub->CreateSession(&create_context, request, &create_resp);
  std::string session_id = session_id_promise.get_future().get();
  create_promise.get_future().get();
  {
    EXPECT_CALL(*events_reporter,
                session_created(IMSI1, testing::_, testing::_, testing::_))
        .Times(1);
    EXPECT_CALL(
        *pipelined_mock,
        ActivateFlows(testing::_,
                      CheckActivateFlowsForTunnIds(
                          IMSI1, ipv4_addrs, ipv6_addrs, enb_teid, agw_teid, 3),
                      testing::_))
        .WillOnce(testing::DoAll(SetPromise(&tunnel_promise),
                                 testing::Return(grpc::Status::OK)));
  }
  grpc::ClientContext tun_update_context;
  UpdateTunnelIdsResponse tun_update_response;
  UpdateTunnelIdsRequest tun_update_request;
  tun_update_request.mutable_sid()->set_id(IMSI1);
  tun_update_request.set_bearer_id(default_bearer);
  tun_update_request.set_enb_teid(enb_teid);
  tun_update_request.set_agw_teid(agw_teid);
  stub->UpdateTunnelIds(&tun_update_context, tun_update_request,
                        &tun_update_response);
  tunnel_promise.get_future().get();
  {
    InSequence s;
    CreditUsageUpdate expected_update;
    create_usage_update(IMSI1, 1, 1024, 512, CreditUsage::QUOTA_EXHAUSTED,
                        &expected_update);
    EXPECT_CALL(*controller_mock,
                UpdateSession(testing::_, CheckSingleUpdate(expected_update),
                              testing::_))
        .Times(1)
        .WillOnce(testing::DoAll(SetUpdateSessionResponse(1024),
                                 SetPromise(&update_promise),
                                 testing::Return(grpc::Status::OK)));
    EXPECT_CALL(*events_reporter,
                session_updated(session_id, testing::_, testing::_))
        .Times(1);
  }
  RuleRecordTable table;
  auto record_list = table.mutable_records();
  create_rule_record(IMSI1, ipv4_addrs, "rule1", 512, 512, record_list->Add());
  create_rule_record(IMSI1, ipv6_addrs, "rule2", 512, 0, record_list->Add());
  create_rule_record(IMSI1, ipv4_addrs, "rule3", 32, 32, record_list->Add());
  send_update_pipelined_table(stub, table);
  update_promise.get_future().get();
  {
    EXPECT_CALL(
        *pipelined_mock,
        DeactivateFlows(testing::_, CheckDeactivateFlows(IMSI1), testing::_))
        .Times(1);
    EXPECT_CALL(*events_reporter, session_terminated(IMSI1, testing::_))
        .Times(1);
    EXPECT_CALL(*controller_mock,
                TerminateSession(testing::_, CheckTerminate(IMSI1), testing::_))
        .Times(1)
        .WillOnce(testing::DoAll(SetSessionTerminateResponse(),
                                 SetPromise(terminate_promise),
                                 testing::Return(grpc::Status::OK)));
  }
  LocalEndSessionResponse end_resp;
  grpc::ClientContext end_context;
  LocalEndSessionRequest end_request;
  end_request.mutable_sid()->set_id(IMSI1);
  stub->EndSession(&end_context, end_request, &end_resp);
  send_empty_pipelined_table(stub);
  set_timeout(5000, terminate_promise);
  terminate_promise->get_future().get();
}
TEST_F ( SessiondTest , end_to_end_success ) { std :: promise < void > create_promise , tunnel_promise , update_promise ; auto terminate_promise = std :: make_shared < std :: promise < void > > ( ) ; std :: promise < std :: string > session_id_promise ; std :: string ipv4_addrs = " " ; std :: string ipv6_addrs = " " ; uint32_t default_bearer = 5 ; uint32_t enb_teid = TEID_1_DL ; uint32_t agw_teid = TEID_1_UL ; auto channel = ServiceRegistrySingleton :: Instance ( ) -> GetGrpcChannel ( " " , ServiceRegistrySingleton :: LOCAL ) ; auto stub = LocalSessionManager :: NewStub ( channel ) ; send_empty_pipelined_table ( stub ) ; wait_for_setup_calls ( ) ; { EXPECT_CALL ( * controller_mock , CreateSession ( testing :: _ , CheckCreateSession ( IMSI1 , & session_id_promise ) , testing :: _ ) ) . Times ( 1 ) . WillOnce ( testing :: DoAll ( SetCreateSessionResponse ( 1536 , 1024 ) , SetPromise ( & create_promise ) , testing :: Return ( grpc :: Status :: OK ) ) ) ; } grpc :: ClientContext create_context ; LocalCreateSessionResponse create_resp ; LocalCreateSessionRequest request ; request . mutable_common_context ( ) -> mutable_sid ( ) -> set_id ( IMSI1 ) ; request . mutable_common_context ( ) -> set_rat_type ( RATType :: TGPP_LTE ) ; request . mutable_rat_specific_context ( ) -> mutable_lte_context ( ) -> set_bearer_id ( default_bearer ) ; request . mutable_common_context ( ) -> set_ue_ipv4 ( ipv4_addrs ) ; request . mutable_common_context ( ) -> set_ue_ipv6 ( ipv6_addrs ) ; Teids emptyTeids ; emptyTeids . set_enb_teid ( 0 ) ; emptyTeids . set_agw_teid ( 0 ) ; request . mutable_common_context ( ) -> mutable_teids ( ) -> CopyFrom ( emptyTeids ) ; stub -> CreateSession ( & create_context , request , & create_resp ) ; std :: string session_id = session_id_promise . get_future ( ) . get ( ) ; create_promise . get_future ( ) . get ( ) ; { EXPECT_CALL ( * events_reporter , session_created ( IMSI1 , testing :: _ , testing :: _ , testing :: _ ) ) . Times ( 1 ) ; EXPECT_CALL ( * pipelined_mock , ActivateFlows ( testing :: _ , CheckActivateFlowsForTunnIds ( IMSI1 , ipv4_addrs , ipv6_addrs , enb_teid , agw_teid , 3 ) , testing :: _ ) ) . WillOnce ( testing :: DoAll ( SetPromise ( & tunnel_promise ) , testing :: Return ( grpc :: Status :: OK ) ) ) ; } grpc :: ClientContext tun_update_context ; UpdateTunnelIdsResponse tun_update_response ; UpdateTunnelIdsRequest tun_update_request ; tun_update_request . mutable_sid ( ) -> set_id ( IMSI1 ) ; tun_update_request . set_bearer_id ( default_bearer ) ; tun_update_request . set_enb_teid ( enb_teid ) ; tun_update_request . set_agw_teid ( agw_teid ) ; stub -> UpdateTunnelIds ( & tun_update_context , tun_update_request , & tun_update_response ) ; tunnel_promise . get_future ( ) . get ( ) ; { InSequence s ; CreditUsageUpdate expected_update ; create_usage_update ( IMSI1 , 1 , 1024 , 512 , CreditUsage :: QUOTA_EXHAUSTED , & expected_update ) ; EXPECT_CALL ( * controller_mock , UpdateSession ( testing :: _ , CheckSingleUpdate ( expected_update ) , testing :: _ ) ) . Times ( 1 ) . WillOnce ( testing :: DoAll ( SetUpdateSessionResponse ( 1024 ) , SetPromise ( & update_promise ) , testing :: Return ( grpc :: Status :: OK ) ) ) ; EXPECT_CALL ( * events_reporter , session_updated ( session_id , testing :: _ , testing :: _ ) ) . Times ( 1 ) ; } RuleRecordTable table ; auto record_list = table . mutable_records ( ) ; create_rule_record ( IMSI1 , ipv4_addrs , " " , 512 , 512 , record_list -> Add ( ) ) ; create_rule_record ( IMSI1 , ipv6_addrs , " " , 512 , 0 , record_list -> Add ( ) ) ; create_rule_record ( IMSI1 , ipv4_addrs , " " , 32 , 32 , record_list -> Add ( ) ) ; send_update_pipelined_table ( stub , table ) ; update_promise . get_future ( ) . get ( ) ; { EXPECT_CALL ( * pipelined_mock , DeactivateFlows ( testing :: _ , CheckDeactivateFlows ( IMSI1 ) , testing :: _ ) ) . Times ( 1 ) ; EXPECT_CALL ( * events_reporter , session_terminated ( IMSI1 , testing :: _ ) ) . Times ( 1 ) ; EXPECT_CALL ( * controller_mock , TerminateSession ( testing :: _ , CheckTerminate ( IMSI1 ) , testing :: _ ) ) . Times ( 1 ) . WillOnce ( testing :: DoAll ( SetSessionTerminateResponse ( ) , SetPromise ( terminate_promise ) , testing :: Return ( grpc :: Status :: OK ) ) ) ; } LocalEndSessionResponse end_resp ; grpc :: ClientContext end_context ; LocalEndSessionRequest end_request ; end_request . mutable_sid ( ) -> set_id ( IMSI1 ) ; stub -> EndSession ( & end_context , end_request , & end_resp ) ; send_empty_pipelined_table ( stub ) ; set_timeout ( 5000 , terminate_promise ) ; terminate_promise -> get_future ( ) . get ( ) ; }
End to end test.
End to end test .
// Setup the SessionD/PipelineD epoch value by sending an empty record. This // will prevent SessionD thinking that PipelineD has restarted mid-test. // 1- CreateSession Expectations // Expect create session with IMSI1 // 1- CreateSession Trigger // Todo, remove emptyTeids once we split CreateSession // Block and wait until we process CreateSessionResponse, after which the // SessionID value will be set. // The thread needs to be halted before proceeding to call ReportRuleStats() // because the call to PipelineD within CreateSession() is an async call, // and the call to PipelineD, ActivateFlows(), is assumed in this test // to happened before the ReportRuleStats(). // 2- UpdateTunnelIds Expectations // Expect rules to be installed and pipelined to be configured // Temporary fix for PipelineD client in SessionD introduces separate // calls for static and dynamic rules. So here is the call for static // rules. // 2- UpdateTunnelIds Trigger // Wait until the ActivateFlows call from UpdateTunnelIds has completed // 3 - PipelineD update + UpdateSession Expectations // Expect update with IMSI1, charging key 1 // 3- ReportRuleStats Trigger // The thread needs to be halted before proceeding to call EndSession() // because the call to FeG within ReportRuleStats() is an async call, // and the call to FeG, UpdateSession(), is assumed in this test // to happened before the EndSession(). // Wait until the ActivateFlows call from UpdateTunnelIds has completed // 4- EndSession Expectations // Expect flows to be deactivated before final update is sent out // 4- EndSession Trigger // The current logic for termination is that we wait until all rules for the // session has finished reporting usage from PipelineD.