YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/yql/redis/redisserver/redisserver-test.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#include <chrono>
15
#include <memory>
16
#include <random>
17
#include <string>
18
#include <thread>
19
#include <vector>
20
21
#include <boost/algorithm/string.hpp>
22
23
#include "yb/client/yb_table_name.h"
24
25
#include "yb/gutil/strings/join.h"
26
#include "yb/gutil/strings/substitute.h"
27
28
#include "yb/integration-tests/redis_table_test_base.h"
29
30
#include "yb/master/flush_manager.h"
31
#include "yb/master/master_admin.pb.h"
32
33
#include "yb/rpc/io_thread_pool.h"
34
35
#include "yb/tserver/mini_tablet_server.h"
36
#include "yb/tserver/tablet_server.h"
37
38
#include "yb/util/cast.h"
39
#include "yb/util/enums.h"
40
#include "yb/util/metrics.h"
41
#include "yb/util/net/socket.h"
42
#include "yb/util/protobuf.h"
43
#include "yb/util/ref_cnt_buffer.h"
44
#include "yb/util/result.h"
45
#include "yb/util/size_literals.h"
46
#include "yb/util/status_log.h"
47
#include "yb/util/test_util.h"
48
#include "yb/util/tsan_util.h"
49
#include "yb/util/value_changer.h"
50
51
#include "yb/yql/redis/redisserver/redis_client.h"
52
#include "yb/yql/redis/redisserver/redis_constants.h"
53
#include "yb/yql/redis/redisserver/redis_encoding.h"
54
#include "yb/yql/redis/redisserver/redis_server.h"
55
56
DECLARE_uint64(redis_max_concurrent_commands);
57
DECLARE_uint64(redis_max_batch);
58
DECLARE_uint64(redis_max_read_buffer_size);
59
DECLARE_uint64(redis_max_queued_bytes);
60
DECLARE_int64(redis_rpc_block_size);
61
DECLARE_bool(redis_safe_batch);
62
DECLARE_bool(emulate_redis_responses);
63
DECLARE_bool(enable_direct_local_tablet_server_call);
64
DECLARE_bool(TEST_tserver_timeout);
65
DECLARE_bool(TEST_enable_backpressure_mode_for_testing);
66
DECLARE_bool(yedis_enable_flush);
67
DECLARE_int32(redis_service_yb_client_timeout_millis);
68
DECLARE_uint64(redis_max_value_size);
69
DECLARE_uint64(redis_max_command_size);
70
DECLARE_int32(redis_password_caching_duration_ms);
71
DECLARE_uint64(rpc_max_message_size);
72
DECLARE_uint64(consensus_max_batch_size_bytes);
73
DECLARE_int32(consensus_rpc_timeout_ms);
74
DECLARE_int64(max_time_in_queue_ms);
75
76
DEFINE_uint64(test_redis_max_concurrent_commands, 20,
77
    "Value of redis_max_concurrent_commands for pipeline test");
78
DEFINE_uint64(test_redis_max_batch, 250,
79
    "Value of redis_max_batch for pipeline test");
80
81
METRIC_DECLARE_gauge_uint64(redis_available_sessions);
82
METRIC_DECLARE_gauge_uint64(redis_allocated_sessions);
83
METRIC_DECLARE_gauge_uint64(redis_monitoring_clients);
84
85
using namespace std::literals;
86
using namespace std::placeholders;
87
88
namespace yb {
89
namespace redisserver {
90
91
using std::string;
92
using std::unique_ptr;
93
using std::vector;
94
using strings::Substitute;
95
using yb::integration_tests::RedisTableTestBase;
96
using yb::util::ToRepeatedPtrField;
97
98
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
99
constexpr int kDefaultTimeoutMs = 100000;
100
#else
101
constexpr int kDefaultTimeoutMs = 10000;
102
#endif
103
104
typedef std::tuple<string, string> CollectionEntry;
105
106
class TestRedisService : public RedisTableTestBase {
107
 public:
108
  void SetUp() override;
109
  void TearDown() override;
110
111
  void StartServer();
112
  void StopServer();
113
  void StartClient();
114
  void StopClient();
115
  void RestartClient();
116
  void SendCommandAndExpectTimeout(const string& cmd);
117
118
  void SendCommandAndExpectResponse(int line,
119
      const string& cmd,
120
      const string& resp,
121
      bool partial = false);
122
123
  void SendCommandAndExpectResponse(int line,
124
      const RefCntBuffer& cmd,
125
      const RefCntBuffer& resp,
126
0
      bool partial = false) {
127
0
    SendCommandAndExpectResponse(line, cmd.ToBuffer(), resp.ToBuffer(), partial);
128
0
  }
129
130
  template <class Callback>
131
  void DoRedisTest(int line,
132
      const std::vector<std::string>& command,
133
      RedisReplyType reply_type,
134
      const Callback& callback);
135
136
  void DoRedisTestString(int line,
137
      const std::vector<std::string>& command,
138
      const std::string& expected,
139
0
      RedisReplyType type = RedisReplyType::kStatus) {
140
0
    DoRedisTest(line, command, type,
141
0
        [line, expected](const RedisReply& reply) {
142
0
          ASSERT_EQ(expected, reply.as_string()) << "Originator: " << __FILE__ << ":" << line;
143
0
        }
144
0
    );
145
0
  }
146
147
  void DoRedisTestSimpleString(int line,
148
      const std::vector<std::string>& command,
149
0
      const std::string& expected) {
150
0
    DoRedisTestString(line, command, expected, RedisReplyType::kStatus);
151
0
  }
152
153
  void DoRedisTestBulkString(int line,
154
      const std::vector<std::string>& command,
155
0
      const std::string& expected) {
156
0
    DoRedisTestString(line, command, expected, RedisReplyType::kString);
157
0
  }
158
159
0
  void DoRedisTestOk(int line, const std::vector<std::string>& command) {
160
0
    DoRedisTestSimpleString(line, command, "OK");
161
0
  }
162
163
  void DoRedisTestExpectError(int line, const std::vector<std::string>& command,
164
0
                              const std::string& error_prefix = "") {
165
0
    DoRedisTest(line, command, RedisReplyType::kError,
166
0
        [line, error_prefix](const RedisReply& reply) {
167
0
          if (!error_prefix.empty()) {
168
0
            ASSERT_EQ(reply.error().find(error_prefix), 0) << "Error message has the wrong prefix "
169
0
              << " expected : " << error_prefix << " got message " << reply.error()
170
0
              << " Originator: " << __FILE__ << ":" << line;
171
0
          }
172
0
        }
173
0
    );
174
0
  }
175
176
  void DoRedisTestExpectSimpleStringEndingWith(
177
0
      int line, const std::vector<std::string>& command, const std::string& suffix = "") {
178
0
    DoRedisTest(line, command, RedisReplyType::kStatus, [line, suffix](const RedisReply& reply) {
179
0
      if (!suffix.empty()) {
180
0
        ASSERT_TRUE(boost::algorithm::ends_with(reply.as_string(), suffix))
181
0
            << "Reply has the wrong suffix. Expected '" << reply.as_string() << "' to end in "
182
0
            << suffix << " Originator: " << __FILE__ << ":" << line;
183
0
      }
184
0
    });
185
0
  }
186
187
  void DoRedisTestExpectErrorMsg(int line, const std::vector<std::string>& command,
188
0
      const std::string& error_msg) {
189
0
    DoRedisTestString(line, command, error_msg, RedisReplyType::kError);
190
0
  }
191
192
  void DoRedisTestInt(int line,
193
                      const std::vector<std::string>& command,
194
0
                      int64_t expected) {
195
0
    DoRedisTest(line, command, RedisReplyType::kInteger,
196
0
        [line, expected](const RedisReply& reply) {
197
0
          ASSERT_EQ(expected, reply.as_integer()) << "Originator: " << __FILE__ << ":" << line;
198
0
        }
199
0
    );
200
0
  }
201
202
  void DoRedisTestIntRange(
203
      int line,
204
      const std::vector<std::string>& command,
205
0
      int64_t expected_min, int64_t expected_max) {
206
0
    DoRedisTest(line, command, RedisReplyType::kInteger,
207
0
        [line, expected_min, expected_max](const RedisReply& reply) {
208
0
          ASSERT_LE(expected_min, reply.as_integer()) << "Originator: " << __FILE__ << ":" << line;
209
0
          ASSERT_GE(expected_max, reply.as_integer()) << "Originator: " << __FILE__ << ":" << line;
210
0
        }
211
0
    );
212
0
  }
213
214
  void DoRedisTestApproxInt(int line,
215
                            const std::vector<std::string>& command,
216
                            int64_t expected,
217
0
                            int64_t err_bound) {
218
0
    DoRedisTestIntRange(line, command, expected - err_bound, expected + err_bound);
219
0
  }
220
221
  void DoRedisTestResultsArray(
222
0
      int line, const std::vector<std::string>& command, const std::vector<RedisReply>& expected) {
223
0
    DoRedisTest(line, command, RedisReplyType::kArray,
224
0
        [line, expected](const RedisReply& reply) {
225
0
          const auto& replies = reply.as_array();
226
0
          ASSERT_EQ(expected.size(), replies.size())
227
0
              << "Originator: " << __FILE__ << ":" << line << std::endl
228
0
              << "Expected: " << yb::ToString(expected) << std::endl
229
0
              << " Replies: " << Max500CharsPrinter(reply.ToString());
230
0
          for (size_t i = 0; i < expected.size(); i++) {
231
0
            DVLOG(3) << "Checking " << replies[i].ToString();
232
0
            if (expected[i].get_type() == RedisReplyType::kString &&
233
0
                expected[i].as_string() == "IGNORED") {
234
0
              continue;
235
0
            }
236
0
            ASSERT_EQ(expected[i], replies[i])
237
0
                << "Originator: " << __FILE__ << ":" << line << ", i: " << i << " expected[i] "
238
0
                << yb::ToString(expected[i]) << " replies[i] " << yb::ToString(replies[i]);
239
0
          }
240
0
        }
241
0
    );
242
0
  }
243
244
  // Note: expected empty string will check for null instead.
245
  void DoRedisTestArray(
246
0
      int line, const std::vector<std::string>& command, const std::vector<std::string>& expected) {
247
0
    std::vector<RedisReply> redis_replies;
248
0
    for (size_t i = 0; i < expected.size(); i++) {
249
0
      redis_replies.push_back(RedisReply(RedisReplyType::kString, expected[i]));
250
0
    }
251
0
    DoRedisTestResultsArray(line, command, redis_replies);
252
0
  }
253
254
0
  void DoRedisTestDouble(int line, const std::vector<std::string>& command, double expected) {
255
0
    DoRedisTest(line, command, RedisReplyType::kString,
256
0
                [line, expected](const RedisReply& reply) {
257
0
                  std::string::size_type sz;
258
0
                  double reply_score = std::stod(reply.as_string(), &sz);
259
0
                  ASSERT_EQ(reply_score, expected) << "Originator: " << __FILE__ << ":" << line;
260
0
                }
261
0
    );
262
0
  }
263
264
  // Used to check pairs of doubles and strings, for range scans withscores.
265
  void DoRedisTestScoreValueArray(int line,
266
      const std::vector<std::string>& command,
267
      const std::vector<double>& expected_scores,
268
0
      const std::vector<std::string>& expected_values) {
269
0
    ASSERT_EQ(expected_scores.size(), expected_values.size());
270
0
    DoRedisTest(line, command, RedisReplyType::kArray,
271
0
      [line, expected_scores, expected_values](const RedisReply& reply) {
272
0
        const auto& replies = reply.as_array();
273
0
        ASSERT_EQ(expected_scores.size() * 2, replies.size())
274
0
                      << "Originator: " << __FILE__ << ":" << line;
275
0
        for (size_t i = 0; i < expected_scores.size(); i++) {
276
0
          ASSERT_EQ(expected_values[i], replies[2 * i].as_string())
277
0
                        << "Originator: " << __FILE__ << ":" << line << ", i: " << i;
278
0
          std::string::size_type sz;
279
0
          double reply_score = std::stod(replies[2 * i + 1].as_string(), &sz);
280
0
          ASSERT_EQ(expected_scores[i], reply_score)
281
0
                        << "Originator: " << __FILE__ << ":" << line << ", i: " << i;
282
0
        }
283
0
      }
284
0
    );
285
0
  }
286
287
  void DoRedisTestNull(int line,
288
0
      const std::vector<std::string>& command) {
289
0
    DoRedisTest(line, command, RedisReplyType::kNull,
290
0
        [line](const RedisReply& reply) {
291
0
          ASSERT_TRUE(reply.is_null()) << "Originator: " << __FILE__ << ":" << line;
292
0
        }
293
0
    );
294
0
  }
295
296
0
  inline void CheckExpired(std::string* key) {
297
0
    SyncClient();
298
0
    DoRedisTestInt(__LINE__, {"TTL", *key}, -2);
299
0
    DoRedisTestInt(__LINE__, {"PTTL", *key}, -2);
300
0
    DoRedisTestInt(__LINE__, {"EXPIRE", *key, "5"}, 0);
301
0
    SyncClient();
302
0
  }
303
304
0
  inline void CheckExpiredPrimitive(std::string* key) {
305
0
    SyncClient();
306
0
    DoRedisTestNull(__LINE__, {"GET", *key});
307
0
    CheckExpired(key);
308
0
  }
309
310
0
  void SyncClient() { client().Commit(); }
311
312
  void VerifyCallbacks();
313
314
0
  Status FlushRedisTable() {
315
    // Flush the table
316
0
    master::FlushTablesRequestPB req;
317
0
    req.set_is_compaction(false);
318
0
    table_name().SetIntoTableIdentifierPB(req.add_tables());
319
0
    master::FlushTablesResponsePB resp;
320
0
    RETURN_NOT_OK(VERIFY_RESULT(mini_cluster()->GetLeaderMiniMaster())->flush_manager().
321
0
                  FlushTables(&req, &resp));
322
323
0
    master::IsFlushTablesDoneRequestPB wait_req;
324
    // Wait for table creation.
325
0
    wait_req.set_flush_request_id(resp.flush_request_id());
326
327
0
    for (int k = 0; k < 20; ++k) {
328
0
      master::IsFlushTablesDoneResponsePB wait_resp;
329
0
      RETURN_NOT_OK(VERIFY_RESULT(mini_cluster()->GetLeaderMiniMaster())
330
0
                        ->flush_manager().IsFlushTablesDone(&wait_req, &wait_resp));
331
0
      if (wait_resp.done()) {
332
0
        return Status::OK();
333
0
      }
334
0
      SleepFor(MonoDelta::FromSeconds(1));
335
0
    }
336
0
    return STATUS(IllegalState, "Could not flush redis table.");
337
0
  }
338
339
0
  int server_port() { return redis_server_port_; }
340
341
  CHECKED_STATUS Send(const std::string& cmd);
342
343
  CHECKED_STATUS SendCommandAndGetResponse(
344
      const string& cmd, size_t expected_resp_length, int timeout_in_millis = kDefaultTimeoutMs);
345
346
0
  size_t CountSessions(const GaugePrototype<uint64_t>& proto) {
347
0
    constexpr uint64_t kInitialValue = 0UL;
348
0
    auto counter = server_->metric_entity()->FindOrCreateGauge(&proto, kInitialValue);
349
0
    return counter->value();
350
0
  }
351
352
0
  virtual Endpoint RedisProxyEndpoint() {
353
0
    if (use_external_mini_cluster()) {
354
0
      return Endpoint(IpAddress(), server_port());
355
0
    }
356
0
    auto server = mini_cluster()->mini_tablet_server(0)->server();
357
0
    return Endpoint(server->first_rpc_address().address(), redis_server_port_);
358
0
  }
359
360
  void TestTSTtl(const std::string& expire_command, int64_t ttl_sec, int64_t expire_val,
361
0
      const std::string& redis_key) {
362
0
    DoRedisTestOk(__LINE__, {"TSADD", redis_key, "10", "v1", "20", "v2", "30", "v3", expire_command,
363
0
        strings::Substitute("$0", expire_val)});
364
0
    SyncClient();
365
0
    DoRedisTestOk(__LINE__, {"TSADD", redis_key, "40", "v4"});
366
0
    DoRedisTestOk(__LINE__, {"TSADD", redis_key, "10", "v5"});
367
0
    DoRedisTestOk(__LINE__, {"TSADD", redis_key, "50", "v6", expire_command,
368
0
        std::to_string(expire_val + ttl_sec)});
369
0
    DoRedisTestOk(__LINE__, {"TSADD", redis_key, "60", "v7", expire_command,
370
0
        std::to_string(expire_val - ttl_sec + kRedisMaxTtlSeconds)});
371
0
    DoRedisTestOk(__LINE__, {"TSADD", redis_key, "70", "v8", expire_command,
372
0
        std::to_string(expire_val - ttl_sec + kRedisMinTtlSetExSeconds)});
373
    // Same kv with different ttl (later one should win).
374
0
    DoRedisTestOk(__LINE__, {"TSADD", redis_key, "80", "v9", expire_command,
375
0
        std::to_string(expire_val)});
376
0
    DoRedisTestOk(__LINE__, {"TSADD", redis_key, "80", "v9", expire_command,
377
0
        std::to_string(expire_val + ttl_sec)});
378
0
    SyncClient();
379
380
    // Wait for min ttl to expire.
381
0
    std::this_thread::sleep_for(std::chrono::seconds(kRedisMinTtlSetExSeconds + 1));
382
383
0
    SyncClient();
384
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "10"}, "v5");
385
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "20"}, "v2");
386
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "30"}, "v3");
387
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "50"}, "v6");
388
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "60"}, "v7");
389
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "80"}, "v9");
390
0
    SyncClient();
391
392
    // Wait for TTL expiry
393
0
    std::this_thread::sleep_for(std::chrono::seconds(ttl_sec + 1));
394
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "10"}, "v5");
395
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "40"}, "v4");
396
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "50"}, "v6");
397
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "60"}, "v7");
398
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "80"}, "v9");
399
0
    DoRedisTestNull(__LINE__, {"TSGET", redis_key, "20"});
400
0
    DoRedisTestNull(__LINE__, {"TSGET", redis_key, "30"});
401
0
    SyncClient();
402
403
    // Wait for next TTL expiry
404
0
    std::this_thread::sleep_for(std::chrono::seconds(ttl_sec + 1));
405
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "10"}, "v5");
406
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "40"}, "v4");
407
0
    DoRedisTestNull(__LINE__, {"TSGET", redis_key, "20"});
408
0
    DoRedisTestNull(__LINE__, {"TSGET", redis_key, "30"});
409
0
    DoRedisTestNull(__LINE__, {"TSGET", redis_key, "50"});
410
0
    DoRedisTestBulkString(__LINE__, {"TSGET", redis_key, "60"}, "v7");
411
0
    SyncClient();
412
0
    VerifyCallbacks();
413
414
    // Test invalid commands.
415
0
    DoRedisTestExpectError(__LINE__, {"TSADD", redis_key, "10", "v1", expire_command,
416
0
        std::to_string(expire_val - 2 * ttl_sec)}); // Negative ttl.
417
0
    DoRedisTestExpectError(__LINE__, {"TSADD", redis_key, "10", "v1", "20", "v2", "30", "v3",
418
0
        expire_command});
419
0
    DoRedisTestExpectError(__LINE__, {"TSADD", redis_key, "10", "v1", expire_command, "v2", "30",
420
0
        "v3"});
421
0
    DoRedisTestExpectError(__LINE__, {"TSADD", expire_command, redis_key, "10", "v1", "30", "v3"});
422
0
    DoRedisTestExpectError(__LINE__, {"TSADD", redis_key, "10", "v1", expire_command, "abc"});
423
0
    DoRedisTestExpectError(__LINE__, {"TSADD", redis_key, "10", "v1", expire_command, "3.0"});
424
0
    DoRedisTestExpectError(__LINE__, {"TSADD", redis_key, "10", "v1", expire_command, "123 "});
425
0
    DoRedisTestExpectError(__LINE__, {"TSADD", redis_key, "10", "v1", expire_command,
426
0
        "9223372036854775808"});
427
0
    DoRedisTestExpectError(__LINE__, {"TSADD", redis_key, "10", "v1", expire_command,
428
0
        "-9223372036854775809"});
429
0
    DoRedisTestExpectError(__LINE__, {"TSADD", redis_key, "10", "v1", expire_command,
430
0
        std::to_string(expire_val - ttl_sec)}); // ttl of 0 not allowed.
431
0
  }
432
433
0
  void TestFlush(const string& flush_cmd, const bool allow_flush) {
434
0
    FLAGS_yedis_enable_flush = allow_flush;
435
    // Populate keys.
436
0
    const int kKeyCount = 100;
437
0
    for (int i = 0; i < kKeyCount; i++) {
438
0
      DoRedisTestOk(__LINE__, {"SET", Substitute("k$0", i),  Substitute("v$0", i)});
439
0
    }
440
0
    SyncClient();
441
442
    // Verify keys.
443
0
    for (int i = 0; i < kKeyCount; i++) {
444
0
      DoRedisTestBulkString(__LINE__, {"GET", Substitute("k$0", i)}, Substitute("v$0", i));
445
0
    }
446
0
    SyncClient();
447
448
0
    if (!allow_flush) {
449
0
      DoRedisTestExpectError(__LINE__, {flush_cmd});
450
0
      SyncClient();
451
0
      return;
452
0
    }
453
454
    // Delete all keys in the database and verify keys are gone.
455
0
    DoRedisTestOk(__LINE__, {flush_cmd});
456
0
    SyncClient();
457
0
    for (int i = 0; i < kKeyCount; i++) {
458
0
      DoRedisTestNull(__LINE__, {"GET", Substitute("k$0", i)});
459
0
    }
460
0
    SyncClient();
461
462
    // Delete all keys in the database again (an NOOP) and verify there is no issue.
463
0
    DoRedisTestOk(__LINE__, {flush_cmd});
464
0
    SyncClient();
465
0
    for (int i = 0; i < kKeyCount; i++) {
466
0
      DoRedisTestNull(__LINE__, {"GET", Substitute("k$0", i)});
467
0
    }
468
0
    SyncClient();
469
0
  }
470
471
  bool expected_no_sessions_ = false;
472
473
0
  RedisClient& client() {
474
0
    if (!test_client_) {
475
0
      io_thread_pool_.emplace("test", 1);
476
0
      test_client_ = CreateClient();
477
0
    }
478
0
    return *test_client_;
479
0
  }
480
481
0
  std::shared_ptr<RedisClient> CreateClient() {
482
0
    auto endpoint = RedisProxyEndpoint();
483
0
    return std::make_shared<RedisClient>(endpoint.address().to_string(), endpoint.port());
484
0
  }
485
486
0
  void UseClient(std::shared_ptr<RedisClient> client) {
487
0
    VLOG(1) << "Using " << client.get() << " replacing " << test_client_.get();
488
0
    test_client_ = client;
489
0
  }
490
491
  void CloseRedisClient();
492
493
  // Tests not repeated because they are already covered in the primitive TTL test:
494
  // Operating on a key that does not exist, EXPIRing with a TTL out of bounds,
495
  // Any (P) version of a command.
496
  template <typename T>
497
  void TestTtlCollection(std::string* collection_key, T* values, int val_size,
498
                         std::function<void(std::string*, T*, int)> set_vals,
499
                         std::function<void(std::string*, T*)> add_elems,
500
                         std::function<void(std::string*, T*)> del_elems,
501
                         std::function<void(std::string*, T*, bool)> get_check,
502
0
                         std::function<void(std::string*, int)> check_card) {
503
504
    // num_shifts is the number of times we call modify
505
0
    int num_shifts = 7;
506
0
    int size = val_size - num_shifts;
507
0
    std::string key = *collection_key;
508
0
    auto init = std::bind(set_vals, collection_key, std::placeholders::_1, size);
509
0
    auto modify = [add_elems, del_elems, check_card, collection_key, size, this]
510
0
                  (T** values) {
511
0
                    SyncClient();
512
0
                    if (std::rand() % 2) {
513
0
                      del_elems(collection_key, *values);
514
0
                      SyncClient();
515
0
                      check_card(collection_key, size - 1);
516
0
                      SyncClient();
517
0
                      add_elems(collection_key, *values + size);
518
0
                    } else {
519
0
                      add_elems(collection_key, *values + size);
520
0
                      SyncClient();
521
0
                      check_card(collection_key, size + 1);
522
0
                      SyncClient();
523
0
                      del_elems(collection_key, *values);
524
0
                    }
525
0
                    SyncClient();
526
0
                    check_card(collection_key, size);
527
0
                    ++*values;
528
0
                  };
Unexecuted instantiation: _ZZN2yb11redisserver16TestRedisService17TestTtlCollectionINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvPS9_PT_iNS3_8functionIFvSA_SC_iEEENSD_IFvSA_SC_EEESH_NSD_IFvSA_SC_bEEENSD_IFvSA_iEEEENKUlPSA_E_clESM_
Unexecuted instantiation: _ZZN2yb11redisserver16TestRedisService17TestTtlCollectionINSt3__15tupleIJNS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESA_EEEEEvPSA_PT_iNS3_8functionIFvSC_SE_iEEENSF_IFvSC_SE_EEESJ_NSF_IFvSC_SE_bEEENSF_IFvSC_iEEEENKUlPPSB_E_clESP_
529
0
    auto check = [get_check, check_card, collection_key, size, val_size, values, this]
530
0
                 (T* curr_vals) {
531
0
                   T* it = values;
532
0
                   SyncClient();
533
0
                   for ( ; it < curr_vals; ++it)
534
0
                     get_check(collection_key, it, false);
535
0
                   for ( ; it < curr_vals + size; ++it)
536
0
                     get_check(collection_key, it, true);
537
0
                   for ( ; it < values + val_size; ++it)
538
0
                     get_check(collection_key, it, false);
539
0
                   SyncClient();
540
0
                   check_card(collection_key, size);
541
0
                   SyncClient();
542
0
                 };
Unexecuted instantiation: _ZZN2yb11redisserver16TestRedisService17TestTtlCollectionINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvPS9_PT_iNS3_8functionIFvSA_SC_iEEENSD_IFvSA_SC_EEESH_NSD_IFvSA_SC_bEEENSD_IFvSA_iEEEENKUlSA_E_clESA_
Unexecuted instantiation: _ZZN2yb11redisserver16TestRedisService17TestTtlCollectionINSt3__15tupleIJNS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESA_EEEEEvPSA_PT_iNS3_8functionIFvSC_SE_iEEENSF_IFvSC_SE_EEESJ_NSF_IFvSC_SE_bEEENSF_IFvSC_iEEEENKUlPSB_E_clESO_
543
0
    auto expired = [get_check, collection_key, size, this](T* values) {
544
0
                     CheckExpired(collection_key);
545
0
                     for (T* it = values; it < values + size; ++it)
546
0
                       get_check(collection_key, it, false);
547
0
                     SyncClient();
548
0
                   };
Unexecuted instantiation: _ZZN2yb11redisserver16TestRedisService17TestTtlCollectionINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvPS9_PT_iNS3_8functionIFvSA_SC_iEEENSD_IFvSA_SC_EEESH_NSD_IFvSA_SC_bEEENSD_IFvSA_iEEEENKUlSA_E0_clESA_
Unexecuted instantiation: _ZZN2yb11redisserver16TestRedisService17TestTtlCollectionINSt3__15tupleIJNS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESA_EEEEEvPSA_PT_iNS3_8functionIFvSC_SE_iEEENSF_IFvSC_SE_EEESJ_NSF_IFvSC_SE_bEEENSF_IFvSC_iEEEENKUlPSB_E0_clESO_
549
550
    // Checking TTL and PERSIST on a persistent collection.
551
0
    init(values);
552
0
    DoRedisTestInt(__LINE__, {"TTL", key}, -1);
553
0
    DoRedisTestInt(__LINE__, {"PTTL", key}, -1);
554
0
    DoRedisTestInt(__LINE__, {"PERSIST", key}, 0);
555
0
    SyncClient();
556
    // Checking that modification does not change anything.
557
0
    modify(&values);
558
0
    DoRedisTestInt(__LINE__, {"TTL", key}, -1);
559
0
    DoRedisTestInt(__LINE__, {"PTTL", key}, -1);
560
0
    DoRedisTestInt(__LINE__, {"PERSIST", key}, 0);
561
0
    check(values);
562
0
    SyncClient();
563
    // Adding TTL and checking that modification does not change anything.
564
0
    DoRedisTestInt(__LINE__, {"EXPIRE", key, "7"}, 1);
565
0
    modify(&values);
566
0
    DoRedisTestInt(__LINE__, {"TTL", key}, 7);
567
0
    check(values);
568
0
    SyncClient();
569
    // Checking that everything is still there after some time.
570
0
    std::this_thread::sleep_for(3s);
571
0
    DoRedisTestInt(__LINE__, {"TTL", key}, 4);
572
0
    check(values);
573
0
    SyncClient();
574
0
    std::this_thread::sleep_for(5s);
575
0
    expired(values);
576
0
    SyncClient();
577
    // Checking expiration changes for a later expiration.
578
0
    init(values);
579
0
    check(values);
580
0
    DoRedisTestInt(__LINE__, {"EXPIRE", key, "5"}, 1);
581
0
    modify(&values);
582
0
    DoRedisTestInt(__LINE__, {"EXPIRE", key, "9"}, 1);
583
0
    DoRedisTestInt(__LINE__, {"TTL", key}, 9);
584
0
    check(values);
585
0
    modify(&values);
586
0
    SyncClient();
587
0
    std::this_thread::sleep_for(5s);
588
0
    DoRedisTestInt(__LINE__, {"TTL", key}, 4);
589
0
    check(values);
590
0
    modify(&values);
591
0
    SyncClient();
592
0
    std::this_thread::sleep_for(5s);
593
0
    SyncClient();
594
0
    expired(values);
595
0
    SyncClient();
596
    // Checking expiration changes for an earlier expiration.
597
0
    init(values);
598
0
    DoRedisTestInt(__LINE__, {"EXPIRE", key, "5"}, 1);
599
0
    modify(&values);
600
0
    DoRedisTestInt(__LINE__, {"EXPIRE", key, "3"}, 1);
601
0
    DoRedisTestInt(__LINE__, {"TTL", key}, 3);
602
0
    check(values);
603
0
    modify(&values);
604
0
    SyncClient();
605
0
    std::this_thread::sleep_for(4s);
606
0
    expired(values);
607
0
    SyncClient();
608
    // Checking persistence.
609
0
    init(values);
610
0
    DoRedisTestInt(__LINE__, {"EXPIRE", key, "6"}, 1);
611
0
    SyncClient();
612
0
    std::this_thread::sleep_for(3s);
613
0
    DoRedisTestInt(__LINE__, {"PERSIST", key}, 1);
614
0
    DoRedisTestInt(__LINE__, {"TTL", key}, -1);
615
0
    check(values);
616
0
    SyncClient();
617
0
    std::this_thread::sleep_for(6s);
618
0
    check(values);
619
0
    SyncClient();
620
    // Testing zero expiration.
621
0
    DoRedisTestInt(__LINE__, {"EXPIRE", key, "0"}, 1);
622
0
    expired(values);
623
0
    SyncClient();
624
    // Testing negative expiration.
625
0
    init(values);
626
0
    DoRedisTestInt(__LINE__, {"EXPIRE", key, "-7"}, 1);
627
0
    expired(values);
628
0
    SyncClient();
629
    // Testing SETEX turns the key back into a primitive.
630
0
    init(values);
631
0
    DoRedisTestOk(__LINE__, {"SETEX", key, "6", "17"});
632
0
    SyncClient();
633
0
    DoRedisTestBulkString(__LINE__, {"GET", key}, "17");
634
0
    SyncClient();
635
0
    std::this_thread::sleep_for(7s);
636
0
    CheckExpired(&key);
637
0
    SyncClient();
638
0
    VerifyCallbacks();
639
0
  }
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService17TestTtlCollectionINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvPS9_PT_iNS3_8functionIFvSA_SC_iEEENSD_IFvSA_SC_EEESH_NSD_IFvSA_SC_bEEENSD_IFvSA_iEEE
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService17TestTtlCollectionINSt3__15tupleIJNS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESA_EEEEEvPSA_PT_iNS3_8functionIFvSC_SE_iEEENSF_IFvSC_SE_EEESJ_NSF_IFvSC_SE_bEEENSF_IFvSC_iEEE
640
641
0
  void TestTtlSet(std::string* collection_key, std::string* collection_values, int card) {
642
0
    std::function<void(std::string*, std::string*, int)> set_init =
643
0
        [this](std::string* key, std::string* values, int size) {
644
0
          for (auto it = values; it < values + size; ++it) {
645
0
            DoRedisTestInt(__LINE__, {"SADD", *key, *it}, 1);
646
0
            SyncClient();
647
0
          }
648
0
          SyncClient();
649
0
        };
650
0
    std::function<void(std::string*, std::string*)> set_add =
651
0
        [this](std::string* key, std::string* value) {
652
0
          DoRedisTestInt(__LINE__, {"SADD", *key, *value}, 1);
653
0
        };
654
0
    std::function<void(std::string*, std::string*)> set_del =
655
0
        [this](std::string* key, std::string* value) {
656
0
          DoRedisTestInt(__LINE__, {"SREM", *key, *value}, 1);
657
0
        };
658
0
    std::function<void(std::string*, std::string*, bool)> set_check =
659
0
        [this](std::string* key, std::string* value, bool exists) {
660
0
          DoRedisTestInt(__LINE__, {"SISMEMBER", *key, *value}, exists);
661
0
        };
662
0
    std::function<void(std::string*, int)> set_card =
663
0
        [this](std::string* key, int size) {
664
0
          DoRedisTestInt(__LINE__, {"SCARD", *key}, size);
665
0
        };
666
667
0
    TestTtlCollection(collection_key, collection_values, card,
668
0
                      set_init, set_add, set_del, set_check, set_card);
669
0
  }
