Compare commits

..

19 commits

Author SHA1 Message Date
d7b32480fd
Handle test server connection timeouts
Add logic to skip tests if there's a timeout error while connecting to the test server. This ensures that transient network issues do not cause test failures.
2024-10-26 17:33:52 +02:00
23399ed84c
Change DefaultHost to loopback address
Updated DefaultHost from "localhost" to "127.0.0.1" in client_test.go. This change ensures consistent and direct communication with the local machine, avoiding potential issues with DNS resolution of "localhost".
2024-10-26 17:17:58 +02:00
90e3162a22
Update CI to support older Go versions
Added Go 1.19 and 1.20 to the CI matrix to extend compatibility testing. This ensures that our project continues to work with these older versions of Go.
2024-10-26 17:11:21 +02:00
273a26ca53
Add tests for Go 1.21+ compatibility
Moved some tests that use JSONlog (which requires Go 1.21+) to a separate file that is skipped on older Go versions.
2024-10-26 17:10:50 +02:00
a815c58571
Update CI workflow to install nullmailer instead of ssmtp
Replacing ssmtp with nullmailer ensures better compatibility with the updated email delivery requirements. The DEBIAN_FRONTEND=noninteractive parameter was also added to avoid interactive prompts during installation.
2024-10-26 16:45:07 +02:00
c33900ca29
Add sudo to apt-get commands in CI workflow
Previously, the apt-get commands lacked the necessary sudo prefix, which could lead to permission issues during the CI process. This change ensures that updates, upgrades, and installations are executed with the appropriate permissions.
2024-10-26 16:26:49 +02:00
4b8bf0507d
Update CI workflow and sendmail test condition
Add the TEST_SENDMAIL environment variable for better control over sendmail tests. Optimize sendmail installation in CI by updating and installing ssmtp. Modify tests to check if TEST_SENDMAIL is set to "true" before running.
2024-10-26 16:25:42 +02:00
9072aef355
Remove support for Go 1.19 and 1.20 in CI workflow
This commit updates the CI configuration to no longer test against Go versions 1.19 and 1.20. The supported Go versions are now 1.21, 1.22, and 1.23, ensuring the CI pipeline aligns with our current support policy.
2024-10-26 15:58:13 +02:00
3aef85e324
Add SPDX license headers to CI workflow file
This change adds SPDX license headers to the .github/workflows/ci.yml file to ensure proper attribution and compliance with the MIT license. The added headers include copyright information and the applicable license type.
2024-10-26 15:57:27 +02:00
f82ac0c5ae
Update concurrency group names in GitHub Actions
This change modifies the concurrency group names to include OS and Go version for better differentiation. This prevents conflicts and ensures that concurrent jobs are properly managed based on their specific matrices.
2024-10-26 15:52:27 +02:00
eeccee0d94
Add checkout step to CI workflow
Ensure CI workflow has access to the latest code by adding a checkout step. This change is necessary for the golangci-lint action to function correctly with the most recent codebase.
2024-10-26 15:50:14 +02:00
9c57ba56cf
Add 'runs-on' directive to lint and govulncheck steps
This ensures the lint and vulnerability check steps run on the 'ubuntu-latest' environment. Establishing a clear execution environment helps maintain consistency across CI runs.
2024-10-26 15:48:10 +02:00
4d4aa1e1df
Add runs-on parameter to dependency review job
This change specifies that the dependency review job should run on the latest version of Ubuntu. It ensures consistency and clarity in the workflow configuration. This modification helps avoid potential issues related to unspecified runner environments.
2024-10-26 15:47:04 +02:00
960c015a93
Remove IPv6 and IPv4 test cases from msg_test.go
Removed test cases for IPv6 and IPv4 addresses from `msg_test.go` as they are no longer required. Also made a minor formatting adjustment to the `checkAddrHeader` function signature for better readability.
2024-10-26 15:45:01 +02:00
12e9a0cb5d
Simplify CI workflow branch checks
Removed file path filters on branch triggers in the CI workflow configuration. This allows the CI to run for any changes made in the main branch, ensuring broader test coverage and catching issues early.
2024-10-26 15:37:07 +02:00
9e6c1f0417
Consolidate CI workflows into a single file
Merged separate workflows for Codecov, dependency-review, golangci-lint, govulncheck, offline-tests, reuse compliance, and SonarQube into a unified CI workflow file in `.github/workflows/ci.yml`. This restructuring simplifies our CI setup and ensures more consistent and efficient pipeline management.
2024-10-26 15:33:05 +02:00
0e9646e0e4
Merge branch 'main' into feature/overhaul-tests 2024-10-26 14:58:41 +02:00
c47f08dc7f
Merge pull request #346 from wneessen/dependabot/github_actions/actions/setup-go-5.1.0
Bump actions/setup-go from 5.0.2 to 5.1.0
2024-10-25 16:32:48 +02:00
dependabot[bot]
87c0575dd4
Bump actions/setup-go from 5.0.2 to 5.1.0
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5.0.2 to 5.1.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](0a12ed9d6a...41dfa10bad)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-25 13:39:33 +00:00
12 changed files with 475 additions and 359 deletions

