From f59ad0357ab0447cc0b614c3b178aa9dc3f5cf4d Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 1 Feb 2022 13:12:46 +0100 Subject: [PATCH 1/8] Fix tests and linter warnings --- api/api_bridge.go | 2 + api/authentication.go | 7 +- api/authentication_test.go | 17 ++- api/client/client.go | 4 +- api/client/const.go | 4 +- api/client/message.go | 9 +- api/client/websocket.go | 4 +- api/database.go | 22 ++-- api/endpoints.go | 2 +- api/endpoints_test.go | 7 +- api/main_test.go | 7 +- api/modules.go | 1 + api/request.go | 5 +- api/router.go | 7 +- config/basic_config.go | 4 +- config/database.go | 6 +- config/expertise.go | 2 - config/get-safe.go | 6 +- config/get_test.go | 6 +- config/main.go | 7 +- config/persistence.go | 6 +- config/persistence_test.go | 3 + config/perspective.go | 2 +- config/registry.go | 4 +- config/registry_test.go | 3 +- config/release.go | 4 +- config/set.go | 4 +- config/set_test.go | 6 +- config/validate.go | 3 +- container/container.go | 28 ++--- container/container_test.go | 13 +- database/accessor/accessor-json-bytes.go | 10 +- database/accessor/accessor-json-string.go | 10 +- database/accessor/accessor-struct.go | 12 +- database/accessor/accessor_test.go | 18 ++- database/boilerplate_test.go | 26 ++-- database/controller.go | 2 +- database/controllers.go | 7 +- database/database.go | 2 +- database/database_test.go | 19 +-- database/errors.go | 2 +- database/hookbase.go | 3 +- database/interface.go | 30 +++-- database/interface_cache.go | 1 - database/interface_cache_test.go | 6 +- database/main.go | 15 +-- database/migration/error.go | 8 +- database/migration/migration.go | 4 +- database/query/condition-bool.go | 1 - database/query/condition-float.go | 1 - database/query/condition-int.go | 1 - database/query/condition-stringslice.go | 2 - database/query/condition.go | 2 +- database/query/condition_test.go | 10 ++ database/query/operators_test.go | 2 + database/query/parser.go | 22 ++-- database/query/parser_test.go | 10 ++ database/query/query_test.go | 11 +- database/record/base_test.go | 2 +- database/record/meta-bench_test.go | 138 ++-------------------- database/record/meta-gencode.go | 10 +- database/record/meta-gencode_test.go | 28 ++--- database/record/meta.go | 2 +- database/record/wrapper.go | 18 +-- database/record/wrapper_test.go | 1 + database/registry.go | 30 ++--- database/storage/badger/badger.go | 14 +-- database/storage/badger/badger_test.go | 5 +- database/storage/bbolt/bbolt.go | 17 ++- database/storage/bbolt/bbolt_test.go | 5 +- database/storage/errors.go | 2 +- database/storage/fstree/fstree.go | 32 +++-- database/storage/fstree/fstree_test.go | 6 +- database/storage/hashmap/map.go | 2 +- database/storage/hashmap/map_test.go | 8 +- database/storage/injectbase.go | 8 +- database/storage/interface.go | 2 +- database/storage/sinkhole/sinkhole.go | 2 +- dataroot/root.go | 6 +- formats/dsd/format.go | 2 + formats/dsd/http.go | 2 + formats/varint/varint_test.go | 12 +- info/module/flags.go | 4 +- info/version.go | 2 +- log/formatting_unix.go | 14 ++- log/input.go | 1 - log/logging.go | 3 +- log/logging_test.go | 3 +- log/output.go | 18 +-- log/trace.go | 4 +- log/trace_test.go | 2 + metrics/metrics_host.go | 11 ++ modules/cmd.go | 4 +- modules/error.go | 4 +- modules/events.go | 8 +- modules/exit.go | 6 +- modules/mgmt.go | 3 +- modules/mgmt_test.go | 1 - modules/microtasks.go | 7 +- modules/microtasks_test.go | 24 ++-- modules/modules.go | 7 +- modules/modules_test.go | 14 +-- modules/start.go | 12 +- modules/status.go | 10 +- modules/subsystems/module.go | 1 - modules/subsystems/registry.go | 5 +- modules/subsystems/subsystems_test.go | 5 +- modules/tasks.go | 15 +-- modules/tasks_test.go | 48 ++++---- modules/worker.go | 3 +- modules/worker_test.go | 6 +- notifications/database.go | 15 ++- notifications/module.go | 4 +- notifications/notification.go | 2 +- portbase.go | 4 +- rng/entropy.go | 10 +- rng/entropy_test.go | 3 +- rng/fullfeed.go | 1 - rng/fullfeed_test.go | 2 + rng/get.go | 4 +- rng/get_test.go | 2 + rng/osfeeder.go | 3 +- rng/rng.go | 4 +- rng/rng_test.go | 2 + rng/test/main.go | 6 +- rng/tickfeeder.go | 2 - run/main.go | 4 +- runtime/module.go | 8 +- runtime/modules_integration.go | 9 +- runtime/provider.go | 8 +- runtime/registry.go | 3 +- runtime/registry_test.go | 11 +- template/module.go | 7 +- template/module_test.go | 6 +- updater/export.go | 6 +- updater/fetch.go | 4 +- updater/file.go | 6 +- updater/filename_test.go | 8 ++ updater/get.go | 2 +- updater/registry.go | 2 +- updater/registry_test.go | 6 +- updater/resource.go | 11 +- updater/resource_test.go | 4 + updater/unpacking.go | 11 +- updater/updating.go | 8 +- utils/debug/debug.go | 3 +- utils/fs.go | 6 +- utils/onceagain_test.go | 1 + utils/osdetail/binmeta_default.go | 2 +- utils/renameio/example_test.go | 8 +- utils/renameio/symlink_test.go | 12 +- utils/renameio/tempfile_linux_test.go | 47 +++++--- utils/renameio/writefile.go | 4 +- utils/renameio/writefile_test.go | 8 +- utils/safe.go | 2 + utils/safe_test.go | 2 + utils/slices_test.go | 10 ++ utils/stablepool_test.go | 4 +- utils/structure.go | 8 +- utils/structure_test.go | 14 +-- utils/uuid.go | 2 +- utils/uuid_test.go | 2 + 162 files changed, 668 insertions(+), 696 deletions(-) diff --git a/api/api_bridge.go b/api/api_bridge.go index c1385ca..6d3d1ed 100644 --- a/api/api_bridge.go +++ b/api/api_bridge.go @@ -37,6 +37,7 @@ type endpointBridgeStorage struct { storage.InjectBase } +// EndpointBridgeRequest holds a bridged request API request. type EndpointBridgeRequest struct { record.Base sync.Mutex @@ -48,6 +49,7 @@ type EndpointBridgeRequest struct { MimeType string } +// EndpointBridgeResponse holds a bridged request API response. type EndpointBridgeResponse struct { record.Base sync.Mutex diff --git a/api/authentication.go b/api/authentication.go index 97f3786..290566f 100644 --- a/api/authentication.go +++ b/api/authentication.go @@ -13,9 +13,8 @@ import ( "github.com/tevino/abool" - "github.com/safing/portbase/modules" - "github.com/safing/portbase/log" + "github.com/safing/portbase/modules" "github.com/safing/portbase/rng" ) @@ -147,7 +146,7 @@ func authenticateRequest(w http.ResponseWriter, r *http.Request, targetHandler h } // Check if we need to do any authentication at all. - switch requiredPermission { + switch requiredPermission { //nolint:exhaustive case NotFound: // Not found. tracer.Trace("api: authenticated handler reported: not found") @@ -543,6 +542,8 @@ func (p Permission) Role() string { return "Admin" case PermitSelf: return "Self" + case Dynamic, NotFound, NotSupported: + return "Invalid" default: return "Invalid" } diff --git a/api/authentication_test.go b/api/authentication_test.go index 0de7a6b..3d7e7c5 100644 --- a/api/authentication_test.go +++ b/api/authentication_test.go @@ -9,9 +9,7 @@ import ( "github.com/stretchr/testify/assert" ) -var ( - testToken = new(AuthToken) -) +var testToken = new(AuthToken) func testAuthenticator(r *http.Request, s *http.Server) (*AuthToken, error) { switch { @@ -65,7 +63,9 @@ func init() { } } -func TestPermissions(t *testing.T) { //nolint:gocognit +func TestPermissions(t *testing.T) { + t.Parallel() + testHandler := &mainHandler{ mux: mainMux, } @@ -99,10 +99,11 @@ func TestPermissions(t *testing.T) { //nolint:gocognit http.MethodHead, http.MethodPost, http.MethodPut, + http.MethodDelete, } { // Set request permission for test requests. - reading := method == http.MethodGet + _, reading, _ := getEffectiveMethod(&http.Request{Method: method}) if reading { testToken.Read = requestPerm testToken.Write = NotSupported @@ -147,7 +148,6 @@ func TestPermissions(t *testing.T) { //nolint:gocognit } if expectSuccess { - // Test for success. if !assert.HTTPBodyContains( t, @@ -164,9 +164,7 @@ func TestPermissions(t *testing.T) { //nolint:gocognit handlerPerm, handlerPerm, ) } - } else { - // Test for error. if !assert.HTTPError(t, testHandler.ServeHTTP, @@ -181,7 +179,6 @@ func TestPermissions(t *testing.T) { //nolint:gocognit handlerPerm, handlerPerm, ) } - } } } @@ -189,6 +186,8 @@ func TestPermissions(t *testing.T) { //nolint:gocognit } func TestPermissionDefinitions(t *testing.T) { + t.Parallel() + if NotSupported != 0 { t.Fatalf("NotSupported must be zero, was %v", NotSupported) } diff --git a/api/client/client.go b/api/client/client.go index e86bd61..213aceb 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -5,9 +5,9 @@ import ( "sync" "time" - "github.com/safing/portbase/log" - "github.com/tevino/abool" + + "github.com/safing/portbase/log" ) const ( diff --git a/api/client/const.go b/api/client/const.go index 080e938..d882683 100644 --- a/api/client/const.go +++ b/api/client/const.go @@ -25,6 +25,4 @@ const ( apiSeperator = "|" ) -var ( - apiSeperatorBytes = []byte(apiSeperator) -) +var apiSeperatorBytes = []byte(apiSeperator) diff --git a/api/client/message.go b/api/client/message.go index 3e9b9dc..0e1cb54 100644 --- a/api/client/message.go +++ b/api/client/message.go @@ -4,15 +4,14 @@ import ( "bytes" "errors" + "github.com/tevino/abool" + "github.com/safing/portbase/container" "github.com/safing/portbase/formats/dsd" - "github.com/tevino/abool" ) -// Client errors. -var ( - ErrMalformedMessage = errors.New("malformed message") -) +// ErrMalformedMessage is returned when a malformed message was encountered. +var ErrMalformedMessage = errors.New("malformed message") // Message is an API message. type Message struct { diff --git a/api/client/websocket.go b/api/client/websocket.go index 9856d9f..f8e2b2a 100644 --- a/api/client/websocket.go +++ b/api/client/websocket.go @@ -4,10 +4,10 @@ import ( "fmt" "sync" - "github.com/safing/portbase/log" + "github.com/gorilla/websocket" "github.com/tevino/abool" - "github.com/gorilla/websocket" + "github.com/safing/portbase/log" ) type wsState struct { diff --git a/api/database.go b/api/database.go index bbdb82c..5087dda 100644 --- a/api/database.go +++ b/api/database.go @@ -8,20 +8,18 @@ import ( "net/http" "sync" - "github.com/tidwall/sjson" - - "github.com/safing/portbase/database/iterator" - "github.com/safing/portbase/formats/dsd" - "github.com/safing/portbase/formats/varint" - "github.com/gorilla/websocket" "github.com/tevino/abool" "github.com/tidwall/gjson" + "github.com/tidwall/sjson" "github.com/safing/portbase/container" "github.com/safing/portbase/database" + "github.com/safing/portbase/database/iterator" "github.com/safing/portbase/database/query" "github.com/safing/portbase/database/record" + "github.com/safing/portbase/formats/dsd" + "github.com/safing/portbase/formats/varint" "github.com/safing/portbase/log" ) @@ -75,7 +73,6 @@ func allowAnyOrigin(r *http.Request) bool { } func startDatabaseAPI(w http.ResponseWriter, r *http.Request) { - upgrader := websocket.Upgrader{ CheckOrigin: allowAnyOrigin, ReadBufferSize: 1024, @@ -89,7 +86,7 @@ func startDatabaseAPI(w http.ResponseWriter, r *http.Request) { return } - new := &DatabaseAPI{ + newDBAPI := &DatabaseAPI{ conn: wsConn, sendQueue: make(chan []byte, 100), queries: make(map[string]*iterator.Iterator), @@ -99,14 +96,13 @@ func startDatabaseAPI(w http.ResponseWriter, r *http.Request) { db: database.NewInterface(nil), } - module.StartWorker("database api handler", new.handler) - module.StartWorker("database api writer", new.writer) + module.StartWorker("database api handler", newDBAPI.handler) + module.StartWorker("database api writer", newDBAPI.writer) log.Tracer(r.Context()).Infof("api request: init websocket %s %s", r.RemoteAddr, r.RequestURI) } func (api *DatabaseAPI) handler(context.Context) error { - // 123|get| // 123|ok|| // 123|error| @@ -429,12 +425,12 @@ func (api *DatabaseAPI) processSub(opID []byte, sub *database.Subscription) { // TODO: use upd, new and delete msgTypes r.Lock() isDeleted := r.Meta().IsDeleted() - new := r.Meta().Created == r.Meta().Modified + isNew := r.Meta().Created == r.Meta().Modified r.Unlock() switch { case isDeleted: api.send(opID, dbMsgTypeDel, r.Key(), nil) - case new: + case isNew: api.send(opID, dbMsgTypeNew, r.Key(), data) default: api.send(opID, dbMsgTypeUpd, r.Key(), data) diff --git a/api/endpoints.go b/api/endpoints.go index 14e6e60..f19b08f 100644 --- a/api/endpoints.go +++ b/api/endpoints.go @@ -21,7 +21,7 @@ import ( // Endpoint describes an API Endpoint. // Path and at least one permission are required. // As is exactly one function. -type Endpoint struct { +type Endpoint struct { //nolint:maligned // Path describes the URL path of the endpoint. Path string diff --git a/api/endpoints_test.go b/api/endpoints_test.go index 102b243..86568a5 100644 --- a/api/endpoints_test.go +++ b/api/endpoints_test.go @@ -5,8 +5,9 @@ import ( "sync" "testing" - "github.com/safing/portbase/database/record" "github.com/stretchr/testify/assert" + + "github.com/safing/portbase/database/record" ) const ( @@ -21,6 +22,8 @@ type actionTestRecord struct { } func TestEndpoints(t *testing.T) { + t.Parallel() + testHandler := &mainHandler{ mux: mainMux, } @@ -113,6 +116,8 @@ func TestEndpoints(t *testing.T) { } func TestActionRegistration(t *testing.T) { + t.Parallel() + assert.Error(t, RegisterEndpoint(Endpoint{})) assert.Error(t, RegisterEndpoint(Endpoint{ diff --git a/api/main_test.go b/api/main_test.go index 1cf19a4..8ca9089 100644 --- a/api/main_test.go +++ b/api/main_test.go @@ -6,11 +6,10 @@ import ( "os" "testing" - "github.com/safing/portbase/dataroot" - "github.com/safing/portbase/modules" - // API depends on the database for the database api. _ "github.com/safing/portbase/database/dbmodule" + "github.com/safing/portbase/dataroot" + "github.com/safing/portbase/modules" ) func init() { @@ -28,7 +27,7 @@ func TestMain(m *testing.M) { os.Exit(1) } // initialize data dir - err = dataroot.Initialize(tmpDir, 0755) + err = dataroot.Initialize(tmpDir, 0o0755) if err != nil { fmt.Fprintf(os.Stderr, "failed to initialize data root: %s\n", err) os.Exit(1) diff --git a/api/modules.go b/api/modules.go index 94b7594..1f79aea 100644 --- a/api/modules.go +++ b/api/modules.go @@ -6,6 +6,7 @@ import ( "github.com/safing/portbase/modules" ) +// ModuleHandler specifies the interface for API endpoints that are bound to a module. type ModuleHandler interface { BelongsTo() *modules.Module } diff --git a/api/request.go b/api/request.go index f5fdbc5..88d77af 100644 --- a/api/request.go +++ b/api/request.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/safing/portbase/log" ) @@ -32,9 +33,7 @@ type Request struct { // apiRequestContextKey is a key used for the context key/value storage. type apiRequestContextKey struct{} -var ( - requestContextKey = apiRequestContextKey{} -) +var requestContextKey = apiRequestContextKey{} // GetAPIRequest returns the API Request of the given http request. func GetAPIRequest(r *http.Request) *Request { diff --git a/api/router.go b/api/router.go index b197634..bdc24c3 100644 --- a/api/router.go +++ b/api/router.go @@ -10,18 +10,17 @@ import ( "sync" "time" - "github.com/safing/portbase/utils" - "github.com/gorilla/mux" "github.com/safing/portbase/log" + "github.com/safing/portbase/utils" ) var ( - // gorilla mux + // mainMux is the main mux router. mainMux = mux.NewRouter() - // main server and lock + // server is the main server. server = &http.Server{} handlerLock sync.RWMutex diff --git a/config/basic_config.go b/config/basic_config.go index 6975231..2d53c41 100644 --- a/config/basic_config.go +++ b/config/basic_config.go @@ -102,8 +102,8 @@ func registerBasicOptions() error { }) } -func loadLogLevel() { - setDefaultConfigOption(CfgLogLevel, log.GetLogLevel().Name(), false) +func loadLogLevel() error { + return setDefaultConfigOption(CfgLogLevel, log.GetLogLevel().Name(), false) } func setLogLevel(ctx context.Context, data interface{}) error { diff --git a/config/database.go b/config/database.go index 0f3ef2c..3d4228b 100644 --- a/config/database.go +++ b/config/database.go @@ -13,9 +13,7 @@ import ( "github.com/safing/portbase/log" ) -var ( - dbController *database.Controller -) +var dbController *database.Controller // StorageInterface provices a storage.Interface to the configuration manager. type StorageInterface struct { @@ -67,6 +65,8 @@ func (s *StorageInterface) Put(r record.Record) (record.Record, error) { value, ok = acc.GetInt("Value") case OptTypeBool: value, ok = acc.GetBool("Value") + case optTypeAny: + ok = false } if !ok { return nil, errors.New("received invalid value in \"Value\"") diff --git a/config/expertise.go b/config/expertise.go index 177f211..f6f7861 100644 --- a/config/expertise.go +++ b/config/expertise.go @@ -1,5 +1,3 @@ -// Package config ... (linter fix) -//nolint:dupl package config import ( diff --git a/config/get-safe.go b/config/get-safe.go index d48e94d..f03d453 100644 --- a/config/get-safe.go +++ b/config/get-safe.go @@ -4,10 +4,8 @@ import "sync" type safe struct{} -var ( - // Concurrent makes concurrency safe get methods available. - Concurrent = &safe{} -) +// Concurrent makes concurrency safe get methods available. +var Concurrent = &safe{} // GetAsString returns a function that returns the wanted string with high performance. func (cs *safe) GetAsString(name string, fallback string) StringOption { diff --git a/config/get_test.go b/config/get_test.go index cb1b2fa..15d10b9 100644 --- a/config/get_test.go +++ b/config/get_test.go @@ -26,6 +26,8 @@ func parseAndReplaceDefaultConfig(jsonData string) error { } func quickRegister(t *testing.T, key string, optType OptionType, defaultValue interface{}) { + t.Helper() + err := Register(&Option{ Name: key, Key: key, @@ -40,7 +42,7 @@ func quickRegister(t *testing.T, key string, optType OptionType, defaultValue in } } -func TestGet(t *testing.T) { //nolint:gocognit +func TestGet(t *testing.T) { //nolint:paralleltest // reset options = make(map[string]*Option) @@ -181,7 +183,7 @@ func TestGet(t *testing.T) { //nolint:gocognit } } -func TestReleaseLevel(t *testing.T) { +func TestReleaseLevel(t *testing.T) { //nolint:paralleltest // reset options = make(map[string]*Option) registerReleaseLevelOption() diff --git a/config/main.go b/config/main.go index f98510e..8127779 100644 --- a/config/main.go +++ b/config/main.go @@ -54,9 +54,12 @@ func start() error { configFilePath = filepath.Join(dataRoot.Path, "config.json") // Load log level from log package after it started. - loadLogLevel() + err := loadLogLevel() + if err != nil { + return err + } - err := registerAsDatabase() + err = registerAsDatabase() if err != nil && !os.IsNotExist(err) { return err } diff --git a/config/persistence.go b/config/persistence.go index c3fff2d..ba18750 100644 --- a/config/persistence.go +++ b/config/persistence.go @@ -9,9 +9,7 @@ import ( "github.com/safing/portbase/log" ) -var ( - configFilePath string -) +var configFilePath string func loadConfig() error { // check if persistence is configured @@ -69,7 +67,7 @@ func saveConfig() error { } // write file - return ioutil.WriteFile(configFilePath, data, 0600) + return ioutil.WriteFile(configFilePath, data, 0o0600) } // JSONToMap parses and flattens a hierarchical json object. diff --git a/config/persistence_test.go b/config/persistence_test.go index 70584c5..982835c 100644 --- a/config/persistence_test.go +++ b/config/persistence_test.go @@ -36,6 +36,7 @@ var ( ) func TestJSONMapConversion(t *testing.T) { + t.Parallel() // convert to json j, err := MapToJSON(mapData) @@ -67,6 +68,8 @@ func TestJSONMapConversion(t *testing.T) { } func TestConfigCleaning(t *testing.T) { + t.Parallel() + // load configFlat, err := JSONToMap(jsonBytes) if err != nil { diff --git a/config/perspective.go b/config/perspective.go index ba4b428..9351051 100644 --- a/config/perspective.go +++ b/config/perspective.go @@ -55,7 +55,7 @@ optionsLoop: if firstErr != nil { if errCnt > 0 { - return perspective, fmt.Errorf("encountered %d errors, first was: %s", errCnt, firstErr) + return perspective, fmt.Errorf("encountered %d errors, first was: %w", errCnt, firstErr) } return perspective, firstErr } diff --git a/config/registry.go b/config/registry.go index 3b80367..1e2e351 100644 --- a/config/registry.go +++ b/config/registry.go @@ -88,13 +88,13 @@ func Register(option *Option) error { if option.ValidationRegex != "" { option.compiledRegex, err = regexp.Compile(option.ValidationRegex) if err != nil { - return fmt.Errorf("config: could not compile option.ValidationRegex: %s", err) + return fmt.Errorf("config: could not compile option.ValidationRegex: %w", err) } } option.activeFallbackValue, err = validateValue(option, option.DefaultValue) if err != nil { - return fmt.Errorf("config: invalid default value: %s", err) + return fmt.Errorf("config: invalid default value: %w", err) } optionsLock.Lock() diff --git a/config/registry_test.go b/config/registry_test.go index 3f5593a..c64aa2d 100644 --- a/config/registry_test.go +++ b/config/registry_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -func TestRegistry(t *testing.T) { +func TestRegistry(t *testing.T) { //nolint:paralleltest // reset options = make(map[string]*Option) @@ -46,5 +46,4 @@ func TestRegistry(t *testing.T) { }); err == nil { t.Error("should fail") } - } diff --git a/config/release.go b/config/release.go index 2d6d98d..2b50e16 100644 --- a/config/release.go +++ b/config/release.go @@ -1,5 +1,3 @@ -// Package config ... (linter fix) -//nolint:dupl package config import ( @@ -12,7 +10,7 @@ import ( // configuration setting. type ReleaseLevel uint8 -// Release Level constants +// Release Level constants. const ( ReleaseLevelStable ReleaseLevel = 0 ReleaseLevelBeta ReleaseLevel = 1 diff --git a/config/set.go b/config/set.go index b9b11ff..f9c285a 100644 --- a/config/set.go +++ b/config/set.go @@ -74,7 +74,7 @@ func replaceConfig(newValues map[string]interface{}) error { if firstErr != nil { if errCnt > 0 { - return fmt.Errorf("encountered %d errors, first was: %s", errCnt, firstErr) + return fmt.Errorf("encountered %d errors, first was: %w", errCnt, firstErr) } return firstErr } @@ -117,7 +117,7 @@ func replaceDefaultConfig(newValues map[string]interface{}) error { if firstErr != nil { if errCnt > 0 { - return fmt.Errorf("encountered %d errors, first was: %s", errCnt, firstErr) + return fmt.Errorf("encountered %d errors, first was: %w", errCnt, firstErr) } return firstErr } diff --git a/config/set_test.go b/config/set_test.go index 1543a22..3c9037e 100644 --- a/config/set_test.go +++ b/config/set_test.go @@ -3,7 +3,7 @@ package config import "testing" -func TestLayersGetters(t *testing.T) { +func TestLayersGetters(t *testing.T) { //nolint:paralleltest // reset options = make(map[string]*Option) @@ -77,10 +77,9 @@ func TestLayersGetters(t *testing.T) { if notBool() { t.Error("expected fallback value: false") } - } -func TestLayersSetters(t *testing.T) { +func TestLayersSetters(t *testing.T) { //nolint:paralleltest // reset options = make(map[string]*Option) @@ -191,5 +190,4 @@ func TestLayersSetters(t *testing.T) { if err := SetDefaultConfigOption("invalid_delete", nil); err == nil { t.Error("should fail") } - } diff --git a/config/validate.go b/config/validate.go index 58fd319..472c645 100644 --- a/config/validate.go +++ b/config/validate.go @@ -24,6 +24,8 @@ func (vc *valueCache) getData(opt *Option) interface{} { return vc.stringVal case OptTypeStringArray: return vc.stringArrayVal + case optTypeAny: + return nil default: return nil } @@ -90,7 +92,6 @@ func validateValue(option *Option, value interface{}) (*valueCache, error) { //n s, ok := entry.(string) if !ok { return nil, fmt.Errorf("validation of option %s failed: element %+v at index %d is not a string", option.Key, entry, pos) - } vConverted[pos] = s } diff --git a/container/container.go b/container/container.go index 1753eb0..1f8d6f8 100644 --- a/container/container.go +++ b/container/container.go @@ -7,7 +7,7 @@ import ( "github.com/safing/portbase/formats/varint" ) -// Container is []byte sclie on steroids, allowing for quick data appending, prepending and fetching as well as transparent error transportation. (Error transportation requires use of varints for data) +// Container is []byte sclie on steroids, allowing for quick data appending, prepending and fetching. type Container struct { compartments [][]byte offset int @@ -145,12 +145,12 @@ func (c *Container) GetAll() []byte { // GetAsContainer returns the given amount of bytes in a new container. Data will NOT be copied and IS consumed. func (c *Container) GetAsContainer(n int) (*Container, error) { - new := c.gatherAsContainer(n) - if new == nil { + newC := c.gatherAsContainer(n) + if newC == nil { return nil, errors.New("container: not enough data to return") } c.skip(n) - return new, nil + return newC, nil } // GetMax returns as much as possible, but the given amount of bytes at maximum. Data MAY be copied and IS consumed. @@ -211,17 +211,13 @@ func (c *Container) renewCompartments() { } func (c *Container) carbonCopy() *Container { - new := &Container{ + newC := &Container{ compartments: make([][]byte, len(c.compartments)), offset: c.offset, err: c.err, } - for i := 0; i < len(c.compartments); i++ { - new.compartments[i] = c.compartments[i] - } - // TODO: investigate why copy fails to correctly duplicate [][]byte - // copy(new.compartments, c.compartments) - return new + copy(newC.compartments, c.compartments) + return newC } func (c *Container) checkOffset() { @@ -300,7 +296,7 @@ func (c *Container) gather(n int) []byte { return slice[:n] } -func (c *Container) gatherAsContainer(n int) (new *Container) { +func (c *Container) gatherAsContainer(n int) (newC *Container) { // Check requested length. if n < 0 { return nil @@ -308,20 +304,20 @@ func (c *Container) gatherAsContainer(n int) (new *Container) { return &Container{} } - new = &Container{} + newC = &Container{} for i := c.offset; i < len(c.compartments); i++ { if n >= len(c.compartments[i]) { - new.compartments = append(new.compartments, c.compartments[i]) + newC.compartments = append(newC.compartments, c.compartments[i]) n -= len(c.compartments[i]) } else { - new.compartments = append(new.compartments, c.compartments[i][:n]) + newC.compartments = append(newC.compartments, c.compartments[i][:n]) n = 0 } } if n > 0 { return nil } - return new + return newC } func (c *Container) skip(n int) { diff --git a/container/container_test.go b/container/container_test.go index 238e9bb..dc3963a 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -23,6 +23,7 @@ var ( ) func TestContainerDataHandling(t *testing.T) { + t.Parallel() c1 := New(utils.DuplicateBytes(testData)) c1c := c1.carbonCopy() @@ -74,6 +75,8 @@ func TestContainerDataHandling(t *testing.T) { } func compareMany(t *testing.T, reference []byte, other ...[]byte) { + t.Helper() + for i, cmp := range other { if !bytes.Equal(reference, cmp) { t.Errorf("sample %d does not match reference: sample is '%s'", i+1, string(cmp)) @@ -82,6 +85,8 @@ func compareMany(t *testing.T, reference []byte, other ...[]byte) { } func TestDataFetching(t *testing.T) { + t.Parallel() + c1 := New(utils.DuplicateBytes(testData)) data := c1.GetMax(1) if string(data[0]) != "T" { @@ -100,6 +105,8 @@ func TestDataFetching(t *testing.T) { } func TestBlocks(t *testing.T) { + t.Parallel() + c1 := New(utils.DuplicateBytes(testData)) c1.PrependLength() @@ -137,10 +144,10 @@ func TestBlocks(t *testing.T) { if n4 != 43 { t.Errorf("n should be 43, was %d", n4) } - } func TestContainerBlockHandling(t *testing.T) { + t.Parallel() c1 := New(utils.DuplicateBytes(testData)) c1.PrependLength() @@ -185,6 +192,8 @@ func TestContainerBlockHandling(t *testing.T) { } func TestContainerMisc(t *testing.T) { + t.Parallel() + c1 := New() d1 := c1.CompileData() if len(d1) > 0 { @@ -193,5 +202,7 @@ func TestContainerMisc(t *testing.T) { } func TestDeprecated(t *testing.T) { + t.Parallel() + NewContainer(utils.DuplicateBytes(testData)) } diff --git a/database/accessor/accessor-json-bytes.go b/database/accessor/accessor-json-bytes.go index f8a6923..0c2b7c8 100644 --- a/database/accessor/accessor-json-bytes.go +++ b/database/accessor/accessor-json-bytes.go @@ -27,11 +27,11 @@ func (ja *JSONBytesAccessor) Set(key string, value interface{}) error { } } - new, err := sjson.SetBytes(*ja.json, key, value) + newJSON, err := sjson.SetBytes(*ja.json, key, value) if err != nil { return err } - *ja.json = new + *ja.json = newJSON return nil } @@ -60,15 +60,15 @@ func (ja *JSONBytesAccessor) GetStringArray(key string) (value []string, ok bool return nil, false } slice := result.Array() - new := make([]string, len(slice)) + sliceCopy := make([]string, len(slice)) for i, res := range slice { if res.Type == gjson.String { - new[i] = res.String() + sliceCopy[i] = res.String() } else { return nil, false } } - return new, true + return sliceCopy, true } // GetInt returns the int found by the given json key and whether it could be successfully extracted. diff --git a/database/accessor/accessor-json-string.go b/database/accessor/accessor-json-string.go index b6e8025..0a2767f 100644 --- a/database/accessor/accessor-json-string.go +++ b/database/accessor/accessor-json-string.go @@ -29,11 +29,11 @@ func (ja *JSONAccessor) Set(key string, value interface{}) error { } } - new, err := sjson.Set(*ja.json, key, value) + newJSON, err := sjson.Set(*ja.json, key, value) if err != nil { return err } - *ja.json = new + *ja.json = newJSON return nil } @@ -84,15 +84,15 @@ func (ja *JSONAccessor) GetStringArray(key string) (value []string, ok bool) { return nil, false } slice := result.Array() - new := make([]string, len(slice)) + sliceCopy := make([]string, len(slice)) for i, res := range slice { if res.Type == gjson.String { - new[i] = res.String() + sliceCopy[i] = res.String() } else { return nil, false } } - return new, true + return sliceCopy, true } // GetInt returns the int found by the given json key and whether it could be successfully extracted. diff --git a/database/accessor/accessor-struct.go b/database/accessor/accessor-struct.go index c13072b..97c46a2 100644 --- a/database/accessor/accessor-struct.go +++ b/database/accessor/accessor-struct.go @@ -37,12 +37,12 @@ func (sa *StructAccessor) Set(key string, value interface{}) error { } // handle special cases - switch field.Kind() { + switch field.Kind() { // nolint:exhaustive // ints case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: var newInt int64 - switch newVal.Kind() { + switch newVal.Kind() { // nolint:exhaustive case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: newInt = newVal.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: @@ -58,7 +58,7 @@ func (sa *StructAccessor) Set(key string, value interface{}) error { // uints case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: var newUint uint64 - switch newVal.Kind() { + switch newVal.Kind() { // nolint:exhaustive case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: newUint = uint64(newVal.Int()) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: @@ -73,7 +73,7 @@ func (sa *StructAccessor) Set(key string, value interface{}) error { // floats case reflect.Float32, reflect.Float64: - switch newVal.Kind() { + switch newVal.Kind() { // nolint:exhaustive case reflect.Float32, reflect.Float64: field.SetFloat(newVal.Float()) default: @@ -124,7 +124,7 @@ func (sa *StructAccessor) GetInt(key string) (value int64, ok bool) { if !field.IsValid() { return 0, false } - switch field.Kind() { + switch field.Kind() { // nolint:exhaustive case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int(), true case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: @@ -140,7 +140,7 @@ func (sa *StructAccessor) GetFloat(key string) (value float64, ok bool) { if !field.IsValid() { return 0, false } - switch field.Kind() { + switch field.Kind() { // nolint:exhaustive case reflect.Float32, reflect.Float64: return field.Float(), true default: diff --git a/database/accessor/accessor_test.go b/database/accessor/accessor_test.go index 3d6d5bb..302c8aa 100644 --- a/database/accessor/accessor_test.go +++ b/database/accessor/accessor_test.go @@ -49,6 +49,8 @@ var ( ) func testGetString(t *testing.T, acc Accessor, key string, shouldSucceed bool, expectedValue string) { + t.Helper() + v, ok := acc.GetString(key) switch { case !ok && shouldSucceed: @@ -62,6 +64,8 @@ func testGetString(t *testing.T, acc Accessor, key string, shouldSucceed bool, e } func testGetStringArray(t *testing.T, acc Accessor, key string, shouldSucceed bool, expectedValue []string) { + t.Helper() + v, ok := acc.GetStringArray(key) switch { case !ok && shouldSucceed: @@ -75,6 +79,8 @@ func testGetStringArray(t *testing.T, acc Accessor, key string, shouldSucceed bo } func testGetInt(t *testing.T, acc Accessor, key string, shouldSucceed bool, expectedValue int64) { + t.Helper() + v, ok := acc.GetInt(key) switch { case !ok && shouldSucceed: @@ -88,6 +94,8 @@ func testGetInt(t *testing.T, acc Accessor, key string, shouldSucceed bool, expe } func testGetFloat(t *testing.T, acc Accessor, key string, shouldSucceed bool, expectedValue float64) { + t.Helper() + v, ok := acc.GetFloat(key) switch { case !ok && shouldSucceed: @@ -101,6 +109,8 @@ func testGetFloat(t *testing.T, acc Accessor, key string, shouldSucceed bool, ex } func testGetBool(t *testing.T, acc Accessor, key string, shouldSucceed bool, expectedValue bool) { + t.Helper() + v, ok := acc.GetBool(key) switch { case !ok && shouldSucceed: @@ -114,6 +124,8 @@ func testGetBool(t *testing.T, acc Accessor, key string, shouldSucceed bool, exp } func testExists(t *testing.T, acc Accessor, key string, shouldSucceed bool) { + t.Helper() + ok := acc.Exists(key) switch { case !ok && shouldSucceed: @@ -124,6 +136,8 @@ func testExists(t *testing.T, acc Accessor, key string, shouldSucceed bool) { } func testSet(t *testing.T, acc Accessor, key string, shouldSucceed bool, valueToSet interface{}) { + t.Helper() + err := acc.Set(key, valueToSet) switch { case err != nil && shouldSucceed: @@ -134,8 +148,9 @@ func testSet(t *testing.T, acc Accessor, key string, shouldSucceed bool, valueTo } func TestAccessor(t *testing.T) { + t.Parallel() - // Test interface compliance + // Test interface compliance. accs := []Accessor{ NewJSONAccessor(&testJSON), NewJSONBytesAccessor(&testJSONBytes), @@ -273,5 +288,4 @@ func TestAccessor(t *testing.T) { for _, acc := range accs { testExists(t, acc, "X", false) } - } diff --git a/database/boilerplate_test.go b/database/boilerplate_test.go index 9cf3383..e6fac39 100644 --- a/database/boilerplate_test.go +++ b/database/boilerplate_test.go @@ -15,12 +15,10 @@ type Example struct { Score int } -var ( - exampleDB = NewInterface(&Options{ - Internal: true, - Local: true, - }) -) +var exampleDB = NewInterface(&Options{ + Internal: true, + Local: true, +}) // GetExample gets an Example from the database. func GetExample(key string) (*Example, error) { @@ -32,20 +30,20 @@ func GetExample(key string) (*Example, error) { // unwrap if r.IsWrapped() { // only allocate a new struct, if we need it - new := &Example{} - err = record.Unwrap(r, new) + newExample := &Example{} + err = record.Unwrap(r, newExample) if err != nil { return nil, err } - return new, nil + return newExample, nil } // or adjust type - new, ok := r.(*Example) + newExample, ok := r.(*Example) if !ok { return nil, fmt.Errorf("record not of type *Example, but %T", r) } - return new, nil + return newExample, nil } func (e *Example) Save() error { @@ -58,10 +56,10 @@ func (e *Example) SaveAs(key string) error { } func NewExample(key, name string, score int) *Example { - new := &Example{ + newExample := &Example{ Name: name, Score: score, } - new.SetKey(key) - return new + newExample.SetKey(key) + return newExample } diff --git a/database/controller.go b/database/controller.go index 47f7444..4cadd45 100644 --- a/database/controller.go +++ b/database/controller.go @@ -78,7 +78,7 @@ func (c *Controller) Get(key string) (record.Record, error) { return r, nil } -// Get returns the metadata of the record with the given key. +// GetMeta returns the metadata of the record with the given key. func (c *Controller) GetMeta(key string) (*record.Meta, error) { if shuttingDown.IsSet() { return nil, ErrShuttingDown diff --git a/database/controllers.go b/database/controllers.go index 13d8fde..e684381 100644 --- a/database/controllers.go +++ b/database/controllers.go @@ -8,6 +8,7 @@ import ( "github.com/safing/portbase/database/storage" ) +// StorageTypeInjected is the type of injected databases. const StorageTypeInjected = "injected" var ( @@ -38,7 +39,7 @@ func getController(name string) (*Controller, error) { // get db registration registeredDB, err := getDatabase(name) if err != nil { - return nil, fmt.Errorf(`could not start database %s: %s`, name, err) + return nil, fmt.Errorf("could not start database %s: %w", name, err) } // Check if database is injected. @@ -49,13 +50,13 @@ func getController(name string) (*Controller, error) { // get location dbLocation, err := getLocation(name, registeredDB.StorageType) if err != nil { - return nil, fmt.Errorf(`could not start database %s (type %s): %s`, name, registeredDB.StorageType, err) + return nil, fmt.Errorf("could not start database %s (type %s): %w", name, registeredDB.StorageType, err) } // start database storageInt, err := storage.StartDatabase(name, registeredDB.StorageType, dbLocation) if err != nil { - return nil, fmt.Errorf(`could not start database %s (type %s): %s`, name, registeredDB.StorageType, err) + return nil, fmt.Errorf("could not start database %s (type %s): %w", name, registeredDB.StorageType, err) } controller = newController(registeredDB, storageInt, registeredDB.ShadowDelete) diff --git a/database/database.go b/database/database.go index 9b77f04..332c3f8 100644 --- a/database/database.go +++ b/database/database.go @@ -4,7 +4,7 @@ import ( "time" ) -// Database holds information about registered databases +// Database holds information about a registered database. type Database struct { Name string Description string diff --git a/database/database_test.go b/database/database_test.go index b6d793e..c4c2a30 100644 --- a/database/database_test.go +++ b/database/database_test.go @@ -2,6 +2,7 @@ package database import ( "context" + "errors" "fmt" "io/ioutil" "log" @@ -11,11 +12,9 @@ import ( "testing" "time" - "github.com/safing/portbase/database/storage" - q "github.com/safing/portbase/database/query" "github.com/safing/portbase/database/record" - + "github.com/safing/portbase/database/storage" _ "github.com/safing/portbase/database/storage/badger" _ "github.com/safing/portbase/database/storage/bbolt" _ "github.com/safing/portbase/database/storage/fstree" @@ -46,7 +45,7 @@ func makeKey(dbName, key string) string { return fmt.Sprintf("%s:%s", dbName, key) } -func testDatabase(t *testing.T, storageType string, shadowDelete bool) { //nolint:gocognit,gocyclo +func testDatabase(t *testing.T, storageType string, shadowDelete bool) { //nolint:gocognit,gocyclo,thelper t.Run(fmt.Sprintf("TestStorage_%s_%v", storageType, shadowDelete), func(t *testing.T) { dbName := fmt.Sprintf("testing-%s-%v", storageType, shadowDelete) fmt.Println(dbName) @@ -180,7 +179,7 @@ func testDatabase(t *testing.T, storageType string, shadowDelete bool) { //nolin // check status individually _, err = dbController.storage.Get("A") - if err != storage.ErrNotFound { + if !errors.Is(err, storage.ErrNotFound) { t.Errorf("A should be deleted and purged, err=%s", err) } B1, err := dbController.storage.Get("B") @@ -208,13 +207,13 @@ func testDatabase(t *testing.T, storageType string, shadowDelete bool) { //nolin B2, err := dbController.storage.Get("B") if err == nil { t.Errorf("B should be deleted and purged, meta: %+v", B2.Meta()) - } else if err != storage.ErrNotFound { + } else if !errors.Is(err, storage.ErrNotFound) { t.Errorf("B should be deleted and purged, err=%s", err) } C2, err := dbController.storage.Get("C") if err == nil { t.Errorf("C should be deleted and purged, meta: %+v", C2.Meta()) - } else if err != storage.ErrNotFound { + } else if !errors.Is(err, storage.ErrNotFound) { t.Errorf("C should be deleted and purged, err=%s", err) } @@ -233,11 +232,11 @@ func testDatabase(t *testing.T, storageType string, shadowDelete bool) { //nolin if err != nil { t.Fatal(err) } - }) } -func TestDatabaseSystem(t *testing.T) { +func TestDatabaseSystem(t *testing.T) { //nolint:tparallel + t.Parallel() // panic after 10 seconds, to check for locks finished := make(chan struct{}) @@ -282,6 +281,8 @@ func TestDatabaseSystem(t *testing.T) { } func countRecords(t *testing.T, db *Interface, query *q.Query) int { + t.Helper() + _, err := query.Check() if err != nil { t.Fatal(err) diff --git a/database/errors.go b/database/errors.go index 1322423..425b0f3 100644 --- a/database/errors.go +++ b/database/errors.go @@ -4,7 +4,7 @@ import ( "errors" ) -// Errors +// Errors. var ( ErrNotFound = errors.New("database entry not found") ErrPermissionDenied = errors.New("access to database record denied") diff --git a/database/hookbase.go b/database/hookbase.go index e89c3cc..ff5d815 100644 --- a/database/hookbase.go +++ b/database/hookbase.go @@ -5,8 +5,7 @@ import ( ) // HookBase implements the Hook interface and provides dummy functions to reduce boilerplate. -type HookBase struct { -} +type HookBase struct{} // UsesPreGet implements the Hook interface and returns false. func (b *HookBase) UsesPreGet() bool { diff --git a/database/interface.go b/database/interface.go index 74a6dbe..acf7bd8 100644 --- a/database/interface.go +++ b/database/interface.go @@ -120,19 +120,19 @@ func NewInterface(opts *Options) *Interface { opts = &Options{} } - new := &Interface{ + newIface := &Interface{ options: opts, } if opts.CacheSize > 0 { cacheBuilder := gcache.New(opts.CacheSize).ARC() if opts.DelayCachedWrites != "" { - cacheBuilder.EvictedFunc(new.cacheEvictHandler) - new.writeCache = make(map[string]record.Record, opts.CacheSize/2) - new.triggerCacheWrite = make(chan struct{}) + cacheBuilder.EvictedFunc(newIface.cacheEvictHandler) + newIface.writeCache = make(map[string]record.Record, opts.CacheSize/2) + newIface.triggerCacheWrite = make(chan struct{}) } - new.cache = cacheBuilder.Build() + newIface.cache = cacheBuilder.Build() } - return new + return newIface } // Exists return whether a record with the given key exists. @@ -157,7 +157,7 @@ func (i *Interface) Get(key string) (record.Record, error) { return r, err } -func (i *Interface) getRecord(dbName string, dbKey string, mustBeWriteable bool) (r record.Record, db *Controller, err error) { +func (i *Interface) getRecord(dbName string, dbKey string, mustBeWriteable bool) (r record.Record, db *Controller, err error) { //nolint:unparam if dbName == "" { dbName, dbKey = record.ParseKey(dbKey) } @@ -201,7 +201,7 @@ func (i *Interface) getRecord(dbName string, dbKey string, mustBeWriteable bool) return r, db, nil } -func (i *Interface) getMeta(dbName string, dbKey string, mustBeWriteable bool) (m *record.Meta, db *Controller, err error) { +func (i *Interface) getMeta(dbName string, dbKey string, mustBeWriteable bool) (m *record.Meta, db *Controller, err error) { //nolint:unparam if dbName == "" { dbName, dbKey = record.ParseKey(dbKey) } @@ -258,7 +258,7 @@ func (i *Interface) InsertValue(key string, attribute string, value interface{}) err = acc.Set(attribute, value) if err != nil { - return fmt.Errorf("failed to set value with %s: %s", acc.Type(), err) + return fmt.Errorf("failed to set value with %s: %w", acc.Type(), err) } i.options.Apply(r) @@ -271,7 +271,7 @@ func (i *Interface) Put(r record.Record) (err error) { var db *Controller if !i.options.HasAllPermissions() { _, db, err = i.getMeta(r.DatabaseName(), r.DatabaseKey(), true) - if err != nil && err != ErrNotFound { + if err != nil && !errors.Is(err, ErrNotFound) { return err } } else { @@ -309,7 +309,7 @@ func (i *Interface) PutNew(r record.Record) (err error) { var db *Controller if !i.options.HasAllPermissions() { _, db, err = i.getMeta(r.DatabaseName(), r.DatabaseKey(), true) - if err != nil && err != ErrNotFound { + if err != nil && !errors.Is(err, ErrNotFound) { return err } } else { @@ -344,11 +344,13 @@ func (i *Interface) PutNew(r record.Record) (err error) { return db.Put(r) } -// PutMany stores many records in the database. Warning: This is nearly a direct database access and omits many things: +// PutMany stores many records in the database. +// Warning: This is nearly a direct database access and omits many things: // - Record locking // - Hooks // - Subscriptions // - Caching +// Use with care. func (i *Interface) PutMany(dbName string) (put func(record.Record) error) { interfaceBatch := make(chan record.Record, 100) @@ -519,6 +521,8 @@ func (i *Interface) Delete(key string) error { } // Query executes the given query on the database. +// Will not see data that is in the write cache, waiting to be written. +// Use with care with caching. func (i *Interface) Query(q *query.Query) (*iterator.Iterator, error) { _, err := q.Check() if err != nil { @@ -530,7 +534,7 @@ func (i *Interface) Query(q *query.Query) (*iterator.Iterator, error) { return nil, err } - // FIXME: + // TODO: Finish caching system integration. // Flush the cache before we query the database. // i.FlushCache() diff --git a/database/interface_cache.go b/database/interface_cache.go index f49f54c..cd57011 100644 --- a/database/interface_cache.go +++ b/database/interface_cache.go @@ -57,7 +57,6 @@ func (i *Interface) DelayedCacheWriter(ctx context.Context) error { // of a total crash. i.flushWriteCache(0) } - } } diff --git a/database/interface_cache_test.go b/database/interface_cache_test.go index ff65260..cfed438 100644 --- a/database/interface_cache_test.go +++ b/database/interface_cache_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -func benchmarkCacheWriting(b *testing.B, storageType string, cacheSize int, sampleSize int, delayWrites bool) { //nolint:gocognit,gocyclo +func benchmarkCacheWriting(b *testing.B, storageType string, cacheSize int, sampleSize int, delayWrites bool) { //nolint:gocognit,gocyclo,thelper b.Run(fmt.Sprintf("CacheWriting_%s_%d_%d_%v", storageType, cacheSize, sampleSize, delayWrites), func(b *testing.B) { // Setup Benchmark. @@ -66,11 +66,10 @@ func benchmarkCacheWriting(b *testing.B, storageType string, cacheSize int, samp // End cache writer and wait cancelCtx() wg.Wait() - }) } -func benchmarkCacheReadWrite(b *testing.B, storageType string, cacheSize int, sampleSize int, delayWrites bool) { //nolint:gocognit,gocyclo +func benchmarkCacheReadWrite(b *testing.B, storageType string, cacheSize int, sampleSize int, delayWrites bool) { //nolint:gocognit,gocyclo,thelper b.Run(fmt.Sprintf("CacheReadWrite_%s_%d_%d_%v", storageType, cacheSize, sampleSize, delayWrites), func(b *testing.B) { // Setup Benchmark. @@ -135,7 +134,6 @@ func benchmarkCacheReadWrite(b *testing.B, storageType string, cacheSize int, sa // End cache writer and wait cancelCtx() wg.Wait() - }) } diff --git a/database/main.go b/database/main.go index ad73f1e..f41ea18 100644 --- a/database/main.go +++ b/database/main.go @@ -5,8 +5,9 @@ import ( "fmt" "path/filepath" - "github.com/safing/portbase/utils" "github.com/tevino/abool" + + "github.com/safing/portbase/utils" ) const ( @@ -25,7 +26,7 @@ var ( // InitializeWithPath initializes the database at the specified location using a path. func InitializeWithPath(dirPath string) error { - return Initialize(utils.NewDirStructure(dirPath, 0755)) + return Initialize(utils.NewDirStructure(dirPath, 0o0755)) } // Initialize initializes the database at the specified location using a dir structure. @@ -34,16 +35,16 @@ func Initialize(dirStructureRoot *utils.DirStructure) error { rootStructure = dirStructureRoot // ensure root and databases dirs - databasesStructure = rootStructure.ChildDir(databasesSubDir, 0700) + databasesStructure = rootStructure.ChildDir(databasesSubDir, 0o0700) err := databasesStructure.Ensure() if err != nil { - return fmt.Errorf("could not create/open database directory (%s): %s", rootStructure.Path, err) + return fmt.Errorf("could not create/open database directory (%s): %w", rootStructure.Path, err) } if registryPersistence.IsSet() { err = loadRegistry() if err != nil { - return fmt.Errorf("could not load database registry (%s): %s", filepath.Join(rootStructure.Path, registryFileName), err) + return fmt.Errorf("could not load database registry (%s): %w", filepath.Join(rootStructure.Path, registryFileName), err) } } @@ -74,11 +75,11 @@ func Shutdown() (err error) { // getLocation returns the storage location for the given name and type. func getLocation(name, storageType string) (string, error) { - location := databasesStructure.ChildDir(name, 0700).ChildDir(storageType, 0700) + location := databasesStructure.ChildDir(name, 0o0700).ChildDir(storageType, 0o0700) // check location err := location.Ensure() if err != nil { - return "", fmt.Errorf(`failed to create/check database dir "%s": %s`, location.Path, err) + return "", fmt.Errorf(`failed to create/check database dir "%s": %w`, location.Path, err) } return location.Path, nil } diff --git a/database/migration/error.go b/database/migration/error.go index 6920fe9..1ecb99f 100644 --- a/database/migration/error.go +++ b/database/migration/error.go @@ -2,12 +2,14 @@ package migration import "errors" +// DiagnosticStep describes one migration step in the Diagnostics. type DiagnosticStep struct { Version string Description string } -type Diagnostics struct { +// Diagnostics holds a detailed error report about a failed migration. +type Diagnostics struct { //nolint:errname // Message holds a human readable message of the encountered // error. Message string @@ -45,9 +47,9 @@ func (err *Diagnostics) Error() string { return msg } -// Unwrap returns the actual error that happend when executing +// Unwrap returns the actual error that happened when executing // a migration. It implements the interface required by the stdlib -// errors package to support errors.Is and errors.As +// errors package to support errors.Is() and errors.As(). func (err *Diagnostics) Unwrap() error { if u := errors.Unwrap(err.Wrapped); u != nil { return u diff --git a/database/migration/migration.go b/database/migration/migration.go index d03d76f..5cd6126 100644 --- a/database/migration/migration.go +++ b/database/migration/migration.go @@ -9,6 +9,7 @@ import ( "time" "github.com/hashicorp/go-version" + "github.com/safing/portbase/database" "github.com/safing/portbase/database/record" "github.com/safing/portbase/formats/dsd" @@ -37,6 +38,7 @@ type Migration struct { MigrateFunc MigrateFunc } +// Registry holds a migration stack. type Registry struct { key string @@ -200,7 +202,7 @@ func (reg *Registry) getExecutionPlan(startOfMigration *version.Version) ([]Migr } // prepare our diagnostics and the execution plan - var execPlan []Migration + execPlan := make([]Migration, 0, len(versions)) for _, ver := range versions { // skip an migration that has already been applied. if startOfMigration != nil && startOfMigration.GreaterThanOrEqual(ver) { diff --git a/database/query/condition-bool.go b/database/query/condition-bool.go index 6136546..a3d6461 100644 --- a/database/query/condition-bool.go +++ b/database/query/condition-bool.go @@ -15,7 +15,6 @@ type boolCondition struct { } func newBoolCondition(key string, operator uint8, value interface{}) *boolCondition { - var parsedValue bool switch v := value.(type) { diff --git a/database/query/condition-float.go b/database/query/condition-float.go index c140bd7..01b2875 100644 --- a/database/query/condition-float.go +++ b/database/query/condition-float.go @@ -15,7 +15,6 @@ type floatCondition struct { } func newFloatCondition(key string, operator uint8, value interface{}) *floatCondition { - var parsedValue float64 switch v := value.(type) { diff --git a/database/query/condition-int.go b/database/query/condition-int.go index 40e4cbc..a0e8b4e 100644 --- a/database/query/condition-int.go +++ b/database/query/condition-int.go @@ -15,7 +15,6 @@ type intCondition struct { } func newIntCondition(key string, operator uint8, value interface{}) *intCondition { - var parsedValue int64 switch v := value.(type) { diff --git a/database/query/condition-stringslice.go b/database/query/condition-stringslice.go index 5bdd168..8839d1f 100644 --- a/database/query/condition-stringslice.go +++ b/database/query/condition-stringslice.go @@ -15,7 +15,6 @@ type stringSliceCondition struct { } func newStringSliceCondition(key string, operator uint8, value interface{}) *stringSliceCondition { - switch v := value.(type) { case string: parsedValue := strings.Split(v, ",") @@ -42,7 +41,6 @@ func newStringSliceCondition(key string, operator uint8, value interface{}) *str operator: errorPresent, } } - } func (c *stringSliceCondition) complies(acc accessor.Accessor) bool { diff --git a/database/query/condition.go b/database/query/condition.go index 33b8e59..6f40e54 100644 --- a/database/query/condition.go +++ b/database/query/condition.go @@ -13,7 +13,7 @@ type Condition interface { string() string } -// Operators +// Operators. const ( Equals uint8 = iota // int GreaterThan // int diff --git a/database/query/condition_test.go b/database/query/condition_test.go index eb871a7..0ce2e55 100644 --- a/database/query/condition_test.go +++ b/database/query/condition_test.go @@ -3,6 +3,8 @@ package query import "testing" func testSuccess(t *testing.T, c Condition) { + t.Helper() + err := c.check() if err != nil { t.Errorf("failed: %s", err) @@ -10,6 +12,8 @@ func testSuccess(t *testing.T, c Condition) { } func TestInterfaces(t *testing.T) { + t.Parallel() + testSuccess(t, newIntCondition("banana", Equals, uint(1))) testSuccess(t, newIntCondition("banana", Equals, uint8(1))) testSuccess(t, newIntCondition("banana", Equals, uint16(1))) @@ -41,6 +45,8 @@ func TestInterfaces(t *testing.T) { } func testCondError(t *testing.T, c Condition) { + t.Helper() + err := c.check() if err == nil { t.Error("should fail") @@ -48,6 +54,8 @@ func testCondError(t *testing.T, c Condition) { } func TestConditionErrors(t *testing.T) { + t.Parallel() + // test invalid value types testCondError(t, newBoolCondition("banana", Is, 1)) testCondError(t, newFloatCondition("banana", FloatEquals, true)) @@ -68,6 +76,8 @@ func TestConditionErrors(t *testing.T) { } func TestWhere(t *testing.T) { + t.Parallel() + c := Where("", 254, nil) err := c.check() if err == nil { diff --git a/database/query/operators_test.go b/database/query/operators_test.go index 3f4fe81..9fa8441 100644 --- a/database/query/operators_test.go +++ b/database/query/operators_test.go @@ -3,6 +3,8 @@ package query import "testing" func TestGetOpName(t *testing.T) { + t.Parallel() + if getOpName(254) != "[unknown]" { t.Error("unexpected output") } diff --git a/database/query/parser.go b/database/query/parser.go index 54615e8..ff28ccf 100644 --- a/database/query/parser.go +++ b/database/query/parser.go @@ -121,7 +121,6 @@ func ParseQuery(query string) (*Query, error) { } func extractSnippets(text string) (snippets []*snippet, err error) { - skip := false start := -1 inParenthesis := false @@ -193,16 +192,17 @@ func extractSnippets(text string) (snippets []*snippet, err error) { } return snippets, nil - } //nolint:gocognit func parseAndOr(getSnippet func() (*snippet, error), remainingSnippets func() int, rootCondition bool) (Condition, error) { - var isOr = false - var typeSet = false - var wrapInNot = false - var expectingMore = true - var conditions []Condition + var ( + isOr = false + typeSet = false + wrapInNot = false + expectingMore = true + conditions []Condition + ) for { if !expectingMore && rootCondition && remainingSnippets() == 0 { @@ -331,21 +331,19 @@ func parseCondition(firstSnippet *snippet, getSnippet func() (*snippet, error)) return Where(firstSnippet.text, operator, value.text), nil } -var ( - escapeReplacer = regexp.MustCompile(`\\([^\\])`) -) +var escapeReplacer = regexp.MustCompile(`\\([^\\])`) // prepToken removes surrounding parenthesis and escape characters. func prepToken(text string) string { return escapeReplacer.ReplaceAllString(strings.Trim(text, "\""), "$1") } -// escapeString correctly escapes a snippet for printing +// escapeString correctly escapes a snippet for printing. func escapeString(token string) string { // check if token contains characters that need to be escaped if strings.ContainsAny(token, "()\"\\\t\r\n ") { // put the token in parenthesis and only escape \ and " - return fmt.Sprintf("\"%s\"", strings.Replace(token, "\"", "\\\"", -1)) + return fmt.Sprintf("\"%s\"", strings.ReplaceAll(token, "\"", "\\\"")) } return token } diff --git a/database/query/parser_test.go b/database/query/parser_test.go index 5dea347..fb30ad8 100644 --- a/database/query/parser_test.go +++ b/database/query/parser_test.go @@ -8,6 +8,8 @@ import ( ) func TestExtractSnippets(t *testing.T) { + t.Parallel() + text1 := `query test: where ( "bananas" > 100 and monkeys.# <= "12")or(coconuts < 10 "and" area > 50) or name sameas Julian or name matches ^King\ ` result1 := []*snippet{ {text: "query", globalPosition: 1}, @@ -58,6 +60,8 @@ func TestExtractSnippets(t *testing.T) { } func testParsing(t *testing.T, queryText string, expectedResult *Query) { + t.Helper() + _, err := expectedResult.Check() if err != nil { t.Errorf("failed to create query: %s", err) @@ -84,6 +88,8 @@ func testParsing(t *testing.T, queryText string, expectedResult *Query) { } func TestParseQuery(t *testing.T) { + t.Parallel() + text1 := `query test: where (bananas > 100 and monkeys.# <= 12) or not (coconuts < 10 and area not > 50) or name sameas Julian or name matches "^King " orderby name limit 10 offset 20` result1 := New("test:").Where(Or( And( @@ -131,6 +137,8 @@ func TestParseQuery(t *testing.T) { } func testParseError(t *testing.T, queryText string, expectedErrorString string) { + t.Helper() + _, err := ParseQuery(queryText) if err == nil { t.Errorf("should fail to parse: %s", queryText) @@ -142,6 +150,8 @@ func testParseError(t *testing.T, queryText string, expectedErrorString string) } func TestParseErrors(t *testing.T) { + t.Parallel() + // syntax testParseError(t, `query`, `unexpected end at position 5`) testParseError(t, `query test: where`, `unexpected end at position 17`) diff --git a/database/query/query_test.go b/database/query/query_test.go index 91f2854..255db04 100644 --- a/database/query/query_test.go +++ b/database/query/query_test.go @@ -8,9 +8,8 @@ import ( "github.com/safing/portbase/formats/dsd" ) -var ( - // copied from https://github.com/tidwall/gjson/blob/master/gjson_test.go - testJSON = `{"age":100, "name":{"here":"B\\\"R"}, +// copied from https://github.com/tidwall/gjson/blob/master/gjson_test.go +var testJSON = `{"age":100, "name":{"here":"B\\\"R"}, "noop":{"what is a wren?":"a bird"}, "happy":true,"immortal":false, "items":[1,2,3,{"tags":[1,2,3],"points":[[1,2],[3,4]]},4,5,6,7], @@ -46,11 +45,11 @@ var ( "lastly":{"yay":"final"}, "temperature": 120.413 }` -) func testQuery(t *testing.T, r record.Record, shouldMatch bool, condition Condition) { - q := New("test:").Where(condition).MustBeValid() + t.Helper() + q := New("test:").Where(condition).MustBeValid() // fmt.Printf("%s\n", q.Print()) matched := q.Matches(r) @@ -63,6 +62,7 @@ func testQuery(t *testing.T, r record.Record, shouldMatch bool, condition Condit } func TestQuery(t *testing.T) { + t.Parallel() // if !gjson.Valid(testJSON) { // t.Fatal("test json is invalid") @@ -110,5 +110,4 @@ func TestQuery(t *testing.T) { testQuery(t, r, true, Where("happy", Exists, nil)) testQuery(t, r, true, Where("created", Matches, "^2014-[0-9]{2}-[0-9]{2}T")) - } diff --git a/database/record/base_test.go b/database/record/base_test.go index f207bb1..2f15211 100644 --- a/database/record/base_test.go +++ b/database/record/base_test.go @@ -3,11 +3,11 @@ package record import "testing" func TestBaseRecord(t *testing.T) { + t.Parallel() // check model interface compliance var m Record b := &TestRecord{} m = b _ = m - } diff --git a/database/record/meta-bench_test.go b/database/record/meta-bench_test.go index a531693..d292d4a 100644 --- a/database/record/meta-bench_test.go +++ b/database/record/meta-bench_test.go @@ -24,22 +24,16 @@ import ( "github.com/safing/portbase/container" "github.com/safing/portbase/formats/dsd" "github.com/safing/portbase/formats/varint" - // Colfer - // "github.com/safing/portbase/database/model/model" - // XDR - // xdr2 "github.com/davecgh/go-xdr/xdr2" ) -var ( - testMeta = &Meta{ - Created: time.Now().Unix(), - Modified: time.Now().Unix(), - Expires: time.Now().Unix(), - Deleted: time.Now().Unix(), - secret: true, - cronjewel: true, - } -) +var testMeta = &Meta{ + Created: time.Now().Unix(), + Modified: time.Now().Unix(), + Expires: time.Now().Unix(), + Deleted: time.Now().Unix(), + secret: true, + cronjewel: true, +} func BenchmarkAllocateBytes(b *testing.B) { for i := 0; i < b.N; i++ { @@ -49,8 +43,8 @@ func BenchmarkAllocateBytes(b *testing.B) { func BenchmarkAllocateStruct1(b *testing.B) { for i := 0; i < b.N; i++ { - var new Meta - _ = new + var newMeta Meta + _ = newMeta } } @@ -61,7 +55,6 @@ func BenchmarkAllocateStruct2(b *testing.B) { } func BenchmarkMetaSerializeContainer(b *testing.B) { - // Start benchmark for i := 0; i < b.N; i++ { c := container.New() @@ -80,11 +73,9 @@ func BenchmarkMetaSerializeContainer(b *testing.B) { c.AppendNumber(0) } } - } func BenchmarkMetaUnserializeContainer(b *testing.B) { - // Setup c := container.New() c.AppendNumber(uint64(testMeta.Created)) @@ -157,11 +148,9 @@ func BenchmarkMetaUnserializeContainer(b *testing.B) { return } } - } func BenchmarkMetaSerializeVarInt(b *testing.B) { - // Start benchmark for i := 0; i < b.N; i++ { encoded := make([]byte, 33) @@ -197,13 +186,10 @@ func BenchmarkMetaSerializeVarInt(b *testing.B) { default: encoded[offset] = 0 } - offset++ } - } func BenchmarkMetaUnserializeVarInt(b *testing.B) { - // Setup encoded := make([]byte, 33) offset := 0 @@ -295,106 +281,9 @@ func BenchmarkMetaUnserializeVarInt(b *testing.B) { return } } - } -// func BenchmarkMetaSerializeWithXDR2(b *testing.B) { -// -// // Setup -// var w bytes.Buffer -// -// // Reset timer for precise results -// b.ResetTimer() -// -// // Start benchmark -// for i := 0; i < b.N; i++ { -// w.Reset() -// _, err := xdr2.Marshal(&w, testMeta) -// if err != nil { -// b.Errorf("failed to serialize with xdr2: %s", err) -// return -// } -// } -// -// } - -// func BenchmarkMetaUnserializeWithXDR2(b *testing.B) { -// -// // Setup -// var w bytes.Buffer -// _, err := xdr2.Marshal(&w, testMeta) -// if err != nil { -// b.Errorf("failed to serialize with xdr2: %s", err) -// } -// encodedData := w.Bytes() -// -// // Reset timer for precise results -// b.ResetTimer() -// -// // Start benchmark -// for i := 0; i < b.N; i++ { -// var newMeta Meta -// _, err := xdr2.Unmarshal(bytes.NewReader(encodedData), &newMeta) -// if err != nil { -// b.Errorf("failed to unserialize with xdr2: %s", err) -// return -// } -// } -// -// } - -// func BenchmarkMetaSerializeWithColfer(b *testing.B) { -// -// testColf := &model.Course{ -// Created: time.Now().Unix(), -// Modified: time.Now().Unix(), -// Expires: time.Now().Unix(), -// Deleted: time.Now().Unix(), -// Secret: true, -// Cronjewel: true, -// } -// -// // Setup -// for i := 0; i < b.N; i++ { -// _, err := testColf.MarshalBinary() -// if err != nil { -// b.Errorf("failed to serialize with colfer: %s", err) -// return -// } -// } -// -// } - -// func BenchmarkMetaUnserializeWithColfer(b *testing.B) { -// -// testColf := &model.Course{ -// Created: time.Now().Unix(), -// Modified: time.Now().Unix(), -// Expires: time.Now().Unix(), -// Deleted: time.Now().Unix(), -// Secret: true, -// Cronjewel: true, -// } -// encodedData, err := testColf.MarshalBinary() -// if err != nil { -// b.Errorf("failed to serialize with colfer: %s", err) -// return -// } -// -// // Setup -// for i := 0; i < b.N; i++ { -// var testUnColf model.Course -// err := testUnColf.UnmarshalBinary(encodedData) -// if err != nil { -// b.Errorf("failed to unserialize with colfer: %s", err) -// return -// } -// } -// -// } - func BenchmarkMetaSerializeWithCodegen(b *testing.B) { - for i := 0; i < b.N; i++ { _, err := testMeta.GenCodeMarshal(nil) if err != nil { @@ -402,11 +291,9 @@ func BenchmarkMetaSerializeWithCodegen(b *testing.B) { return } } - } func BenchmarkMetaUnserializeWithCodegen(b *testing.B) { - // Setup encodedData, err := testMeta.GenCodeMarshal(nil) if err != nil { @@ -426,11 +313,9 @@ func BenchmarkMetaUnserializeWithCodegen(b *testing.B) { return } } - } func BenchmarkMetaSerializeWithDSDJSON(b *testing.B) { - for i := 0; i < b.N; i++ { _, err := dsd.Dump(testMeta, dsd.JSON) if err != nil { @@ -438,11 +323,9 @@ func BenchmarkMetaSerializeWithDSDJSON(b *testing.B) { return } } - } func BenchmarkMetaUnserializeWithDSDJSON(b *testing.B) { - // Setup encodedData, err := dsd.Dump(testMeta, dsd.JSON) if err != nil { @@ -462,5 +345,4 @@ func BenchmarkMetaUnserializeWithDSDJSON(b *testing.B) { return } } - } diff --git a/database/record/meta-gencode.go b/database/record/meta-gencode.go index 6494a1d..98c2ce5 100644 --- a/database/record/meta-gencode.go +++ b/database/record/meta-gencode.go @@ -13,7 +13,7 @@ var ( _ = time.Now() ) -// GenCodeSize returns the size of the gencode marshalled byte slice +// GenCodeSize returns the size of the gencode marshalled byte slice. func (m *Meta) GenCodeSize() (s int) { s += 34 return @@ -133,24 +133,16 @@ func (m *Meta) GenCodeUnmarshal(buf []byte) (uint64, error) { i := uint64(0) { - m.Created = 0 | (int64(buf[0+0]) << 0) | (int64(buf[1+0]) << 8) | (int64(buf[2+0]) << 16) | (int64(buf[3+0]) << 24) | (int64(buf[4+0]) << 32) | (int64(buf[5+0]) << 40) | (int64(buf[6+0]) << 48) | (int64(buf[7+0]) << 56) - } { - m.Modified = 0 | (int64(buf[0+8]) << 0) | (int64(buf[1+8]) << 8) | (int64(buf[2+8]) << 16) | (int64(buf[3+8]) << 24) | (int64(buf[4+8]) << 32) | (int64(buf[5+8]) << 40) | (int64(buf[6+8]) << 48) | (int64(buf[7+8]) << 56) - } { - m.Expires = 0 | (int64(buf[0+16]) << 0) | (int64(buf[1+16]) << 8) | (int64(buf[2+16]) << 16) | (int64(buf[3+16]) << 24) | (int64(buf[4+16]) << 32) | (int64(buf[5+16]) << 40) | (int64(buf[6+16]) << 48) | (int64(buf[7+16]) << 56) - } { - m.Deleted = 0 | (int64(buf[0+24]) << 0) | (int64(buf[1+24]) << 8) | (int64(buf[2+24]) << 16) | (int64(buf[3+24]) << 24) | (int64(buf[4+24]) << 32) | (int64(buf[5+24]) << 40) | (int64(buf[6+24]) << 48) | (int64(buf[7+24]) << 56) - } { m.secret = buf[32] == 1 diff --git a/database/record/meta-gencode_test.go b/database/record/meta-gencode_test.go index 7050e7d..2de765c 100644 --- a/database/record/meta-gencode_test.go +++ b/database/record/meta-gencode_test.go @@ -6,30 +6,30 @@ import ( "time" ) -var ( - genCodeTestMeta = &Meta{ - Created: time.Now().Unix(), - Modified: time.Now().Unix(), - Expires: time.Now().Unix(), - Deleted: time.Now().Unix(), - secret: true, - cronjewel: true, - } -) +var genCodeTestMeta = &Meta{ + Created: time.Now().Unix(), + Modified: time.Now().Unix(), + Expires: time.Now().Unix(), + Deleted: time.Now().Unix(), + secret: true, + cronjewel: true, +} func TestGenCode(t *testing.T) { + t.Parallel() + encoded, err := genCodeTestMeta.GenCodeMarshal(nil) if err != nil { t.Fatal(err) } - new := &Meta{} - _, err = new.GenCodeUnmarshal(encoded) + newMeta := &Meta{} + _, err = newMeta.GenCodeUnmarshal(encoded) if err != nil { t.Fatal(err) } - if !reflect.DeepEqual(genCodeTestMeta, new) { - t.Errorf("objects are not equal, got: %v", new) + if !reflect.DeepEqual(genCodeTestMeta, newMeta) { + t.Errorf("objects are not equal, got: %v", newMeta) } } diff --git a/database/record/meta.go b/database/record/meta.go index e9f4fcf..54a0e61 100644 --- a/database/record/meta.go +++ b/database/record/meta.go @@ -2,7 +2,7 @@ package record import "time" -// Meta holds +// Meta holds metadata about the record. type Meta struct { Created int64 Modified int64 diff --git a/database/record/wrapper.go b/database/record/wrapper.go index 3ef77fc..903d8f1 100644 --- a/database/record/wrapper.go +++ b/database/record/wrapper.go @@ -32,21 +32,21 @@ func NewRawWrapper(database, key string, data []byte) (*Wrapper, error) { metaSection, n, err := varint.GetNextBlock(data[offset:]) if err != nil { - return nil, fmt.Errorf("could not get meta section: %s", err) + return nil, fmt.Errorf("could not get meta section: %w", err) } offset += n newMeta := &Meta{} _, err = dsd.Load(metaSection, newMeta) if err != nil { - return nil, fmt.Errorf("could not unmarshal meta section: %s", err) + return nil, fmt.Errorf("could not unmarshal meta section: %w", err) } var format uint8 = dsd.RAW if !newMeta.IsDeleted() { format, n, err = varint.Unpack8(data[offset:]) if err != nil { - return nil, fmt.Errorf("could not get dsd format: %s", err) + return nil, fmt.Errorf("could not get dsd format: %w", err) } offset += n } @@ -79,7 +79,7 @@ func NewWrapper(key string, meta *Meta, format uint8, data []byte) (*Wrapper, er }, nil } -// Marshal marshals the object, without the database key or metadata +// Marshal marshals the object, without the database key or metadata. func (w *Wrapper) Marshal(r Record, format uint8) ([]byte, error) { if w.Meta() == nil { return nil, errors.New("missing meta") @@ -134,19 +134,19 @@ func (w *Wrapper) IsWrapped() bool { } // Unwrap unwraps data into a record. -func Unwrap(wrapped, new Record) error { +func Unwrap(wrapped, r Record) error { wrapper, ok := wrapped.(*Wrapper) if !ok { return fmt.Errorf("cannot unwrap %T", wrapped) } - err := dsd.LoadAsFormat(wrapper.Data, wrapper.Format, new) + err := dsd.LoadAsFormat(wrapper.Data, wrapper.Format, r) if err != nil { - return fmt.Errorf("failed to unwrap %T: %s", new, err) + return fmt.Errorf("failed to unwrap %T: %w", r, err) } - new.SetKey(wrapped.Key()) - new.SetMeta(wrapped.Meta()) + r.SetKey(wrapped.Key()) + r.SetMeta(wrapped.Meta()) return nil } diff --git a/database/record/wrapper_test.go b/database/record/wrapper_test.go index 5f58a6b..bf148a1 100644 --- a/database/record/wrapper_test.go +++ b/database/record/wrapper_test.go @@ -8,6 +8,7 @@ import ( ) func TestWrapper(t *testing.T) { + t.Parallel() // check model interface compliance var m Record diff --git a/database/registry.go b/database/registry.go index 2e27b6c..7c68b59 100644 --- a/database/registry.go +++ b/database/registry.go @@ -32,7 +32,7 @@ var ( // If the database is already registered, only // the description and the primary API will be // updated and the effective object will be returned. -func Register(new *Database) (*Database, error) { +func Register(db *Database) (*Database, error) { if !initialized.IsSet() { return nil, errors.New("database not initialized") } @@ -40,31 +40,31 @@ func Register(new *Database) (*Database, error) { registryLock.Lock() defer registryLock.Unlock() - registeredDB, ok := registry[new.Name] + registeredDB, ok := registry[db.Name] save := false if ok { // update database - if registeredDB.Description != new.Description { - registeredDB.Description = new.Description + if registeredDB.Description != db.Description { + registeredDB.Description = db.Description save = true } - if registeredDB.ShadowDelete != new.ShadowDelete { - registeredDB.ShadowDelete = new.ShadowDelete + if registeredDB.ShadowDelete != db.ShadowDelete { + registeredDB.ShadowDelete = db.ShadowDelete save = true } } else { // register new database - if !nameConstraint.MatchString(new.Name) { + if !nameConstraint.MatchString(db.Name) { return nil, errors.New("database name must only contain alphanumeric and `_-` characters and must be at least 3 characters long") } now := time.Now().Round(time.Second) - new.Registered = now - new.LastUpdated = now - new.LastLoaded = time.Time{} + db.Registered = now + db.LastUpdated = now + db.LastLoaded = time.Time{} - registry[new.Name] = new + registry[db.Name] = db save = true } @@ -124,14 +124,14 @@ func loadRegistry() error { } // parse - new := make(map[string]*Database) - err = json.Unmarshal(data, &new) + databases := make(map[string]*Database) + err = json.Unmarshal(data, &databases) if err != nil { return err } // set - registry = new + registry = databases return nil } @@ -150,7 +150,7 @@ func saveRegistry(lock bool) error { // write file // TODO: write atomically (best effort) filePath := path.Join(rootStructure.Path, registryFileName) - return ioutil.WriteFile(filePath, data, 0600) + return ioutil.WriteFile(filePath, data, 0o0600) } func registryWriter() { diff --git a/database/storage/badger/badger.go b/database/storage/badger/badger.go index 2501f9b..8b2a5b9 100644 --- a/database/storage/badger/badger.go +++ b/database/storage/badger/badger.go @@ -30,7 +30,7 @@ func NewBadger(name, location string) (storage.Interface, error) { opts := badger.DefaultOptions(location) db, err := badger.Open(opts) - if err == badger.ErrTruncateNeeded { + if errors.Is(err, badger.ErrTruncateNeeded) { // clean up after crash log.Warningf("database/storage: truncating corrupted value log of badger database %s: this may cause data loss", name) opts.Truncate = true @@ -54,7 +54,7 @@ func (b *Badger) Get(key string) (record.Record, error) { var err error item, err = txn.Get([]byte(key)) if err != nil { - if err == badger.ErrKeyNotFound { + if errors.Is(err, badger.ErrKeyNotFound) { return storage.ErrNotFound } return err @@ -114,7 +114,7 @@ func (b *Badger) Put(r record.Record) (record.Record, error) { func (b *Badger) Delete(key string) error { return b.db.Update(func(txn *badger.Txn) error { err := txn.Delete([]byte(key)) - if err != nil && err != badger.ErrKeyNotFound { + if err != nil && !errors.Is(err, badger.ErrKeyNotFound) { return err } return nil @@ -125,7 +125,7 @@ func (b *Badger) Delete(key string) error { func (b *Badger) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) { _, err := q.Check() if err != nil { - return nil, fmt.Errorf("invalid query: %s", err) + return nil, fmt.Errorf("invalid query: %w", err) } queryIter := iterator.New() @@ -169,17 +169,17 @@ func (b *Badger) queryExecutor(queryIter *iterator.Iterator, q *query.Query, loc if err != nil { return err } - new, err := record.NewRawWrapper(b.name, r.DatabaseKey(), copiedData) + newWrapper, err := record.NewRawWrapper(b.name, r.DatabaseKey(), copiedData) if err != nil { return err } select { case <-queryIter.Done: return nil - case queryIter.Next <- new: + case queryIter.Next <- newWrapper: default: select { - case queryIter.Next <- new: + case queryIter.Next <- newWrapper: case <-queryIter.Done: return nil case <-time.After(1 * time.Minute): diff --git a/database/storage/badger/badger_test.go b/database/storage/badger/badger_test.go index 934f664..898e4ac 100644 --- a/database/storage/badger/badger_test.go +++ b/database/storage/badger/badger_test.go @@ -1,4 +1,3 @@ -//nolint:unparam,maligned package badger import ( @@ -20,7 +19,7 @@ var ( _ storage.Maintainer = &Badger{} ) -type TestRecord struct { +type TestRecord struct { //nolint:maligned record.Base sync.Mutex S string @@ -40,6 +39,8 @@ type TestRecord struct { } func TestBadger(t *testing.T) { + t.Parallel() + testDir, err := ioutil.TempDir("", "testing-") if err != nil { t.Fatal(err) diff --git a/database/storage/bbolt/bbolt.go b/database/storage/bbolt/bbolt.go index 48cd0d0..663552c 100644 --- a/database/storage/bbolt/bbolt.go +++ b/database/storage/bbolt/bbolt.go @@ -16,9 +16,7 @@ import ( "github.com/safing/portbase/database/storage" ) -var ( - bucketName = []byte{0} -) +var bucketName = []byte{0} // BBolt database made pluggable for portbase. type BBolt struct { @@ -39,10 +37,10 @@ func NewBBolt(name, location string) (storage.Interface, error) { } // Open/Create database, retry if there is a timeout. - db, err := bbolt.Open(dbFile, 0600, dbOptions) + db, err := bbolt.Open(dbFile, 0o0600, dbOptions) for i := 0; i < 5 && err != nil; i++ { // Try again if there is an error. - db, err = bbolt.Open(dbFile, 0600, dbOptions) + db, err = bbolt.Open(dbFile, 0o0600, dbOptions) } if err != nil { return nil, err @@ -89,7 +87,6 @@ func (b *BBolt) Get(key string) (record.Record, error) { } return nil }) - if err != nil { return nil, err } @@ -188,7 +185,7 @@ func (b *BBolt) Delete(key string) error { func (b *BBolt) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) { _, err := q.Check() if err != nil { - return nil, fmt.Errorf("invalid query: %s", err) + return nil, fmt.Errorf("invalid query: %w", err) } queryIter := iterator.New() @@ -235,19 +232,19 @@ func (b *BBolt) queryExecutor(queryIter *iterator.Iterator, q *query.Query, loca duplicate := make([]byte, len(value)) copy(duplicate, value) - new, err := record.NewRawWrapper(b.name, iterWrapper.DatabaseKey(), duplicate) + newWrapper, err := record.NewRawWrapper(b.name, iterWrapper.DatabaseKey(), duplicate) if err != nil { return err } select { case <-queryIter.Done: return nil - case queryIter.Next <- new: + case queryIter.Next <- newWrapper: default: select { case <-queryIter.Done: return nil - case queryIter.Next <- new: + case queryIter.Next <- newWrapper: case <-time.After(1 * time.Second): return errors.New("query timeout") } diff --git a/database/storage/bbolt/bbolt_test.go b/database/storage/bbolt/bbolt_test.go index 03fa3f0..f11b965 100644 --- a/database/storage/bbolt/bbolt_test.go +++ b/database/storage/bbolt/bbolt_test.go @@ -1,4 +1,3 @@ -//nolint:unparam,maligned package bbolt import ( @@ -22,7 +21,7 @@ var ( _ storage.Purger = &BBolt{} ) -type TestRecord struct { +type TestRecord struct { //nolint:maligned record.Base sync.Mutex S string @@ -42,6 +41,8 @@ type TestRecord struct { } func TestBBolt(t *testing.T) { + t.Parallel() + testDir, err := ioutil.TempDir("", "testing-") if err != nil { t.Fatal(err) diff --git a/database/storage/errors.go b/database/storage/errors.go index bd3ab41..ecc2853 100644 --- a/database/storage/errors.go +++ b/database/storage/errors.go @@ -2,7 +2,7 @@ package storage import "errors" -// Errors for storages +// Errors for storages. var ( ErrNotFound = errors.New("storage entry not found") ) diff --git a/database/storage/fstree/fstree.go b/database/storage/fstree/fstree.go index 9cc755a..cf6c56c 100644 --- a/database/storage/fstree/fstree.go +++ b/database/storage/fstree/fstree.go @@ -23,8 +23,8 @@ import ( ) const ( - defaultFileMode = os.FileMode(int(0644)) - defaultDirMode = os.FileMode(int(0755)) + defaultFileMode = os.FileMode(0o0644) + defaultDirMode = os.FileMode(0o0755) onWindows = runtime.GOOS == "windows" ) @@ -42,7 +42,7 @@ func init() { func NewFSTree(name, location string) (storage.Interface, error) { basePath, err := filepath.Abs(location) if err != nil { - return nil, fmt.Errorf("fstree: failed to validate path %s: %s", location, err) + return nil, fmt.Errorf("fstree: failed to validate path %s: %w", location, err) } file, err := os.Stat(basePath) @@ -50,10 +50,10 @@ func NewFSTree(name, location string) (storage.Interface, error) { if os.IsNotExist(err) { err = os.MkdirAll(basePath, defaultDirMode) if err != nil { - return nil, fmt.Errorf("fstree: failed to create directory %s: %s", basePath, err) + return nil, fmt.Errorf("fstree: failed to create directory %s: %w", basePath, err) } } else { - return nil, fmt.Errorf("fstree: failed to stat path %s: %s", basePath, err) + return nil, fmt.Errorf("fstree: failed to stat path %s: %w", basePath, err) } } else { if !file.IsDir() { @@ -93,7 +93,7 @@ func (fst *FSTree) Get(key string) (record.Record, error) { if os.IsNotExist(err) { return nil, storage.ErrNotFound } - return nil, fmt.Errorf("fstree: failed to read file %s: %s", dstPath, err) + return nil, fmt.Errorf("fstree: failed to read file %s: %w", dstPath, err) } r, err := record.NewRawWrapper(fst.name, key, data) @@ -132,11 +132,11 @@ func (fst *FSTree) Put(r record.Record) (record.Record, error) { // create dir and try again err = os.MkdirAll(filepath.Dir(dstPath), defaultDirMode) if err != nil { - return nil, fmt.Errorf("fstree: failed to create directory %s: %s", filepath.Dir(dstPath), err) + return nil, fmt.Errorf("fstree: failed to create directory %s: %w", filepath.Dir(dstPath), err) } err = writeFile(dstPath, data, defaultFileMode) if err != nil { - return nil, fmt.Errorf("fstree: could not write file %s: %s", dstPath, err) + return nil, fmt.Errorf("fstree: could not write file %s: %w", dstPath, err) } } @@ -153,7 +153,7 @@ func (fst *FSTree) Delete(key string) error { // remove entry err = os.Remove(dstPath) if err != nil { - return fmt.Errorf("fstree: could not delete %s: %s", dstPath, err) + return fmt.Errorf("fstree: could not delete %s: %w", dstPath, err) } return nil @@ -163,7 +163,7 @@ func (fst *FSTree) Delete(key string) error { func (fst *FSTree) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) { _, err := q.Check() if err != nil { - return nil, fmt.Errorf("invalid query: %s", err) + return nil, fmt.Errorf("invalid query: %w", err) } walkPrefix, err := fst.buildFilePath(q.DatabaseKeyPrefix(), false) @@ -180,7 +180,7 @@ func (fst *FSTree) Query(q *query.Query, local, internal bool) (*iterator.Iterat case os.IsNotExist(err): walkRoot = filepath.Dir(walkPrefix) default: // err != nil - return nil, fmt.Errorf("fstree: could not stat query root %s: %s", walkPrefix, err) + return nil, fmt.Errorf("fstree: could not stat query root %s: %w", walkPrefix, err) } queryIter := iterator.New() @@ -191,10 +191,8 @@ func (fst *FSTree) Query(q *query.Query, local, internal bool) (*iterator.Iterat func (fst *FSTree) queryExecutor(walkRoot string, queryIter *iterator.Iterator, q *query.Query, local, internal bool) { err := filepath.Walk(walkRoot, func(path string, info os.FileInfo, err error) error { - - // check for error if err != nil { - return fmt.Errorf("fstree: error in walking fs: %s", err) + return fmt.Errorf("fstree: error in walking fs: %w", err) } if info.IsDir() { @@ -217,17 +215,17 @@ func (fst *FSTree) queryExecutor(walkRoot string, queryIter *iterator.Iterator, if os.IsNotExist(err) { return nil } - return fmt.Errorf("fstree: failed to read file %s: %s", path, err) + return fmt.Errorf("fstree: failed to read file %s: %w", path, err) } // parse key, err := filepath.Rel(fst.basePath, path) if err != nil { - return fmt.Errorf("fstree: failed to extract key from filepath %s: %s", path, err) + return fmt.Errorf("fstree: failed to extract key from filepath %s: %w", path, err) } r, err := record.NewRawWrapper(fst.name, key, data) if err != nil { - return fmt.Errorf("fstree: failed to load file %s: %s", path, err) + return fmt.Errorf("fstree: failed to load file %s: %w", path, err) } if !r.Meta().CheckValidity() { diff --git a/database/storage/fstree/fstree_test.go b/database/storage/fstree/fstree_test.go index 88af845..437859f 100644 --- a/database/storage/fstree/fstree_test.go +++ b/database/storage/fstree/fstree_test.go @@ -2,7 +2,5 @@ package fstree import "github.com/safing/portbase/database/storage" -var ( - // Compile time interface checks. - _ storage.Interface = &FSTree{} -) +// Compile time interface checks. +var _ storage.Interface = &FSTree{} diff --git a/database/storage/hashmap/map.go b/database/storage/hashmap/map.go index eb25f24..2d74d49 100644 --- a/database/storage/hashmap/map.go +++ b/database/storage/hashmap/map.go @@ -113,7 +113,7 @@ func (hm *HashMap) Delete(key string) error { func (hm *HashMap) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) { _, err := q.Check() if err != nil { - return nil, fmt.Errorf("invalid query: %s", err) + return nil, fmt.Errorf("invalid query: %w", err) } queryIter := iterator.New() diff --git a/database/storage/hashmap/map_test.go b/database/storage/hashmap/map_test.go index 31df9e1..32a9da9 100644 --- a/database/storage/hashmap/map_test.go +++ b/database/storage/hashmap/map_test.go @@ -1,4 +1,3 @@ -//nolint:unparam,maligned package hashmap import ( @@ -6,10 +5,9 @@ import ( "sync" "testing" - "github.com/safing/portbase/database/storage" - "github.com/safing/portbase/database/query" "github.com/safing/portbase/database/record" + "github.com/safing/portbase/database/storage" ) var ( @@ -18,7 +16,7 @@ var ( _ storage.Batcher = &HashMap{} ) -type TestRecord struct { +type TestRecord struct { //nolint:maligned record.Base sync.Mutex S string @@ -38,6 +36,8 @@ type TestRecord struct { } func TestHashMap(t *testing.T) { + t.Parallel() + // start db, err := NewHashMap("test", "") if err != nil { diff --git a/database/storage/injectbase.go b/database/storage/injectbase.go index abe78e2..52fae8e 100644 --- a/database/storage/injectbase.go +++ b/database/storage/injectbase.go @@ -10,15 +10,13 @@ import ( "github.com/safing/portbase/database/record" ) -var ( - // ErrNotImplemented is returned when a function is not implemented by a storage. - ErrNotImplemented = errors.New("not implemented") -) +// ErrNotImplemented is returned when a function is not implemented by a storage. +var ErrNotImplemented = errors.New("not implemented") // InjectBase is a dummy base structure to reduce boilerplate code for injected storage interfaces. type InjectBase struct{} -// Compile time interface check +// Compile time interface check. var _ Interface = &InjectBase{} // Get returns a database record. diff --git a/database/storage/interface.go b/database/storage/interface.go index 7546485..463f2bc 100644 --- a/database/storage/interface.go +++ b/database/storage/interface.go @@ -26,7 +26,7 @@ type Interface interface { MaintainRecordStates(ctx context.Context, purgeDeletedBefore time.Time, shadowDelete bool) error } -// Maintainer defines the database storage API for backends that support optimized fetching of only the metadata. +// MetaHandler defines the database storage API for backends that support optimized fetching of only the metadata. type MetaHandler interface { GetMeta(key string) (*record.Meta, error) } diff --git a/database/storage/sinkhole/sinkhole.go b/database/storage/sinkhole/sinkhole.go index af6b082..e61c031 100644 --- a/database/storage/sinkhole/sinkhole.go +++ b/database/storage/sinkhole/sinkhole.go @@ -17,7 +17,7 @@ type Sinkhole struct { } var ( - // Compile time interface check + // Compile time interface checks. _ storage.Interface = &Sinkhole{} _ storage.Maintainer = &Sinkhole{} _ storage.Batcher = &Sinkhole{} diff --git a/dataroot/root.go b/dataroot/root.go index 84c5275..9b8acdd 100644 --- a/dataroot/root.go +++ b/dataroot/root.go @@ -7,11 +7,9 @@ import ( "github.com/safing/portbase/utils" ) -var ( - root *utils.DirStructure -) +var root *utils.DirStructure -// Initialize initializes the data root directory +// Initialize initializes the data root directory. func Initialize(rootDir string, perm os.FileMode) error { if root != nil { return errors.New("already initialized") diff --git a/formats/dsd/format.go b/formats/dsd/format.go index 676071e..7403832 100644 --- a/formats/dsd/format.go +++ b/formats/dsd/format.go @@ -2,6 +2,7 @@ package dsd import "errors" +// Errors. var ( ErrIncompatibleFormat = errors.New("dsd: format is incompatible with operation") ErrIsRaw = errors.New("dsd: given data is in raw format") @@ -26,6 +27,7 @@ const ( LIST = 76 // L ) +// Default Formats. var ( DefaultSerializationFormat uint8 = JSON DefaultCompressionFormat uint8 = GZIP diff --git a/formats/dsd/http.go b/formats/dsd/http.go index dd6e336..8653785 100644 --- a/formats/dsd/http.go +++ b/formats/dsd/http.go @@ -10,6 +10,7 @@ import ( "net/http" ) +// HTTP Related Errors. var ( ErrMissingBody = errors.New("dsd: missing http body") ErrMissingContentType = errors.New("dsd: missing http content type") @@ -120,6 +121,7 @@ func DumpToHTTPResponse(w http.ResponseWriter, r *http.Request, t interface{}) e return nil } +// Format and MimeType mappings. var ( FormatToMimeType = map[uint8]string{ JSON: "application/json; charset=utf-8", diff --git a/formats/varint/varint_test.go b/formats/varint/varint_test.go index 5e049ad..9f2250e 100644 --- a/formats/varint/varint_test.go +++ b/formats/varint/varint_test.go @@ -7,10 +7,9 @@ import ( ) func TestConversion(t *testing.T) { + t.Parallel() - // t.Run("Basic Static Encoding and Decoding", func(t *testing.T) { ... } - - var subjects = []struct { + subjects := []struct { intType uint8 bytes []byte integer uint64 @@ -100,14 +99,12 @@ func TestConversion(t *testing.T) { } } - } func TestFails(t *testing.T) { + t.Parallel() - // t.Run("Basic Static Encoding and Decoding", func(t *testing.T) { ... } - - var subjects = []struct { + subjects := []struct { intType uint8 bytes []byte }{ @@ -141,5 +138,4 @@ func TestFails(t *testing.T) { } } - } diff --git a/info/module/flags.go b/info/module/flags.go index a3caaa1..8bbc50d 100644 --- a/info/module/flags.go +++ b/info/module/flags.go @@ -8,9 +8,7 @@ import ( "github.com/safing/portbase/modules" ) -var ( - showVersion bool -) +var showVersion bool func init() { modules.Register("info", prep, nil, nil) diff --git a/info/version.go b/info/version.go index a1790ee..caae346 100644 --- a/info/version.go +++ b/info/version.go @@ -76,7 +76,7 @@ func FullVersion() string { } s += fmt.Sprintf("\ncommit %s\n", commit) s += fmt.Sprintf("built with %s (%s) %s/%s\n", runtime.Version(), runtime.Compiler, runtime.GOOS, runtime.GOARCH) - s += fmt.Sprintf(" using options %s\n", strings.Replace(buildOptions, "§", " ", -1)) + s += fmt.Sprintf(" using options %s\n", strings.ReplaceAll(buildOptions, "§", " ")) s += fmt.Sprintf(" by %s@%s\n", buildUser, buildHost) s += fmt.Sprintf(" on %s\n", buildDate) s += fmt.Sprintf("\nLicensed under the %s license.\nThe source code is available here: %s", license, buildSource) diff --git a/log/formatting_unix.go b/log/formatting_unix.go index 1e56839..553fc0e 100644 --- a/log/formatting_unix.go +++ b/log/formatting_unix.go @@ -1,4 +1,4 @@ -// +build !windows +// go:build !windows package log @@ -8,14 +8,16 @@ const ( ) const ( - // colorBlack = "\033[30m" - colorRed = "\033[31m" - // colorGreen = "\033[32m" + colorRed = "\033[31m" colorYellow = "\033[33m" colorBlue = "\033[34m" colorMagenta = "\033[35m" colorCyan = "\033[36m" - // colorWhite = "\033[37m" + + // Saved for later: + // colorBlack = "\033[30m" //. + // colorGreen = "\033[32m" //. + // colorWhite = "\033[37m" //. ) func (s Severity) color() string { @@ -30,6 +32,8 @@ func (s Severity) color() string { return colorRed case CriticalLevel: return colorMagenta + case TraceLevel: + return "" default: return "" } diff --git a/log/input.go b/log/input.go index 639278c..dd0b293 100644 --- a/log/input.go +++ b/log/input.go @@ -15,7 +15,6 @@ var ( ) func log(level Severity, msg string, tracer *ContextTracer) { - if !started.IsSet() { // a bit resource intense, but keeps logs before logging started. // TODO: create option to disable logging diff --git a/log/logging.go b/log/logging.go index 27439dd..4000df4 100644 --- a/log/logging.go +++ b/log/logging.go @@ -88,7 +88,7 @@ func (ll *logLine) Equal(ol *logLine) bool { return true } -// Log Levels +// Log Levels. const ( TraceLevel Severity = 1 DebugLevel Severity = 2 @@ -185,7 +185,6 @@ func ParseLevel(level string) Severity { // Start starts the logging system. Must be called in order to see logs. func Start() (err error) { - if !initializing.SetToIf(false, true) { return nil } diff --git a/log/logging_test.go b/log/logging_test.go index 557ab02..577ee51 100644 --- a/log/logging_test.go +++ b/log/logging_test.go @@ -13,8 +13,8 @@ func init() { } } -// test waiting func TestLogging(t *testing.T) { + t.Parallel() // skip if testing.Short() { @@ -61,5 +61,4 @@ func TestLogging(t *testing.T) { // do not really shut down, we may need logging for other tests // ShutdownLogging() - } diff --git a/log/output.go b/log/output.go index 39d91f8..1c8f1ac 100644 --- a/log/output.go +++ b/log/output.go @@ -143,13 +143,11 @@ StackTrace: }() var currentLine *logLine - var nextLine *logLine var duplicates uint64 for { // reset currentLine = nil - nextLine = nil duplicates = 0 // wait until logs need to be processed @@ -175,7 +173,7 @@ StackTrace: writeLoop: for { select { - case nextLine = <-logBuffer: + case nextLine := <-logBuffer: // first line we process, just assign to currentLine if currentLine == nil { currentLine = nextLine @@ -209,10 +207,6 @@ StackTrace: // add to unexpected logs addUnexpectedLogs(currentLine) } - // reset state - currentLine = nil //nolint:ineffassign - nextLine = nil - duplicates = 0 //nolint:ineffassign // back down a little select { @@ -281,13 +275,13 @@ func GetLastUnexpectedLogs() []string { defer lastUnexpectedLogsLock.Unlock() // Make a copy and return. - len := len(lastUnexpectedLogs) + logsLen := len(lastUnexpectedLogs) start := lastUnexpectedLogsIndex - logsCopy := make([]string, 0, len) + logsCopy := make([]string, 0, logsLen) // Loop from mid-to-mid. - for i := start; i < start+len; i++ { - if lastUnexpectedLogs[i%len] != "" { - logsCopy = append(logsCopy, lastUnexpectedLogs[i%len]) + for i := start; i < start+logsLen; i++ { + if lastUnexpectedLogs[i%logsLen] != "" { + logsCopy = append(logsCopy, lastUnexpectedLogs[i%logsLen]) } } diff --git a/log/trace.go b/log/trace.go index f90b306..640594d 100644 --- a/log/trace.go +++ b/log/trace.go @@ -19,9 +19,7 @@ type ContextTracer struct { logs []*logLine } -var ( - key = ContextTracerKey{} -) +var key = ContextTracerKey{} // AddTracer adds a ContextTracer to the returned Context. Will return a nil ContextTracer if logging level is not set to trace. Will return a nil ContextTracer if one already exists. Will return a nil ContextTracer in case of an error. Will return a nil context if nil. func AddTracer(ctx context.Context) (context.Context, *ContextTracer) { diff --git a/log/trace_test.go b/log/trace_test.go index 1e7df02..999e0f3 100644 --- a/log/trace_test.go +++ b/log/trace_test.go @@ -7,6 +7,8 @@ import ( ) func TestContextTracer(t *testing.T) { + t.Parallel() + // skip if testing.Short() { t.Skip() diff --git a/metrics/metrics_host.go b/metrics/metrics_host.go index 5a08554..159c270 100644 --- a/metrics/metrics_host.go +++ b/metrics/metrics_host.go @@ -111,6 +111,7 @@ func getLoadAvg() *load.AvgStat { return loadAvg } +// LoadAvg1 returns the 1-minute average system load. func LoadAvg1() (loadAvg float64, ok bool) { if stat := getLoadAvg(); stat != nil { return stat.Load1 / float64(runtime.NumCPU()), true @@ -118,6 +119,7 @@ func LoadAvg1() (loadAvg float64, ok bool) { return 0, false } +// LoadAvg5 returns the 5-minute average system load. func LoadAvg5() (loadAvg float64, ok bool) { if stat := getLoadAvg(); stat != nil { return stat.Load5 / float64(runtime.NumCPU()), true @@ -125,6 +127,7 @@ func LoadAvg5() (loadAvg float64, ok bool) { return 0, false } +// LoadAvg15 returns the 5-minute average system load. func LoadAvg15() (loadAvg float64, ok bool) { if stat := getLoadAvg(); stat != nil { return stat.Load15 / float64(runtime.NumCPU()), true @@ -159,6 +162,7 @@ func getMemStat() *mem.VirtualMemoryStat { return memStat } +// MemTotal returns the total system memory. func MemTotal() (total uint64, ok bool) { if stat := getMemStat(); stat != nil { return stat.Total, true @@ -166,6 +170,7 @@ func MemTotal() (total uint64, ok bool) { return 0, false } +// MemUsed returns the used system memory. func MemUsed() (used uint64, ok bool) { if stat := getMemStat(); stat != nil { return stat.Used, true @@ -173,6 +178,7 @@ func MemUsed() (used uint64, ok bool) { return 0, false } +// MemAvailable returns the available system memory. func MemAvailable() (available uint64, ok bool) { if stat := getMemStat(); stat != nil { return stat.Available, true @@ -180,6 +186,7 @@ func MemAvailable() (available uint64, ok bool) { return 0, false } +// MemUsedPercent returns the percent of used system memory. func MemUsedPercent() (usedPercent float64, ok bool) { if stat := getMemStat(); stat != nil { return stat.UsedPercent, true @@ -223,6 +230,7 @@ func getDiskStat() *disk.UsageStat { return diskStat } +// DiskTotal returns the total disk space (from the program's data root). func DiskTotal() (total uint64, ok bool) { if stat := getDiskStat(); stat != nil { return stat.Total, true @@ -230,6 +238,7 @@ func DiskTotal() (total uint64, ok bool) { return 0, false } +// DiskUsed returns the used disk space (from the program's data root). func DiskUsed() (used uint64, ok bool) { if stat := getDiskStat(); stat != nil { return stat.Used, true @@ -237,6 +246,7 @@ func DiskUsed() (used uint64, ok bool) { return 0, false } +// DiskFree returns the available disk space (from the program's data root). func DiskFree() (free uint64, ok bool) { if stat := getDiskStat(); stat != nil { return stat.Free, true @@ -244,6 +254,7 @@ func DiskFree() (free uint64, ok bool) { return 0, false } +// DiskUsedPercent returns the percent of used disk space (from the program's data root). func DiskUsedPercent() (usedPercent float64, ok bool) { if stat := getDiskStat(); stat != nil { return stat.UsedPercent, true diff --git a/modules/cmd.go b/modules/cmd.go index a829b51..376457c 100644 --- a/modules/cmd.go +++ b/modules/cmd.go @@ -1,8 +1,6 @@ package modules -var ( - cmdLineOperation func() error -) +var cmdLineOperation func() error // SetCmdLineOperation sets a command line operation to be executed instead of starting the system. This is useful when functions need all modules to be prepared for a special operation. func SetCmdLineOperation(fn func() error) { diff --git a/modules/error.go b/modules/error.go index d244298..8d94d1f 100644 --- a/modules/error.go +++ b/modules/error.go @@ -11,7 +11,7 @@ import ( var ( errorReportingChannel chan *ModuleError reportToStdErr = true - lastReportedError *ModuleError + lastReportedError *ModuleError //nolint:errname reportingLock sync.Mutex ) @@ -120,7 +120,7 @@ func (me *ModuleError) Report() { // IsPanic returns whether the given error is a wrapped panic by the modules package and additionally returns it, if true. func IsPanic(err error) (bool, *ModuleError) { - switch val := err.(type) { + switch val := err.(type) { //nolint:errorlint // TODO: improve case *ModuleError: return true, val default: diff --git a/modules/events.go b/modules/events.go index fd1a9bf..3d4e066 100644 --- a/modules/events.go +++ b/modules/events.go @@ -5,12 +5,13 @@ import ( "errors" "fmt" - "github.com/safing/portbase/log" "github.com/tevino/abool" + + "github.com/safing/portbase/log" ) type eventHooks struct { - // hooks holds all registed hooks for the event. + // hooks holds all registered hooks for the event. hooks []*eventHook // internal signifies that the event and it's data may not be exposed and may @@ -195,7 +196,8 @@ var ( eventSubscriptionFuncReady = abool.NewBool(false) ) -// SetEventSubscriptionFunc +// SetEventSubscriptionFunc sets a function that is called for every event. +// This enabled the runtime package to expose events. func SetEventSubscriptionFunc(fn func(moduleName, eventName string, internal bool, data interface{})) bool { if eventSubscriptionFuncEnabled.SetToIf(false, true) { eventSubscriptionFunc = fn diff --git a/modules/exit.go b/modules/exit.go index 67d38bc..6bb8607 100644 --- a/modules/exit.go +++ b/modules/exit.go @@ -1,15 +1,13 @@ package modules -var ( - exitStatusCode int -) +var exitStatusCode int // SetExitStatusCode sets the exit code that the program shell return to the host after shutdown. func SetExitStatusCode(n int) { exitStatusCode = n } -// GetExitStatusCode waits for the shutdown to complete and then returns the exit code +// GetExitStatusCode waits for the shutdown to complete and then returns the previously set exit code. func GetExitStatusCode() int { <-shutdownCompleteSignal return exitStatusCode diff --git a/modules/mgmt.go b/modules/mgmt.go index 42a255f..78bdeb9 100644 --- a/modules/mgmt.go +++ b/modules/mgmt.go @@ -3,8 +3,9 @@ package modules import ( "context" - "github.com/safing/portbase/log" "github.com/tevino/abool" + + "github.com/safing/portbase/log" ) var ( diff --git a/modules/mgmt_test.go b/modules/mgmt_test.go index 3e6009b..f8d6be3 100644 --- a/modules/mgmt_test.go +++ b/modules/mgmt_test.go @@ -5,7 +5,6 @@ import ( ) func testModuleMgmt(t *testing.T) { - // enable module management EnableModuleManagement(nil) diff --git a/modules/microtasks.go b/modules/microtasks.go index 6ccf9ef..92f23d6 100644 --- a/modules/microtasks.go +++ b/modules/microtasks.go @@ -5,8 +5,9 @@ import ( "sync/atomic" "time" - "github.com/safing/portbase/log" "github.com/tevino/abool" + + "github.com/safing/portbase/log" ) // TODO: getting some errors when in nanosecond precision for tests: @@ -159,9 +160,7 @@ func (m *Module) runMicroTask(name *string, fn func(context.Context) error) (err return //nolint:nakedret // need to use named return val in order to change in defer } -var ( - microTaskSchedulerStarted = abool.NewBool(false) -) +var microTaskSchedulerStarted = abool.NewBool(false) func microTaskScheduler() { // only ever start once diff --git a/modules/microtasks_test.go b/modules/microtasks_test.go index 7cde095..0138bc1 100644 --- a/modules/microtasks_test.go +++ b/modules/microtasks_test.go @@ -18,8 +18,7 @@ func init() { go microTaskScheduler() } -// test waiting -func TestMicroTaskWaiting(t *testing.T) { +func TestMicroTaskWaiting(t *testing.T) { //nolint:paralleltest // Too much interference expected. // skip if testing.Short() { @@ -108,17 +107,20 @@ func TestMicroTaskWaiting(t *testing.T) { if completeOutput != mtwExpectedOutput { t.Errorf("MicroTask waiting test failed, expected sequence %s, got %s", mtwExpectedOutput, completeOutput) } - } -// test ordering +// Test Microtask ordering. -// globals -var mtoWaitGroup sync.WaitGroup -var mtoOutputChannel chan string -var mtoWaitCh chan struct{} +// Microtask test globals. + +var ( + mtoWaitGroup sync.WaitGroup + mtoOutputChannel chan string + mtoWaitCh chan struct{} +) + +// Microtask test functions. -// functions func mediumPrioTaskTester() { defer mtoWaitGroup.Done() <-mtoWaitCh @@ -139,8 +141,7 @@ func lowPrioTaskTester() { }) } -// test -func TestMicroTaskOrdering(t *testing.T) { +func TestMicroTaskOrdering(t *testing.T) { //nolint:paralleltest // Too much interference expected. // skip if testing.Short() { @@ -204,5 +205,4 @@ func TestMicroTaskOrdering(t *testing.T) { if !strings.Contains(completeOutput, "11111") || !strings.Contains(completeOutput, "22222") { t.Errorf("MicroTask ordering test failed, output was %s. This happens occasionally, please run the test multiple times to verify", completeOutput) } - } diff --git a/modules/modules.go b/modules/modules.go index e5fc278..8c2b20a 100644 --- a/modules/modules.go +++ b/modules/modules.go @@ -8,15 +8,16 @@ import ( "sync/atomic" "time" - "github.com/safing/portbase/log" "github.com/tevino/abool" + + "github.com/safing/portbase/log" ) var ( modules = make(map[string]*Module) mgmtLock sync.Mutex - // lock modules when starting + // modulesLocked locks `modules` during starting. modulesLocked = abool.New() moduleStartTimeout = 2 * time.Minute @@ -27,7 +28,7 @@ var ( ) // Module represents a module. -type Module struct { //nolint:maligned // not worth the effort +type Module struct { sync.RWMutex Name string diff --git a/modules/modules_test.go b/modules/modules_test.go index 9d40fca..d3a8d74 100644 --- a/modules/modules_test.go +++ b/modules/modules_test.go @@ -13,6 +13,8 @@ var ( ) func registerTestModule(t *testing.T, name string, dependencies ...string) { + t.Helper() + Register( name, func() error { @@ -45,16 +47,15 @@ func testCleanExit() error { return ErrCleanExit } -func TestModules(t *testing.T) { +func TestModules(t *testing.T) { //nolint:tparallel // Too much interference expected. t.Parallel() // Not really, just a workaround for running these tests last. - t.Run("TestModuleOrder", testModuleOrder) - t.Run("TestModuleMgmt", testModuleMgmt) - t.Run("TestModuleErrors", testModuleErrors) + t.Run("TestModuleOrder", testModuleOrder) //nolint:paralleltest // Too much interference expected. + t.Run("TestModuleMgmt", testModuleMgmt) //nolint:paralleltest // Too much interference expected. + t.Run("TestModuleErrors", testModuleErrors) //nolint:paralleltest // Too much interference expected. } func testModuleOrder(t *testing.T) { - registerTestModule(t, "database") registerTestModule(t, "stats", "database") registerTestModule(t, "service", "database") @@ -88,7 +89,6 @@ func testModuleOrder(t *testing.T) { } func testModuleErrors(t *testing.T) { - // test prep error Register("prepfail", testFail, nil, nil) err := Start() @@ -101,7 +101,7 @@ func testModuleErrors(t *testing.T) { // test prep clean exit Register("prepcleanexit", testCleanExit, nil, nil) err = Start() - if err != ErrCleanExit { + if !errors.Is(err, ErrCleanExit) { t.Error("should fail with clean exit") } diff --git a/modules/start.go b/modules/start.go index e9968cf..f92a90c 100644 --- a/modules/start.go +++ b/modules/start.go @@ -49,7 +49,7 @@ func Start() error { // parse flags err = parseFlags() if err != nil { - if err != ErrCleanExit { + if !errors.Is(err, ErrCleanExit) { fmt.Fprintf(os.Stderr, "CRITICAL ERROR: failed to parse flags: %s\n", err) } return err @@ -59,7 +59,7 @@ func Start() error { if globalPrepFn != nil { err = globalPrepFn() if err != nil { - if err != ErrCleanExit { + if !errors.Is(err, ErrCleanExit) { fmt.Fprintf(os.Stderr, "CRITICAL ERROR: %s\n", err) } return err @@ -69,7 +69,7 @@ func Start() error { // prep modules err = prepareModules() if err != nil { - if err != ErrCleanExit { + if !errors.Is(err, ErrCleanExit) { fmt.Fprintf(os.Stderr, "CRITICAL ERROR: %s\n", err) } return err @@ -148,11 +148,11 @@ func prepareModules() error { // wait for reports rep = <-reports if rep.err != nil { - if rep.err == ErrCleanExit { + if errors.Is(rep.err, ErrCleanExit) { return rep.err } rep.module.NewErrorMessage("prep module", rep.err).Report() - return fmt.Errorf("failed to prep module %s: %s", rep.module.Name, rep.err) + return fmt.Errorf("failed to prep module %s: %w", rep.module.Name, rep.err) } reportCnt++ } else { @@ -200,7 +200,7 @@ func startModules() error { rep = <-reports if rep.err != nil { rep.module.NewErrorMessage("start module", rep.err).Report() - return fmt.Errorf("modules: could not start module %s: %s", rep.module.Name, rep.err) + return fmt.Errorf("modules: could not start module %s: %w", rep.module.Name, rep.err) } reportCnt++ log.Infof("modules: started %s", rep.module.Name) diff --git a/modules/status.go b/modules/status.go index 33bad05..2810fec 100644 --- a/modules/status.go +++ b/modules/status.go @@ -6,7 +6,7 @@ import ( "github.com/tevino/abool" ) -// Module Status Values +// Module Status Values. const ( StatusDead uint8 = 0 // not prepared, not started StatusPreparing uint8 = 1 @@ -16,7 +16,7 @@ const ( StatusOnline uint8 = 5 // online and running ) -// Module Failure Status Values +// Module Failure Status Values. const ( FailureNone uint8 = 0 FailureHint uint8 = 1 @@ -24,7 +24,7 @@ const ( FailureError uint8 = 3 ) -// ready status +// Ready Stati. const ( statusWaiting uint8 = iota statusReady @@ -138,7 +138,7 @@ func (m *Module) setFailure(status uint8, id, title, msg string, lockModule bool // Propagate failure status. if failureUpdateNotifyFuncReady.IsSet() { - m.RunWorker("failure status updater", func(context.Context) error { + _ = m.RunWorker("failure status updater", func(context.Context) error { // Only use data in worker that won't change anymore. // Resolve previous failure state if available. @@ -180,7 +180,7 @@ func (m *Module) Resolve(failureID string) { // Propagate failure status. if failureUpdateNotifyFuncReady.IsSet() { - m.RunWorker("failure status updater", func(context.Context) error { + _ = m.RunWorker("failure status updater", func(context.Context) error { // Only use data in worker that won't change anymore. failureUpdateNotifyFunc(FailureNone, resolveFailureID, "", "") return nil diff --git a/modules/subsystems/module.go b/modules/subsystems/module.go index 48a3784..31d129b 100644 --- a/modules/subsystems/module.go +++ b/modules/subsystems/module.go @@ -6,7 +6,6 @@ import ( "fmt" "github.com/safing/portbase/config" - _ "github.com/safing/portbase/database/dbmodule" // database module is required "github.com/safing/portbase/modules" "github.com/safing/portbase/runtime" ) diff --git a/modules/subsystems/registry.go b/modules/subsystems/registry.go index bc16944..6225b07 100644 --- a/modules/subsystems/registry.go +++ b/modules/subsystems/registry.go @@ -9,11 +9,12 @@ import ( "sync" "time" + "github.com/tevino/abool" + "github.com/safing/portbase/config" "github.com/safing/portbase/database/record" "github.com/safing/portbase/modules" "github.com/safing/portbase/runtime" - "github.com/tevino/abool" ) var ( @@ -94,7 +95,7 @@ func (mng *Manager) Start() error { return nil } -// Get implements runtime.ValueProvider +// Get implements runtime.ValueProvider. func (mng *Manager) Get(keyOrPrefix string) ([]record.Record, error) { mng.l.RLock() defer mng.l.RUnlock() diff --git a/modules/subsystems/subsystems_test.go b/modules/subsystems/subsystems_test.go index 4351a34..23949f2 100644 --- a/modules/subsystems/subsystems_test.go +++ b/modules/subsystems/subsystems_test.go @@ -7,16 +7,17 @@ import ( "time" "github.com/safing/portbase/config" + _ "github.com/safing/portbase/database/dbmodule" "github.com/safing/portbase/dataroot" "github.com/safing/portbase/modules" ) -func TestSubsystems(t *testing.T) { +func TestSubsystems(t *testing.T) { //nolint:paralleltest // Too much interference expected. // tmp dir for data root (db & config) tmpDir, err := ioutil.TempDir("", "portbase-testing-") // initialize data dir if err == nil { - err = dataroot.Initialize(tmpDir, 0755) + err = dataroot.Initialize(tmpDir, 0o0755) } // handle setup error if err != nil { diff --git a/modules/tasks.go b/modules/tasks.go index cebb295..a37b96e 100644 --- a/modules/tasks.go +++ b/modules/tasks.go @@ -8,8 +8,9 @@ import ( "sync/atomic" "time" - "github.com/safing/portbase/log" "github.com/tevino/abool" + + "github.com/safing/portbase/log" ) // Task is managed task bound to a module. @@ -92,7 +93,7 @@ func (m *Module) newTask(name string, fn func(context.Context, *Task) error) *Ta } // create new task - new := &Task{ + newTask := &Task{ name: name, module: m, taskFn: fn, @@ -100,9 +101,9 @@ func (m *Module) newTask(name string, fn func(context.Context, *Task) error) *Ta } // create context - new.ctx, new.cancelCtx = context.WithCancel(m.Ctx) + newTask.ctx, newTask.cancelCtx = context.WithCancel(m.Ctx) - return new + return newTask } func (t *Task) isActive() bool { @@ -397,7 +398,7 @@ func (t *Task) addToSchedule(overtime bool) { // insert task into schedule for e := taskSchedule.Front(); e != nil; e = e.Next() { // check for self - eVal := e.Value.(*Task) + eVal := e.Value.(*Task) //nolint:forcetypeassert // Can only be *Task. if eVal == t { continue } @@ -480,7 +481,7 @@ func taskQueueHandler() { } // value -> Task - t := e.Value.(*Task) + t := e.Value.(*Task) //nolint:forcetypeassert // Can only be *Task. // run t.runWithLocking() } @@ -507,7 +508,7 @@ func taskScheduleHandler() { scheduleLock.Unlock() continue } - t := e.Value.(*Task) + t := e.Value.(*Task) //nolint:forcetypeassert // Can only be *Task. // process Task if t.overtime { diff --git a/modules/tasks_test.go b/modules/tasks_test.go index 65d262e..0d7aef8 100644 --- a/modules/tasks_test.go +++ b/modules/tasks_test.go @@ -29,20 +29,24 @@ func init() { }() } -// test waiting +// Test queued tasks. -// globals -var qtWg sync.WaitGroup -var qtOutputChannel chan string -var qtSleepDuration time.Duration -var qtModule *Module +// Queued task test globals. + +var ( + qtWg sync.WaitGroup + qtOutputChannel chan string + qtSleepDuration time.Duration + qtModule *Module +) func init() { qtModule = initNewModule("task test module", nil, nil, nil) qtModule.status = StatusOnline } -// functions +// Queued task test functions. + func queuedTaskTester(s string) { qtModule.NewTask(s, func(ctx context.Context, t *Task) error { time.Sleep(qtSleepDuration * 2) @@ -61,8 +65,7 @@ func prioritizedTaskTester(s string) { }).QueuePrioritized() } -// test -func TestQueuedTask(t *testing.T) { +func TestQueuedTask(t *testing.T) { //nolint:paralleltest // Too much interference expected. // skip if testing.Short() { t.Skip("skipping test in short mode, as it is not fully deterministic") @@ -103,18 +106,21 @@ func TestQueuedTask(t *testing.T) { if completeOutput != expectedOutput { t.Errorf("QueuedTask test failed, expected sequence %s, got %s", expectedOutput, completeOutput) } - } -// test scheduled tasks +// Test scheduled tasks. -// globals -var stWg sync.WaitGroup -var stOutputChannel chan string -var stSleepDuration time.Duration -var stWaitCh chan bool +// Scheduled task test globals. + +var ( + stWg sync.WaitGroup + stOutputChannel chan string + stSleepDuration time.Duration + stWaitCh chan bool +) + +// Scheduled task test functions. -// functions func scheduledTaskTester(s string, sched time.Time) { qtModule.NewTask(s, func(ctx context.Context, t *Task) error { time.Sleep(stSleepDuration) @@ -124,8 +130,7 @@ func scheduledTaskTester(s string, sched time.Time) { }).Schedule(sched) } -// test -func TestScheduledTaskWaiting(t *testing.T) { +func TestScheduledTaskWaiting(t *testing.T) { //nolint:paralleltest // Too much interference expected. // skip if testing.Short() { @@ -166,10 +171,9 @@ func TestScheduledTaskWaiting(t *testing.T) { if completeOutput != expectedOutput { t.Errorf("ScheduledTask test failed, expected sequence %s, got %s", expectedOutput, completeOutput) } - } -func TestRequeueingTask(t *testing.T) { +func TestRequeueingTask(t *testing.T) { //nolint:paralleltest // Too much interference expected. blockWg := &sync.WaitGroup{} wg := &sync.WaitGroup{} @@ -222,7 +226,7 @@ func TestRequeueingTask(t *testing.T) { wg.Wait() } -func TestQueueSuccession(t *testing.T) { +func TestQueueSuccession(t *testing.T) { //nolint:paralleltest // Too much interference expected. var cnt int wg := &sync.WaitGroup{} wg.Add(10) diff --git a/modules/worker.go b/modules/worker.go index 19fce55..d5ce369 100644 --- a/modules/worker.go +++ b/modules/worker.go @@ -10,7 +10,7 @@ import ( "github.com/safing/portbase/log" ) -// Worker Default Configuration +// Default Worker Configuration. const ( DefaultBackoffDuration = 2 * time.Second ) @@ -121,7 +121,6 @@ func (m *Module) runWorker(name string, fn func(context.Context) error) (err err } func (m *Module) runCtrlFnWithTimeout(name string, timeout time.Duration, fn func() error) error { - stopFnError := make(chan error) go func() { stopFnError <- m.runCtrlFn(name, fn) diff --git a/modules/worker_test.go b/modules/worker_test.go index 6c86dbf..552eddb 100644 --- a/modules/worker_test.go +++ b/modules/worker_test.go @@ -13,7 +13,7 @@ var ( errTest = errors.New("test error") ) -func TestWorker(t *testing.T) { +func TestWorker(t *testing.T) { //nolint:paralleltest // Too much interference expected. // test basic functionality err := wModule.RunWorker("test worker", func(ctx context.Context) error { return nil @@ -26,7 +26,7 @@ func TestWorker(t *testing.T) { err = wModule.RunWorker("test worker", func(ctx context.Context) error { return errTest }) - if err != errTest { + if !errors.Is(err, errTest) { t.Errorf("worker failed with unexpected error: %s", err) } @@ -52,7 +52,7 @@ func TestWorker(t *testing.T) { // test panic recovery err = wModule.RunWorker("test worker", func(ctx context.Context) error { var a []byte - _ = a[0] //nolint // we want to runtime panic! + _ = a[0] return nil }) t.Logf("panic error message: %s", err) diff --git a/notifications/database.go b/notifications/database.go index f9d8be7..0cff2d8 100644 --- a/notifications/database.go +++ b/notifications/database.go @@ -21,7 +21,7 @@ var ( dbController *database.Controller ) -// Storage interface errors +// Storage interface errors. var ( ErrInvalidData = errors.New("invalid data, must be a notification object") ErrInvalidPath = errors.New("invalid path") @@ -126,7 +126,6 @@ func (s *StorageInterface) Put(r record.Record) (record.Record, error) { // record is already locked! key := r.DatabaseKey() n, err := EnsureNotification(r) - if err != nil { return nil, ErrInvalidData } @@ -223,18 +222,18 @@ func EnsureNotification(r record.Record) (*Notification, error) { // unwrap if r.IsWrapped() { // only allocate a new struct, if we need it - new := &Notification{} - err := record.Unwrap(r, new) + n := &Notification{} + err := record.Unwrap(r, n) if err != nil { return nil, err } - return new, nil + return n, nil } // or adjust type - new, ok := r.(*Notification) + n, ok := r.(*Notification) if !ok { - return nil, fmt.Errorf("record not of type *Example, but %T", r) + return nil, fmt.Errorf("record not of type *Notification, but %T", r) } - return new, nil + return n, nil } diff --git a/notifications/module.go b/notifications/module.go index 1000e94..764035f 100644 --- a/notifications/module.go +++ b/notifications/module.go @@ -6,9 +6,7 @@ import ( "github.com/safing/portbase/modules" ) -var ( - module *modules.Module -) +var module *modules.Module func init() { module = modules.Register("notifications", prep, start, nil, "database", "base") diff --git a/notifications/notification.go b/notifications/notification.go index 1b283d0..77034ea 100644 --- a/notifications/notification.go +++ b/notifications/notification.go @@ -47,7 +47,7 @@ const ( ) // Notification represents a notification that is to be delivered to the user. -type Notification struct { +type Notification struct { //nolint:maligned record.Base // EventID is used to identify a specific notification. It consists of // the module name and a per-module unique event id. diff --git a/portbase.go b/portbase.go index 8d9385e..3de9f60 100644 --- a/portbase.go +++ b/portbase.go @@ -3,11 +3,9 @@ package main import ( "os" + _ "github.com/safing/portbase/api" "github.com/safing/portbase/info" "github.com/safing/portbase/run" - - // include packages here - _ "github.com/safing/portbase/api" ) func main() { diff --git a/rng/entropy.go b/rng/entropy.go index 4d5f572..7a2545d 100644 --- a/rng/entropy.go +++ b/rng/entropy.go @@ -13,9 +13,7 @@ const ( minFeedEntropy = 256 ) -var ( - rngFeeder = make(chan []byte) -) +var rngFeeder = make(chan []byte) // The Feeder is used to feed entropy to the RNG. type Feeder struct { @@ -32,13 +30,13 @@ type entropyData struct { // NewFeeder returns a new entropy Feeder. func NewFeeder() *Feeder { - new := &Feeder{ + newFeeder := &Feeder{ input: make(chan *entropyData), needsEntropy: abool.NewBool(true), buffer: container.New(), } - module.StartServiceWorker("feeder", 0, new.run) - return new + module.StartServiceWorker("feeder", 0, newFeeder.run) + return newFeeder } // NeedsEntropy returns whether the feeder is currently gathering entropy. diff --git a/rng/entropy_test.go b/rng/entropy_test.go index 08a2d62..76ebb4c 100644 --- a/rng/entropy_test.go +++ b/rng/entropy_test.go @@ -6,6 +6,8 @@ import ( ) func TestFeeder(t *testing.T) { + t.Parallel() + // wait for start / first round to complete time.Sleep(1 * time.Millisecond) @@ -68,5 +70,4 @@ func TestFeeder(t *testing.T) { case <-time.After(10 * time.Millisecond): t.Error("call blocks!") } - } diff --git a/rng/fullfeed.go b/rng/fullfeed.go index 7db631d..e055f3e 100644 --- a/rng/fullfeed.go +++ b/rng/fullfeed.go @@ -6,7 +6,6 @@ import ( ) func getFullFeedDuration() time.Duration { - // full feed every 5x time of reseedAfterSeconds secsUntilFullFeed := reseedAfterSeconds * 5 diff --git a/rng/fullfeed_test.go b/rng/fullfeed_test.go index 5e8b84c..c3da837 100644 --- a/rng/fullfeed_test.go +++ b/rng/fullfeed_test.go @@ -5,6 +5,8 @@ import ( ) func TestFullFeeder(t *testing.T) { + t.Parallel() + for i := 0; i < 10; i++ { go func() { rngFeeder <- []byte{0} diff --git a/rng/get.go b/rng/get.go index c7f168c..3ff97be 100644 --- a/rng/get.go +++ b/rng/get.go @@ -21,7 +21,7 @@ var ( rngLastFeed = time.Now() ) -// reader provides an io.Reader interface +// reader provides an io.Reader interface. type reader struct{} func init() { @@ -58,7 +58,7 @@ func Read(b []byte) (n int, err error) { return copy(b, rng.PseudoRandomData(uint(len(b)))), nil } -// Read implements the io.Reader interface +// Read implements the io.Reader interface. func (r reader) Read(b []byte) (n int, err error) { return Read(b) } diff --git a/rng/get_test.go b/rng/get_test.go index 38444ec..b920037 100644 --- a/rng/get_test.go +++ b/rng/get_test.go @@ -5,6 +5,8 @@ import ( ) func TestNumberRandomness(t *testing.T) { + t.Parallel() + // skip in automated tests t.Logf("Integer number bias test deactivated, as it sometimes triggers.") t.SkipNow() diff --git a/rng/osfeeder.go b/rng/osfeeder.go index 4bffe0e..36aa8e4 100644 --- a/rng/osfeeder.go +++ b/rng/osfeeder.go @@ -7,7 +7,6 @@ import ( ) func osFeeder(ctx context.Context) error { - entropyBytes := minFeedEntropy / 8 feeder := NewFeeder() defer feeder.CloseFeeder() @@ -17,7 +16,7 @@ func osFeeder(ctx context.Context) error { osEntropy := make([]byte, entropyBytes) n, err := rand.Read(osEntropy) if err != nil { - return fmt.Errorf("could not read entropy from os: %s", err) + return fmt.Errorf("could not read entropy from os: %w", err) } if n != entropyBytes { return fmt.Errorf("could not read enough entropy from os: got only %d bytes instead of %d", n, entropyBytes) diff --git a/rng/rng.go b/rng/rng.go index 4a017ba..9ad5655 100644 --- a/rng/rng.go +++ b/rng/rng.go @@ -21,7 +21,7 @@ var ( rngReady = false rngCipher = "aes" - // possible values: aes, serpent + // Possible values: "aes", "serpent". module *modules.Module ) @@ -56,7 +56,7 @@ func start() error { osEntropy := make([]byte, minFeedEntropy/8) _, err := rand.Read(osEntropy) if err != nil { - return fmt.Errorf("could not read entropy from os: %s", err) + return fmt.Errorf("could not read entropy from os: %w", err) } // feed rngLock.Lock() diff --git a/rng/rng_test.go b/rng/rng_test.go index b081b73..be70e17 100644 --- a/rng/rng_test.go +++ b/rng/rng_test.go @@ -12,6 +12,8 @@ func init() { } func TestRNG(t *testing.T) { + t.Parallel() + key := make([]byte, 16) rngCipher = "aes" diff --git a/rng/test/main.go b/rng/test/main.go index 7a4a8e6..ad5d7be 100644 --- a/rng/test/main.go +++ b/rng/test/main.go @@ -52,15 +52,15 @@ func prep() error { if len(os.Args) > 3 { n, err := strconv.ParseUint(os.Args[3], 10, 64) if err != nil { - return fmt.Errorf("failed to parse output size: %s", err) + return fmt.Errorf("failed to parse output size: %w", err) } outputSize = n * 1000000 } var err error - outputFile, err = os.OpenFile(os.Args[2], os.O_CREATE|os.O_WRONLY, 0660) + outputFile, err = os.OpenFile(os.Args[2], os.O_CREATE|os.O_WRONLY, 0o0644) if err != nil { - return fmt.Errorf("failed to open output file: %s", err) + return fmt.Errorf("failed to open output file: %w", err) } return nil diff --git a/rng/tickfeeder.go b/rng/tickfeeder.go index a44c7bd..6dbe69a 100644 --- a/rng/tickfeeder.go +++ b/rng/tickfeeder.go @@ -7,7 +7,6 @@ import ( ) func getTickFeederTickDuration() time.Duration { - // be ready in 1/10 time of reseedAfterSeconds msecsAvailable := reseedAfterSeconds * 100 // ex.: reseed after 10 minutes: msecsAvailable = 60000 @@ -33,7 +32,6 @@ func getTickFeederTickDuration() time.Duration { // tickFeeder is a really simple entropy feeder that adds the least significant bit of the current nanosecond unixtime to its pool every time it 'ticks'. // The more work the program does, the better the quality, as the internal schedular cannot immediately run the goroutine when it's ready. func tickFeeder(ctx context.Context) error { - var value int64 var pushes int feeder := NewFeeder() diff --git a/run/main.go b/run/main.go index 0af7482..c14c880 100644 --- a/run/main.go +++ b/run/main.go @@ -2,6 +2,7 @@ package run import ( "bufio" + "errors" "flag" "fmt" "io" @@ -29,11 +30,10 @@ func init() { // Run execute a full program lifecycle (including signal handling) based on modules. Just empty-import required packages and do os.Exit(run.Run()). func Run() int { - // Start err := modules.Start() if err != nil { - if err == modules.ErrCleanExit { + if errors.Is(err, modules.ErrCleanExit) { return 0 } diff --git a/runtime/module.go b/runtime/module.go index 2f22f61..ce02717 100644 --- a/runtime/module.go +++ b/runtime/module.go @@ -7,11 +7,9 @@ import ( "github.com/safing/portbase/modules" ) -var ( - // DefaultRegistry is the default registry - // that is used by the module-level API. - DefaultRegistry = NewRegistry() -) +// DefaultRegistry is the default registry +// that is used by the module-level API. +var DefaultRegistry = NewRegistry() func init() { modules.Register("runtime", nil, startModule, nil, "database") diff --git a/runtime/modules_integration.go b/runtime/modules_integration.go index 2a16c47..264a5dd 100644 --- a/runtime/modules_integration.go +++ b/runtime/modules_integration.go @@ -10,9 +10,7 @@ import ( "github.com/safing/portbase/modules" ) -var ( - modulesIntegrationUpdatePusher func(...record.Record) -) +var modulesIntegrationUpdatePusher func(...record.Record) func startModulesIntegration() (err error) { modulesIntegrationUpdatePusher, err = Register("modules/", &ModulesIntegration{}) @@ -27,6 +25,7 @@ func startModulesIntegration() (err error) { return nil } +// ModulesIntegration provides integration with the modules system. type ModulesIntegration struct{} // Set is called when the value is set from outside. @@ -45,13 +44,13 @@ func (mi *ModulesIntegration) Get(keyOrPrefix string) ([]record.Record, error) { return nil, database.ErrNotFound } -type eventData struct { //nolint:unused // This is a cascading false positive. +type eventData struct { record.Base sync.Mutex Data interface{} } -func pushModuleEvent(moduleName, eventName string, internal bool, data interface{}) { //nolint:unused // This is a false positive, the function is provided to modules.SetEventSubscriptionFunc(). +func pushModuleEvent(moduleName, eventName string, internal bool, data interface{}) { // Create event record and set key. eventRecord := &eventData{ Data: data, diff --git a/runtime/provider.go b/runtime/provider.go index 8ddf583..87f179c 100644 --- a/runtime/provider.go +++ b/runtime/provider.go @@ -67,6 +67,8 @@ func (fn SimpleValueGetterFunc) Get(keyOrPrefix string) ([]record.Record, error) return fn(keyOrPrefix) } -// compile time checks -var _ ValueProvider = SimpleValueGetterFunc(nil) -var _ ValueProvider = SimpleValueSetterFunc(nil) +// Compile time checks. +var ( + _ ValueProvider = SimpleValueGetterFunc(nil) + _ ValueProvider = SimpleValueSetterFunc(nil) +) diff --git a/runtime/registry.go b/runtime/registry.go index 2b7bd31..7fe7ee3 100644 --- a/runtime/registry.go +++ b/runtime/registry.go @@ -7,13 +7,14 @@ import ( "sync" "github.com/armon/go-radix" + "golang.org/x/sync/errgroup" + "github.com/safing/portbase/database" "github.com/safing/portbase/database/iterator" "github.com/safing/portbase/database/query" "github.com/safing/portbase/database/record" "github.com/safing/portbase/database/storage" "github.com/safing/portbase/log" - "golang.org/x/sync/errgroup" ) var ( diff --git a/runtime/registry_test.go b/runtime/registry_test.go index fe8b8a6..84f88b5 100644 --- a/runtime/registry_test.go +++ b/runtime/registry_test.go @@ -5,10 +5,11 @@ import ( "sync" "testing" - "github.com/safing/portbase/database/query" - "github.com/safing/portbase/database/record" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/safing/portbase/database/query" + "github.com/safing/portbase/database/record" ) type testRecord struct { @@ -71,6 +72,8 @@ func getTestRegistry(t *testing.T) *Registry { } func TestRegistryGet(t *testing.T) { + t.Parallel() + var ( r record.Record err error @@ -98,6 +101,8 @@ func TestRegistryGet(t *testing.T) { } func TestRegistryQuery(t *testing.T) { + t.Parallel() + reg := getTestRegistry(t) q := query.New("runtime:p") @@ -122,6 +127,8 @@ func TestRegistryQuery(t *testing.T) { } func TestRegistryRegister(t *testing.T) { + t.Parallel() + r := NewRegistry() cases := []struct { diff --git a/template/module.go b/template/module.go index 580b7fa..f2bc13a 100644 --- a/template/module.go +++ b/template/module.go @@ -13,14 +13,9 @@ const ( eventStateUpdate = "state update" ) -var ( - module *modules.Module -) +var module *modules.Module func init() { - // register base module, for database initialization - modules.Register("base", nil, nil, nil) - // register module module = modules.Register("template", prep, start, stop) // add dependencies... subsystems.Register( diff --git a/template/module_test.go b/template/module_test.go index 987ef74..6e76eb9 100644 --- a/template/module_test.go +++ b/template/module_test.go @@ -6,11 +6,15 @@ import ( "os" "testing" + _ "github.com/safing/portbase/database/dbmodule" "github.com/safing/portbase/dataroot" "github.com/safing/portbase/modules" ) func TestMain(m *testing.M) { + // register base module, for database initialization + modules.Register("base", nil, nil, nil) + // enable module for testing module.Enable() @@ -21,7 +25,7 @@ func TestMain(m *testing.M) { os.Exit(1) } // initialize data dir - err = dataroot.Initialize(tmpDir, 0755) + err = dataroot.Initialize(tmpDir, 0o0755) if err != nil { fmt.Fprintf(os.Stderr, "failed to initialize data root: %s\n", err) os.Exit(1) diff --git a/updater/export.go b/updater/export.go index 55b6133..7ce394a 100644 --- a/updater/export.go +++ b/updater/export.go @@ -7,10 +7,10 @@ func (reg *ResourceRegistry) Export() map[string]*Resource { defer reg.RUnlock() // copy the map - new := make(map[string]*Resource) + copiedResources := make(map[string]*Resource) for key, val := range reg.resources { - new[key] = val + copiedResources[key] = val } - return new + return copiedResources } diff --git a/updater/fetch.go b/updater/fetch.go index 85465f2..e6942a9 100644 --- a/updater/fetch.go +++ b/updater/fetch.go @@ -64,7 +64,7 @@ func (reg *ResourceRegistry) fetchFile(ctx context.Context, client *http.Client, // set permissions if !onWindows { // TODO: only set executable files to 0755, set other to 0644 - err = os.Chmod(rv.storagePath(), 0755) + err = os.Chmod(rv.storagePath(), 0o0755) if err != nil { log.Warningf("%s: failed to set permissions on downloaded file %s: %s", reg.Name, rv.storagePath(), err) } @@ -117,7 +117,7 @@ func (reg *ResourceRegistry) makeRequest(ctx context.Context, client *http.Clien downloadURL = u.String() // create request - req, err := http.NewRequestWithContext(ctx, "GET", downloadURL, http.NoBody) //nolint:gosec + req, err := http.NewRequestWithContext(ctx, "GET", downloadURL, http.NoBody) if err != nil { return nil, "", fmt.Errorf("failed to create request for %q: %w", downloadURL, err) } diff --git a/updater/file.go b/updater/file.go index 1ad76f0..b879e3a 100644 --- a/updater/file.go +++ b/updater/file.go @@ -5,10 +5,10 @@ import ( "os" "strings" + semver "github.com/hashicorp/go-version" + "github.com/safing/portbase/log" "github.com/safing/portbase/utils" - - semver "github.com/hashicorp/go-version" ) // File represents a file from the update system. @@ -50,7 +50,7 @@ func (file *File) Blacklist() error { return file.resource.Blacklist(file.version.VersionNumber) } -// used marks the file as active +// markActiveWithLocking marks the file as active, locking the resource in the process. func (file *File) markActiveWithLocking() { file.resource.Lock() defer file.resource.Unlock() diff --git a/updater/filename_test.go b/updater/filename_test.go index be8abf4..cf5fb92 100644 --- a/updater/filename_test.go +++ b/updater/filename_test.go @@ -8,6 +8,8 @@ import ( ) func testRegexMatch(t *testing.T, testRegex *regexp.Regexp, testString string, shouldMatch bool) { + t.Helper() + if testRegex.MatchString(testString) != shouldMatch { if shouldMatch { t.Errorf("regex %s should match %s", testRegex, testString) @@ -18,6 +20,8 @@ func testRegexMatch(t *testing.T, testRegex *regexp.Regexp, testString string, s } func testRegexFind(t *testing.T, testRegex *regexp.Regexp, testString string, shouldMatch bool) { + t.Helper() + if (testRegex.FindString(testString) != "") != shouldMatch { if shouldMatch { t.Errorf("regex %s should find %s", testRegex, testString) @@ -28,6 +32,8 @@ func testRegexFind(t *testing.T, testRegex *regexp.Regexp, testString string, sh } func testVersionTransformation(t *testing.T, testFilename, testIdentifier, testVersion string) { + t.Helper() + identifier, version, ok := GetIdentifierAndVersion(testFilename) if !ok { t.Errorf("failed to get identifier and version of %s", testFilename) @@ -40,6 +46,8 @@ func testVersionTransformation(t *testing.T, testFilename, testIdentifier, testV } func TestRegexes(t *testing.T) { + t.Parallel() + testRegexMatch(t, rawVersionRegex, "0.1.2", true) testRegexMatch(t, rawVersionRegex, "0.1.2-beta", true) testRegexMatch(t, rawVersionRegex, "0.1.2-staging", true) diff --git a/updater/get.go b/updater/get.go index fd0d133..b04dbbc 100644 --- a/updater/get.go +++ b/updater/get.go @@ -9,7 +9,7 @@ import ( "github.com/safing/portbase/log" ) -// Errors +// Errors returned by the updater package. var ( ErrNotFound = errors.New("the requested file could not be found") ErrNotAvailableLocally = errors.New("the requested file is not available locally") diff --git a/updater/registry.go b/updater/registry.go index 26055d6..6267a33 100644 --- a/updater/registry.go +++ b/updater/registry.go @@ -61,7 +61,7 @@ func (reg *ResourceRegistry) Initialize(storageDir *utils.DirStructure) error { // initialize private attributes reg.storageDir = storageDir - reg.tmpDir = storageDir.ChildDir("tmp", 0700) + reg.tmpDir = storageDir.ChildDir("tmp", 0o0700) reg.resources = make(map[string]*Resource) // remove tmp dir to delete old entries diff --git a/updater/registry_test.go b/updater/registry_test.go index 8412a0c..2ef1b78 100644 --- a/updater/registry_test.go +++ b/updater/registry_test.go @@ -8,9 +8,7 @@ import ( "github.com/safing/portbase/utils" ) -var ( - registry *ResourceRegistry -) +var registry *ResourceRegistry func TestMain(m *testing.M) { // setup @@ -23,7 +21,7 @@ func TestMain(m *testing.M) { DevMode: true, Online: true, } - err = registry.Initialize(utils.NewDirStructure(tmpDir, 0777)) + err = registry.Initialize(utils.NewDirStructure(tmpDir, 0o0777)) if err != nil { panic(err) } diff --git a/updater/resource.go b/updater/resource.go index 7099a28..ab9b38a 100644 --- a/updater/resource.go +++ b/updater/resource.go @@ -8,14 +8,12 @@ import ( "strings" "sync" - "github.com/safing/portbase/log" - semver "github.com/hashicorp/go-version" + + "github.com/safing/portbase/log" ) -var ( - devVersion *semver.Version -) +var devVersion *semver.Version func init() { var err error @@ -106,7 +104,7 @@ func (rv *ResourceVersion) isSelectable() bool { // isBetaVersionNumber checks if rv is marked as a beta version by checking // the version string. It does not honor the BetaRelease field of rv! -func (rv *ResourceVersion) isBetaVersionNumber() bool { +func (rv *ResourceVersion) isBetaVersionNumber() bool { //nolint:unused // "b" suffix check if for backwards compatibility // new versions should use the pre-release suffix as // declared by https://semver.org @@ -264,7 +262,6 @@ func (res *Resource) selectVersion() { log.Debugf("updater: active version of %s is %s, update available", res.Identifier, res.ActiveVersion.VersionNumber) } - }() if len(res.Versions) == 0 { diff --git a/updater/resource_test.go b/updater/resource_test.go index c7df6a3..3177544 100644 --- a/updater/resource_test.go +++ b/updater/resource_test.go @@ -9,6 +9,8 @@ import ( ) func TestVersionSelection(t *testing.T) { + t.Parallel() + res := registry.newResource("test/a") err := res.AddVersion("1.2.2", true, false, false) @@ -93,6 +95,8 @@ func TestVersionSelection(t *testing.T) { } func TestVersionParsing(t *testing.T) { + t.Parallel() + assert.Equal(t, "1.2.3", parseVersion("1.2.3")) assert.Equal(t, "1.2.0", parseVersion("1.2.0")) assert.Equal(t, "0.2.0", parseVersion("0.2.0")) diff --git a/updater/unpacking.go b/updater/unpacking.go index 3a2ed12..5b19b86 100644 --- a/updater/unpacking.go +++ b/updater/unpacking.go @@ -10,12 +10,15 @@ import ( "path/filepath" "strings" - "github.com/safing/portbase/log" - "github.com/hashicorp/go-multierror" + + "github.com/safing/portbase/log" "github.com/safing/portbase/utils" ) +// MaxUnpackSize specifies the maximum size that will be unpacked. +const MaxUnpackSize = 1000000000 // 1GB + // UnpackGZIP unpacks a GZIP compressed reader r // and returns a new reader. It's suitable to be // used with registry.GetPackedFile. @@ -95,7 +98,7 @@ func (res *Resource) unpackZipArchive() (err error) { // Create the tmp directory for unpacking. err = res.registry.tmpDir.EnsureAbsPath(tmpDir) if err != nil { - return fmt.Errorf("failed to create tmp dir for unpacking: %s", err) + return fmt.Errorf("failed to create tmp dir for unpacking: %w", err) } // Defer clean up of directories. @@ -168,7 +171,7 @@ func copyFromZipArchive(archiveFile *zip.File, dstPath string) error { defer dstFile.Close() // Copy full file from archive to dst. - if _, err := io.Copy(dstFile, fileReader); err != nil { + if _, err := io.CopyN(dstFile, fileReader, MaxUnpackSize); err != nil { return err } diff --git a/updater/updating.go b/updater/updating.go index 81021bf..05b89d4 100644 --- a/updater/updating.go +++ b/updater/updating.go @@ -10,9 +10,8 @@ import ( "path/filepath" "strings" - "github.com/safing/portbase/utils" - "github.com/safing/portbase/log" + "github.com/safing/portbase/utils" ) // UpdateIndexes downloads all indexes. An error is only returned when all @@ -32,7 +31,7 @@ func (reg *ResourceRegistry) UpdateIndexes(ctx context.Context) error { } if !anySuccess { - return fmt.Errorf("failed to update all indexes, last error was: %s", lastErr) + return fmt.Errorf("failed to update all indexes, last error was: %w", lastErr) } return nil } @@ -94,7 +93,8 @@ func (reg *ResourceRegistry) downloadIndex(ctx context.Context, client *http.Cli // save index indexPath := filepath.FromSlash(idx.Path) - err = ioutil.WriteFile(filepath.Join(reg.storageDir.Path, indexPath), data, 0644) + // Index files must be readable by portmaster-staert with user permissions in order to load the index. + err = ioutil.WriteFile(filepath.Join(reg.storageDir.Path, indexPath), data, 0o0644) //nolint:gosec if err != nil { log.Warningf("%s: failed to save updated index %s: %s", reg.Name, idx.Path, err) } diff --git a/utils/debug/debug.go b/utils/debug/debug.go index 514bef5..a28146b 100644 --- a/utils/debug/debug.go +++ b/utils/debug/debug.go @@ -8,10 +8,11 @@ import ( "strings" "time" + "github.com/shirou/gopsutil/host" + "github.com/safing/portbase/info" "github.com/safing/portbase/log" "github.com/safing/portbase/modules" - "github.com/shirou/gopsutil/host" ) // Info gathers debugging information and stores everything in a buffer in diff --git a/utils/fs.go b/utils/fs.go index ac72c91..e0873a7 100644 --- a/utils/fs.go +++ b/utils/fs.go @@ -27,17 +27,17 @@ func EnsureDirectory(path string, perm os.FileMode) error { } err = os.Remove(path) if err != nil { - return fmt.Errorf("could not remove file %s to place dir: %s", path, err) + return fmt.Errorf("could not remove file %s to place dir: %w", path, err) } } // file does not exist (or has been deleted) if err == nil || os.IsNotExist(err) { err = os.Mkdir(path, perm) if err != nil { - return fmt.Errorf("could not create dir %s: %s", path, err) + return fmt.Errorf("could not create dir %s: %w", path, err) } return os.Chmod(path, perm) } // other error opening path - return fmt.Errorf("failed to access %s: %s", path, err) + return fmt.Errorf("failed to access %s: %w", path, err) } diff --git a/utils/onceagain_test.go b/utils/onceagain_test.go index 06fc6ec..0863d27 100644 --- a/utils/onceagain_test.go +++ b/utils/onceagain_test.go @@ -10,6 +10,7 @@ import ( ) func TestOnceAgain(t *testing.T) { + t.Parallel() oa := OnceAgain{} executed := abool.New() diff --git a/utils/osdetail/binmeta_default.go b/utils/osdetail/binmeta_default.go index dee29e1..c9307fc 100644 --- a/utils/osdetail/binmeta_default.go +++ b/utils/osdetail/binmeta_default.go @@ -1,4 +1,4 @@ -//+build !windows +// go:build !windows package osdetail diff --git a/utils/renameio/example_test.go b/utils/renameio/example_test.go index cb08fa5..685e79e 100644 --- a/utils/renameio/example_test.go +++ b/utils/renameio/example_test.go @@ -13,7 +13,9 @@ func ExampleTempFile_justone() { if err != nil { return err } - defer t.Cleanup() + defer func() { + _ = t.Cleanup() + }() if _, err := fmt.Fprintf(t, "temperature_degc %f\n", temperature); err != nil { return err } @@ -35,7 +37,9 @@ func ExampleTempFile_many() { if err != nil { return err } - defer t.Cleanup() + defer func() { + _ = t.Cleanup() + }() if _, err := fmt.Fprintf(t, "temperature_degc %f\n", temperature); err != nil { return err } diff --git a/utils/renameio/symlink_test.go b/utils/renameio/symlink_test.go index e82d1e1..120d014 100644 --- a/utils/renameio/symlink_test.go +++ b/utils/renameio/symlink_test.go @@ -1,4 +1,4 @@ -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows +// go:build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package renameio @@ -11,14 +11,18 @@ import ( ) func TestSymlink(t *testing.T) { - d, err := ioutil.TempDir("", "tempdirtest") + t.Parallel() + + d, err := ioutil.TempDir("", "test-renameio-testsymlink") if err != nil { t.Fatal(err) } - defer os.RemoveAll(d) + t.Cleanup(func() { + _ = os.RemoveAll(d) + }) want := []byte("Hello World") - if err := ioutil.WriteFile(filepath.Join(d, "hello.txt"), want, 0644); err != nil { + if err := ioutil.WriteFile(filepath.Join(d, "hello.txt"), want, 0o0600); err != nil { t.Fatal(err) } diff --git a/utils/renameio/tempfile_linux_test.go b/utils/renameio/tempfile_linux_test.go index 16da9b5..bf569ea 100644 --- a/utils/renameio/tempfile_linux_test.go +++ b/utils/renameio/tempfile_linux_test.go @@ -1,4 +1,4 @@ -// +build linux +// go:build linux package renameio @@ -11,33 +11,47 @@ import ( ) func TestTempDir(t *testing.T) { + t.Parallel() + if tmpdir, ok := os.LookupEnv("TMPDIR"); ok { - defer os.Setenv("TMPDIR", tmpdir) // restore + t.Cleanup(func() { + os.Setenv("TMPDIR", tmpdir) // restore + }) } else { - defer os.Unsetenv("TMPDIR") // restore + t.Cleanup(func() { + os.Unsetenv("TMPDIR") // restore + }) } - mount1, err := ioutil.TempDir("", "tempdirtest") + mount1, err := ioutil.TempDir("", "test-renameio-testtempdir1") if err != nil { t.Fatal(err) } - defer os.RemoveAll(mount1) + t.Cleanup(func() { + os.RemoveAll(mount1) + }) - mount2, err := ioutil.TempDir("", "tempdirtest") + mount2, err := ioutil.TempDir("", "test-renameio-testtempdir2") if err != nil { t.Fatal(err) } - defer os.RemoveAll(mount2) + t.Cleanup(func() { + os.RemoveAll(mount2) + }) if err := syscall.Mount("tmpfs", mount1, "tmpfs", 0, ""); err != nil { t.Skipf("cannot mount tmpfs on %s: %v", mount1, err) } - defer syscall.Unmount(mount1, 0) + t.Cleanup(func() { + _ = syscall.Unmount(mount1, 0) + }) if err := syscall.Mount("tmpfs", mount2, "tmpfs", 0, ""); err != nil { t.Skipf("cannot mount tmpfs on %s: %v", mount2, err) } - defer syscall.Unmount(mount2, 0) + t.Cleanup(func() { + _ = syscall.Unmount(mount2, 0) + }) tests := []struct { name string @@ -83,14 +97,19 @@ func TestTempDir(t *testing.T) { } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if tt.TMPDIR == "" { + testCase := tt + + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + if testCase.TMPDIR == "" { os.Unsetenv("TMPDIR") } else { - os.Setenv("TMPDIR", tt.TMPDIR) + os.Setenv("TMPDIR", testCase.TMPDIR) } - if got := tempDir(tt.dir, tt.path); got != tt.want { - t.Fatalf("tempDir(%q, %q): got %q, want %q", tt.dir, tt.path, got, tt.want) + + if got := tempDir(testCase.dir, testCase.path); got != testCase.want { + t.Fatalf("tempDir(%q, %q): got %q, want %q", testCase.dir, testCase.path, got, testCase.want) } }) } diff --git a/utils/renameio/writefile.go b/utils/renameio/writefile.go index 35df136..4f3dc03 100644 --- a/utils/renameio/writefile.go +++ b/utils/renameio/writefile.go @@ -9,7 +9,9 @@ func WriteFile(filename string, data []byte, perm os.FileMode) error { if err != nil { return err } - defer t.Cleanup() + defer func() { + _ = t.Cleanup() + }() // Set permissions before writing data, in case the data is sensitive. if err := t.Chmod(perm); err != nil { diff --git a/utils/renameio/writefile_test.go b/utils/renameio/writefile_test.go index dbe6984..92872e7 100644 --- a/utils/renameio/writefile_test.go +++ b/utils/renameio/writefile_test.go @@ -1,4 +1,4 @@ -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows +// go:build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package renameio @@ -11,7 +11,9 @@ import ( ) func TestWriteFile(t *testing.T) { - d, err := ioutil.TempDir("", "tempdirtest") + t.Parallel() + + d, err := ioutil.TempDir("", "test-renameio-testwritefile") if err != nil { t.Fatal(err) } @@ -20,7 +22,7 @@ func TestWriteFile(t *testing.T) { filename := filepath.Join(d, "hello.sh") wantData := []byte("#!/bin/sh\necho \"Hello World\"\n") - wantPerm := os.FileMode(0755) + wantPerm := os.FileMode(0o0600) if err := WriteFile(filename, wantData, wantPerm); err != nil { t.Fatal(err) } diff --git a/utils/safe.go b/utils/safe.go index e3a55b8..90199cf 100644 --- a/utils/safe.go +++ b/utils/safe.go @@ -5,6 +5,7 @@ import ( "strings" ) +// SafeFirst16Bytes return the first 16 bytes of the given data in safe form. func SafeFirst16Bytes(data []byte) string { if len(data) == 0 { return "" @@ -16,6 +17,7 @@ func SafeFirst16Bytes(data []byte) string { ) } +// SafeFirst16Chars return the first 16 characters of the given data in safe form. func SafeFirst16Chars(s string) string { return SafeFirst16Bytes([]byte(s)) } diff --git a/utils/safe_test.go b/utils/safe_test.go index d60d4c9..43480f7 100644 --- a/utils/safe_test.go +++ b/utils/safe_test.go @@ -7,6 +7,8 @@ import ( ) func TestSafeFirst16(t *testing.T) { + t.Parallel() + assert.Equal(t, "47 6f 20 69 73 20 61 6e 20 6f 70 65 6e 20 73 6f |Go is an open so|", SafeFirst16Bytes([]byte("Go is an open source programming language.")), diff --git a/utils/slices_test.go b/utils/slices_test.go index 15c7580..50ac494 100644 --- a/utils/slices_test.go +++ b/utils/slices_test.go @@ -13,6 +13,8 @@ var ( ) func TestStringInSlice(t *testing.T) { + t.Parallel() + if !StringInSlice(stringTestSlice, "a") { t.Fatal("string reported not in slice (1), but it is") } @@ -35,6 +37,8 @@ func TestStringInSlice(t *testing.T) { } func TestRemoveFromStringSlice(t *testing.T) { + t.Parallel() + test1 := DuplicateStrings(stringTestSlice) test1 = RemoveFromStringSlice(test1, "b") if StringInSlice(test1, "b") { @@ -47,6 +51,8 @@ func TestRemoveFromStringSlice(t *testing.T) { } func TestDuplicateStrings(t *testing.T) { + t.Parallel() + a := DuplicateStrings(stringTestSlice) if !StringSliceEqual(a, stringTestSlice) { t.Fatal("copied string slice is not equal") @@ -58,6 +64,8 @@ func TestDuplicateStrings(t *testing.T) { } func TestStringSliceEqual(t *testing.T) { + t.Parallel() + if !StringSliceEqual(stringTestSlice, stringTestSlice) { t.Fatal("strings are equal, but are reported as not") } @@ -70,6 +78,8 @@ func TestStringSliceEqual(t *testing.T) { } func TestDuplicateBytes(t *testing.T) { + t.Parallel() + a := DuplicateBytes(byteTestSlice) if !bytes.Equal(a, byteTestSlice) { t.Fatal("copied bytes slice is not equal") diff --git a/utils/stablepool_test.go b/utils/stablepool_test.go index 32d69d1..0f8ed72 100644 --- a/utils/stablepool_test.go +++ b/utils/stablepool_test.go @@ -10,6 +10,7 @@ import ( ) func TestStablePoolRealWorld(t *testing.T) { + t.Parallel() // "real world" simulation cnt := 0 @@ -73,6 +74,7 @@ func TestStablePoolRealWorld(t *testing.T) { } func TestStablePoolFuzzing(t *testing.T) { + t.Parallel() // fuzzing test fuzzPool := &StablePool{} @@ -101,6 +103,7 @@ func TestStablePoolFuzzing(t *testing.T) { } func TestStablePoolBreaking(t *testing.T) { + t.Parallel() // try to break it breakPool := &StablePool{} @@ -114,5 +117,4 @@ func TestStablePoolBreaking(t *testing.T) { assert.Equal(t, k, breakPool.Get(), "should match") } } - } diff --git a/utils/structure.go b/utils/structure.go index 5a8b331..5a50d97 100644 --- a/utils/structure.go +++ b/utils/structure.go @@ -41,15 +41,15 @@ func (ds *DirStructure) ChildDir(dirName string, perm os.FileMode) (child *DirSt } // create new - new := &DirStructure{ + newDir := &DirStructure{ Path: filepath.Join(ds.Path, dirName), Dir: dirName, Perm: perm, Parent: ds, Children: make(map[string]*DirStructure), } - ds.Children[dirName] = new - return new + ds.Children[dirName] = newDir + return newDir } // Ensure ensures that the specified directory structure (from the first parent on) exists. @@ -94,7 +94,7 @@ func (ds *DirStructure) EnsureAbsPath(dirPath string) error { // get relative path relPath, err := filepath.Rel(ds.Path, dirPath) if err != nil { - return fmt.Errorf("failed to get relative path: %s", err) + return fmt.Errorf("failed to get relative path: %w", err) } // split to path elements diff --git a/utils/structure_test.go b/utils/structure_test.go index 59cc611..8cbb2ae 100644 --- a/utils/structure_test.go +++ b/utils/structure_test.go @@ -1,4 +1,4 @@ -// +build !windows +// go:build !windows package utils @@ -29,12 +29,12 @@ func ExampleDirStructure() { return } - ds := NewDirStructure(basePath, 0755) - secret := ds.ChildDir("secret", 0700) - repo := ds.ChildDir("repo", 0777) - _ = repo.ChildDir("a", 0700) - b := repo.ChildDir("b", 0707) - c := b.ChildDir("c", 0750) + ds := NewDirStructure(basePath, 0o0755) + secret := ds.ChildDir("secret", 0o0700) + repo := ds.ChildDir("repo", 0o0777) + _ = repo.ChildDir("a", 0o0700) + b := repo.ChildDir("b", 0o0707) + c := b.ChildDir("c", 0o0750) err = ds.Ensure() if err != nil { diff --git a/utils/uuid.go b/utils/uuid.go index 8d185c4..bf437ba 100644 --- a/utils/uuid.go +++ b/utils/uuid.go @@ -12,7 +12,7 @@ var ( instanceUUID = RandomUUID("instance") ) -// RandomUUID returns a new random UUID with optionally provided ns +// RandomUUID returns a new random UUID with optionally provided ns. func RandomUUID(ns string) uuid.UUID { randUUID, err := uuid.NewV4() switch { diff --git a/utils/uuid_test.go b/utils/uuid_test.go index fff8825..6985b81 100644 --- a/utils/uuid_test.go +++ b/utils/uuid_test.go @@ -8,6 +8,8 @@ import ( ) func TestUUID(t *testing.T) { + t.Parallel() + // check randomness a := RandomUUID("") a2 := RandomUUID("") From ea573104837889b0fea82ecd7d0b2dee250de2f1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 1 Feb 2022 13:16:02 +0100 Subject: [PATCH 2/8] Update test script --- test | 42 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/test b/test index ef569db..815080c 100755 --- a/test +++ b/test @@ -17,9 +17,9 @@ function help { echo " install install deps for running tests" echo "" echo "options:" - echo " --scripted dont jump console lines (still use colors)" - echo " --test-only skip linters and only run tests" - echo " [package] run tests only on this package" + echo " --scripted don't jump console lines (still use colors)" + echo " --test-only run tests only, no linters" + echo " [package] run only on this package" } function run { @@ -62,22 +62,6 @@ function run { rm -f $tmpfile } -function checkformat { - if [[ $scripted -eq 0 ]]; then - echo "[......] gofmt $1" - fi - - output=$(gofmt -l $GOPATH/src/$1/*.go) - if [[ $output == "" ]]; then - echo -e "${goUp}[\e[01;32m OK \e[00m] gofmt $*" - else - echo -e "${goUp}[\e[01;31m FAIL \e[00m] gofmt $*" - echo "The following files do not conform to gofmt:" - gofmt -l $GOPATH/src/$1/*.go # keeps format - errors=$((errors+1)) - fi -} - # get and switch to script dir baseDir="$( cd "$(dirname "$0")" && pwd )" cd "$baseDir" @@ -154,18 +138,14 @@ if [[ $testonly -eq 0 ]]; then exit 1 fi fi + # target selection if [[ "$1" == "" ]]; then # get all packages - packages=$(go list ./...) + packages=$(go list -e ./...) else # single package testing - packages=$(go list)/$1 - if [[ ! -d "$GOPATH/src/$packages" ]]; then - echo "go package $packages does not exist" - help - exit 1 - fi + packages=$(go list -e)/$1 echo "note: only running tests for package $packages" fi @@ -175,16 +155,14 @@ echo "running tests for ${platformInfo//$'\n'/ }:" # run vet/test on packages for package in $packages; do - package=${package#github.com/safing/portbase} - package=${package#/} - package=$PWD/$package + packagename=${package#github.com/safing/portbase} #TODO: could be queried with `go list .` + packagename=${packagename#/} echo "" echo $package if [[ $testonly -eq 0 ]]; then - checkformat $package run golint -set_exit_status -min_confidence 1.0 $package run go vet $package - run golangci-lint run $package + run golangci-lint run $packagename fi run go test -cover $fullTestFlags $package done @@ -196,4 +174,4 @@ if [[ $errors -gt 0 ]]; then else echo "succeeded with $warnings warnings" exit 0 -fi \ No newline at end of file +fi From dba4ba3dc78b017666ab2a0c1b72eaffb32ea097 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 1 Feb 2022 13:16:38 +0100 Subject: [PATCH 3/8] Update golangci-lint config --- .golangci.yml | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 127b277..468bfff 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,17 +1,37 @@ +# Docs: +# https://golangci-lint.run/usage/linters/ + linters: enable-all: true disable: - - lll - - gochecknoinits - - gochecknoglobals + - cyclop + - exhaustivestruct + - forbidigo - funlen - - whitespace - - wsl - - gomnd + - gochecknoglobals + - gochecknoinits + - gocognit + - gocyclo - goerr113 + - gomnd + - ifshort + - interfacer + - lll + - nestif + - nlreturn + - noctx + - revive - testpackage + - whitespace + - wrapcheck + - wsl linters-settings: + gci: + # put imports beginning with prefix after 3rd-party packages; + # only support one prefix + # if not set, use goimports.local-prefixes + local-prefixes: github.com/safing godox: # report any comments starting with keywords, this is useful for TODO or FIXME comments that # might be left in the code accidentally and should be resolved before merging From fcb5ca24732b42edbab5824d2ef3df47c83d07bf Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 1 Feb 2022 13:16:53 +0100 Subject: [PATCH 4/8] Update golangci-lint to v1.44 --- .github/workflows/go.yml | 2 +- test | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 9246bcf..94aa7dc 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -37,7 +37,7 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@v2 with: - version: v1.29 + version: v1.44 only-new-issues: true args: -c ./.golangci.yml skip-go-installation: true diff --git a/test b/test index 815080c..fd0f3ee 100755 --- a/test +++ b/test @@ -107,8 +107,8 @@ if [[ $install -eq 1 ]]; then echo "$ go get -u golang.org/x/lint/golint" go get -u golang.org/x/lint/golint # TODO: update golangci-lint version regularly - echo "$ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.29.0" - curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.29.0 + echo "$ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.0" + curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.0 exit 0 fi From 3e4e0c361d1dea277956e7c3ceef99c14ca3c075 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 1 Feb 2022 13:40:50 +0100 Subject: [PATCH 5/8] Fix or disable new linters --- .golangci.yml | 6 ++++++ database/accessor/accessor.go | 2 -- database/accessor/accessor_test.go | 2 +- database/database_test.go | 2 +- database/record/record.go | 4 ++++ formats/dsd/dsd_test.go | 2 +- formats/dsd/gencode_test.go | 4 ++-- log/output.go | 2 +- modules/subsystems/registry.go | 2 +- modules/tasks.go | 2 +- runtime/registry.go | 6 +++--- runtime/registry_test.go | 4 ++-- 12 files changed, 23 insertions(+), 15 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 468bfff..6cdc8ff 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -4,6 +4,8 @@ linters: enable-all: true disable: + - containedctx + - contextcheck - cyclop - exhaustivestruct - forbidigo @@ -16,12 +18,16 @@ linters: - gomnd - ifshort - interfacer + - ireturn - lll - nestif + - nilnil - nlreturn - noctx - revive + - tagliatelle - testpackage + - varnamelen - whitespace - wrapcheck - wsl diff --git a/database/accessor/accessor.go b/database/accessor/accessor.go index 9fde0e0..67a5373 100644 --- a/database/accessor/accessor.go +++ b/database/accessor/accessor.go @@ -13,8 +13,6 @@ type Accessor interface { GetFloat(key string) (value float64, ok bool) GetBool(key string) (value bool, ok bool) Exists(key string) bool - Set(key string, value interface{}) error - Type() string } diff --git a/database/accessor/accessor_test.go b/database/accessor/accessor_test.go index 302c8aa..5954c10 100644 --- a/database/accessor/accessor_test.go +++ b/database/accessor/accessor_test.go @@ -44,7 +44,7 @@ var ( F64: 42.42, B: true, } - testJSONBytes, _ = json.Marshal(testStruct) + testJSONBytes, _ = json.Marshal(testStruct) //nolint:errchkjson testJSON = string(testJSONBytes) ) diff --git a/database/database_test.go b/database/database_test.go index c4c2a30..b2d0225 100644 --- a/database/database_test.go +++ b/database/database_test.go @@ -45,7 +45,7 @@ func makeKey(dbName, key string) string { return fmt.Sprintf("%s:%s", dbName, key) } -func testDatabase(t *testing.T, storageType string, shadowDelete bool) { //nolint:gocognit,gocyclo,thelper +func testDatabase(t *testing.T, storageType string, shadowDelete bool) { //nolint:maintidx,thelper t.Run(fmt.Sprintf("TestStorage_%s_%v", storageType, shadowDelete), func(t *testing.T) { dbName := fmt.Sprintf("testing-%s-%v", storageType, shadowDelete) fmt.Println(dbName) diff --git a/database/record/record.go b/database/record/record.go index 65808f2..1da432c 100644 --- a/database/record/record.go +++ b/database/record/record.go @@ -12,17 +12,21 @@ type Record interface { DatabaseName() string // test DatabaseKey() string // config + // Metadata. Meta() *Meta SetMeta(meta *Meta) CreateMeta() UpdateMeta() + // Serialization. Marshal(self Record, format uint8) ([]byte, error) MarshalRecord(self Record) ([]byte, error) GetAccessor(self Record) accessor.Accessor + // Locking. Lock() Unlock() + // Wrapping. IsWrapped() bool } diff --git a/formats/dsd/dsd_test.go b/formats/dsd/dsd_test.go index 79fdd9b..479f727 100644 --- a/formats/dsd/dsd_test.go +++ b/formats/dsd/dsd_test.go @@ -117,7 +117,7 @@ var ( } ) -func TestConversion(t *testing.T) { +func TestConversion(t *testing.T) { //nolint:maintidx t.Parallel() compressionFormats := []uint8{AUTO, GZIP} diff --git a/formats/dsd/gencode_test.go b/formats/dsd/gencode_test.go index f1366f3..1957961 100644 --- a/formats/dsd/gencode_test.go +++ b/formats/dsd/gencode_test.go @@ -259,7 +259,7 @@ func (d *GenCodeTestStruct) Size() (s uint64) { return } -func (d *GenCodeTestStruct) GenCodeMarshal(buf []byte) ([]byte, error) { +func (d *GenCodeTestStruct) GenCodeMarshal(buf []byte) ([]byte, error) { //nolint:maintidx size := d.Size() { if uint64(cap(buf)) >= size { @@ -555,7 +555,7 @@ func (d *GenCodeTestStruct) GenCodeMarshal(buf []byte) ([]byte, error) { return buf[:i+35], nil } -func (d *GenCodeTestStruct) GenCodeUnmarshal(buf []byte) (uint64, error) { +func (d *GenCodeTestStruct) GenCodeUnmarshal(buf []byte) (uint64, error) { //nolint:maintidx i := uint64(0) { diff --git a/log/output.go b/log/output.go index 1c8f1ac..f3831c2 100644 --- a/log/output.go +++ b/log/output.go @@ -96,7 +96,7 @@ func TriggerWriterChannel() chan struct{} { } func defaultColorFormater(line Message, duplicates uint64) string { - return formatLine(line.(*logLine), duplicates, true) + return formatLine(line.(*logLine), duplicates, true) //nolint:forcetypeassert // TODO: improve } func startWriter() { diff --git a/modules/subsystems/registry.go b/modules/subsystems/registry.go index 6225b07..2914243 100644 --- a/modules/subsystems/registry.go +++ b/modules/subsystems/registry.go @@ -269,6 +269,6 @@ func (mng *Manager) findParentSubsystem(m *modules.Module) (*Subsystem, *ModuleS // Otherwise Less() will panic. type bySubsystemID []record.Record -func (sl bySubsystemID) Less(i, j int) bool { return sl[i].(*Subsystem).ID < sl[j].(*Subsystem).ID } +func (sl bySubsystemID) Less(i, j int) bool { return sl[i].(*Subsystem).ID < sl[j].(*Subsystem).ID } //nolint:forcetypeassert // Can only be *Subsystem. func (sl bySubsystemID) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] } func (sl bySubsystemID) Len() int { return len(sl) } diff --git a/modules/tasks.go b/modules/tasks.go index a37b96e..0f23dbf 100644 --- a/modules/tasks.go +++ b/modules/tasks.go @@ -427,7 +427,7 @@ func waitUntilNextScheduledTask() <-chan time.Time { defer scheduleLock.Unlock() if taskSchedule.Len() > 0 { - return time.After(time.Until(taskSchedule.Front().Value.(*Task).executeAt)) + return time.After(time.Until(taskSchedule.Front().Value.(*Task).executeAt)) //nolint:forcetypeassert // Can only be *Task. } return waitForever } diff --git a/runtime/registry.go b/runtime/registry.go index 7fe7ee3..26235e2 100644 --- a/runtime/registry.go +++ b/runtime/registry.go @@ -278,7 +278,7 @@ func (r *Registry) getMatchingProvider(key string) *keyedValueProvider { return nil } - return provider.(*keyedValueProvider) + return provider.(*keyedValueProvider) //nolint:forcetypeassert } func (r *Registry) collectProviderByPrefix(prefix string) []*keyedValueProvider { @@ -288,12 +288,12 @@ func (r *Registry) collectProviderByPrefix(prefix string) []*keyedValueProvider // if there's a LongestPrefix provider that's the only one // we need to ask if _, p, ok := r.providers.LongestPrefix(prefix); ok { - return []*keyedValueProvider{p.(*keyedValueProvider)} + return []*keyedValueProvider{p.(*keyedValueProvider)} //nolint:forcetypeassert } var providers []*keyedValueProvider r.providers.WalkPrefix(prefix, func(key string, p interface{}) bool { - providers = append(providers, p.(*keyedValueProvider)) + providers = append(providers, p.(*keyedValueProvider)) //nolint:forcetypeassert return false }) diff --git a/runtime/registry_test.go b/runtime/registry_test.go index 84f88b5..f4459ca 100644 --- a/runtime/registry_test.go +++ b/runtime/registry_test.go @@ -84,12 +84,12 @@ func TestRegistryGet(t *testing.T) { r, err = reg.Get("p1/f1/v1") require.NoError(t, err) require.NotNil(t, r) - assert.Equal(t, "p1.1", r.(*testRecord).Value) + assert.Equal(t, "p1.1", r.(*testRecord).Value) //nolint:forcetypeassert r, err = reg.Get("p1/v3") require.NoError(t, err) require.NotNil(t, r) - assert.Equal(t, "p1.3", r.(*testRecord).Value) + assert.Equal(t, "p1.3", r.(*testRecord).Value) //nolint:forcetypeassert r, err = reg.Get("p1/v4") require.Error(t, err) From 9222e0b328e04febb57a81b7b023fa046a165f2e Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 1 Feb 2022 13:47:57 +0100 Subject: [PATCH 6/8] Fix gofmt CI test --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 94aa7dc..2b13cbc 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -55,7 +55,7 @@ jobs: run: ./golint -set_exit_status -min_confidence 1.0 ./... - name: Run gofmt - run: bash -c "test -z $(gofmt -s -l .)" + run: bash -c 'test -z "$(gofmt -s -l .)"' test: name: Test From 22c59c50cc9ea3d196cf50551a29e230a5aef863 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 1 Feb 2022 13:57:38 +0100 Subject: [PATCH 7/8] Disable gofmt CI test for now --- .github/workflows/go.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 2b13cbc..b7b83ab 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -54,8 +54,9 @@ jobs: - name: Run golint run: ./golint -set_exit_status -min_confidence 1.0 ./... - - name: Run gofmt - run: bash -c 'test -z "$(gofmt -s -l .)"' + # TODO: Enable gofmt again when all environments are up to date. + # - name: Run gofmt + # run: bash -c 'test -z "$(gofmt -s -l .)"' test: name: Test From 6650fb3b19dac19fb514ef845f6d897ea808d8f9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 2 Feb 2022 14:58:27 +0100 Subject: [PATCH 8/8] Update linter settings and fix warnings --- .github/workflows/go.yml | 9 ++++++++- .golangci.yml | 20 ++++++++++++++++++++ api/client/websocket.go | 2 +- api/database.go | 2 +- api/main_test.go | 2 +- config/set_test.go | 10 +++++----- database/database_test.go | 2 +- database/query/parser.go | 2 +- database/record/meta-gencode.go | 9 --------- database/storage/badger/badger_test.go | 4 +++- database/storage/bbolt/bbolt_test.go | 4 +++- formats/dsd/gencode_test.go | 12 ------------ metrics/api.go | 4 +++- modules/subsystems/subsystems_test.go | 2 +- rng/test/main.go | 10 +++++----- template/module_test.go | 2 +- test | 9 --------- updater/fetch.go | 12 ++++++++---- updater/file.go | 4 +++- updater/registry_test.go | 2 +- updater/unpacking.go | 12 +++++++++--- utils/atomic.go | 4 +++- utils/debug/debug.go | 16 ++++++++-------- utils/renameio/tempfile.go | 12 +++++++----- utils/renameio/tempfile_linux_test.go | 12 ++++++------ utils/renameio/writefile_test.go | 4 +++- 26 files changed, 102 insertions(+), 81 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index b7b83ab..35826da 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -54,7 +54,14 @@ jobs: - name: Run golint run: ./golint -set_exit_status -min_confidence 1.0 ./... - # TODO: Enable gofmt again when all environments are up to date. + # golint is run (sufficiently; with excludes) as a part of golangci-lint. + # - name: Install golint + # run: bash -c "GOBIN=$(pwd) go get -u golang.org/x/lint/golint" + # + # - name: Run golint + # run: ./golint -set_exit_status -min_confidence 1.0 ./... + + # gofmt is run (sufficiently; with excludes) as a part of golangci-lint. # - name: Run gofmt # run: bash -c 'test -z "$(gofmt -s -l .)"' diff --git a/.golangci.yml b/.golangci.yml index 6cdc8ff..b4c851b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -33,6 +33,9 @@ linters: - wsl linters-settings: + revive: + # See https://github.com/mgechev/revive#available-rules for details. + enable-all-rules: true gci: # put imports beginning with prefix after 3rd-party packages; # only support one prefix @@ -43,3 +46,20 @@ linters-settings: # might be left in the code accidentally and should be resolved before merging keywords: - FIXME + gosec: + # To specify a set of rules to explicitly exclude. + # Available rules: https://github.com/securego/gosec#available-rules + excludes: + - G204 # Variables in commands. + - G304 # Variables in file paths. + - G505 # We need crypto/sha1 for non-security stuff. Using `nolint:` triggers another linter. + +issues: + exclude-use-default: false + exclude-rules: + - text: "a blank import .*" + linters: + - golint + - text: "ST1000: at least one file in a package should have a package comment.*" + linters: + - stylecheck diff --git a/api/client/websocket.go b/api/client/websocket.go index f8e2b2a..622cadf 100644 --- a/api/client/websocket.go +++ b/api/client/websocket.go @@ -41,7 +41,7 @@ func (c *Client) wsConnect() error { case <-c.shutdownSignal: state.Error("") } - state.wsConn.Close() + _ = state.wsConn.Close() state.wg.Wait() return nil diff --git a/api/database.go b/api/database.go index 5087dda..970dc38 100644 --- a/api/database.go +++ b/api/database.go @@ -251,7 +251,7 @@ func (api *DatabaseAPI) shutdown(err error) error { // Trigger shutdown. close(api.shutdownSignal) - api.conn.Close() + _ = api.conn.Close() return nil } diff --git a/api/main_test.go b/api/main_test.go index 8ca9089..078f4b6 100644 --- a/api/main_test.go +++ b/api/main_test.go @@ -52,6 +52,6 @@ func TestMain(m *testing.M) { fmt.Fprintf(os.Stderr, "failed to cleanly shutdown test: %s\n", err) } // clean up and exit - os.RemoveAll(tmpDir) + _ = os.RemoveAll(tmpDir) os.Exit(exitCode) } diff --git a/config/set_test.go b/config/set_test.go index 3c9037e..7d74ee2 100644 --- a/config/set_test.go +++ b/config/set_test.go @@ -1,4 +1,4 @@ -//nolint:goconst,errcheck +//nolint:goconst package config import "testing" @@ -83,7 +83,7 @@ func TestLayersSetters(t *testing.T) { //nolint:paralleltest // reset options = make(map[string]*Option) - Register(&Option{ + _ = Register(&Option{ Name: "name", Key: "monkey", Description: "description", @@ -93,7 +93,7 @@ func TestLayersSetters(t *testing.T) { //nolint:paralleltest DefaultValue: "banana", ValidationRegex: "^(banana|water)$", }) - Register(&Option{ + _ = Register(&Option{ Name: "name", Key: "zebras/zebra", Description: "description", @@ -103,7 +103,7 @@ func TestLayersSetters(t *testing.T) { //nolint:paralleltest DefaultValue: []string{"black", "white"}, ValidationRegex: "^[a-z]+$", }) - Register(&Option{ + _ = Register(&Option{ Name: "name", Key: "elephant", Description: "description", @@ -113,7 +113,7 @@ func TestLayersSetters(t *testing.T) { //nolint:paralleltest DefaultValue: 2, ValidationRegex: "", }) - Register(&Option{ + _ = Register(&Option{ Name: "name", Key: "hot", Description: "description", diff --git a/database/database_test.go b/database/database_test.go index b2d0225..33cb2df 100644 --- a/database/database_test.go +++ b/database/database_test.go @@ -36,7 +36,7 @@ func TestMain(m *testing.M) { // Clean up the test directory. // Do not defer, as we end this function with a os.Exit call. - os.RemoveAll(testDir) + _ = os.RemoveAll(testDir) os.Exit(exitCode) } diff --git a/database/query/parser.go b/database/query/parser.go index ff28ccf..988ea59 100644 --- a/database/query/parser.go +++ b/database/query/parser.go @@ -207,7 +207,7 @@ func parseAndOr(getSnippet func() (*snippet, error), remainingSnippets func() in for { if !expectingMore && rootCondition && remainingSnippets() == 0 { // advance snippetsPos by one, as it will be set back by 1 - getSnippet() //nolint:errcheck + _, _ = getSnippet() if len(conditions) == 1 { return conditions[0], nil } diff --git a/database/record/meta-gencode.go b/database/record/meta-gencode.go index 98c2ce5..180e7fa 100644 --- a/database/record/meta-gencode.go +++ b/database/record/meta-gencode.go @@ -2,15 +2,6 @@ package record import ( "fmt" - "io" - "time" - "unsafe" -) - -var ( - _ = unsafe.Sizeof(0) - _ = io.ReadFull - _ = time.Now() ) // GenCodeSize returns the size of the gencode marshalled byte slice. diff --git a/database/storage/badger/badger_test.go b/database/storage/badger/badger_test.go index 898e4ac..9cff49f 100644 --- a/database/storage/badger/badger_test.go +++ b/database/storage/badger/badger_test.go @@ -45,7 +45,9 @@ func TestBadger(t *testing.T) { if err != nil { t.Fatal(err) } - defer os.RemoveAll(testDir) // clean up + defer func() { + _ = os.RemoveAll(testDir) // clean up + }() // start db, err := NewBadger("test", testDir) diff --git a/database/storage/bbolt/bbolt_test.go b/database/storage/bbolt/bbolt_test.go index f11b965..5e9b302 100644 --- a/database/storage/bbolt/bbolt_test.go +++ b/database/storage/bbolt/bbolt_test.go @@ -47,7 +47,9 @@ func TestBBolt(t *testing.T) { if err != nil { t.Fatal(err) } - defer os.RemoveAll(testDir) // clean up + defer func() { + _ = os.RemoveAll(testDir) // clean up + }() // start db, err := NewBBolt("test", testDir) diff --git a/formats/dsd/gencode_test.go b/formats/dsd/gencode_test.go index 1957961..2fbf18a 100644 --- a/formats/dsd/gencode_test.go +++ b/formats/dsd/gencode_test.go @@ -1,18 +1,6 @@ //nolint:nakedret,unconvert,gocognit,wastedassign,gofumpt package dsd -import ( - "io" - "time" - "unsafe" -) - -var ( - _ = unsafe.Sizeof(0) - _ = io.ReadFull - _ = time.Now() -) - func (d *SimpleTestStruct) Size() (s uint64) { { diff --git a/metrics/api.go b/metrics/api.go index a83e195..974140e 100644 --- a/metrics/api.go +++ b/metrics/api.go @@ -101,7 +101,9 @@ func writeMetricsTo(ctx context.Context, url string) error { if err != nil { return err } - defer resp.Body.Close() + defer func() { + _ = resp.Body.Close() + }() // Check return status. if resp.StatusCode >= 200 && resp.StatusCode <= 299 { diff --git a/modules/subsystems/subsystems_test.go b/modules/subsystems/subsystems_test.go index 23949f2..ab632e5 100644 --- a/modules/subsystems/subsystems_test.go +++ b/modules/subsystems/subsystems_test.go @@ -120,5 +120,5 @@ func TestSubsystems(t *testing.T) { //nolint:paralleltest // Too much interferen } // clean up and exit - os.RemoveAll(tmpDir) + _ = os.RemoveAll(tmpDir) } diff --git a/rng/test/main.go b/rng/test/main.go index ad5d7be..acaabf6 100644 --- a/rng/test/main.go +++ b/rng/test/main.go @@ -58,7 +58,7 @@ func prep() error { } var err error - outputFile, err = os.OpenFile(os.Args[2], os.O_CREATE|os.O_WRONLY, 0o0644) + outputFile, err = os.OpenFile(os.Args[2], os.O_CREATE|os.O_WRONLY, 0o0644) //nolint:gosec if err != nil { return fmt.Errorf("failed to open output file: %w", err) } @@ -106,13 +106,13 @@ func fortuna(_ context.Context) error { bytesWritten += 64 if bytesWritten%1024 == 0 { - os.Stderr.WriteString(".") + _, _ = os.Stderr.WriteString(".") } if bytesWritten%65536 == 0 { fmt.Fprintf(os.Stderr, "\n%d bytes written\n", bytesWritten) } if bytesWritten >= outputSize { - os.Stderr.WriteString("\n") + _, _ = os.Stderr.WriteString("\n") break } } @@ -145,7 +145,7 @@ func tickfeeder(ctx context.Context) error { } bytesWritten += 8 if bytesWritten%1024 == 0 { - os.Stderr.WriteString(".") + _, _ = os.Stderr.WriteString(".") } if bytesWritten%65536 == 0 { fmt.Fprintf(os.Stderr, "\n%d bytes written\n", bytesWritten) @@ -154,7 +154,7 @@ func tickfeeder(ctx context.Context) error { } if bytesWritten >= outputSize { - os.Stderr.WriteString("\n") + _, _ = os.Stderr.WriteString("\n") break } } diff --git a/template/module_test.go b/template/module_test.go index 6e76eb9..30c9bb8 100644 --- a/template/module_test.go +++ b/template/module_test.go @@ -50,6 +50,6 @@ func TestMain(m *testing.M) { fmt.Fprintf(os.Stderr, "failed to cleanly shutdown test: %s\n", err) } // clean up and exit - os.RemoveAll(tmpDir) + _ = os.RemoveAll(tmpDir) os.Exit(exitCode) } diff --git a/test b/test index fd0f3ee..a9afaf0 100755 --- a/test +++ b/test @@ -104,8 +104,6 @@ fi # install if [[ $install -eq 1 ]]; then echo "installing dependencies..." - echo "$ go get -u golang.org/x/lint/golint" - go get -u golang.org/x/lint/golint # TODO: update golangci-lint version regularly echo "$ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.0" curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.0 @@ -122,12 +120,6 @@ if [[ $testonly -eq 0 ]]; then echo "gofmt command not found" exit 1 fi - if [[ $(which golint) == "" ]]; then - echo "golint command not found" - echo "install with: go get -u golang.org/x/lint/golint" - echo "or run: ./test install" - exit 1 - fi if [[ $(which golangci-lint) == "" ]]; then echo "golangci-lint command not found" echo "install with: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin vX.Y.Z" @@ -160,7 +152,6 @@ for package in $packages; do echo "" echo $package if [[ $testonly -eq 0 ]]; then - run golint -set_exit_status -min_confidence 1.0 $package run go vet $package run golangci-lint run $packagename fi diff --git a/updater/fetch.go b/updater/fetch.go index e6942a9..adad517 100644 --- a/updater/fetch.go +++ b/updater/fetch.go @@ -45,7 +45,9 @@ func (reg *ResourceRegistry) fetchFile(ctx context.Context, client *http.Client, if err != nil { return err } - defer resp.Body.Close() + defer func() { + _ = resp.Body.Close() + }() // download and write file n, err := io.Copy(atomicFile, resp.Body) @@ -64,7 +66,7 @@ func (reg *ResourceRegistry) fetchFile(ctx context.Context, client *http.Client, // set permissions if !onWindows { // TODO: only set executable files to 0755, set other to 0644 - err = os.Chmod(rv.storagePath(), 0o0755) + err = os.Chmod(rv.storagePath(), 0o0755) //nolint:gosec // See TODO above. if err != nil { log.Warningf("%s: failed to set permissions on downloaded file %s: %s", reg.Name, rv.storagePath(), err) } @@ -89,7 +91,9 @@ func (reg *ResourceRegistry) fetchData(ctx context.Context, client *http.Client, if err != nil { return nil, err } - defer resp.Body.Close() + defer func() { + _ = resp.Body.Close() + }() // download and write file buf := bytes.NewBuffer(make([]byte, 0, resp.ContentLength)) @@ -135,7 +139,7 @@ func (reg *ResourceRegistry) makeRequest(ctx context.Context, client *http.Clien // check return code if resp.StatusCode != http.StatusOK { - resp.Body.Close() + _ = resp.Body.Close() return nil, "", fmt.Errorf("failed to fetch %q: %d %s", downloadURL, resp.StatusCode, resp.Status) } diff --git a/updater/file.go b/updater/file.go index b879e3a..8c78978 100644 --- a/updater/file.go +++ b/updater/file.go @@ -92,7 +92,9 @@ func (file *File) Unpack(suffix string, unpacker Unpacker) (string, error) { if err != nil { return "", err } - defer f.Close() + defer func() { + _ = f.Close() + }() r, err := unpacker(f) if err != nil { diff --git a/updater/registry_test.go b/updater/registry_test.go index 2ef1b78..d25ef87 100644 --- a/updater/registry_test.go +++ b/updater/registry_test.go @@ -31,6 +31,6 @@ func TestMain(m *testing.M) { ret := m.Run() // teardown - os.RemoveAll(tmpDir) + _ = os.RemoveAll(tmpDir) os.Exit(ret) } diff --git a/updater/unpacking.go b/updater/unpacking.go index 5b19b86..00283bc 100644 --- a/updater/unpacking.go +++ b/updater/unpacking.go @@ -117,7 +117,9 @@ func (res *Resource) unpackZipArchive() (err error) { if err != nil { return } - defer archiveReader.Close() + defer func() { + _ = archiveReader.Close() + }() // Save all files to the tmp dir. for _, file := range archiveReader.File { @@ -161,14 +163,18 @@ func copyFromZipArchive(archiveFile *zip.File, dstPath string) error { if err != nil { return err } - defer fileReader.Close() + defer func() { + _ = fileReader.Close() + }() // Open destination file for writing. dstFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, archiveFile.Mode()) if err != nil { return err } - defer dstFile.Close() + defer func() { + _ = dstFile.Close() + }() // Copy full file from archive to dst. if _, err := io.CopyN(dstFile, fileReader, MaxUnpackSize); err != nil { diff --git a/utils/atomic.go b/utils/atomic.go index cd1224d..cde4a1a 100644 --- a/utils/atomic.go +++ b/utils/atomic.go @@ -74,7 +74,9 @@ func CopyFileAtomic(dest string, src string, opts *AtomicFileOptions) error { if err != nil { return err } - defer f.Close() + defer func() { + _ = f.Close() + }() return CreateAtomic(dest, f, opts) } diff --git a/utils/debug/debug.go b/utils/debug/debug.go index a28146b..bd74e2b 100644 --- a/utils/debug/debug.go +++ b/utils/debug/debug.go @@ -51,37 +51,37 @@ func addContentLineBreaks(flags InfoFlag) bool { func (di *Info) AddSection(name string, flags InfoFlag, content ...string) { // Check if we need a spacer. if di.Len() > 0 { - di.WriteString("\n\n") + _, _ = di.WriteString("\n\n") } // Write section to buffer. // Write section header. if di.Style == "github" { - di.WriteString(fmt.Sprintf("
\n%s\n\n", name)) + _, _ = di.WriteString(fmt.Sprintf("
\n%s\n\n", name)) } else { - di.WriteString(fmt.Sprintf("**%s**:\n\n", name)) + _, _ = di.WriteString(fmt.Sprintf("**%s**:\n\n", name)) } // Write section content. if useCodeSection(flags) { // Write code header: Needs one empty line between previous data. - di.WriteString("```\n") + _, _ = di.WriteString("```\n") } for i, part := range content { - di.WriteString(part) + _, _ = di.WriteString(part) if addContentLineBreaks(flags) && i < len(content)-1 { - di.WriteString("\n") + _, _ = di.WriteString("\n") } } if useCodeSection(flags) { // Write code footer: Needs one empty line between next data. - di.WriteString("\n```\n") + _, _ = di.WriteString("\n```\n") } // Write section header. if di.Style == "github" { - di.WriteString("\n
") + _, _ = di.WriteString("\n
") } } diff --git a/utils/renameio/tempfile.go b/utils/renameio/tempfile.go index acfad61..8364d64 100644 --- a/utils/renameio/tempfile.go +++ b/utils/renameio/tempfile.go @@ -38,17 +38,19 @@ func tempDir(dir, dest string) string { cleanup := true defer func() { if cleanup { - os.Remove(testsrc.Name()) + _ = os.Remove(testsrc.Name()) } }() - testsrc.Close() + _ = testsrc.Close() testdest, err := ioutil.TempFile(filepath.Dir(dest), "."+filepath.Base(dest)) if err != nil { return fallback } - defer os.Remove(testdest.Name()) - testdest.Close() + defer func() { + _ = os.Remove(testdest.Name()) + }() + _ = testdest.Close() if err := os.Rename(testsrc.Name(), testdest.Name()); err != nil { return fallback @@ -149,7 +151,7 @@ func Symlink(oldname, newname string) error { cleanup := true defer func() { if cleanup { - os.RemoveAll(d) + _ = os.RemoveAll(d) } }() diff --git a/utils/renameio/tempfile_linux_test.go b/utils/renameio/tempfile_linux_test.go index bf569ea..2077709 100644 --- a/utils/renameio/tempfile_linux_test.go +++ b/utils/renameio/tempfile_linux_test.go @@ -15,11 +15,11 @@ func TestTempDir(t *testing.T) { if tmpdir, ok := os.LookupEnv("TMPDIR"); ok { t.Cleanup(func() { - os.Setenv("TMPDIR", tmpdir) // restore + _ = os.Setenv("TMPDIR", tmpdir) // restore }) } else { t.Cleanup(func() { - os.Unsetenv("TMPDIR") // restore + _ = os.Unsetenv("TMPDIR") // restore }) } @@ -28,7 +28,7 @@ func TestTempDir(t *testing.T) { t.Fatal(err) } t.Cleanup(func() { - os.RemoveAll(mount1) + _ = os.RemoveAll(mount1) }) mount2, err := ioutil.TempDir("", "test-renameio-testtempdir2") @@ -36,7 +36,7 @@ func TestTempDir(t *testing.T) { t.Fatal(err) } t.Cleanup(func() { - os.RemoveAll(mount2) + _ = os.RemoveAll(mount2) }) if err := syscall.Mount("tmpfs", mount1, "tmpfs", 0, ""); err != nil { @@ -103,9 +103,9 @@ func TestTempDir(t *testing.T) { t.Parallel() if testCase.TMPDIR == "" { - os.Unsetenv("TMPDIR") + _ = os.Unsetenv("TMPDIR") } else { - os.Setenv("TMPDIR", testCase.TMPDIR) + _ = os.Setenv("TMPDIR", testCase.TMPDIR) } if got := tempDir(testCase.dir, testCase.path); got != testCase.want { diff --git a/utils/renameio/writefile_test.go b/utils/renameio/writefile_test.go index 92872e7..5c04651 100644 --- a/utils/renameio/writefile_test.go +++ b/utils/renameio/writefile_test.go @@ -17,7 +17,9 @@ func TestWriteFile(t *testing.T) { if err != nil { t.Fatal(err) } - defer os.RemoveAll(d) + defer func() { + _ = os.RemoveAll(d) + }() filename := filepath.Join(d, "hello.sh")