670
671
0
  void TestTtlSortedSet(std::string* collection_key, CollectionEntry* collection_values, int card) {
672
0
    std::function<void(std::string*, CollectionEntry*, int)> sorted_set_init =
673
0
        [this](std::string* key, CollectionEntry* values, int size) {
674
0
          for (auto it = values; it < values + size; ++it) {
675
0
            DoRedisTestInt(__LINE__, {"ZADD", *key, std::get<0>(*it), std::get<1>(*it)}, 1);
676
0
            SyncClient();
677
0
          }
678
0
          SyncClient();
679
0
        };
680
0
    std::function<void(std::string*, CollectionEntry*)> sorted_set_add =
681
0
        [this](std::string* key, CollectionEntry* value) {
682
0
          DoRedisTestInt(__LINE__, {"ZADD", *key, std::get<0>(*value), std::get<1>(*value)}, 1);
683
0
        };
684
0
    std::function<void(std::string*, CollectionEntry*)> sorted_set_del =
685
0
        [this](std::string* key, CollectionEntry* value) {
686
0
          DoRedisTestInt(__LINE__, {"ZREM", *key, std::get<1>(*value)}, 1);
687
0
        };
688
0
    std::function<void(std::string*, CollectionEntry*, bool)> sorted_set_check =
689
0
        [this](std::string* key, CollectionEntry* value, bool exists) {
690
0
          if (exists) {
691
0
            char buf[20];
692
0
            std::snprintf(buf, sizeof(buf), "%.6f", std::stof(std::get<0>(*value)));
693
0
            DoRedisTestBulkString(__LINE__, {"ZSCORE", *key, std::get<1>(*value)},
694
0
                                  buf);
695
0
          } else {
696
0
            DoRedisTestNull(__LINE__, {"ZSCORE", *key, std::get<1>(*value)});
697
0
          }
698
0
        };
699
0
    std::function<void(std::string*, int)> sorted_set_card =
700
0
        [this](std::string* key, int size) {
701
0
          DoRedisTestInt(__LINE__, {"ZCARD", *key}, size);
702
0
        };
703
704
0
    TestTtlCollection(collection_key, collection_values, card,
705
0
                      sorted_set_init, sorted_set_add, sorted_set_del,
706
0
                      sorted_set_check, sorted_set_card);
707
0
  }
708
709
0
  void TestTtlHash(std::string* collection_key, CollectionEntry* collection_values, int card) {
710
0
    std::function<void(std::string*, CollectionEntry*, int)> hash_init =
711
0
        [this](std::string* key, CollectionEntry* values, int size) {
712
0
          for (auto it = values; it < values + size; ++it) {
713
0
            DoRedisTestInt(__LINE__, {"HSET", *key, std::get<0>(*it), std::get<1>(*it)}, 1);
714
0
            SyncClient();
715
0
          }
716
0
          SyncClient();
717
0
        };
718
0
    std::function<void(std::string*, CollectionEntry*)> hash_add =
719
0
        [this](std::string* key, CollectionEntry* value) {
720
0
          DoRedisTestInt(__LINE__, {"HSET", *key, std::get<0>(*value), std::get<1>(*value)}, 1);
721
0
        };
722
0
    std::function<void(std::string*, CollectionEntry*)> hash_del =
723
0
        [this](std::string* key, CollectionEntry* value) {
724
0
          DoRedisTestInt(__LINE__, {"HDEL", *key, std::get<0>(*value)}, 1);
725
0
        };
726
0
    std::function<void(std::string*, CollectionEntry*, bool)> hash_check =
727
0
        [this](std::string* key, CollectionEntry* value, bool exists) {
728
0
          if (exists)
729
0
            DoRedisTestBulkString(__LINE__, {"HGET", *key, std::get<0>(*value)},
730
0
                                  std::get<1>(*value));
731
0
          else
732
0
            DoRedisTestNull(__LINE__, {"HGET", *key, std::get<0>(*value)});
733
0
        };
734
0
    std::function<void(std::string*, int)> hash_card =
735
0
        [this](std::string* key, int size) {
736
0
          DoRedisTestInt(__LINE__, {"HLEN", *key}, size);
737
0
        };
738
739
0
    TestTtlCollection(collection_key, collection_values, card,
740
0
                      hash_init, hash_add, hash_del, hash_check, hash_card);
741
0
  }
742
743
  void TestAbort(const std::string& command);
744
745
 protected:
746
  std::string int64Max_ = std::to_string(std::numeric_limits<int64_t>::max());
747
  std::string int64MaxExclusive_ = "(" + int64Max_;
748
  std::string int64Min_ = std::to_string(std::numeric_limits<int64_t>::min());
749
  std::string int64MinExclusive_ = "(" + int64Min_;
750
  uint64_t redis_max_read_buffer_size_ = 512_MB;
751
752
 private:
753
  std::atomic<int> num_callbacks_called_{0};
754
  int expected_callbacks_called_ = 0;
755
  Socket client_sock_;
756
  unique_ptr<RedisServer> server_;
757
  int redis_server_port_ = 0;
758
  unique_ptr<FileLock> redis_port_lock_;
759
  unique_ptr<FileLock> redis_webserver_lock_;
760
  std::vector<uint8_t> resp_;
761
  boost::optional<rpc::IoThreadPool> io_thread_pool_;
762
  std::shared_ptr<RedisClient> test_client_;
763
};
764
765
class NoLocalCallsRedisServiceTest : public TestRedisService {
766
 public:
767
0
  void SetUp() override {
768
0
    FLAGS_enable_direct_local_tablet_server_call = false;
769
0
    TestRedisService::SetUp();
770
0
  }
771
};
772
773
774
0
void TestRedisService::SetUp() {
775
0
  FLAGS_redis_service_yb_client_timeout_millis = kDefaultTimeoutMs;
776
0
  if (IsSanitizer()) {
777
0
    FLAGS_redis_max_value_size = 1_MB;
778
0
    FLAGS_rpc_max_message_size = FLAGS_redis_max_value_size * 4 - 1;
779
0
    FLAGS_redis_max_command_size = FLAGS_rpc_max_message_size - 2_KB;
780
0
    FLAGS_consensus_max_batch_size_bytes = FLAGS_rpc_max_message_size - 2_KB;
781
0
  } else {
782
0
#ifndef NDEBUG
783
0
    FLAGS_redis_max_value_size = 32_MB;
784
0
    FLAGS_rpc_max_message_size = FLAGS_redis_max_value_size * 4 - 1;
785
0
    FLAGS_redis_max_command_size = FLAGS_rpc_max_message_size - 2_KB;
786
0
    FLAGS_consensus_max_batch_size_bytes = FLAGS_rpc_max_message_size - 2_KB;
787
0
    FLAGS_consensus_rpc_timeout_ms = 3000;
788
0
#endif
789
0
  }
790
0
  FLAGS_redis_max_read_buffer_size = redis_max_read_buffer_size_;
791
0
  LOG(INFO) << "FLAGS_redis_max_read_buffer_size=" << FLAGS_redis_max_read_buffer_size
792
0
            << ", FLAGS_redis_max_queued_bytes=" << FLAGS_redis_max_queued_bytes;
793
794
0
  RedisTableTestBase::SetUp();
795
796
0
  StartServer();
797
0
  StartClient();
798
0
}
799
800
0
void TestRedisService::StartServer() {
801
0
  if (use_external_mini_cluster()) {
802
0
    redis_server_port_ = external_mini_cluster()->tablet_server(0)->redis_rpc_port();
803
0
    return;
804
0
  }
805
806
0
  redis_server_port_ = GetFreePort(&redis_port_lock_);
807
0
  RedisServerOptions opts;
808
0
  opts.rpc_opts.rpc_bind_addresses = AsString(RedisProxyEndpoint());
809
  // No need to save the webserver port, as we don't plan on using it. Just use a unique free port.
810
0
  opts.webserver_opts.port = GetFreePort(&redis_webserver_lock_);
811
0
  string fs_root = GetTestPath("RedisServerTest-fsroot");
812
0
  opts.fs_opts.wal_paths = {fs_root};
813
0
  opts.fs_opts.data_paths = {fs_root};
814
815
0
  auto master_rpc_addrs = master_rpc_addresses_as_strings();
816
0
  opts.master_addresses_flag = JoinStrings(master_rpc_addrs, ",");
817
818
0
  server_ = std::make_unique<RedisServer>(opts, mini_cluster()->mini_tablet_server(0)->server());
819
0
  LOG(INFO) << "Starting redis server...";
820
0
  CHECK_OK(server_->Start());
821
0
  LOG(INFO) << "Redis server successfully started.";
822
0
}
823
824
0
void TestRedisService::StopServer() {
825
0
  if (!server_) {
826
0
    return;
827
0
  }
828
0
  LOG(INFO) << "Shut down redis server...";
829
0
  server_->Shutdown();
830
0
  server_.reset();
831
0
  LOG(INFO) << "Redis server successfully shut down.";
832
0
}
833
834
0
void TestRedisService::StartClient() {
835
0
  Endpoint remote = RedisProxyEndpoint();
836
0
  CHECK_OK(client_sock_.Init(0));
837
0
  CHECK_OK(client_sock_.SetNoDelay(false));
838
0
  LOG(INFO) << "Connecting to " << remote;
839
0
  CHECK_OK(client_sock_.Connect(remote));
840
0
  Endpoint local;
841
0
  CHECK_OK(client_sock_.GetSocketAddress(&local));
842
0
  CHECK_OK(client_sock_.GetPeerAddress(&remote));
843
0
  LOG(INFO) << "Connected: " << local << " => " << remote;
844
0
}
845
846
0
void TestRedisService::StopClient() { EXPECT_OK(client_sock_.Close()); }
847
848
0
void TestRedisService::RestartClient() {
849
0
  StopClient();
850
0
  StartClient();
851
0
}
852
853
0
void TestRedisService::CloseRedisClient() {
854
0
  if (test_client_) {
855
0
    test_client_->Disconnect();
856
0
    test_client_.reset();
857
0
  }
858
0
  if (io_thread_pool_) {
859
0
    io_thread_pool_->Shutdown();
860
0
    io_thread_pool_->Join();
861
0
  }
862
0
  StopClient();
863
0
}
864
865
0
void TestRedisService::TearDown() {
866
0
  if (!use_external_mini_cluster()) {
867
0
    size_t allocated_sessions = CountSessions(METRIC_redis_allocated_sessions);
868
0
    if (!expected_no_sessions_) {
869
0
      EXPECT_GT(allocated_sessions, 0); // Check that metric is sane.
870
0
    } else {
871
0
      EXPECT_EQ(0, allocated_sessions);
872
0
    }
873
0
    EXPECT_EQ(allocated_sessions, CountSessions(METRIC_redis_available_sessions));
874
0
  }
875
876
0
  CloseRedisClient();
877
0
  StopServer();
878
0
  RedisTableTestBase::TearDown();
879
0
}
880
881
0
Status TestRedisService::Send(const std::string& cmd) {
882
  // Send the command.
883
0
  auto bytes_written = EXPECT_RESULT(client_sock_.Write(to_uchar_ptr(cmd.c_str()), cmd.length()));
884
885
0
  EXPECT_EQ(cmd.length(), bytes_written);
886
887
0
  return Status::OK();
888
0
}
889
890
Status TestRedisService::SendCommandAndGetResponse(
891
0
    const string& cmd, size_t expected_resp_length, int timeout_in_millis) {
892
0
  RETURN_NOT_OK(Send(cmd));
893
894
  // Receive the response.
895
0
  MonoTime deadline = MonoTime::Now();
896
0
  deadline.AddDelta(MonoDelta::FromMilliseconds(timeout_in_millis));
897
0
  resp_.resize(expected_resp_length);
898
0
  if (expected_resp_length) {
899
0
    memset(resp_.data(), 0, expected_resp_length);
900
0
  }
901
0
  auto bytes_read = VERIFY_RESULT(client_sock_.BlockingRecv(
902
0
      resp_.data(), expected_resp_length, deadline));
903
0
  resp_.resize(bytes_read);
904
0
  if (expected_resp_length != bytes_read) {
905
0
    return STATUS(
906
0
        IOError, Substitute("Received $1 bytes instead of $2", bytes_read, expected_resp_length));
907
0
  }
908
0
  return Status::OK();
909
0
}
910
911
0
void TestRedisService::SendCommandAndExpectTimeout(const string& cmd) {
912
  // Don't expect to receive even 1 byte.
913
0
  ASSERT_TRUE(SendCommandAndGetResponse(cmd, 1).IsTimedOut());
914
0
}
915
916
void TestRedisService::SendCommandAndExpectResponse(int line,
917
    const string& cmd,
918
    const string& expected,
919
0
    bool partial) {
920
0
  if (partial) {
921
0
    auto seed = GetRandomSeed32();
922
0
    std::mt19937_64 rng(seed);
923
0
    size_t last = cmd.length() - 2;
924
0
    size_t splits = std::uniform_int_distribution<size_t>(1, 10)(rng);
925
0
    std::vector<size_t> bounds(splits);
926
0
    std::generate(bounds.begin(), bounds.end(), [&rng, last]{
927
0
      return std::uniform_int_distribution<size_t>(1, last)(rng);
928
0
    });
929
0
    std::sort(bounds.begin(), bounds.end());
930
0
    bounds.erase(std::unique(bounds.begin(), bounds.end()), bounds.end());
931
0
    size_t p = 0;
932
0
    for (auto i : bounds) {
933
0
      ASSERT_OK(Send(cmd.substr(p, i - p)));
934
0
      p = i;
935
0
      std::this_thread::sleep_for(std::chrono::milliseconds(5));
936
0
    }
937
0
    ASSERT_OK(SendCommandAndGetResponse(cmd.substr(p), expected.length()));
938
0
  } else {
939
0
    auto status = SendCommandAndGetResponse(cmd, expected.length());
940
0
    if (!status.ok()) {
941
0
      LOG(INFO) << "    Sent: " << Slice(cmd).ToDebugString();
942
0
      LOG(INFO) << "Received: " << Slice(resp_.data(), resp_.size()).ToDebugString();
943
0
      LOG(INFO) << "Expected: " << Slice(expected).ToDebugString();
944
0
    }
945
0
    ASSERT_OK(status);
946
0
  }
947
948
  // Verify that the response is as expected.
949
950
0
  std::string response(to_char_ptr(resp_.data()), expected.length());
951
0
  ASSERT_EQ(expected, response)
952
0
                << "Command: " << Slice(cmd).ToDebugString() << std::endl
953
0
                << "Originator: " << __FILE__ << ":" << line;
954
0
}
955
956
template <class Callback>
957
void TestRedisService::DoRedisTest(int line,
958
    const std::vector<std::string>& command,
959
    RedisReplyType reply_type,
960
0
    const Callback& callback) {
961
0
  expected_callbacks_called_++;
962
0
  VLOG(4) << "Testing with line: " << __FILE__ << ":" << line;
963
0
  client().Send(command, [this, line, reply_type, callback](const RedisReply& reply) {
964
0
    VLOG(4) << "Received response for line: " << __FILE__ << ":" << line << " : "
965
0
            << reply.as_string() << ", of type: " << to_underlying(reply.get_type());
966
0
    num_callbacks_called_++;
967
0
    ASSERT_EQ(reply_type, reply.get_type())
968
0
        << "Originator: " << __FILE__ << ":" << line << ", reply: "
969
0
        << Max500CharsPrinter(reply.ToString());
970
0
    callback(reply);
971
0
  });
972
0
}
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS1_17DoRedisTestStringEiRKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEERKSA_NS0_14RedisReplyTypeEEUlRKNS0_10RedisReplyEE_EEviSE_SH_RKT_
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS1_22DoRedisTestExpectErrorEiRKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEERKSA_EUlRKNS0_10RedisReplyEE_EEviSE_NS0_14RedisReplyTypeERKT_
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS1_14DoRedisTestIntEiRKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEExEUlRKNS0_10RedisReplyEE_EEviSE_NS0_14RedisReplyTypeERKT_
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS1_15DoRedisTestNullEiRKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEEEUlRKNS0_10RedisReplyEE_EEviSE_NS0_14RedisReplyTypeERKT_
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS1_39DoRedisTestExpectSimpleStringEndingWithEiRKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEERKSA_EUlRKNS0_10RedisReplyEE_EEviSE_NS0_14RedisReplyTypeERKT_
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS1_23DoRedisTestResultsArrayEiRKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEERKNS4_INS0_10RedisReplyENS8_ISF_EEEEEUlRKSF_E_EEviSE_NS0_14RedisReplyTypeERKT_
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS1_26DoRedisTestScoreValueArrayEiRKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEERKNS4_IdNS8_IdEEEESE_EUlRKNS0_10RedisReplyEE_EEviSE_NS0_14RedisReplyTypeERKT_
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS1_17DoRedisTestDoubleEiRKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEEdEUlRKNS0_10RedisReplyEE_EEviSE_NS0_14RedisReplyTypeERKT_
Unexecuted instantiation: _ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS1_19DoRedisTestIntRangeEiRKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEExxEUlRKNS0_10RedisReplyEE_EEviSE_NS0_14RedisReplyTypeERKT_
Unexecuted instantiation: redisserver-test.cc:_ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS0_47TestRedisService_TestUsingOpenSourceClient_Test8TestBodyEvE3$_1EEviRKNSt3__16vectorINS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEENSA_ISC_EEEENS0_14RedisReplyTypeERKT_
Unexecuted instantiation: redisserver-test.cc:_ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS0_36TestRedisService_TestDummyLocal_Test8TestBodyEvE3$_2EEviRKNSt3__16vectorINS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEENSA_ISC_EEEENS0_14RedisReplyTypeERKT_
Unexecuted instantiation: redisserver-test.cc:_ZN2yb11redisserver16TestRedisService11DoRedisTestIZNS0_44TestRedisService_TestAdditionalCommands_Test8TestBodyEvE3$_3EEviRKNSt3__16vectorINS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEENSA_ISC_EEEENS0_14RedisReplyTypeERKT_
973
974
0
void TestRedisService::VerifyCallbacks() {
975
0
  ASSERT_EQ(expected_callbacks_called_, num_callbacks_called_.load(std::memory_order_acquire));
976
0
}
977
978
0
TEST_F(TestRedisService, SimpleCommandInline) {
979
0
  SendCommandAndExpectResponse(__LINE__, "set foo bar\r\n", "+OK\r\n");
980
0
}
981
982
0
void TestRedisService::TestAbort(const std::string& command) {
983
0
  ASSERT_OK(Send(command));
984
0
  std::this_thread::sleep_for(1000ms);
985
0
  StopClient();
986
987
  // TODO When reactor is shutting down, we cannot notify it that call is responded.
988
  // It is possible that it could happen not only with debug sleep.
989
0
  std::this_thread::sleep_for(2000ms);
990
0
}
991
992
0
TEST_F(TestRedisService, AbortDuringProcessing) {
993
0
  TestAbort("DEBUGSLEEP 2000\r\n");
994
0
}
995
996
class TestRedisServiceCleanQueueOnShutdown : public TestRedisService {
997
 public:
998
0
  void SetUp() override {
999
0
    saver_.emplace();
1000
1001
0
    FLAGS_redis_max_concurrent_commands = 1;
1002
0
    FLAGS_redis_max_batch = 1;
1003
0
    TestRedisService::SetUp();
1004
0
  }
1005
1006
0
  void TearDown() override {
1007
0
    TestRedisService::TearDown();
1008
0
    saver_.reset();
1009
0
  }
1010
1011
 private:
1012
  boost::optional<google::FlagSaver> saver_;
1013
};
1014
1015
0
TEST_F_EX(TestRedisService, AbortQueueOnShutdown, TestRedisServiceCleanQueueOnShutdown) {
1016
0
  TestAbort("DEBUGSLEEP 2000\r\nDEBUGSLEEP 999999999\r\n");
1017
0
}
1018
1019
0
TEST_F(TestRedisService, AbortBatches) {
1020
0
  TestAbort("DEBUGSLEEP 2000\r\nSET foo 1\r\nGET foo\r\nDEBUGSLEEP 999999999\r\n");
1021
0
}
1022
1023
class TestRedisServiceReceiveBufferOverflow : public TestRedisService {
1024
 public:
1025
0
  void SetUp() override {
1026
0
    saver_.emplace();
1027
1028
0
    FLAGS_redis_max_concurrent_commands = 1;
1029
0
    FLAGS_redis_max_batch = 1;
1030
    // TODO FLAGS_rpc_initial_buffer_size = 128;
1031
0
    redis_max_read_buffer_size_changer_.Init(128, &redis_max_read_buffer_size_);
1032
0
    FLAGS_redis_max_queued_bytes = 0;
1033
0
    TestRedisService::SetUp();
1034
0
  }
1035
1036
0
  void TearDown() override {
1037
0
    TestRedisService::TearDown();
1038
0
    redis_max_read_buffer_size_changer_.Reset();
1039
0
    saver_.reset();
1040
0
  }
1041
1042
 private:
1043
  boost::optional<google::FlagSaver> saver_;
1044
  ValueChanger<uint64_t> redis_max_read_buffer_size_changer_;
1045
};
1046
1047
0
TEST_F_EX(TestRedisService, ReceiveBufferOverflow, TestRedisServiceReceiveBufferOverflow) {
1048
0
  auto key = std::string(FLAGS_redis_max_read_buffer_size - 12, 'X');
1049
0
  SendCommandAndExpectResponse(
1050
0
      __LINE__, Format("DEBUGSLEEP 2000\r\nSET key $0\r\n", key), "+OK\r\n+OK\r\n");
1051
1052
0
  SendCommandAndExpectResponse(
1053
0
      __LINE__,
1054
0
      Format("DEBUGSLEEP 2000\r\nSET key1 $0\r\nSET key2 $0\r\n", key, key),
1055
0
      "+OK\r\n+OK\r\n+OK\r\n");
1056
0
}
1057
1058
class TestTooBigCommand : public TestRedisService {
1059
0
  void SetUp() override {
1060
0
    FLAGS_redis_rpc_block_size = 32;
1061
0
    redis_max_read_buffer_size_changer_.Init(1024, &redis_max_read_buffer_size_);
1062
0
    TestRedisService::SetUp();
1063
0
  }
1064
1065
0
  void TearDown() override {
1066
0
    TestRedisService::TearDown();
1067
0
    redis_max_read_buffer_size_changer_.Reset();
1068
0
  }
1069
1070
 private:
1071
  ValueChanger<uint64_t> redis_max_read_buffer_size_changer_;
1072
};
1073
1074
TEST_F_EX(TestRedisService, TooBigCommand, TestTooBigCommand) {
1075
  std::string small_key(FLAGS_redis_max_read_buffer_size / 2, 'X');
1076
  SendCommandAndExpectResponse(
1077
      __LINE__, Format("SET key1 $0\r\nSET key2 $0\r\n", small_key), "+OK\r\n+OK\r\n");
1078
  std::string big_key(FLAGS_redis_max_read_buffer_size, 'X');
1079
  std::string key_suffix(FLAGS_redis_rpc_block_size, 'Y');
1080
  auto status = SendCommandAndGetResponse(Format("SET key$0 $1\r\n", key_suffix, big_key), 1);
1081
  ASSERT_TRUE(status.IsNetworkError()) << "Status: " << status;
1082
}
1083
1084
0
TEST_F_EX(TestRedisService, HugeCommandInline, NoLocalCallsRedisServiceTest) {
1085
  // Set a larger timeout for the yql layer : 1 min vs 10 min for tsan/asan.
1086
0
  FLAGS_redis_service_yb_client_timeout_millis = 6 * kDefaultTimeoutMs;
1087
1088
0
  LOG(INFO) << "Creating a value of size " << FLAGS_redis_max_value_size;
1089
0
  std::string value(FLAGS_redis_max_value_size, 'T');
1090
0
  DoRedisTestOk(__LINE__, {"SET", "foo", value});
1091
0
  SyncClient();
1092
0
  DoRedisTestBulkString(__LINE__, {"GET", "foo"}, value);
1093
0
  SyncClient();
1094
0
  DoRedisTestOk(__LINE__, {"SET", "foo", "Test"});
1095
0
  DoRedisTestBulkString(__LINE__, {"GET", "foo"}, "Test");
1096
0
  SyncClient();
1097
0
  DoRedisTestExpectError(__LINE__, {"SET", "foo", "Too much" + value});
1098
0
  SyncClient();
1099
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "subkey1", value}, 1);
1100
0
  SyncClient();
1101
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "subkey2", value}, 1);
1102
0
  SyncClient();
1103
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "subkey3", value}, 1);
1104
0
  SyncClient();
1105
0
  DoRedisTestArray(__LINE__, {"HGETALL", "map_key"}, {"subkey1", value, "subkey2", value,
1106
0
      "subkey3", value});
1107
0
  SyncClient();
1108
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "subkey4", value}, 1);
1109
0
  DoRedisTestExpectError(__LINE__, {"HGETALL", "map_key"});
1110
0
  SyncClient();
1111
0
  DoRedisTestInt(__LINE__, {"DEL", "map_key"}, 1);
1112
0
  SyncClient();
1113
0
  DoRedisTestInt(__LINE__, {"DEL", "foo"}, 1);
1114
0
  SyncClient();
1115
0
  value[0]  = 'A';
1116
0
  DoRedisTestOk(
1117
0
      __LINE__, {"HMSET", "map_key1", "subkey1", value, "subkey2", value, "subkey3", value});
1118
0
  SyncClient();
1119
0
  DoRedisTestArray(
1120
0
      __LINE__, {"HGETALL", "map_key1"}, {"subkey1", value, "subkey2", value, "subkey3", value});
1121
0
  SyncClient();
1122
0
  value[0] = 'B';
1123
0
  DoRedisTestExpectError(
1124
0
      __LINE__,
1125
0
      {"HMSET", "map_key1", "subkey1", value, "subkey2", value, "subkey3", value,
1126
0
          "subkey4", value});
1127
0
  SyncClient();
1128
0
  VerifyCallbacks();
1129
0
}
1130
1131
0
TEST_F(TestRedisService, SimpleCommandMulti) {
1132
0
  SendCommandAndExpectResponse(
1133
0
      __LINE__, "*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n", "+OK\r\n");
1134
0
}
1135
1136
0
TEST_F(TestRedisService, BatchedCommandsInline) {
1137
0
  SendCommandAndExpectResponse(
1138
0
      __LINE__,
1139
0
      "set a 5\r\nset foo bar\r\nget foo\r\nget a\r\n",
1140
0
      "+OK\r\n+OK\r\n$3\r\nbar\r\n$1\r\n5\r\n");
1141
0
}
1142
1143
0
TEST_F(TestRedisService, TestTimedoutInQueue) {
1144
0
  FLAGS_redis_max_batch = 1;
1145
0
  SetAtomicFlag(true, &FLAGS_TEST_enable_backpressure_mode_for_testing);
1146
1147
0
  DoRedisTestOk(__LINE__, {"SET", "foo", "value"});
1148
0
  DoRedisTestBulkString(__LINE__, {"GET", "foo"}, "value");
1149
0
  DoRedisTestOk(__LINE__, {"SET", "foo", "Test"});
1150
1151
  // All calls past this call should fail.
1152
0
  DoRedisTestOk(__LINE__, {"DEBUGSLEEP", yb::ToString(FLAGS_max_time_in_queue_ms)});
1153
1154
0
  const string expected_message =
1155
0
      "The server is overloaded. Call waited in the queue past max_time_in_queue.";
1156
0
  DoRedisTestExpectError(__LINE__, {"SET", "foo", "Test"}, expected_message);
1157
0
  DoRedisTestExpectError(__LINE__, {"GET", "foo"}, expected_message);
1158
0
  DoRedisTestExpectError(__LINE__, {"DEBUGSLEEP", "2000"}, expected_message);
1159
1160
0
  SyncClient();
1161
0
  VerifyCallbacks();
1162
0
}
1163
1164
0
TEST_F(TestRedisService, BatchedCommandsInlinePartial) {
1165
0
  for (int i = 0; i != 1000; ++i) {
1166
0
    ASSERT_NO_FATAL_FAILURE(
1167
0
        SendCommandAndExpectResponse(
1168
0
            __LINE__,
1169
0
            "set a 5\r\nset foo bar\r\nget foo\r\nget a\r\n",
1170
0
            "+OK\r\n+OK\r\n$3\r\nbar\r\n$1\r\n5\r\n",
1171
0
            /* partial */ true)
1172
0
    );
1173
0
  }
1174
0
}
1175
1176
namespace {
1177
1178
class TestRedisServicePipelined : public TestRedisService {
1179
 public:
1180
0
  void SetUp() override {
1181
0
    FLAGS_redis_safe_batch = false;
1182
0
    FLAGS_redis_max_concurrent_commands = FLAGS_test_redis_max_concurrent_commands;
1183
0
    FLAGS_redis_max_batch = FLAGS_test_redis_max_batch;
1184
0
    TestRedisService::SetUp();
1185
0
  }
1186
};
1187
1188
#ifndef THREAD_SANITIZER
1189
const size_t kPipelineKeys = 1000;
1190
#else
1191
const size_t kPipelineKeys = 100;
1192
#endif
1193
1194
0
size_t ValueForKey(size_t key) {
1195
0
  return key * 2;
1196
0
}
1197
1198
0
std::string PipelineSetCommand() {
1199
0
  std::string command;
1200
0
  for (size_t i = 0; i != kPipelineKeys; ++i) {
1201
0
    command += yb::Format("set $0 $1\r\n", i, ValueForKey(i));
1202
0
  }
1203
0
  return command;
1204
0
}
1205
1206
0
std::string PipelineSetResponse() {
1207
0
  std::string response;
1208
0
  for (size_t i = 0; i != kPipelineKeys; ++i) {
1209
0
    response += "+OK\r\n";
1210
0
  }
1211
0
  return response;
1212
0
}
1213
1214
0
std::string PipelineGetCommand() {
1215
0
  std::string command;
1216
0
  for (size_t i = 0; i != kPipelineKeys; ++i) {
1217
0
    command += yb::Format("get $0\r\n", i);
1218
0
  }
1219
0
  return command;
1220
0
}
1221
1222
0
std::string PipelineGetResponse() {
1223
0
  std::string response;
1224
0
  for (size_t i = 0; i != kPipelineKeys; ++i) {
1225
0
    std::string value = std::to_string(ValueForKey(i));
1226
0
    response += yb::Format("$$$0\r\n$1\r\n", value.length(), value);
1227
0
  }
1228
0
  return response;
1229
0
}
1230
1231
} // namespace
1232
1233
0
TEST_F_EX(TestRedisService, Pipeline, TestRedisServicePipelined) {
1234
0
  auto start = std::chrono::steady_clock::now();
1235
0
  SendCommandAndExpectResponse(__LINE__, PipelineSetCommand(), PipelineSetResponse());
1236
0
  auto mid = std::chrono::steady_clock::now();
1237
0
  SendCommandAndExpectResponse(__LINE__, PipelineGetCommand(), PipelineGetResponse());
1238
0
  auto end = std::chrono::steady_clock::now();
1239
0
  auto set_time = std::chrono::duration_cast<std::chrono::milliseconds>(mid - start);
1240
0
  auto get_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - mid);
1241
0
  LOG(INFO) << yb::Format("Unsafe set: $0ms, get: $1ms", set_time.count(), get_time.count());
1242
0
}
1243
1244
0
TEST_F_EX(TestRedisService, PipelinePartial, TestRedisServicePipelined) {
1245
0
  SendCommandAndExpectResponse(__LINE__,
1246
0
      PipelineSetCommand(),
1247
0
      PipelineSetResponse(),
1248
0
      true /* partial */);
1249
0
  SendCommandAndExpectResponse(__LINE__,
1250
0
      PipelineGetCommand(),
1251
0
      PipelineGetResponse(),
1252
0
      true /* partial */);
1253
0
}
1254
1255
namespace {
1256
1257
class BatchGenerator {
1258
 public:
1259
0
  explicit BatchGenerator(bool collisions) : collisions_(collisions), random_(293462970) {}
1260
1261
0
  std::pair<std::string, std::string> Generate() {
1262
0
    new_values_.clear();
1263
0
    requested_keys_.clear();
1264
0
    std::string command, response;
1265
0
    size_t size = size_distribution_(random_);
1266
0
    for (size_t j = 0; j != size; ++j) {
1267
0
      bool get = !keys_.empty() && (bool_distribution_(random_) != 0);
1268
0
      if (get) {
1269
0
        int key = keys_[std::uniform_int_distribution<size_t>(0, keys_.size() - 1)(random_)];
1270
0
        if (!collisions_ && new_values_.count(key)) {
1271
0
          continue;
1272
0
        }
1273
0
        command += yb::Format("get $0\r\n", key);
1274
0
        auto value = std::to_string(values_[key]);
1275
0
        response += yb::Format("$$$0\r\n$1\r\n", value.length(), value);
1276
0
        requested_keys_.insert(key);
1277
0
      } else {
1278
0
        int value = value_distribution_(random_);
1279
0
        for (;;) {
1280
0
          int key = key_distribution_(random_);
1281
0
          if (collisions_) {
1282
0
            StoreValue(key, value);
1283
0
          } else if(requested_keys_.count(key) || !new_values_.emplace(key, value).second) {
1284
0
            continue;
1285
0
          }
1286
0
          command += yb::Format("set $0 $1\r\n", key, value);
1287
0
          response += "+OK\r\n";
1288
0
          break;
1289
0
        }
1290
0
      }
1291
0
    }
1292
1293
0
    for (const auto& p : new_values_) {
1294
0
      StoreValue(p.first, p.second);
1295
0
    }
1296
0
    return std::make_pair(std::move(command), std::move(response));
1297
0
  }
1298
 private:
1299
0
  void StoreValue(int key, int value) {
1300
0
    auto it = values_.find(key);
1301
0
    if (it == values_.end()) {
1302
0
      values_.emplace(key, value);
1303
0
      keys_.push_back(key);
1304
0
    } else {
1305
0
      it->second = value;
1306
0
    }
1307
0
  }
1308
1309
  static constexpr size_t kMinSize = 500;
1310
  static constexpr size_t kMaxSize = kMinSize + 511;
1311
  static constexpr int kMinKey = 0;
1312
  static constexpr int kMaxKey = 1023;
1313
  static constexpr int kMinValue = 0;
1314
  static constexpr int kMaxValue = 1023;
1315
1316
  const bool collisions_;
1317
  std::mt19937_64 random_;
1318
  std::uniform_int_distribution<int> bool_distribution_{0, 1};
1319
  std::uniform_int_distribution<size_t> size_distribution_{kMinSize, kMaxSize};
1320
  std::uniform_int_distribution<int> key_distribution_{kMinKey, kMaxKey};
1321
  std::uniform_int_distribution<int> value_distribution_{kMinValue, kMaxValue};
1322
1323
  std::unordered_map<int, int> values_;
1324
  std::unordered_map<int, int> new_values_;
1325
  std::unordered_set<int> requested_keys_;
1326
  std::vector<int> keys_;
1327
};
1328
1329
} // namespace
1330
1331
0
TEST_F_EX(TestRedisService, MixedBatch, TestRedisServicePipelined) {
1332
0
  constexpr size_t kBatches = 50;
1333
0
  BatchGenerator generator(false);
1334
0
  for (size_t i = 0; i != kBatches; ++i) {
1335
0
    auto batch = generator.Generate();
1336
0
    SendCommandAndExpectResponse(__LINE__, batch.first, batch.second);
1337
0
  }
1338
0
}
1339
1340
class TestRedisServiceSafeBatch : public TestRedisService {
1341
 public:
1342
0
  void SetUp() override {
1343
0
    FLAGS_redis_max_concurrent_commands = 1;
1344
0
    FLAGS_redis_max_batch = FLAGS_test_redis_max_batch;
1345
0
    FLAGS_redis_safe_batch = true;
1346
0
    TestRedisService::SetUp();
1347
0
  }
1348
};
1349
1350
0
TEST_F_EX(TestRedisService, SafeMixedBatch, TestRedisServiceSafeBatch) {
1351
0
  constexpr size_t kBatches = 50;
1352
0
  BatchGenerator generator(true);
1353
0
  std::vector<decltype(generator.Generate())> batches;
1354
0
  for (size_t i = 0; i != kBatches; ++i) {
1355
0
    batches.push_back(generator.Generate());
1356
0
  }
1357
0
  auto start = std::chrono::steady_clock::now();
1358
0
  for (const auto& batch : batches) {
1359
0
    SendCommandAndExpectResponse(__LINE__, batch.first, batch.second);
1360
0
  }
1361
0
  auto total = std::chrono::steady_clock::now() - start;
1362
0
  auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(total).count();
1363
0
  LOG(INFO) << Format("Total: $0ms, average: $1ms", ms, ms / kBatches);
1364
0
}
1365
1366
0
TEST_F_EX(TestRedisService, SafeBatchPipeline, TestRedisServiceSafeBatch) {
1367
0
  auto start = std::chrono::steady_clock::now();
1368
0
  SendCommandAndExpectResponse(__LINE__, PipelineSetCommand(), PipelineSetResponse());
1369
0
  auto mid = std::chrono::steady_clock::now();
1370
0
  SendCommandAndExpectResponse(__LINE__, PipelineGetCommand(), PipelineGetResponse());
1371
0
  auto end = std::chrono::steady_clock::now();
1372
0
  auto set_time = std::chrono::duration_cast<std::chrono::milliseconds>(mid - start);
1373
0
  auto get_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - mid);
