public async Task SortedSetPopMulti_Multi_Async() { using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.SortedSetPop), r => r.SortedSetPop); var db = conn.GetDatabase(); var key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); db.SortedSetAdd(key, entries, CommandFlags.FireAndForget); var last = await db.SortedSetPopAsync(key, Order.Descending).ForAwait(); Assert.True(last.HasValue); Assert.Equal(entries[9], last.Value); Assert.Equal(9, db.SortedSetLength(key)); var moreLasts = await db.SortedSetPopAsync(key, 2, Order.Descending).ForAwait(); Assert.Equal(2, moreLasts.Length); Assert.Equal(entries[8], moreLasts[0]); Assert.Equal(entries[7], moreLasts[1]); Assert.Equal(7, db.SortedSetLength(key)); } }
public async Task SortedSetPopMulti_Single_Async() { using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.SortedSetPop), r => r.SortedSetPop); var db = conn.GetDatabase(); var key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); db.SortedSetAdd(key, entries, CommandFlags.FireAndForget); var first = await db.SortedSetPopAsync(key).ForAwait(); Assert.True(first.HasValue); Assert.Equal(entries[0], first.Value); Assert.Equal(9, db.SortedSetLength(key)); var moreFirsts = await db.SortedSetPopAsync(key, 1).ForAwait(); Assert.Single(moreFirsts); Assert.Equal(entries[1], moreFirsts[0]); Assert.Equal(8, db.SortedSetLength(key)); } }
public void NoInlineReplacement() { const string Script = "redis.call('set', @key, 'hello@example')"; using (var conn = Create(allowAdmin: true)) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); var server = conn.GetServer(TestConfig.Current.PrimaryServerAndPort); server.ScriptFlush(); var script = LuaScript.Prepare(Script); Assert.Equal("redis.call('set', ARGV[1], 'hello@example')", script.ExecutableScript); var db = conn.GetDatabase(); var key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var p = new { key }; script.Evaluate(db, p, flags: CommandFlags.FireAndForget); var val = db.StringGet(key); Assert.Equal("hello@example", val); } }
public async Task StringGetSetExpiryAbsolute() { using var muxer = Create(); Skip.IfMissingFeature(muxer, nameof(RedisFeatures.GetEx), r => r.GetEx); var conn = muxer.GetDatabase(); var key = Me(); conn.KeyDelete(key, CommandFlags.FireAndForget); conn.StringSet(key, "abc", TimeSpan.FromHours(1)); var newDate = DateTime.UtcNow.AddMinutes(30); var val = conn.StringGetSetExpiryAsync(key, newDate); var valTtl = conn.KeyTimeToLiveAsync(key); Assert.Equal("abc", await val); var time = await valTtl; Assert.NotNull(time); Assert.InRange(time.Value, TimeSpan.FromMinutes(29.8), TimeSpan.FromMinutes(30.2)); // And ensure our type checking works var ex = await Assert.ThrowsAsync <ArgumentException>(() => conn.StringGetSetExpiryAsync(key, new DateTime(100, DateTimeKind.Unspecified))); Assert.NotNull(ex); }
public void StreamAddMultipleValuePairsWithManualId() { var id = "42-0"; var key = GetUniqueKey("manual_id_multiple_values"); using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); var fields = new NameValueEntry[] { new NameValueEntry("field1", "value1"), new NameValueEntry("field2", "value2") }; var messageId = db.StreamAdd(key, fields, id); var entries = db.StreamRange(key); Assert.Equal(id, messageId); Assert.NotNull(entries); Assert.True(entries.Length == 1); Assert.Equal(id, entries[0].Id); } }
public void StreamPendingNoMessagesOrConsumers() { var key = GetUniqueKey("stream_pending_empty"); var groupName = "test_group"; using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); var id = db.StreamAdd(key, "field1", "value1"); db.StreamDelete(key, new RedisValue[] { id }); db.StreamCreateConsumerGroup(key, groupName, "0-0"); var pendingInfo = db.StreamPending(key, "test_group"); Assert.Equal(0, pendingInfo.PendingMessageCount); Assert.Equal(RedisValue.Null, pendingInfo.LowestPendingMessageId); Assert.Equal(RedisValue.Null, pendingInfo.HighestPendingMessageId); Assert.NotNull(pendingInfo.Consumers); Assert.True(pendingInfo.Consumers.Length == 0); } }
public void StreamReadEmptyStreams() { var key1 = GetUniqueKey("read_empty_stream_1"); var key2 = GetUniqueKey("read_empty_stream_2"); using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); // Write to a stream to create the key. var id1 = db.StreamAdd(key1, "field1", "value1"); var id2 = db.StreamAdd(key2, "field2", "value2"); // Delete the key to empty the stream. db.StreamDelete(key1, new RedisValue[] { id1 }); db.StreamDelete(key2, new RedisValue[] { id2 }); var len1 = db.StreamLength(key1); var len2 = db.StreamLength(key2); // Read the entire stream from the beginning. var entries1 = db.StreamRead(key1, "0-0"); var entries2 = db.StreamRead(key2, "0-0"); Assert.True(entries1.Length == 0); Assert.True(entries2.Length == 0); Assert.Equal(0, len1); Assert.Equal(0, len2); } }
public void StreamGroupConsumerInfoGet() { var key = GetUniqueKey("group_consumer_info"); var group = "test_group"; var consumer1 = "test_consumer_1"; var consumer2 = "test_consumer_2"; using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); var id1 = db.StreamAdd(key, "field1", "value1"); var id2 = db.StreamAdd(key, "field2", "value2"); var id3 = db.StreamAdd(key, "field3", "value3"); var id4 = db.StreamAdd(key, "field4", "value4"); db.StreamCreateConsumerGroup(key, group, "-"); db.StreamReadGroup(key, group, consumer1, count: 1); db.StreamReadGroup(key, group, consumer2); var consumerInfoList = db.StreamConsumerInfo(key, group); Assert.NotNull(consumerInfoList); Assert.Equal(2, consumerInfoList.Length); Assert.Equal(consumer1, consumerInfoList[0].Name); Assert.Equal(consumer2, consumerInfoList[1].Name); Assert.Equal(1, consumerInfoList[0].PendingMessageCount); Assert.Equal(3, consumerInfoList[1].PendingMessageCount); } }
public void StreamInfoGetWithEmptyStream() { var key = GetUniqueKey("stream_info_empty"); using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); // Add an entry and then delete it so the stream is empty, then run streaminfo // to ensure it functions properly on an empty stream. Namely, the first-entry // and last-entry messages should be null. var id = db.StreamAdd(key, "field1", "value1"); db.StreamDelete(key, new RedisValue[] { id }); Assert.Equal(0, db.StreamLength(key)); var streamInfo = db.StreamInfo(key); Assert.True(streamInfo.FirstEntry.IsNull); Assert.True(streamInfo.LastEntry.IsNull); } }
public async Task SetNotExistsAndGet() { using (var muxer = Create()) { Skip.IfMissingFeature(muxer, nameof(RedisFeatures.SetNotExistsAndGet), r => r.SetNotExistsAndGet); var conn = muxer.GetDatabase(); var prefix = Me(); conn.KeyDelete(prefix + "1", CommandFlags.FireAndForget); conn.KeyDelete(prefix + "2", CommandFlags.FireAndForget); conn.KeyDelete(prefix + "3", CommandFlags.FireAndForget); conn.KeyDelete(prefix + "4", CommandFlags.FireAndForget); conn.StringSet(prefix + "1", "abc", flags: CommandFlags.FireAndForget); var x0 = conn.StringSetAndGetAsync(prefix + "1", "def", when: When.NotExists); var x1 = conn.StringSetAndGetAsync(prefix + "2", "def", when: When.NotExists); var x2 = conn.StringSetAndGetAsync(prefix + "3", "def", expiry: TimeSpan.FromSeconds(4), when: When.NotExists); var x3 = conn.StringSetAndGetAsync(prefix + "4", "def", expiry: TimeSpan.FromMilliseconds(4001), when: When.NotExists); var s0 = conn.StringGetAsync(prefix + "1"); var s1 = conn.StringGetAsync(prefix + "2"); Assert.Equal("abc", await x0); Assert.Equal(RedisValue.Null, await x1); Assert.Equal(RedisValue.Null, await x2); Assert.Equal(RedisValue.Null, await x3); Assert.Equal("abc", await s0); Assert.Equal("def", await s1); } }
public void StreamAddMultipleValuePairsWithAutoId() { using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var key = GetUniqueKey("multiple_value_pairs"); var fields = new NameValueEntry[] { new NameValueEntry("field1", "value1"), new NameValueEntry("field2", "value2") }; var db = conn.GetDatabase(); var messageId = db.StreamAdd(key, fields); var entries = db.StreamRange(key); Assert.True(entries.Length == 1); Assert.Equal(messageId, entries[0].Id); Assert.True(entries[0].Values.Length == 2); Assert.True(entries[0].Values[0].Name == "field1" && entries[0].Values[0].Value == "value1"); Assert.True(entries[0].Values[1].Name == "field2" && entries[0].Values[1].Value == "value2"); } }
public void StreamConsumerGroupReadFromStreamBeginningWithCount() { var key = GetUniqueKey("group_read_with_count"); var groupName = "test_group"; using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); var id1 = db.StreamAdd(key, "field1", "value1"); var id2 = db.StreamAdd(key, "field2", "value2"); var id3 = db.StreamAdd(key, "field3", "value3"); var id4 = db.StreamAdd(key, "field4", "value4"); db.StreamCreateConsumerGroup(key, groupName, "-"); // Start reading after id1. var entries = db.StreamReadGroup(key, groupName, "test_consumer", id1, 2); // Ensure we only received the requested count and that the IDs match the expected values. Assert.True(entries.Length == 2); Assert.True(id2 == entries[0].Id); Assert.True(id3 == entries[1].Id); } }
public void StreamReadMultipleStreamsWithEmptyResponse() { var key1 = GetUniqueKey("read_multi_1"); var key2 = GetUniqueKey("read_multi_2"); using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); var id1 = db.StreamAdd(key1, "field1", "value1"); var id2 = db.StreamAdd(key1, "fiedl2", "value2"); var id3 = db.StreamAdd(key2, "field3", "value3"); var id4 = db.StreamAdd(key2, "field4", "value4"); var streamList = new StreamIdPair[] { // Read past the end of both streams. new StreamIdPair(key1, id2), new StreamIdPair(key2, id4) }; var streams = db.StreamRead(streamList); // We expect an empty response. Assert.True(streams.Length == 0); } }
public void StreamReadMultipleStreamsWithReadPastSecondStream() { var key1 = GetUniqueKey("read_multi_1"); var key2 = GetUniqueKey("read_multi_2"); using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); var id1 = db.StreamAdd(key1, "field1", "value1"); var id2 = db.StreamAdd(key1, "fiedl2", "value2"); var id3 = db.StreamAdd(key2, "field3", "value3"); var id4 = db.StreamAdd(key2, "field4", "value4"); var streamList = new StreamIdPair[2] { new StreamIdPair(key1, "0-0"), // read past the end of stream # 2 new StreamIdPair(key2, id4) }; var streams = db.StreamRead(streamList); // We should only get the first stream back. Assert.True(streams.Length == 1); Assert.Equal(key1, streams[0].Key); Assert.True(streams[0].Entries.Length == 2); } }
public void CheckLoads(bool async) { using (var conn0 = Create(allowAdmin: true)) using (var conn1 = Create(allowAdmin: true)) { Skip.IfMissingFeature(conn0, nameof(RedisFeatures.Scripting), f => f.Scripting); // note that these are on different connections (so we wouldn't expect // the flush to drop the local cache - assume it is a surprise!) var server = conn0.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); var db = conn1.GetDatabase(); const string script = "return 1;"; // start empty server.ScriptFlush(); Assert.False(server.ScriptExists(script)); // run once, causes to be cached Assert.True((bool)db.ScriptEvaluate(script)); Assert.True(server.ScriptExists(script)); // can run again Assert.True((bool)db.ScriptEvaluate(script)); // ditch the scripts; should no longer exist db.Ping(); server.ScriptFlush(); Assert.False(server.ScriptExists(script)); db.Ping(); if (async) { // now: fails the first time try { db.Wait(db.ScriptEvaluateAsync(script)); Assert.True(false, "ScriptEvaluateAsync should fail"); } catch (AggregateException ex) { Assert.Single(ex.InnerExceptions); Assert.IsType<RedisServerException>(ex.InnerExceptions[0]); Assert.Equal("NOSCRIPT No matching script. Please use EVAL.", ex.InnerExceptions[0].Message); } } else { // just works; magic Assert.True((bool)db.ScriptEvaluate(script)); } // but gets marked as unloaded, so we can use it again... Assert.True((bool)db.ScriptEvaluate(script)); // which will cause it to be cached Assert.True(server.ScriptExists(script)); } }
public void StreamReadExpectedExceptionNullStreamList() { using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); Assert.Throws <ArgumentNullException>(() => db.StreamRead(null)); } }
public void StreamAddSinglePairWithAutoId() { using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); var messageId = db.StreamAdd(GetUniqueKey("auto_id"), "field1", "value1"); Assert.True(messageId != RedisValue.Null && ((string)messageId).Length > 0); } }
public void StreamReadExpectedExceptionInvalidCountSingleStream() { var key = GetUniqueKey("read_exception_invalid_count_single"); using (var conn = Create()) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Streams), r => r.Streams); var db = conn.GetDatabase(); Assert.Throws <ArgumentOutOfRangeException>(() => db.StreamRead(key, "0-0", 0)); } }
public void CompareScriptToDirect() { const string Script = "return redis.call('incr', KEYS[1])"; using (var conn = Create(allowAdmin: true)) { Skip.IfMissingFeature(conn, nameof(RedisFeatures.Scripting), f => f.Scripting); var server = conn.GetServer(TestConfig.Current.MasterServer, TestConfig.Current.MasterPort); server.FlushAllDatabases(); server.ScriptFlush(); server.ScriptLoad(Script); var db = conn.GetDatabase(); db.Ping(); // k, we're all up to date now; clean db, minimal script cache // we're using a pipeline here, so send 1000 messages, but for timing: only care about the last const int LOOP = 5000; RedisKey key = "foo"; RedisKey[] keys = new[] { key }; // script takes an array // run via script db.KeyDelete(key); CollectGarbage(); var watch = Stopwatch.StartNew(); for (int i = 1; i < LOOP; i++) // the i=1 is to do all-but-one { db.ScriptEvaluate(Script, keys, flags: CommandFlags.FireAndForget); } var scriptResult = db.ScriptEvaluate(Script, keys); // last one we wait for (no F+F) watch.Stop(); TimeSpan scriptTime = watch.Elapsed; // run via raw op db.KeyDelete(key); CollectGarbage(); watch = Stopwatch.StartNew(); for (int i = 1; i < LOOP; i++) // the i=1 is to do all-but-one { db.StringIncrement(key, flags: CommandFlags.FireAndForget); } var directResult = db.StringIncrement(key); // last one we wait for (no F+F) watch.Stop(); TimeSpan directTime = watch.Elapsed; Assert.Equal(LOOP, (long)scriptResult); Assert.Equal(LOOP, directResult); Output.WriteLine("script: {0}ms; direct: {1}ms", scriptTime.TotalMilliseconds, directTime.TotalMilliseconds); } }