Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: golangci-lint
on:
push:
paths:
- "go.sum"
- "go.mod"
- "**.go"
- ".github/workflows/golangci-lint.yml"
- ".golangci.yml"
pull_request:

permissions: # added using https://github.com/step-security/secure-repo
contents: read

jobs:
golangci:
permissions:
contents: read # for actions/checkout to fetch code
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
name: lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Install Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: 1.24.x
- name: Lint
uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0
with:
args: --verbose
version: v2.0.2
29 changes: 29 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
version: "2"
run:
timeout: 15m
output:
show-stats: false

formatters:
enable:
- gci
- gofumpt
settings:
gci:
sections:
- standard
- default
gofumpt:
extra-rules: true

issues:
max-issues-per-linter: 0
max-same-issues: 0

linters:
# Keep this list sorted alphabetically
disable:
# TODO: Cleanup errcheck issues.
- errcheck
enable:
- revive
6 changes: 2 additions & 4 deletions memcache/fakeserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,8 @@ func (c *testConn) handleRequestLine(line string) bool {
if noReply == "" {
if ok {
return c.reply("TOUCHED")
} else {
return c.reply("NOT_FOUND")
}
return c.reply("NOT_FOUND")
}
return true
}
Expand All @@ -163,7 +162,7 @@ func (c *testConn) handleRequestLine(line string) bool {
flags, _ := strconv.ParseUint(flagsStr, 10, 32)
exptimeVal, _ := strconv.ParseInt(exptimeStr, 10, 64)
itemLen, _ := strconv.ParseInt(lenStr, 10, 32)
//log.Printf("got %q flags=%q exp=%d %d len=%d cas=%q noreply=%q", verb, key, flags, exptimeVal, itemLen, casUniq, noReply)
// log.Printf("got %q flags=%q exp=%d %d len=%d cas=%q noreply=%q", verb, key, flags, exptimeVal, itemLen, casUniq, noReply)
if c.s.m == nil {
c.s.m = make(map[string]serverItem)
}
Expand Down Expand Up @@ -274,7 +273,6 @@ func (c *testConn) handleRequestLine(line string) bool {
}

return false

}