1374
0
  LOG(INFO) << yb::Format("Safe set: $0ms, get: $1ms", set_time.count(), get_time.count());
1375
0
}
1376
1377
0
TEST_F(TestRedisService, BatchedCommandMulti) {
1378
0
  SendCommandAndExpectResponse(
1379
0
      __LINE__,
1380
0
      "*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n"
1381
0
          "*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n"
1382
0
          "*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n",
1383
0
      "+OK\r\n+OK\r\n+OK\r\n");
1384
0
}
1385
1386
0
TEST_F(TestRedisService, BatchedCommandMultiPartial) {
1387
0
  for (int i = 0; i != 1000; ++i) {
1388
0
    ASSERT_NO_FATAL_FAILURE(
1389
0
        SendCommandAndExpectResponse(
1390
0
            __LINE__,
1391
0
            "*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$5\r\nTEST1\r\n"
1392
0
                "*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$5\r\nTEST2\r\n"
1393
0
                "*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$5\r\nTEST3\r\n"
1394
0
                "*2\r\n$3\r\nget\r\n$3\r\nfoo\r\n",
1395
0
            "+OK\r\n+OK\r\n+OK\r\n$5\r\nTEST3\r\n",
1396
0
            /* partial */ true)
1397
0
    );
1398
0
  }
1399
0
}
1400
1401
0
TEST_F(TestRedisService, IncompleteCommandInline) {
1402
0
  expected_no_sessions_ = true;
1403
0
  SendCommandAndExpectTimeout("TEST");
1404
0
}
1405
1406
0
TEST_F(TestRedisService, MalformedCommandsFollowedByAGoodOne) {
1407
0
  expected_no_sessions_ = true;
1408
0
  ASSERT_NOK(SendCommandAndGetResponse("*3\r\n.1\r\n", 1));
1409
0
  RestartClient();
1410
0
  ASSERT_NOK(SendCommandAndGetResponse("*0\r\n.2\r\n", 1));
1411
0
  RestartClient();
1412
0
  ASSERT_NOK(SendCommandAndGetResponse("*-4\r\n.3\r\n", 1));
1413
0
  RestartClient();
1414
0
  SendCommandAndExpectResponse(__LINE__, "*2\r\n$4\r\necho\r\n$3\r\nfoo\r\n", "$3\r\nfoo\r\n");
1415
0
}
1416
1417
namespace {
1418
1419
0
void TestBadCommand(std::string command, TestRedisService* test) {
1420
0
  ASSERT_NOK(test->SendCommandAndGetResponse(command, 1)) << "Command: " << command;
1421
0
  test->RestartClient();
1422
1423
0
  command.erase(std::remove(command.begin(), command.end(), '\n'), command.end());
1424
1425
0
  if (!command.empty()) {
1426
0
    ASSERT_NOK(test->SendCommandAndGetResponse(command, 1)) << "Command: " << command;
1427
0
    test->RestartClient();
1428
0
  }
1429
0
}
1430
1431
} // namespace
1432
1433
0
TEST_F(TestRedisService, BadCommand) {
1434
0
  expected_no_sessions_ = true;
1435
1436
0
  TestBadCommand("\n", this);
1437
0
  TestBadCommand(" \r\n", this);
1438
0
  TestBadCommand("*\r\n9\r\n", this);
1439
0
  TestBadCommand("1\r\n\r\n", this);
1440
0
  TestBadCommand("1\r\n \r\n", this);
1441
0
  TestBadCommand("1\r\n*0\r\n", this);
1442
0
}
1443
1444
0
TEST_F(TestRedisService, BadRandom) {
1445
0
  expected_no_sessions_ = true;
1446
0
  const std::string allowed = " -$*\r\n0123456789";
1447
0
  std::string command;
1448
0
  constexpr size_t kTotalProbes = 100;
1449
0
  constexpr size_t kMinCommandLength = 1;
1450
0
  constexpr size_t kMaxCommandLength = 100;
1451
0
  constexpr int kTimeoutInMillis = 250;
1452
0
  for (int i = 0; i != kTotalProbes; ++i) {
1453
0
    size_t len = RandomUniformInt(kMinCommandLength, kMaxCommandLength);
1454
0
    command.clear();
1455
0
    for (size_t idx = 0; idx != len; ++idx) {
1456
0
      command += RandomElement(allowed);
1457
0
      if (command[command.length() - 1] == '\r') {
1458
0
        command += '\n';
1459
0
      }
1460
0
    }
1461
1462
0
    LOG(INFO) << "Command: " << command;
1463
0
    auto status = SendCommandAndGetResponse(command, 1, kTimeoutInMillis);
1464
    // We don't care about status here, because even usually it fails,
1465
    // sometimes it has non empty response.
1466
    // Our main goal is to test that server does not crash.
1467
0
    LOG(INFO) << "Status: " << status;
1468
1469
0
    RestartClient();
1470
0
  }
1471
0
}
1472
1473
0
TEST_F(TestRedisService, IncompleteCommandMulti) {
1474
0
  expected_no_sessions_ = true;
1475
0
  SendCommandAndExpectTimeout("*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$4\r\nTE");
1476
0
}
1477
1478
0
TEST_F(TestRedisService, Echo) {
1479
0
  expected_no_sessions_ = true;
1480
0
  SendCommandAndExpectResponse(__LINE__, "*2\r\n$4\r\necho\r\n$3\r\nfoo\r\n", "$3\r\nfoo\r\n");
1481
0
  SendCommandAndExpectResponse(
1482
0
      __LINE__, "*2\r\n$4\r\necho\r\n$8\r\nfoo bar \r\n", "$8\r\nfoo bar \r\n");
1483
0
  SendCommandAndExpectResponse(
1484
0
      __LINE__,
1485
0
      EncodeAsArray({  // The request is sent as a multi bulk array.
1486
0
          "echo"s,
1487
0
          "foo bar"s
1488
0
      }),
1489
0
      EncodeAsBulkString("foo bar")  // The response is in the bulk string format.
1490
0
  );
1491
0
}
1492
1493
0
TEST_F(TestRedisService, TestSetOnly) {
1494
0
  SendCommandAndExpectResponse(
1495
0
      __LINE__, "*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n", "+OK\r\n");
1496
0
  SendCommandAndExpectResponse(
1497
0
      __LINE__, "*3\r\n$3\r\nset\r\n$4\r\nfool\r\n$4\r\nBEST\r\n", "+OK\r\n");
1498
0
}
1499
1500
0
TEST_F(TestRedisService, TestCaseInsensitiveness) {
1501
0
  SendCommandAndExpectResponse(
1502
0
      __LINE__, "*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n", "+OK\r\n");
1503
0
  SendCommandAndExpectResponse(
1504
0
      __LINE__, "*3\r\n$3\r\nSet\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n", "+OK\r\n");
1505
0
  SendCommandAndExpectResponse(
1506
0
      __LINE__, "*3\r\n$3\r\nsEt\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n", "+OK\r\n");
1507
0
  SendCommandAndExpectResponse(
1508
0
      __LINE__, "*3\r\n$3\r\nseT\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n", "+OK\r\n");
1509
0
  SendCommandAndExpectResponse(
1510
0
      __LINE__, "*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n", "+OK\r\n");
1511
0
}
1512
1513
0
TEST_F(TestRedisService, TestSetThenGet) {
1514
0
  SendCommandAndExpectResponse(__LINE__,
1515
0
      "*3\r\n$3\r\nset\r\n$3\r\nfoo\r\n$4\r\nTEST\r\n", "+OK\r\n");
1516
0
  SendCommandAndExpectResponse(__LINE__, "*2\r\n$3\r\nget\r\n$3\r\nfoo\r\n", "$4\r\nTEST\r\n");
1517
0
  SendCommandAndExpectResponse(
1518
0
      __LINE__,
1519
0
      EncodeAsArray({  // The request is sent as a multi bulk array.
1520
0
          "set"s,
1521
0
          "name"s,
1522
0
          "yugabyte"s
1523
0
      }),
1524
0
      EncodeAsSimpleString("OK")  // The response is in the simple string format.
1525
0
  );
1526
0
  SendCommandAndExpectResponse(
1527
0
      __LINE__,
1528
0
      EncodeAsArray({  // The request is sent as a multi bulk array.
1529
0
          "get"s,
1530
0
          "name"s
1531
0
      }),
1532
0
      EncodeAsBulkString("yugabyte")  // The response is in the bulk string format.
1533
0
  );
1534
0
}
1535
1536
0
TEST_F(TestRedisService, TestUsingOpenSourceClient) {
1537
0
  DoRedisTestOk(__LINE__, {"SET", "hello", "42"});
1538
1539
0
  DoRedisTest(__LINE__, {"DECRBY", "hello", "12"},
1540
0
      RedisReplyType::kError, // TODO: fix error handling
1541
0
      [](const RedisReply &reply) {
1542
        // TBD: ASSERT_EQ(30, reply.as_integer());
1543
0
      });
1544
1545
0
  DoRedisTestBulkString(__LINE__, {"GET", "hello"}, "42");
1546
0
  DoRedisTestOk(__LINE__, {"SET", "world", "72"});
1547
1548
0
  SyncClient();
1549
0
  VerifyCallbacks();
1550
0
}
1551
1552
0
TEST_F(TestRedisService, TestBinaryUsingOpenSourceClient) {
1553
0
  const std::string kFooValue = "\001\002\r\n\003\004"s;
1554
0
  const std::string kBarValue = "\013\010\000"s;
1555
1556
0
  DoRedisTestOk(__LINE__, {"SET", "foo", kFooValue});
1557
0
  DoRedisTestBulkString(__LINE__, {"GET", "foo"}, kFooValue);
1558
0
  DoRedisTestOk(__LINE__, {"SET", "bar", kBarValue});
1559
0
  DoRedisTestBulkString(__LINE__, {"GET", "bar"}, kBarValue);
1560
1561
0
  SyncClient();
1562
0
  VerifyCallbacks();
1563
0
}
1564
1565
0
TEST_F(TestRedisService, TestSingleCommand) {
1566
0
  DoRedisTestOk(__LINE__, {"SET", "k1", ""});
1567
0
  DoRedisTestInt(__LINE__, {"HSET", "k2", "s1", ""}, 1);
1568
1569
0
  SyncClient();
1570
1571
0
  DoRedisTestBulkString(__LINE__, {"GET", "k1"}, "");
1572
0
  SyncClient();
1573
0
  VerifyCallbacks();
1574
0
}
1575
1576
0
TEST_F(TestRedisService, TestEmptyValue) {
1577
0
  DoRedisTestOk(__LINE__, {"SET", "k1", ""});
1578
0
  DoRedisTestInt(__LINE__, {"HSET", "k2", "s1", ""}, 1);
1579
1580
0
  SyncClient();
1581
1582
0
  DoRedisTestBulkString(__LINE__, {"GET", "k1"}, "");
1583
0
  DoRedisTestBulkString(__LINE__, {"HGET", "k2", "s1"}, "");
1584
1585
0
  SyncClient();
1586
0
  VerifyCallbacks();
1587
0
}
1588
1589
void ConnectWithPassword(
1590
    TestRedisService* test, const char* password, bool auth_should_succeed,
1591
0
    bool get_should_succeed) {
1592
0
  auto rc1 = test->CreateClient();
1593
0
  test->UseClient(rc1);
1594
1595
0
  if (auth_should_succeed) {
1596
0
    if (password != nullptr) test->DoRedisTestOk(__LINE__, {"AUTH", password});
1597
0
  } else {
1598
0
    if (password != nullptr) test->DoRedisTestExpectError(__LINE__, {"AUTH", password});
1599
0
  }
1600
1601
0
  if (get_should_succeed) {
1602
0
    test->DoRedisTestOk(__LINE__, {"SET", "k1", "5"});
1603
0
    test->DoRedisTestBulkString(__LINE__, {"GET", "k1"}, "5");
1604
0
  } else {
1605
0
    test->DoRedisTestExpectError(__LINE__, {"SET", "k1", "5"});
1606
0
    test->DoRedisTestExpectError(__LINE__, {"GET", "k1"});
1607
0
  }
1608
1609
0
  test->SyncClient();
1610
0
  test->UseClient(nullptr);
1611
0
}
1612
1613
0
TEST_F(TestRedisService, TestSelect) {
1614
0
  auto rc1 = CreateClient();
1615
0
  auto rc2 = CreateClient();
1616
0
  auto rc3 = CreateClient();
1617
1618
0
  const string default_db("0");
1619
0
  const string second_db("2");
1620
1621
0
  UseClient(rc1);
1622
0
  DoRedisTestOk(__LINE__, {"SET", "key", "v1"});
1623
0
  SyncClient();
1624
1625
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v1");
1626
0
  SyncClient();
1627
1628
  // Select without creating a db should fail.
1629
0
  DoRedisTestExpectError(__LINE__, {"SELECT", second_db.c_str()});
1630
0
  SyncClient();
1631
1632
  // The connection would be closed upon a bad Select.
1633
0
  DoRedisTestExpectError(__LINE__, {"PING"});
1634
0
  SyncClient();
1635
1636
  // Use a different client.
1637
0
  UseClient(rc2);
1638
  // Get the value from the default_db.
1639
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v1");
1640
0
  SyncClient();
1641
1642
  // Create DB.
1643
0
  DoRedisTestOk(__LINE__, {"CREATEDB", second_db.c_str()});
1644
0
  SyncClient();
1645
1646
  // Select should now go through.
1647
0
  DoRedisTestOk(__LINE__, {"SELECT", second_db.c_str()});
1648
0
  SyncClient();
1649
1650
  // Get should be empty.
1651
0
  DoRedisTestNull(__LINE__, {"GET", "key"});
1652
0
  SyncClient();
1653
  // Set a diffferent value
1654
0
  DoRedisTestOk(__LINE__, {"SET", "key", "v2"});
1655
0
  SyncClient();
1656
  // Get that value
1657
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v2");
1658
0
  SyncClient();
1659
  // Select the original db and get the value.
1660
0
  DoRedisTestOk(__LINE__, {"SELECT", default_db.c_str()});
1661
0
  SyncClient();
1662
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v1");
1663
0
  SyncClient();
1664
1665
0
  UseClient(rc3);
1666
  // By default we should get the value from db-0
1667
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v1");
1668
  // Select second db.
1669
0
  DoRedisTestOk(__LINE__, {"SELECT", second_db.c_str()});
1670
  // Get that value
1671
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v2");
1672
0
  SyncClient();
1673
1674
  // List DB.
1675
0
  DoRedisTestArray(__LINE__, {"LISTDB"}, {default_db, second_db});
1676
0
  SyncClient();
1677
1678
  // Delete DB.
1679
0
  DoRedisTestOk(__LINE__, {"DeleteDB", second_db.c_str()});
1680
0
  SyncClient();
1681
  // Expect to not be able to read the value.
1682
0
  DoRedisTestExpectError(__LINE__, {"GET", "key"});
1683
0
  SyncClient();
1684
  // Expect to not be able to read the value.
1685
0
  DoRedisTestExpectError(__LINE__, {"SET", "key", "v2"});
1686
0
  SyncClient();
1687
1688
  // List DB.
1689
0
  DoRedisTestArray(__LINE__, {"LISTDB"}, {default_db});
1690
0
  SyncClient();
1691
1692
0
  rc1->Disconnect();
1693
0
  rc2->Disconnect();
1694
0
  rc3->Disconnect();
1695
1696
0
  UseClient(nullptr);
1697
0
  VerifyCallbacks();
1698
0
}
1699
1700
0
TEST_F(TestRedisService, TestTruncate) {
1701
0
  const string default_db("0");
1702
0
  const string second_db("2");
1703
1704
0
  DoRedisTestOk(__LINE__, {"SET", "key", "v1"});
1705
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v1");
1706
0
  SyncClient();
1707
1708
  // Create DB.
1709
0
  DoRedisTestOk(__LINE__, {"CREATEDB", second_db.c_str()});
1710
  // Select should now go through.
1711
0
  DoRedisTestOk(__LINE__, {"SELECT", second_db.c_str()});
1712
0
  SyncClient();
1713
1714
  // Set a diffferent value
1715
0
  DoRedisTestOk(__LINE__, {"SET", "key", "v2"});
1716
  // Get that value
1717
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v2");
1718
0
  SyncClient();
1719
1720
  // Select the original db and get the value.
1721
0
  DoRedisTestOk(__LINE__, {"SELECT", default_db.c_str()});
1722
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v1");
1723
0
  SyncClient();
1724
1725
  // Flush the default_db
1726
0
  DoRedisTestOk(__LINE__, {"FLUSHDB"});
1727
1728
  // Get should be empty.
1729
0
  DoRedisTestOk(__LINE__, {"SELECT", default_db.c_str()});
1730
0
  DoRedisTestNull(__LINE__, {"GET", "key"});
1731
0
  SyncClient();
1732
0
  DoRedisTestOk(__LINE__, {"SELECT", second_db.c_str()});
1733
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v2");
1734
0
  SyncClient();
1735
1736
0
  DoRedisTestOk(__LINE__, {"SELECT", default_db.c_str()});
1737
0
  DoRedisTestOk(__LINE__, {"SET", "key", "v1"});
1738
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v1");
1739
0
  SyncClient();
1740
1741
  // Flush the default_db
1742
0
  DoRedisTestOk(__LINE__, {"FLUSHALL"});
1743
1744
0
  DoRedisTestNull(__LINE__, {"GET", "key"});
1745
0
  SyncClient();
1746
1747
0
  DoRedisTestOk(__LINE__, {"SELECT", default_db.c_str()});
1748
0
  DoRedisTestNull(__LINE__, {"GET", "key"});
1749
0
  SyncClient();
1750
0
  DoRedisTestOk(__LINE__, {"SELECT", second_db.c_str()});
1751
0
  DoRedisTestNull(__LINE__, {"GET", "key"});
1752
0
  SyncClient();
1753
1754
  // List DB.
1755
0
  DoRedisTestArray(__LINE__, {"LISTDB"}, {default_db, second_db});
1756
0
  SyncClient();
1757
1758
0
  VerifyCallbacks();
1759
0
}
1760
1761
0
TEST_F(TestRedisService, TestDeleteDB) {
1762
0
  const string default_db("0");
1763
0
  const string second_db("2");
1764
1765
0
  DoRedisTestOk(__LINE__, {"SET", "key", "v1"});
1766
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v1");
1767
0
  SyncClient();
1768
1769
  // Create DB.
1770
0
  DoRedisTestOk(__LINE__, {"CREATEDB", second_db.c_str()});
1771
  // Select should now go through.
1772
0
  DoRedisTestOk(__LINE__, {"SELECT", second_db.c_str()});
1773
0
  SyncClient();
1774
1775
  // Set a diffferent value
1776
0
  DoRedisTestOk(__LINE__, {"SET", "key", "v2"});
1777
  // Get that value
1778
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v2");
1779
0
  SyncClient();
1780
1781
  // Delete and recreate the DB.
1782
  // List DB.
1783
0
  DoRedisTestArray(__LINE__, {"LISTDB"}, {default_db, second_db});
1784
0
  SyncClient();
1785
0
  DoRedisTestOk(__LINE__, {"DELETEDB", second_db.c_str()});
1786
0
  SyncClient();
1787
0
  DoRedisTestArray(__LINE__, {"LISTDB"}, {default_db});
1788
0
  SyncClient();
1789
0
  DoRedisTestOk(__LINE__, {"CREATEDB", second_db.c_str()});
1790
0
  SyncClient();
1791
0
  DoRedisTestArray(__LINE__, {"LISTDB"}, {default_db, second_db});
1792
0
  SyncClient();
1793
  // With retries we should succeed immediately.
1794
0
  DoRedisTestNull(__LINE__, {"GET", "key"});
1795
0
  SyncClient();
1796
  // Set a diffferent value
1797
0
  DoRedisTestOk(__LINE__, {"SET", "key", "v2"});
1798
0
  SyncClient();
1799
  // Get that value
1800
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v2");
1801
0
  SyncClient();
1802
1803
  // Delete and recreate the DB. Followed by a write.
1804
0
  DoRedisTestArray(__LINE__, {"LISTDB"}, {default_db, second_db});
1805
0
  SyncClient();
1806
0
  DoRedisTestOk(__LINE__, {"DELETEDB", second_db.c_str()});
1807
0
  SyncClient();
1808
0
  DoRedisTestArray(__LINE__, {"LISTDB"}, {default_db});
1809
0
  SyncClient();
1810
0
  DoRedisTestOk(__LINE__, {"CREATEDB", second_db.c_str()});
1811
0
  SyncClient();
1812
  // Set a value
1813
0
  DoRedisTestOk(__LINE__, {"SET", "key", "v3"});
1814
0
  SyncClient();
1815
  // Get that value
1816
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "v3");
1817
0
  SyncClient();
1818
1819
  // Delete and recreate the DB. Followed by a local op.
1820
0
  DoRedisTestArray(__LINE__, {"LISTDB"}, {default_db, second_db});
1821
0
  SyncClient();
1822
0
  DoRedisTestOk(__LINE__, {"DELETEDB", second_db.c_str()});
1823
0
  SyncClient();
1824
0
  DoRedisTestArray(__LINE__, {"LISTDB"}, {default_db});
1825
0
  SyncClient();
1826
0
  DoRedisTestOk(__LINE__, {"CREATEDB", second_db.c_str()});
1827
0
  SyncClient();
1828
0
  DoRedisTestBulkString(__LINE__, {"PING", "cmd2"}, "cmd2");
1829
0
  SyncClient();
1830
0
  DoRedisTestBulkString(__LINE__, {"PING", "cmd2"}, "cmd2");
1831
0
  SyncClient();
1832
1833
0
  VerifyCallbacks();
1834
0
}
1835
1836
0
TEST_F(TestRedisService, TestMonitor) {
1837
0
  constexpr uint32 kDelayMs = NonTsanVsTsan(100, 1000);
1838
0
  expected_no_sessions_ = true;
1839
0
  auto rc1 = CreateClient();
1840
0
  auto rc2 = CreateClient();
1841
0
  auto mc1 = CreateClient();
1842
0
  auto mc2 = CreateClient();
1843
1844
0
  UseClient(rc1);
1845
0
  DoRedisTestBulkString(__LINE__, {"PING", "cmd1"}, "cmd1");  // Excluded from both mc1 and mc2.
1846
0
  SyncClient();
1847
1848
  // Check number of monitoring clients.
1849
0
  ASSERT_EQ(0, CountSessions(METRIC_redis_monitoring_clients));
1850
1851
0
  UseClient(mc1);
1852
0
  DoRedisTestOk(__LINE__, {"MONITOR"});
1853
0
  SyncClient();
1854
1855
  // Wait for the server to realize that the connection is closed.
1856
0
  std::this_thread::sleep_for(std::chrono::milliseconds(kDelayMs));
1857
  // Check number of monitoring clients.
1858
0
  ASSERT_EQ(1, CountSessions(METRIC_redis_monitoring_clients));
1859
1860
0
  UseClient(rc2);
1861
0
  DoRedisTestBulkString(__LINE__, {"PING", "cmd2"}, "cmd2");  // Included in mc1.
1862
0
  SyncClient();
1863
1864
0
  UseClient(mc2);
1865
0
  DoRedisTestOk(__LINE__, {"MONITOR"});
1866
0
  SyncClient();
1867
1868
  // Wait for the server to realize that the connection is closed.
1869
0
  std::this_thread::sleep_for(std::chrono::milliseconds(kDelayMs));
1870
  // Check number of monitoring clients.
1871
0
  ASSERT_EQ(2, CountSessions(METRIC_redis_monitoring_clients));
1872
1873
0
  UseClient(rc1);
1874
0
  const string really_long(100, 'x');
1875
0
  const string response_ending = string("\"PING\" \"").append(really_long).append("\"");
1876
0
  DoRedisTestBulkString(__LINE__, {"PING", really_long}, really_long); // Included in mc1 and mc2.
1877
0
  SyncClient();
1878
1879
0
  UseClient(mc1);
1880
  // Check the responses for monitor on mc1.
1881
  // Responses are of the format
1882
  // <TS> {<db-id> <client-ip>:<port>} "CMD" "ARG1" ....
1883
  // We will check for the responses to end in "CMD" "ARG1"
1884
0
  DoRedisTestExpectSimpleStringEndingWith(__LINE__, {}, "\"PING\" \"cmd2\"");
1885
0
  DoRedisTestExpectSimpleStringEndingWith(__LINE__, {}, response_ending);
1886
0
  SyncClient();
1887
1888
0
  UseClient(mc2);
1889
  // Check the responses for monitor on mc2.
1890
0
  DoRedisTestExpectSimpleStringEndingWith(__LINE__, {}, response_ending);
1891
0
  SyncClient();
1892
1893
  // Check number of monitoring clients.
1894
0
  ASSERT_EQ(2, CountSessions(METRIC_redis_monitoring_clients));
1895
1896
  // Close one monitoring clients.
1897
0
  mc1->Disconnect();
1898
  // Wait for the server to realize that the connection is closed.
1899
0
  std::this_thread::sleep_for(std::chrono::milliseconds(kDelayMs));
1900
1901
  // Check number of monitoring clients.
1902
0
  UseClient(rc1);
1903
0
  DoRedisTestBulkString(__LINE__, {"PING", "test"}, "test");
1904
0
  SyncClient();
1905
1906
  // Wait for the server to realize that the connection is closed.
1907
0
  std::this_thread::sleep_for(std::chrono::milliseconds(kDelayMs));
1908
  // Check number of monitoring clients.
1909
0
  ASSERT_EQ(1, CountSessions(METRIC_redis_monitoring_clients));
1910
1911
0
  mc2->Disconnect();
1912
  // Wait for the server to realize that the connection is closed.
1913
0
  std::this_thread::sleep_for(std::chrono::milliseconds(kDelayMs));
1914
1915
  // Check number of monitoring clients.
1916
0
  UseClient(rc1);
1917
0
  DoRedisTestBulkString(__LINE__, {"PING", "test"}, "test");
1918
0
  SyncClient();
1919
1920
  // Wait for the server to realize that the connection is closed.
1921
0
  std::this_thread::sleep_for(std::chrono::milliseconds(kDelayMs));
1922
1923
0
  ASSERT_EQ(0, CountSessions(METRIC_redis_monitoring_clients));
1924
1925
0
  UseClient(nullptr);
1926
0
  VerifyCallbacks();
1927
0
}
1928
1929
void TestSubscribe(
1930
    TestRedisService* tester,
1931
    std::shared_ptr<RedisClient> ps0,  // Used for PubSub command
1932
    std::shared_ptr<RedisClient> sc1,  // Used for Subscribe
1933
    std::shared_ptr<RedisClient> sc2,
1934
    std::shared_ptr<RedisClient> sc3,
1935
    std::shared_ptr<RedisClient> pc1,  // Used for Publish
1936
0
    std::shared_ptr<RedisClient> pc2) {
1937
0
  const string topic1 = "topic1", topic2 = "topic2";
1938
0
  const string msg1 = "msg1", msg2 = "msg2";
1939
1940
0
  if (ps0) {
1941
0
    tester->UseClient(ps0);
1942
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
1943
0
    tester->DoRedisTestResultsArray(
1944
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
1945
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
1946
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
1947
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
1948
0
    tester->SyncClient();
1949
0
  }
1950
1951
0
  tester->UseClient(sc1);
1952
0
  tester->DoRedisTestResultsArray(
1953
0
      __LINE__, {"SUBSCRIBE", topic1},
1954
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
1955
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
1956
0
  tester->SyncClient();
1957
1958
0
  if (ps0) {
1959
0
    tester->UseClient(ps0);
1960
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {topic1});
1961
0
    tester->DoRedisTestResultsArray(
1962
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
1963
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(1),
1964
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
1965
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
1966
0
    tester->SyncClient();
1967
0
  }
1968
1969
0
  tester->UseClient(sc2);
1970
0
  tester->DoRedisTestResultsArray(
1971
0
      __LINE__, {"SUBSCRIBE", topic2},
1972
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
1973
0
       RedisReply(RedisReplyType::kString, topic2), RedisReply(1)});
1974
0
  tester->SyncClient();
1975
1976
0
  if (ps0) {
1977
0
    tester->UseClient(ps0);
1978
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {topic1, topic2});
1979
0
    tester->DoRedisTestResultsArray(
1980
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
1981
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(1),
1982
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(1)});
1983
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
1984
0
    tester->SyncClient();
1985
0
  }
1986
1987
0
  tester->UseClient(sc3);
1988
0
  tester->DoRedisTestResultsArray(
1989
0
      __LINE__, {"SUBSCRIBE", topic1},
1990
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
1991
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
1992
0
  tester->DoRedisTestResultsArray(
1993
0
      __LINE__, {"SUBSCRIBE", topic2},
1994
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
1995
0
       RedisReply(RedisReplyType::kString, topic2), RedisReply(2)});
1996
0
  tester->SyncClient();
1997
1998
0
  if (ps0) {
1999
0
    tester->UseClient(ps0);
2000
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {topic1, topic2});
2001
0
    tester->DoRedisTestResultsArray(
2002
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2003
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(2),
2004
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(2)});
2005
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
2006
0
    tester->SyncClient();
2007
0
  }
2008
2009
  // Now send msg1 to topic 1.
2010
0
  tester->UseClient(pc1);
2011
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic1, msg1}, 2);
2012
0
  tester->SyncClient();
2013
2014
  // Now send msg2 to topic 2.
2015
0
  tester->UseClient(pc2);
2016
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic2, msg2}, 2);
2017
0
  tester->SyncClient();
2018
2019
  // Verify the received messages.
2020
0
  tester->UseClient(sc1);
2021
0
  tester->DoRedisTestArray(__LINE__, {}, {"message", topic1, msg1});
2022
0
  tester->SyncClient();
2023
2024
0
  tester->UseClient(sc2);
2025
0
  tester->DoRedisTestArray(__LINE__, {}, {"message", topic2, msg2});
2026
  // No more messages to receive.
2027
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2028
0
  tester->SyncClient();
2029
2030
0
  tester->UseClient(sc3);
2031
0
  tester->DoRedisTestArray(__LINE__, {}, {"message", topic1, msg1});
2032
0
  tester->DoRedisTestArray(__LINE__, {}, {"message", topic2, msg2});
2033
  // No more messages to receive.
2034
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2035
0
  tester->SyncClient();
2036
2037
0
  tester->UseClient(nullptr);
2038
0
  tester->VerifyCallbacks();
2039
0
}
2040
2041
void TestUnsubscribe(
2042
    TestRedisService* tester,
2043
    std::shared_ptr<RedisClient> ps0,  // Used for PubSub command
2044
    std::shared_ptr<RedisClient> sc1,  // Used for Subscribe
2045
    std::shared_ptr<RedisClient> sc2,
2046
    std::shared_ptr<RedisClient> sc3,
2047
    std::shared_ptr<RedisClient> pc1,  // Used for Publish
2048
0
    std::shared_ptr<RedisClient> pc2) {
2049
0
  const string topic1 = "topic1", topic2 = "topic2";
2050
0
  const string msg1 = "msg1", msg2 = "msg2", msg3 = "msg3", msg4 = "msg4";
2051
2052
0
  tester->UseClient(sc1);
2053
0
  tester->DoRedisTestResultsArray(
2054
0
      __LINE__, {"SUBSCRIBE", topic1, topic2},
2055
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
2056
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
2057
0
  tester->DoRedisTestResultsArray(
2058
0
      __LINE__, {}, {RedisReply(RedisReplyType::kString, "subscribe"),
2059
0
                     RedisReply(RedisReplyType::kString, topic2), RedisReply(2)});
2060
0
  tester->SyncClient();
2061
2062
0
  tester->UseClient(sc2);
2063
0
  tester->DoRedisTestResultsArray(
2064
0
      __LINE__, {"SUBSCRIBE", topic1, topic2},
2065
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
2066
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
2067
0
  tester->DoRedisTestResultsArray(
2068
0
      __LINE__, {}, {RedisReply(RedisReplyType::kString, "subscribe"),
2069
0
                     RedisReply(RedisReplyType::kString, topic2), RedisReply(2)});
2070
0
  tester->SyncClient();
2071
2072
0
  tester->UseClient(sc3);
2073
0
  tester->DoRedisTestResultsArray(
2074
0
      __LINE__, {"SUBSCRIBE", topic1, topic2},
2075
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
2076
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
2077
0
  tester->DoRedisTestResultsArray(
2078
0
      __LINE__, {}, {RedisReply(RedisReplyType::kString, "subscribe"),
2079
0
                     RedisReply(RedisReplyType::kString, topic2), RedisReply(2)});
2080
0
  tester->SyncClient();
2081
2082
0
  if (ps0) {
2083
0
    tester->UseClient(ps0);
2084
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {topic1, topic2});
2085
0
    tester->DoRedisTestResultsArray(
2086
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2087
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(3),
2088
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(3)});
2089
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
2090
0
    tester->SyncClient();
2091
0
  }
2092
2093
  // sc1 will unsubscribe from topic1. Will still be subscribed to topic2.
2094
0
  tester->UseClient(sc1);
2095
0
  tester->DoRedisTestResultsArray(
2096
0
      __LINE__, {"UNSUBSCRIBE", topic1},
2097
0
      {RedisReply(RedisReplyType::kString, "unsubscribe"),
2098
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
2099
0
  tester->SyncClient();
2100
2101
  // sc2 will unsubscribe from all topics. Will still be subscribed to none.
2102
0
  tester->UseClient(sc2);
2103
0
  tester->DoRedisTestResultsArray(
2104
0
      __LINE__, {"UNSUBSCRIBE", topic1, topic2},
2105
0
      {RedisReply(RedisReplyType::kString, "unsubscribe"),
2106
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
2107
0
  tester->DoRedisTestResultsArray(
2108
0
      __LINE__, {}, {RedisReply(RedisReplyType::kString, "unsubscribe"),
2109
0
                     RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2110
0
  tester->SyncClient();
2111
2112
0
  if (ps0) {
2113
0
    tester->UseClient(ps0);
2114
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {topic1, topic2});
2115
0
    tester->DoRedisTestResultsArray(
2116
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2117
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(1),
2118
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(2)});
2119
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
2120
0
    tester->SyncClient();
2121
0
  }
2122
2123
  // Now send msg1 to topic 1.
2124
0
  tester->UseClient(pc1);
2125
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic1, msg1}, 1);
2126
0
  tester->SyncClient();
2127
2128
  // Now send msg2 to topic 2.
2129
0
  tester->UseClient(pc2);
2130
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic2, msg2}, 2);
2131
0
  tester->SyncClient();
2132
2133
  // Verify the received messages.
2134
0
  tester->UseClient(sc1);
2135
0
  tester->DoRedisTestArray(__LINE__, {}, {"message", topic2, msg2});
2136
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2137
0
  tester->SyncClient();
2138
2139
0
  tester->UseClient(sc2);
2140
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2141
0
  tester->SyncClient();
2142
2143
0
  tester->UseClient(sc3);
2144
0
  tester->DoRedisTestArray(__LINE__, {}, {"message", topic1, msg1});
2145
0
  tester->DoRedisTestArray(__LINE__, {}, {"message", topic2, msg2});
2146
  // No more messages to receive.
2147
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2148
0
  tester->SyncClient();
2149
2150
  // sc3 will unsubscribe from all topics. sc1 will still be subscribed to topic2.
2151
0
  tester->UseClient(sc3);
2152
  // Redis does not specify a particular order. So, the following two messages
2153
  // could be in received in either order.
2154
0
  tester->DoRedisTestResultsArray(
2155
0
      __LINE__, {"UNSUBSCRIBE"}, {RedisReply(RedisReplyType::kString, "unsubscribe"),
2156
0
                                  RedisReply(RedisReplyType::kString, "IGNORED"), RedisReply(1)});
2157
0
  tester->DoRedisTestResultsArray(
2158
0
      __LINE__, {}, {RedisReply(RedisReplyType::kString, "unsubscribe"),
2159
0
                     RedisReply(RedisReplyType::kString, "IGNORED"), RedisReply(0)});
2160
0
  tester->SyncClient();
2161
2162
0
  if (ps0) {
2163
0
    tester->UseClient(ps0);
2164
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {topic2});
2165
0
    tester->DoRedisTestResultsArray(
2166
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2167
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2168
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(1)});
2169
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
2170
0
    tester->SyncClient();
2171
0
  }
