From 446270e4ea77de704fdd4a0259558c57c64a7bb2 Mon Sep 17 00:00:00 2001
From: janhavigupta007 <46344506+janhavigupta007@users.noreply.github.com>
Date: Fri, 11 Oct 2024 03:26:41 +0000
Subject: [PATCH] Implementing list commands (#2386)

* Go: Implementing List commands

Signed-off-by: Janhavi Gupta <janhavigupta@google.com>
---
 go/api/base_client.go                |  82 ++++++++
 go/api/command_options.go            |  25 +++
 go/api/list_commands.go              | 194 +++++++++++++++++++
 go/integTest/shared_commands_test.go | 271 ++++++++++++++++++++++++++-
 4 files changed, 571 insertions(+), 1 deletion(-)

diff --git a/go/api/base_client.go b/go/api/base_client.go
index 5347f711f1..39584164ce 100644
--- a/go/api/base_client.go
+++ b/go/api/base_client.go
@@ -513,6 +513,88 @@ func (client *baseClient) RPush(key string, elements []string) (Result[int64], e
 	return handleLongResponse(result)
 }
 
+func (client *baseClient) LRange(key string, start int64, end int64) ([]Result[string], error) {
+	result, err := client.executeCommand(C.LRange, []string{key, utils.IntToString(start), utils.IntToString(end)})
+	if err != nil {
+		return nil, err
+	}
+
+	return handleStringArrayResponse(result)
+}
+
+func (client *baseClient) LIndex(key string, index int64) (Result[string], error) {
+	result, err := client.executeCommand(C.LIndex, []string{key, utils.IntToString(index)})
+	if err != nil {
+		return CreateNilStringResult(), err
+	}
+
+	return handleStringOrNullResponse(result)
+}
+
+func (client *baseClient) LTrim(key string, start int64, end int64) (Result[string], error) {
+	result, err := client.executeCommand(C.LTrim, []string{key, utils.IntToString(start), utils.IntToString(end)})
+	if err != nil {
+		return CreateNilStringResult(), err
+	}
+
+	return handleStringResponse(result)
+}
+
+func (client *baseClient) LLen(key string) (Result[int64], error) {
+	result, err := client.executeCommand(C.LLen, []string{key})
+	if err != nil {
+		return CreateNilInt64Result(), err
+	}
+
+	return handleLongResponse(result)
+}
+
+func (client *baseClient) LRem(key string, count int64, element string) (Result[int64], error) {
+	result, err := client.executeCommand(C.LRem, []string{key, utils.IntToString(count), element})
+	if err != nil {
+		return CreateNilInt64Result(), err
+	}
+
+	return handleLongResponse(result)
+}
+
+func (client *baseClient) RPop(key string) (Result[string], error) {
+	result, err := client.executeCommand(C.RPop, []string{key})
+	if err != nil {
+		return CreateNilStringResult(), err
+	}
+
+	return handleStringOrNullResponse(result)
+}
+
+func (client *baseClient) RPopCount(key string, count int64) ([]Result[string], error) {
+	result, err := client.executeCommand(C.RPop, []string{key, utils.IntToString(count)})
+	if err != nil {
+		return nil, err
+	}
+
+	return handleStringArrayOrNullResponse(result)
+}
+
+func (client *baseClient) LInsert(
+	key string,
+	insertPosition InsertPosition,
+	pivot string,
+	element string,
+) (Result[int64], error) {
+	insertPositionStr, err := insertPosition.toString()
+	if err != nil {
+		return CreateNilInt64Result(), err
+	}
+
+	result, err := client.executeCommand(C.LInsert, []string{key, insertPositionStr, pivot, element})
+	if err != nil {
+		return CreateNilInt64Result(), err
+	}
+
+	return handleLongResponse(result)
+}
+
 func (client *baseClient) Ping() (string, error) {
 	result, err := client.executeCommand(C.Ping, []string{})
 	if err != nil {
diff --git a/go/api/command_options.go b/go/api/command_options.go
index 18e752dbe9..7d37979926 100644
--- a/go/api/command_options.go
+++ b/go/api/command_options.go
@@ -203,3 +203,28 @@ const (
 	RankKeyword   string = "RANK"   // Valkey API keyword use to determine the rank of the match to return.
 	MaxLenKeyword string = "MAXLEN" // Valkey API keyword used to determine the maximum number of list items to compare.
 )
+
+// A InsertPosition defines where to insert new elements into a list.
+//
+// See [valkey.io]
+//
+// [valkey.io]: https://valkey.io/commands/linsert/
+type InsertPosition string
+
+const (
+	// Insert new element before the pivot.
+	Before InsertPosition = "BEFORE"
+	// Insert new element after the pivot.
+	After InsertPosition = "AFTER"
+)
+
+func (insertPosition InsertPosition) toString() (string, error) {
+	switch insertPosition {
+	case Before:
+		return string(Before), nil
+	case After:
+		return string(After), nil
+	default:
+		return "", &RequestError{"Invalid insert position"}
+	}
+}
diff --git a/go/api/list_commands.go b/go/api/list_commands.go
index 6993e56498..f6149f11be 100644
--- a/go/api/list_commands.go
+++ b/go/api/list_commands.go
@@ -192,4 +192,198 @@ type ListCommands interface {
 	//
 	// [valkey.io]: https://valkey.io/commands/rpush/
 	RPush(key string, elements []string) (Result[int64], error)
+
+	// Returns the specified elements of the list stored at key.
+	// The offsets start and end are zero-based indexes, with 0 being the first element of the list, 1 being the next element
+	// and so on. These offsets can also be negative numbers indicating offsets starting at the end of the list, with -1 being
+	// the last element of the list, -2 being the penultimate, and so on.
+	//
+	// See [valkey.io] for details.
+	//
+	// Parameters:
+	//  key   - The key of the list.
+	//  start - The starting point of the range.
+	//  end   - The end of the range.
+	//
+	// Return value:
+	//  Array of elements as Result[string] in the specified range.
+	//  If start exceeds the end of the list, or if start is greater than end, an empty array will be returned.
+	//  If end exceeds the actual end of the list, the range will stop at the actual end of the list.
+	//  If key does not exist an empty array will be returned.
+	//
+	// For example:
+	//  1. result, err := client.LRange("my_list", 0, 2)
+	// result: []api.Result[string]{api.CreateStringResult("value1"), api.CreateStringResult("value2"),
+	// api.CreateStringResult("value3")}
+	//  2. result, err := client.LRange("my_list", -2, -1)
+	//     result: []api.Result[string]{api.CreateStringResult("value2"), api.CreateStringResult("value3")}
+	//  3. result, err := client.LRange("non_existent_key", 0, 2)
+	//     result: []api.Result[string]{}
+	//
+	// [valkey.io]: https://valkey.io/commands/lrange/
+	LRange(key string, start int64, end int64) ([]Result[string], error)
+
+	// Returns the element at index from the list stored at key.
+	// The index is zero-based, so 0 means the first element, 1 the second element and so on. Negative indices can be used to
+	// designate elements starting at the tail of the list. Here, -1 means the last element, -2 means the penultimate and so
+	// forth.
+	//
+	// See [valkey.io] for details.
+	//
+	// Parameters:
+	//  key   - The key of the list.
+	//  index - The index of the element in the list to retrieve.
+	//
+	// Return value:
+	//  The Result[string] containing element at index in the list stored at key.
+	//  If index is out of range or if key does not exist, [api.CreateNilStringResult()] is returned.
+	//
+	// For example:
+	//  1. result, err := client.LIndex("myList", 0)
+	//     result.Value(): "value1" // Returns the first element in the list stored at 'myList'.
+	//     result.IsNil(): false
+	//  2. result, err := client.LIndex("myList", -1)
+	//     result.Value(): "value3" // Returns the last element in the list stored at 'myList'.
+	//     result.IsNil(): false
+	//
+	// [valkey.io]: https://valkey.io/commands/lindex/
+	LIndex(key string, index int64) (Result[string], error)
+
+	// Trims an existing list so that it will contain only the specified range of elements specified.
+	// The offsets start and end are zero-based indexes, with 0 being the first element of the list, 1 being the next element
+	// and so on. These offsets can also be negative numbers indicating offsets starting at the end of the list, with -1 being
+	// the last element of the list, -2 being the penultimate, and so on.
+	//
+	// See [valkey.io] for details.
+	//
+	// Parameters:
+	//  key   - The key of the list.
+	//  start - The starting point of the range.
+	//  end   - The end of the range.
+	//
+	// Return value:
+	//  The Result[string] containing always "OK".
+	// If start exceeds the end of the list, or if start is greater than end, the result will be an empty list (which causes
+	// key to be removed).
+	//  If end exceeds the actual end of the list, it will be treated like the last element of the list.
+	//  If key does not exist, OK will be returned without changes to the database.
+	//
+	// For example:
+	//  result, err := client.LTrim("my_list", 0, 1)
+	//  result.Value(): "OK"
+	//  result.IsNil(): false
+	//
+	// [valkey.io]: https://valkey.io/commands/ltrim/
+	LTrim(key string, start int64, end int64) (Result[string], error)
+
+	// Returns the length of the list stored at key.
+	//
+	// See [valkey.io] for details.
+	//
+	// Parameters:
+	//  key - The key of the list.
+	//
+	// Return value:
+	//  The Result[int64] containing the length of the list at key.
+	//  If key does not exist, it is interpreted as an empty list and 0 is returned.
+	//
+	// For example:
+	//  result, err := client.LLen("my_list")
+	//  result.Value(): int64(3) // Indicates that there are 3 elements in the list.
+	//  result.IsNil(): false
+	//
+	// [valkey.io]: https://valkey.io/commands/llen/
+	LLen(key string) (Result[int64], error)
+
+	// Removes the first count occurrences of elements equal to element from the list stored at key.
+	// If count is positive: Removes elements equal to element moving from head to tail.
+	// If count is negative: Removes elements equal to element moving from tail to head.
+	// If count is 0 or count is greater than the occurrences of elements equal to element, it removes all elements equal to
+	// element.
+	//
+	// See [valkey.io] for details.
+	//
+	// Parameters:
+	//  key     - The key of the list.
+	//  count   - The count of the occurrences of elements equal to element to remove.
+	//  element - The element to remove from the list.
+	//
+	// Return value:
+	//  The Result[int64] containing the number of the removed elements.
+	//  If key does not exist, 0 is returned.
+	//
+	// For example:
+	//  result, err := client.LRem("my_list", 2, "value")
+	//  result.Value(): int64(2)
+	//  result.IsNil(): false
+	//
+	// [valkey.io]: https://valkey.io/commands/lrem/
+	LRem(key string, count int64, element string) (Result[int64], error)
+
+	// Removes and returns the last elements of the list stored at key.
+	// The command pops a single element from the end of the list.
+	//
+	// See [valkey.io] for details.
+	//
+	// Parameters:
+	//  key - The key of the list.
+	//
+	// Return value:
+	//  The Result[string] containing the value of the last element.
+	//  If key does not exist, [api.CreateNilStringResult()] will be returned.
+	//
+	// For example:
+	//  1. result, err := client.RPop("my_list")
+	//     result.Value(): "value1"
+	//     result.IsNil(): false
+	//  2. result, err := client.RPop("non_exiting_key")
+	//     result.Value(): ""
+	//     result.IsNil(): true
+	//
+	// [valkey.io]: https://valkey.io/commands/rpop/
+	RPop(key string) (Result[string], error)
+
+	// Removes and returns up to count elements from the list stored at key, depending on the list's length.
+	//
+	// See [valkey.io] for details.
+	//
+	// Parameters:
+	//  key   - The key of the list.
+	//  count - The count of the elements to pop from the list.
+	//
+	// Return value:
+	//  An array of popped elements as Result[string] will be returned depending on the list's length.
+	//  If key does not exist, nil will be returned.
+	//
+	// For example:
+	//  1. result, err := client.RPopCount("my_list", 2)
+	//     result: []api.Result[string]{api.CreateStringResult("value1"), api.CreateStringResult("value2")}
+	//  2. result, err := client.RPop("non_exiting_key")
+	//     result: nil
+	//
+	// [valkey.io]: https://valkey.io/commands/rpop/
+	RPopCount(key string, count int64) ([]Result[string], error)
+
+	// Inserts element in the list at key either before or after the pivot.
+	//
+	// See [valkey.io] for details.
+	//
+	// Parameters:
+	//  key            - The key of the list.
+	//  insertPosition - The relative position to insert into - either api.Before or api.After the pivot.
+	//  pivot          - An element of the list.
+	//  element        - The new element to insert.
+	//
+	// Return value:
+	//  The Result[int64] containing the list length after a successful insert operation.
+	//  If the key doesn't exist returns -1.
+	//  If the pivot wasn't found, returns 0.
+	//
+	// For example:
+	//  "my_list": {"Hello", "Wprld"}
+	//  result, err := client.LInsert("my_list", api.Before, "World", "There")
+	//  result.Value(): 3
+	//
+	// [valkey.io]: https://valkey.io/commands/linsert/
+	LInsert(key string, insertPosition InsertPosition, pivot string, element string) (Result[int64], error)
 }
diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go
index b5b46c8fd0..a25c9cbe54 100644
--- a/go/integTest/shared_commands_test.go
+++ b/go/integTest/shared_commands_test.go
@@ -1240,9 +1240,278 @@ func (suite *GlideTestSuite) TestRPush() {
 		key2 := uuid.NewString()
 		suite.verifyOK(client.Set(key2, "value"))
 
-		res2, err := client.LPush(key2, []string{"value1"})
+		res2, err := client.RPush(key2, []string{"value1"})
 		assert.Equal(suite.T(), api.CreateNilInt64Result(), res2)
 		assert.NotNil(suite.T(), err)
 		assert.IsType(suite.T(), &api.RequestError{}, err)
 	})
 }
+
+func (suite *GlideTestSuite) TestLRange() {
+	suite.runWithDefaultClients(func(client api.BaseClient) {
+		list := []string{"value4", "value3", "value2", "value1"}
+		key := uuid.NewString()
+
+		res1, err := client.LPush(key, list)
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(4), res1.Value())
+
+		resultList := []api.Result[string]{
+			api.CreateStringResult("value1"),
+			api.CreateStringResult("value2"),
+			api.CreateStringResult("value3"),
+			api.CreateStringResult("value4"),
+		}
+		res2, err := client.LRange(key, int64(0), int64(-1))
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), resultList, res2)
+
+		res3, err := client.LRange("non_existing_key", int64(0), int64(-1))
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), []api.Result[string]{}, res3)
+
+		key2 := uuid.NewString()
+		suite.verifyOK(client.Set(key2, "value"))
+
+		res4, err := client.LRange(key2, int64(0), int64(1))
+		assert.Equal(suite.T(), ([]api.Result[string])(nil), res4)
+		assert.NotNil(suite.T(), err)
+		assert.IsType(suite.T(), &api.RequestError{}, err)
+	})
+}
+
+func (suite *GlideTestSuite) TestLIndex() {
+	suite.runWithDefaultClients(func(client api.BaseClient) {
+		list := []string{"value4", "value3", "value2", "value1"}
+		key := uuid.NewString()
+
+		res1, err := client.LPush(key, list)
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(4), res1.Value())
+
+		res2, err := client.LIndex(key, int64(0))
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), "value1", res2.Value())
+		assert.Equal(suite.T(), false, res2.IsNil())
+
+		res3, err := client.LIndex(key, int64(-1))
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), "value4", res3.Value())
+		assert.Equal(suite.T(), false, res3.IsNil())
+
+		res4, err := client.LIndex("non_existing_key", int64(0))
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), api.CreateNilStringResult(), res4)
+
+		key2 := uuid.NewString()
+		suite.verifyOK(client.Set(key2, "value"))
+
+		res5, err := client.LIndex(key2, int64(0))
+		assert.Equal(suite.T(), api.CreateNilStringResult(), res5)
+		assert.NotNil(suite.T(), err)
+		assert.IsType(suite.T(), &api.RequestError{}, err)
+	})
+}
+
+func (suite *GlideTestSuite) TestLTrim() {
+	suite.runWithDefaultClients(func(client api.BaseClient) {
+		list := []string{"value4", "value3", "value2", "value1"}
+		key := uuid.NewString()
+
+		res1, err := client.LPush(key, list)
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(4), res1.Value())
+
+		suite.verifyOK(client.LTrim(key, int64(0), int64(1)))
+
+		res2, err := client.LRange(key, int64(0), int64(-1))
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), []api.Result[string]{api.CreateStringResult("value1"), api.CreateStringResult("value2")}, res2)
+
+		suite.verifyOK(client.LTrim(key, int64(4), int64(2)))
+
+		res3, err := client.LRange(key, int64(0), int64(-1))
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), []api.Result[string]{}, res3)
+
+		key2 := uuid.NewString()
+		suite.verifyOK(client.Set(key2, "value"))
+
+		res4, err := client.LIndex(key2, int64(0))
+		assert.Equal(suite.T(), api.CreateNilStringResult(), res4)
+		assert.NotNil(suite.T(), err)
+		assert.IsType(suite.T(), &api.RequestError{}, err)
+	})
+}
+
+func (suite *GlideTestSuite) TestLLen() {
+	suite.runWithDefaultClients(func(client api.BaseClient) {
+		list := []string{"value4", "value3", "value2", "value1"}
+		key := uuid.NewString()
+
+		res1, err := client.LPush(key, list)
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(4), res1.Value())
+
+		res2, err := client.LLen(key)
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(4), res2.Value())
+		assert.Equal(suite.T(), false, res2.IsNil())
+
+		res3, err := client.LLen("non_existing_key")
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(0), res3.Value())
+		assert.Equal(suite.T(), false, res3.IsNil())
+
+		key2 := uuid.NewString()
+		suite.verifyOK(client.Set(key2, "value"))
+
+		res4, err := client.LLen(key2)
+		assert.Equal(suite.T(), api.CreateNilInt64Result(), res4)
+		assert.NotNil(suite.T(), err)
+		assert.IsType(suite.T(), &api.RequestError{}, err)
+	})
+}
+
+func (suite *GlideTestSuite) TestLRem() {
+	suite.runWithDefaultClients(func(client api.BaseClient) {
+		list := []string{"value1", "value2", "value1", "value1", "value2"}
+		key := uuid.NewString()
+
+		res1, err := client.LPush(key, list)
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(5), res1.Value())
+
+		res2, err := client.LRem(key, 2, "value1")
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(2), res2.Value())
+		assert.Equal(suite.T(), false, res2.IsNil())
+		res3, err := client.LRange(key, int64(0), int64(-1))
+		assert.Nil(suite.T(), err)
+		assert.Equal(
+			suite.T(),
+			[]api.Result[string]{
+				api.CreateStringResult("value2"),
+				api.CreateStringResult("value2"),
+				api.CreateStringResult("value1"),
+			},
+			res3,
+		)
+
+		res4, err := client.LRem(key, -1, "value2")
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(1), res4.Value())
+		assert.Equal(suite.T(), false, res4.IsNil())
+		res5, err := client.LRange(key, int64(0), int64(-1))
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), []api.Result[string]{api.CreateStringResult("value2"), api.CreateStringResult("value1")}, res5)
+
+		res6, err := client.LRem(key, 0, "value2")
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(1), res6.Value())
+		assert.Equal(suite.T(), false, res6.IsNil())
+		res7, err := client.LRange(key, int64(0), int64(-1))
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), []api.Result[string]{api.CreateStringResult("value1")}, res7)
+
+		res8, err := client.LRem("non_existing_key", 0, "value")
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(0), res8.Value())
+		assert.Equal(suite.T(), false, res8.IsNil())
+	})
+}
+
+func (suite *GlideTestSuite) TestRPopAndRPopCount() {
+	suite.runWithDefaultClients(func(client api.BaseClient) {
+		list := []string{"value1", "value2", "value3", "value4"}
+		key := uuid.NewString()
+
+		res1, err := client.RPush(key, list)
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(4), res1.Value())
+
+		res2, err := client.RPop(key)
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), "value4", res2.Value())
+		assert.Equal(suite.T(), false, res2.IsNil())
+
+		res3, err := client.RPopCount(key, int64(2))
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), []api.Result[string]{api.CreateStringResult("value3"), api.CreateStringResult("value2")}, res3)
+
+		res4, err := client.RPop("non_existing_key")
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), api.CreateNilStringResult(), res4)
+
+		res5, err := client.RPopCount("non_existing_key", int64(2))
+		assert.Equal(suite.T(), ([]api.Result[string])(nil), res5)
+		assert.Nil(suite.T(), err)
+
+		key2 := uuid.NewString()
+		suite.verifyOK(client.Set(key2, "value"))
+
+		res6, err := client.RPop(key2)
+		assert.Equal(suite.T(), api.CreateNilStringResult(), res6)
+		assert.NotNil(suite.T(), err)
+		assert.IsType(suite.T(), &api.RequestError{}, err)
+
+		res7, err := client.RPopCount(key2, int64(2))
+		assert.Equal(suite.T(), ([]api.Result[string])(nil), res7)
+		assert.NotNil(suite.T(), err)
+		assert.IsType(suite.T(), &api.RequestError{}, err)
+	})
+}
+
+func (suite *GlideTestSuite) TestLInsert() {
+	suite.runWithDefaultClients(func(client api.BaseClient) {
+		list := []string{"value1", "value2", "value3", "value4"}
+		key := uuid.NewString()
+
+		res1, err := client.RPush(key, list)
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(4), res1.Value())
+
+		res2, err := client.LInsert(key, api.Before, "value2", "value1.5")
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(5), res2.Value())
+		assert.Equal(suite.T(), false, res2.IsNil())
+
+		res3, err := client.LInsert(key, api.After, "value3", "value3.5")
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(6), res3.Value())
+		assert.Equal(suite.T(), false, res3.IsNil())
+
+		res4, err := client.LRange(key, int64(0), int64(-1))
+		assert.Nil(suite.T(), err)
+		assert.Equal(
+			suite.T(),
+			[]api.Result[string]{
+				api.CreateStringResult("value1"),
+				api.CreateStringResult("value1.5"),
+				api.CreateStringResult("value2"),
+				api.CreateStringResult("value3"),
+				api.CreateStringResult("value3.5"),
+				api.CreateStringResult("value4"),
+			},
+			res4,
+		)
+
+		res5, err := client.LInsert("non_existing_key", api.Before, "pivot", "elem")
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(0), res5.Value())
+		assert.Equal(suite.T(), false, res5.IsNil())
+
+		res6, err := client.LInsert(key, api.Before, "value5", "value6")
+		assert.Nil(suite.T(), err)
+		assert.Equal(suite.T(), int64(-1), res6.Value())
+		assert.Equal(suite.T(), false, res6.IsNil())
+
+		key2 := uuid.NewString()
+		suite.verifyOK(client.Set(key2, "value"))
+
+		res7, err := client.LInsert(key2, api.Before, "value5", "value6")
+		assert.Equal(suite.T(), api.CreateNilInt64Result(), res7)
+		assert.NotNil(suite.T(), err)
+		assert.IsType(suite.T(), &api.RequestError{}, err)
+	})
+}