Repository: pion/sctp
Pull request #149 (2020-09-17 03:22:02)

Update CI configs to v0.4.7
Update lint scripts and CI configs.

codecov[bot]: # [Codecov](https://codecov.io/gh/pion/sctp/pull/149?src=pr&el=h1) Report
> Merging [#149](https://codecov.io/gh/pion/sctp/pull/149?src=pr&el=desc) into [master](https://codecov.io/gh/pion/sctp/commit/7a427a972af5c48ca50ef5f5b8f21d03bf5dc57c?el=desc) will **decrease** coverage by `9.27%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/pion/sctp/pull/149/graphs/tree.svg?width=650&height=150&src=pr&token=AB8S3U6xR9)](https://codecov.io/gh/pion/sctp/pull/149?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #149      +/-   ##
==========================================
- Coverage   79.16%   69.88%   -9.28%     
==========================================
  Files          43       43              
  Lines        2813     2813              
==========================================
- Hits         2227     1966     -261     
- Misses        451      686     +235     
- Partials      135      161      +26     
```

| Flag | Coverage Δ | |
|---|---|---|
| #go | `?` | |
| #wasm | `69.88% <ø> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/pion/sctp/pull/149?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [association\_stats.go](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree#diff-YXNzb2NpYXRpb25fc3RhdHMuZ28=) | `69.23% <0.00%> (-30.77%)` | :arrow_down: |
| [error\_cause\_protocol\_violation.go](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree#diff-ZXJyb3JfY2F1c2VfcHJvdG9jb2xfdmlvbGF0aW9uLmdv) | `63.63% <0.00%> (-18.19%)` | :arrow_down: |
| [association.go](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree#diff-YXNzb2NpYXRpb24uZ28=) | `66.25% <0.00%> (-17.01%)` | :arrow_down: |
| [stream.go](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree#diff-c3RyZWFtLmdv) | `77.38% <0.00%> (-15.48%)` | :arrow_down: |
| [chunk\_forward\_tsn.go](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree#diff-Y2h1bmtfZm9yd2FyZF90c24uZ28=) | `80.85% <0.00%> (-14.90%)` | :arrow_down: |
| [error\_cause\_header.go](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree#diff-ZXJyb3JfY2F1c2VfaGVhZGVyLmdv) | `89.47% <0.00%> (-10.53%)` | :arrow_down: |
| [error\_cause.go](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree#diff-ZXJyb3JfY2F1c2UuZ28=) | `24.44% <0.00%> (-8.89%)` | :arrow_down: |
| [rtx\_timer.go](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree#diff-cnR4X3RpbWVyLmdv) | `89.77% <0.00%> (-7.96%)` | :arrow_down: |
| [chunk\_payload\_data.go](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree#diff-Y2h1bmtfcGF5bG9hZF9kYXRhLmdv) | `62.12% <0.00%> (-7.58%)` | :arrow_down: |
| [chunk\_abort.go](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree#diff-Y2h1bmtfYWJvcnQuZ28=) | `53.12% <0.00%> (-6.25%)` | :arrow_down: |
| ... and [3 more](https://codecov.io/gh/pion/sctp/pull/149/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pion/sctp/pull/149?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pion/sctp/pull/149?src=pr&el=footer). Last update [7a427a9...d3fe55c](https://codecov.io/gh/pion/sctp/pull/149?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

scorpionknifes: I'm taking this one.
scorpionknifes: I'm looking at ```chunk_abort.go``` and ```chunk_error.go```, these two files seems to be the same (dupl). I'm wondering if there is any way to define the two struct without dupl. Maybe this is something we can fix this after generics comes out in golang.

Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 570f17b..4213697 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -3,6 +3,80 @@ linters-settings:
     check-shadowing: true
   misspell:
     locale: US
+  exhaustive:
+    default-signifies-exhaustive: true
+
+linters:
+  enable:
+    - asciicheck       # Simple linter to check that your code does not contain non-ASCII identifiers
+    - bodyclose        # checks whether HTTP response body is closed successfully
+    - deadcode         # Finds unused code
+    - depguard         # Go linter that checks if package imports are in a list of acceptable packages
+    - dogsled          # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
+    - dupl             # Tool for code clone detection
+    - errcheck         # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
+    - exhaustive       # check exhaustiveness of enum switch statements
+    - exportloopref    # checks for pointers to enclosing loop variables
+    - gci              # Gci control golang package import order and make it always deterministic.
+    - gochecknoglobals # Checks that no globals are present in Go code
+    - gochecknoinits   # Checks that no init functions are present in Go code
+    - gocognit         # Computes and checks the cognitive complexity of functions
+    - goconst          # Finds repeated strings that could be replaced by a constant
+    - gocritic         # The most opinionated Go source code linter
+    - godox            # Tool for detection of FIXME, TODO and other comment keywords
+    - goerr113         # Golang linter to check the errors handling expressions
+    - gofmt            # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
+    - gofumpt          # Gofumpt checks whether code was gofumpt-ed.
+    - goheader         # Checks is file header matches to pattern
+    - goimports        # Goimports does everything that gofmt does. Additionally it checks unused imports
+    - golint           # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
+    - gomodguard       # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
+    - goprintffuncname # Checks that printf-like functions are named with `f` at the end
+    - gosec            # Inspects source code for security problems
+    - gosimple         # Linter for Go source code that specializes in simplifying a code
+    - govet            # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
+    - ineffassign      # Detects when assignments to existing variables are not used
+    - misspell         # Finds commonly misspelled English words in comments
+    - nakedret         # Finds naked returns in functions greater than a specified function length
+    - noctx            # noctx finds sending http request without context.Context
+    - scopelint        # Scopelint checks for unpinned variables in go programs
+    - staticcheck      # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
+    - structcheck      # Finds unused struct fields
+    - stylecheck       # Stylecheck is a replacement for golint
+    - typecheck        # Like the front-end of a Go compiler, parses and type-checks Go code
+    - unconvert        # Remove unnecessary type conversions
+    - unparam          # Reports unused function parameters
+    - unused           # Checks Go code for unused constants, variables, functions and types
+    - varcheck         # Finds unused global variables and constants
+    - whitespace       # Tool for detection of leading and trailing whitespace
+  disable:
+    - funlen           # Tool for detection of long functions
+    - gocyclo          # Computes and checks the cyclomatic complexity of functions
+    - godot            # Check if comments end in a period
+    - gomnd            # An analyzer to detect magic numbers.
+    - lll              # Reports long lines
+    - maligned         # Tool to detect Go structs that would take less memory if their fields were sorted
+    - nestif           # Reports deeply nested if statements
+    - nlreturn         # nlreturn checks for a new line before return and branch statements to increase code clarity
+    - nolintlint       # Reports ill-formed or insufficient nolint directives
+    - prealloc         # Finds slice declarations that could potentially be preallocated
+    - rowserrcheck     # checks whether Err of rows is checked successfully
+    - sqlclosecheck    # Checks that sql.Rows and sql.Stmt are closed.
+    - testpackage      # linter that makes you use a separate _test package
+    - wsl              # Whitespace Linter - Forces you to use empty lines!
+
+issues:
+  exclude-rules:
+    # Allow complex tests, better to be self contained
+    - path: _test\.go
+      linters:
+        - gocognit
+
+    # Allow complex main function in examples
+    - path: examples
+      text: "of func `main` is high"
+      linters:
+        - gocognit
 
 run:
   skip-dirs-use-default: false
diff --git a/README.md b/README.md
index d093edb..18b5693 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,7 @@ Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contribu
 * [Lukas Herman](https://github.com/lherman-cs)
 * [Luke Curley](https://github.com/kixelated) - *Performance*
 * [Aaron France](https://github.com/AeroNotix)
+* [ZHENK](https://github.com/scorpionknifes)
 
 ### License
 MIT License - see [LICENSE](LICENSE) for full text
diff --git a/association.go b/association.go
index 096659b..1393cb8 100644
--- a/association.go
+++ b/association.go
@@ -16,7 +16,10 @@ import (
 )
 
 // Use global random generator to properly seed by crypto grade random.
-var globalMathRandomGenerator = randutil.NewMathRandomGenerator()
+var (
+	globalMathRandomGenerator = randutil.NewMathRandomGenerator() // nolint:gochecknoglobals
+	errChunk                  = errors.New("Abort chunk, with following errors")
+)
 
 const (
 	receiveMTU            uint32 = 8192 // MTU for inbound packet (from DTLS)
@@ -338,8 +341,8 @@ func (a *Association) sendInit() error {
 
 	outbound := &packet{}
 	outbound.verificationTag = a.peerVerificationTag
-	a.sourcePort = 5000      // TODO: Spec??
-	a.destinationPort = 5000 // TODO: Spec??
+	a.sourcePort = 5000      // Spec??
+	a.destinationPort = 5000 // Spec??
 	outbound.sourcePort = a.sourcePort
 	outbound.destinationPort = a.destinationPort
 
@@ -375,7 +378,6 @@ func (a *Association) sendCookieEcho() error {
 func (a *Association) Close() error {
 	a.log.Debugf("[%s] closing association..", a.name)
 
-	// TODO: shutdown sequence
 	a.setState(closed)
 
 	err := a.netConn.Close()
@@ -510,7 +512,7 @@ func (a *Association) handleInbound(raw []byte) error {
 		return nil
 	}
 
-	a.handleChunkStart(p)
+	a.handleChunkStart()
 
 	for _, c := range p.chunks {
 		if err := a.handleChunk(p, c); err != nil {
@@ -518,7 +520,7 @@ func (a *Association) handleInbound(raw []byte) error {
 		}
 	}
 
-	a.handleChunkEnd(p)
+	a.handleChunkEnd()
 
 	return nil
 }
@@ -742,7 +744,7 @@ func checkPacket(p *packet) error {
 
 	// Check values on the packet that are specific to a particular chunk type
 	for _, c := range p.chunks {
-		switch c.(type) {
+		switch c.(type) { // nolint:gocritic
 		case *chunkInit:
 			// An INIT or INIT ACK chunk MUST NOT be bundled with any other chunk.
 			// They MUST be the only chunks present in the SCTP packets that carry
@@ -811,6 +813,7 @@ func (a *Association) BytesReceived() uint64 {
 }
 
 func setSupportedExtensions(init *chunkInitCommon) {
+	// nolint:godox
 	// TODO RFC5061 https://tools.ietf.org/html/rfc6525#section-5.2
 	// An implementation supporting this (Supported Extensions Parameter)
 	// extension MUST list the ASCONF, the ASCONF-ACK, and the AUTH chunks
@@ -852,7 +855,7 @@ func (a *Association) handleInit(p *packet, i *chunkInit) ([]*packet, error) {
 	a.peerLastTSN = i.initialTSN - 1
 
 	for _, param := range i.params {
-		switch v := param.(type) {
+		switch v := param.(type) { // nolint:gocritic
 		case *paramSupportedExtensions:
 			for _, t := range v.ChunkTypes {
 				if t == ctForwardTSN {
@@ -1025,7 +1028,7 @@ func (a *Association) handleCookieEcho(c *chunkCookieEcho) []*packet {
 }
 
 // The caller should hold the lock.
-func (a *Association) handleCookieAck() []*packet {
+func (a *Association) handleCookieAck() {
 	state := a.getState()
 	a.log.Debugf("[%s] COOKIE-ACK received in state '%s'", a.name, getAssociationStateString(state))
 	if state != cookieEchoed {
@@ -1033,7 +1036,7 @@ func (a *Association) handleCookieAck() []*packet {
 		// 5.2.5.  Handle Duplicate COOKIE-ACK.
 		//   At any state other than COOKIE-ECHOED, an endpoint should silently
 		//   discard a received COOKIE ACK chunk.
-		return nil
+		return
 	}
 
 	a.t1Cookie.stop()
@@ -1041,7 +1044,6 @@ func (a *Association) handleCookieAck() []*packet {
 
 	a.setState(established)
 	a.handshakeCompletedCh <- nil
-	return nil
 }
 
 // The caller should hold the lock.
@@ -1202,7 +1204,7 @@ func (a *Association) getOrCreateStream(streamIdentifier uint16) *Stream {
 }
 
 // The caller should hold the lock.
-func (a *Association) processSelectiveAck(d *chunkSelectiveAck) (map[uint16]int, uint32, error) {
+func (a *Association) processSelectiveAck(d *chunkSelectiveAck) (map[uint16]int, uint32, error) { // nolint:gocognit
 	bytesAckedPerStream := map[uint16]int{}
 
 	// New ack point, so pop all ACKed packets from inflightQueue
@@ -1328,7 +1330,7 @@ func (a *Association) onCumulativeTSNAckPointAdvanced(totalBytesAcked int) {
 		if !a.inFastRecovery &&
 			a.pendingQueue.size() > 0 {
 			a.cwnd += min32(uint32(totalBytesAcked), a.cwnd) // TCP way
-			//a.cwnd += min32(uint32(totalBytesAcked), a.mtu) // SCTP way (slow)
+			// a.cwnd += min32(uint32(totalBytesAcked), a.mtu) // SCTP way (slow)
 			a.log.Tracef("[%s] updated cwnd=%d ssthresh=%d acked=%d (SS)",
 				a.name, a.cwnd, a.ssthresh, totalBytesAcked)
 		} else {
@@ -1544,11 +1546,9 @@ func (a *Association) createForwardTSN() *chunkForwardTSN {
 		ssn, ok := streamMap[c.streamIdentifier]
 		if !ok {
 			streamMap[c.streamIdentifier] = c.streamSequenceNumber
-		} else {
+		} else if sna16LT(ssn, c.streamSequenceNumber) {
 			// to report only once with greatest SSN
-			if sna16LT(ssn, c.streamSequenceNumber) {
-				streamMap[c.streamIdentifier] = c.streamSequenceNumber
-			}
+			streamMap[c.streamIdentifier] = c.streamSequenceNumber
 		}
 	}
 
@@ -1664,7 +1664,7 @@ func (a *Association) handleForwardTSN(c *chunkForwardTSN) []*packet {
 	// from the reassemblyQueue.
 	for _, forwarded := range c.streams {
 		if s, ok := a.streams[forwarded.identifier]; ok {
-			s.handleForwardTSNForOrdered(c.newCumulativeTSN, forwarded.sequence)
+			s.handleForwardTSNForOrdered(forwarded.sequence)
 		}
 	}
 
@@ -1706,7 +1706,6 @@ func (a *Association) sendResetRequest(streamIdentifier uint16) error {
 
 // The caller should hold the lock.
 func (a *Association) handleReconfigParam(raw param) (*packet, error) {
-	// TODO: Check RSN
 	switch p := raw.(type) {
 	case *paramOutgoingResetRequest:
 		a.reconfigRequests[p.reconfigRequestSequenceNumber] = p
@@ -2002,7 +2001,7 @@ func pack(p *packet) []*packet {
 	return []*packet{p}
 }
 
-func (a *Association) handleChunkStart(p *packet) {
+func (a *Association) handleChunkStart() {
 	a.lock.Lock()
 	defer a.lock.Unlock()
 
@@ -2010,7 +2009,7 @@ func (a *Association) handleChunkStart(p *packet) {
 	a.immediateAckTriggered = false
 }
 
-func (a *Association) handleChunkEnd(p *packet) {
+func (a *Association) handleChunkEnd() {
 	a.lock.Lock()
 	defer a.lock.Unlock()
 
@@ -2050,7 +2049,7 @@ func (a *Association) handleChunk(p *packet, c chunk) error {
 		for _, e := range c.errorCauses {
 			errStr += fmt.Sprintf("(%s)", e)
 		}
-		return fmt.Errorf("[%s] Abort chunk, with following errors: %s", a.name, errStr)
+		return fmt.Errorf("[%s] %w: %s", a.name, errChunk, errStr)
 
 	case *chunkError:
 		var errStr string
@@ -2066,7 +2065,7 @@ func (a *Association) handleChunk(p *packet, c chunk) error {
 		packets = a.handleCookieEcho(c)
 
 	case *chunkCookieAck:
-		packets = a.handleCookieAck()
+		a.handleCookieAck()
 
 	case *chunkPayloadData:
 		packets = a.handleData(c)
diff --git a/chunk_abort.go b/chunk_abort.go
index caae026..9fd4692 100644
--- a/chunk_abort.go
+++ b/chunk_abort.go
@@ -1,4 +1,4 @@
-package sctp
+package sctp // nolint:dupl
 
 import (
 	"fmt"
@@ -57,6 +57,7 @@ func (a *chunkAbort) unmarshal(raw []byte) error {
 	}
 	return nil
 }
+
 func (a *chunkAbort) marshal() ([]byte, error) {
 	a.chunkHeader.typ = ctAbort
 	a.flags = 0x00
diff --git a/chunk_error.go b/chunk_error.go
index e5122b9..eb29324 100644
--- a/chunk_error.go
+++ b/chunk_error.go
@@ -1,4 +1,4 @@
-package sctp
+package sctp // nolint:dupl
 
 import (
 	"fmt"
@@ -64,6 +64,7 @@ func (a *chunkError) unmarshal(raw []byte) error {
 	}
 	return nil
 }
+
 func (a *chunkError) marshal() ([]byte, error) {
 	a.chunkHeader.typ = ctError
 	a.flags = 0x00
diff --git a/chunk_forward_tsn.go b/chunk_forward_tsn.go
index b56287a..f6ff357 100644
--- a/chunk_forward_tsn.go
+++ b/chunk_forward_tsn.go
@@ -44,6 +44,8 @@ const (
 	forwardTSNStreamLength = 4
 )
 
+var errMarshalStreamFailed = errors.New("failed to marshal stream")
+
 func (c *chunkForwardTSN) unmarshal(raw []byte) error {
 	if err := c.chunkHeader.unmarshal(raw); err != nil {
 		return err
@@ -61,7 +63,7 @@ func (c *chunkForwardTSN) unmarshal(raw []byte) error {
 		s := chunkForwardTSNStream{}
 
 		if err := s.unmarshal(c.raw[offset:]); err != nil {
-			return fmt.Errorf("failed to unmarshal stream: %v", err)
+			return fmt.Errorf("failed to unmarshal stream: %w", err)
 		}
 
 		c.streams = append(c.streams, s)
@@ -80,7 +82,7 @@ func (c *chunkForwardTSN) marshal() ([]byte, error) {
 	for _, s := range c.streams {
 		b, err := s.marshal()
 		if err != nil {
-			return nil, fmt.Errorf("failed to marshal stream: %v", err)
+			return nil, fmt.Errorf("%w: %v", errMarshalStreamFailed, err)
 		}
 		out = append(out, b...)
 	}
@@ -133,7 +135,7 @@ func (s *chunkForwardTSNStream) unmarshal(raw []byte) error {
 	return nil
 }
 
-func (s *chunkForwardTSNStream) marshal() ([]byte, error) {
+func (s *chunkForwardTSNStream) marshal() ([]byte, error) { // nolint:unparam
 	out := make([]byte, forwardTSNStreamLength)
 
 	binary.BigEndian.PutUint16(out[0:], s.identifier)
diff --git a/chunk_init.go b/chunk_init.go
index b38b766..65b9b1a 100644
--- a/chunk_init.go
+++ b/chunk_init.go
@@ -1,4 +1,4 @@
-package sctp
+package sctp // nolint:dupl
 
 import (
 	"fmt"
diff --git a/chunk_init_ack.go b/chunk_init_ack.go
index 93af52c..551bcea 100644
--- a/chunk_init_ack.go
+++ b/chunk_init_ack.go
@@ -1,4 +1,4 @@
-package sctp
+package sctp // nolint:dupl
 
 import (
 	"fmt"
diff --git a/chunk_init_common.go b/chunk_init_common.go
index 948fbf6..f64be78 100644
--- a/chunk_init_common.go
+++ b/chunk_init_common.go
@@ -149,7 +149,7 @@ func (i chunkInitCommon) String() string {
 	)
 
 	for i, param := range i.params {
-		res = res + fmt.Sprintf("Param %d:\n %s", i, param)
+		res += fmt.Sprintf("Param %d:\n %s", i, param)
 	}
 	return res
 }
diff --git a/chunk_reconfig.go b/chunk_reconfig.go
index 88fa3a2..a53ad5e 100644
--- a/chunk_reconfig.go
+++ b/chunk_reconfig.go
@@ -83,6 +83,7 @@ func (c *chunkReconfig) marshal() ([]byte, error) {
 }
 
 func (c *chunkReconfig) check() (abort bool, err error) {
+	// nolint:godox
 	// TODO: check allowed combinations:
 	// https://tools.ietf.org/html/rfc6525#section-3.1
 	return true, nil
@@ -92,7 +93,7 @@ func (c *chunkReconfig) check() (abort bool, err error) {
 func (c *chunkReconfig) String() string {
 	res := fmt.Sprintf("Param A:\n %s", c.paramA)
 	if c.paramB != nil {
-		res = res + fmt.Sprintf("Param B:\n %s", c.paramB)
+		res += fmt.Sprintf("Param B:\n %s", c.paramB)
 	}
 	return res
 }
diff --git a/control_queue.go b/control_queue.go
index 0829cf4..7e13469 100644
--- a/control_queue.go
+++ b/control_queue.go
@@ -1,6 +1,5 @@
 package sctp
 
-////////////////////////////////////////////////////////////////////////////////
 // control queue
 
 type controlQueue struct {
diff --git a/examples/ping-pong/conn.go b/examples/ping-pong/conn.go
index a7b7bc8..8ecaf8e 100644
--- a/examples/ping-pong/conn.go
+++ b/examples/ping-pong/conn.go
@@ -11,7 +11,7 @@ import (
 // simply using the `Write` method. So, to make it work, `disconnectedPacketConn`
 // will infer the last packet that it reads as the reply address for `Write`
 
-type disconnectedPacketConn struct { //nolint: unused
+type disconnectedPacketConn struct { // nolint: unused
 	mu    sync.RWMutex
 	rAddr net.Addr
 	pConn net.PacketConn
diff --git a/examples/ping-pong/ping.go b/examples/ping-pong/ping.go
index aef6bc0..fd2796b 100644
--- a/examples/ping-pong/ping.go
+++ b/examples/ping-pong/ping.go
@@ -14,7 +14,7 @@ import (
 func main() {
 	conn, err := net.Dial("udp", "127.0.0.1:5678")
 	if err != nil {
-		log.Fatal(err)
+		log.Panic(err)
 	}
 	defer conn.Close()
 	fmt.Println("dialed udp ponger")
@@ -25,14 +25,14 @@ func main() {
 	}
 	a, err := sctp.Client(config)
 	if err != nil {
-		log.Fatal(err)
+		log.Panic(err)
 	}
 	defer a.Close()
 	fmt.Println("created a client")
 
 	stream, err := a.OpenStream(0, sctp.PayloadTypeWebRTCString)
 	if err != nil {
-		log.Fatal(err)
+		log.Panic(err)
 	}
 	defer stream.Close()
 	fmt.Println("opened a stream")
@@ -46,7 +46,7 @@ func main() {
 			pingMsg := fmt.Sprintf("ping %d", pingSeqNum)
 			_, err = stream.Write([]byte(pingMsg))
 			if err != nil {
-				log.Fatal(err)
+				log.Panic(err)
 			}
 			fmt.Println("sent:", pingMsg)
 			pingSeqNum++
@@ -57,7 +57,7 @@ func main() {
 		buff := make([]byte, 1024)
 		_, err = stream.Read(buff)
 		if err != nil {
-			log.Fatal(err)
+			log.Panic(err)
 		}
 		pongMsg := string(buff)
 		fmt.Println("received:", pongMsg)
diff --git a/examples/ping-pong/pong.go b/examples/ping-pong/pong.go
index cf63e2c..1616fa5 100644
--- a/examples/ping-pong/pong.go
+++ b/examples/ping-pong/pong.go
@@ -20,7 +20,7 @@ func main() {
 
 	conn, err := net.ListenUDP("udp", &addr)
 	if err != nil {
-		log.Fatal(err)
+		log.Panic(err)
 	}
 	defer conn.Close()
 	fmt.Println("created a udp listener")
@@ -31,14 +31,14 @@ func main() {
 	}
 	a, err := sctp.Server(config)
 	if err != nil {
-		log.Fatal(err)
+		log.Panic(err)
 	}
 	defer a.Close()
 	fmt.Println("created a server")
 
 	stream, err := a.AcceptStream()
 	if err != nil {
-		log.Fatal(err)
+		log.Panic(err)
 	}
 	defer stream.Close()
 	fmt.Println("accepted a stream")
@@ -50,7 +50,7 @@ func main() {
 		buff := make([]byte, 1024)
 		_, err = stream.Read(buff)
 		if err != nil {
-			log.Fatal(err)
+			log.Panic(err)
 		}
 		pingMsg := string(buff)
 		fmt.Println("received:", pingMsg)
@@ -59,7 +59,7 @@ func main() {
 		pongMsg := fmt.Sprintf("pong %d", pongSeqNum)
 		_, err = stream.Write([]byte(pongMsg))
 		if err != nil {
-			log.Fatal(err)
+			log.Panic(err)
 		}
 		fmt.Println("sent:", pongMsg)
 
diff --git a/packet.go b/packet.go
index 0784c92..dcc650b 100644
--- a/packet.go
+++ b/packet.go
@@ -9,11 +9,11 @@ import (
 )
 
 // Create the crc32 table we'll use for the checksum
-var castagnoliTable = crc32.MakeTable(crc32.Castagnoli)
+var castagnoliTable = crc32.MakeTable(crc32.Castagnoli) // nolint:gochecknoglobals
 
 // Allocate and zero this data once.
 // We need to use it for the checksum and don't want to allocate/clear each time.
-var fourZeroes [4]byte
+var fourZeroes [4]byte // nolint:gochecknoglobals
 
 /*
 Packet represents an SCTP packet, defined in https://tools.ietf.org/html/rfc4960#section-3
@@ -172,7 +172,7 @@ func (p *packet) String() string {
 		p.verificationTag,
 	)
 	for i, chunk := range p.chunks {
-		res = res + fmt.Sprintf("Chunk %d:\n %s", i, chunk)
+		res += fmt.Sprintf("Chunk %d:\n %s", i, chunk)
 	}
 	return res
 }
diff --git a/param.go b/param.go
index a06bc22..08e46d1 100644
--- a/param.go
+++ b/param.go
@@ -29,6 +29,7 @@ func buildParam(t paramType, rawParam []byte) (param, error) {
 		return (&paramOutgoingResetRequest{}).unmarshal(rawParam)
 	case reconfigResp:
 		return (&paramReconfigResponse{}).unmarshal(rawParam)
+	default:
+		return nil, errors.Errorf("Unhandled ParamType %v", t)
 	}
-	return nil, errors.Errorf("Unhandled ParamType %v", t)
 }
diff --git a/param_outgoing_reset_request.go b/param_outgoing_reset_request.go
index a213f24..ceae178 100644
--- a/param_outgoing_reset_request.go
+++ b/param_outgoing_reset_request.go
@@ -2,7 +2,6 @@ package sctp
 
 import (
 	"encoding/binary"
-
 	"errors"
 )
 
@@ -53,6 +52,8 @@ type paramOutgoingResetRequest struct {
 	streamIdentifiers []uint16
 }
 
+var errSSNResetRequestParamTooShort = errors.New("outgoing SSN reset request parameter too short")
+
 func (r *paramOutgoingResetRequest) marshal() ([]byte, error) {
 	r.typ = outSSNResetReq
 	r.raw = make([]byte, paramOutgoingResetRequestStreamIdentifiersOffset+2*len(r.streamIdentifiers))
@@ -71,7 +72,7 @@ func (r *paramOutgoingResetRequest) unmarshal(raw []byte) (param, error) {
 		return nil, err
 	}
 	if len(r.raw) < paramOutgoingResetRequestStreamIdentifiersOffset {
-		return nil, errors.New("outgoing SSN reset request parameter too short")
+		return nil, errSSNResetRequestParamTooShort
 	}
 	r.reconfigRequestSequenceNumber = binary.BigEndian.Uint32(r.raw)
 	r.reconfigResponseSequenceNumber = binary.BigEndian.Uint32(r.raw[4:])
diff --git a/param_reconfig_response.go b/param_reconfig_response.go
index 6e14d9e..d9eab55 100644
--- a/param_reconfig_response.go
+++ b/param_reconfig_response.go
@@ -2,9 +2,8 @@ package sctp
 
 import (
 	"encoding/binary"
-	"fmt"
-
 	"errors"
+	"fmt"
 )
 
 // This parameter is used by the receiver of a Re-configuration Request
@@ -46,6 +45,8 @@ const (
 	reconfigResultInProgress                    reconfigResult = 6
 )
 
+var errReconfigRespParamTooShort = errors.New("reconfig response parameter too short")
+
 func (t reconfigResult) String() string {
 	switch t {
 	case reconfigResultSuccessNOP:
@@ -82,7 +83,7 @@ func (r *paramReconfigResponse) unmarshal(raw []byte) (param, error) {
 		return nil, err
 	}
 	if len(r.raw) < 8 {
-		return nil, errors.New("reconfig response parameter too short")
+		return nil, errReconfigRespParamTooShort
 	}
 	r.reconfigResponseSequenceNumber = binary.BigEndian.Uint32(r.raw)
 	r.result = reconfigResult(binary.BigEndian.Uint32(r.raw[4:]))
diff --git a/pending_queue.go b/pending_queue.go
index 34ca27a..5f204d3 100644
--- a/pending_queue.go
+++ b/pending_queue.go
@@ -1,10 +1,9 @@
 package sctp
 
 import (
-	"fmt"
+	"github.com/pkg/errors"
 )
 
-////////////////////////////////////////////////////////////////////////////////
 // pendingBaseQueue
 
 type pendingBaseQueue struct {
@@ -39,7 +38,6 @@ func (q *pendingBaseQueue) size() int {
 	return len(q.queue)
 }
 
-////////////////////////////////////////////////////////////////////////////////
 // pendingQueue
 
 type pendingQueue struct {
@@ -50,6 +48,12 @@ type pendingQueue struct {
 	unorderedIsSelected bool
 }
 
+var (
+	errUnexpectedChuckPoppedUnordered = errors.New("unexpected chunk popped (unordered)")
+	errUnexpectedChuckPoppedOrdered   = errors.New("unexpected chunk popped (ordered)")
+	errUnexpectedQState               = errors.New("unexpected q state (should've been selected)")
+)
+
 func newPendingQueue() *pendingQueue {
 	return &pendingQueue{
 		unorderedQueue: newPendingBaseQueue(),
@@ -86,12 +90,12 @@ func (q *pendingQueue) pop(c *chunkPayloadData) error {
 		if q.unorderedIsSelected {
 			popped = q.unorderedQueue.pop()
 			if popped != c {
-				return fmt.Errorf("unexped chunk popped (unordered)")
+				return errUnexpectedChuckPoppedUnordered
 			}
 		} else {
 			popped = q.orderedQueue.pop()
 			if popped != c {
-				return fmt.Errorf("unexped chunk popped (ordered)")
+				return errUnexpectedChuckPoppedOrdered
 			}
 		}
 		if popped.endingFragment {
@@ -99,12 +103,12 @@ func (q *pendingQueue) pop(c *chunkPayloadData) error {
 		}
 	} else {
 		if !c.beginningFragment {
-			return fmt.Errorf("unexpected q state (should've been selected)")
+			return errUnexpectedQState
 		}
 		if c.unordered {
 			popped := q.unorderedQueue.pop()
 			if popped != c {
-				return fmt.Errorf("unexped chunk popped (unordered)")
+				return errUnexpectedChuckPoppedUnordered
 			}
 			if !popped.endingFragment {
 				q.selected = true
@@ -113,7 +117,7 @@ func (q *pendingQueue) pop(c *chunkPayloadData) error {
 		} else {
 			popped := q.orderedQueue.pop()
 			if popped != c {
-				return fmt.Errorf("unexped chunk popped (ordered)")
+				return errUnexpectedChuckPoppedOrdered
 			}
 			if !popped.endingFragment {
 				q.selected = true
diff --git a/reassembly_queue.go b/reassembly_queue.go
index 11456a2..f71d59c 100644
--- a/reassembly_queue.go
+++ b/reassembly_queue.go
@@ -1,10 +1,11 @@
 package sctp
 
 import (
-	"fmt"
 	"io"
 	"sort"
 	"sync/atomic"
+
+	"github.com/pkg/errors"
 )
 
 func sortChunksByTSN(a []*chunkPayloadData) {
@@ -105,6 +106,8 @@ type reassemblyQueue struct {
 	nBytes          uint64
 }
 
+var errTryAgain = errors.New("try again")
+
 func newReassemblyQueue(si uint16) *reassemblyQueue {
 	// From RFC 4960 Sec 6.5:
 	//   The Stream Sequence Number in all the streams MUST start from 0 when
@@ -251,24 +254,25 @@ func (r *reassemblyQueue) isReadable() bool {
 func (r *reassemblyQueue) read(buf []byte) (int, PayloadProtocolIdentifier, error) {
 	var cset *chunkSet
 	// Check unordered first
-	if len(r.unordered) > 0 {
+	switch {
+	case len(r.unordered) > 0:
 		cset = r.unordered[0]
 		r.unordered = r.unordered[1:]
-	} else if len(r.ordered) > 0 {
+	case len(r.ordered) > 0:
 		// Now, check ordered
 		cset = r.ordered[0]
 		if !cset.isComplete() {
-			return 0, 0, fmt.Errorf("try again")
+			return 0, 0, errTryAgain
 		}
 		if sna16GT(cset.ssn, r.nextSSN) {
-			return 0, 0, fmt.Errorf("try again")
+			return 0, 0, errTryAgain
 		}
 		r.ordered = r.ordered[1:]
 		if cset.ssn == r.nextSSN {
 			r.nextSSN++
 		}
-	} else {
-		return 0, 0, fmt.Errorf("try again")
+	default:
+		return 0, 0, errTryAgain
 	}
 
 	// Concat all fragments into the buffer
@@ -290,7 +294,7 @@ func (r *reassemblyQueue) read(buf []byte) (int, PayloadProtocolIdentifier, erro
 	return nWritten, ppi, err
 }
 
-func (r *reassemblyQueue) forwardTSNForOrdered(newCumulativeTSN uint32, lastSSN uint16) {
+func (r *reassemblyQueue) forwardTSNForOrdered(lastSSN uint16) {
 	// Use lastSSN to locate a chunkSet then remove it if the set has
 	// not been complete
 	keep := []*chunkSet{}
diff --git a/stream.go b/stream.go
index c628ce3..8a17b97 100644
--- a/stream.go
+++ b/stream.go
@@ -97,7 +97,7 @@ func (s *Stream) ReadSCTP(p []byte) (int, PayloadProtocolIdentifier, error) {
 		n, ppi, err := s.reassemblyQueue.read(p)
 		if err == nil {
 			return n, ppi, nil
-		} else if err == io.ErrShortBuffer {
+		} else if errors.Is(err, io.ErrShortBuffer) {
 			return 0, PayloadProtocolIdentifier(0), err
 		}
 
@@ -126,7 +126,7 @@ func (s *Stream) handleData(pd *chunkPayloadData) {
 	}
 }
 
-func (s *Stream) handleForwardTSNForOrdered(newCumulativeTSN uint32, ssn uint16) {
+func (s *Stream) handleForwardTSNForOrdered(ssn uint16) {
 	var readable bool
 
 	func() {
@@ -139,7 +139,7 @@ func (s *Stream) handleForwardTSNForOrdered(newCumulativeTSN uint32, ssn uint16)
 
 		// Remove all chunks older than or equal to the new TSN from
 		// the reassemblyQueue.
-		s.reassemblyQueue.forwardTSNForOrdered(newCumulativeTSN, ssn)
+		s.reassemblyQueue.forwardTSNForOrdered(ssn)
 		readable = s.reassemblyQueue.isReadable()
 	}()
 


Test patch:
diff --git a/association_test.go b/association_test.go
index 3b392a8..39a1b0c 100644
--- a/association_test.go
+++ b/association_test.go
@@ -5,7 +5,6 @@ package sctp
 import (
 	cryptoRand "crypto/rand"
 	"encoding/binary"
-	"fmt"
 	"io"
 	"math"
 	"math/rand"
@@ -18,9 +17,19 @@ import (
 
 	"github.com/pion/logging"
 	"github.com/pion/transport/test"
+	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
 
+var (
+	errHandshakeFailed       = errors.New("handshake failed")
+	errSINotMatch            = errors.New("SI should match")
+	errReadData              = errors.New("failed to read data")
+	errReceivedDataNot3Bytes = errors.New("received data must by 3 bytes")
+	errPPIUnexpected         = errors.New("unexpected ppi")
+	errReceivedDataMismatch  = errors.New("received data mismatch")
+)
+
 func TestAssocStressDuplex(t *testing.T) {
 	// Limit runtime in case of deadlocks
 	lim := test.TimeOut(time.Second * 20)
@@ -41,7 +50,7 @@ func stressDuplex(t *testing.T) {
 
 	defer stop(t)
 
-	// TODO: Increase once SCTP is more reliable in case of slow reader
+	// Need to Increase once SCTP is more reliable in case of slow reader
 	opt := test.Options{
 		MsgSize:  2048, // 65535,
 		MsgCount: 10,   // 1000,
@@ -231,8 +240,6 @@ func (c *dumbConn) SetWriteDeadline(t time.Time) error {
 	return nil
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
 func createNewAssociationPair(br *test.Bridge, ackMode int, recvBufSize uint32) (*Association, *Association, error) {
 	var a0, a1 *Association
 	var err0, err1 error
@@ -280,7 +287,7 @@ loop1:
 	}
 
 	if !a0handshakeDone || !a1handshakeDone {
-		return nil, nil, fmt.Errorf("handshake failed")
+		return nil, nil, errHandshakeFailed
 	}
 
 	if err0 != nil {
@@ -301,12 +308,12 @@ func closeAssociationPair(br *test.Bridge, a0, a1 *Association) {
 	close1Ch := make(chan bool)
 
 	go func() {
-		//nolint:errcheck,gosec
+		// nolint:errcheck,gosec
 		a0.Close()
 		close0Ch <- true
 	}()
 	go func() {
-		//nolint:errcheck,gosec
+		// nolint:errcheck,gosec
 		a1.Close()
 		close1Ch <- true
 	}()
@@ -368,7 +375,7 @@ func establishSessionPair(br *test.Bridge, a0, a1 *Association, si uint16) (*Str
 	}
 
 	if s0.streamIdentifier != s1.streamIdentifier {
-		return nil, nil, fmt.Errorf("SI should match")
+		return nil, nil, errSINotMatch
 	}
 
 	br.Process()
@@ -376,19 +383,19 @@ func establishSessionPair(br *test.Bridge, a0, a1 *Association, si uint16) (*Str
 	buf := make([]byte, 1024)
 	n, ppi, err := s1.ReadSCTP(buf)
 	if err != nil {
-		return nil, nil, fmt.Errorf("faild to read data")
+		return nil, nil, errReadData
 	}
 
 	if n != len(helloMsg) {
-		return nil, nil, fmt.Errorf("received data must by 3 bytes")
+		return nil, nil, errReceivedDataNot3Bytes
 	}
 
 	if ppi != PayloadTypeWebRTCDCEP {
-		return nil, nil, fmt.Errorf("unexpected ppi")
+		return nil, nil, errPPIUnexpected
 	}
 
 	if string(buf[:n]) != helloMsg {
-		return nil, nil, fmt.Errorf("received data mismatch")
+		return nil, nil, errReceivedDataMismatch
 	}
 
 	flushBuffers(br, a0, a1)
@@ -513,7 +520,7 @@ func TestAssocReliable(t *testing.T) {
 		closeAssociationPair(br, a0, a1)
 	})
 
-	t.Run("ordered fragmented then defragmented", func(t *testing.T) {
+	t.Run("ordered fragmented then defragmented", func(t *testing.T) { // nolint:dupl
 		lim := test.TimeOut(time.Second * 10)
 		defer lim.Stop()
 
@@ -554,7 +561,7 @@ func TestAssocReliable(t *testing.T) {
 		closeAssociationPair(br, a0, a1)
 	})
 
-	t.Run("unordered fragmented then defragmented", func(t *testing.T) {
+	t.Run("unordered fragmented then defragmented", func(t *testing.T) { // nolint:dupl
 		lim := test.TimeOut(time.Second * 10)
 		defer lim.Stop()
 
@@ -780,7 +787,7 @@ func TestAssocUnreliable(t *testing.T) {
 	rand.Seed(time.Now().UnixNano())
 	rand.Shuffle(len(sbuf), func(i, j int) { sbuf[i], sbuf[j] = sbuf[j], sbuf[i] })
 
-	t.Run("Rexmit ordered no fragment", func(t *testing.T) {
+	t.Run("Rexmit ordered no fragment", func(t *testing.T) { // nolint:dupl
 		lim := test.TimeOut(time.Second * 10)
 		defer lim.Stop()
 
@@ -890,7 +897,7 @@ func TestAssocUnreliable(t *testing.T) {
 		closeAssociationPair(br, a0, a1)
 	})
 
-	t.Run("Rexmit unordered no fragment", func(t *testing.T) {
+	t.Run("Rexmit unordered no fragment", func(t *testing.T) { // nolint:dupl
 		lim := test.TimeOut(time.Second * 10)
 		defer lim.Stop()
 
@@ -998,7 +1005,7 @@ func TestAssocUnreliable(t *testing.T) {
 		closeAssociationPair(br, a0, a1)
 	})
 
-	t.Run("Timed ordered", func(t *testing.T) {
+	t.Run("Timed ordered", func(t *testing.T) { // nolint:dupl
 		lim := test.TimeOut(time.Second * 10)
 		defer lim.Stop()
 
@@ -1035,7 +1042,7 @@ func TestAssocUnreliable(t *testing.T) {
 		}
 		assert.Equal(t, len(sbuf), n, "unexpected length of written data")
 
-		//br.Drop(0, 0, 1) // drop the first packet (second one should be sacked)
+		// br.Drop(0, 0, 1) // drop the first packet (second one should be sacked)
 		flushBuffers(br, a0, a1)
 
 		buf := make([]byte, 2000)
@@ -1187,13 +1194,14 @@ func TestCreateForwardTSN(t *testing.T) {
 		si1OK := false
 		si2OK := false
 		for _, s := range fwdtsn.streams {
-			if s.identifier == 1 {
+			switch s.identifier {
+			case 1:
 				assert.Equal(t, uint16(3), s.sequence, "ssn should be 3")
 				si1OK = true
-			} else if s.identifier == 2 {
+			case 2:
 				assert.Equal(t, uint16(1), s.sequence, "ssn should be 1")
 				si2OK = true
-			} else {
+			default:
 				assert.Fail(t, "unexpected stream indentifier")
 			}
 		}
@@ -1564,6 +1572,8 @@ func TestAssocT1CookieTimer(t *testing.T) {
 				switch c.(type) {
 				case *chunkCookieEcho:
 					return false // drop
+				default:
+					return true
 				}
 			}
 			return true
@@ -2233,6 +2243,7 @@ func newFakeEchoConn(errClose error) *fakeEchoConn {
 		errClose: errClose,
 	}
 }
+
 func (c *fakeEchoConn) Read(b []byte) (int, error) {
 	r, ok := <-c.echo
 	if ok {
@@ -2247,6 +2258,7 @@ func (c *fakeEchoConn) Read(b []byte) (int, error) {
 	}
 	return 0, io.EOF
 }
+
 func (c *fakeEchoConn) Write(b []byte) (int, error) {
 	c.mu.Lock()
 	defer c.mu.Unlock()
@@ -2259,6 +2271,7 @@ func (c *fakeEchoConn) Write(b []byte) (int, error) {
 	c.bytesSent += uint64(len(b))
 	return len(b), nil
 }
+
 func (c *fakeEchoConn) Close() error {
 	c.mu.Lock()
 	defer c.mu.Unlock()
diff --git a/chunk_forward_tsn_test.go b/chunk_forward_tsn_test.go
index 2643cd6..5c3b37b 100644
--- a/chunk_forward_tsn_test.go
+++ b/chunk_forward_tsn_test.go
@@ -6,13 +6,15 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-var testChunkForwardTSN = []byte{0xc0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x3}
+func testChunkForwardTSN() []byte {
+	return []byte{0xc0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x3}
+}
 
 func TestChunkForwardTSN_Success(t *testing.T) {
 	tt := []struct {
 		binary []byte
 	}{
-		{testChunkForwardTSN},
+		{testChunkForwardTSN()},
 		{[]byte{0xc0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x3, 0x0, 0x4, 0x0, 0x5}},
 		{[]byte{0xc0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x3, 0x0, 0x4, 0x0, 0x5, 0x0, 0x6, 0x0, 0x7}},
 	}
diff --git a/chunk_reconfig_test.go b/chunk_reconfig_test.go
index e2c348f..3deb2f0 100644
--- a/chunk_reconfig_test.go
+++ b/chunk_reconfig_test.go
@@ -10,11 +10,11 @@ func TestChunkReconfig_Success(t *testing.T) {
 	tt := []struct {
 		binary []byte
 	}{
-		{append([]byte{0x82, 0x0, 0x0, 0x1a}, testChunkReconfigParamA...)}, // Note: chunk trailing padding is added in packet.marshal
-		{append([]byte{0x82, 0x0, 0x0, 0x14}, testChunkReconfigParamB...)},
-		{append([]byte{0x82, 0x0, 0x0, 0x10}, testChunkReconfigResponce...)},
-		{append(append([]byte{0x82, 0x0, 0x0, 0x2c}, padByte(testChunkReconfigParamA, 2)...), testChunkReconfigParamB...)},
-		{append(append([]byte{0x82, 0x0, 0x0, 0x2a}, testChunkReconfigParamB...), testChunkReconfigParamA...)}, // Note: chunk trailing padding is added in packet.marshal
+		{append([]byte{0x82, 0x0, 0x0, 0x1a}, testChunkReconfigParamA()...)}, // Note: chunk trailing padding is added in packet.marshal
+		{append([]byte{0x82, 0x0, 0x0, 0x14}, testChunkReconfigParamB()...)},
+		{append([]byte{0x82, 0x0, 0x0, 0x10}, testChunkReconfigResponce()...)},
+		{append(append([]byte{0x82, 0x0, 0x0, 0x2c}, padByte(testChunkReconfigParamA(), 2)...), testChunkReconfigParamB()...)},
+		{append(append([]byte{0x82, 0x0, 0x0, 0x2a}, testChunkReconfigParamB()...), testChunkReconfigParamA()...)}, // Note: chunk trailing padding is added in packet.marshal
 	}
 
 	for i, tc := range tt {
@@ -40,7 +40,7 @@ func TestChunkReconfigUnmarshal_Failure(t *testing.T) {
 		{"chunk header to short", []byte{0x82}},
 		{"missing parse param type (A)", []byte{0x82, 0x0, 0x0, 0x4}},
 		{"wrong param (A)", []byte{0x82, 0x0, 0x0, 0x8, 0x0, 0xd, 0x0, 0x0}},
-		{"wrong param (B)", append(append([]byte{0x82, 0x0, 0x0, 0x18}, testChunkReconfigParamB...), []byte{0x0, 0xd, 0x0, 0x0}...)},
+		{"wrong param (B)", append(append([]byte{0x82, 0x0, 0x0, 0x18}, testChunkReconfigParamB()...), []byte{0x0, 0xd, 0x0, 0x0}...)},
 	}
 
 	for i, tc := range tt {
diff --git a/chunk_test.go b/chunk_test.go
index bb44c12..f33fde4 100644
--- a/chunk_test.go
+++ b/chunk_test.go
@@ -9,11 +9,13 @@ import (
 
 func TestInitChunk(t *testing.T) {
 	pkt := &packet{}
-	rawPkt := []byte{0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x81, 0x46, 0x9d, 0xfc, 0x01, 0x00, 0x00, 0x56, 0x55,
+	rawPkt := []byte{
+		0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x81, 0x46, 0x9d, 0xfc, 0x01, 0x00, 0x00, 0x56, 0x55,
 		0xb9, 0x64, 0xa5, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0xe8, 0x6d, 0x10, 0x30, 0xc0, 0x00, 0x00, 0x04, 0x80,
 		0x08, 0x00, 0x09, 0xc0, 0x0f, 0xc1, 0x80, 0x82, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x24, 0x9f, 0xeb, 0xbb, 0x5c, 0x50,
 		0xc9, 0xbf, 0x75, 0x9c, 0xb1, 0x2c, 0x57, 0x4f, 0xa4, 0x5a, 0x51, 0xba, 0x60, 0x17, 0x78, 0x27, 0x94, 0x5c, 0x31, 0xe6,
-		0x5d, 0x5b, 0x09, 0x47, 0xe2, 0x22, 0x06, 0x80, 0x04, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x06, 0x80, 0xc1, 0x00, 0x00}
+		0x5d, 0x5b, 0x09, 0x47, 0xe2, 0x22, 0x06, 0x80, 0x04, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x06, 0x80, 0xc1, 0x00, 0x00,
+	}
 	err := pkt.unmarshal(rawPkt)
 	if err != nil {
 		t.Error(errors.Wrap(err, "Unmarshal failed, has chunk"))
@@ -24,17 +26,18 @@ func TestInitChunk(t *testing.T) {
 		t.Error("Failed to cast Chunk -> Init")
 	}
 
-	if err != nil {
+	switch {
+	case err != nil:
 		t.Error(errors.Wrap(err, "Unmarshal init Chunk failed"))
-	} else if i.initiateTag != 1438213285 {
+	case i.initiateTag != 1438213285:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect initiate tag exp: %d act: %d", 1438213285, i.initiateTag))
-	} else if i.advertisedReceiverWindowCredit != 131072 {
+	case i.advertisedReceiverWindowCredit != 131072:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect advertisedReceiverWindowCredit exp: %d act: %d", 131072, i.advertisedReceiverWindowCredit))
-	} else if i.numOutboundStreams != 1024 {
+	case i.numOutboundStreams != 1024:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect numOutboundStreams tag exp: %d act: %d", 1024, i.numOutboundStreams))
-	} else if i.numInboundStreams != 2048 {
+	case i.numInboundStreams != 2048:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect numInboundStreams exp: %d act: %d", 2048, i.numInboundStreams))
-	} else if i.initialTSN != uint32(3899461680) {
+	case i.initialTSN != uint32(3899461680):
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect initialTSN exp: %d act: %d", uint32(3899461680), i.initialTSN))
 	}
 }
@@ -123,17 +126,18 @@ func TestInitMarshalUnmarshal(t *testing.T) {
 		t.Error("Failed to cast Chunk -> InitAck")
 	}
 
-	if err != nil {
+	switch {
+	case err != nil:
 		t.Error(errors.Wrap(err, "Unmarshal init ack Chunk failed"))
-	} else if i.initiateTag != 123 {
+	case i.initiateTag != 123:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect initiate tag exp: %d act: %d", 123, i.initiateTag))
-	} else if i.advertisedReceiverWindowCredit != 1024 {
+	case i.advertisedReceiverWindowCredit != 1024:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect advertisedReceiverWindowCredit exp: %d act: %d", 1024, i.advertisedReceiverWindowCredit))
-	} else if i.numOutboundStreams != 1 {
+	case i.numOutboundStreams != 1:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect numOutboundStreams tag exp: %d act: %d", 1, i.numOutboundStreams))
-	} else if i.numInboundStreams != 1 {
+	case i.numInboundStreams != 1:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect numInboundStreams exp: %d act: %d", 1, i.numInboundStreams))
-	} else if i.initialTSN != 123 {
+	case i.initialTSN != 123:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect initialTSN exp: %d act: %d", 123, i.initialTSN))
 	}
 }
@@ -186,7 +190,7 @@ func TestReconfigChunk(t *testing.T) {
 
 func TestForwardTSNChunk(t *testing.T) {
 	pkt := &packet{}
-	rawPkt := append([]byte{0x13, 0x88, 0x13, 0x88, 0xb6, 0xa5, 0x12, 0xe5, 0x1f, 0x9d, 0xa0, 0xfb}, testChunkForwardTSN...)
+	rawPkt := append([]byte{0x13, 0x88, 0x13, 0x88, 0xb6, 0xa5, 0x12, 0xe5, 0x1f, 0x9d, 0xa0, 0xfb}, testChunkForwardTSN()...)
 	err := pkt.unmarshal(rawPkt)
 	if err != nil {
 		t.Error(errors.Wrap(err, "Unmarshal failed, has chunk"))
diff --git a/packet_test.go b/packet_test.go
index 1e10135..63cf0e0 100644
--- a/packet_test.go
+++ b/packet_test.go
@@ -16,21 +16,24 @@ func TestPacketUnmarshal(t *testing.T) {
 
 	headerOnly := []byte{0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x06, 0xa9, 0x00, 0xe1}
 	err := pkt.unmarshal(headerOnly)
-	if err != nil {
+	switch {
+	case err != nil:
 		t.Error(errors.Wrap(err, "Unmarshal failed for SCTP packet with no chunks"))
-	} else if pkt.sourcePort != 5000 {
+	case pkt.sourcePort != 5000:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect source port exp: %d act: %d", 5000, pkt.sourcePort))
-	} else if pkt.destinationPort != 5000 {
+	case pkt.destinationPort != 5000:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect destination port exp: %d act: %d", 5000, pkt.destinationPort))
-	} else if pkt.verificationTag != 0 {
+	case pkt.verificationTag != 0:
 		t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect verification tag exp: %d act: %d", 0, pkt.verificationTag))
 	}
 
-	rawChunk := []byte{0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x81, 0x46, 0x9d, 0xfc, 0x01, 0x00, 0x00, 0x56, 0x55,
+	rawChunk := []byte{
+		0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x81, 0x46, 0x9d, 0xfc, 0x01, 0x00, 0x00, 0x56, 0x55,
 		0xb9, 0x64, 0xa5, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0xe8, 0x6d, 0x10, 0x30, 0xc0, 0x00, 0x00, 0x04, 0x80,
 		0x08, 0x00, 0x09, 0xc0, 0x0f, 0xc1, 0x80, 0x82, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x24, 0x9f, 0xeb, 0xbb, 0x5c, 0x50,
 		0xc9, 0xbf, 0x75, 0x9c, 0xb1, 0x2c, 0x57, 0x4f, 0xa4, 0x5a, 0x51, 0xba, 0x60, 0x17, 0x78, 0x27, 0x94, 0x5c, 0x31, 0xe6,
-		0x5d, 0x5b, 0x09, 0x47, 0xe2, 0x22, 0x06, 0x80, 0x04, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x06, 0x80, 0xc1, 0x00, 0x00}
+		0x5d, 0x5b, 0x09, 0x47, 0xe2, 0x22, 0x06, 0x80, 0x04, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x06, 0x80, 0xc1, 0x00, 0x00,
+	}
 
 	if err := pkt.unmarshal(rawChunk); err != nil {
 		t.Error(errors.Wrap(err, "Unmarshal failed, has chunk"))
diff --git a/param_forward_tsn_supported_test.go b/param_forward_tsn_supported_test.go
index 33bd78c..ea9d92c 100644
--- a/param_forward_tsn_supported_test.go
+++ b/param_forward_tsn_supported_test.go
@@ -6,23 +6,25 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-var (
-	testParamForwardTSNSupported = []byte{0xc0, 0x0, 0x0, 0x4}
-)
+func testParamForwardTSNSupported() []byte {
+	return []byte{0xc0, 0x0, 0x0, 0x4}
+}
 
 func TestParamForwardTSNSupported_Success(t *testing.T) {
 	tt := []struct {
 		binary []byte
 		parsed *paramForwardTSNSupported
 	}{
-		{testParamForwardTSNSupported,
+		{
+			testParamForwardTSNSupported(),
 			&paramForwardTSNSupported{
 				paramHeader: paramHeader{
 					typ: forwardTSNSupp,
 					len: 4,
 					raw: []byte{},
 				},
-			}},
+			},
+		},
 	}
 
 	for i, tc := range tt {
diff --git a/param_outgoing_reset_request_test.go b/param_outgoing_reset_request_test.go
index b087c54..dad4c48 100644
--- a/param_outgoing_reset_request_test.go
+++ b/param_outgoing_reset_request_test.go
@@ -6,40 +6,47 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-var (
-	testChunkReconfigParamA = []byte{0x0, 0xd, 0x0, 0x16, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x3, 0x0, 0x4, 0x0, 0x5, 0x0, 0x6}
-	testChunkReconfigParamB = []byte{0x0, 0xd, 0x0, 0x10, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x3}
-)
+func testChunkReconfigParamA() []byte {
+	return []byte{0x0, 0xd, 0x0, 0x16, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x3, 0x0, 0x4, 0x0, 0x5, 0x0, 0x6}
+}
+
+func testChunkReconfigParamB() []byte {
+	return []byte{0x0, 0xd, 0x0, 0x10, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x3}
+}
 
 func TestParamOutgoingResetRequest_Success(t *testing.T) {
 	tt := []struct {
 		binary []byte
 		parsed *paramOutgoingResetRequest
 	}{
-		{testChunkReconfigParamA,
+		{
+			testChunkReconfigParamA(),
 			&paramOutgoingResetRequest{
 				paramHeader: paramHeader{
 					typ: outSSNResetReq,
 					len: 22,
-					raw: testChunkReconfigParamA[4:],
+					raw: testChunkReconfigParamA()[4:],
 				},
 				reconfigRequestSequenceNumber:  1,
 				reconfigResponseSequenceNumber: 2,
 				senderLastTSN:                  3,
 				streamIdentifiers:              []uint16{4, 5, 6},
-			}},
-		{testChunkReconfigParamB,
+			},
+		},
+		{
+			testChunkReconfigParamB(),
 			&paramOutgoingResetRequest{
 				paramHeader: paramHeader{
 					typ: outSSNResetReq,
 					len: 16,
-					raw: testChunkReconfigParamB[4:],
+					raw: testChunkReconfigParamB()[4:],
 				},
 				reconfigRequestSequenceNumber:  1,
 				reconfigResponseSequenceNumber: 2,
 				senderLastTSN:                  3,
 				streamIdentifiers:              []uint16{},
-			}},
+			},
+		},
 	}
 
 	for i, tc := range tt {
@@ -62,7 +69,7 @@ func TestParamOutgoingResetRequest_Failure(t *testing.T) {
 		name   string
 		binary []byte
 	}{
-		{"packet too short", testChunkReconfigParamA[:8]},
+		{"packet too short", testChunkReconfigParamA()[:8]},
 		{"param too short", []byte{0x0, 0xd, 0x0, 0x4}},
 	}
 
diff --git a/param_reconfig_response_test.go b/param_reconfig_response_test.go
index f80110b..067d1a6 100644
--- a/param_reconfig_response_test.go
+++ b/param_reconfig_response_test.go
@@ -6,25 +6,27 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-var (
-	testChunkReconfigResponce = []byte{0x0, 0x10, 0x0, 0xc, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1}
-)
+func testChunkReconfigResponce() []byte {
+	return []byte{0x0, 0x10, 0x0, 0xc, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1}
+}
 
 func TestParamReconfigResponse_Success(t *testing.T) {
 	tt := []struct {
 		binary []byte
 		parsed *paramReconfigResponse
 	}{
-		{testChunkReconfigResponce,
+		{
+			testChunkReconfigResponce(),
 			&paramReconfigResponse{
 				paramHeader: paramHeader{
 					typ: reconfigResp,
 					len: 12,
-					raw: testChunkReconfigResponce[4:],
+					raw: testChunkReconfigResponce()[4:],
 				},
 				reconfigResponseSequenceNumber: 1,
 				result:                         reconfigResultSuccessPerformed,
-			}},
+			},
+		},
 	}
 
 	for i, tc := range tt {
@@ -47,7 +49,7 @@ func TestParamReconfigResponse_Failure(t *testing.T) {
 		name   string
 		binary []byte
 	}{
-		{"packet too short", testChunkReconfigParamA[:8]},
+		{"packet too short", testChunkReconfigParamA()[:8]},
 		{"param too short", []byte{0x0, 0x10, 0x0, 0x4}},
 	}
 
diff --git a/param_test.go b/param_test.go
index 0eed1d9..e3ac568 100644
--- a/param_test.go
+++ b/param_test.go
@@ -10,7 +10,7 @@ func TestBuildParam_Success(t *testing.T) {
 	tt := []struct {
 		binary []byte
 	}{
-		{testChunkReconfigParamA},
+		{testChunkReconfigParamA()},
 	}
 
 	for i, tc := range tt {
@@ -36,7 +36,7 @@ func TestBuildParam_Failure(t *testing.T) {
 		binary []byte
 	}{
 		{"invalid ParamType", []byte{0x0, 0x0}},
-		{"build failure", testChunkReconfigParamA[:8]},
+		{"build failure", testChunkReconfigParamA()[:8]},
 	}
 
 	for i, tc := range tt {
diff --git a/paramheader_test.go b/paramheader_test.go
index 9bb5bc8..fab4588 100644
--- a/paramheader_test.go
+++ b/paramheader_test.go
@@ -6,21 +6,23 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-var (
-	testParamHeader = []byte{0x0, 0x1, 0x0, 0x4}
-)
+func testParamHeader() []byte {
+	return []byte{0x0, 0x1, 0x0, 0x4}
+}
 
 func TestParamHeader_Success(t *testing.T) {
 	tt := []struct {
 		binary []byte
 		parsed *paramHeader
 	}{
-		{testParamHeader,
+		{
+			testParamHeader(),
 			&paramHeader{
 				typ: heartbeatInfo,
 				len: 4,
 				raw: []byte{},
-			}},
+			},
+		},
 	}
 
 	for i, tc := range tt {
@@ -43,10 +45,10 @@ func TestParamHeaderUnmarshal_Failure(t *testing.T) {
 		name   string
 		binary []byte
 	}{
-		{"header too short", testParamHeader[:2]},
+		{"header too short", testParamHeader()[:2]},
 		// {"wrong param type", []byte{0x0, 0x0, 0x0, 0x4}}, // Not possible to fail parseParamType atm.
 		{"reported length below header length", []byte{0x0, 0xd, 0x0, 0x3}},
-		{"wrong reported length", testChunkReconfigParamA[:4]},
+		{"wrong reported length", testChunkReconfigParamA()[:4]},
 	}
 
 	for i, tc := range tt {
diff --git a/reassembly_queue_test.go b/reassembly_queue_test.go
index e12af1d..9154bf2 100644
--- a/reassembly_queue_test.go
+++ b/reassembly_queue_test.go
@@ -1,7 +1,6 @@
 package sctp
 
 import (
-	//"fmt"
 	"io"
 	"testing"
 
@@ -400,7 +399,7 @@ func TestReassemblyQueue(t *testing.T) {
 		assert.False(t, complete, "chunk set should not be complete yet")
 		assert.Equal(t, 9, rq.getNumBytes(), "num bytes mismatch")
 
-		rq.forwardTSNForOrdered(13, ssnDropped)
+		rq.forwardTSNForOrdered(ssnDropped)
 
 		assert.Equal(t, 1, len(rq.ordered), "there should be one chunk left")
 		assert.Equal(t, 3, rq.getNumBytes(), "num bytes mismatch")
diff --git a/rtx_timer_test.go b/rtx_timer_test.go
index edd9634..4d1d6b8 100644
--- a/rtx_timer_test.go
+++ b/rtx_timer_test.go
@@ -1,7 +1,6 @@
 package sctp
 
 import (
-	//"fmt"
 	"math"
 	"sync/atomic"
 	"testing"
@@ -84,8 +83,10 @@ func TestRTOManager(t *testing.T) {
 	})
 }
 
-type onRTO func(id int, n uint)
-type onRtxFailure func(id int)
+type (
+	onRTO        func(id int, n uint)
+	onRtxFailure func(id int)
+)
 
 type testTimerObserver struct {
 	onRTO        onRTO
@@ -118,7 +119,7 @@ func TestRtxTimer(t *testing.T) {
 
 		assert.False(t, rt.isRunning(), "should not be running")
 
-		//since := time.Now()
+		// since := time.Now()
 		ok := rt.start(30)
 		assert.True(t, ok, "should be true")
 		assert.True(t, rt.isRunning(), "should be running")
diff --git a/util_test.go b/util_test.go
index ab5889d..3a304ef 100644
--- a/util_test.go
+++ b/util_test.go
@@ -29,7 +29,7 @@ func TestPadByte_Success(t *testing.T) {
 func TestSerialNumberArithmetic(t *testing.T) {
 	const div int = 16
 
-	t.Run("32-bit", func(t *testing.T) {
+	t.Run("32-bit", func(t *testing.T) { // nolint:dupl
 		const serialBits uint32 = 32
 		const interval uint32 = uint32((uint64(1) << uint64(serialBits)) / uint64(div))
 		const maxForwardDistance uint32 = 1<<(serialBits-1) - 1
@@ -65,7 +65,7 @@ func TestSerialNumberArithmetic(t *testing.T) {
 		}
 	})
 
-	t.Run("16-bit", func(t *testing.T) {
+	t.Run("16-bit", func(t *testing.T) { // nolint:dupl
 		const serialBits uint16 = 16
 		const interval uint16 = uint16((uint64(1) << uint64(serialBits)) / uint64(div))
 		const maxForwardDistance uint16 = 1<<(serialBits-1) - 1
diff --git a/vnet_test.go b/vnet_test.go
index 8819e89..bdf7994 100644
--- a/vnet_test.go
+++ b/vnet_test.go
@@ -30,11 +30,13 @@ type vNetEnv struct {
 	numToDropCookieAck  int
 }
 
+var errSCTPPacketParse = fmt.Errorf("unable to parse SCTP packet")
+
 func (venv *vNetEnv) dropNextDataChunk(numToDrop int) {
 	venv.numToDropData = numToDrop
 }
 
-func (venv *vNetEnv) dropNextReconfigChunk(numToDrop int) {
+func (venv *vNetEnv) dropNextReconfigChunk(numToDrop int) { // nolint:unused
 	venv.numToDropReconfig = numToDrop
 }
 
@@ -71,7 +73,7 @@ func buildVNetEnv(cfg *vNetEnvConfig) (*vNetEnv, error) {
 			var toDrop bool
 			p := &packet{}
 			if err2 := p.unmarshal(c.UserData()); err2 != nil {
-				panic(fmt.Errorf("unable to parse SCTP packet"))
+				panic(errSCTPPacketParse)
 			}
 
 		loop:
@@ -383,7 +385,7 @@ func TestRwndFull(t *testing.T) {
 	})
 }
 
-func testStreamClose(t *testing.T, dropReconfig bool) {
+func TestStreamClose(t *testing.T) {
 	lim := test.TimeOut(time.Second * 10)
 	defer lim.Stop()
 
@@ -559,16 +561,6 @@ func testStreamClose(t *testing.T, dropReconfig bool) {
 	log.Info("all done")
 }
 
-func TestStreamClose(t *testing.T) {
-	t.Run("Normal close", func(t *testing.T) {
-		testStreamClose(t, false)
-	})
-
-	t.Run("Drop reconfig packet", func(t *testing.T) {
-		testStreamClose(t, true)
-	})
-}
-
 // this test case reproduces the issue mentioned in
 // https://github.com/pion/webrtc/issues/1270#issuecomment-653953743
 // and confirmes the fix.