2172
2173
  // Now send msg3 to topic 2.
2174
0
  tester->UseClient(pc2);
2175
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic2, msg3}, 1);
2176
0
  tester->SyncClient();
2177
2178
  // No one should receive the message except sc1.
2179
0
  tester->UseClient(sc1);
2180
0
  tester->DoRedisTestArray(__LINE__, {}, {"message", topic2, msg3});
2181
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2182
0
  tester->SyncClient();
2183
0
  tester->UseClient(sc2);
2184
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2185
0
  tester->SyncClient();
2186
0
  tester->UseClient(sc3);
2187
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2188
0
  tester->SyncClient();
2189
2190
  // sc1 will unsubscribe from topic2. No one left subscribed to any topic.
2191
0
  tester->UseClient(sc1);
2192
0
  tester->DoRedisTestResultsArray(
2193
0
      __LINE__, {"UNSUBSCRIBE"}, {RedisReply(RedisReplyType::kString, "unsubscribe"),
2194
0
                                  RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2195
0
  tester->SyncClient();
2196
2197
0
  if (ps0) {
2198
0
    tester->UseClient(ps0);
2199
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2200
0
    tester->DoRedisTestResultsArray(
2201
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2202
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2203
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2204
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
2205
0
    tester->SyncClient();
2206
0
  }
2207
2208
  // Now send msg4 to topic 2.
2209
0
  tester->UseClient(pc2);
2210
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic2, msg4}, 0);
2211
0
  tester->SyncClient();
2212
2213
  // No one should receive the message.
2214
0
  tester->UseClient(sc1);
2215
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2216
0
  tester->SyncClient();
2217
0
  tester->UseClient(sc2);
2218
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2219
0
  tester->SyncClient();
2220
0
  tester->UseClient(sc3);
2221
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2222
0
  tester->SyncClient();
2223
2224
0
  tester->UseClient(nullptr);
2225
0
  tester->VerifyCallbacks();
2226
0
}
2227
2228
void TestPSubscribe(
2229
    TestRedisService* tester,
2230
    std::shared_ptr<RedisClient> ps0,  // Used for PubSub command
2231
    std::shared_ptr<RedisClient> sc1,  // Used for Subscribe
2232
    std::shared_ptr<RedisClient> sc2,
2233
    std::shared_ptr<RedisClient> sc3,
2234
    std::shared_ptr<RedisClient> pc1,  // Used for Publish
2235
0
    std::shared_ptr<RedisClient> pc2) {
2236
0
  const string pattern1 = "t*1", pattern2 = "t*2", common_pattern = "t*";
2237
0
  const string topic1 = "topic1", topic2 = "topic2";
2238
0
  const string msg1 = "msg1", msg2 = "msg2";
2239
2240
0
  if (ps0) {
2241
0
    tester->UseClient(ps0);
2242
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2243
0
    tester->DoRedisTestResultsArray(
2244
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2245
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2246
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2247
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
2248
0
    tester->SyncClient();
2249
0
  }
2250
2251
0
  tester->UseClient(sc1);
2252
0
  tester->DoRedisTestResultsArray(
2253
0
      __LINE__, {"PSUBSCRIBE", pattern1},
2254
0
      {RedisReply(RedisReplyType::kString, "psubscribe"),
2255
0
       RedisReply(RedisReplyType::kString, pattern1), RedisReply(1)});
2256
0
  tester->SyncClient();
2257
2258
0
  if (ps0) {
2259
0
    tester->UseClient(ps0);
2260
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2261
0
    tester->DoRedisTestResultsArray(
2262
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2263
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2264
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2265
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 1);
2266
0
    tester->SyncClient();
2267
0
  }
2268
2269
0
  tester->UseClient(sc2);
2270
0
  tester->DoRedisTestResultsArray(
2271
0
      __LINE__, {"psubscribe", pattern2},
2272
0
      {RedisReply(RedisReplyType::kString, "psubscribe"),
2273
0
       RedisReply(RedisReplyType::kString, pattern2), RedisReply(1)});
2274
0
  tester->SyncClient();
2275
2276
0
  if (ps0) {
2277
0
    tester->UseClient(ps0);
2278
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2279
0
    tester->DoRedisTestResultsArray(
2280
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2281
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2282
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2283
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 2);
2284
0
    tester->SyncClient();
2285
0
  }
2286
2287
0
  tester->UseClient(sc3);
2288
0
  tester->DoRedisTestResultsArray(
2289
0
      __LINE__, {"psubscribe", common_pattern},
2290
0
      {RedisReply(RedisReplyType::kString, "psubscribe"),
2291
0
       RedisReply(RedisReplyType::kString, common_pattern), RedisReply(1)});
2292
0
  tester->SyncClient();
2293
2294
  // Now send msg1 to pattern 1.
2295
0
  tester->UseClient(pc1);
2296
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic1, msg1}, 2);
2297
0
  tester->SyncClient();
2298
2299
  // Now send msg2 to pattern 2.
2300
0
  tester->UseClient(pc2);
2301
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic2, msg2}, 2);
2302
0
  tester->SyncClient();
2303
2304
  // Verify the received messages.
2305
0
  tester->UseClient(sc1);
2306
0
  tester->DoRedisTestArray(__LINE__, {}, {"pmessage", pattern1, topic1, msg1});
2307
0
  tester->SyncClient();
2308
2309
0
  tester->UseClient(sc2);
2310
0
  tester->DoRedisTestArray(__LINE__, {}, {"pmessage", pattern2, topic2, msg2});
2311
  // No more messages to receive.
2312
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2313
0
  tester->SyncClient();
2314
2315
0
  tester->UseClient(sc3);
2316
0
  tester->DoRedisTestArray(__LINE__, {}, {"pmessage", common_pattern, topic1, msg1});
2317
0
  tester->DoRedisTestArray(__LINE__, {}, {"pmessage", common_pattern, topic2, msg2});
2318
  // No more messages to receive.
2319
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2320
0
  tester->SyncClient();
2321
2322
0
  tester->UseClient(nullptr);
2323
0
  tester->VerifyCallbacks();
2324
0
}
2325
2326
void TestPUnsubscribe(
2327
    TestRedisService* tester,
2328
    std::shared_ptr<RedisClient> ps0,  // Used for PubSub command
2329
    std::shared_ptr<RedisClient> sc1,  // Used for Subscribe
2330
    std::shared_ptr<RedisClient> sc2,
2331
    std::shared_ptr<RedisClient> sc3,
2332
    std::shared_ptr<RedisClient> pc1,  // Used for Publish
2333
0
    std::shared_ptr<RedisClient> pc2) {
2334
0
  const string pattern1 = "to*1", pattern2 = "to*2";
2335
0
  const string topic1 = "topic1", topic2 = "topic2";
2336
0
  const string msg1 = "msg1", msg2 = "msg2", msg3 = "msg3";
2337
2338
0
  if (ps0) {
2339
0
    tester->UseClient(ps0);
2340
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2341
0
    tester->DoRedisTestResultsArray(
2342
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2343
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2344
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2345
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
2346
0
    tester->SyncClient();
2347
0
  }
2348
2349
0
  tester->UseClient(sc1);
2350
0
  tester->DoRedisTestResultsArray(
2351
0
      __LINE__, {"psubscribe", pattern1, pattern2},
2352
0
      {RedisReply(RedisReplyType::kString, "psubscribe"),
2353
0
       RedisReply(RedisReplyType::kString, pattern1), RedisReply(1)});
2354
0
  tester->DoRedisTestResultsArray(
2355
0
      __LINE__, {}, {RedisReply(RedisReplyType::kString, "psubscribe"),
2356
0
                     RedisReply(RedisReplyType::kString, pattern2), RedisReply(2)});
2357
0
  tester->SyncClient();
2358
2359
0
  if (ps0) {
2360
0
    tester->UseClient(ps0);
2361
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2362
0
    tester->DoRedisTestResultsArray(
2363
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2364
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2365
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2366
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 2);
2367
0
    tester->SyncClient();
2368
0
  }
2369
2370
0
  tester->UseClient(sc2);
2371
0
  tester->DoRedisTestResultsArray(
2372
0
      __LINE__, {"psubscribe", pattern1, pattern2},
2373
0
      {RedisReply(RedisReplyType::kString, "psubscribe"),
2374
0
       RedisReply(RedisReplyType::kString, pattern1), RedisReply(1)});
2375
0
  tester->DoRedisTestResultsArray(
2376
0
      __LINE__, {}, {RedisReply(RedisReplyType::kString, "psubscribe"),
2377
0
                     RedisReply(RedisReplyType::kString, pattern2), RedisReply(2)});
2378
0
  tester->SyncClient();
2379
2380
0
  if (ps0) {
2381
0
    tester->UseClient(ps0);
2382
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2383
0
    tester->DoRedisTestResultsArray(
2384
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2385
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2386
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2387
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 2);
2388
0
    tester->SyncClient();
2389
0
  }
2390
2391
0
  tester->UseClient(sc3);
2392
0
  tester->DoRedisTestResultsArray(
2393
0
      __LINE__, {"psubscribe", pattern1, pattern2},
2394
0
      {RedisReply(RedisReplyType::kString, "psubscribe"),
2395
0
       RedisReply(RedisReplyType::kString, pattern1), RedisReply(1)});
2396
0
  tester->DoRedisTestResultsArray(
2397
0
      __LINE__, {}, {RedisReply(RedisReplyType::kString, "psubscribe"),
2398
0
                     RedisReply(RedisReplyType::kString, pattern2), RedisReply(2)});
2399
0
  tester->SyncClient();
2400
2401
0
  if (ps0) {
2402
0
    tester->UseClient(ps0);
2403
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2404
0
    tester->DoRedisTestResultsArray(
2405
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2406
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2407
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2408
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 2);
2409
0
    tester->SyncClient();
2410
0
  }
2411
2412
  // sc1 will punsubscribe from pattern2. Will still be psubscribed to pattern1.
2413
0
  tester->UseClient(sc1);
2414
0
  tester->DoRedisTestResultsArray(
2415
0
      __LINE__, {"punsubscribe", pattern1},
2416
0
      {RedisReply(RedisReplyType::kString, "punsubscribe"),
2417
0
       RedisReply(RedisReplyType::kString, pattern1), RedisReply(1)});
2418
0
  tester->SyncClient();
2419
2420
  // sc2 will punsubscribe from all patterns. Will still be psubscribed to none.
2421
0
  tester->UseClient(sc2);
2422
0
  tester->DoRedisTestResultsArray(
2423
0
      __LINE__, {"punsubscribe", pattern1, pattern2},
2424
0
      {RedisReply(RedisReplyType::kString, "punsubscribe"),
2425
0
       RedisReply(RedisReplyType::kString, pattern1), RedisReply(1)});
2426
0
  tester->DoRedisTestResultsArray(
2427
0
      __LINE__, {}, {RedisReply(RedisReplyType::kString, "punsubscribe"),
2428
0
                     RedisReply(RedisReplyType::kString, pattern2), RedisReply(0)});
2429
0
  tester->SyncClient();
2430
2431
  // Now send msg1 to pattern 1.
2432
0
  tester->UseClient(pc1);
2433
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic1, msg1}, 1);
2434
0
  tester->SyncClient();
2435
2436
  // Now send msg2 to pattern 2.
2437
0
  tester->UseClient(pc2);
2438
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic2, msg2}, 2);
2439
0
  tester->SyncClient();
2440
2441
  // Verify the received pmessages.
2442
0
  tester->UseClient(sc1);
2443
0
  tester->DoRedisTestArray(__LINE__, {}, {"pmessage", pattern2, topic2, msg2});
2444
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2445
0
  tester->SyncClient();
2446
2447
0
  tester->UseClient(sc2);
2448
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2449
0
  tester->SyncClient();
2450
2451
0
  tester->UseClient(sc3);
2452
0
  tester->DoRedisTestArray(__LINE__, {}, {"pmessage", pattern1, topic1, msg1});
2453
0
  tester->DoRedisTestArray(__LINE__, {}, {"pmessage", pattern2, topic2, msg2});
2454
  // No more messages to receive.
2455
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2456
0
  tester->SyncClient();
2457
2458
0
  if (ps0) {
2459
0
    tester->UseClient(ps0);
2460
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2461
0
    tester->DoRedisTestResultsArray(
2462
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2463
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2464
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2465
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 2);
2466
0
    tester->SyncClient();
2467
0
  }
2468
2469
  // sc3 will punsubscribe from all patterns.
2470
0
  tester->UseClient(sc3);
2471
  // Redis does not specify a particular order. So, the following two messages
2472
  // could be in received in either order.
2473
0
  tester->DoRedisTestResultsArray(
2474
0
      __LINE__, {"punsubscribe"}, {RedisReply(RedisReplyType::kString, "punsubscribe"),
2475
0
                                   RedisReply(RedisReplyType::kString, "IGNORED"), RedisReply(1)});
2476
0
  tester->DoRedisTestResultsArray(
2477
0
      __LINE__, {}, {RedisReply(RedisReplyType::kString, "punsubscribe"),
2478
0
                     RedisReply(RedisReplyType::kString, "IGNORED"), RedisReply(0)});
2479
0
  tester->SyncClient();
2480
2481
0
  if (ps0) {
2482
0
    tester->UseClient(ps0);
2483
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2484
0
    tester->DoRedisTestResultsArray(
2485
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2486
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2487
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2488
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 1);
2489
0
    tester->SyncClient();
2490
0
  }
2491
2492
  // Now send msg3 to pattern 2. only sc1 receives it.
2493
0
  tester->UseClient(pc2);
2494
0
  tester->DoRedisTestInt(__LINE__, {"PUBLISH", topic2, msg3}, 1);
2495
0
  tester->SyncClient();
2496
2497
  // No one should receive the message.
2498
0
  tester->UseClient(sc1);
2499
0
  tester->DoRedisTestArray(__LINE__, {}, {"pmessage", pattern2, topic2, msg3});
2500
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2501
0
  tester->SyncClient();
2502
0
  tester->UseClient(sc2);
2503
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2504
0
  tester->SyncClient();
2505
0
  tester->UseClient(sc3);
2506
0
  tester->DoRedisTestArray(__LINE__, {"PING"}, {"pong", ""});
2507
0
  tester->SyncClient();
2508
2509
  // Get sc1 to also punsubscribe from pattern 2. No one is subscribed to any patterns anymore.
2510
0
  tester->UseClient(sc1);
2511
0
  tester->DoRedisTestResultsArray(
2512
0
      __LINE__, {"punsubscribe"}, {RedisReply(RedisReplyType::kString, "punsubscribe"),
2513
0
                                   RedisReply(RedisReplyType::kString, pattern2), RedisReply(0)});
2514
0
  tester->SyncClient();
2515
2516
0
  if (ps0) {
2517
0
    tester->UseClient(ps0);
2518
0
    tester->DoRedisTestArray(__LINE__, {"pubsub", "channels"}, {});
2519
0
    tester->DoRedisTestResultsArray(
2520
0
        __LINE__, {"pubsub", "numsub", topic1, topic2},
2521
0
        {RedisReply(RedisReplyType::kString, topic1), RedisReply(0),
2522
0
         RedisReply(RedisReplyType::kString, topic2), RedisReply(0)});
2523
0
    tester->DoRedisTestInt(__LINE__, {"pubsub", "numpat"}, 0);
2524
0
    tester->SyncClient();
2525
0
  }
2526
2527
0
  tester->UseClient(nullptr);
2528
0
  tester->VerifyCallbacks();
2529
0
}
2530
2531
// Utility for testing various combination(s).
2532
YB_DEFINE_ENUM(SubOrUnsub, (kSubscribe)(kUnsubscribe));
2533
YB_DEFINE_ENUM(PatternOrChannel, (kChannel)(kPattern));
2534
YB_DEFINE_ENUM(LocalOrCluster, (kLocal)(kCluster));
2535
2536
class TestRedisServiceExternal : public TestRedisService {
2537
 protected:
2538
  void TestPubSub(LocalOrCluster ltype, SubOrUnsub stype, PatternOrChannel ptype);
2539
2540
0
  void CustomizeExternalMiniCluster(ExternalMiniClusterOptions* opts) override {
2541
0
    opts->extra_tserver_flags.push_back(
2542
0
        "--redis_connection_soft_limit_grace_period_sec=" +
2543
0
        AsString(static_cast<int>(kSoftLimitGracePeriod.ToSeconds())));
2544
0
  }
2545
2546
  static const MonoDelta kSoftLimitGracePeriod;
2547
2548
 private:
2549
0
  Endpoint RedisProxyEndpoint() override {
2550
0
    auto ts0 = external_mini_cluster()->tablet_server(0);
2551
0
    return Endpoint(IpAddress::from_string(ts0->bind_host()), ts0->redis_rpc_port());
2552
0
  }
2553
2554
0
  bool use_external_mini_cluster() override { return true; }
2555
};
2556
2557
const MonoDelta TestRedisServiceExternal::kSoftLimitGracePeriod = yb::NonTsanVsTsan(1s, 10s);
2558
2559
void TestRedisServiceExternal::TestPubSub(
2560
0
    LocalOrCluster ltype, SubOrUnsub stype, PatternOrChannel ptype) {
2561
0
  std::shared_ptr<RedisClient> ps0, sc1, sc2, sc3, pc1, pc2;
2562
2563
0
  if (ltype == LocalOrCluster::kLocal) {
2564
0
    auto ts0 = external_mini_cluster()->tablet_server(0);
2565
0
    auto host0 = ts0->bind_host();
2566
0
    auto port0 = ts0->redis_rpc_port();
2567
2568
0
    sc1 = std::make_shared<RedisClient>(host0, port0);
2569
0
    sc2 = std::make_shared<RedisClient>(host0, port0);
2570
0
    sc3 = std::make_shared<RedisClient>(host0, port0);
2571
0
    pc1 = std::make_shared<RedisClient>(host0, port0);
2572
0
    pc2 = std::make_shared<RedisClient>(host0, port0);
2573
0
    ps0 = std::make_shared<RedisClient>(host0, port0);
2574
0
  } else {
2575
0
    auto ts0 = external_mini_cluster()->tablet_server(0);
2576
0
    auto host0 = ts0->bind_host();
2577
0
    auto port0 = ts0->redis_rpc_port();
2578
0
    auto ts1 = external_mini_cluster()->tablet_server(1);
2579
0
    auto host1 = ts1->bind_host();
2580
0
    auto port1 = ts1->redis_rpc_port();
2581
2582
0
    sc1 = std::make_shared<RedisClient>(host0, port0);
2583
0
    sc2 = std::make_shared<RedisClient>(host1, port1);
2584
0
    sc3 = std::make_shared<RedisClient>(host0, port0);
2585
0
    pc1 = std::make_shared<RedisClient>(host0, port0);
2586
0
    pc2 = std::make_shared<RedisClient>(host1, port1);
2587
0
    ps0 = nullptr;  // Diabled. PubSub monitoring only queries the local proxy.
2588
0
  }
2589
2590
0
  if (stype == SubOrUnsub::kSubscribe) {
2591
0
    if (ptype == PatternOrChannel::kChannel) {
2592
0
      TestSubscribe(this, ps0, sc1, sc2, sc3, pc1, pc2);
2593
0
    } else {
2594
0
      TestPSubscribe(this, ps0, sc1, sc2, sc3, pc1, pc2);
2595
0
    }
2596
0
  } else {
2597
0
    if (ptype == PatternOrChannel::kChannel) {
2598
0
      TestUnsubscribe(this, ps0, sc1, sc2, sc3, pc1, pc2);
2599
0
    } else {
2600
0
      TestPUnsubscribe(this, ps0, sc1, sc2, sc3, pc1, pc2);
2601
0
    }
2602
0
  }
2603
0
}
2604
2605
0
TEST_F(TestRedisServiceExternal, TestSubscribe) {
2606
0
  expected_no_sessions_ = true;
2607
0
  TestPubSub(LocalOrCluster::kLocal, SubOrUnsub::kSubscribe, PatternOrChannel::kChannel);
2608
0
}
2609
2610
0
TEST_F(TestRedisServiceExternal, TestSubscribeCluster) {
2611
0
  expected_no_sessions_ = true;
2612
0
  TestPubSub(LocalOrCluster::kCluster, SubOrUnsub::kSubscribe, PatternOrChannel::kChannel);
2613
0
}
2614
2615
0
TEST_F(TestRedisServiceExternal, TestUnsubscribe) {
2616
0
  expected_no_sessions_ = true;
2617
0
  TestPubSub(LocalOrCluster::kLocal, SubOrUnsub::kUnsubscribe, PatternOrChannel::kChannel);
2618
0
}
2619
2620
0
TEST_F(TestRedisServiceExternal, TestUnsubscribeCluster) {
2621
0
  expected_no_sessions_ = true;
2622
0
  TestPubSub(LocalOrCluster::kCluster, SubOrUnsub::kUnsubscribe, PatternOrChannel::kChannel);
2623
0
}
2624
2625
0
TEST_F(TestRedisServiceExternal, TestPSubscribe) {
2626
0
  expected_no_sessions_ = true;
2627
0
  TestPubSub(LocalOrCluster::kLocal, SubOrUnsub::kSubscribe, PatternOrChannel::kPattern);
2628
0
}
2629
2630
0
TEST_F(TestRedisServiceExternal, TestPSubscribeCluster) {
2631
0
  expected_no_sessions_ = true;
2632
0
  TestPubSub(LocalOrCluster::kCluster, SubOrUnsub::kSubscribe, PatternOrChannel::kPattern);
2633
0
}
2634
2635
0
TEST_F(TestRedisServiceExternal, TestPUnsubscribe) {
2636
0
  expected_no_sessions_ = true;
2637
0
  TestPubSub(LocalOrCluster::kLocal, SubOrUnsub::kUnsubscribe, PatternOrChannel::kPattern);
2638
0
}
2639
2640
0
TEST_F(TestRedisServiceExternal, TestPUnsubscribeCluster) {
2641
0
  expected_no_sessions_ = true;
2642
0
  TestPubSub(LocalOrCluster::kCluster, SubOrUnsub::kUnsubscribe, PatternOrChannel::kPattern);
2643
0
}
2644
2645
0
TEST_F(TestRedisServiceExternal, TestSlowSubscribersCatchingUp) {
2646
0
  expected_no_sessions_ = true;
2647
2648
0
  auto ts0 = external_mini_cluster()->tablet_server(0);
2649
0
  auto host0 = ts0->bind_host();
2650
0
  auto port0 = ts0->redis_rpc_port();
2651
2652
0
  auto sc1 = std::make_shared<RedisClient>(host0, port0);
2653
0
  auto pc1 = std::make_shared<RedisClient>(host0, port0);
2654
2655
0
  const string topic1 = "topic1";
2656
0
  const string padding(1_MB, 'x');
2657
2658
0
  UseClient(sc1);
2659
0
  DoRedisTestResultsArray(
2660
0
      __LINE__, {"SUBSCRIBE", topic1},
2661
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
2662
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
2663
0
  SyncClient();
2664
2665
0
  constexpr int kNumLoops = 3;
2666
0
  constexpr int kNumMsgs = 20;
2667
0
  const auto kSoftLimitGracePeriodMinusDelta =
2668
0
      MonoDelta::FromSeconds(kSoftLimitGracePeriod.ToSeconds() * 0.8);
2669
0
  const auto kSoftLimitGracePeriodPlusDelta =
2670
0
      MonoDelta::FromSeconds(kSoftLimitGracePeriod.ToSeconds() * 1.2);
2671
0
  for (int loops = 0; loops < kNumLoops; loops++) {
2672
    // Write approx 20MB of data. More than the soft limit. But less than the hard limit.
2673
0
    UseClient(pc1);
2674
0
    for (int i = 0; i < kNumMsgs; i++) {
2675
      // Now send msg1 to topic 1.
2676
0
      auto msg = Substitute("trial-$0 : $1", i, padding);
2677
0
      VLOG(2) << "Trial " << i << ". Publishing message of size " << msg.length() << " bytes";
2678
0
      DoRedisTestInt(__LINE__, {"PUBLISH", topic1, msg}, 1);
2679
0
      ASSERT_NO_FATALS(SyncClient());
2680
0
    }
2681
2682
    // Wait for less than what the server to enforce the soft limit.
2683
0
    SleepFor(kSoftLimitGracePeriodMinusDelta);
2684
2685
0
    for (int i = 0; i < kNumMsgs; i++) {
2686
      // Verify the received messages.
2687
0
      VLOG(2) << "Trial " << i << ". Receiving subscribed message";
2688
0
      UseClient(sc1);
2689
0
      auto msg = Substitute("trial-$0 : $1", i, padding);
2690
0
      DoRedisTestArray(__LINE__, {}, {"message", topic1, msg});
2691
0
      ASSERT_NO_FATALS(SyncClient());
2692
0
    }
2693
2694
0
    SleepFor(kSoftLimitGracePeriodPlusDelta);
2695
0
  }
2696
2697
0
  const string big_padding(20_MB, 'x');
2698
0
  for (int loops = 0; loops < kNumLoops; loops++) {
2699
    // Write > soft limit sized data in one shot.
2700
0
    UseClient(pc1);
2701
0
    auto msg = Substitute("Big-$0", big_padding);
2702
0
    VLOG(2) << loops << ". Publishing a big message of size " << msg.length();
2703
0
    DoRedisTestInt(__LINE__, {"PUBLISH", topic1, msg}, 1);
2704
0
    ASSERT_NO_FATALS(SyncClient());
2705
2706
    // Wait for less than what the server to enforce the soft limit.
2707
0
    SleepFor(kSoftLimitGracePeriodMinusDelta);
2708
2709
0
    UseClient(sc1);
2710
0
    DoRedisTestArray(__LINE__, {}, {"message", topic1, msg});
2711
0
    ASSERT_NO_FATALS(SyncClient());
2712
2713
0
    SleepFor(kSoftLimitGracePeriodPlusDelta);
2714
0
  }
2715
0
}
2716
2717
0
TEST_F(TestRedisServiceExternal, TestSlowSubscribersSoftLimit) {
2718
0
  expected_no_sessions_ = true;
2719
2720
0
  auto ts0 = external_mini_cluster()->tablet_server(0);
2721
0
  auto host0 = ts0->bind_host();
2722
0
  auto port0 = ts0->redis_rpc_port();
2723
2724
0
  auto sc1 = std::make_shared<RedisClient>(host0, port0);
2725
0
  auto pc1 = std::make_shared<RedisClient>(host0, port0);
2726
2727
0
  const string topic1 = "topic1";
2728
0
  const string padding(1_MB, 'x');
2729
2730
0
  UseClient(sc1);
2731
0
  DoRedisTestResultsArray(
2732
0
      __LINE__, {"SUBSCRIBE", topic1},
2733
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
2734
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
2735
0
  SyncClient();
2736
2737
0
  UseClient(pc1);
2738
  // Write approx 15MB of data. Something more than the soft limit.
2739
0
  for (int i = 0; i < 15; i++) {
2740
    // Now send msg1 to topic 1.
2741
0
    auto msg = Substitute("trial-$0 : $1", i, padding);
2742
0
    VLOG(2) << "Trial " << i << ". Publishing message of size " << msg.length() << " bytes";
2743
0
    DoRedisTestInt(__LINE__, {"PUBLISH", topic1, msg}, 1);
2744
0
    ASSERT_NO_FATALS(SyncClient());
2745
0
  }
2746
2747
  // Wait for the server to enforce the soft limit.
2748
0
  SleepFor(kSoftLimitGracePeriod);
2749
2750
0
  DoRedisTestApproxInt(__LINE__, {"PUBLISH", topic1, "whatever"}, 1, 1);
2751
0
  ASSERT_NO_FATALS(SyncClient());
2752
0
  for (int i = 15; i < 30; i++) {
2753
    // Now send msg1 to topic 1.
2754
0
    auto msg = Substitute("trial-$0 : $1", i, padding);
2755
0
    VLOG(2) << "Trial " << i << ". Publishing message of size " << msg.length() << " bytes";
2756
0
    DoRedisTestInt(__LINE__, {"PUBLISH", topic1, msg}, 0);
2757
0
    ASSERT_NO_FATALS(SyncClient());
2758
0
  }
2759
2760
  // sc1 should have already been disconnected.
2761
0
  UseClient(sc1);
2762
0
  DoRedisTestExpectError(__LINE__, {});
2763
0
}
2764
2765
0
TEST_F(TestRedisServiceExternal, TestSlowSubscribersHardLimit) {
2766
0
  expected_no_sessions_ = true;
2767
2768
0
  auto ts0 = external_mini_cluster()->tablet_server(0);
2769
0
  auto host0 = ts0->bind_host();
2770
0
  auto port0 = ts0->redis_rpc_port();
2771
2772
0
  auto sc1 = std::make_shared<RedisClient>(host0, port0);
2773
0
  auto pc1 = std::make_shared<RedisClient>(host0, port0);
2774
2775
0
  const string topic1 = "topic1";
2776
0
  const string padding(1_MB, 'x');
2777
2778
0
  UseClient(sc1);
2779
0
  DoRedisTestResultsArray(
2780
0
      __LINE__, {"SUBSCRIBE", topic1},
2781
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
2782
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
2783
0
  SyncClient();
2784
2785
0
  UseClient(pc1);
2786
  // Write approx 32MB of data.
2787
0
  for (int i = 0; i < 32; i++) {
2788
    // Now send msg1 to topic 1.
2789
0
    auto msg = Substitute("trial-$0 : $1", i, padding);
2790
0
    VLOG(2) << "Trial " << i << ". Publishing message of size " << msg.length() << " bytes";
2791
0
    DoRedisTestInt(__LINE__, {"PUBLISH", topic1, msg}, 1);
2792
0
    ASSERT_NO_FATALS(SyncClient());
2793
0
  }
2794
2795
  // Let's allow for some msgs to be either sent to the subscriber or unsent, to account for
2796
  // buffering in the lower layers.
2797
0
  for (int i = 32; i < 40; i++) {
2798
0
    auto msg = Substitute("trial-$0 : $1", i, padding);
2799
0
    VLOG(2) << "Trial " << i << ". Publishing message of size " << msg.length() << " bytes";
2800
0
    DoRedisTestApproxInt(__LINE__, {"PUBLISH", topic1, msg}, 1, 1);
2801
0
    ASSERT_NO_FATALS(SyncClient());
2802
0
  }
2803
2804
  // The slow subscriber should have been disconnected. Expect the msg to be sent to no one.
2805
0
  for (int i = 40; i < 50; i++) {
2806
    // Now send msg1 to topic 1.
2807
0
    auto msg = Substitute("trial-$0 : $1", i, padding);
2808
0
    VLOG(2) << "Trial " << i << ". Publishing message of size " << msg.length() << " bytes";
2809
0
    DoRedisTestInt(__LINE__, {"PUBLISH", topic1, msg}, 0);
2810
0
    ASSERT_NO_FATALS(SyncClient());
2811
0
  }
2812
2813
0
  UseClient(sc1);
2814
  // sc1 should have already been disconnected.
2815
0
  DoRedisTestExpectError(__LINE__, {});
2816
0
}
2817
2818
0
TEST_F(TestRedisServiceExternal, SubscribedClientMode) {
2819
0
  expected_no_sessions_ = true;
2820
0
  const string topic1 = "topic1";
2821
0
  const string value = "value";
2822
2823
0
  DoRedisTestSimpleString(__LINE__, {"PING"}, "PONG");
2824
0
  DoRedisTestBulkString(__LINE__, {"PING", "cmd2"}, "cmd2");
2825
0
  SyncClient();
2826
2827
0
  DoRedisTestResultsArray(
2828
0
      __LINE__, {"SUBSCRIBE", topic1},
2829
0
      {RedisReply(RedisReplyType::kString, "subscribe"),
2830
0
       RedisReply(RedisReplyType::kString, topic1), RedisReply(1)});
2831
0
  SyncClient();
2832
2833
0
  DoRedisTestExpectError(__LINE__, {"SET", "foo", value});
2834
0
  SyncClient();
2835
2836
0
  DoRedisTestArray(__LINE__, {"PING", "cmd2"}, {"pong", "cmd2"});
2837
0
  SyncClient();
2838
2839
0
  DoRedisTestOk(__LINE__, {"QUIT"});
2840
0
  SyncClient();
2841
0
}
2842
2843
0
TEST_F(TestRedisService, TestAuth) {
2844
0
  FLAGS_redis_password_caching_duration_ms = 0;
2845
0
  const char* kRedisAuthPassword = "redis-password";
2846
  // Expect new connections to require authentication
2847
0
  auto rc1 = CreateClient();
2848
0
  auto rc2 = CreateClient();
2849
0
  UseClient(rc1);
2850
0
  DoRedisTestSimpleString(__LINE__, {"PING"}, "PONG");
2851
0
  SyncClient();
2852
0
  UseClient(rc2);
2853
0
  DoRedisTestSimpleString(__LINE__, {"PING"}, "PONG");
2854
0
  SyncClient();
2855
2856
  // Set require pass using one connection
2857
0
  UseClient(rc1);
2858
0
  DoRedisTestOk(__LINE__, {"CONFIG", "SET", "REQUIREPASS", kRedisAuthPassword});
2859
0
  DoRedisTestArray(__LINE__, {"CONFIG", "GET", "REQUIREPASS"}, {});
2860
0
  DoRedisTestArray(__LINE__, {"CONFIG", "GET", "FooBar"}, {});
2861
0
  SyncClient();
2862
0
  UseClient(nullptr);
2863
  // Other pre-established connections should still be able to work, without re-authentication.
2864
0
  UseClient(rc2);
2865
0
  DoRedisTestSimpleString(__LINE__, {"PING"}, "PONG");
2866
0
  SyncClient();
2867
2868
  // Ensure that new connections need the correct password to authenticate.
2869
0
  ConnectWithPassword(this, nullptr, false, false);
2870
0
  ConnectWithPassword(this, "wrong-password", false, false);
2871
0
  ConnectWithPassword(this, kRedisAuthPassword, true, true);
2872
2873
  // Set multiple passwords.
2874
0
  UseClient(rc1);
2875
0
  DoRedisTestOk(__LINE__, {"CONFIG", "SET", "REQUIREPASS", "passwordA,passwordB"});
2876
0
  SyncClient();
2877
0
  UseClient(nullptr);
2878
2879
0
  ConnectWithPassword(this, nullptr, false, false);
2880
0
  ConnectWithPassword(this, "wrong-password", false, false);
2881
  // Old password should no longer work.
2882
0
  ConnectWithPassword(this, kRedisAuthPassword, false, false);
2883
0
  ConnectWithPassword(this, "passwordA", true, true);
2884
0
  ConnectWithPassword(this, "passwordB", true, true);
2885
0
  ConnectWithPassword(this, "passwordC", false, false);
2886
  // Need to provide one. Not both while authenticating.
2887
0
  ConnectWithPassword(this, "passwordA,passwordB", false, false);
2888
2889
  // Setting more than 2 passwords should fail.
2890
0
  UseClient(rc1);
2891
0
  DoRedisTestExpectError(
2892
0
      __LINE__, {"CONFIG", "SET", "REQUIREPASS", "passwordA,passwordB,passwordC"});
2893
0
  SyncClient();
2894
2895
  // Now set no password.
2896
0
  DoRedisTestOk(__LINE__, {"CONFIG", "SET", "REQUIREPASS", ""});
2897
0
  SyncClient();
2898
0
  UseClient(nullptr);
2899
2900
  // Setting wrong/old password(s) should fail. But set/get commands after that should succeed
2901
  // regardless.
2902
0
  ConnectWithPassword(this, "wrong-password", false, true);
2903
0
  ConnectWithPassword(this, kRedisAuthPassword, false, true);
2904
0
  ConnectWithPassword(this, "passwordA", false, true);
2905
0
  ConnectWithPassword(this, "passwordB", false, true);
2906
0
  ConnectWithPassword(this, nullptr, true, true);
2907
2908
0
  VerifyCallbacks();
2909
0
}
2910
2911
0
TEST_F(TestRedisService, TestPasswordChangeWithDelay) {
2912
0
  constexpr uint32 kCachingDurationMs = 1000;
2913
0
  FLAGS_redis_password_caching_duration_ms = kCachingDurationMs;
2914
0
  const char* kRedisAuthPassword = "redis-password";
2915
0
  auto start = std::chrono::steady_clock::now();
2916
0
  auto rc1 = CreateClient();
2917
2918
0
  UseClient(rc1);
2919
0
  DoRedisTestOk(__LINE__, {"CONFIG", "SET", "REQUIREPASS", kRedisAuthPassword});
2920
0
  SyncClient();
2921
0
  UseClient(nullptr);
2922
2923
  // Proxy may not realize the password change immediately.
2924
  // Expect the old password to work only if we haven't taken too long to get here.
2925
0
  const std::chrono::milliseconds kNotTooLong(kCachingDurationMs / 2);
2926
0
  auto now = std::chrono::steady_clock::now();
2927
0
  if (std::chrono::duration_cast<std::chrono::milliseconds>(now - start) < kNotTooLong) {
2928
0
    ConnectWithPassword(this, nullptr, true, true);
2929
0
    ConnectWithPassword(this, kRedisAuthPassword, false, true);
2930
0
  }
2931
2932
  // Wait for the cached redis credentials in the redis proxy to expire.
2933
0
  constexpr uint32 kDelayMs = 100;
2934
0
  std::this_thread::sleep_for(std::chrono::milliseconds(kCachingDurationMs + kDelayMs));
2935
2936
  // Expect the proxy to realize the effect of the password change.
2937
0
  ConnectWithPassword(this, nullptr, false, false);
2938
0
  ConnectWithPassword(this, kRedisAuthPassword, true, true);
2939
2940
0
  VerifyCallbacks();
2941
0
}
2942
2943
0
TEST_F(TestRedisService, TestRename) {
2944
0
  DoRedisTestOk(__LINE__, {"SET", "k1", "5"});
2945
0
  SyncClient();
2946
0
  DoRedisTestInt(__LINE__, {"EXPIRE", "k1", "100"}, 1);
2947
0
  SyncClient();
2948
2949
0
  DoRedisTestBulkString(__LINE__, {"GET", "k1"}, "5");
2950
0
  DoRedisTestNull(__LINE__, {"GET", "k2"});
2951
0
  SyncClient();
2952
0
  DoRedisTestApproxInt(__LINE__, {"TTL", "k1"}, 100, 5);
2953
0
  DoRedisTestInt(__LINE__, {"TTL", "k2"}, -2);
2954
0
  SyncClient();
2955
2956
0
  DoRedisTestOk(__LINE__, {"RENAME", "k1", "k2"});
2957
0
  SyncClient();
2958
2959
0
  DoRedisTestNull(__LINE__, {"GET", "k1"});
2960
0
  DoRedisTestBulkString(__LINE__, {"GET", "k2"}, "5");
2961
0
  SyncClient();
2962
0
  DoRedisTestApproxInt(__LINE__, {"TTL", "k2"}, 100, 5);
2963
0
  DoRedisTestInt(__LINE__, {"TTL", "k1"}, -2);
2964
0
  SyncClient();
2965
2966
  // Degenerate case src == dest.
2967
0
  DoRedisTestOk(__LINE__, {"RENAME", "k2", "k2"});
2968
0
  SyncClient();
2969
0
  DoRedisTestBulkString(__LINE__, {"GET", "k2"}, "5");
2970
0
  SyncClient();
2971
2972
  // Failure cases.
2973
0
  DoRedisTestExpectError(__LINE__, {"RENAME", "non-existent", "k2"});
2974
0
  SyncClient();
2975
0
  DoRedisTestBulkString(__LINE__, {"GET", "k2"}, "5");
2976
0
  SyncClient();
2977
0
}
2978
2979
0
TEST_F(TestRedisService, TestRenameSameTablet) {
2980
  // Rename to a key in the same tablet
2981
  // specify prefix to ensure that the keys are on the same tablet.
2982
0
  DoRedisTestOk(__LINE__, {"SET", "{k}0", "5"});
2983
0
  DoRedisTestOk(__LINE__, {"RENAME", "{k}0", "{k}xxxxxx"});
2984
0
  SyncClient();
2985
0
  DoRedisTestNull(__LINE__, {"GET", "{k}0"});
2986
0
  DoRedisTestBulkString(__LINE__, {"GET", "{k}xxxxxx"}, "5");
2987
0
  SyncClient();
2988
0
}
2989
2990
0
TEST_F(TestRedisService, TestRenameSameTabletRandomized) {
2991
  // Rename to a key in the same tablet
2992
  // randomized 1/24 odds of being in the same tablet as k0.
2993
0
  for (int i = 1; i < 100; i++) {
2994
0
    const string dest = strings::Substitute("k$0", i);
2995
0
    VLOG(1) << "Renaming from k0 to " << dest;
2996
0
    DoRedisTestOk(__LINE__, {"SET", "k0", "5"});
2997
0
    SyncClient();
2998
0
    DoRedisTestOk(__LINE__, {"RENAME", "k0", dest});
2999
0
    SyncClient();
3000
0
    DoRedisTestNull(__LINE__, {"GET", "k0"});
3001
0
    DoRedisTestBulkString(__LINE__, {"GET", dest}, "5");
3002
0
    SyncClient();
3003
0
  }
3004
0
}
3005
3006
0
TEST_F(TestRedisService, TestRenamePipeline) {
3007
  // Pipeline case.
3008
0
  DoRedisTestOk(__LINE__, {"SET", "ka", "4"});
3009
0
  SyncClient();
3010
3011
0
  DoRedisTestOk(__LINE__, {"SET", "ka", "5"});
3012
0
  DoRedisTestOk(__LINE__, {"RENAME", "ka", "kb"});
3013
0
  DoRedisTestBulkString(__LINE__, {"GET", "kb"}, "5");
3014
0
  DoRedisTestNull(__LINE__, {"GET", "ka"});
3015
0
  SyncClient();
3016
0
}
3017
3018
0
TEST_F(TestRedisService, TestRenameHash) {
3019
0
  DoRedisTestInt(__LINE__, {"HSET", "k1", "s1", "5"}, 1);
3020
0
  DoRedisTestInt(__LINE__, {"HSET", "k1", "s2", "6"}, 1);
3021
0
  SyncClient();
3022
0
  DoRedisTestInt(__LINE__, {"EXPIRE", "k1", "100"}, 1);
3023
3024
0
  SyncClient();
3025
0
  DoRedisTestOk(__LINE__, {"SET", "k2", "x"});
3026
0
  SyncClient();
3027
3028
0
  DoRedisTestBulkString(__LINE__, {"HGET", "k1", "s1"}, "5");
3029
0
  DoRedisTestBulkString(__LINE__, {"HGET", "k1", "s2"}, "6");
3030
0
  DoRedisTestBulkString(__LINE__, {"GET", "k2"}, "x");
3031
0
  SyncClient();
3032
0
  DoRedisTestApproxInt(__LINE__, {"TTL", "k1"}, 100, 5);
3033
0
  DoRedisTestInt(__LINE__, {"TTL", "k2"}, -1);
3034
0
  SyncClient();
3035
3036
0
  DoRedisTestOk(__LINE__, {"RENAME", "k1", "k2"});
3037
0
  SyncClient();
3038
3039
0
  DoRedisTestBulkString(__LINE__, {"HGET", "k2", "s1"}, "5");
3040
0
  DoRedisTestBulkString(__LINE__, {"HGET", "k2", "s2"}, "6");
3041
0
  DoRedisTestNull(__LINE__, {"GET", "k1"});
3042
0
  DoRedisTestNull(__LINE__, {"HGET", "k1", "s1"});
3043
0
  SyncClient();
3044
0
  DoRedisTestApproxInt(__LINE__, {"TTL", "k2"}, 100, 5);
3045
0
  DoRedisTestInt(__LINE__, {"TTL", "k1"}, -2);
3046
0
  SyncClient();
3047
0
}
3048
3049
0
TEST_F(TestRedisService, TestRenameSet) {
3050
0
  DoRedisTestInt(__LINE__, {"SADD", "k1", "s1", "s2"}, 2);
3051
0
  SyncClient();
3052
0
  DoRedisTestInt(__LINE__, {"EXPIRE", "k1", "100"}, 1);
3053
0
  SyncClient();
3054
3055
0
  DoRedisTestArray(__LINE__, {"SMEMBERS", "k1"}, {"s1", "s2"});
3056
0
  DoRedisTestNull(__LINE__, {"GET", "k2"});
3057
0
  DoRedisTestArray(__LINE__, {"SMEMBERS", "k2"}, {});
3058
0
  SyncClient();
3059
0
  DoRedisTestApproxInt(__LINE__, {"TTL", "k1"}, 100, 5);
3060
0
  DoRedisTestInt(__LINE__, {"TTL", "k2"}, -2);
3061
0
  SyncClient();
3062
3063
0
  DoRedisTestOk(__LINE__, {"RENAME", "k1", "k2"});
3064
0
  SyncClient();
3065
3066
0
  DoRedisTestArray(__LINE__, {"SMEMBERS", "k2"}, {"s1", "s2"});
3067
0
  DoRedisTestNull(__LINE__, {"GET", "k1"});
3068
0
  DoRedisTestArray(__LINE__, {"SMEMBERS", "k1"}, {});
3069
0
  SyncClient();
3070
0
  DoRedisTestApproxInt(__LINE__, {"TTL", "k2"}, 100, 5);
3071
0
  DoRedisTestInt(__LINE__, {"TTL", "k1"}, -2);
3072
0
  SyncClient();
3073
0
}
3074
3075
0
TEST_F(TestRedisService, TestRenameSortedSet) {
3076
0
  DoRedisTestInt(__LINE__, {"ZADD", "k1", "-2", "sk1", "2", "sk2"}, 2);
3077
0
  SyncClient();
3078
0
  DoRedisTestInt(__LINE__, {"EXPIRE", "k1", "100"}, 1);
3079
0
  SyncClient();
3080
3081
0
  DoRedisTestScoreValueArray(
3082
0
      __LINE__, {"ZRANGEBYSCORE", "k1", "-inf", "+inf", "WITHSCORES"}, {-2, 2}, {"sk1", "sk2"});
3083
0
  DoRedisTestNull(__LINE__, {"GET", "k2"});
3084
0
  SyncClient();
3085
0
  DoRedisTestApproxInt(__LINE__, {"TTL", "k1"}, 100, 5);
3086
0
  DoRedisTestInt(__LINE__, {"TTL", "k2"}, -2);
3087
0
  SyncClient();
3088
3089
0
  DoRedisTestOk(__LINE__, {"RENAME", "k1", "k2"});
3090
0
  SyncClient();
3091
3092
0
  DoRedisTestScoreValueArray(
3093
0
      __LINE__, {"ZRANGEBYSCORE", "k2", "-inf", "+inf", "WITHSCORES"}, {-2, 2}, {"sk1", "sk2"});
3094
0
  DoRedisTestNull(__LINE__, {"GET", "k1"});
3095
0
  SyncClient();
3096
0
  DoRedisTestApproxInt(__LINE__, {"TTL", "k2"}, 100, 5);
3097
0
  DoRedisTestInt(__LINE__, {"TTL", "k1"}, -2);
3098
0
  SyncClient();
3099
0
}
3100
3101
0
TEST_F(TestRedisService, TestRenameTSType) {
3102
0
  DoRedisTestOk(__LINE__, {"TSADD", "k1", "2", "sk1", "-2", "sk2"});
3103
0
  SyncClient();
3104
3105
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "k1", "-inf", "+inf"}, {"-2", "sk2", "2", "sk1"});
3106
0
  DoRedisTestNull(__LINE__, {"GET", "k2"});
3107
0
  SyncClient();
3108
3109
0
  DoRedisTestOk(__LINE__, {"RENAME", "k1", "k2"});
3110
0
  SyncClient();
3111
3112
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "k2", "-inf", "+inf"}, {"-2", "sk2", "2", "sk1"});
3113
0
  DoRedisTestNull(__LINE__, {"GET", "k1"});
