Skip to content

Commit

Permalink
Applying some fixes to PR
Browse files Browse the repository at this point in the history
  • Loading branch information
TalZaccai committed May 28, 2024
1 parent 79fbbd2 commit 3ffd1aa
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 74 deletions.
25 changes: 11 additions & 14 deletions libs/client/GarnetClientAPI/GarnetClientListCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

Expand Down Expand Up @@ -42,22 +43,20 @@ public void ListLeftPush(string key, string element, Action<long, long, string>
/// <param name="elements">The elements to be added.</param>
/// <param name="callback">The callback function when operation completes.</param>
/// <param name="context">An optional context to correlate request to callback.</param>
public void ListLeftPush(string key, List<string> elements, Action<long, long, string> callback, long context = 0)
public void ListLeftPush(string key, IEnumerable<string> elements, Action<long, long, string> callback, long context = 0)
{
ArgumentNullException.ThrowIfNull(key);
ArgumentNullException.ThrowIfNull(elements);
ArgumentNullException.ThrowIfNull(callback);

if (elements.Count == 0)
var arrElem = new[] { key }.Union(elements).ToArray();

if (arrElem.Length == 1)
{
throw new ArgumentException("The elements can't be empty.", nameof(elements));
}

elements.Insert(0, key);

ExecuteForLongResult(callback, context, nameof(LPUSH), elements);

elements.RemoveAt(0);
ExecuteForLongResult(callback, context, nameof(LPUSH), arrElem);
}

/// <summary>
Expand Down Expand Up @@ -110,22 +109,20 @@ public void ListRightPush(string key, string element, Action<long, long, string>
/// <param name="elements">The elements to be added.</param>
/// <param name="callback">The callback function when operation completes.</param>
/// <param name="context">An optional context to correlate request to callback.</param>
public void ListRightPush(string key, List<string> elements, Action<long, long, string> callback, long context = 0)
public void ListRightPush(string key, IEnumerable<string> elements, Action<long, long, string> callback, long context = 0)
{
ArgumentNullException.ThrowIfNull(key);
ArgumentNullException.ThrowIfNull(elements);
ArgumentNullException.ThrowIfNull(callback);

if (elements.Count == 0)
var arrElem = new[] { key }.Union(elements).ToArray();

if (arrElem.Length == 1)
{
throw new ArgumentException("The elements can't be empty.", nameof(elements));
}

elements.Insert(0, key);

ExecuteForLongResult(callback, context, nameof(RPUSH), elements);

elements.RemoveAt(0);
ExecuteForLongResult(callback, context, nameof(RPUSH), arrElem);
}

/// <summary>
Expand Down
147 changes: 87 additions & 60 deletions test/Garnet.test/RespListGarnetClientTests.cs
Original file line number Diff line number Diff line change
@@ -1,138 +1,165 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Garnet.client;
using NUnit.Framework;
using StackExchange.Redis;

namespace Garnet.test
{
[TestFixture]
public class RespListGarnetClientTests
{
private GarnetServer _server;
private GarnetServer server;

[OneTimeSetUp]
public void Setup()
{
TestUtils.DeleteDirectory(TestUtils.MethodTestDir, wait: true);
_server = TestUtils.CreateGarnetServer(TestUtils.MethodTestDir, lowMemory: true);
_server.Start();
server = TestUtils.CreateGarnetServer(TestUtils.MethodTestDir, lowMemory: true);
server.Start();
}

private static object[] LeftPushTestCases =
[
new object[] { "list1", new [] { "foo" }, new [] { "foo" } },
new object[] { "list2", new [] { "foo", "baz" }, new [] { "baz", "foo" } },
new object[] { "list1", new [] { "bar", "baz" }, new [] { "baz", "bar", "foo" } },
new object[] { "list3", new [] { "foo", "bar", "baz" }, new [] { "baz", "bar", "foo" } },
new object[] { "list2", new [] { "foo", "bar", "baz" }, new[] { "baz", "bar", "foo", "baz", "foo" } }
];

private static object[] RightPushTestCases =
[
new object[] { "list1", new [] { "foo" }, new [] { "foo" } },
new object[] { "list2", new [] { "foo", "baz" }, new [] { "foo", "baz" } },
new object[] { "list1", new [] { "bar", "baz" }, new [] { "foo", "bar", "baz" } },
new object[] { "list3", new [] { "foo", "bar", "baz" }, new [] { "foo", "bar", "baz" } },
new object[] { "list2", new [] { "foo", "bar", "baz" }, new[] { "foo", "baz", "foo", "bar", "baz" } }
];

private static string GetTestKey(string key)
{
var testName = TestContext.CurrentContext.Test.MethodName;
return $"{testName}_{key}";
}

[Test]
public void AddElementsToTheListHead_WithCallback()
[TestCaseSource(nameof(LeftPushTestCases))]

public void AddElementsToTheListHead_WithCallback(string key, string[] elements, string[] expectedList)
{
// Arrange
using var db = new GarnetClient(TestUtils.Address, TestUtils.Port);
db.Connect();

ManualResetEventSlim e = new();
using ManualResetEventSlim e = new();

// Act & Assert
db.ListLeftPush("list1", "foo", (_, returnValue, _) =>
{
Assert.AreEqual(1, returnValue);
e.Set();
});
var isResultSet = false;
var actualListLength = 0L;

e.Wait();
e.Reset();
// Act & Assert
var testKey = GetTestKey(key);

db.ListLeftPush("list1", ["bar", "baz"], (_, returnValue, _) =>
db.ListLeftPush(testKey, elements, (_, returnValue, _) =>
{
Assert.AreEqual(3, returnValue);
actualListLength = returnValue;
isResultSet = true;
e.Set();
});

e.Wait();
e.Reset();

db.ListLeftPush("list2", ["foo", "baz"], (_, returnValue, _) =>
{
Assert.AreEqual(2, returnValue);
e.Set();
});
Assert.IsTrue(isResultSet);
Assert.AreEqual(expectedList.Length, actualListLength);

e.Wait();
e.Reset();
e.Dispose();
ValidateListContent(testKey, expectedList);
}

[Test]
[TestCase("list3", new string[] { "foo", "bar" }, 2)]
[TestCase("list4", new string[] { "foo", "bar", "baz" }, 3)]
[TestCase("list3", new string[] { "baz" }, 3)]
[TestCase("list5", new string[] { "foo" }, 1)]
public async Task AddElementsToTheListHead_ReturnsListItemsCount(string key, string[] elements, int result)
[TestCaseSource(nameof(LeftPushTestCases))]
public async Task AddElementsToTheListHead_WithAsync(string key, string[] elements, string[] expectedList)
{
// Arrange
using var db = new GarnetClient(TestUtils.Address, TestUtils.Port);
await db.ConnectAsync();

// Act & Assert
Assert.AreEqual(result, await db.ListLeftPushAsync(key, elements));
var testKey = GetTestKey(key);

var actualListLength = await db.ListLeftPushAsync(testKey, elements);
Assert.AreEqual(expectedList.Length, actualListLength);

ValidateListContent(testKey, expectedList);
}

[Test]
public void AddElementsToListTail_WithCallback()
[TestCaseSource(nameof(RightPushTestCases))]
public void AddElementsToListTail_WithCallback(string key, string[] elements, string[] expectedList)
{
// Arrange
using var db = new GarnetClient(TestUtils.Address, TestUtils.Port);
db.Connect();

ManualResetEventSlim e = new();
using ManualResetEventSlim e = new();

// Act & Assert
db.ListRightPush("list6", "foo", (_, returnValue, _) =>
{
Assert.AreEqual(1, returnValue);
e.Set();
});
var isResultSet = false;
var actualListLength = 0L;

e.Wait();
e.Reset();
// Act & Assert
var testKey = GetTestKey(key);

db.ListRightPush("list6", ["bar", "baz"], (_, returnValue, _) =>
db.ListRightPush(testKey, elements, (_, returnValue, _) =>
{
Assert.AreEqual(3, returnValue);
actualListLength = returnValue;
isResultSet = true;
e.Set();
});

e.Wait();
e.Reset();

db.ListRightPush("list7", ["foo", "baz"], (_, returnValue, _) =>
{
Assert.AreEqual(2, returnValue);
e.Set();
});
Assert.IsTrue(isResultSet);
Assert.AreEqual(expectedList.Length, actualListLength);

e.Wait();
e.Reset();
e.Dispose();
ValidateListContent(testKey, expectedList);
}

[Test]
[TestCase("list8", new string[] { "foo", "bar" }, 2)]
[TestCase("list9", new string[] { "foo", "bar", "baz" }, 3)]
[TestCase("list8", new string[] { "baz" }, 3)]
[TestCase("list10", new string[] { "foo" }, 1)]
public async Task AddElementsToTheListTail_ReturnsListItemsCount(string key, string[] elements, int result)
[TestCaseSource(nameof(RightPushTestCases))]
public async Task AddElementsToTheListTail_WithAsync(string key, string[] elements, string[] expectedList)
{
// Arrange
using var db = new GarnetClient(TestUtils.Address, TestUtils.Port);
await db.ConnectAsync();

// Act & Assert
Assert.AreEqual(result, await db.ListRightPushAsync(key, elements));
var testKey = GetTestKey(key);

var actualListLength = await db.ListRightPushAsync(testKey, elements.ToArray());
Assert.AreEqual(expectedList.Length, actualListLength);

ValidateListContent(testKey, expectedList);
}

private void ValidateListContent(string key, string[] expectedList)
{
// Using SE.Redis client to validate list content since Garnet client doesn't yet support LRANGE
using var redis = ConnectionMultiplexer.Connect(TestUtils.GetConfig());
var db = redis.GetDatabase(0);

var actualElements = db.ListRange(key);
Assert.AreEqual(expectedList.Length, actualElements.Length);
for (var i = 0; i < actualElements.Length; i++)
{
Assert.AreEqual(expectedList[i], actualElements[i].ToString());
}
}

[OneTimeTearDown]
public void TearDown()
{
_server.Dispose();
server.Dispose();

TestUtils.DeleteDirectory(TestUtils.MethodTestDir);
}
Expand Down

0 comments on commit 3ffd1aa

Please sign in to comment.