func computeExpTime(n int64) time.Time {
Expand Down
12 changes: 6 additions & 6 deletions memcache/memcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,14 @@ var (
// CompareAndSwap) failed because the condition was not satisfied.
ErrNotStored = errors.New("memcache: item not stored")

// ErrServer means that a server error occurred.
// ErrServerError means that a server error occurred.
ErrServerError = errors.New("memcache: server error")

// ErrNoStats means that no statistics were available.
ErrNoStats = errors.New("memcache: no statistics available")

// ErrMalformedKey is returned when an invalid key is used.
// Keys must be at maximum 250 bytes long and not
// contain whitespace or control characters.
ErrMalformedKey = errors.New("malformed: key is too long or contains invalid characters")

// ErrNoServers is returned when no servers are configured or available.
Expand Down Expand Up @@ -101,7 +100,6 @@ func legalKey(key string) bool {

var (
crlf = []byte("\r\n")
space = []byte(" ")
resultOK = []byte("OK\r\n")
resultStored = []byte("STORED\r\n")
resultNotStored = []byte("NOT_STORED\r\n")
Expand Down Expand Up @@ -326,6 +324,7 @@ func (c *Client) onItem(item *Item, fn func(*Client, *bufio.ReadWriter, *Item) e
return nil
}

// FlushAll send the flush_all command.
func (c *Client) FlushAll() error {
return c.selector.Each(c.flushAllFromAddr)
}
Expand Down Expand Up @@ -460,7 +459,8 @@ func (c *Client) touchFromAddr(addr net.Addr, keys []string, expiration int32) e
}
switch {
case bytes.Equal(line, resultTouched):
break
// TODO: SA4011: ineffective break statement. Did you mean to break out of the outer loop?
break //nolint:staticcheck
case bytes.Equal(line, resultNotFound):
return ErrCacheMiss
default:
Expand Down Expand Up @@ -504,7 +504,7 @@ func (c *Client) GetMulti(keys []string) (map[string]*Item, error) {
}

var err error
for _ = range keyMap {
for range keyMap {
if ge := <-ch; ge != nil {
err = ge
}
Expand Down Expand Up @@ -750,7 +750,7 @@ func (c *Client) DeleteAll() error {
})
}

// Get and Touch the item with the provided key. The error ErrCacheMiss is
// GetAndTouch Get and Touch the item with the provided key. The error ErrCacheMiss is
// returned if the item didn't already exist in the cache.
func (c *Client) GetAndTouch(key string, expiration int32) (item *Item, err error) {
err = c.withKeyAddr(key, func(addr net.Addr) error {
Expand Down
101 changes: 63 additions & 38 deletions memcache/memcache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ func TestTLS(t *testing.T) {
}
t.Logf("version: %s", bytes.TrimSpace(out))

if err := os.WriteFile(filepath.Join(td, "/cert.pem"), LocalhostCert, 0644); err != nil {
if err := os.WriteFile(filepath.Join(td, "/cert.pem"), LocalhostCert, 0o644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(td, "/key.pem"), LocalhostKey, 0644); err != nil {
if err := os.WriteFile(filepath.Join(td, "/key.pem"), LocalhostKey, 0o644); err != nil {
t.Fatal(err)
}

Expand Down Expand Up @@ -155,7 +155,6 @@ func TestTLS(t *testing.T) {
InsecureSkipVerify: true,
}
return td.DialContext(ctx, network, addr)

}
testWithClient(t, c)
}
Expand Down Expand Up @@ -248,16 +247,16 @@ func testWithClient(t *testing.T, c *Client) {
}

// Append
append := &Item{Key: "append", Value: []byte("appendval")}
if err := c.Append(append); err != ErrNotStored {
appendItem := &Item{Key: "append", Value: []byte("appendval")}
if err := c.Append(appendItem); err != ErrNotStored {
t.Fatalf("first append(append) want ErrNotStored, got %v", err)
}
c.Set(append)
c.Set(appendItem)
err = c.Append(&Item{Key: "append", Value: []byte("1")})
checkErr(err, "second append(append): %v", err)
appended, err := c.Get("append")
checkErr(err, "third append(append): %v", err)
if string(appended.Value) != string(append.Value)+"1" {
if string(appended.Value) != string(appendItem.Value)+"1" {
t.Fatalf("Append: want=append1, got=%s", string(appended.Value))
}

Expand Down Expand Up @@ -305,7 +304,7 @@ func testWithClient(t *testing.T, c *Client) {
// Delete
err = c.Delete("foo")
checkErr(err, "Delete: %v", err)
it, err = c.Get("foo")
_, err = c.Get("foo")
if err != ErrCacheMiss {
t.Errorf("post-Delete want ErrCacheMiss, got %v", err)
}
Expand All @@ -324,12 +323,12 @@ func testWithClient(t *testing.T, c *Client) {
}
err = c.Delete("num")
checkErr(err, "delete num: %v", err)
n, err = c.Increment("num", 1)
_, err = c.Increment("num", 1)
if err != ErrCacheMiss {
t.Fatalf("increment post-delete: want ErrCacheMiss, got %v", err)
}
mustSet(&Item{Key: "num", Value: []byte("not-numeric")})
n, err = c.Increment("num", 1)
_, err = c.Increment("num", 1)
if err == nil || !strings.Contains(err.Error(), "client error") {
t.Fatalf("increment non-number: want client error, got %v", err)
}
Expand All @@ -338,7 +337,7 @@ func testWithClient(t *testing.T, c *Client) {
// Test Delete All
err = c.DeleteAll()
checkErr(err, "DeleteAll: %v", err)
it, err = c.Get("bar")
_, err = c.Get("bar")
if err != ErrCacheMiss {
t.Errorf("post-DeleteAll want ErrCacheMiss, got %v", err)
}
Expand Down Expand Up @@ -387,7 +386,7 @@ func testTouchWithClient(t *testing.T, c *Client) {

_, err = c.Get("bar")
if err == nil {
t.Fatalf("item bar did not expire within %v seconds", time.Now().Sub(setTime).Seconds())
t.Fatalf("item bar did not expire within %v seconds", time.Since(setTime).Seconds())
} else {
if err != ErrCacheMiss {
t.Fatalf("unexpected error retrieving bar: %v", err.Error())
Expand Down Expand Up @@ -446,32 +445,58 @@ func TestScanGetResponseLine(t *testing.T) {
wantSize int
wantErr bool
}{
{name: "blank", line: "",
wantErr: true},
{name: "malformed1", line: "VALU foobar1234 1 4096\r\n",
wantErr: true},
{name: "malformed2", line: "VALUEfoobar1234 1 4096\r\n",
wantErr: true},
{name: "malformed3", line: "VALUE foobar1234 14096\r\n",
wantErr: true},
{name: "malformed4", line: "VALUE foobar123414096\r\n",
wantErr: true},
{name: "no-eol", line: "VALUE foobar1234 1 4096",
wantErr: true},
{name: "basic", line: "VALUE foobar1234 1 4096\r\n",
wantKey: "foobar1234", wantFlags: 1, wantSize: 4096},
{name: "casid", line: "VALUE foobar1234 1 4096 1234\r\n",
wantKey: "foobar1234", wantFlags: 1, wantSize: 4096, wantCasid: 1234},
{name: "flags-max-uint32", line: "VALUE key 4294967295 1\r\n",
wantKey: "key", wantFlags: 4294967295, wantSize: 1},
{name: "flags-overflow", line: "VALUE key 4294967296 1\r\n",
wantErr: true},
{name: "size-max-uint32", line: "VALUE key 1 2147483647\r\n",
wantKey: "key", wantFlags: 1, wantSize: 2147483647},
{name: "size-overflow", line: "VALUE key 1 4294967296\r\n",
wantErr: true},
{name: "casid-overflow", line: "VALUE key 1 4096 18446744073709551616\r\n",
wantErr: true},
{
name: "blank", line: "",
wantErr: true,
},
{
name: "malformed1", line: "VALU foobar1234 1 4096\r\n",
wantErr: true,
},
{
name: "malformed2", line: "VALUEfoobar1234 1 4096\r\n",
wantErr: true,
},
{
name: "malformed3", line: "VALUE foobar1234 14096\r\n",
wantErr: true,
},
{
name: "malformed4", line: "VALUE foobar123414096\r\n",
wantErr: true,
},
{
name: "no-eol", line: "VALUE foobar1234 1 4096",
wantErr: true,
},
{
name: "basic", line: "VALUE foobar1234 1 4096\r\n",
wantKey: "foobar1234", wantFlags: 1, wantSize: 4096,
},
{
name: "casid", line: "VALUE foobar1234 1 4096 1234\r\n",
wantKey: "foobar1234", wantFlags: 1, wantSize: 4096, wantCasid: 1234,
},
{
name: "flags-max-uint32", line: "VALUE key 4294967295 1\r\n",
wantKey: "key", wantFlags: 4294967295, wantSize: 1,
},
{
name: "flags-overflow", line: "VALUE key 4294967296 1\r\n",
wantErr: true,
},
{
name: "size-max-uint32", line: "VALUE key 1 2147483647\r\n",
wantKey: "key", wantFlags: 1, wantSize: 2147483647,
},
{
name: "size-overflow", line: "VALUE key 1 4294967296\r\n",
wantErr: true,
},
{
name: "casid-overflow", line: "VALUE key 1 4096 18446744073709551616\r\n",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions memcache/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ var keyBufPool = sync.Pool{
},
}

// PickServer returns the address for a server from the ServerList.
func (ss *ServerList) PickServer(key string) (net.Addr, error) {
ss.mu.RLock()
defer ss.mu.RUnlock()
Expand Down