3114
0
  SyncClient();
3115
0
}
3116
3117
0
TEST_F(TestRedisService, TestIncr) {
3118
0
  DoRedisTestOk(__LINE__, {"SET", "k1", "5"});
3119
0
  DoRedisTestBulkString(__LINE__, {"GET", "k1"}, "5");
3120
3121
0
  DoRedisTestInt(__LINE__, {"INCR", "k1"}, 6);
3122
0
  DoRedisTestBulkString(__LINE__, {"GET", "k1"}, "6");
3123
3124
0
  DoRedisTestInt(__LINE__, {"INCRBY", "k1", "4"}, 10);
3125
0
  DoRedisTestBulkString(__LINE__, {"GET", "k1"}, "10");
3126
3127
0
  DoRedisTestInt(__LINE__, {"INCRBY", "k1", "-5"}, 5);
3128
0
  DoRedisTestBulkString(__LINE__, {"GET", "k1"}, "5");
3129
3130
0
  DoRedisTestNull(__LINE__, {"GET", "kne1"});
3131
0
  DoRedisTestInt(__LINE__, {"INCR", "kne1"}, 1);
3132
0
  DoRedisTestBulkString(__LINE__, {"GET", "kne1"}, "1");
3133
3134
0
  DoRedisTestNull(__LINE__, {"GET", "kne2"});
3135
0
  DoRedisTestInt(__LINE__, {"INCRBY", "kne2", "5"}, 5);
3136
0
  DoRedisTestBulkString(__LINE__, {"GET", "kne2"}, "5");
3137
0
  SyncClient();
3138
3139
0
  DoRedisTestInt(__LINE__, {"HSET", "h1", "f1", "5"}, 1);
3140
0
  DoRedisTestBulkString(__LINE__, {"HGET", "h1", "f1"}, "5");
3141
0
  SyncClient();
3142
3143
0
  DoRedisTestInt(__LINE__, {"HINCRBY", "h1", "f1", "1"}, 6);
3144
0
  DoRedisTestBulkString(__LINE__, {"HGET", "h1", "f1"}, "6");
3145
0
  SyncClient();
3146
3147
0
  DoRedisTestInt(__LINE__, {"HINCRBY", "h1", "f1", "4"}, 10);
3148
0
  DoRedisTestBulkString(__LINE__, {"HGET", "h1", "f1"}, "10");
3149
0
  SyncClient();
3150
3151
0
  DoRedisTestInt(__LINE__, {"HINCRBY", "h1", "f1", "-5"}, 5);
3152
0
  DoRedisTestBulkString(__LINE__, {"HGET", "h1", "f1"}, "5");
3153
3154
0
  DoRedisTestInt(__LINE__, {"HINCRBY", "h1", "fne", "6"}, 6);
3155
0
  DoRedisTestBulkString(__LINE__, {"HGET", "h1", "fne"}, "6");
3156
0
  SyncClient();
3157
3158
0
  DoRedisTestInt(__LINE__, {"HINCRBY", "hstr", "fstr", "5"}, 5);
3159
0
  DoRedisTestBulkString(__LINE__, {"HGET", "hstr", "fstr"}, "5");
3160
0
  SyncClient();
3161
3162
0
  DoRedisTestNull(__LINE__, {"GET", "hne1"});
3163
0
  DoRedisTestInt(__LINE__, {"HINCRBY", "hne1", "fne", "6"}, 6);
3164
0
  DoRedisTestBulkString(__LINE__, {"HGET", "hne1", "fne"}, "6");
3165
3166
0
  DoRedisTestInt(__LINE__, {"HINCRBY", "hne1", "fne", "-16"}, -10);
3167
0
  DoRedisTestBulkString(__LINE__, {"HGET", "hne1", "fne"}, "-10");
3168
3169
0
  SyncClient();
3170
0
  LOG(INFO) << "Done with the test";
3171
0
  VerifyCallbacks();
3172
0
}
3173
3174
0
TEST_F(TestRedisService, TestKeysPipeline) {
3175
0
  DoRedisTestOk(__LINE__, {"SET", "xa", "5"});
3176
0
  DoRedisTestArray(__LINE__, {"KEYS", "*"}, {"xa"});
3177
0
  DoRedisTestNull(__LINE__, {"GET", "xb"});
3178
0
  DoRedisTestBulkString(__LINE__, {"GET", "xa"}, "5");
3179
0
  SyncClient();
3180
0
  VerifyCallbacks();
3181
0
}
3182
3183
0
TEST_F(TestRedisService, TestIncrCorner) {
3184
0
  DoRedisTestOk(__LINE__, {"SET", "kstr", "str"});
3185
0
  SyncClient();
3186
3187
0
  DoRedisTestExpectError(__LINE__, {"INCR", "kstr"}, "ERR");
3188
0
  DoRedisTestBulkString(__LINE__, {"GET", "kstr"}, "str");
3189
0
  DoRedisTestExpectError(__LINE__, {"INCRBY", "kstr", "5"}, "ERR");
3190
0
  DoRedisTestBulkString(__LINE__, {"GET", "kstr"}, "str");
3191
0
  SyncClient();
3192
3193
0
  DoRedisTestInt(__LINE__, {"HSET", "h1", "f1", "5"}, 1);
3194
0
  DoRedisTestInt(__LINE__, {"HSET", "h1", "fstr", "str"}, 1);
3195
0
  SyncClient();
3196
3197
  // over 32 bit
3198
0
  DoRedisTestOk(__LINE__, {"SET", "novar", "17179869184"});
3199
0
  SyncClient();
3200
0
  DoRedisTestInt(__LINE__, {"INCR", "novar"}, 17179869185);
3201
0
  SyncClient();
3202
0
  DoRedisTestInt(__LINE__, {"INCRBY", "novar", "17179869183"}, 34359738368);
3203
0
  SyncClient();
3204
3205
  // over 32 bit
3206
0
  DoRedisTestOk(__LINE__, {"SET", "novar64", "9223372036854775807"}); // 2 ** 63 - 1
3207
0
  SyncClient();
3208
0
  DoRedisTestExpectError(__LINE__, {"INCR", "novar64"}, "Increment would overflow");
3209
0
  SyncClient();
3210
3211
  // INCRBY on a Hash type should fail.
3212
0
  DoRedisTestExpectError(__LINE__, {"INCRBY", "h1", "5"}, "WRONGTYPE");
3213
0
  SyncClient();
3214
  // HINCRBY should fail on a normal key.
3215
0
  DoRedisTestExpectError(__LINE__, {"HINCRBY", "kstr", "fstr", "5"}, "WRONGTYPE");
3216
0
  SyncClient();
3217
  // HINCRBY too many arguments.
3218
0
  DoRedisTestExpectError(__LINE__, {"HINCRBY", "h1", "f1", "5", "extra_arg"});
3219
0
  SyncClient();
3220
3221
0
  DoRedisTestExpectError(__LINE__, {"HINCRBY", "h1", "fstr", "5"}, "ERR");
3222
0
  DoRedisTestBulkString(__LINE__, {"HGET", "h1", "fstr"}, "str");
3223
0
  SyncClient();
3224
3225
0
  VerifyCallbacks();
3226
0
}
3227
3228
// This test also uses the open source client
3229
0
TEST_F(TestRedisService, TestTtlSetEx) {
3230
3231
0
  DoRedisTestOk(__LINE__, {"SET", "k1", "v1"});
3232
0
  DoRedisTestOk(__LINE__, {"SET", "k2", "v2", "EX", "1"});
3233
0
  DoRedisTestOk(__LINE__, {"SET", "k3", "v3", "EX", NonTsanVsTsan("20", "100")});
3234
0
  DoRedisTestOk(__LINE__, {"SET", "k4", "v4", "EX", std::to_string(kRedisMaxTtlSeconds)});
3235
0
  DoRedisTestOk(__LINE__, {"SET", "k5", "v5", "EX", std::to_string(kRedisMinTtlSetExSeconds)});
3236
3237
  // Invalid ttl.
3238
0
  DoRedisTestExpectError(__LINE__, {"SET", "k6", "v6", "EX",
3239
0
      std::to_string(kRedisMaxTtlSeconds + 1)});
3240
0
  DoRedisTestExpectError(__LINE__, {"SET", "k7", "v7", "EX",
3241
0
      std::to_string(kRedisMinTtlSetExSeconds - 1)});
3242
3243
  // Commands are pipelined and only sent when client.commit() is called.
3244
  // sync_commit() waits until all responses are received.
3245
0
  SyncClient();
3246
0
  std::this_thread::sleep_for(2s);
3247
3248
0
  DoRedisTestBulkString(__LINE__, {"GET", "k1"}, "v1");
3249
0
  DoRedisTestNull(__LINE__, {"GET", "k2"});
3250
0
  DoRedisTestBulkString(__LINE__, {"GET", "k3"}, "v3");
3251
0
  DoRedisTestBulkString(__LINE__, {"GET", "k4"}, "v4");
3252
0
  DoRedisTestNull(__LINE__, {"GET", "k5"});
3253
3254
0
  SyncClient();
3255
0
  DoRedisTestOk(__LINE__, {"SET", "k10", "v10", "EX", "5", "NX"});
3256
0
  SyncClient();
3257
0
  DoRedisTestBulkString(__LINE__, {"GET", "k10"}, "v10");
3258
0
  SyncClient();
3259
3260
0
  std::this_thread::sleep_for(10s);
3261
0
  DoRedisTestOk(__LINE__, {"SET", "k10", "v10", "EX", "5", "NX"});
3262
3263
0
  SyncClient();
3264
0
  VerifyCallbacks();
3265
0
}
3266
3267
0
TEST_F(TestRedisService, TestDummyLocal) {
3268
0
  expected_no_sessions_ = true;
3269
0
  DoRedisTestBulkString(__LINE__, {"INFO"}, kInfoResponse);
3270
0
  DoRedisTestBulkString(__LINE__, {"INFO", "Replication"}, kInfoResponse);
3271
0
  DoRedisTestBulkString(__LINE__, {"INFO", "foo", "bar", "whatever", "whatever"}, kInfoResponse);
3272
0
  DoRedisTest(__LINE__, {"INFO"}, RedisReplyType::kString, [] (const RedisReply& reply) {
3273
0
      ASSERT_NE(reply.as_string().find("redis_version"), string::npos);
3274
0
    }
3275
0
  );
3276
3277
0
  DoRedisTestOk(__LINE__, {"COMMAND"});
3278
0
  DoRedisTestExpectError(__LINE__, {"EVAL"});
3279
3280
0
  SyncClient();
3281
0
  VerifyCallbacks();
3282
0
}
3283
3284
0
TEST_F(TestRedisService, TestTimeSeriesTtl) {
3285
0
  FLAGS_emulate_redis_responses = true;
3286
0
  DoRedisTestOk(__LINE__, {"TSADD", "key", "10", "v", "EXPIRE_IN", "5"});
3287
0
  SyncClient();
3288
3289
0
  std::this_thread::sleep_for(std::chrono::seconds(10));
3290
0
  DoRedisTestNull(__LINE__, {"TSGET", "key", "10"});
3291
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "key", "2", "val"});
3292
0
  DoRedisTestOk(__LINE__, {"TSADD", "key", "20", "v"});
3293
3294
0
  SyncClient();
3295
0
  VerifyCallbacks();
3296
0
}
3297
3298
0
TEST_F(TestRedisService, TestTimeSeries) {
3299
  // The default value is true, but we explicitly set this here for clarity.
3300
0
  FLAGS_emulate_redis_responses = true;
3301
3302
  // Need an int for timeseries as a score.
3303
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "42.0", "42"});
3304
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "12.0", "42"});
3305
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "subkey1", "42"});
3306
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "subkey2", "12"});
3307
0
  DoRedisTestExpectError(__LINE__, {"TSGET", "ts_key", "subkey1"});
3308
0
  DoRedisTestExpectError(__LINE__, {"TSGET", "ts_key", "subkey2"});
3309
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "1", "v1", "2", "v2", "3.0", "v3"});
3310
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "1", "v1", "2", "v2", "abc", "v3"});
3311
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "1", "v1", "2", "v2", "123abc", "v3"});
3312
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "1", "v1", "2", "v2", " 123", "v3"});
3313
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "1", "v1", "2", "v2", "0xff", "v3"});
3314
3315
  // Incorrect number of arguments.
3316
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "subkey1"});
3317
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "subkey2"});
3318
0
  DoRedisTestExpectError(__LINE__, {"TSGET", "ts_key"});
3319
0
  DoRedisTestExpectError(__LINE__, {"TSGET", "ts_key"});
3320
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "ts_key", "1", "v1", "2", "v2", "3"});
3321
3322
  // Valid statements.
3323
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key", "-10", "value1"});
3324
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key", "-20", "value2"});
3325
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key", "-30", "value3"});
3326
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key", "10", "value4"});
3327
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key", "20", "value5"});
3328
  // For duplicate keys, the last one is picked up.
3329
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key", "30", "value100", "30", "value6"});
3330
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key", int64Max_, "valuemax"});
3331
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key", int64Min_, "valuemin"});
3332
0
  SyncClient();
3333
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key", "30", "value7"});
3334
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_multi", "10", "v1", "20", "v2", "30", "v3", "40", "v4"});
3335
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_multi", "10", "v5", "50", "v6", "30", "v7", "60", "v8"});
3336
0
  SyncClient();
3337
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_multi", "10", "v9", "70", "v10", "30", "v11", "80", "v12"});
3338
0
  SyncClient();
3339
3340
  // Ensure we retrieve appropriate results.
3341
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_key", "-10"}, "value1");
3342
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_key", "-20"}, "value2");
3343
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_key", "-30"}, "value3");
3344
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_key", "10"}, "value4");
3345
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_key", "20"}, "value5");
3346
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_key", "30"}, "value7");
3347
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_key", int64Max_}, "valuemax");
3348
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_key", int64Min_}, "valuemin");
3349
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_multi", "10"}, "v9");
3350
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_multi", "20"}, "v2");
3351
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_multi", "30"}, "v11");
3352
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_multi", "40"}, "v4");
3353
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_multi", "50"}, "v6");
3354
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_multi", "60"}, "v8");
3355
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_multi", "70"}, "v10");
3356
0
  DoRedisTestBulkString(__LINE__, {"TSGET", "ts_multi", "80"}, "v12");
3357
3358
  // Keys that are not present.
3359
0
  DoRedisTestNull(__LINE__, {"TSGET", "ts_key", "40"});
3360
0
  DoRedisTestNull(__LINE__, {"TSGET", "abc", "30"});
3361
3362
  // HGET/SISMEMBER/GET should not work with this.
3363
0
  DoRedisTestExpectError(__LINE__, {"HGET", "ts_key", "30"});
3364
0
  DoRedisTestExpectError(__LINE__, {"SISMEMBER", "ts_key", "30"});
3365
0
  DoRedisTestExpectError(__LINE__, {"HEXISTS", "ts_key", "30"});
3366
0
  DoRedisTestExpectError(__LINE__, {"GET", "ts_key"});
3367
3368
  // TSGET should not work with HSET.
3369
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "30", "v1"}, 1);
3370
0
  DoRedisTestExpectError(__LINE__, {"TSGET", "map_key", "30"});
3371
3372
0
  SyncClient();
3373
0
  VerifyCallbacks();
3374
0
}
3375
3376
0
TEST_F(TestRedisService, TestSortedSets) {
3377
  // The default value is true, but we explicitly set this here for clarity.
3378
0
  FLAGS_emulate_redis_responses = true;
3379
3380
  // Need an double for sorted sets as a score.
3381
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "subkey1", "42"});
3382
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "subkey2", "12"});
3383
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "1", "v1", "2", "v2", "abc", "v3"});
3384
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "1", "v1", "2", "v2", "123abc", "v3"});
3385
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "1", "v1", "2", "v2", " 123", "v3"});
3386
0
  DoRedisTestExpectError(__LINE__, {"ZRANGEBYSCORE", "z_key", "1", " 2"});
3387
0
  DoRedisTestExpectError(__LINE__, {"ZRANGEBYSCORE", "z_key", "1", "abc"});
3388
0
  DoRedisTestExpectError(__LINE__, {"ZRANGEBYSCORE", "z_key", "abc", "2"});
3389
3390
  // Incorrect number of arguments.
3391
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "subkey1"});
3392
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "1", "v1", "2", "v2", "3"});
3393
0
  DoRedisTestExpectError(__LINE__, {"ZRANGEBYSCORE", "z_key", "1"});
3394
0
  DoRedisTestExpectError(__LINE__, {"ZRANGEBYSCORE", "z_key", "1", "2", "3"});
3395
0
  DoRedisTestExpectError(__LINE__, {"ZRANGEBYSCORE", "z_key", "1", "2", "WITHSCORES", "abc"});
3396
0
  DoRedisTestExpectError(__LINE__, {"ZREM", "z_key"});
3397
3398
  // Valid statements
3399
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "-30.0", "v1"}, 1);
3400
0
  SyncClient();
3401
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "-20.0", "v2"}, 1);
3402
0
  SyncClient();
3403
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "-10.0", "v3"}, 1);
3404
0
  SyncClient();
3405
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "10.0", "v4"}, 1);
3406
0
  SyncClient();
3407
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "20.0", "v5"}, 1);
3408
0
  SyncClient();
3409
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "30.0", "v6"}, 1);
3410
0
  SyncClient();
3411
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key",
3412
0
      strings::Substitute("$0", std::numeric_limits<double>::max()), "vmax"}, 1);
3413
0
  SyncClient();
3414
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key",
3415
0
      strings::Substitute("$0",  -std::numeric_limits<double>::max()), "vmin"}, 1);
3416
0
  SyncClient();
3417
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "40.0", "v6"}, 0);
3418
0
  SyncClient();
3419
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "0x1e", "v6"}, 0);
3420
0
  SyncClient();
3421
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "-20", "v1"}, 0);
3422
0
  SyncClient();
3423
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "-30", "v1"}, 0);
3424
0
  SyncClient();
3425
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "30.000001", "v7"}, 1);
3426
0
  SyncClient();
3427
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "30.000001", "v8"}, 1);
3428
0
  SyncClient();
3429
0
  DoRedisTestInt(__LINE__, {"ZCARD", "z_key"}, 10);
3430
0
  DoRedisTestOk(__LINE__, {"SET", "s_key", "s_val"});
3431
0
  SyncClient();
3432
0
  DoRedisTestExpectError(__LINE__, {"ZCARD", "s_key"});
3433
0
  DoRedisTestExpectErrorMsg(__LINE__, {"ZCARD", "s_key"},
3434
0
      "WRONGTYPE Operation against a key holding the wrong kind of value");
3435
3436
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi", "-10.0", "v3", "-20.0", "v2", "-30.0", "v1",
3437
0
      "10.0", "v4", "20.0", "v5", "30.0", "v6"}, 6);
3438
0
  SyncClient();
3439
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi", "40.0", "v6", "0x1e", "v6", "-20", "v1", "-30", "v1",
3440
0
      "30.000001", "v7", "30.000001", "v8"}, 2);
3441
0
  SyncClient();
3442
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi",
3443
0
      strings::Substitute("$0", std::numeric_limits<double>::max()), "vmax",
3444
0
      strings::Substitute("$0", -std::numeric_limits<double>::max()), "vmin"}, 2);
