1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include "src/core/lib/transport/connectivity_state.h"
20 
21 #include <string.h>
22 
23 #include <gtest/gtest.h>
24 
25 #include <grpc/support/log.h>
26 
27 #include "src/core/lib/iomgr/exec_ctx.h"
28 #include "test/core/util/test_config.h"
29 #include "test/core/util/tracer_util.h"
30 
31 namespace grpc_core {
32 namespace {
33 
TEST(ConnectivityStateName,Basic)34 TEST(ConnectivityStateName, Basic) {
35   EXPECT_STREQ("IDLE", ConnectivityStateName(GRPC_CHANNEL_IDLE));
36   EXPECT_STREQ("CONNECTING", ConnectivityStateName(GRPC_CHANNEL_CONNECTING));
37   EXPECT_STREQ("READY", ConnectivityStateName(GRPC_CHANNEL_READY));
38   EXPECT_STREQ("TRANSIENT_FAILURE",
39                ConnectivityStateName(GRPC_CHANNEL_TRANSIENT_FAILURE));
40   EXPECT_STREQ("SHUTDOWN", ConnectivityStateName(GRPC_CHANNEL_SHUTDOWN));
41 }
42 
43 class Watcher : public ConnectivityStateWatcherInterface {
44  public:
Watcher(int * count,grpc_connectivity_state * output,bool * destroyed=nullptr)45   Watcher(int* count, grpc_connectivity_state* output,
46           bool* destroyed = nullptr)
47       : count_(count), output_(output), destroyed_(destroyed) {}
48 
~Watcher()49   ~Watcher() {
50     if (destroyed_ != nullptr) *destroyed_ = true;
51   }
52 
Notify(grpc_connectivity_state new_state)53   void Notify(grpc_connectivity_state new_state) override {
54     ++*count_;
55     *output_ = new_state;
56   }
57 
58  private:
59   int* count_;
60   grpc_connectivity_state* output_;
61   bool* destroyed_;
62 };
63 
TEST(StateTracker,SetAndGetState)64 TEST(StateTracker, SetAndGetState) {
65   ConnectivityStateTracker tracker("xxx", GRPC_CHANNEL_CONNECTING);
66   EXPECT_EQ(tracker.state(), GRPC_CHANNEL_CONNECTING);
67   tracker.SetState(GRPC_CHANNEL_READY, "whee");
68   EXPECT_EQ(tracker.state(), GRPC_CHANNEL_READY);
69 }
70 
TEST(StateTracker,NotificationUponAddingWatcher)71 TEST(StateTracker, NotificationUponAddingWatcher) {
72   int count = 0;
73   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
74   ConnectivityStateTracker tracker("xxx", GRPC_CHANNEL_CONNECTING);
75   tracker.AddWatcher(GRPC_CHANNEL_IDLE,
76                      MakeOrphanable<Watcher>(&count, &state));
77   EXPECT_EQ(count, 1);
78   EXPECT_EQ(state, GRPC_CHANNEL_CONNECTING);
79 }
80 
TEST(StateTracker,NotificationUponStateChange)81 TEST(StateTracker, NotificationUponStateChange) {
82   int count = 0;
83   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
84   ConnectivityStateTracker tracker("xxx", GRPC_CHANNEL_IDLE);
85   tracker.AddWatcher(GRPC_CHANNEL_IDLE,
86                      MakeOrphanable<Watcher>(&count, &state));
87   EXPECT_EQ(count, 0);
88   EXPECT_EQ(state, GRPC_CHANNEL_IDLE);
89   tracker.SetState(GRPC_CHANNEL_CONNECTING, "whee");
90   EXPECT_EQ(count, 1);
91   EXPECT_EQ(state, GRPC_CHANNEL_CONNECTING);
92 }
93 
TEST(StateTracker,SubscribeThenUnsubscribe)94 TEST(StateTracker, SubscribeThenUnsubscribe) {
95   int count = 0;
96   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
97   bool destroyed = false;
98   ConnectivityStateTracker tracker("xxx", GRPC_CHANNEL_IDLE);
99   ConnectivityStateWatcherInterface* watcher =
100       new Watcher(&count, &state, &destroyed);
101   tracker.AddWatcher(GRPC_CHANNEL_IDLE,
102                      OrphanablePtr<ConnectivityStateWatcherInterface>(watcher));
103   // No initial notification, since we started the watch from the
104   // current state.
105   EXPECT_EQ(count, 0);
106   EXPECT_EQ(state, GRPC_CHANNEL_IDLE);
107   // Cancel watch.  This should not generate another notification.
108   tracker.RemoveWatcher(watcher);
109   EXPECT_TRUE(destroyed);
110   EXPECT_EQ(count, 0);
111   EXPECT_EQ(state, GRPC_CHANNEL_IDLE);
112 }
113 
TEST(StateTracker,OrphanUponShutdown)114 TEST(StateTracker, OrphanUponShutdown) {
115   int count = 0;
116   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
117   bool destroyed = false;
118   ConnectivityStateTracker tracker("xxx", GRPC_CHANNEL_IDLE);
119   ConnectivityStateWatcherInterface* watcher =
120       new Watcher(&count, &state, &destroyed);
121   tracker.AddWatcher(GRPC_CHANNEL_IDLE,
122                      OrphanablePtr<ConnectivityStateWatcherInterface>(watcher));
123   // No initial notification, since we started the watch from the
124   // current state.
125   EXPECT_EQ(count, 0);
126   EXPECT_EQ(state, GRPC_CHANNEL_IDLE);
127   // Set state to SHUTDOWN.
128   tracker.SetState(GRPC_CHANNEL_SHUTDOWN, "shutting down");
129   EXPECT_TRUE(destroyed);
130   EXPECT_EQ(count, 1);
131   EXPECT_EQ(state, GRPC_CHANNEL_SHUTDOWN);
132 }
133 
TEST(StateTracker,AddWhenAlreadyShutdown)134 TEST(StateTracker, AddWhenAlreadyShutdown) {
135   int count = 0;
136   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
137   bool destroyed = false;
138   ConnectivityStateTracker tracker("xxx", GRPC_CHANNEL_SHUTDOWN);
139   ConnectivityStateWatcherInterface* watcher =
140       new Watcher(&count, &state, &destroyed);
141   tracker.AddWatcher(GRPC_CHANNEL_IDLE,
142                      OrphanablePtr<ConnectivityStateWatcherInterface>(watcher));
143   EXPECT_TRUE(destroyed);
144   EXPECT_EQ(count, 1);
145   EXPECT_EQ(state, GRPC_CHANNEL_SHUTDOWN);
146 }
147 
TEST(StateTracker,NotifyShutdownAtDestruction)148 TEST(StateTracker, NotifyShutdownAtDestruction) {
149   int count = 0;
150   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
151   {
152     ConnectivityStateTracker tracker("xxx", GRPC_CHANNEL_IDLE);
153     tracker.AddWatcher(GRPC_CHANNEL_IDLE,
154                        MakeOrphanable<Watcher>(&count, &state));
155     // No initial notification, since we started the watch from the
156     // current state.
157     EXPECT_EQ(count, 0);
158     EXPECT_EQ(state, GRPC_CHANNEL_IDLE);
159   }
160   // Upon tracker destruction, we get a notification for SHUTDOWN.
161   EXPECT_EQ(count, 1);
162   EXPECT_EQ(state, GRPC_CHANNEL_SHUTDOWN);
163 }
164 
TEST(StateTracker,DoNotNotifyShutdownAtDestructionIfAlreadyInShutdown)165 TEST(StateTracker, DoNotNotifyShutdownAtDestructionIfAlreadyInShutdown) {
166   int count = 0;
167   grpc_connectivity_state state = GRPC_CHANNEL_SHUTDOWN;
168   {
169     ConnectivityStateTracker tracker("xxx", GRPC_CHANNEL_SHUTDOWN);
170     tracker.AddWatcher(GRPC_CHANNEL_SHUTDOWN,
171                        MakeOrphanable<Watcher>(&count, &state));
172     // No initial notification, since we started the watch from the
173     // current state.
174     EXPECT_EQ(count, 0);
175     EXPECT_EQ(state, GRPC_CHANNEL_SHUTDOWN);
176   }
177   // No additional notification upon tracker destruction, since we were
178   // already in state SHUTDOWN.
179   EXPECT_EQ(count, 0);
180   EXPECT_EQ(state, GRPC_CHANNEL_SHUTDOWN);
181 }
182 
183 }  // namespace
184 }  // namespace grpc_core
185 
main(int argc,char ** argv)186 int main(int argc, char** argv) {
187   ::testing::InitGoogleTest(&argc, argv);
188   grpc::testing::TestEnvironment env(argc, argv);
189   grpc_init();
190   grpc_core::testing::grpc_tracer_enable_flag(
191       &grpc_core::grpc_connectivity_state_trace);
192   int ret = RUN_ALL_TESTS();
193   grpc_shutdown();
194   return ret;
195 }
196