summaryrefslogtreecommitdiffstats
path: root/fnet/src/tests/frt/rpc/session.cpp
blob: a7b889dc71bdaeece7ebe9240a717f31144f02c0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/fnet/frt/frt.h>


class Session
{
private:
  static FastOS_Mutex _lock;
  static int        _cnt;
  int               _val;

public:
  Session() : _val(0)
  {
    _lock.Lock();
    ++_cnt;
    _lock.Unlock();
  }

  ~Session()
  {
    _lock.Lock();
    --_cnt;
    _lock.Unlock();
  }

  void SetValue(int val) { _val = val; }
  int GetValue() const { return _val; }
  static int GetCnt() { return _cnt; }
};

FastOS_Mutex Session::_lock;
int Session::_cnt(0);


struct RPC : public FRT_Invokable
{
  bool bogusFini;

  RPC() : bogusFini(false) {}

  void InitSession(FRT_RPCRequest *req)
  {
    Session *session = new Session();
    req->GetConnection()->SetContext(FNET_Context((void *) session));
  }

  void FiniSession(FRT_RPCRequest *req)
  {
    Session *session =
      (Session *)req->GetConnection()->GetContext()._value.VOIDP;
    bogusFini |= (session == nullptr);
    delete session;
  }

  void GetValue(FRT_RPCRequest *req)
  {
    Session *session =
      (Session *)req->GetConnection()->GetContext()._value.VOIDP;
    req->GetReturn()->AddInt32(session->GetValue());
  }

  void SetValue(FRT_RPCRequest *req)
  {
    Session *session =
      (Session *)req->GetConnection()->GetContext()._value.VOIDP;
    session->SetValue(req->GetParams()->GetValue(0)._intval32);
  }

  void Init(FRT_Supervisor *s)
  {
    FRT_ReflectionBuilder rb(s);
    rb.DefineMethod("getValue", "", "i", true,
                    FRT_METHOD(RPC::GetValue), this);
    rb.DefineMethod("setValue", "i", "", true,
                    FRT_METHOD(RPC::SetValue), this);
    s->SetSessionInitHook(FRT_METHOD(RPC::InitSession), this);
    s->SetSessionFiniHook(FRT_METHOD(RPC::FiniSession), this);
  }
};

TEST("session") {
    RPC rpc;
    FRT_Supervisor orb;
    char spec[64];
    rpc.Init(&orb);
    ASSERT_TRUE(orb.Listen("tcp/0"));
    sprintf(spec, "tcp/localhost:%d", orb.GetListenPort());
    ASSERT_TRUE(orb.Start());

    FRT_Target     *target = orb.GetTarget(spec);
    FRT_RPCRequest *req    = orb.AllocRPCRequest();

    req->SetMethodName("getValue");
    target->InvokeSync(req, 5.0);
    ASSERT_TRUE(!req->IsError() &&
                 strcmp(req->GetReturnSpec(), "i") == 0 &&
                 req->GetReturn()->GetValue(0)._intval32 == 0);

    req = orb.AllocRPCRequest(req);
    req->SetMethodName("setValue");
    req->GetParams()->AddInt32(42);
    target->InvokeSync(req, 5.0);
    ASSERT_TRUE(!req->IsError() &&
                 strcmp(req->GetReturnSpec(), "") == 0);

    req = orb.AllocRPCRequest(req);
    req->SetMethodName("getValue");
    target->InvokeSync(req, 5.0);
    ASSERT_TRUE(!req->IsError() &&
                 strcmp(req->GetReturnSpec(), "i") == 0 &&
                 req->GetReturn()->GetValue(0)._intval32 == 42);

    EXPECT_TRUE(Session::GetCnt() == 1);

    req->SubRef();
    target->SubRef();
    orb.ShutDown(true);
    EXPECT_TRUE(Session::GetCnt() == 0);
    EXPECT_TRUE(!rpc.bogusFini);
};

TEST_MAIN() { TEST_RUN_ALL(); }