3445
0
  SyncClient();
3446
0
  DoRedisTestInt(__LINE__, {"ZCARD", "z_multi"}, 10);
3447
3448
  // Ensure we retrieve appropriate results.
3449
0
  LOG(INFO) << "Starting ZRANGE queries";
3450
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "+inf", "-inf"}, {});
3451
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "-inf", "+inf"},
3452
0
      {"vmin", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "vmax"});
3453
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "(-inf", "(+inf"},
3454
0
      {"vmin", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "vmax"});
3455
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "20.0", "30.0"}, {"v5", "v6"});
3456
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "20.0", "30.000001"},
3457
0
      {"v5", "v6", "v7", "v8"});
3458
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "20.0", "(30.000001"}, {"v5", "v6"});
3459
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "(20.0", "30.000001"}, {"v6", "v7", "v8"});
3460
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "-20.0", "-10.0"}, {"v2", "v3"});
3461
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "(-20.0", "(-10.0"}, {});
3462
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "+inf", "-inf"}, {});
3463
3464
0
  DoRedisTestScoreValueArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "20.0", "30.0", "WITHSCORES"},
3465
0
      {20.0, 30.0}, {"v5", "v6"});
3466
0
  DoRedisTestScoreValueArray(__LINE__,
3467
0
      {"ZRANGEBYSCORE", "z_key", "20.0", "30.000001", "withscores"},
3468
0
      {20.0, 30.0, 30.000001, 30.000001}, {"v5", "v6", "v7", "v8"});
3469
3470
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_multi", "-inf", "+inf"},
3471
0
      {"vmin", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "vmax"});
3472
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_multi", "(-inf", "(+inf"},
3473
0
      {"vmin", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "vmax"});
3474
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_multi", "20.0", "30.0"}, {"v5", "v6"});
3475
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_multi", "20.0", "30.000001"},
3476
0
      {"v5", "v6", "v7", "v8"});
3477
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_multi", "20.0", "(30.000001"}, {"v5", "v6"});
3478
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_multi", "(20.0", "30.000001"},
3479
0
      {"v6", "v7", "v8"});
3480
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_multi", "-20.0", "-10.0"}, {"v2", "v3"});
3481
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_multi", "(-20.0", "(-10.0"}, {});
3482
3483
0
  DoRedisTestScoreValueArray(__LINE__, {"ZRANGEBYSCORE", "z_multi", "20.0", "30.0", "WITHSCORES"},
3484
0
      {20.0, 30.0}, {"v5", "v6"});
3485
0
  DoRedisTestScoreValueArray(__LINE__,
3486
0
      {"ZRANGEBYSCORE", "z_multi", "20.0", "30.000001", "withscores"},
3487
0
      {20.0, 30.0, 30.000001, 30.000001}, {"v5", "v6", "v7", "v8"});
3488
3489
0
  DoRedisTestInt(__LINE__, {"ZREM", "z_key", "v6"}, 1);
3490
0
  SyncClient();
3491
0
  DoRedisTestInt(__LINE__, {"ZREM", "z_key", "v6"}, 0);
3492
0
  SyncClient();
3493
0
  DoRedisTestInt(__LINE__, {"ZREM", "z_key", "v7"}, 1);
3494
0
  SyncClient();
3495
0
  DoRedisTestInt(__LINE__, {"ZREM", "z_key", "v9"}, 0);
3496
0
  SyncClient();
3497
3498
0
  DoRedisTestInt(__LINE__, {"ZREM", "z_multi", "v6", "v7", "v9"}, 2);
3499
0
  SyncClient();
3500
0
  DoRedisTestInt(__LINE__, {"ZREM", "z_multi", "v6", "v7", "v9"}, 0);
3501
0
  SyncClient();
3502
3503
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "-inf", "+inf"},
3504
0
      {"vmin", "v1", "v2", "v3", "v4", "v5", "v8", "vmax"});
3505
0
  DoRedisTestInt(__LINE__, {"ZCARD", "z_key"}, 8);
3506
3507
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_multi", "-inf", "+inf"},
3508
0
      {"vmin", "v1", "v2", "v3", "v4", "v5", "v8", "vmax"});
3509
0
  DoRedisTestInt(__LINE__, {"ZCARD", "z_multi"}, 8);
3510
3511
  // Test NX/CH option.
3512
0
  LOG(INFO) << "Starting ZADD with options";
3513
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "NX", "0", "v8"}, 0);
3514
0
  SyncClient();
3515
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "NX", "CH", "0", "v8"}, 0);
3516
0
  SyncClient();
3517
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "NX", "0", "v9"}, 1);
3518
0
  SyncClient();
3519
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "NX", "40", "v9"}, 0);
3520
0
  SyncClient();
3521
3522
  // Make sure that only v9 exists at 0 and not at 40.
3523
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "0.0", "0.0"}, {"v9"});
3524
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "40.0", "40.0"}, {});
3525
0
  DoRedisTestInt(__LINE__, {"ZCARD", "z_key"}, 9);
3526
3527
  // Test XX/CH option.
3528
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "XX", "CH", "0", "v8"}, 1);
3529
0
  SyncClient();
3530
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "XX", "30.000001", "v8"}, 0);
3531
0
  SyncClient();
3532
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "XX", "0", "v10"}, 0);
3533
0
  SyncClient();
3534
3535
  // Make sure that only v9 exists at 0 and v8 exists at 30.000001.
3536
0
  DoRedisTestScoreValueArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "0.0", "0.0", "WITHSCORES"},
3537
0
      {0.0}, {"v9"});
3538
0
  DoRedisTestScoreValueArray(__LINE__,
3539
0
      {"ZRANGEBYSCORE", "z_key", "30.000001", "30.000001", "WITHSCORES"},
3540
0
      {30.000001}, {"v8"});
3541
0
  DoRedisTestInt(__LINE__, {"ZCARD", "z_key"}, 9);
3542
0
  DoRedisTestInt(__LINE__, {"ZCARD", "does_not_exist"}, 0);
3543
3544
  // Test NX/XX/CH option for multi.
3545
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi", "NX", "0", "v8", "40", "v9"}, 1);
3546
0
  SyncClient();
3547
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi", "CH", "0", "v8", "0", "v9"}, 2);
3548
0
  SyncClient();
3549
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi", "XX", "CH", "30.000001", "v8", "0", "v10"}, 1);
3550
0
  SyncClient();
3551
3552
  // Make sure that only v9 exists and 0 and v8 exists at 30.000001.
3553
0
  DoRedisTestScoreValueArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "0.0", "0.0", "WITHSCORES"},
3554
0
      {0.0}, {"v9"});
3555
0
  DoRedisTestScoreValueArray(__LINE__,
3556
0
      {"ZRANGEBYSCORE", "z_key", "30.000001", "30.000001", "WITHSCORES"},
3557
0
      {30.000001}, {"v8"});
3558
0
  DoRedisTestInt(__LINE__, {"ZCARD", "z_multi"}, 9);
3559
3560
  // Test incr option.
3561
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "INCR", "10", "v8"}, 0);
3562
0
  SyncClient();
3563
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "INCR", "XX", "CH", "10", "v8"}, 1);
3564
0
  SyncClient();
3565
  // This shouldn't do anything, since NX option is specified.
3566
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "INCR", "NX", "10", "v8"}, 0);
3567
0
  SyncClient();
3568
3569
  // Make sure v8 has been incremented by 20.
3570
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "30.000001", "30.000001"}, {});
3571
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "50.000001", "50.000001"}, {"v8"});
3572
0
  DoRedisTestInt(__LINE__, {"ZCARD", "z_key"}, 9);
3573
3574
  // HGET/SISMEMBER/GET/TS should not work with this.
3575
0
  DoRedisTestExpectError(__LINE__, {"SISMEMBER", "z_key", "30"});
3576
0
  DoRedisTestExpectError(__LINE__, {"HEXISTS", "z_key", "30"});
3577
0
  DoRedisTestExpectError(__LINE__, {"GET", "z_key"});
3578
0
  DoRedisTestExpectError(__LINE__, {"TSRANGE", "z_key", "1", "a"});
3579
3580
  // ZADD should not work with HSET.
3581
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "30", "v1"}, 1);
3582
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "map_key", "40", "v2"});
3583
3584
  // Cannot have both NX and XX options.
3585
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "CH", "NX", "XX", "0", "v1"});
3586
3587
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "CH", "NX", "INCR"});
3588
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "XX"});
3589
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "CH", "NX", "0", "v1", "1"});
3590
  // Cannot have incr with multiple score value pairs.
3591
0
  DoRedisTestExpectError(__LINE__, {"ZADD", "z_key", "INCR", "0", "v1", "1", "v2"});
3592
3593
  // Test ZREM on non-existent key and then add the same key.
3594
0
  DoRedisTestInt(__LINE__, {"ZREM", "my_z_set", "v1"}, 0);
3595
0
  SyncClient();
3596
0
  DoRedisTestInt(__LINE__, {"ZCARD", "my_z_set"}, 0);
3597
0
  SyncClient();
3598
0
  DoRedisTestInt(__LINE__, {"ZADD", "my_z_set", "1", "v1"}, 1);
3599
0
  SyncClient();
3600
0
  DoRedisTestInt(__LINE__, {"ZCARD", "my_z_set"}, 1);
3601
0
  SyncClient();
3602
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "my_z_set", "1", "1"}, {"v1"});
3603
0
}
3604
3605
0
TEST_F(TestRedisService, ZRangeByScoreInvalidOptions) {
3606
0
  expected_no_sessions_ = true;
3607
3608
  // Not enough args to ZRANGEBYSCORE should throw an error.
3609
0
  DoRedisTestExpectError(__LINE__, {"ZRANGEBYSCORE", "z_key", "-inf", "+inf", "LIMIT"});
3610
0
  DoRedisTestExpectError(__LINE__, {"ZRANGEBYSCORE", "z_key", "-inf", "+inf", "LIMIT", "2"});
3611
0
  DoRedisTestExpectError(__LINE__, {"ZRANGEBYSCORE", "z_key", "-inf", "+inf", "LIMIT", "a", "1"});
3612
0
  DoRedisTestExpectError(__LINE__, {
3613
0
      "ZRANGEBYSCORE", "z_key", "-inf", "+inf", "LIMIT", "1", "2", "3"});
3614
0
  DoRedisTestExpectError(__LINE__, {
3615
0
      "ZRANGEBYSCORE", "z_key", "-inf", "+inf", "LIMIT", "WITHSCORES", "2", "3"});
3616
0
  DoRedisTestExpectError(__LINE__, {
3617
0
      "ZRANGEBYSCORE", "z_key", "-inf", "+inf", "WITHSCORES", "2", "3"});
3618
0
  SyncClient();
3619
0
  VerifyCallbacks();
3620
0
}
3621
3622
0
TEST_F(TestRedisService, TestZRevRange) {
3623
  // The default value is true, but we explicitly set this here for clarity.
3624
0
  FLAGS_emulate_redis_responses = true;
3625
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi", "0", "v0", "0", "v1", "0", "v2",
3626
0
      "1", "v3", "1", "v4", "1", "v5"}, 6);
3627
0
  SyncClient();
3628
3629
0
  DoRedisTestArray(__LINE__, {"ZREVRANGE", "z_multi", "0", "5"},
3630
0
                   {"v5", "v4", "v3", "v2", "v1", "v0"});
3631
0
  DoRedisTestScoreValueArray(__LINE__, {"ZREVRANGE", "z_multi", "0", "-1", "WITHSCORES"},
3632
0
                             {1, 1, 1, 0, 0, 0},
3633
0
                             {"v5", "v4", "v3", "v2", "v1", "v0"});
3634
0
  DoRedisTestArray(__LINE__, {"ZREVRANGE", "z_multi", "0", "1"}, {"v5", "v4"});
3635
0
  DoRedisTestArray(__LINE__, {"ZREVRANGE", "z_multi", "2", "3"}, {"v3", "v2"});
3636
0
  DoRedisTestArray(__LINE__, {"ZREVRANGE", "z_multi", "6", "7"}, {});
3637
0
  DoRedisTestArray(__LINE__, {"ZREVRANGE", "z_multi", "0", "-1"},
3638
0
                   {"v5", "v4", "v3", "v2", "v1", "v0"});
3639
0
  DoRedisTestArray(__LINE__, {"ZREVRANGE", "z_multi", "-2", "-1"}, {"v1", "v0"});
3640
0
  DoRedisTestArray(__LINE__, {"ZREVRANGE", "z_multi", "-3", "-2"}, {"v2", "v1"});
3641
0
  DoRedisTestArray(__LINE__, {"ZREVRANGE", "z_multi", "-3", "5"}, {"v2", "v1", "v0"});
3642
3643
  // Test empty key.
3644
0
  DoRedisTestArray(__LINE__, {"ZREVRANGE", "z_key", "0", "1"}, {});
3645
3646
0
  DoRedisTestExpectError(__LINE__, {"ZREVRANGE", "z_multi", "0"});
3647
0
  DoRedisTestExpectError(__LINE__, {"ZREVRANGE", "z_multi", "1", "2", "3"});
3648
0
  DoRedisTestExpectError(__LINE__, {"ZREVRANGE", "z_multi", "1", "2", "WITHSCORES", "1"});
3649
0
  DoRedisTestExpectError(__LINE__, {"ZREVRANGE", "z_multi", "1.0", "2.0"});
3650
0
  DoRedisTestExpectError(__LINE__, {"ZREVRANGE", "1", "2"});
3651
0
  DoRedisTestExpectError(__LINE__, {"ZREVRANGE", "z_multi", "0", "(2"});
3652
0
  DoRedisTestExpectError(__LINE__, {"ZREVRANGE", "z_multi", "(0", "2"});
3653
0
  DoRedisTestExpectError(__LINE__, {"ZREVRANGE", "z_multi", "(0", "(2"});
3654
3655
  // Test key with wrong type.
3656
0
  DoRedisTestOk(__LINE__, {"SET", "s_key", "s_val"});
3657
0
  DoRedisTestExpectError(__LINE__, {"ZREVRANGE", "s_key", "1", "2"});
3658
3659
0
  SyncClient();
3660
0
  VerifyCallbacks();
3661
0
}
3662
3663
0
TEST_F(TestRedisService, TestZRange) {
3664
  // The default value is true, but we explicitly set this here for clarity.
3665
0
  FLAGS_emulate_redis_responses = true;
3666
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi", "0", "v0", "0", "v1", "0", "v2",
3667
0
      "1", "v3", "1", "v4", "1", "v5"}, 6);
3668
0
  SyncClient();
3669
3670
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "0", "5"}, {"v0", "v1", "v2", "v3", "v4", "v5"});
3671
0
  DoRedisTestScoreValueArray(__LINE__, {"ZRANGE", "z_multi", "0", "-1", "WITHSCORES"},
3672
0
                             {0, 0, 0, 1, 1, 1},
3673
0
                             {"v0", "v1", "v2", "v3", "v4", "v5"});
3674
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "0", "1"}, {"v0", "v1"});
3675
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "2", "3"}, {"v2", "v3"});
3676
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "6", "7"}, {});
3677
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "0", "-1"},
3678
0
                   {"v0", "v1", "v2", "v3", "v4", "v5"});
3679
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "-2", "-1"}, {"v4", "v5"});
3680
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "-3", "-2"}, {"v3", "v4"});
3681
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "-3", "5"}, {"v3", "v4", "v5"});
3682
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "0", "100"},
3683
0
                   {"v0", "v1", "v2", "v3", "v4", "v5"});
3684
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "-100", "100"},
3685
0
                   {"v0", "v1", "v2", "v3", "v4", "v5"});
3686
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "10", "100"}, {});
3687
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_multi", "-100", "-10"}, {});
3688
3689
  // Test empty key.
3690
0
  DoRedisTestArray(__LINE__, {"ZRANGE", "z_key", "0", "1"}, {});
3691
3692
0
  DoRedisTestExpectError(__LINE__, {"ZRANGE", "z_multi", "0"});
3693
0
  DoRedisTestExpectError(__LINE__, {"ZRANGE", "z_multi", "1", "2", "3"});
3694
0
  DoRedisTestExpectError(__LINE__, {"ZRANGE", "z_multi", "1", "2", "WITHSCORES", "1"});
3695
0
  DoRedisTestExpectError(__LINE__, {"ZRANGE", "z_multi", "1.0", "2.0"});
3696
0
  DoRedisTestExpectError(__LINE__, {"ZRANGE", "1", "2"});
3697
3698
  // Test key with wrong type.
3699
0
  DoRedisTestOk(__LINE__, {"SET", "s_key", "s_val"});
3700
0
  DoRedisTestExpectError(__LINE__, {"ZRANGE", "s_key", "1", "2"});
3701
3702
0
  SyncClient();
3703
0
  VerifyCallbacks();
3704
0
}
3705
3706
0
TEST_F(TestRedisService, TestZScore) {
3707
  // The default value is true, but we explicitly set this here for clarity.
3708
0
  FLAGS_emulate_redis_responses = true;
3709
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi", "0", "v0", "0", "v0_copy", "1", "v1",
3710
0
      "2", "v2", "3", "v3", "4.5", "v4"}, 6);
3711
0
  SyncClient();
3712
3713
0
  DoRedisTestDouble(__LINE__, {"ZSCORE", "z_multi", "v0"}, 0.0);
3714
0
  DoRedisTestDouble(__LINE__, {"ZSCORE", "z_multi", "v0_copy"}, 0.0);
3715
0
  DoRedisTestDouble(__LINE__, {"ZSCORE", "z_multi", "v1"}, 1.0);
3716
0
  DoRedisTestDouble(__LINE__, {"ZSCORE", "z_multi", "v2"}, 2.0);
3717
0
  DoRedisTestDouble(__LINE__, {"ZSCORE", "z_multi", "v3"}, 3.0);
3718
0
  DoRedisTestDouble(__LINE__, {"ZSCORE", "z_multi", "v4"}, 4.5);
3719
3720
0
  DoRedisTestNull(__LINE__, {"ZSCORE", "z_no_exist", "v4"});
3721
3722
0
  SyncClient();
3723
0
  VerifyCallbacks();
3724
0
}
3725
3726
0
TEST_F(TestRedisService, TestTimeSeriesTTL) {
3727
0
  int64_t ttl_sec = 10;
3728
0
  TestTSTtl("EXPIRE_IN", ttl_sec, ttl_sec, "test_expire_in");
3729
0
  int64_t curr_time_sec = GetCurrentTimeMicros() / MonoTime::kMicrosecondsPerSecond;
3730
0
  TestTSTtl("EXPIRE_AT", ttl_sec, curr_time_sec + ttl_sec, "test_expire_at");
3731
3732
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "test_expire_in", "10", "v1", "EXPIRE_IN",
3733
0
      std::to_string(kRedisMinTtlSetExSeconds - 1)});
3734
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "test_expire_in", "10", "v1", "EXPIRE_IN",
3735
0
      std::to_string(kRedisMaxTtlSeconds + 1)});
3736
3737
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "test_expire_at", "10", "v1", "EXPIRE_AT",
3738
0
      std::to_string(curr_time_sec - 10)});
3739
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "test_expire_at", "10", "v1", "expire_at",
3740
0
      std::to_string(curr_time_sec - 10)});
3741
3742
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "test_expire_at", "10", "v1", "EXPIRE_AT",
3743
0
      std::to_string(curr_time_sec + kRedisMinTtlSetExSeconds - 1)});
3744
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "test_expire_at", "10", "v1", "expire_at",
3745
0
      std::to_string(curr_time_sec + kRedisMinTtlSetExSeconds - 1)});
3746
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "test_expire_at", "10", "v1", "exPiRe_aT",
3747
0
                                    std::to_string(curr_time_sec + kRedisMinTtlSetExSeconds - 1)});
3748
3749
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "test_expire_at", "10", "v1", "EXPIRE_IN",
3750
0
      std::to_string(curr_time_sec + kRedisMaxTtlSeconds + 1)});
3751
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "test_expire_at", "10", "v1", "expire_in",
3752
0
      std::to_string(curr_time_sec + kRedisMaxTtlSeconds + 1)});
3753
0
  DoRedisTestExpectError(__LINE__, {"TSADD", "test_expire_at", "10", "v1", "eXpIrE_In",
3754
0
                                    std::to_string(curr_time_sec + kRedisMaxTtlSeconds + 1)});
3755
0
}
3756
3757
0
TEST_F(TestRedisService, TestTsCard) {
3758
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
3759
0
      "-50", "v1",
3760
0
      "-40", "v2",
3761
0
      "-30", "v3",
3762
0
      "-20", "v4",
3763
0
      "-10", "v5",
3764
0
      "10", "v6",
3765
0
      "20", "v7",
3766
0
      "30", "v8",
3767
0
      "40", "v9",
3768
0
      "50", "v10",
3769
0
  });
3770
3771
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key1",
3772
0
      "10", "v6",
3773
0
      "20", "v7",
3774
0
      "30", "v8",
3775
0
      "40", "v9",
3776
0
      "50", "v10",
3777
0
  });
3778
3779
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key2", "10", "v6"});
3780
0
  SyncClient();
3781
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key2", "11", "v7", "EXPIRE_IN", "10"});
3782
0
  SyncClient();
3783
3784
0
  DoRedisTestInt(__LINE__, {"TSCARD", "ts_key"}, 10);
3785
0
  SyncClient();
3786
0
  DoRedisTestInt(__LINE__, {"TSCARD", "ts_key1"}, 5);
3787
0
  SyncClient();
3788
0
  DoRedisTestInt(__LINE__, {"TSCARD", "ts_key2"}, 2);
3789
0
  SyncClient();
3790
0
  DoRedisTestInt(__LINE__, {"TSCARD", "invalid_key"}, 0);
3791
0
  SyncClient();
3792
3793
  // After TTL expiry.
3794
0
  std::this_thread::sleep_for(std::chrono::seconds(11));
3795
0
  DoRedisTestInt(__LINE__, {"TSCARD", "ts_key2"}, 1);
3796
3797
  // Test errors.
3798
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi", "0", "v0", "0", "v1", "0", "v2",
3799
0
      "1", "v3", "1", "v4", "1", "v5"}, 6);
3800
0
  DoRedisTestExpectError(__LINE__, {"TSCARD", "z_multi"}); // incorrect type.
3801
3802
0
  SyncClient();
3803
0
  VerifyCallbacks();
3804
0
}
3805
3806
0
TEST_F(TestRedisService, TestTsLastN) {
3807
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
3808
0
      "-50", "v1",
3809
0
      "-40", "v2",
3810
0
      "-30", "v3",
3811
0
      "-20", "v4",
3812
0
      "-10", "v5",
3813
0
      "10", "v6",
3814
0
      "20", "v7",
3815
0
      "30", "v8",
3816
0
      "40", "v9",
3817
0
      "50", "v10",
3818
0
  });
3819
3820
0
  SyncClient();
3821
0
  DoRedisTestArray(__LINE__, {"TSLASTN", "ts_key", "5"},
3822
0
                   {"10", "v6", "20", "v7", "30", "v8", "40", "v9", "50", "v10"});
3823
0
  DoRedisTestArray(__LINE__, {"TSLASTN", "ts_key", "4"},
3824
0
                   {"20", "v7", "30", "v8", "40", "v9", "50", "v10"});
3825
0
  DoRedisTestArray(__LINE__, {"TSLASTN", "ts_key", "3"},
3826
0
                   {"30", "v8", "40", "v9", "50", "v10"});
3827
0
  DoRedisTestArray(__LINE__, {"TSLASTN", "ts_key", "2"},
3828
0
                   {"40", "v9", "50", "v10"});
3829
0
  DoRedisTestArray(__LINE__, {"TSLASTN", "ts_key", "10"},
3830
0
                   {"-50", "v1", "-40", "v2", "-30", "v3", "-20", "v4", "-10", "v5", "10", "v6",
3831
0
                       "20", "v7", "30", "v8", "40", "v9", "50", "v10"});
3832
0
  DoRedisTestArray(__LINE__, {"TSLASTN", "ts_key", "20"},
3833
0
                   {"-50", "v1", "-40", "v2", "-30", "v3", "-20", "v4", "-10", "v5", "10", "v6",
3834
0
                       "20", "v7", "30", "v8", "40", "v9", "50", "v10"});
3835
0
  DoRedisTestArray(__LINE__, {"TSLASTN", "ts_key",
3836
0
                       std::to_string(std::numeric_limits<int32>::max())},
3837
0
                   {"-50", "v1", "-40", "v2", "-30", "v3", "-20", "v4", "-10", "v5", "10", "v6",
3838
0
                       "20", "v7", "30", "v8", "40", "v9", "50", "v10"});
3839
3840
0
  DoRedisTestExpectError(__LINE__, {"TSLASTN", "ts_key", "abc"});
3841
0
  DoRedisTestExpectError(__LINE__, {"TSLASTN", "ts_key", "3.0"});
3842
0
  DoRedisTestExpectError(__LINE__, {"TSLASTN", "ts_key", "999999999999"}); // out of bounds.
3843
0
  DoRedisTestExpectError(__LINE__, {"TSLASTN", "ts_key", "-999999999999"}); // out of bounds.
3844
0
  DoRedisTestExpectError(__LINE__, {"TSLASTN", "ts_key", "0"}); // out of bounds.
3845
0
  DoRedisTestExpectError(__LINE__, {"TSLASTN", "ts_key", "-1"}); // out of bounds.
3846
0
  DoRedisTestNull(__LINE__, {"TSLASTN", "randomkey", "10"}); // invalid key.
3847
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_multi", "0", "v0", "0", "v1", "0", "v2",
3848
0
      "1", "v3", "1", "v4", "1", "v5"}, 6);
3849
0
  DoRedisTestExpectError(__LINE__, {"TSLASTN", "z_multi", "10"}); // incorrect type.
3850
0
  SyncClient();
3851
0
  VerifyCallbacks();
3852
0
}
3853
3854
0
TEST_F(TestRedisService, TestTsRangeByTime) {
3855
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
3856
0
      "-50", "v1",
3857
0
      "-40", "v2",
3858
0
      "-30", "v3",
3859
0
      "-20", "v4",
3860
0
      "-10", "v5",
3861
0
      "10", "v6",
3862
0
      "20", "v7",
3863
0
      "30", "v8",
3864
0
      "40", "v9",
3865
0
      "50", "v10",
3866
0
  });
3867
3868
0
  SyncClient();
3869
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-35", "25"},
3870
0
      {"-30", "v3", "-20", "v4", "-10", "v5", "10", "v6", "20", "v7"});
3871
3872
  // Overwrite and test.
3873
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
3874
0
      "-50", "v11",
3875
0
      "-40", "v22",
3876
0
      "-30", "v33",
3877
0
      "-20", "v44",
3878
0
      "-10", "v55",
3879
0
      "10", "v66",
3880
0
      "20", "v77",
3881
0
      "30", "v88",
3882
0
      "40", "v99",
3883
0
      "50", "v110",
3884
0
  });
3885
3886
0
  SyncClient();
3887
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-55", "-10"},
3888
0
      {"-50", "v11", "-40", "v22", "-30", "v33", "-20", "v44", "-10", "v55"});
3889
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-20", "55"},
3890
0
      {"-20", "v44", "-10", "v55", "10", "v66", "20", "v77", "30", "v88", "40", "v99",
3891
0
          "50", "v110"});
3892
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-55", "55"},
3893
0
      {"-50", "v11", "-40", "v22", "-30", "v33", "-20", "v44", "-10", "v55",
3894
0
          "10", "v66", "20", "v77", "30", "v88", "40", "v99", "50", "v110"});
3895
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-15", "-5"}, {"-10", "v55"});
3896
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "10"}, {"10", "v66"});
3897
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-10", "-10"}, {"-10", "v55"});
3898
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-57", "-55"}, {});
3899
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "55", "60"}, {});
3900
3901
  // Test with ttl.
3902
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
3903
0
      "-30", "v333",
3904
0
      "-10", "v555",
3905
0
      "20", "v777",
3906
0
      "30", "v888",
3907
0
      "50", "v1110",
3908
0
      "EXPIRE_IN", "5",
3909
0
  });
3910
0
  SyncClient();
3911
0
  std::this_thread::sleep_for(std::chrono::seconds(6));
3912
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-55", "-10"},
3913
0
      {"-50", "v11", "-40", "v22", "-20", "v44"});
3914
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-20", "55"},
3915
0
      {"-20", "v44", "10", "v66", "40", "v99"});
3916
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-55", "60"},
3917
0
      {"-50", "v11", "-40", "v22", "-20", "v44", "10", "v66", "40", "v99"});
3918
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-15", "-5"}, {});
3919
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "10"}, {"10", "v66"});
3920
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-25", "-15"}, {"-20", "v44"});
3921
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-5", "-15"}, {});
3922
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-45", "-55"}, {});
3923
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "45", "55"}, {});
3924
3925
  // Test exclusive ranges.
3926
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "(-20", "(40"}, {"10", "v66"});
3927
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "(-20", "(-20"}, {});
3928
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "(-20", "-10"}, {});
3929
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-10", "(10"}, {});
3930
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "(-50", "(-40"}, {});
3931
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-55", "(11"},
3932
0
      {"-50", "v11", "-40", "v22", "-20", "v44", "10", "v66"});
3933
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "(-50", "10"},
3934
0
      {"-40", "v22", "-20", "v44", "10", "v66"});
3935
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "(-51", "10"},
3936
0
      {"-50", "v11", "-40", "v22", "-20", "v44", "10", "v66"});
3937
3938
  // Test infinity.
3939
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-10", "+inf"},
3940
0
      {"10", "v66", "40", "v99"});
3941
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-inf", "10"},
3942
0
      {"-50", "v11", "-40", "v22", "-20", "v44", "10", "v66"});
3943
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-10", "(+inf"},
3944
0
      {"10", "v66", "40", "v99"});
3945
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "(-inf", "10"},
3946
0
      {"-50", "v11", "-40", "v22", "-20", "v44", "10", "v66"});
3947
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-inf", "+inf"},
3948
0
      {"-50", "v11", "-40", "v22", "-20", "v44", "10", "v66", "40", "v99"});
3949
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "(-inf", "(+inf"},
3950
0
      {"-50", "v11", "-40", "v22", "-20", "v44", "10", "v66", "40", "v99"});
3951
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "+inf", "-inf"}, {});
3952
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "+inf", "10"}, {});
3953
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "+inf", "+inf"}, {});
3954
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "-inf"}, {});
3955
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-inf", "-inf"}, {});
3956
0
  SyncClient();
3957
3958
  // Test infinity with int64 min, max.
3959
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_inf",
3960
0
      int64Min_, "v1",
3961
0
      "-10", "v2",
3962
0
      "10", "v3",
3963
0
      int64Max_, "v4",
3964
0
  });
3965
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", "-inf", "+inf"},
3966
0
      {int64Min_, "v1", "-10", "v2", "10", "v3", int64Max_, "v4"});
3967
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", "(-inf", "(+inf"},
3968
0
      {int64Min_, "v1", "-10", "v2", "10", "v3", int64Max_, "v4"});
3969
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", "-inf", "-inf"},
3970
0
      {});
3971
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", "+inf", "+inf"},
3972
0
      {});
3973
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", "-10", "(+inf"},
3974
0
      {"-10", "v2", "10", "v3", int64Max_, "v4"});
3975
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", "-10", "+inf"},
3976
0
      {"-10", "v2", "10", "v3", int64Max_, "v4"});
3977
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", "(-inf", "10"},
3978
0
      {int64Min_, "v1", "-10", "v2", "10", "v3"});
3979
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", "-inf", "10"},
3980
0
      {int64Min_, "v1", "-10", "v2", "10", "v3"});
3981
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", int64Min_, int64Max_},
3982
0
      {int64Min_, "v1", "-10", "v2", "10", "v3", int64Max_, "v4"});
3983
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", int64MaxExclusive_, int64Max_},
3984
0
      {});
3985
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", int64MaxExclusive_, int64MaxExclusive_},
3986
0
      {});
3987
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", int64Max_, int64MaxExclusive_},
3988
0
      {});
3989
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", int64MinExclusive_, int64MinExclusive_},
3990
0
      {});
3991
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", int64MinExclusive_, int64Min_},
3992
0
      {});
3993
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", int64Min_, int64MinExclusive_},
3994
0
      {});
3995
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", int64Min_, int64Min_},
3996
0
      {int64Min_, "v1"});
3997
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_inf", int64Max_, int64Max_},
3998
0
      {int64Max_, "v4"});
3999
4000
  // Test invalid requests.
4001
0
  DoRedisTestExpectError(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "20", "30"});
4002
0
  DoRedisTestExpectError(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "abc"});
4003
0
  DoRedisTestExpectError(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "20.1"});
4004
0
  DoRedisTestOk(__LINE__, {"HMSET", "map_key",
4005
0
      "1", "v100",
4006
0
      "2", "v200",
4007
0
      "3", "v300",
4008
0
      "4", "v400",
4009
0
      "5", "v500",
4010
0
  });
4011
0
  DoRedisTestOk(__LINE__, {"HMSET", "map_key",
4012
0
      "6", "v600"
4013
0
  });
4014
0
  DoRedisTestOk(__LINE__, {"SET", "key", "value"});
4015
0
  SyncClient();
4016
0
  DoRedisTestExpectError(__LINE__, {"TSRANGEBYTIME", "map_key", "1", "5"});
4017
0
  DoRedisTestExpectError(__LINE__, {"TSRANGEBYTIME", "key"});
4018
4019
0
  SyncClient();
4020
0
  VerifyCallbacks();
4021
0
}
4022
4023
0
TEST_F(TestRedisService, TestTsRevRangeByTime) {
4024
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
4025
0
      "-50", "v1",
4026
0
      "-40", "v2",
4027
0
      "-30", "v3",
4028
0
      "-20", "v4",
4029
0
      "-10", "v5",
4030
0
      "10", "v6",
4031
0
      "20", "v7",
4032
0
      "30", "v8",
4033
0
      "40", "v9",
4034
0
      "50", "v10",
4035
0
  });
4036
4037
0
  SyncClient();
4038
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-35", "25"},
4039
0
                   {"20", "v7", "10", "v6", "-10", "v5", "-20", "v4", "-30", "v3"});
4040
4041
  // Overwrite and test.
4042
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
4043
0
      "-50", "v11",
4044
0
      "-40", "v22",
4045
0
      "-30", "v33",
4046
0
      "-20", "v44",
4047
0
      "-10", "v55",
4048
0
      "10", "v66",
4049
0
      "20", "v77",
4050
0
      "30", "v88",
4051
0
      "40", "v99",
4052
0
      "50", "v110",
4053
0
  });
4054
4055
0
  SyncClient();
4056
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-55", "-10"},
4057
0
                   {"-10", "v55", "-20", "v44", "-30", "v33", "-40", "v22", "-50", "v11"});
4058
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-20", "55"},
4059
0
                   {"50", "v110", "40", "v99", "30", "v88", "20", "v77", "10", "v66", "-10",
4060
0
                    "v55", "-20", "v44"});
