refactor: modernise Go code with go fix and manual improvements (#2027)
Apply go fix ./... analysers (Go 1.26) across backend and examples:
- interface{} → any (type alias, no behaviour change)
- for i := 0; i < N; i++ → for range N / for i := range N
- slices.Contains / slices.ContainsFunc replacing manual loops
- strings.SplitSeq replacing strings.Split in range (avoids allocation)
- strings.CutPrefix replacing HasPrefix+TrimPrefix
- min() replacing manual if/else
- fmt.Appendf replacing []byte(fmt.Sprintf(...))
- strings.Builder replacing string += concatenation
- wg.Go(func(){}) replacing wg.Add(1)/go/wg.Done() pattern
- removed redundant ii := i loop variable copies (unnecessary since Go 1.22)
omitempty on struct-typed JSON fields: go fix removed omitempty from
struct-typed fields (time.Time, PostInfo, UserDetailEntry) because
encoding/json's omitempty never applied to struct types — it was always
a no-op. Kept as bare tags (no omitzero replacement) to preserve the
existing serialisation behaviour.
This commit is contained in:
@@ -251,11 +251,11 @@ func (m *MemData) Flag(req engine.FlagRequest) (val bool, err error) {
|
||||
|
||||
// ListFlags get list of flagged keys, like blocked & verified user
|
||||
// works for full locator (post flags) or with userID
|
||||
func (m *MemData) ListFlags(req engine.FlagRequest) (res []interface{}, err error) {
|
||||
func (m *MemData) ListFlags(req engine.FlagRequest) (res []any, err error) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
res = []interface{}{}
|
||||
res = []any{}
|
||||
|
||||
switch req.Flag {
|
||||
case engine.Verified:
|
||||
|
||||
@@ -198,7 +198,7 @@ func TestMemData_FindForUserPagination(t *testing.T) {
|
||||
}
|
||||
|
||||
// write 200 comments
|
||||
for i := 0; i < 200; i++ {
|
||||
for i := range 200 {
|
||||
c.ID = fmt.Sprintf("idd-%d", i)
|
||||
c.Text = fmt.Sprintf("text #%d", i)
|
||||
c.Timestamp = time.Date(2017, 12, 20, 15, 18, i, 0, time.Local)
|
||||
@@ -484,7 +484,7 @@ func TestMemData_FlagVerified(t *testing.T) {
|
||||
func TestMemData_FlagListVerified(t *testing.T) {
|
||||
|
||||
b := prepMem(t)
|
||||
toIDs := func(inp []interface{}) (res []string) {
|
||||
toIDs := func(inp []any) (res []string) {
|
||||
res = make([]string, len(inp))
|
||||
for i, v := range inp {
|
||||
vv, ok := v.(string)
|
||||
@@ -530,7 +530,7 @@ func TestMemData_FlagListBlocked(t *testing.T) {
|
||||
return err
|
||||
}
|
||||
|
||||
toBlocked := func(inp []interface{}) (res []store.BlockedUser) {
|
||||
toBlocked := func(inp []any) (res []store.BlockedUser) {
|
||||
res = make([]store.BlockedUser, len(inp))
|
||||
for i, v := range inp {
|
||||
vv, ok := v.(store.BlockedUser)
|
||||
|
||||
@@ -73,7 +73,7 @@ func (s *RPC) admEnabledHndl(id uint64, params json.RawMessage) (rr jrpc.Respons
|
||||
// onEvent returns nothing, callback to OnEvent
|
||||
func (s *RPC) admEventHndl(id uint64, params json.RawMessage) (rr jrpc.Response) {
|
||||
var siteID string
|
||||
var ps []interface{}
|
||||
var ps []any
|
||||
if err := json.Unmarshal(params, &ps); err != nil {
|
||||
return jrpc.Response{Error: err.Error()}
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ func TestRPC_listFlagsHndl(t *testing.T) {
|
||||
|
||||
flags, err = re.ListFlags(verifyFlagReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []interface{}{"u1"}, flags)
|
||||
assert.Equal(t, []any{"u1"}, flags)
|
||||
verifiedUsers := make([]string, 0, len(flags))
|
||||
for _, v := range flags {
|
||||
verifiedUsers = append(verifiedUsers, v.(string))
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
)
|
||||
|
||||
func chooseRandomUnusedPort() (port int) {
|
||||
for i := 0; i < 10; i++ {
|
||||
for range 10 {
|
||||
port = 40000 + int(rand.Int31n(10000))
|
||||
if ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err == nil {
|
||||
_ = ln.Close()
|
||||
@@ -34,7 +34,7 @@ func chooseRandomUnusedPort() (port int) {
|
||||
func waitForHTTPServerStart(port int) {
|
||||
// wait for up to 3 seconds for server to start before returning it
|
||||
client := http.Client{Timeout: time.Second}
|
||||
for i := 0; i < 300; i++ {
|
||||
for range 300 {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
if resp, err := client.Get(fmt.Sprintf("http://localhost:%d", port)); err == nil {
|
||||
_ = resp.Body.Close()
|
||||
|
||||
@@ -179,7 +179,7 @@ func (cc *CleanupCommand) listComments(postURL string) ([]store.Comment, error)
|
||||
|
||||
commentsWithInfo := struct {
|
||||
Comments []store.Comment `json:"comments"`
|
||||
Info store.PostInfo `json:"info,omitempty"`
|
||||
Info store.PostInfo `json:"info"`
|
||||
}{}
|
||||
|
||||
if err = json.NewDecoder(r.Body).Decode(&commentsWithInfo); err != nil {
|
||||
|
||||
@@ -173,7 +173,7 @@ func cleanupRoutes(t *testing.T, r *chi.Mux, c *cleanedComments) {
|
||||
|
||||
commentsWithInfo := struct {
|
||||
Comments []store.Comment `json:"comments"`
|
||||
Info store.PostInfo `json:"info,omitempty"`
|
||||
Info store.PostInfo `json:"info"`
|
||||
}{}
|
||||
|
||||
switch r.URL.Query().Get("url") {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"os/signal"
|
||||
"path"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -479,12 +480,7 @@ func stringsSetAndDifferent(s1, s2 string) bool {
|
||||
}
|
||||
|
||||
func contains(s string, a []string) bool {
|
||||
for _, t := range a {
|
||||
if t == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(a, s)
|
||||
}
|
||||
|
||||
// newServerApp prepares application and return it with all active parts
|
||||
|
||||
@@ -789,7 +789,7 @@ func Test_getAllowedDomains(t *testing.T) {
|
||||
}
|
||||
|
||||
func chooseRandomUnusedPort() (port int) {
|
||||
for i := 0; i < 10; i++ {
|
||||
for range 10 {
|
||||
port = 40000 + int(rand.Int31n(10000))
|
||||
if ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err == nil {
|
||||
_ = ln.Close()
|
||||
@@ -803,7 +803,7 @@ func waitForHTTPServerStart(port int) {
|
||||
// wait for up to 3 seconds for server to start before returning it
|
||||
client := http.Client{Timeout: time.Second}
|
||||
defer client.CloseIdleConnections()
|
||||
for i := 0; i < 300; i++ {
|
||||
for range 300 {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
if resp, err := client.Get(fmt.Sprintf("http://localhost:%d", port)); err == nil {
|
||||
_ = resp.Body.Close()
|
||||
@@ -814,7 +814,7 @@ func waitForHTTPServerStart(port int) {
|
||||
|
||||
func waitForHTTPSServerStart(port int) {
|
||||
// wait for up to 3 seconds for HTTPS server to start
|
||||
for i := 0; i < 300; i++ {
|
||||
for range 300 {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
conn, _ := net.DialTimeout("tcp", fmt.Sprintf("localhost:%d", port), time.Millisecond*10)
|
||||
if conn != nil {
|
||||
|
||||
+1
-4
@@ -92,10 +92,7 @@ func logDeprecatedParams(params []cmd.DeprecatedFlag) {
|
||||
func getDump() string {
|
||||
maxSize := 5 * 1024 * 1024
|
||||
stacktrace := make([]byte, maxSize)
|
||||
length := runtime.Stack(stacktrace, true)
|
||||
if length > maxSize {
|
||||
length = maxSize
|
||||
}
|
||||
length := min(runtime.Stack(stacktrace, true), maxSize)
|
||||
return string(stacktrace[:length])
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ func TestGetDump(t *testing.T) {
|
||||
}
|
||||
|
||||
func chooseRandomUnusedPort() (port int) {
|
||||
for i := 0; i < 10; i++ {
|
||||
for range 10 {
|
||||
port = 40000 + int(rand.Int31n(10000))
|
||||
if ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err == nil {
|
||||
_ = ln.Close()
|
||||
@@ -144,7 +144,7 @@ func waitForHTTPServerStart(port int) {
|
||||
// wait for up to 10 seconds for server to start before returning it
|
||||
client := http.Client{Timeout: time.Second}
|
||||
defer client.CloseIdleConnections()
|
||||
for i := 0; i < 100; i++ {
|
||||
for range 100 {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
if resp, err := client.Get(fmt.Sprintf("http://localhost:%d", port)); err == nil {
|
||||
_ = resp.Body.Close()
|
||||
|
||||
@@ -48,7 +48,7 @@ type commentoCommenter struct {
|
||||
Link string `json:"link"`
|
||||
Photo string `json:"photo"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
JoinDate time.Time `json:"joinDate,omitempty"`
|
||||
JoinDate time.Time `json:"joinDate"`
|
||||
IsModerator bool `json:"isModerator"`
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ func (u *URLMapper) loadRules(reader io.Reader) error {
|
||||
|
||||
u.rules = make(map[string]string)
|
||||
|
||||
for _, row := range strings.Split(rulesText, "\n") {
|
||||
for row := range strings.SplitSeq(rulesText, "\n") {
|
||||
row = strings.TrimSpace(row)
|
||||
urls := strings.Split(row, " ")
|
||||
if len(urls) != 2 {
|
||||
@@ -64,8 +64,8 @@ func (u *URLMapper) URL(url string) string {
|
||||
}
|
||||
oldURL = strings.TrimSuffix(oldURL, "*")
|
||||
newURL = strings.TrimSuffix(newURL, "*")
|
||||
if strings.HasPrefix(url, oldURL) {
|
||||
return newURL + strings.TrimPrefix(url, oldURL)
|
||||
if after, ok := strings.CutPrefix(url, oldURL); ok {
|
||||
return newURL + after
|
||||
}
|
||||
}
|
||||
// search failed, return given url
|
||||
|
||||
@@ -162,7 +162,7 @@ func TestNative_ImportManyWithError(t *testing.T) {
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteString(`{"version":1, "users":[], "posts":[]}` + "\n")
|
||||
for i := 0; i < 100; i++ {
|
||||
for i := range 100 {
|
||||
fmt.Fprintf(buf, goodRec, i)
|
||||
}
|
||||
buf.WriteString("{}\n")
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestService_Many(t *testing.T) {
|
||||
s := NewService(nil, 5, d1, d2)
|
||||
assert.NotNil(t, s)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
for i := range 10 {
|
||||
s.Submit(Request{Comment: store.Comment{ID: fmt.Sprintf("%d", 100+i)}})
|
||||
s.SubmitVerification(VerificationRequest{User: fmt.Sprintf("%d", 100+i)})
|
||||
time.Sleep(time.Millisecond * time.Duration(rand.Int31n(20)))
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
type tgRequester interface {
|
||||
Request(ctx context.Context, method string, b []byte, data interface{}) error
|
||||
Request(ctx context.Context, method string, b []byte, data any) error
|
||||
}
|
||||
|
||||
// TGUpdatesReceiver used to dispatch telegram updates to multiple receivers
|
||||
|
||||
@@ -39,7 +39,7 @@ type mockTGRequester struct {
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (m *mockTGRequester) Request(_ context.Context, _ string, _ []byte, data interface{}) error {
|
||||
func (m *mockTGRequester) Request(_ context.Context, _ string, _ []byte, data any) error {
|
||||
if m.hit < 2 {
|
||||
m.hit++
|
||||
assert.NoError(m.t, json.Unmarshal([]byte(getUpdatesResp), data))
|
||||
|
||||
@@ -87,7 +87,7 @@ func TestAdmin_Delete(t *testing.T) {
|
||||
// check count updated
|
||||
res, code = get(t, ts.URL+"/api/v1/count?site=remark42&url=https://radio-t.com/blah")
|
||||
assert.Equal(t, http.StatusOK, code)
|
||||
b := map[string]interface{}{}
|
||||
b := map[string]any{}
|
||||
err = json.Unmarshal([]byte(res), &b)
|
||||
assert.NoError(t, err)
|
||||
t.Logf("%#v", b)
|
||||
@@ -718,7 +718,7 @@ func TestAdmin_DeleteMeRequest(t *testing.T) {
|
||||
User: &token.User{
|
||||
ID: "user1",
|
||||
Picture: "pic.image",
|
||||
Attributes: map[string]interface{}{
|
||||
Attributes: map[string]any{
|
||||
"delete_me": true,
|
||||
},
|
||||
},
|
||||
@@ -786,7 +786,7 @@ func TestAdmin_DeleteMeRequestFailed(t *testing.T) {
|
||||
},
|
||||
User: &token.User{
|
||||
ID: "provider1_user1",
|
||||
Attributes: map[string]interface{}{
|
||||
Attributes: map[string]any{
|
||||
"delete_me": true,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -276,8 +276,8 @@ func TestMigrator_ImportDouble(t *testing.T) {
|
||||
"picture":"/api/v1/avatar/remark.image","profile":"https://remark42.com","admin":true,
|
||||
"ip":"ae12fe3b5f129b5cc4cdd2b136b7b7947c4d2741"},"locator":{"site":"remark42","url":"https://radio-t.com/blah1"},"score":0,
|
||||
"votes":{},"time":"2018-04-30T01:37:00.849053725-05:00"}`
|
||||
recs := []string{}
|
||||
for i := 0; i < 50; i++ {
|
||||
recs := make([]string, 0, 50)
|
||||
for i := range 50 {
|
||||
recs = append(recs, fmt.Sprintf(tmpl, i))
|
||||
}
|
||||
r := strings.NewReader(`{"version":1}` + strings.Join(recs, "\n")) // reader with 10k records
|
||||
@@ -329,7 +329,7 @@ func TestMigrator_ImportWaitExpired(t *testing.T) {
|
||||
"votes":{},"time":"2018-04-30T01:37:00.849053725-05:00"}`
|
||||
nRecs := 50
|
||||
recs := make([]string, 0, nRecs)
|
||||
for i := 0; i < nRecs; i++ {
|
||||
for i := range nRecs {
|
||||
recs = append(recs, fmt.Sprintf(tmpl, i))
|
||||
}
|
||||
r := strings.NewReader(`{"version":1}` + strings.Join(recs, "\n")) // reader with `nRecs` records
|
||||
|
||||
@@ -96,12 +96,12 @@ const lastCommentsScope = "last"
|
||||
|
||||
type commentsWithInfo struct {
|
||||
Comments []store.Comment `json:"comments"`
|
||||
Info store.PostInfo `json:"info,omitempty"`
|
||||
Info store.PostInfo `json:"info"`
|
||||
}
|
||||
|
||||
type treeWithInfo struct {
|
||||
*service.Tree
|
||||
Info store.PostInfo `json:"info,omitempty"`
|
||||
Info store.PostInfo `json:"info"`
|
||||
}
|
||||
|
||||
// Run the lister and request's router, activate rest server
|
||||
@@ -504,7 +504,7 @@ func addFileServer(r chi.Router, embedFS embed.FS, webRoot, version string) {
|
||||
})
|
||||
}
|
||||
|
||||
func encodeJSONWithHTML(v interface{}) ([]byte, error) {
|
||||
func encodeJSONWithHTML(v any) ([]byte, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(false)
|
||||
|
||||
@@ -579,7 +579,7 @@ func (s *private) emailUnsubscribeCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// MustExecute behaves like template.Execute, but panics if an error occurs.
|
||||
MustExecute := func(tmpl *template.Template, wr io.Writer, data interface{}) {
|
||||
MustExecute := func(tmpl *template.Template, wr io.Writer, data any) {
|
||||
if err := tmpl.Execute(wr, data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -670,7 +670,7 @@ func (s *private) userAllDataCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
merr = multierror.Append(merr, write([]byte(`, "comments":`))) // send comments prefix
|
||||
|
||||
// get comments in 100 in each paginated request
|
||||
for i := 0; i < 100; i++ {
|
||||
for i := range 100 {
|
||||
comments, errUser := s.dataService.User(siteID, user.ID, 100, i*100, rest.GetUserOrEmpty(r))
|
||||
if errUser != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusInternalServerError, errUser, "can't get user comments", rest.ErrInternal)
|
||||
@@ -711,7 +711,7 @@ func (s *private) deleteMeCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
User: &token.User{
|
||||
ID: user.ID,
|
||||
Name: user.Name,
|
||||
Attributes: map[string]interface{}{
|
||||
Attributes: map[string]any{
|
||||
"delete_me": true, // prevents this token from being used for login
|
||||
},
|
||||
},
|
||||
|
||||
@@ -49,7 +49,7 @@ func TestRest_Create(t *testing.T) {
|
||||
c := R.JSON{}
|
||||
err = json.Unmarshal(b, &c)
|
||||
assert.NoError(t, err)
|
||||
loc := c["locator"].(map[string]interface{})
|
||||
loc := c["locator"].(map[string]any)
|
||||
assert.Equal(t, "remark42", loc["site"])
|
||||
assert.Equal(t, "https://radio-t.com/blah1", loc["url"])
|
||||
assert.True(t, len(c["id"].(string)) > 8)
|
||||
@@ -71,7 +71,7 @@ func TestRest_CreateFilteredCode(t *testing.T) {
|
||||
c := R.JSON{}
|
||||
err = json.Unmarshal(b, &c)
|
||||
require.NoError(t, err, string(b))
|
||||
loc := c["locator"].(map[string]interface{})
|
||||
loc := c["locator"].(map[string]any)
|
||||
assert.Equal(t, "remark42", loc["site"])
|
||||
assert.Equal(t, "https://radio-t.com/blah1", loc["url"])
|
||||
assert.Equal(t, "`foo<bar>`", c["orig"])
|
||||
@@ -123,7 +123,7 @@ func TestRest_CreateAndPreviewWithImage(t *testing.T) {
|
||||
require.NoError(t, err, string(b))
|
||||
assert.NotContains(t, c["text"], pngServer.URL)
|
||||
assert.Contains(t, c["text"], srv.RemarkURL)
|
||||
loc := c["locator"].(map[string]interface{})
|
||||
loc := c["locator"].(map[string]any)
|
||||
assert.Equal(t, "remark42", loc["site"])
|
||||
assert.Equal(t, "https://radio-t.com/blah1", loc["url"])
|
||||
assert.True(t, len(c["id"].(string)) > 8)
|
||||
@@ -1456,7 +1456,7 @@ func TestRest_UserAllDataManyComments(t *testing.T) {
|
||||
c := store.Comment{User: user, Text: "test test #1", Locator: store.Locator{SiteID: "remark42",
|
||||
URL: "https://radio-t.com/blah1"}, Timestamp: time.Date(2018, 5, 27, 1, 14, 10, 0, time.Local)}
|
||||
|
||||
for i := 0; i < 51; i++ {
|
||||
for i := range 51 {
|
||||
c.ID = fmt.Sprintf("id-%03d", i)
|
||||
c.Timestamp = c.Timestamp.Add(time.Second)
|
||||
_, err := srv.DataService.Create(c)
|
||||
|
||||
@@ -930,7 +930,7 @@ func TestRest_Config(t *testing.T) {
|
||||
err := json.Unmarshal([]byte(body), &j)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 300.0, j["edit_duration"])
|
||||
assert.EqualValues(t, []interface{}{"a1", "a2"}, j["admins"])
|
||||
assert.EqualValues(t, []any{"a1", "a2"}, j["admins"])
|
||||
assert.Equal(t, "admin@remark-42.com", j["admin_email"])
|
||||
assert.Equal(t, 4000.0, j["max_comment_size"])
|
||||
assert.Equal(t, -5.0, j["low_score"])
|
||||
|
||||
@@ -437,7 +437,7 @@ func Test_validEmailAuth(t *testing.T) {
|
||||
|
||||
// randomPath pick a file or folder name which is not in use for sure
|
||||
func randomPath(tempDir, basename, suffix string) (string, error) {
|
||||
for i := 0; i < 10; i++ {
|
||||
for range 10 {
|
||||
fname := fmt.Sprintf("/%s/%s-%d%s", tempDir, basename, rand.Int31(), suffix)
|
||||
fmt.Printf("fname %q", fname)
|
||||
_, err := os.Stat(fname)
|
||||
@@ -667,7 +667,7 @@ func requireAdminOnly(t *testing.T, req *http.Request) {
|
||||
}
|
||||
|
||||
func chooseRandomUnusedPort() (port int) {
|
||||
for i := 0; i < 10; i++ {
|
||||
for range 10 {
|
||||
port = 40000 + int(rand.Int31n(10000))
|
||||
if ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err == nil {
|
||||
_ = ln.Close()
|
||||
@@ -679,7 +679,7 @@ func chooseRandomUnusedPort() (port int) {
|
||||
|
||||
func waitForHTTPSServerStart(port int) {
|
||||
// wait for up to 3 seconds for HTTPS server to start
|
||||
for i := 0; i < 300; i++ {
|
||||
for range 300 {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
conn, _ := net.DialTimeout("tcp", fmt.Sprintf("localhost:%d", port), time.Millisecond*10)
|
||||
if conn != nil {
|
||||
|
||||
@@ -51,7 +51,7 @@ type errTmplData struct {
|
||||
// error code is not included in render as it is intended for UI developers and not for the users
|
||||
func SendErrorHTML(w http.ResponseWriter, r *http.Request, httpStatusCode int, err error, details string, errCode int) {
|
||||
// MustExecute behaves like template.Execute, but panics if an error occurs.
|
||||
MustExecute := func(tmpl *template.Template, wr io.Writer, data interface{}) {
|
||||
MustExecute := func(tmpl *template.Template, wr io.Writer, data any) {
|
||||
if err = tmpl.Execute(wr, data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ func TestImage_RoutesCachingImage(t *testing.T) {
|
||||
|
||||
func TestImage_RoutesUsingCachedImage(t *testing.T) {
|
||||
// in order to validate that cached data used cache "will return" some other data from what http server would
|
||||
testImage := []byte(fmt.Sprintf("%256s", "X"))
|
||||
testImage := fmt.Appendf(nil, "%256s", "X")
|
||||
imageStore := image.StoreMock{LoadFunc: func(string) ([]byte, error) {
|
||||
return testImage, nil
|
||||
}}
|
||||
|
||||
@@ -56,7 +56,7 @@ func SetUserInfo(r *http.Request, user store.User) *http.Request {
|
||||
Picture: user.Picture,
|
||||
IP: user.IP,
|
||||
Audience: user.SiteID,
|
||||
Attributes: map[string]interface{}{
|
||||
Attributes: map[string]any{
|
||||
"blocked": user.Blocked,
|
||||
"verified": user.Verified,
|
||||
},
|
||||
|
||||
@@ -50,8 +50,8 @@ type PostInfo struct {
|
||||
CountLeft int `json:"count_left"` // used only with returning search results limited by number, otherwise zero
|
||||
LastComment string `json:"last_comment,omitempty"` // used only with returning search results limited by number
|
||||
ReadOnly bool `json:"read_only,omitempty" bson:"read_only,omitempty"` // can be attached to site-wide comments but won't be set then
|
||||
FirstTS time.Time `json:"first_time,omitempty" bson:"first_time,omitempty"`
|
||||
LastTS time.Time `json:"last_time,omitempty" bson:"last_time,omitempty"`
|
||||
FirstTS time.Time `json:"first_time" bson:"first_time,omitempty"`
|
||||
LastTS time.Time `json:"last_time" bson:"last_time,omitempty"`
|
||||
}
|
||||
|
||||
// BlockedUser holds id and ts for blocked user
|
||||
|
||||
@@ -346,13 +346,13 @@ func (b *BoltDB) Info(req InfoRequest) ([]store.PostInfo, error) {
|
||||
|
||||
// ListFlags get list of flagged keys, like blocked & verified user
|
||||
// works for full locator (post flags) or with userID
|
||||
func (b *BoltDB) ListFlags(req FlagRequest) (res []interface{}, err error) {
|
||||
func (b *BoltDB) ListFlags(req FlagRequest) (res []any, err error) {
|
||||
bdb, e := b.db(req.Locator.SiteID)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
res = []interface{}{}
|
||||
res = []any{}
|
||||
switch req.Flag {
|
||||
case Verified:
|
||||
err = bdb.View(func(tx *bolt.Tx) error {
|
||||
@@ -957,7 +957,7 @@ func (b *BoltDB) getUserBucket(tx *bolt.Tx, userID string) (*bolt.Bucket, error)
|
||||
}
|
||||
|
||||
// save marshaled value to key for bucket. Should run in update tx
|
||||
func (b *BoltDB) save(bkt *bolt.Bucket, key string, value interface{}) (err error) {
|
||||
func (b *BoltDB) save(bkt *bolt.Bucket, key string, value any) (err error) {
|
||||
if value == nil {
|
||||
return fmt.Errorf("can't save nil value for %s", key)
|
||||
}
|
||||
@@ -972,7 +972,7 @@ func (b *BoltDB) save(bkt *bolt.Bucket, key string, value interface{}) (err erro
|
||||
}
|
||||
|
||||
// load and unmarshal json value by key from bucket. Should run in view tx
|
||||
func (b *BoltDB) load(bkt *bolt.Bucket, key string, res interface{}) error {
|
||||
func (b *BoltDB) load(bkt *bolt.Bucket, key string, res any) error {
|
||||
value := bkt.Get([]byte(key))
|
||||
if value == nil {
|
||||
return fmt.Errorf("no value for %s", key)
|
||||
@@ -1027,7 +1027,7 @@ func (b *BoltDB) db(siteID string) (*bolt.DB, error) {
|
||||
|
||||
// makeRef creates reference combining url and comment id
|
||||
func (b *BoltDB) makeRef(comment store.Comment) []byte {
|
||||
return []byte(fmt.Sprintf("%s!!%s", comment.Locator.URL, comment.ID))
|
||||
return fmt.Appendf(nil, "%s!!%s", comment.Locator.URL, comment.ID)
|
||||
}
|
||||
|
||||
// parseRef gets parts of reference
|
||||
|
||||
@@ -236,7 +236,7 @@ func TestBoltDB_FindForUserPagination(t *testing.T) {
|
||||
}
|
||||
|
||||
// write 200 comments
|
||||
for i := 0; i < 200; i++ {
|
||||
for i := range 200 {
|
||||
c.ID = fmt.Sprintf("id-%d", i)
|
||||
c.Text = fmt.Sprintf("text #%d", i)
|
||||
c.Timestamp = time.Date(2017, 12, 20, 15, 18, i, 0, time.Local)
|
||||
@@ -540,7 +540,7 @@ func TestBolt_FlagListVerified(t *testing.T) {
|
||||
b, teardown := prep(t)
|
||||
defer teardown()
|
||||
|
||||
toIDs := func(inp []interface{}) (res []string) {
|
||||
toIDs := func(inp []any) (res []string) {
|
||||
res = make([]string, len(inp))
|
||||
for i, v := range inp {
|
||||
vv, ok := v.(string)
|
||||
@@ -580,7 +580,7 @@ func TestBolt_FlagListBlocked(t *testing.T) {
|
||||
return err
|
||||
}
|
||||
|
||||
toBlocked := func(inp []interface{}) (res []store.BlockedUser) {
|
||||
toBlocked := func(inp []any) (res []store.BlockedUser) {
|
||||
res = make([]store.BlockedUser, len(inp))
|
||||
for i, v := range inp {
|
||||
vv, ok := v.(store.BlockedUser)
|
||||
|
||||
@@ -24,7 +24,7 @@ type Interface interface {
|
||||
Count(req FindRequest) (int, error) // get count for post or user
|
||||
Delete(req DeleteRequest) error // Delete post(s), user, comment, user details, or everything
|
||||
Flag(req FlagRequest) (bool, error) // set and get flags
|
||||
ListFlags(req FlagRequest) ([]interface{}, error) // get list of flagged keys, like blocked & verified user
|
||||
ListFlags(req FlagRequest) ([]any, error) // get list of flagged keys, like blocked & verified user
|
||||
|
||||
// UserDetail sets or gets single detail value, or gets all details for requested site
|
||||
// Returns list even for single entry request is a compromise in order to have both single detail getting and setting
|
||||
@@ -45,7 +45,7 @@ type FindRequest struct {
|
||||
Locator store.Locator `json:"locator"` // lack of URL means site operation
|
||||
UserID string `json:"user_id,omitempty"` // presence of UserID treated as user-related find
|
||||
Sort string `json:"sort,omitempty"` // sort order with +/-field syntax
|
||||
Since time.Time `json:"since,omitempty"` // time limit for found results
|
||||
Since time.Time `json:"since"` // time limit for found results
|
||||
Limit int `json:"limit,omitempty"`
|
||||
Skip int `json:"skip,omitempty"`
|
||||
}
|
||||
|
||||
@@ -71,24 +71,24 @@ func (r *RPC) Flag(req FlagRequest) (status bool, err error) {
|
||||
return status, err
|
||||
}
|
||||
|
||||
func unmarshalString(data []byte) ([]interface{}, error) {
|
||||
func unmarshalString(data []byte) ([]any, error) {
|
||||
var strings []string
|
||||
if err := json.Unmarshal(data, &strings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := make([]interface{}, 0, len(strings))
|
||||
list := make([]any, 0, len(strings))
|
||||
for _, w := range strings {
|
||||
list = append(list, w)
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func unmarshalBlockedUser(data []byte) ([]interface{}, error) {
|
||||
func unmarshalBlockedUser(data []byte) ([]any, error) {
|
||||
var blockedUsers []store.BlockedUser
|
||||
if err := json.Unmarshal(data, &blockedUsers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := make([]interface{}, 0, len(blockedUsers))
|
||||
list := make([]any, 0, len(blockedUsers))
|
||||
for _, w := range blockedUsers {
|
||||
list = append(list, w)
|
||||
}
|
||||
@@ -96,7 +96,7 @@ func unmarshalBlockedUser(data []byte) ([]interface{}, error) {
|
||||
}
|
||||
|
||||
// ListFlags get list of flagged keys, like blocked & verified user
|
||||
func (r *RPC) ListFlags(req FlagRequest) ([]interface{}, error) {
|
||||
func (r *RPC) ListFlags(req FlagRequest) ([]any, error) {
|
||||
resp, err := r.Call("store.list_flags", req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -190,7 +190,7 @@ func TestFsStore_location(t *testing.T) {
|
||||
}
|
||||
|
||||
svc := FileSystem{Location: "/tmp", Partitions: 10}
|
||||
for i := 0; i < 1000; i++ {
|
||||
for range 1000 {
|
||||
v := randomID(rand.Intn(64))
|
||||
location := svc.location("/tmp", v)
|
||||
elems := strings.Split(location, "/")
|
||||
|
||||
@@ -111,9 +111,7 @@ func (s *Service) Submit(idsFn func() []string) {
|
||||
s.once.Do(func() {
|
||||
log.Printf("[DEBUG] image submitter activated")
|
||||
s.submitCh = make(chan submitReq, submitQueueSize)
|
||||
s.wg.Add(1)
|
||||
go func() {
|
||||
defer s.wg.Done()
|
||||
s.wg.Go(func() {
|
||||
for req := range s.submitCh {
|
||||
// wait for EditDuration expiration with emergency pass on term
|
||||
for atomic.LoadInt32(&s.term) == 0 && time.Since(req.TS) <= s.EditDuration {
|
||||
@@ -127,7 +125,7 @@ func (s *Service) Submit(idsFn func() []string) {
|
||||
atomic.AddInt32(&s.submitCount, -1)
|
||||
}
|
||||
log.Printf("[INFO] image submitter terminated")
|
||||
}()
|
||||
})
|
||||
})
|
||||
|
||||
atomic.AddInt32(&s.submitCount, 1)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
@@ -47,12 +48,7 @@ func (m *RestrictedWordsMatcher) Match(siteID, text string) bool {
|
||||
tokens := m.tokenize(text)
|
||||
trie := newWildcardTrie(restrictedWords...)
|
||||
|
||||
for _, token := range tokens {
|
||||
if trie.check(token) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.ContainsFunc(tokens, trie.check)
|
||||
}
|
||||
|
||||
func (m *RestrictedWordsMatcher) tokenize(text string) []string {
|
||||
|
||||
@@ -62,7 +62,7 @@ type UserMetaData struct {
|
||||
Until time.Time `json:"until"`
|
||||
} `json:"blocked"`
|
||||
Verified bool `json:"verified"`
|
||||
Details engine.UserDetailEntry `json:"details,omitempty"`
|
||||
Details engine.UserDetailEntry `json:"details"`
|
||||
}
|
||||
|
||||
// PostMetaData keeps info about post flags
|
||||
@@ -676,12 +676,7 @@ func (s *DataStore) IsAdmin(siteID, userID string) bool {
|
||||
log.Printf("[WARN] can't get admins for %s, %v", siteID, err)
|
||||
return false
|
||||
}
|
||||
for _, a := range admins {
|
||||
if a == userID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(admins, userID)
|
||||
}
|
||||
|
||||
// IsReadOnly checks if post read-only
|
||||
|
||||
@@ -438,13 +438,11 @@ func TestService_VoteAggressive(t *testing.T) {
|
||||
|
||||
// crazy vote +1 as user1
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 1000; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for range 1000 {
|
||||
wg.Go(func() {
|
||||
_, _ = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: res[0].ID,
|
||||
UserID: "user1", Val: true})
|
||||
}()
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
res, err = b.Last("radio-t", 0, time.Time{}, store.User{ID: "user1"})
|
||||
@@ -458,14 +456,12 @@ func TestService_VoteAggressive(t *testing.T) {
|
||||
assert.Equal(t, 0, len(res[0].VotedIPs), "vote ips hidden")
|
||||
|
||||
// random +1/-1 result should be [0..2]
|
||||
for i := 0; i < 100; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for range 100 {
|
||||
wg.Go(func() {
|
||||
val := rand.Intn(2) > 0
|
||||
_, _ = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: res[0].ID,
|
||||
UserID: "user1", Val: val})
|
||||
}()
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
res, err = b.Last("radio-t", 0, time.Time{}, store.User{})
|
||||
@@ -492,14 +488,11 @@ func TestService_VoteConcurrent(t *testing.T) {
|
||||
|
||||
// concurrent vote +1 as multiple users for the same comment
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 100; i++ {
|
||||
wg.Add(1)
|
||||
ii := i
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i := range 100 {
|
||||
wg.Go(func() {
|
||||
_, _ = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: res[0].ID,
|
||||
UserID: fmt.Sprintf("user1-%d", ii), Val: true})
|
||||
}()
|
||||
UserID: fmt.Sprintf("user1-%d", i), Val: true})
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
res, err = b.Last("radio-t", 0, time.Time{}, store.User{})
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestTitle_Get(t *testing.T) {
|
||||
_, err = ex.Get(ts.URL + "/bad")
|
||||
require.Error(t, err)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
for range 100 {
|
||||
r, err := ex.Get(ts.URL + "/good")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "blah 123", r)
|
||||
@@ -70,9 +70,9 @@ func TestTitle_Get(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTitle_GetConcurrent(t *testing.T) {
|
||||
body := ""
|
||||
for n := 0; n < 1000; n++ {
|
||||
body += "something something blah blah\n"
|
||||
var body strings.Builder
|
||||
for range 1000 {
|
||||
body.WriteString("something something blah blah\n")
|
||||
}
|
||||
ex := NewTitleExtractor(http.Client{Timeout: 5 * time.Second}, []string{"127.0.0.1"})
|
||||
defer ex.Close()
|
||||
@@ -80,7 +80,7 @@ func TestTitle_GetConcurrent(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.HasPrefix(r.URL.String(), "/good") {
|
||||
atomic.AddInt32(&hits, 1)
|
||||
_, err := fmt.Fprintf(w, "<html><title>blah 123 %s</title><body>%s</body></html>", r.URL.String(), body)
|
||||
_, err := fmt.Fprintf(w, "<html><title>blah 123 %s</title><body>%s</body></html>", r.URL.String(), body.String())
|
||||
assert.NoError(t, err)
|
||||
return
|
||||
}
|
||||
@@ -90,12 +90,11 @@ func TestTitle_GetConcurrent(t *testing.T) {
|
||||
|
||||
g := syncs.NewSizedGroup(10)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
ii := i
|
||||
for i := range 100 {
|
||||
g.Go(func(_ context.Context) {
|
||||
title, err := ex.Get(ts.URL + "/good/" + strconv.Itoa(ii))
|
||||
title, err := ex.Get(ts.URL + "/good/" + strconv.Itoa(i))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "blah 123 "+"/good/"+strconv.Itoa(ii), title)
|
||||
assert.Equal(t, "blah 123 "+"/good/"+strconv.Itoa(i), title)
|
||||
})
|
||||
}
|
||||
g.Wait()
|
||||
@@ -115,7 +114,7 @@ func TestTitle_GetFailed(t *testing.T) {
|
||||
_, err := ex.Get(ts.URL + "/bad")
|
||||
require.Error(t, err)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
for range 100 {
|
||||
r, err := ex.Get(ts.URL + "/bad")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "", r)
|
||||
|
||||
Reference in New Issue
Block a user