diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 07527aa..4b28d5e 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -9,6 +9,12 @@ jobs:
runs-on: ${{ matrix.os }}
permissions:
contents: write
+ services:
+ memcached:
+ image: memcached:latest
+ ports:
+ - 11211:11211
+ options: --entrypoint=""
strategy:
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
@@ -30,7 +36,7 @@ jobs:
uses: tj-actions/coverage-badge-go@v1
if: ${{ runner.os == 'linux' }}
with:
- green: 80
+ green: 70
filename: coverage.out
- uses: stefanzweifel/git-auto-commit-action@v5
diff --git a/README.md b/README.md
index c3339c6..83b83af 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
# Gomemcached
+
---
diff --git a/consistenthash/hashring_test.go b/consistenthash/hashring_test.go
index 9ba672f..7d31f77 100644
--- a/consistenthash/hashring_test.go
+++ b/consistenthash/hashring_test.go
@@ -30,13 +30,16 @@ func BenchmarkHashRingGet(b *testing.B) {
func TestHashRing_GetAllNodes(t *testing.T) {
ch := NewHashRing()
+ allNodes := ch.GetAllNodes()
+ assert.Nil(t, allNodes, "GetAllNodes: without added nodes")
+
for i := 0; i < keySize; i++ {
ch.Add("localhost:" + strconv.Itoa(i))
}
count := ch.GetNodesCount()
assert.Equalf(t, keySize, count, "GetNodesCount: have - %d; want - %d", count, keySize)
- allNodes := ch.GetAllNodes()
+ allNodes = ch.GetAllNodes()
assert.Equal(t, keySize, len(allNodes))
for i := 0; i < keySize; i++ {
diff --git a/memcached/constants_test.go b/memcached/constants_test.go
index d25c065..4ea6a4e 100644
--- a/memcached/constants_test.go
+++ b/memcached/constants_test.go
@@ -4,6 +4,8 @@ package memcached
import (
"strings"
"testing"
+
+ "github.com/stretchr/testify/assert"
)
func TestCommandCodeString(t *testing.T) {
@@ -38,3 +40,113 @@ func TestIsQuiet(t *testing.T) {
}
}
}
+
+func Test_prepareAuthData(t *testing.T) {
+ type args struct {
+ user string
+ pass string
+ }
+ tests := []struct {
+ name string
+ args args
+ want []byte
+ }{
+ {
+ name: "1", args: args{
+ user: "testuser",
+ pass: "testpass",
+ },
+ want: []byte("\x00testuser\x00testpass"),
+ },
+ {
+ name: "2", args: args{
+ user: "anotheruser",
+ pass: "anotherpass",
+ },
+ want: []byte("\x00anotheruser\x00anotherpass"),
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want, prepareAuthData(tt.args.user, tt.args.pass), "prepareAuthData(%v, %v)", tt.args.user, tt.args.pass)
+ })
+ }
+}
+
+func TestOpCode_changeOnQuiet(t *testing.T) {
+ type args struct {
+ def OpCode
+ }
+ tests := []struct {
+ name string
+ o OpCode
+ args args
+ want OpCode
+ }{
+ {
+ name: GET.String(),
+ o: GET,
+ args: args{def: GETQ},
+ want: GETQ,
+ },
+ {
+ name: SET.String(),
+ o: SET,
+ args: args{def: GETQ},
+ want: SETQ,
+ },
+ {
+ name: ADD.String(),
+ o: ADD,
+ args: args{def: GETQ},
+ want: ADDQ,
+ },
+ {
+ name: REPLACE.String(),
+ o: REPLACE,
+ args: args{def: GETQ},
+ want: REPLACEQ,
+ },
+ {
+ name: DELETE.String(),
+ o: DELETE,
+ args: args{def: GETQ},
+ want: DELETEQ,
+ },
+ {
+ name: INCREMENT.String(),
+ o: INCREMENT,
+ args: args{def: GETQ},
+ want: INCREMENTQ,
+ },
+ {
+ name: DECREMENT.String(),
+ o: DECREMENT,
+ args: args{def: GETQ},
+ want: DECREMENTQ,
+ },
+ {
+ name: FLUSH.String(),
+ o: FLUSH,
+ args: args{def: GETQ},
+ want: FLUSHQ,
+ },
+ {
+ name: APPEND.String(),
+ o: APPEND,
+ args: args{def: GETQ},
+ want: APPENDQ,
+ },
+ {
+ name: PREPEND.String(),
+ o: PREPEND,
+ args: args{def: GETQ},
+ want: PREPENDQ,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want, tt.o.changeOnQuiet(tt.args.def), "changeOnQuiet(%v)", tt.args.def)
+ })
+ }
+}
diff --git a/memcached/options_test.go b/memcached/options_test.go
new file mode 100644
index 0000000..23588cb
--- /dev/null
+++ b/memcached/options_test.go
@@ -0,0 +1,50 @@
+package memcached
+
+import (
+ "os"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+
+ "github.com/aliexpressru/gomemcached/consistenthash"
+)
+
+func TestWithOptions(t *testing.T) {
+ const (
+ maxIdleConns = 10
+ disable = true
+ enable
+ authUser = "admin"
+ authPass = "password"
+ timeout = 5 * time.Second
+ period = time.Second
+ )
+
+ hr := consistenthash.NewCustomHashRing(1, nil)
+ os.Setenv("MEMCACHED_SERVERS", "localhost:11211")
+ mcl, _ := InitFromEnv(
+ WithMaxIdleConns(maxIdleConns),
+ WithTimeout(timeout),
+ WithCustomHashRing(hr),
+ WithPeriodForNodeHealthCheck(period),
+ WithPeriodForRebuildingNodes(period),
+ WithDisableNodeProvider(),
+ WithDisableRefreshConnsInPool(),
+ WithDisableMemcachedDiagnostic(),
+ WithAuthentication(authUser, authPass),
+ )
+ t.Cleanup(func() {
+ mcl.CloseAllConns()
+ })
+
+ assert.Equal(t, maxIdleConns, mcl.maxIdleConns, "WithMaxIdleConns should set maxIdleConns")
+ assert.Equal(t, timeout, mcl.timeout, "WithTimeout should set timeout")
+ assert.Equal(t, hr, mcl.hr, "WithCustomHashRing should set hr")
+ assert.Equal(t, period, mcl.nodeHCPeriod, "WithPeriodForNodeHealthCheck should set period")
+ assert.Equal(t, period, mcl.nodeRBPeriod, "WithPeriodForRebuildingNodes should set period")
+ assert.Equal(t, disable, mcl.disableNodeProvider, "WithDisableNodeProvider should set disable")
+ assert.Equal(t, disable, mcl.disableRefreshConns, "WithDisableRefreshConnsInPool should set disable")
+ assert.Equal(t, disable, mcl.disableMemcachedDiagnostic, "WithDisableMemcachedDiagnostic should set disable")
+ assert.Equal(t, enable, mcl.authEnable, "WithAuthentication should set enable")
+}
diff --git a/memcached/requests_test.go b/memcached/requests_test.go
index 5812c21..2ae4a0f 100644
--- a/memcached/requests_test.go
+++ b/memcached/requests_test.go
@@ -364,3 +364,90 @@ func BenchmarkReceiveRequestNoBuf(b *testing.B) {
}
}
}
+
+func TestRequest_prepareExtras(t *testing.T) {
+ type fields struct {
+ Opcode OpCode
+ }
+ type args struct {
+ expiration uint32
+ delta uint64
+ initVal uint64
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ expect []byte
+ }{
+ {
+ name: "GET must not have extras",
+ fields: fields{
+ Opcode: GET,
+ },
+ args: args{
+ expiration: 256,
+ delta: 1,
+ initVal: 1,
+ },
+ expect: nil,
+ },
+ {
+ name: "SET",
+ fields: fields{
+ Opcode: SET,
+ },
+ args: args{
+ expiration: 256,
+ delta: 1,
+ initVal: 1,
+ },
+ expect: []byte{
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00,
+ },
+ },
+ {
+ name: "INCREMENT",
+ fields: fields{
+ Opcode: INCREMENT,
+ },
+ args: args{
+ expiration: 256,
+ delta: 1,
+ initVal: 42,
+ },
+ expect: []byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a,
+ 0x00, 0x00, 0x01, 0x00,
+ },
+ },
+ {
+ name: "FLUSH",
+ fields: fields{
+ Opcode: FLUSH,
+ },
+ args: args{
+ expiration: 256,
+ delta: 0,
+ initVal: 0,
+ },
+ expect: []byte{
+ 0x00, 0x00, 0x01, 0x00,
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := &Request{
+ Opcode: tt.fields.Opcode,
+ }
+ r.prepareExtras(tt.args.expiration, tt.args.delta, tt.args.initVal)
+
+ if !bytes.Equal(r.Extras, tt.expect) {
+ t.Fatalf("Expected %#v == %#v", r.Extras, tt.expect)
+ }
+ })
+ }
+}