4061
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-55", "55"},
4062
0
                   {"50", "v110", "40", "v99", "30", "v88", "20", "v77", "10", "v66", "-10",
4063
0
                    "v55", "-20", "v44", "-30", "v33", "-40", "v22", "-50", "v11"});
4064
4065
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-15", "-5"}, {"-10", "v55"});
4066
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "10"}, {"10", "v66"});
4067
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-10", "-10"}, {"-10", "v55"});
4068
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-57", "-55"}, {});
4069
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "55", "60"}, {});
4070
4071
  // Test with limit.
4072
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-55", "-10", "LIMIT", "1"},
4073
0
                   {"-10", "v55"});
4074
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-55", "-10", "LIMIT", "2"},
4075
0
                   {"-10", "v55", "-20", "v44"});
4076
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-20", "55", "LIMIT", "4"},
4077
0
                   {"50", "v110", "40", "v99", "30", "v88", "20", "v77"});
4078
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-55", "55", "LIMIT", "5"},
4079
0
                   {"50", "v110", "40", "v99", "30", "v88", "20", "v77", "10", "v66"});
4080
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "+inf", "LIMIT", "1"},
4081
0
                   {"50", "v110"});
4082
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "(50", "LIMIT", "1"},
4083
0
                   {"40", "v99"});
4084
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "(40", "LIMIT", "1"},
4085
0
                   {"30", "v88"});
4086
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "(30", "LIMIT", "1"},
4087
0
                   {"20", "v77"});
4088
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "(20", "LIMIT", "1"},
4089
0
                   {"10", "v66"});
4090
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "(10", "LIMIT", "1"},
4091
0
                   {"-10", "v55"});
4092
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "(-10", "LIMIT", "1"},
4093
0
                   {"-20", "v44"});
4094
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "(-20", "LIMIT", "1"},
4095
0
                   {"-30", "v33"});
4096
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "(-30", "LIMIT", "1"},
4097
0
                   {"-40", "v22"});
4098
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "(-40", "LIMIT", "1"},
4099
0
                   {"-50", "v11"});
4100
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "(-50", "LIMIT", "1"},
4101
0
                   {});
4102
4103
  // Test with a limit larger than the total number of elements.
4104
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-55", "-10", "LIMIT", "300"},
4105
0
                   {"-10", "v55", "-20", "v44", "-30", "v33", "-40", "v22", "-50", "v11"});
4106
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-20", "55", "LIMIT", "121"},
4107
0
                   {"50", "v110", "40", "v99", "30", "v88", "20", "v77", "10", "v66", "-10",
4108
0
                    "v55", "-20", "v44"});
4109
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-55", "55", "LIMIT", "34"},
4110
0
                   {"50", "v110", "40", "v99", "30", "v88", "20", "v77", "10", "v66", "-10",
4111
0
                    "v55", "-20", "v44", "-30", "v33", "-40", "v22", "-50", "v11"});
4112
4113
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-15", "-5"}, {"-10", "v55"});
4114
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "10"}, {"10", "v66"});
4115
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-10", "-10"}, {"-10", "v55"});
4116
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-57", "-55"}, {});
4117
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "55", "60"}, {});
4118
4119
  // Test with ttl.
4120
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
4121
0
      "-30", "v333",
4122
0
      "-10", "v555",
4123
0
      "20", "v777",
4124
0
      "30", "v888",
4125
0
      "50", "v1110",
4126
0
      "EXPIRE_IN", "5",
4127
0
  });
4128
0
  SyncClient();
4129
0
  std::this_thread::sleep_for(std::chrono::seconds(6));
4130
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-55", "-10"},
4131
0
                   {"-20", "v44", "-40", "v22", "-50", "v11"});
4132
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-20", "55"},
4133
0
                   {"40", "v99", "10", "v66", "-20", "v44"});
4134
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-55", "60"},
4135
0
                   {"40", "v99", "10", "v66", "-20", "v44", "-40", "v22", "-50", "v11"});
4136
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-15", "-5"}, {});
4137
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "10"}, {"10", "v66"});
4138
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-25", "-15"}, {"-20", "v44"});
4139
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-5", "-15"}, {});
4140
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-45", "-55"}, {});
4141
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "45", "55"}, {});
4142
4143
  // Test exclusive ranges.
4144
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "(-20", "(40"}, {"10", "v66"});
4145
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "(-20", "(-20"}, {});
4146
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "(-20", "-10"}, {});
4147
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-10", "(10"}, {});
4148
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "(-50", "(-40"}, {});
4149
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-55", "(11"},
4150
0
                   {"10", "v66", "-20", "v44", "-40", "v22", "-50", "v11"});
4151
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "(-50", "10"},
4152
0
                   {"10", "v66", "-20", "v44", "-40", "v22"});
4153
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "(-51", "10"},
4154
0
                   {"10", "v66", "-20", "v44", "-40", "v22", "-50", "v11"});
4155
4156
  // Test infinity.
4157
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-10", "+inf"},
4158
0
                   {"40", "v99", "10", "v66"});
4159
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "10"},
4160
0
                   {"10", "v66", "-20", "v44", "-40", "v22", "-50", "v11"});
4161
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-10", "(+inf"},
4162
0
                   {"40", "v99", "10", "v66"});
4163
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "(-inf", "10"},
4164
0
                   {"10", "v66", "-20", "v44", "-40", "v22", "-50", "v11"});
4165
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "+inf"},
4166
0
                   {"40", "v99", "10", "v66", "-20", "v44", "-40", "v22", "-50", "v11"});
4167
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "(-inf", "(+inf"},
4168
0
                   {"40", "v99", "10", "v66", "-20", "v44", "-40", "v22", "-50", "v11"});
4169
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "+inf", "-inf"}, {});
4170
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "+inf", "10"}, {});
4171
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "+inf", "+inf"}, {});
4172
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "-inf"}, {});
4173
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "-inf", "-inf"}, {});
4174
0
  SyncClient();
4175
4176
  // Test infinity with int64 min, max.
4177
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_inf",
4178
0
      int64Min_, "v1",
4179
0
      "-10", "v2",
4180
0
      "10", "v3",
4181
0
      int64Max_, "v4",
4182
0
  });
4183
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", "-inf", "+inf"},
4184
0
                   {int64Max_, "v4", "10", "v3", "-10", "v2", int64Min_, "v1"});
4185
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", "(-inf", "(+inf"},
4186
0
                   {int64Max_, "v4", "10", "v3", "-10", "v2", int64Min_, "v1"});
4187
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", "-inf", "-inf"},
4188
0
                   {});
4189
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", "+inf", "+inf"},
4190
0
                   {});
4191
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", "-10", "(+inf"},
4192
0
                   {int64Max_, "v4", "10", "v3", "-10", "v2"});
4193
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", "-10", "+inf"},
4194
0
                   {int64Max_, "v4", "10", "v3", "-10", "v2"});
4195
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", "(-inf", "10"},
4196
0
                   {"10", "v3", "-10", "v2", int64Min_, "v1"});
4197
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", "-inf", "10"},
4198
0
                   {"10", "v3", "-10", "v2", int64Min_, "v1"});
4199
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", int64Min_, int64Max_},
4200
0
                   {int64Max_, "v4", "10", "v3", "-10", "v2", int64Min_, "v1"});
4201
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", int64MaxExclusive_, int64Max_},
4202
0
                   {});
4203
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", int64MaxExclusive_, int64MaxExclusive_},
4204
0
                   {});
4205
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", int64Max_, int64MaxExclusive_},
4206
0
                   {});
4207
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", int64MinExclusive_, int64MinExclusive_},
4208
0
                   {});
4209
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", int64MinExclusive_, int64Min_},
4210
0
                   {});
4211
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", int64Min_, int64MinExclusive_},
4212
0
                   {} );
4213
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", int64Min_, int64Min_},
4214
0
                   {int64Min_, "v1"});
4215
0
  DoRedisTestArray(__LINE__, {"TSREVRANGEBYTIME", "ts_inf", int64Max_, int64Max_},
4216
0
                   {int64Max_, "v4"});
4217
4218
  // Test invalid requests.
4219
0
  DoRedisTestExpectError(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "20", "30"});
4220
0
  DoRedisTestExpectError(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "abc"});
4221
0
  DoRedisTestExpectError(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "20.1"});
4222
0
  DoRedisTestExpectError(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "20", "LIMIT"});
4223
0
  DoRedisTestExpectError(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "20", "LIMIT", "BC"});
4224
0
  DoRedisTestExpectError(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "20", "LIMIT", "1.3"});
4225
0
  DoRedisTestExpectError(__LINE__, {"TSREVRANGEBYTIME", "ts_key", "10", "20", "SOMETHING", "3"});
4226
4227
0
  DoRedisTestOk(__LINE__, {"HMSET", "map_key",
4228
0
      "1", "v100",
4229
0
      "2", "v200",
4230
0
      "3", "v300",
4231
0
      "4", "v400",
4232
0
      "5", "v500",
4233
0
  });
4234
0
  DoRedisTestOk(__LINE__, {"HMSET", "map_key",
4235
0
      "6", "v600"
4236
0
  });
4237
0
  DoRedisTestOk(__LINE__, {"SET", "key", "value"});
4238
0
  SyncClient();
4239
0
  DoRedisTestExpectError(__LINE__, {"TSREVRANGEBYTIME", "map_key", "1", "5"});
4240
0
  DoRedisTestExpectError(__LINE__, {"TSREVRANGEBYTIME", "key"});
4241
4242
0
  SyncClient();
4243
0
  VerifyCallbacks();
4244
0
}
4245
4246
0
TEST_F(TestRedisService, TestTsRem) {
4247
4248
  // Try some deletes before inserting any data.
4249
0
  DoRedisTestOk(__LINE__, {"TSREM", "invalid_key", "20", "40", "70", "90"});
4250
4251
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
4252
0
      "10", "v1",
4253
0
      "20", "v2",
4254
0
      "30", "v3",
4255
0
      "40", "v4",
4256
0
      "50", "v5",
4257
0
      "60", "v6",
4258
0
      "70", "v7",
4259
0
      "80", "v8",
4260
0
      "90", "v9",
4261
0
      "100", "v10",
4262
0
  });
4263
4264
  // Try some deletes.
4265
0
  SyncClient();
4266
0
  DoRedisTestOk(__LINE__, {"TSREM", "ts_key", "20", "40", "70", "90"});
4267
0
  SyncClient();
4268
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "100"},
4269
0
      {"10", "v1", "30", "v3", "50", "v5", "60", "v6", "80", "v8", "100", "v10"});
4270
0
  DoRedisTestOk(__LINE__, {"TSREM", "ts_key", "30", "60", "70", "80", "90"});
4271
0
  SyncClient();
4272
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "100"},
4273
0
      {"10", "v1", "50", "v5", "100", "v10"});
4274
4275
  // Now add some data and try some more deletes.
4276
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
4277
0
      "25", "v25",
4278
0
      "35", "v35",
4279
0
      "45", "v45",
4280
0
      "55", "v55",
4281
0
      "75", "v75",
4282
0
      "85", "v85",
4283
0
      "95", "v95",
4284
0
  });
4285
0
  SyncClient();
4286
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "100"},
4287
0
      {"10", "v1", "25", "v25", "35", "v35", "45", "v45", "50", "v5", "55", "v55",
4288
0
          "75", "v75", "85", "v85", "95", "v95", "100", "v10"});
4289
0
  DoRedisTestOk(__LINE__, {"TSREM", "ts_key", "10", "25", "30", "45", "50", "65", "70", "85",
4290
0
      "90"});
4291
0
  SyncClient();
4292
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "100"},
4293
0
      {"35", "v35", "55", "v55", "75", "v75", "95", "v95", "100", "v10"});
4294
4295
  // Delete top level, then add some values and verify.
4296
0
  DoRedisTestInt(__LINE__, {"DEL", "ts_key"}, 1);
4297
0
  SyncClient();
4298
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key",
4299
0
      "22", "v22",
4300
0
      "33", "v33",
4301
0
      "44", "v44",
4302
0
      "55", "v55",
4303
0
      "77", "v77",
4304
0
      "88", "v88",
4305
0
      "99", "v99",
4306
0
  });
4307
0
  SyncClient();
4308
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "10", "100"},
4309
0
      {"22", "v22", "33", "v33", "44", "v44", "55", "v55", "77", "v77", "88", "v88",
4310
0
          "99", "v99"});
4311
4312
  // Now try invalid commands.
4313
0
  DoRedisTestExpectError(__LINE__, {"TSREM", "ts_key"}); // Not enough arguments.
4314
0
  DoRedisTestExpectError(__LINE__, {"TSREM", "ts_key", "v1", "10"}); // wrong type for timestamp.
4315
0
  DoRedisTestExpectError(__LINE__, {"TSREM", "ts_key", "1.0", "10"}); // wrong type for timestamp.
4316
0
  DoRedisTestExpectError(__LINE__, {"HDEL", "ts_key", "22"}); // wrong delete type.
4317
0
  DoRedisTestOk(__LINE__, {"HMSET", "hkey", "10", "v1", "20", "v2"});
4318
0
  DoRedisTestExpectError(__LINE__, {"TSREM", "hkey", "10", "20"}); // wrong delete type.
4319
4320
0
  SyncClient();
4321
0
  VerifyCallbacks();
4322
0
}
4323
4324
0
TEST_F(TestRedisService, TestOverwrites) {
4325
  // The default value is true, but we explicitly set this here for clarity.
4326
0
  FLAGS_emulate_redis_responses = true;
4327
4328
  // Test Upsert.
4329
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "subkey1", "42"}, 1);
4330
0
  DoRedisTestBulkString(__LINE__, {"HGET", "map_key", "subkey1"}, "42");
4331
  // Overwrite the same key. Using Set.
4332
0
  DoRedisTestOk(__LINE__, {"SET", "map_key", "new_value"});
4333
0
  DoRedisTestBulkString(__LINE__, {"GET", "map_key"}, "new_value");
4334
0
  SyncClient();
4335
4336
  // Test NX.
4337
0
  DoRedisTestOk(__LINE__, {"SET", "key", "value1", "NX"});
4338
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "value1");
4339
0
  DoRedisTestNull(__LINE__, {"SET", "key", "value2", "NX"});
4340
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "value1");
4341
4342
  // Test XX.
4343
0
  DoRedisTestOk(__LINE__, {"SET", "key", "value2", "XX"});
4344
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "value2");
4345
0
  DoRedisTestOk(__LINE__, {"SET", "key", "value3", "XX"});
4346
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "value3");
4347
0
  DoRedisTestNull(__LINE__, {"SET", "unknown_key", "value", "XX"});
4348
4349
0
  SyncClient();
4350
0
  VerifyCallbacks();
4351
0
}
4352
4353
0
TEST_F(TestRedisService, TestSetNX) {
4354
  // Test Insert.
4355
0
  DoRedisTestInt(__LINE__, {"SETNX", "key1", "value1"}, 1);
4356
0
  DoRedisTestBulkString(__LINE__, {"GET", "key1"}, "value1");
4357
  // Overwrite the same key. Using SetNX.
4358
0
  DoRedisTestInt(__LINE__, {"SETNX", "key1", "new_value"}, 0);
4359
0
  DoRedisTestBulkString(__LINE__, {"GET", "key1"}, "value1");
4360
  // Test a new key.
4361
0
  DoRedisTestInt(__LINE__, {"SETNX", "key2", "value2"}, 1);
4362
0
  DoRedisTestBulkString(__LINE__, {"GET", "key2"}, "value2");
4363
4364
  // Test `SET key value NX`.
4365
0
  DoRedisTestOk(__LINE__, {"SET", "key3", "value3", "NX"});
4366
0
  DoRedisTestBulkString(__LINE__, {"GET", "key3"}, "value3");
4367
0
  DoRedisTestNull(__LINE__, {"SET", "key3", "new_value", "NX"});
4368
0
  DoRedisTestBulkString(__LINE__, {"GET", "key3"}, "value3");
4369
4370
  // Test `SET key value NX` after SETNX.
4371
0
  DoRedisTestNull(__LINE__, {"SET", "key1", "new_value", "NX"});
4372
0
  DoRedisTestBulkString(__LINE__, {"GET", "key1"}, "value1");
4373
4374
  // Test SETNX after `SET key value NX`.
4375
0
  DoRedisTestInt(__LINE__, {"SETNX", "key3", "new_value"}, 0);
4376
0
  DoRedisTestBulkString(__LINE__, {"GET", "key3"}, "value3");
4377
  // Test a new key.
4378
0
  DoRedisTestInt(__LINE__, {"SETNX", "key4", "value4"}, 1);
4379
0
  DoRedisTestBulkString(__LINE__, {"GET", "key4"}, "value4");
4380
4381
  // Now try invalid commands.
4382
0
  DoRedisTestExpectError(__LINE__, {"SETNX"}); // Not enough arguments.
4383
0
  DoRedisTestExpectError(__LINE__, {"SETNX", "key"}); // Not enough arguments.
4384
0
  DoRedisTestExpectError(__LINE__, {"SETNX", "key", "score", "value"}); // Too many arguments.
4385
0
  DoRedisTestExpectError(__LINE__, {"SETNX", "key", "score1", "value1", "score2",
4386
0
                                    "value2"}); // Too many arguments.
4387
4388
0
  SyncClient();
4389
0
  VerifyCallbacks();
4390
0
}
4391
4392
0
TEST_F(TestRedisService, TestAdditionalCommands) {
4393
4394
  // The default value is true, but we explicitly set this here for clarity.
4395
0
  FLAGS_emulate_redis_responses = true;
4396
4397
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "subkey1", "42"}, 1);
4398
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "subkey2", "12"}, 1);
4399
4400
0
  SyncClient();
4401
4402
  // With emulate_redis_responses flag = true, we expect an int response 0 because the subkey
4403
  // already existed. If flag is false, we'll get an OK response, which is tested later.
4404
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "subkey1", "41"}, 0);
4405
4406
0
  SyncClient();
4407
4408
0
  DoRedisTestBulkString(__LINE__, {"HGET", "map_key", "subkey1"}, "41");
4409
4410
0
  DoRedisTestResultsArray(
4411
0
      __LINE__, {"HMGET", "map_key", "subkey1", "subkey3", "subkey2"},
4412
0
      {RedisReply(RedisReplyType::kString, "41"), RedisReply(),
4413
0
       RedisReply(RedisReplyType::kString, "12")});
4414
4415
0
  DoRedisTestArray(__LINE__, {"HGETALL", "map_key"}, {"subkey1", "41", "subkey2", "12"});
4416
4417
0
  DoRedisTestOk(__LINE__, {"SET", "key1", "30"});
4418
4419
0
  SyncClient();
4420
4421
  // Should be error due to wrong type.
4422
0
  DoRedisTestExpectError(__LINE__, {"HGET", "key1", "subkey1"});
4423
4424
0
  DoRedisTestBulkString(__LINE__, {"GETSET", "key1", "val1"}, "30");
4425
0
  DoRedisTestNull(__LINE__, {"GETSET", "non_existent", "val2"});
4426
4427
0
  SyncClient();
4428
4429
0
  DoRedisTestBulkString(__LINE__, {"GET", "key1"}, "val1");
4430
0
  DoRedisTestInt(__LINE__, {"APPEND", "key1", "extra1"}, 10);
4431
4432
0
  SyncClient();
4433
4434
0
  DoRedisTestBulkString(__LINE__, {"GET", "key1"}, "val1extra1");
4435
4436
0
  DoRedisTestNull(__LINE__, {"GET", "key2"});
4437
  // Deleting an empty key should return 0
4438
0
  DoRedisTestInt(__LINE__, {"DEL", "key2"}, 0);
4439
  // Appending to an empty key should work
4440
0
  DoRedisTestInt(__LINE__, {"APPEND", "key2", "val2"}, 4);
4441
4442
0
  SyncClient();
4443
4444
0
  DoRedisTestBulkString(__LINE__, {"GET", "key2"}, "val2");
4445
4446
0
  SyncClient();
4447
4448
0
  DoRedisTestInt(__LINE__, {"DEL", "key2"}, 1);
4449
4450
0
  SyncClient();
4451
4452
0
  DoRedisTestNull(__LINE__, {"GET", "key2"});
4453
0
  DoRedisTestInt(__LINE__, {"SETRANGE", "key1", "2", "xyz3"}, 10);
4454
0
  DoRedisTestInt(__LINE__, {"SETRANGE", "sr1", "2", "abcd"}, 6);
4455
0
  DoRedisTestBulkString(__LINE__, {"GET", "sr1"}, "\0\0abcd"s);
4456
4457
0
  SyncClient();
4458
4459
0
  DoRedisTestBulkString(__LINE__, {"GET", "key1"}, "vaxyz3tra1");
4460
0
  DoRedisTestOk(__LINE__, {"SET", "key3", "23"});
4461
4462
0
  SyncClient();
4463
4464
0
  DoRedisTestInt(__LINE__, {"INCR", "key3"}, 24);
4465
  // If no value is present, 0 is the default
4466
0
  DoRedisTestInt(__LINE__, {"INCR", "key4"}, 1);
4467
4468
0
  SyncClient();
4469
4470
0
  DoRedisTestBulkString(__LINE__, {"GET", "key3"}, "24");
4471
4472
0
  DoRedisTestInt(__LINE__, {"STRLEN", "key1"}, 10);
4473
0
  DoRedisTestInt(__LINE__, {"STRLEN", "key2"}, 0);
4474
0
  DoRedisTestInt(__LINE__, {"STRLEN", "key3"}, 2);
4475
4476
0
  DoRedisTestInt(__LINE__, {"EXISTS", "key1"}, 1);
4477
0
  DoRedisTestInt(__LINE__, {"EXISTS", "key2"}, 0);
4478
0
  DoRedisTestInt(__LINE__, {"EXISTS", "key3"}, 1);
4479
0
  DoRedisTestInt(__LINE__, {"EXISTS", "map_key"}, 1);
4480
0
  DoRedisTestBulkString(__LINE__, {"GETRANGE", "key1", "1", "-1"}, "axyz3tra1");
4481
0
  DoRedisTestBulkString(__LINE__, {"GETRANGE", "key5", "1", "4"}, "");
4482
0
  DoRedisTestBulkString(__LINE__, {"GETRANGE", "key1", "-12", "4"}, "vaxyz");
4483
4484
0
  DoRedisTestOk(__LINE__, {"HMSET", "map_key", "subkey5", "19", "subkey6", "14"});
4485
  // The last value for a duplicate key is picked up.
4486
0
  DoRedisTestOk(__LINE__, {"HMSET", "map_key", "hashkey1", "v1", "hashkey2", "v2",
4487
0
      "hashkey1", "v3"});
4488
4489
0
  SyncClient();
4490
4491
0
  DoRedisTestArray(__LINE__, {"HGETALL", "map_key"},
4492
0
      {"hashkey1", "v3", "hashkey2", "v2", "subkey1", "41", "subkey2", "12", "subkey5", "19",
4493
0
          "subkey6", "14"});
4494
0
  DoRedisTestArray(__LINE__, {"HKEYS", "map_key"},
4495
0
      {"hashkey1", "hashkey2", "subkey1", "subkey2", "subkey5", "subkey6"});
4496
0
  DoRedisTestArray(__LINE__, {"HVALS", "map_key"},
4497
0
      {"v3", "v2", "41", "12", "19", "14"});
4498
0
  DoRedisTestInt(__LINE__, {"HLEN", "map_key"}, 6);
4499
0
  DoRedisTestInt(__LINE__, {"HLEN", "does_not_exist"}, 0);
4500
0
  DoRedisTestInt(__LINE__, {"HEXISTS", "map_key", "subkey1"}, 1);
4501
0
  DoRedisTestInt(__LINE__, {"HEXISTS", "map_key", "subkey2"}, 1);
4502
0
  DoRedisTestInt(__LINE__, {"HEXISTS", "map_key", "subkey3"}, 0);
4503
0
  DoRedisTestInt(__LINE__, {"HEXISTS", "map_key", "subkey4"}, 0);
4504
0
  DoRedisTestInt(__LINE__, {"HEXISTS", "map_key", "subkey5"}, 1);
4505
0
  DoRedisTestInt(__LINE__, {"HEXISTS", "map_key", "subkey6"}, 1);
4506
  // HSTRLEN
4507
0
  DoRedisTestInt(__LINE__, {"HSTRLEN", "map_key", "subkey1"}, 2);
4508
0
  DoRedisTestInt(__LINE__, {"HSTRLEN", "map_key", "does_not_exist"}, 0);
4509
0
  SyncClient();
4510
4511
  // HDEL
4512
  // subkey7 doesn't exists
4513
0
  DoRedisTestInt(__LINE__, {"HDEL", "map_key", "subkey2", "subkey7", "subkey5"}, 2);
4514
0
  SyncClient();
4515
0
  DoRedisTestInt(__LINE__, {"HDEL", "map_key", "subkey9"}, 0);
4516
0
  SyncClient();
4517
0
  DoRedisTestInt(__LINE__, {"EXISTS", "map_key"}, 1);
4518
0
  DoRedisTestArray(__LINE__, {"HGETALL", "map_key"}, {"hashkey1", "v3", "hashkey2", "v2",
4519
0
      "subkey1", "41", "subkey6", "14"});
4520
0
  DoRedisTestInt(__LINE__, {"DEL", "map_key"}, 1); // Delete the whole map with a del
4521
0
  SyncClient();
4522
4523
0
  DoRedisTestInt(__LINE__, {"EXISTS", "map_key"}, 0);
4524
0
  DoRedisTestArray(__LINE__, {"HGETALL", "map_key"}, {});
4525
4526
0
  DoRedisTestInt(__LINE__, {"EXISTS", "set1"}, 0);
4527
0
  DoRedisTestInt(__LINE__, {"SADD", "set1", "val1"}, 1);
4528
0
  SyncClient();
4529
0
  DoRedisTestInt(__LINE__, {"DEL", "set1"}, 1);
4530
0
  SyncClient();
4531
0
  DoRedisTestInt(__LINE__, {"SADD", "set1", "val1"}, 1);
4532
0
  DoRedisTestInt(__LINE__, {"SADD", "set2", "val5", "val5", "val5"}, 1);
4533
0
  SyncClient();
4534
0
  DoRedisTestInt(__LINE__, {"EXISTS", "set1"}, 1);
4535
4536
0
  SyncClient();
4537
4538
0
  DoRedisTestInt(__LINE__, {"SADD", "set1", "val2", "val1", "val3"}, 2);
4539
4540
0
  SyncClient();
4541
4542
0
  DoRedisTestArray(__LINE__, {"SMEMBERS", "set1"}, {"val1", "val2", "val3"});
4543
0
  DoRedisTestInt(__LINE__, {"SCARD", "set1"}, 3);
4544
0
  DoRedisTestInt(__LINE__, {"SCARD", "does_not_exist"}, 0);
4545
0
  DoRedisTestInt(__LINE__, {"SISMEMBER", "set1", "val1"}, 1);
4546
0
  DoRedisTestInt(__LINE__, {"SISMEMBER", "set1", "val2"}, 1);
4547
0
  DoRedisTestInt(__LINE__, {"SISMEMBER", "set1", "val3"}, 1);
4548
0
  DoRedisTestInt(__LINE__, {"SISMEMBER", "set1", "val4"}, 0);
4549
0
  SyncClient();
4550
4551
  // SREM remove val1 and val3. val4 doesn't exist.
4552
0
  DoRedisTestInt(__LINE__, {"SREM", "set1", "val1", "val3", "val4"}, 2);
4553
0
  SyncClient();
4554
0
  DoRedisTestArray(__LINE__, {"SMEMBERS", "set1"}, {"val2"});
4555
4556
  // AUTH accepts 1 argument.
4557
0
  DoRedisTestExpectError(__LINE__, {"AUTH", "foo", "subkey5", "19", "subkey6", "14"});
4558
0
  DoRedisTestExpectError(__LINE__, {"AUTH"});
4559
  // CONFIG should be dummy implementations, that respond OK irrespective of the arguments
4560
0
  DoRedisTestOk(__LINE__, {"CONFIG", "foo", "subkey5", "19", "subkey6", "14"});
4561
0
  DoRedisTestOk(__LINE__, {"CONFIG"});
4562
  // Commands are pipelined and only sent when client.commit() is called.
4563
  // sync_commit() waits until all responses are received.
4564
0
  SyncClient();
4565
4566
0
  DoRedisTest(__LINE__, {"ROLE"}, RedisReplyType::kArray,
4567
0
      [](const RedisReply& reply) {
4568
0
        const auto& replies = reply.as_array();
4569
0
        ASSERT_EQ(3, replies.size());
4570
0
        ASSERT_EQ("master", replies[0].as_string());
4571
0
        ASSERT_EQ(0, replies[1].as_integer());
4572
0
        ASSERT_TRUE(replies[2].is_array()) << "replies[2]: " << replies[2].ToString();
4573
0
        ASSERT_EQ(0, replies[2].as_array().size());
4574
0
      }
4575
0
  );
4576
4577
0
  DoRedisTestBulkString(__LINE__, {"PING", "foo"}, "foo");
4578
0
  DoRedisTestSimpleString(__LINE__, {"PING"}, "PONG");
4579
4580
0
  DoRedisTestOk(__LINE__, {"QUIT"});
4581
4582
0
  DoRedisTestOk(__LINE__, {"FLUSHDB"});
4583
4584
0
  SyncClient();
4585
4586
0
  VerifyCallbacks();
4587
0
}
4588
4589
0
TEST_F(TestRedisService, TestDel) {
4590
  // The default value is true, but we explicitly set this here for clarity.
4591
0
  FLAGS_emulate_redis_responses = true;
4592
4593
0
  DoRedisTestOk(__LINE__, {"SET", "key", "value"});
4594
0
  DoRedisTestInt(__LINE__, {"DEL", "key"}, 1);
4595
0
  DoRedisTestInt(__LINE__, {"DEL", "key"}, 0);
4596
0
  DoRedisTestInt(__LINE__, {"DEL", "non_existent"}, 0);
4597
0
  SyncClient();
4598
0
  VerifyCallbacks();
4599
0
}
4600
4601
0
TEST_F(TestRedisService, TestHDel) {
4602
  // The default value is true, but we explicitly set this here for clarity.
4603
0
  FLAGS_emulate_redis_responses = true;
4604
4605
0
  DoRedisTestInt(__LINE__, {"HSET", "map_key", "subkey1", "42"}, 1);
4606
0
  SyncClient();
4607
0
  DoRedisTestInt(__LINE__, {"HDEL", "map_key", "subkey1", "non_existent_1", "non_existent_2"}, 1);
4608
0
  SyncClient();
4609
0
  DoRedisTestInt(__LINE__, {"HDEL", "map_key", "non_existent_1"}, 0);
4610
0
  SyncClient();
4611
0
  DoRedisTestInt(__LINE__, {"HDEL", "map_key", "non_existent_1", "non_existent_2"}, 0);
4612
0
  SyncClient();
4613
0
  DoRedisTestInt(__LINE__, {"HDEL", "map_key", "non_existent_1", "non_existent_1"}, 0);
4614
0
  SyncClient();
4615
0
  VerifyCallbacks();
4616
0
}
4617
4618
0
TEST_F(TestRedisService, TestSADDBatch) {
4619
0
  DoRedisTestInt(__LINE__, {"SADD", "set1", "10"}, 1);
4620
0
  DoRedisTestInt(__LINE__, {"SADD", "set1", "20"}, 1);
4621
0
  DoRedisTestInt(__LINE__, {"SADD", "set1", "30"}, 1);
4622
0
  DoRedisTestInt(__LINE__, {"SADD", "set1", "30"}, 0);
4623
0
  SyncClient();
4624
0
  DoRedisTestInt(__LINE__, {"SISMEMBER", "set1", "10"}, 1);
4625
0
  DoRedisTestInt(__LINE__, {"SISMEMBER", "set1", "20"}, 1);
4626
0
  DoRedisTestInt(__LINE__, {"SISMEMBER", "set1", "30"}, 1);
4627
0
  SyncClient();
4628
0
  VerifyCallbacks();
4629
0
}
4630
4631
0
TEST_F(TestRedisService, TestSRem) {
4632
  // The default value is true, but we explicitly set this here for clarity.
4633
0
  FLAGS_emulate_redis_responses = true;
4634
4635
0
  DoRedisTestInt(__LINE__, {"SADD", "set_key", "subkey1"}, 1);
4636
0
  SyncClient();
4637
0
  DoRedisTestInt(__LINE__, {"SREM", "set_key", "subkey1", "non_existent_1", "non_existent_2"}, 1);
4638
0
  SyncClient();
4639
0
  DoRedisTestInt(__LINE__, {"SREM", "set_key", "non_existent_1"}, 0);
4640
0
  SyncClient();
4641
0
  DoRedisTestInt(__LINE__, {"SREM", "set_key", "non_existent_1", "non_existent_2"}, 0);
4642
0
  SyncClient();
4643
0
  DoRedisTestInt(__LINE__, {"SREM", "set_key", "non_existent_1", "non_existent_1"}, 0);
4644
0
  SyncClient();
4645
0
  VerifyCallbacks();
4646
0
}
4647
4648
0
TEST_F(TestRedisService, TestEmulateFlagFalse) {
4649
0
  FLAGS_emulate_redis_responses = false;
4650
4651
0
  DoRedisTestOk(__LINE__, {"HSET", "map_key", "subkey1", "42"});
4652
4653
0
  DoRedisTestOk(__LINE__, {"SADD", "set_key", "val1", "val2", "val1"});
4654
4655
0
  DoRedisTestOk(__LINE__, {"HDEL", "map_key", "subkey1", "subkey2"});
4656
4657
0
  SyncClient();
4658
4659
0
  VerifyCallbacks();
4660
0
}
4661
4662
0
TEST_F(TestRedisService, TestHMGetTiming) {
4663
0
  const int num_keys = 50;
4664
  // For small hset size will not get consistent result.
4665
0
  const int size_hset = 1000;
4666
0
  const int num_subkeys = 1000;
4667
0
  const int num_hmgets = 10;
4668
0
  const bool is_random = true;
4669
0
  const bool is_serial = true; // Sequentially sync client to measure latency
4670
0
  const bool test_nonexisting = true;
4671
4672
0
  auto start = std::chrono::steady_clock::now();
4673
4674
0
  for (int i = 0; i < num_keys; i++) {
4675
0
    for (int j = 0; j < size_hset; j++) {
4676
0
      string si = std::to_string(i);
4677
0
      string sj = std::to_string(j);
4678
0
      DoRedisTestInt(__LINE__, {"HSET", "parent_" + si, "subkey_" + sj, "value_" + sj}, 1);
4679
0
    }
4680
0
    if (IsSanitizer() || ((i & 0x7) == 0)) {
4681
0
      SyncClient();
4682
0
    }
4683
0
  }
4684
4685
0
  SyncClient();
4686
4687
0
  auto mid = std::chrono::steady_clock::now();
4688
4689
0
  int max_query_subkey = test_nonexisting ? size_hset * 2 : size_hset;
4690
4691
0
  for (int i = 0; i < num_hmgets; i++) {
4692
0
    string si = std::to_string(i % num_keys);
4693
0
    vector<string> command = {"HMGET", "parent_" + si};
4694
0
    vector<RedisReply> expected;
4695
0
    for (int j = 0; j < num_subkeys; j++) {
4696
0
      int idx = is_random ?
4697
0
          RandomUniformInt(0, max_query_subkey) :
4698
0
          (j * max_query_subkey) / num_subkeys;
4699
0
      string sj = std::to_string(idx);
4700
0
      command.push_back("subkey_" + sj);
4701
0
      expected.push_back(
4702
0
          idx >= size_hset ? RedisReply() : RedisReply(RedisReplyType::kString, "value_" + sj));
4703
0
    }
4704
0
    DoRedisTestResultsArray(__LINE__, command, expected);
4705
0
    if (is_serial) {
4706
0
      SyncClient();
4707
0
    }
4708
0
  }
4709
4710
0
  SyncClient();
4711
4712
0
  auto end = std::chrono::steady_clock::now();
4713
4714
0
  auto set_time = std::chrono::duration_cast<std::chrono::milliseconds>(mid - start).count();
4715
0
  auto get_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - mid).count();