195
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,195 @@
# SPDX-FileCopyrightText: 2024 The go-mail Authors
#
# SPDX-License-Identifier: MIT
name: CI
permissions:
contents: read
on:
push:
branches:
- main
pull_request:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
jobs:
codecov:
name: Test with Codecov coverage (${{ matrix.os }} / ${{ matrix.go }})
runs-on: ${{ matrix.os }}
concurrency:
group: ci-codecov-${{ matrix.os }}-${{ matrix.go }}
cancel-in-progress: true
strategy:
matrix:
os: [ubuntu-latest]
go: ['1.23']
env:
PERFORM_ONLINE_TEST: ${{ vars.PERFORM_ONLINE_TEST }}
TEST_SENDMAIL: ${{ vars.TEST_SENDMAIL }}
TEST_HOST: ${{ secrets.TEST_HOST }}
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASS: ${{ secrets.TEST_PASS }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
- name: Setup go
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
with:
go-version: ${{ matrix.go }}
check-latest: true
- name: Install sendmail
run: |
sudo apt-get -y update >/dev/null && sudo apt-get -y upgrade >/dev/null && sudo DEBIAN_FRONTEND=noninteractive apt-get -y install nullmailer >/dev/null && which sendmail
- name: Run go test
if: success()
run: |
go test -race -shuffle=on --coverprofile=coverage.coverprofile --covermode=atomic ./...
- name: Upload coverage to Codecov
if: success()
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
lint:
name: golangci-lint (${{ matrix.go }})
runs-on: ubuntu-latest
concurrency:
group: ci-lint-${{ matrix.go }}
cancel-in-progress: true
strategy:
matrix:
go: ['1.23']
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Setup go
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
with:
go-version: ${{ matrix.go }}
check-latest: true
- name: Checkout Code
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
- name: golangci-lint
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
with:
version: latest
dependency-review:
name: Dependency review
runs-on: ubuntu-latest
concurrency:
group: ci-dependency-review
cancel-in-progress: true
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
- name: 'Dependency Review'
uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5
govulncheck:
name: Go vulnerabilities check
runs-on: ubuntu-latest
concurrency:
group: ci-govulncheck
cancel-in-progress: true
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Run govulncheck
uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1.0.4
test:
name: Test (${{ matrix.os }} / ${{ matrix.go }})
runs-on: ${{ matrix.os }}
concurrency:
group: ci-test-${{ matrix.os }}-${{ matrix.go }}
cancel-in-progress: true
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
go: ['1.19', '1.20', '1.21', '1.22', '1.23']
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
- name: Setup go
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
with:
go-version: ${{ matrix.go }}
- name: Run go test
run: |
go test -race -shuffle=on ./...
reuse:
name: REUSE Compliance Check
runs-on: ubuntu-latest
concurrency:
group: ci-reuse
cancel-in-progress: true
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
- name: REUSE Compliance Check
uses: fsfe/reuse-action@3ae3c6bdf1257ab19397fab11fd3312144692083 # v4.0.0
sonarqube:
name: Test with SonarQube review (${{ matrix.os }} / ${{ matrix.go }})
runs-on: ${{ matrix.os }}
concurrency:
group: ci-codecov-${{ matrix.go }}
cancel-in-progress: true
strategy:
matrix:
os: [ubuntu-latest]
go: ['1.23']
env:
PERFORM_ONLINE_TEST: ${{ vars.PERFORM_ONLINE_TEST }}
TEST_HOST: ${{ secrets.TEST_HOST }}
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASS: ${{ secrets.TEST_PASS }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
- name: Setup go
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
with:
go-version: ${{ matrix.go }}
check-latest: true
- name: Run go test
run: |
go test -shuffle=on -race --coverprofile=./cov.out ./...
- name: SonarQube scan
uses: sonarsource/sonarqube-scan-action@884b79409bbd464b2a59edc326a4b77dc56b2195 # master
if: success()
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
- name: SonarQube quality gate
uses: sonarsource/sonarqube-quality-gate-action@dc2f7b0dd95544cd550de3028f89193576e958b9 # master
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

View file

@ -1,67 +0,0 @@
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
#
# SPDX-License-Identifier: CC0-1.0
name: Codecov workflow
on:
push:
branches:
- main
paths:
- '**.go'
- 'go.*'
- '.github/workflows/codecov.yml'
- 'codecov.yml'
pull_request:
branches:
- main
paths:
- '**.go'
- 'go.*'
- '.github/workflows/codecov.yml'
- 'codecov.yml'
env:
TEST_HOST: ${{ secrets.TEST_HOST }}
TEST_FROM: ${{ secrets.TEST_USER }}
TEST_ALLOW_SEND: "1"
TEST_SMTPAUTH_USER: ${{ secrets.TEST_USER }}
TEST_SMTPAUTH_PASS: ${{ secrets.TEST_PASS }}
TEST_SMTPAUTH_TYPE: "LOGIN"
TEST_ONLINE_SCRAM: "1"
TEST_HOST_SCRAM: ${{ secrets.TEST_HOST_SCRAM }}
TEST_USER_SCRAM: ${{ secrets.TEST_USER_SCRAM }}
TEST_PASS_SCRAM: ${{ secrets.TEST_PASS_SCRAM }}
permissions:
contents: read
jobs:
run:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
go: ['1.23']
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
- name: Setup go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
with:
go-version: ${{ matrix.go }}
- name: Install sendmail
if: matrix.go == '1.23' && matrix.os == 'ubuntu-latest'
run: |
sudo apt-get -y install sendmail; which sendmail
- name: Run Tests
run: |
go test -race --coverprofile=coverage.coverprofile --covermode=atomic ./...
- name: Upload coverage to Codecov
if: success() && matrix.go == '1.23' && matrix.os == 'ubuntu-latest'
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos

View file

@ -1,31 +0,0 @@
# SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
#
# SPDX-License-Identifier: CC0-1.0
# Dependency Review Action
#
# This Action will scan dependency manifest files that change as part of a Pull Request,
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
# Once installed, if the workflow run is marked as required,
# PRs introducing known-vulnerable packages will be blocked from merging.
#
# Source repository: https://github.com/actions/dependency-review-action
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: 'Checkout Repository'
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: 'Dependency Review'
uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5

View file

@ -1,54 +0,0 @@
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
#
# SPDX-License-Identifier: CC0-1.0
name: golangci-lint
on:
push:
tags:
- v*
branches:
- main
pull_request:
permissions:
contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
# pull-requests: read
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
with:
go-version: '1.23'
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: golangci-lint
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: latest
# Optional: working directory, useful for monorepos
# working-directory: somedir
# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true
# Optional: if set to true then the all caching functionality will be complete disabled,
# takes precedence over all other caching options.
# skip-cache: true
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
# skip-pkg-cache: true
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true

View file

@ -1,21 +0,0 @@
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
#
# SPDX-License-Identifier: CC0-1.0
name: Govulncheck Security Scan
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Run govulncheck
uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1.0.4

View file

@ -1,45 +0,0 @@
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
#
# SPDX-License-Identifier: CC0-1.0
name: Offline tests workflow
on:
push:
branches:
- main
paths:
- '**.go'
- 'go.*'
- '.github/workflows/offline-tests.yml'
pull_request:
branches:
- main
paths:
- '**.go'
- 'go.*'
- '.github/workflows/offline-tests.yml'
permissions:
contents: read
jobs:
run:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
go: ['1.19', '1.20', '1.21', '1.22', '1.23']
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Checkout Code
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
- name: Setup go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
with:
go-version: ${{ matrix.go }}
- name: Run Tests
run: |
go test -race -shuffle=on ./...

View file

@ -1,23 +0,0 @@
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
#
# SPDX-License-Identifier: CC0-1.0
name: REUSE Compliance Check
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
- name: REUSE Compliance Check
uses: fsfe/reuse-action@3ae3c6bdf1257ab19397fab11fd3312144692083 # v4.0.0

View file

@ -1,56 +0,0 @@
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
#
# SPDX-License-Identifier: CC0-1.0
name: SonarQube
permissions:
contents: read
on:
push:
branches:
- main
paths:
- '**.go'
- 'go.*'
- '.github/workflows/sonarqube.yml'
pull_request:
branches:
- main
paths:
- '**.go'
- 'go.*'
- '.github/workflows/sonarqube.yml'
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
with:
go-version: '1.23'
- name: Run unit Tests
run: |
go test -shuffle=on -race --coverprofile=./cov.out ./...
- uses: sonarsource/sonarqube-scan-action@884b79409bbd464b2a59edc326a4b77dc56b2195 # master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
- uses: sonarsource/sonarqube-quality-gate-action@dc2f7b0dd95544cd550de3028f89193576e958b9 # master
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

126
client_121_test.go Normal file
View file

@ -0,0 +1,126 @@
// SPDX-FileCopyrightText: 2024 The go-mail Authors
//
// SPDX-License-Identifier: MIT
//go:build go1.21
// +build go1.21
package mail
import (
"bytes"
"context"
"errors"
"fmt"
"net"
"os"
"reflect"
"strings"
"testing"
"time"
"github.com/wneessen/go-mail/log"
)
func TestNewClientNewVersionsOnly(t *testing.T) {
tests := []struct {
name string
option Option
expectFunc func(c *Client) error
shouldfail bool
expectErr *error
}{
{
"WithLogger log.JSONlog", WithLogger(log.NewJSON(os.Stderr, log.LevelDebug)),
func(c *Client) error {
if c.logger == nil {
return errors.New("failed to set logger. Want logger bug got got nil")
}
loggerType := reflect.TypeOf(c.logger).String()
if loggerType != "*log.JSONlog" {
return fmt.Errorf("failed to set logger. Want logger type: %s, got: %s",
"*log.JSONlog", loggerType)
}
return nil
},
false, nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client, err := NewClient(DefaultHost, tt.option)
if !tt.shouldfail && err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if tt.shouldfail && err == nil {
t.Errorf("client creation was supposed to fail, but it didn't")
}
if tt.shouldfail && tt.expectErr != nil {
if !errors.Is(err, *tt.expectErr) {
t.Errorf("error for NewClient mismatch. Expected: %s, got: %s",
*tt.expectErr, err)
}
}
if tt.expectFunc != nil {
if err = tt.expectFunc(client); err != nil {
t.Errorf("NewClient with custom option failed: %s", err)
}
}
})
}
}
func TestClient_DialWithContextNewVersionsOnly(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
PortAdder.Add(1)
serverPort := int(TestServerPortBase + PortAdder.Load())
featureSet := "250-AUTH PLAIN\r\n250-8BITMIME\r\n250-DSN\r\n250 SMTPUTF8"
go func() {
if err := simpleSMTPServer(ctx, t, &serverProps{FeatureSet: featureSet, ListenPort: serverPort}); err != nil {
t.Errorf("failed to start test server: %s", err)
return
}
}()
time.Sleep(time.Millisecond * 30)
t.Run("connect with full debug logging and auth logging", func(t *testing.T) {
ctxDial, cancelDial := context.WithTimeout(ctx, time.Millisecond*500)
t.Cleanup(cancelDial)
logBuffer := bytes.NewBuffer(nil)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS),
WithDebugLog(), WithLogAuthData(), WithLogger(log.NewJSON(logBuffer, log.LevelDebug)),
WithSMTPAuth(SMTPAuthPlain), WithUsername("test"), WithPassword("password"))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err)
}
t.Cleanup(func() {
if err = client.Close(); err != nil {
t.Errorf("failed to close the client: %s", err)
}
})
logs := parseJSONLog(t, logBuffer)
if len(logs.Lines) == 0 {
t.Errorf("failed to enable debug logging, but no logs were found")
}
authFound := false
for _, logline := range logs.Lines {
if strings.EqualFold(logline.Message, "AUTH PLAIN AHRlc3QAcGFzc3dvcmQ=") &&
logline.Direction.From == "client" && logline.Direction.To == "server" {
authFound = true
}
}
if !authFound {
t.Errorf("logAuthData not working, no authentication info found in logs")
}
})
}