4716
4717
0
  LOG(INFO) << yb::Format("Total HSET time: $0ms Total HMGET time: $1ms",  set_time, get_time);
4718
4719
0
  VerifyCallbacks();
4720
0
}
4721
4722
0
TEST_F(TestRedisService, TestTtlSet) {
4723
0
  std::string collection_key = "russell";
4724
0
  std::string values[10] = {"the", "set", "of", "all", "sets",
4725
0
                            "that", "do", "not", "contain", "themselves"};
4726
0
  int card = 10;
4727
0
  TestTtlSet(&collection_key, values, card);
4728
0
}
4729
4730
0
TEST_F(TestRedisService, TestTtlSortedSet) {
4731
0
  std::string collection_key = "sort_me_up";
4732
0
  CollectionEntry values[10] = { std::make_tuple("5.4223", "insertion"),
4733
0
                                 std::make_tuple("-1", "bogo"),
4734
0
                                 std::make_tuple("8", "selection"),
4735
0
                                 std::make_tuple("3.1415926", "heap"),
4736
0
                                 std::make_tuple("2.718", "quick"),
4737
0
                                 std::make_tuple("1", "merge"),
4738
0
                                 std::make_tuple("9.9", "bubble"),
4739
0
                                 std::make_tuple("0", "radix"),
4740
0
                                 std::make_tuple("9.9", "shell"),
4741
0
                                 std::make_tuple("11", "comb") };
4742
0
  int card = 10;
4743
0
  TestTtlSortedSet(&collection_key, values, card);
4744
0
}
4745
4746
0
TEST_F(TestRedisService, TestTtlHash) {
4747
0
  std::string collection_key = "hash_browns";
4748
0
  CollectionEntry values[10] = { std::make_tuple("eggs", "hyperloglog"),
4749
0
                                 std::make_tuple("bagel", "bloom"),
4750
0
                                 std::make_tuple("ham", "quotient"),
4751
0
                                 std::make_tuple("salmon", "cuckoo"),
4752
0
                                 std::make_tuple("porridge", "lp_norm_sketch"),
4753
0
                                 std::make_tuple("muffin", "count_sketch"),
4754
0
                                 std::make_tuple("doughnut", "hopscotch"),
4755
0
                                 std::make_tuple("oatmeal", "fountain_codes"),
4756
0
                                 std::make_tuple("fruit", "linear_probing"),
4757
0
                                 std::make_tuple("toast", "chained") };
4758
0
  int card = 10;
4759
0
  TestTtlHash(&collection_key, values, card);
4760
0
}
4761
4762
0
TEST_F(TestRedisService, TestTtlTimeseries) {
4763
0
  std::string key = "timeseries";
4764
0
  DoRedisTestOk(__LINE__, {"TSADD", key, "1", "hello", "2", "how", "3", "are", "5", "you"});
4765
  // Checking TTL on timeseries.
4766
0
  DoRedisTestInt(__LINE__, {"TTL", key}, -1);
4767
0
  DoRedisTestInt(__LINE__, {"PTTL", key}, -1);
4768
0
  SyncClient();
4769
  // Checking PERSIST and (P)EXPIRE do not work.
4770
0
  DoRedisTestExpectError(__LINE__, {"PERSIST", key});
4771
0
  DoRedisTestExpectError(__LINE__, {"EXPIRE", key, "13"});
4772
0
  DoRedisTestExpectError(__LINE__, {"PEXPIRE", key, "16384"});
4773
0
  SyncClient();
4774
  // Checking SETEX turns it back into a normal key.
4775
0
  DoRedisTestOk(__LINE__, {"SETEX", key, "6", "17"});
4776
0
  SyncClient();
4777
0
  DoRedisTestBulkString(__LINE__, {"GET", key}, "17");
4778
0
  SyncClient();
4779
0
  std::this_thread::sleep_for(7s);
4780
0
  CheckExpired(&key);
4781
0
  SyncClient();
4782
0
  VerifyCallbacks();
4783
0
}
4784
4785
// For testing commands where the value is overwritten, but TTL is not.
4786
0
TEST_F(TestRedisService, TestTtlModifyNoOverwrite) {
4787
  // TODO: when we support RENAME, it should also be added here.
4788
0
  std::string k1 = "key";
4789
0
  std::string k2 = "keyy";
4790
0
  const int64_t millisecond_error = 500;
4791
  // Test integer modify
4792
0
  DoRedisTestOk(__LINE__, {"SET", k1, "3"});
4793
0
  SyncClient();
4794
0
  DoRedisTestInt(__LINE__, {"EXPIRE", k1, "14"}, 1);
4795
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, 14);
4796
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 14000, millisecond_error);
4797
0
  DoRedisTestInt(__LINE__, {"INCR", k1}, 4);
4798
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, 14);
4799
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 14000, millisecond_error);
4800
0
  SyncClient();
4801
0
  std::this_thread::sleep_for(5s);
4802
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, 9);
4803
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 9000, millisecond_error);
4804
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, "4");
4805
0
  DoRedisTestInt(__LINE__, {"INCRBY", k1, "3"}, 7);
4806
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, 9);
4807
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 9000, millisecond_error);
4808
0
  SyncClient();
4809
0
  std::this_thread::sleep_for(4s);
4810
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, "7");
4811
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, 5);
4812
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 5000, millisecond_error);
4813
0
  SyncClient();
4814
0
  std::this_thread::sleep_for(5s);
4815
0
  CheckExpired(&k1);
4816
  // Test string modify
4817
0
  DoRedisTestOk(__LINE__, {"SETEX", k2, "12", "from what I've tasted of desire "});
4818
0
  SyncClient();
4819
0
  DoRedisTestInt(__LINE__, {"TTL", k2}, 12);
4820
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k2}, 12000, millisecond_error);
4821
0
  DoRedisTestInt(__LINE__, {"APPEND", k2, "I hold with those who favor fire."}, 65);
4822
0
  DoRedisTestInt(__LINE__, {"TTL", k2}, 12);
4823
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k2}, 12000, millisecond_error);
4824
0
  SyncClient();
4825
0
  std::this_thread::sleep_for(5s);
4826
0
  DoRedisTestInt(__LINE__, {"TTL", k2}, 7);
4827
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k2}, 7000, millisecond_error);
4828
0
  DoRedisTestBulkString(__LINE__, {"GET", k2}, "from what I've tasted of desire "
4829
0
                        "I hold with those who favor fire.");
4830
0
  SyncClient();
4831
0
  std::this_thread::sleep_for(3s);
4832
0
  DoRedisTestInt(__LINE__, {"SETRANGE", k2, "5", "the beginning of time, sir"}, 65);
4833
0
  DoRedisTestInt(__LINE__, {"TTL", k2}, 4);
4834
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k2}, 4000, millisecond_error);
4835
0
  DoRedisTestBulkString(__LINE__, {"GET", k2}, "from the beginning of time, "
4836
0
                        "sir I hold with those who favor fire.");
4837
0
  SyncClient();
4838
0
  std::this_thread::sleep_for(2s);
4839
0
  DoRedisTestInt(__LINE__, {"TTL", k2}, 2);
4840
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k2}, 2000, millisecond_error);
4841
0
  DoRedisTestBulkString(__LINE__, {"GET", k2}, "from the beginning of time, "
4842
0
                        "sir I hold with those who favor fire.");
4843
0
  SyncClient();
4844
0
  std::this_thread::sleep_for(3s);
4845
0
  CheckExpired(&k2);
4846
  // Test Persist
4847
0
  DoRedisTestOk(__LINE__, {"SETEX", k1, "13", "we've been pulling out the nails that hold up"});
4848
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, 13);
4849
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 13000, millisecond_error);
4850
0
  DoRedisTestInt(__LINE__, {"APPEND", k1, " everything you've known"}, 69);
4851
0
  SyncClient();
4852
0
  std::this_thread::sleep_for(5s);
4853
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, 8);
4854
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 8000, millisecond_error);
4855
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, "we've been pulling out the nails "
4856
0
                        "that hold up everything you've known");
4857
0
  DoRedisTestInt(__LINE__, {"PERSIST", k1}, 1);
4858
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, -1);
4859
0
  DoRedisTestInt(__LINE__, {"PTTL", k1}, -1);
4860
0
  SyncClient();
4861
0
  std::this_thread::sleep_for(9s);
4862
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, "we've been pulling out the nails "
4863
0
                        "that hold up everything you've known");
4864
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, -1);
4865
0
  DoRedisTestInt(__LINE__, {"PTTL", k1}, -1);
4866
0
}
4867
4868
// For testing TTL-related commands on primitives.
4869
0
TEST_F(TestRedisService, TestTtlPrimitive) {
4870
0
  std::string k1 = "foo";
4871
0
  std::string k2 = "fu";
4872
0
  std::string k3 = "phu";
4873
0
  std::string value = "bar";
4874
0
  int64_t millisecond_error = 500;
4875
  // Checking expected behavior on a key with no ttl.
4876
0
  DoRedisTestOk(__LINE__, {"SET", k1, value});
4877
0
  SyncClient();
4878
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
4879
0
  DoRedisTestInt(__LINE__, {"TTL", k2}, -2);
4880
0
  DoRedisTestInt(__LINE__, {"PTTL", k2}, -2);
4881
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, -1);
4882
0
  DoRedisTestInt(__LINE__, {"PTTL", k1}, -1);
4883
0
  SyncClient();
4884
  // Setting a TTL and checking expected return values.
4885
0
  DoRedisTestInt(__LINE__, {"EXPIRE", k1, "4"}, 1);
4886
0
  SyncClient();
4887
0
  {
4888
0
    int attempt = 1;
4889
0
    while (true) {
4890
0
      const auto ttl_set_at = std::chrono::system_clock::now();
4891
0
      DoRedisTestInt(__LINE__, {"TTL", k1}, 4);
4892
0
      DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 4000, millisecond_error);
4893
0
      DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
4894
0
      SyncClient();
4895
0
      auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
4896
0
          std::chrono::system_clock::now() - ttl_set_at).count();
4897
0
      std::this_thread::sleep_for(std::max(
4898
0
          static_cast<int64_t>(0), static_cast<int64_t>(2500 - elapsed_ms)) * 1ms);
4899
      // By this point there should be about 1.4 seconds left until the key's expiration.
4900
0
      auto total_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
4901
0
          std::chrono::system_clock::now() - ttl_set_at).count();
4902
0
      if (total_elapsed_ms > 2550) {
4903
0
        if (attempt < 10) {
4904
0
          LOG(INFO) << "TTL test took too long, re-trying (attempt: "
4905
0
                    << attempt << ")";
4906
0
          attempt++;
4907
0
          DoRedisTestOk(__LINE__, {"SET", k1, value});
4908
0
          DoRedisTestInt(__LINE__, {"EXPIRE", k1, "4"}, 1);
4909
0
          continue;
4910
0
        } else {
4911
0
          LOG(WARNING) << "TTL test took too long, not re-trying: attempt=" << attempt;
4912
0
        }
4913
0
      }
4914
0
      DoRedisTestInt(__LINE__, {"TTL", k1}, 1);
4915
0
      DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 1000, millisecond_error);
4916
0
      DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
4917
0
      SyncClient();
4918
      // Checking expected return values after expiration.
4919
0
      std::this_thread::sleep_for(2s);
4920
0
      CheckExpiredPrimitive(&k1);
4921
0
      break;  // Success.
4922
0
    }
4923
0
  }
4924
  // Testing functionality with SETEX.
4925
0
  DoRedisTestOk(__LINE__, {"SETEX", k1, "5", value});
4926
0
  SyncClient();
4927
0
  DoRedisTestIntRange(__LINE__, {"TTL", k1}, 4, 5);
4928
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 4500, millisecond_error);
4929
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
4930
0
  SyncClient();
4931
  // Set a new, earlier expiration.
4932
0
  DoRedisTestInt(__LINE__, {"EXPIRE", k1, "2"}, 1);
4933
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, 2);
4934
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 1500, millisecond_error);
4935
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
4936
0
  SyncClient();
4937
  // Check that the value expires as expected.
4938
0
  std::this_thread::sleep_for(2s);
4939
0
  CheckExpiredPrimitive(&k1);
4940
  // Initialize with SET using the EX flag.
4941
0
  DoRedisTestOk(__LINE__, {"SET", k1, value, "EX", "2"});
4942
0
  SyncClient();
4943
  // Set a new, later, expiration.
4944
0
  DoRedisTestInt(__LINE__, {"EXPIRE", k1, "8"}, 1);
4945
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, 8);
4946
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 8000, millisecond_error);
4947
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
4948
0
  SyncClient();
4949
  // Checking expected return values after a while, before expiration.
4950
0
  std::this_thread::sleep_for(4s);
4951
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, 4);
4952
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k1}, 4000, millisecond_error);
4953
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
4954
0
  SyncClient();
4955
  // Persisting the key and checking expected return values.
4956
0
  DoRedisTestInt(__LINE__, {"PERSIST", k1}, 1);
4957
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, -1);
4958
0
  DoRedisTestInt(__LINE__, {"PTTL", k1}, -1);
4959
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
4960
0
  SyncClient();
4961
  // Check that the key and value are still there after a while.
4962
0
  std::this_thread::sleep_for(30s);
4963
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, -1);
4964
0
  DoRedisTestInt(__LINE__, {"PTTL", k1}, -1);
4965
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
4966
0
  SyncClient();
4967
  // Persist a key that does not exist.
4968
0
  DoRedisTestInt(__LINE__, {"PERSIST", k2}, 0);
4969
0
  SyncClient();
4970
  // Persist a key that has no TTL.
4971
0
  DoRedisTestInt(__LINE__, {"PERSIST", k1}, 0);
4972
0
  SyncClient();
4973
  // Vanilla set on a key and persisting it.
4974
0
  DoRedisTestOk(__LINE__, {"SET", k2, value});
4975
0
  SyncClient();
4976
0
  DoRedisTestInt(__LINE__, {"PERSIST", k2}, 0);
4977
0
  DoRedisTestInt(__LINE__, {"TTL", k2}, -1);
4978
0
  DoRedisTestInt(__LINE__, {"PTTL", k2}, -1);
4979
0
  SyncClient();
4980
  // Expiring with an invalid TTL. We do not check the minimum,
4981
  // because any negative value leads to an immediate deletion.
4982
0
  DoRedisTestExpectError(__LINE__, {"PEXPIRE", k2,
4983
0
      std::to_string(kRedisMaxTtlMillis + 1)});
4984
0
  DoRedisTestExpectError(__LINE__, {"EXPIRE", k2,
4985
0
      std::to_string(kRedisMaxTtlMillis / MonoTime::kMillisecondsPerSecond + 1)});
4986
0
  SyncClient();
4987
  // Test that setting a zero-valued TTL properly expires the value.
4988
0
  DoRedisTestInt(__LINE__, {"EXPIRE", k2, "0"}, 1);
4989
0
  CheckExpiredPrimitive(&k2);
4990
  // One more time with a negative TTL.
4991
0
  DoRedisTestOk(__LINE__, {"SET", k2, value});
4992
0
  SyncClient();
4993
0
  DoRedisTestInt(__LINE__, {"EXPIRE", k2, "-7"}, 1);
4994
0
  CheckExpiredPrimitive(&k2);
4995
0
  DoRedisTestOk(__LINE__, {"SETEX", k2, "-7", value});
4996
0
  CheckExpiredPrimitive(&k2);
4997
  // Test PExpire
4998
0
  DoRedisTestOk(__LINE__, {"SET", k2, value});
4999
0
  SyncClient();
5000
0
  DoRedisTestInt(__LINE__, {"PEXPIRE", k2, "3200"}, 1);
5001
0
  DoRedisTestInt(__LINE__, {"TTL", k2}, 3);
5002
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k2}, 3200, millisecond_error);
5003
0
  SyncClient();
5004
0
  std::this_thread::sleep_for(1s);
5005
0
  DoRedisTestInt(__LINE__, {"TTL", k2}, 2);
5006
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k2}, 2200, millisecond_error);
5007
0
  SyncClient();
5008
0
  std::this_thread::sleep_for(3s);
5009
0
  CheckExpiredPrimitive(&k2);
5010
  // Test PSetEx
5011
0
  DoRedisTestOk(__LINE__, {"PSETEX", k3, "2300", value});
5012
0
  SyncClient();
5013
0
  std::this_thread::sleep_for(1s);
5014
0
  DoRedisTestInt(__LINE__, {"TTL", k3}, 1);
5015
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k3}, 1300, millisecond_error);
5016
0
  SyncClient();
5017
0
  std::this_thread::sleep_for(2s);
5018
0
  CheckExpiredPrimitive(&k3);
5019
0
  VerifyCallbacks();
5020
0
}
5021
5022
// For testing TestExpireAt
5023
0
TEST_F(TestRedisService, TestExpireAt) {
5024
0
  std::string k1 = "foo";
5025
0
  std::string k2 = "fu";
5026
0
  std::string k3 = "phu";
5027
0
  std::string value = "bar";
5028
0
  int64_t millisecond_error = 500;
5029
0
  int64_t second_error = 1;
5030
0
  DoRedisTestOk(__LINE__, {"SET", k1, value});
5031
0
  SyncClient();
5032
0
  DoRedisTestInt(__LINE__, {"EXPIREAT", k1, std::to_string(std::time(0) + 5)}, 1);
5033
0
  SyncClient();
5034
0
  DoRedisTestApproxInt(__LINE__, {"TTL", k1}, 5, second_error);
5035
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
5036
0
  SyncClient();
5037
0
  std::this_thread::sleep_for(2s);
5038
0
  DoRedisTestApproxInt(__LINE__, {"TTL", k1}, 3, second_error);
5039
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
5040
0
  SyncClient();
5041
  // Setting a new, later expiration.
5042
0
  DoRedisTestInt(__LINE__, {"EXPIREAT", k1, std::to_string(std::time(0) + 7)}, 1);
5043
0
  SyncClient();
5044
0
  DoRedisTestApproxInt(__LINE__, {"TTL", k1}, 7, second_error);
5045
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
5046
0
  SyncClient();
5047
  // Checking expected return values after expiration.
5048
0
  std::this_thread::sleep_for(8s);
5049
0
  CheckExpiredPrimitive(&k1);
5050
5051
  // Again, but with an earlier expiration.
5052
0
  DoRedisTestOk(__LINE__, {"SET", k1, value});
5053
0
  SyncClient();
5054
0
  DoRedisTestInt(__LINE__, {"EXPIREAT", k1, std::to_string(std::time(0) + 13)}, 1);
5055
0
  SyncClient();
5056
0
  DoRedisTestApproxInt(__LINE__, {"TTL", k1}, 13, second_error);
5057
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
5058
0
  SyncClient();
5059
  // Setting a new, earlier expiration.
5060
0
  DoRedisTestInt(__LINE__, {"EXPIREAT", k1, std::to_string(std::time(0) + 5)}, 1);
5061
0
  SyncClient();
5062
0
  DoRedisTestApproxInt(__LINE__, {"TTL", k1}, 5, second_error);
5063
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
5064
0
  SyncClient();
5065
  // Check that the value expires as expected.
5066
0
  std::this_thread::sleep_for(6s);
5067
0
  CheckExpiredPrimitive(&k1);
5068
5069
  // Persisting the key and checking expected return values.
5070
0
  DoRedisTestOk(__LINE__, {"SET", k1, value});
5071
0
  SyncClient();
5072
0
  DoRedisTestInt(__LINE__, {"EXPIREAT", k1, std::to_string(std::time(0) + 3)}, 1);
5073
0
  SyncClient();
5074
0
  DoRedisTestInt(__LINE__, {"PERSIST", k1}, 1);
5075
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, -1);
5076
0
  DoRedisTestInt(__LINE__, {"PTTL", k1}, -1);
5077
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
5078
0
  SyncClient();
5079
  // Check that the key and value are still there after a while.
5080
0
  std::this_thread::sleep_for(30s);
5081
0
  DoRedisTestInt(__LINE__, {"TTL", k1}, -1);
5082
0
  DoRedisTestInt(__LINE__, {"PTTL", k1}, -1);
5083
0
  DoRedisTestBulkString(__LINE__, {"GET", k1}, value);
5084
0
  SyncClient();
5085
  // Test that setting a zero-valued time properly expires the value.
5086
0
  DoRedisTestInt(__LINE__, {"EXPIREAT", k1, "0"}, 1);
5087
0
  CheckExpiredPrimitive(&k1);
5088
  // One more time with a negative expiration time.
5089
0
  DoRedisTestOk(__LINE__, {"SET", k2, value});
5090
0
  SyncClient();
5091
0
  DoRedisTestInt(__LINE__, {"EXPIREAT", k2, "-7"}, 1);
5092
0
  CheckExpiredPrimitive(&k2);
5093
  // Again with times before the current time.
5094
0
  DoRedisTestOk(__LINE__, {"SET", k2, value});
5095
0
  SyncClient();
5096
0
  DoRedisTestInt(__LINE__, {"EXPIREAT", k2, std::to_string(std::time(0) - 3)}, 1);
5097
0
  CheckExpiredPrimitive(&k2);
5098
  // Again with the current time.
5099
0
  DoRedisTestOk(__LINE__, {"SET", k2, value});
5100
0
  SyncClient();
5101
0
  DoRedisTestInt(__LINE__, {"EXPIREAT", k2, std::to_string(std::time(0))}, 1);
5102
0
  CheckExpiredPrimitive(&k2);
5103
  // Test PExpireAt
5104
0
  DoRedisTestOk(__LINE__, {"SET", k2, value});
5105
0
  SyncClient();
5106
0
  DoRedisTestInt(__LINE__, {"PEXPIREAT", k2, std::to_string(std::time(0) * 1000 + 3200)}, 1);
5107
0
  DoRedisTestApproxInt(__LINE__, {"TTL", k2}, 3, second_error);
5108
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k2}, 3200, 2 * millisecond_error);
5109
0
  SyncClient();
5110
0
  std::this_thread::sleep_for(1s);
5111
0
  DoRedisTestApproxInt(__LINE__, {"TTL", k2}, 2, second_error);
5112
0
  DoRedisTestApproxInt(__LINE__, {"PTTL", k2}, 2200, 2 * millisecond_error);
5113
0
  SyncClient();
5114
0
  std::this_thread::sleep_for(3s);
5115
0
  CheckExpiredPrimitive(&k2);
5116
  // Test ExpireAt on nonexistent key
5117
0
  DoRedisTestInt(__LINE__, {"EXPIREAT", k3, std::to_string(std::time(0) + 4)}, 0);
5118
0
  SyncClient();
5119
0
  DoRedisTestNull(__LINE__, {"GET", k3});
5120
0
  SyncClient();
5121
0
  VerifyCallbacks();
5122
0
}
5123
5124
0
TEST_F(TestRedisService, TestQuit) {
5125
0
  DoRedisTestOk(__LINE__, {"SET", "key", "value"});
5126
0
  DoRedisTestBulkString(__LINE__, {"GET", "key"}, "value");
5127
0
  DoRedisTestInt(__LINE__, {"DEL", "key"}, 1);
5128
0
  DoRedisTestOk(__LINE__, {"QUIT"});
5129
0
  SyncClient();
5130
0
  VerifyCallbacks();
5131
  // Connection closed so following command fails
5132
0
  DoRedisTestExpectError(__LINE__, {"SET", "key", "value"});
5133
0
  SyncClient();
5134
0
  VerifyCallbacks();
5135
0
}
5136
5137
0
TEST_F(TestRedisService, TestFlushAll) {
5138
0
  TestFlush("FLUSHALL", false);
5139
0
  TestFlush("FLUSHALL", true);
5140
0
}
5141
5142
0
TEST_F(TestRedisService, TestFlushDb) {
5143
0
  TestFlush("FLUSHDB", false);
5144
0
  TestFlush("FLUSHDB", true);
5145
0
}
5146
5147
// Test deque functionality of the list.
5148
0
TEST_F(TestRedisService, TestListBasic) {
5149
0
  DoRedisTestInt(__LINE__, {"LPUSH", "letters", "florea", "elena", "dumitru"}, 3);
5150
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 3);
5151
0
  DoRedisTestInt(__LINE__, {"LPUSH", "letters", "constantin", "barbu"}, 5);
5152
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 5);
5153
0
  DoRedisTestBulkString(__LINE__, {"LPOP", "letters"}, "barbu");
5154
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 4);
5155
0
  DoRedisTestInt(__LINE__, {"LPUSH", "letters", "ana"}, 5);
5156
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 5);
5157
0
  DoRedisTestInt(__LINE__, {"RPUSH", "letters", "lazar", "maria", "nicolae"}, 8);
5158
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 8);
5159
0
  DoRedisTestBulkString(__LINE__, {"LPOP", "letters"}, "ana");
5160
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 7);
5161
0
  DoRedisTestBulkString(__LINE__, {"RPOP", "letters"}, "nicolae");
5162
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 6);
5163
0
  DoRedisTestInt(__LINE__, {"RPUSH", "letters", "gheorghe", "haralambie", "ion"}, 9);
5164
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 9);
5165
0
  DoRedisTestInt(__LINE__, {"LPUSH", "letters", "vasile", "udrea", "tudor", "sandu"}, 13);
5166
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 13);
5167
0
  DoRedisTestInt(__LINE__, {"RPUSH", "letters", "jiu", "kilogram"}, 15);
5168
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 15);
5169
0
  DoRedisTestBulkString(__LINE__, {"RPOP", "letters"}, "kilogram");
5170
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 14);
5171
0
  DoRedisTestBulkString(__LINE__, {"LPOP", "letters"}, "sandu");
5172
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 13);
5173
0
  DoRedisTestInt(__LINE__, {"RPUSH", "letters", "dublu v", "xenia", "i grec"}, 16);
5174
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 16);
5175
0
  DoRedisTestInt(__LINE__, {"LPUSH", "letters", "radu", "q", "petre", "olga"}, 20);
5176
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 20);
5177
0
  DoRedisTestBulkString(__LINE__, {"RPOP", "letters"}, "i grec");
5178
0
  DoRedisTestInt(__LINE__, {"LLEN", "letters"}, 19);
5179
0
  DoRedisTestInt(__LINE__, {"RPUSH", "letters", "zamfir"}, 20);
5180
0
  SyncClient();
5181
5182
  // Degenerate cases
5183
0
  DoRedisTestOk(__LINE__, {"SET", "bravo", "alpha"});
5184
0
  DoRedisTestNull(__LINE__, {"LPOP", "november"});
5185
0
  DoRedisTestNull(__LINE__, {"RPOP", "kilo"});
5186
0
  DoRedisTestInt(__LINE__, {"LPUSH", "sierra", "yankee"}, 1);
5187
0
  SyncClient();
5188
0
  DoRedisTestExpectError(__LINE__, {"LPOP", "bravo"});
5189
0
  DoRedisTestBulkString(__LINE__, {"RPOP", "sierra"}, "yankee");
5190
0
  DoRedisTestExpectError(__LINE__, {"RPOP", "bravo"});
5191
0
  SyncClient();
5192
0
  DoRedisTestNull(__LINE__, {"LPOP", "sierra"});
5193
0
  DoRedisTestNull(__LINE__, {"RPOP", "sierra"});
5194
0
}
5195
5196
0
TEST_F(TestRedisService, Keys) {
5197
  // The default value is true, but we explicitly set this here for clarity.
5198
0
  FLAGS_emulate_redis_responses = true;
5199
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key_0", "1", "a"}, 1);
5200
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key_0", "2", "b"}, 1);
5201
0
  DoRedisTestOk(__LINE__, {"SET", "z_key_1", "v1"});
5202
0
  DoRedisTestOk(__LINE__, {"SET", "z_key_1", "v2"});
5203
0
  SyncClient();
5204
5205
0
  DoRedisTestArray(__LINE__, {"KEYS", "*"}, {"z_key_1", "z_key_0"});
5206
0
  DoRedisTestArray(__LINE__, {"KEYS", "*key*1"}, {"z_key_1"});
5207
0
  DoRedisTestArray(__LINE__, {"KEYS", "*key\\*1"}, {});
5208
0
  DoRedisTestArray(__LINE__, {"KEYS", "z_key_[^1]"}, {"z_key_0"});
5209
0
  DoRedisTestArray(__LINE__, {"KEYS", "z_key_[02]"}, {"z_key_0"});
5210
0
  DoRedisTestArray(__LINE__, {"KEYS", "z_k?y_?"}, {"z_key_1", "z_key_0"});
5211
0
  DoRedisTestArray(__LINE__, {"KEYS", "z_key_\\?"}, {});
5212
0
  DoRedisTestArray(__LINE__, {"KEYS", "z_key_["}, {});
5213
0
  DoRedisTestArray(__LINE__, {"KEYS", "z_key_."}, {});
5214
0
  DoRedisTestArray(__LINE__, {"KEYS", "z_key_[]"}, {});
5215
0
  SyncClient();
5216
5217
0
  DoRedisTestInt(__LINE__, {"HSET", "z_key_\0", "f", "v"}, 1);
5218
0
  SyncClient();
5219
0
  DoRedisTestArray(__LINE__, {"KEYS", "z_key_\0"}, {"z_key_\0"});
5220
5221
0
  SyncClient();
5222
0
  VerifyCallbacks();
5223
0
}
5224
5225
0
TEST_F(TestRedisService, KeysZeroChar) {
5226
0
  FLAGS_emulate_redis_responses = true;
5227
0
  string s("foo\0bar", 6);
5228
0
  string s1("foo\0bars", 7);
5229
0
  DoRedisTestInt(__LINE__, {"HSET", s, "1", "a"}, 1);
5230
0
  SyncClient();
5231
0
  DoRedisTestArray(__LINE__, {"KEYS", "foo"}, {});
5232
0
  DoRedisTestArray(__LINE__, {"KEYS", s}, {s});
5233
0
  DoRedisTestArray(__LINE__, {"KEYS", s1}, {});
5234
0
  SyncClient();
5235
0
  VerifyCallbacks();
5236
0
}
5237
5238
0
TEST_F(TestRedisService, RangeScanTimeout) {
5239
  // Test SortedSets.
5240
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "1.0", "v1"}, 1);
5241
0
  SyncClient();
5242
0
  DoRedisTestArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "-inf", "+inf"}, {"v1"});
5243
0
  SyncClient();
5244
5245
0
  FLAGS_TEST_tserver_timeout = true;
5246
0
  DoRedisTestExpectError(__LINE__, {"ZRANGEBYSCORE", "z_key", "-inf", "+inf"},
5247
0
                         "Deadline for query passed.");
5248
0
  SyncClient();
5249
0
  FLAGS_TEST_tserver_timeout = false;
5250
5251
  // Test TimeSeries.
5252
0
  DoRedisTestOk(__LINE__, {"TSADD", "ts_key", "1", "v1"});
5253
0
  SyncClient();
5254
0
  DoRedisTestArray(__LINE__, {"TSRANGEBYTIME", "ts_key", "-inf", "+inf"}, {"1", "v1"});
5255
0
  SyncClient();
5256
5257
0
  FLAGS_TEST_tserver_timeout = true;
5258
0
  DoRedisTestExpectError(__LINE__, {"TSRANGEBYTIME", "ts_key", "-inf", "+inf"},
5259
0
                         "Deadline for query passed.");
5260
0
  SyncClient();
5261
0
  FLAGS_TEST_tserver_timeout = false;
5262
5263
  // Test a point read doesn't time out.
5264
0
  DoRedisTestOk(__LINE__, {"SET", "k", "v"});
5265
0
  SyncClient();
5266
0
  DoRedisTestBulkString(__LINE__, {"GET", "k"}, "v");
5267
0
  SyncClient();
5268
5269
0
  FLAGS_TEST_tserver_timeout = true;
5270
0
  DoRedisTestBulkString(__LINE__, {"GET", "k"}, "v");
5271
5272
0
  SyncClient();
5273
0
  VerifyCallbacks();
5274
0
}
5275
5276
0
TEST_F(TestRedisService, KeysTimeout) {
5277
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "1.0", "v1"}, 1);
5278
0
  SyncClient();
5279
0
  FLAGS_TEST_tserver_timeout = true;
5280
0
  DoRedisTestExpectError(__LINE__, {"KEYS", "*"},
5281
0
                         "Errors occurred while reaching out to the tablet servers");
5282
0
  SyncClient();
5283
0
  FLAGS_TEST_tserver_timeout = false;
5284
0
  DoRedisTestArray(__LINE__, {"KEYS", "*"}, {"z_key"});
5285
0
  SyncClient();
5286
0
  VerifyCallbacks();
5287
0
}
5288
5289
0
TEST_F(TestRedisService, KeysWithFlush) {
5290
0
  for (int i = 0; i < 2; i++) {
5291
0
    DoRedisTestOk(__LINE__, {"SET", Format("k$0", i), Format("v$0", i)});
5292
0
    SyncClient();
5293
0
    ASSERT_OK(FlushRedisTable());
5294
0
  }
5295
5296
0
  DoRedisTestArray(__LINE__, {"KEYS", "*"}, {"k0", "k1"});
5297
0
  SyncClient();
5298
0
  VerifyCallbacks();
5299
0
}
5300
5301
0
TEST_F(TestRedisService, SortedSetsIncr) {
5302
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "1", "v1"}, 1);
5303
0
  SyncClient();
5304
0
  DoRedisTestInt(__LINE__, {"ZADD", "z_key", "incr", "1", "v1"}, 0);
5305
0
  SyncClient();
5306
0
  DoRedisTestScoreValueArray(__LINE__, {"ZRANGEBYSCORE", "z_key", "-inf", "+inf", "WITHSCORES"},
5307
0
                                       {2}, {"v1"});
5308
0
  SyncClient();
5309
0
}
5310
5311
}  // namespace redisserver
5312
}  // namespace yb