View file

@ -29,7 +29,7 @@ import (
const ( const (
// DefaultHost is used as default hostname for the Client // DefaultHost is used as default hostname for the Client
DefaultHost = "localhost" DefaultHost = "127.0.0.1"
// TestRcpt is a trash mail address to send test mails to // TestRcpt is a trash mail address to send test mails to
TestRcpt = "couttifaddebro-1473@yopmail.com" TestRcpt = "couttifaddebro-1473@yopmail.com"
// TestServerProto is the protocol used for the simple SMTP test server // TestServerProto is the protocol used for the simple SMTP test server
@ -268,21 +268,6 @@ func TestNewClient(t *testing.T) {
}, },
false, nil, false, nil,
}, },
{
"WithLogger log.JSONlog", WithLogger(log.NewJSON(os.Stderr, log.LevelDebug)),
func(c *Client) error {
if c.logger == nil {
return errors.New("failed to set logger. Want logger bug got got nil")
}
loggerType := reflect.TypeOf(c.logger).String()
if loggerType != "*log.JSONlog" {
return fmt.Errorf("failed to set logger. Want logger type: %s, got: %s",
"*log.JSONlog", loggerType)
}
return nil
},
false, nil,
},
{ {
"WithHELO", WithHELO(hostname), "WithHELO", WithHELO(hostname),
func(c *Client) error { func(c *Client) error {
@ -1181,6 +1166,10 @@ func TestClient_SetDebugLog(t *testing.T) {
client.SetDebugLog(true) client.SetDebugLog(true)
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -1210,6 +1199,10 @@ func TestClient_SetDebugLog(t *testing.T) {
client.SetDebugLog(false) client.SetDebugLog(false)
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -1235,6 +1228,10 @@ func TestClient_SetDebugLog(t *testing.T) {
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -1559,6 +1556,10 @@ func TestClient_Close(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
if !client.smtpClient.HasConnection() { if !client.smtpClient.HasConnection() {
@ -1593,6 +1594,10 @@ func TestClient_Close(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
if !client.smtpClient.HasConnection() { if !client.smtpClient.HasConnection() {
@ -1631,6 +1636,10 @@ func TestClient_Close(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
if !client.smtpClient.HasConnection() { if !client.smtpClient.HasConnection() {
@ -1665,6 +1674,10 @@ func TestClient_DialWithContext(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -1688,6 +1701,10 @@ func TestClient_DialWithContext(t *testing.T) {
client.fallbackPort = serverPort client.fallbackPort = serverPort
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -1759,42 +1776,6 @@ func TestClient_DialWithContext(t *testing.T) {
t.Fatalf("client has connection") t.Fatalf("client has connection")
} }
}) })
t.Run("connect with full debug logging and auth logging", func(t *testing.T) {
ctxDial, cancelDial := context.WithTimeout(ctx, time.Millisecond*500)
t.Cleanup(cancelDial)
logBuffer := bytes.NewBuffer(nil)
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS),
WithDebugLog(), WithLogAuthData(), WithLogger(log.NewJSON(logBuffer, log.LevelDebug)),
WithSMTPAuth(SMTPAuthPlain), WithUsername("test"), WithPassword("password"))
if err != nil {
t.Fatalf("failed to create new client: %s", err)
}
if err = client.DialWithContext(ctxDial); err != nil {
t.Fatalf("failed to connect to the test server: %s", err)
}
t.Cleanup(func() {
if err = client.Close(); err != nil {
t.Errorf("failed to close the client: %s", err)
}
})
logs := parseJSONLog(t, logBuffer)
if len(logs.Lines) == 0 {
t.Errorf("failed to enable debug logging, but no logs were found")
}
authFound := false
for _, logline := range logs.Lines {
if strings.EqualFold(logline.Message, "AUTH PLAIN AHRlc3QAcGFzc3dvcmQ=") &&
logline.Direction.From == "client" && logline.Direction.To == "server" {
authFound = true
}
}
if !authFound {
t.Errorf("logAuthData not working, no authentication info found in logs")
}
})
t.Run("connect should fail on HELO", func(t *testing.T) { t.Run("connect should fail on HELO", func(t *testing.T) {
ctxFail, cancelFail := context.WithCancel(ctx) ctxFail, cancelFail := context.WithCancel(ctx)
defer cancelFail() defer cancelFail()
@ -1887,6 +1868,10 @@ func TestClient_DialWithContext(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
}) })
@ -1917,6 +1902,10 @@ func TestClient_DialWithContext(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
}) })
@ -2009,6 +1998,10 @@ func TestClient_DialWithContext(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
if err := client.Close(); err != nil { if err := client.Close(); err != nil {
@ -2040,6 +2033,10 @@ func TestClient_Reset(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2073,6 +2070,10 @@ func TestClient_Reset(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
if err = client.Close(); err != nil { if err = client.Close(); err != nil {
@ -2108,6 +2109,10 @@ func TestClient_Reset(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to the test server: %s", err) t.Fatalf("failed to connect to the test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2145,6 +2150,10 @@ func TestClient_DialAndSendWithContext(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialAndSend(message); err != nil { if err = client.DialAndSend(message); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to dial and send: %s", err) t.Fatalf("failed to dial and send: %s", err)
} }
}) })
@ -2173,6 +2182,10 @@ func TestClient_DialAndSendWithContext(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialAndSendWithContext(ctxDial, message); err != nil { if err = client.DialAndSendWithContext(ctxDial, message); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to dial and send: %s", err) t.Fatalf("failed to dial and send: %s", err)
} }
}) })
@ -2311,6 +2324,10 @@ func TestClient_auth(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test service: %s", err) t.Fatalf("failed to connect to test service: %s", err)
} }
if err := client.Close(); err != nil { if err := client.Close(); err != nil {
@ -2498,6 +2515,10 @@ func TestClient_Send(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2550,6 +2571,10 @@ func TestClient_Send(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2607,6 +2632,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2646,6 +2675,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2687,6 +2720,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2733,6 +2770,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2779,6 +2820,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2825,6 +2870,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2864,6 +2913,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2911,6 +2964,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -2958,6 +3015,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -3004,6 +3065,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -3050,6 +3115,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -3096,6 +3165,10 @@ func TestClient_checkConn(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -3133,6 +3206,10 @@ func TestClient_checkConn(t *testing.T) {
t.Fatalf("failed to create new client: %s", err) t.Fatalf("failed to create new client: %s", err)
} }
if err = client.DialWithContext(ctxDial); err != nil { if err = client.DialWithContext(ctxDial); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to connect to test server: %s", err) t.Fatalf("failed to connect to test server: %s", err)
} }
t.Cleanup(func() { t.Cleanup(func() {
@ -3199,7 +3276,11 @@ func TestClient_onlinetests(t *testing.T) {
t.Cleanup(cancel) t.Cleanup(cancel)
if err = client.DialWithContext(ctx); err != nil { if err = client.DialWithContext(ctx); err != nil {
t.Errorf("failed to dial to test server: %s", err) var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to dial to test server: %s", err)
} }
if err = client.smtpClient.Noop(); err != nil { if err = client.smtpClient.Noop(); err != nil {
t.Errorf("failed to send noop: %s", err) t.Errorf("failed to send noop: %s", err)
@ -3241,7 +3322,11 @@ func TestClient_onlinetests(t *testing.T) {
t.Cleanup(cancel) t.Cleanup(cancel)
if err = client.DialWithContext(ctx); err != nil { if err = client.DialWithContext(ctx); err != nil {
t.Errorf("failed to dial to test server: %s", err) var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to dial to test server: %s", err)
} }
if err = client.smtpClient.Noop(); err != nil { if err = client.smtpClient.Noop(); err != nil {
t.Errorf("failed to send noop: %s", err) t.Errorf("failed to send noop: %s", err)
@ -3283,7 +3368,11 @@ func TestClient_onlinetests(t *testing.T) {
t.Cleanup(cancel) t.Cleanup(cancel)
if err = client.DialWithContext(ctx); err != nil { if err = client.DialWithContext(ctx); err != nil {
t.Errorf("failed to dial to test server: %s", err) var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("failed to dial to test server: %s", err)
} }
if err = client.smtpClient.Noop(); err != nil { if err = client.smtpClient.Noop(); err != nil {
t.Errorf("failed to send noop: %s", err) t.Errorf("failed to send noop: %s", err)
@ -3325,6 +3414,10 @@ func TestClient_XOAuth2OnFaker(t *testing.T) {
t.Fatalf("unable to create new client: %v", err) t.Fatalf("unable to create new client: %v", err)
} }
if err = c.DialWithContext(context.Background()); err != nil { if err = c.DialWithContext(context.Background()); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
t.Skip("failed to connect to the test server due to timeout")
}
t.Fatalf("unexpected dial error: %v", err) t.Fatalf("unexpected dial error: %v", err)
} }
if err = c.Close(); err != nil { if err = c.Close(); err != nil {

View file

@ -16,8 +16,8 @@ import (
// TestMsg_WriteToSendmailWithContext tests the WriteToSendmailWithContext() method of the Msg // TestMsg_WriteToSendmailWithContext tests the WriteToSendmailWithContext() method of the Msg
func TestMsg_WriteToSendmailWithContext(t *testing.T) { func TestMsg_WriteToSendmailWithContext(t *testing.T) {
if os.Getenv("TEST_SKIP_SENDMAIL") != "" { if os.Getenv("TEST_SENDMAIL") != "true" {
t.Skipf("TEST_SKIP_SENDMAIL variable is set. Skipping sendmail test") t.Skipf("TEST_SENDMAIL variable is not set. Skipping sendmail test")
} }
tests := []struct { tests := []struct {
name string name string
@ -45,8 +45,8 @@ func TestMsg_WriteToSendmailWithContext(t *testing.T) {
// TestMsg_WriteToSendmail will test the output to the local sendmail command // TestMsg_WriteToSendmail will test the output to the local sendmail command
func TestMsg_WriteToSendmail(t *testing.T) { func TestMsg_WriteToSendmail(t *testing.T) {
if os.Getenv("TEST_SKIP_SENDMAIL") != "" { if os.Getenv("TEST_SENDMAIL") != "true" {
t.Skipf("TEST_SKIP_SENDMAIL variable is set. Skipping sendmail test") t.Skipf("TEST_SENDMAIL variable is not set. Skipping sendmail test")
} }
_, err := os.Stat(SendmailPath) _, err := os.Stat(SendmailPath)
if err != nil { if err != nil {

View file

@ -113,8 +113,6 @@ var (
{`hi\ there@domain.tld`, false}, // Spaces must be quoted {`hi\ there@domain.tld`, false}, // Spaces must be quoted
{"hello@tld", true}, // TLD is enough {"hello@tld", true}, // TLD is enough
{`你好@域名.顶级域名`, true}, // We speak RFC6532 {`你好@域名.顶级域名`, true}, // We speak RFC6532
{`cow@[dead::beef]`, true}, // IPv6 is fine
{"1@[1.101.236.21]", true}, // IPv4 is fine
{"1@23456789", true}, // Hypothetically valid, if somebody registers that TLD {"1@23456789", true}, // Hypothetically valid, if somebody registers that TLD
{"1@[23456789]", false}, // While 23456789 is decimal for 1.101.236.21 it is not RFC5322 compliant {"1@[23456789]", false}, // While 23456789 is decimal for 1.101.236.21 it is not RFC5322 compliant
} }
@ -1140,7 +1138,8 @@ func TestMsg_ToFromString(t *testing.T) {
// checkAddrHeader validates a single email address in the AddrHeader of a message. // checkAddrHeader validates a single email address in the AddrHeader of a message.
func checkAddrHeader(t *testing.T, message *Msg, header AddrHeader, fn string, field, wantFields int, func checkAddrHeader(t *testing.T, message *Msg, header AddrHeader, fn string, field, wantFields int,
wantMail, wantName string) { wantMail, wantName string,
) {
t.Helper() t.Helper()
addresses, ok := message.addrHeader[header] addresses, ok := message.addrHeader[header]
if !ok { if !ok {