From c4a6a297d714009159c4b7f734a218def333e349 Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Mon, 9 Sep 2024 18:16:46 +0400 Subject: [PATCH] Transform test into e2e test Signed-off-by: Anton Litvinov --- .github/workflows/tests-and-linters.yml | 3 + ci/test/e2e.go | 36 ++++++++ docker-compose.e2e-shaper.yml | 25 +++++ e2e/gorunner-shaper/Dockerfile | 3 + e2e/gorunner-shaper/Dockerfile.precompiled | 6 ++ e2e/shaper/runner.go | 92 +++++++++++++++++++ .../shaper}/shaper_service_test.go | 30 ++++-- e2e/shaper/websvc/Dockerfile | 5 + e2e/shaper/websvc/main.go | 33 +++++++ 9 files changed, 226 insertions(+), 7 deletions(-) create mode 100644 docker-compose.e2e-shaper.yml create mode 100644 e2e/gorunner-shaper/Dockerfile create mode 100644 e2e/gorunner-shaper/Dockerfile.precompiled create mode 100644 e2e/shaper/runner.go rename {services/wireguard/endpoint/netstack-provider => e2e/shaper}/shaper_service_test.go (84%) create mode 100644 e2e/shaper/websvc/Dockerfile create mode 100644 e2e/shaper/websvc/main.go diff --git a/.github/workflows/tests-and-linters.yml b/.github/workflows/tests-and-linters.yml index 49aa7a5131..602f816597 100644 --- a/.github/workflows/tests-and-linters.yml +++ b/.github/workflows/tests-and-linters.yml @@ -60,6 +60,9 @@ jobs: - name: E2E basic test run: go run mage.go -v TestE2EBasic + - name: E2E shaper test + run: go run mage.go -v TestE2EShaper + e2e-nat: runs-on: ubuntu-latest diff --git a/ci/test/e2e.go b/ci/test/e2e.go index e14754b674..fd5b6973fa 100644 --- a/ci/test/e2e.go +++ b/ci/test/e2e.go @@ -24,6 +24,7 @@ import ( "github.com/magefile/mage/mg" "github.com/magefile/mage/sh" "github.com/mysteriumnetwork/node/e2e" + e2e_shaper "github.com/mysteriumnetwork/node/e2e/shaper" "github.com/mysteriumnetwork/node/logconfig" "github.com/rs/zerolog/log" ) @@ -50,6 +51,23 @@ func BuildE2eTestBinary() error { return os.Rename("./e2e.test", "./build/e2e/test") } +// BuildE2eShaperTestBinary builds the e2e test binary. +func BuildE2eShaperTestBinary() error { + err := sh.RunWith(crossCompileFlags, "go", "test", "-c", "./e2e/shaper") + if err != nil { + return err + } + err = sh.RunWith(crossCompileFlags, "go", "build", "-o", "shaper.websvc", "./e2e/shaper/websvc") + if err != nil { + return err + } + + _ = os.Mkdir("./build/e2e/", os.ModeDir) + os.Rename("./shaper.test", "./build/e2e/shaper.test") + os.Rename("./shaper.websvc", "./build/e2e/shaper.websvc") + return nil +} + // BuildE2eDeployerBinary builds the deployer binary for e2e tests. func BuildE2eDeployerBinary() error { return sh.RunWith(crossCompileFlags, "go", "build", "-o", "./build/e2e/deployer", "./e2e/blockchain/deployer.go") @@ -75,6 +93,24 @@ func TestE2EBasic() error { return runner.Test("myst-provider") } +// TestE2EShaper runs end-to-end tests +func TestE2EShaper() error { + logconfig.Bootstrap() + + mg.Deps(BuildE2eShaperTestBinary) + + composeFiles := []string{ + "./docker-compose.e2e-shaper.yml", + } + + runner, cleanup := e2e_shaper.NewRunner(composeFiles, "node_e2e_shaper_test", "") + defer cleanup() + if err := runner.Init(); err != nil { + return err + } + return runner.Test() +} + // TestE2ENAT runs end-to-end tests in NAT environment func TestE2ENAT() error { logconfig.Bootstrap() diff --git a/docker-compose.e2e-shaper.yml b/docker-compose.e2e-shaper.yml new file mode 100644 index 0000000000..a049a571b7 --- /dev/null +++ b/docker-compose.e2e-shaper.yml @@ -0,0 +1,25 @@ +version: '3.0' +services: + + shaper-websvc: + build: + context: . + dockerfile: ./e2e/shaper/websvc/Dockerfile + cap_add: + - NET_ADMIN + working_dir: /node + expose: + - 8083 + + #go runner to run go programs inside localnet (usefull for contract deployment or e2e test running) + go-runner: + depends_on: + - shaper-websvc + build: + context: . + dockerfile: ./e2e/gorunner-shaper/Dockerfile.precompiled + cap_add: + - NET_ADMIN + volumes: + - ./e2e/blockchain/keystore:/node/keystore + working_dir: /node diff --git a/e2e/gorunner-shaper/Dockerfile b/e2e/gorunner-shaper/Dockerfile new file mode 100644 index 0000000000..acc0ca2727 --- /dev/null +++ b/e2e/gorunner-shaper/Dockerfile @@ -0,0 +1,3 @@ +FROM golang:1.20-alpine + +RUN apk add --no-cache bash gcc musl-dev make linux-headers iptables ipset ca-certificates openvpn bash sudo openresolv diff --git a/e2e/gorunner-shaper/Dockerfile.precompiled b/e2e/gorunner-shaper/Dockerfile.precompiled new file mode 100644 index 0000000000..3eed44d7e7 --- /dev/null +++ b/e2e/gorunner-shaper/Dockerfile.precompiled @@ -0,0 +1,6 @@ +FROM alpine:3.12 + +RUN apk add --no-cache bash gcc musl-dev make linux-headers iptables ipset ca-certificates openvpn bash sudo openresolv +RUN ln -s /sbin/iptables /usr/sbin/iptables + +COPY ./build/e2e/shaper.test /usr/local/bin/shaper.test diff --git a/e2e/shaper/runner.go b/e2e/shaper/runner.go new file mode 100644 index 0000000000..24b3494807 --- /dev/null +++ b/e2e/shaper/runner.go @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 The "MysteriumNetwork/node" Authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package shaper + +import ( + "github.com/magefile/mage/sh" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" +) + +// NewRunner returns e2e test runners instance +func NewRunner(composeFiles []string, testEnv, services string) (runner *Runner, cleanup func()) { + fileArgs := make([]string, 0) + for _, f := range composeFiles { + fileArgs = append(fileArgs, "-f", f) + } + var args []string + args = append(args, fileArgs...) + args = append(args, "-p", testEnv) + + runner = &Runner{ + compose: sh.RunCmd("docker", append([]string{"compose"}, args...)...), + composeOut: sh.OutCmd("docker", append([]string{"compose"}, args...)...), + testEnv: testEnv, + services: services, + } + return runner, runner.cleanup +} + +// Runner is e2e tests runner responsible for starting test environment and running e2e tests. +type Runner struct { + compose func(args ...string) error + composeOut func(args ...string) (string, error) + etherPassphrase string + testEnv string + services string +} + +// Test starts given provider and consumer nodes and runs e2e tests. +func (r *Runner) Test() (retErr error) { + log.Info().Msg("Running tests for env: " + r.testEnv) + + err := r.compose("run", "go-runner", + "/usr/local/bin/shaper.test", + ) + + retErr = errors.Wrap(err, "tests failed!") + return +} + +func (r *Runner) cleanup() { + log.Info().Msg("Cleaning up") + + _ = r.compose("logs") + if err := r.compose("down", "--volumes", "--remove-orphans", "--timeout", "30"); err != nil { + log.Warn().Err(err).Msg("Cleanup error") + } +} + +// Init starts bug6022.test dependency +func (r *Runner) Init() error { + log.Info().Msg("Starting other services") + if err := r.compose("pull"); err != nil { + return errors.Wrap(err, "could not pull images") + } + + if err := r.compose("up", "-d", "shaper-websvc"); err != nil { + return errors.Wrap(err, "starting other services failed!") + } + + log.Info().Msg("Building app images") + if err := r.compose("build"); err != nil { + return errors.Wrap(err, "building app images failed!") + } + + return nil +} diff --git a/services/wireguard/endpoint/netstack-provider/shaper_service_test.go b/e2e/shaper/shaper_service_test.go similarity index 84% rename from services/wireguard/endpoint/netstack-provider/shaper_service_test.go rename to e2e/shaper/shaper_service_test.go index 4f4526f95a..2d4ec49fc3 100644 --- a/services/wireguard/endpoint/netstack-provider/shaper_service_test.go +++ b/e2e/shaper/shaper_service_test.go @@ -15,15 +15,17 @@ * along with this program. If not, see . */ -package netstack_provider +package shaper import ( "bytes" "encoding/hex" "io" "log" + "net" "net/http" "net/netip" + "net/url" "strings" "testing" @@ -33,10 +35,10 @@ import ( "github.com/mysteriumnetwork/node/config" netstack "github.com/mysteriumnetwork/node/services/wireguard/endpoint/netstack" + netstack_provider "github.com/mysteriumnetwork/node/services/wireguard/endpoint/netstack-provider" ) func startClient(t *testing.T, priv, pubServ wgtypes.Key) { - tun, tnet, err := netstack.CreateNetTUN( []netip.Addr{netip.MustParseAddr("192.168.4.100")}, []netip.Addr{netip.MustParseAddr("8.8.8.8")}, @@ -69,14 +71,26 @@ func startClient(t *testing.T, priv, pubServ wgtypes.Key) { }, } - resp, err := client.Get("http://107.173.23.19:8080/test") + // resolve docker container hostname + u, _ := url.Parse("http://shaper-websvc:8083/test") + address, err := net.LookupHost(u.Hostname()) if err != nil { t.Error(err) return } + u.Host = address[0] + ":" + u.Port() + + resp, err := client.Get(u.String()) + if err != nil { + t.Error(err) + log.Println(err) + return + } + body, err := io.ReadAll(resp.Body) if err != nil { t.Error(err) + log.Println(err) return } log.Println("Reply:", string(body)) @@ -87,12 +101,10 @@ func startClient(t *testing.T, priv, pubServ wgtypes.Key) { ok = "failed" } log.Println("Test result:", ok) - // dev.Down() - // tun.Close() } func startServer(t *testing.T, privKey, pubClinet wgtypes.Key) { - tun, _, _, err := CreateNetTUNWithStack( + tun, _, _, err := netstack_provider.CreateNetTUNWithStack( []netip.Addr{netip.MustParseAddr("192.168.4.1")}, 53, device.DefaultMTU, @@ -124,7 +136,9 @@ func TestShaperEnabled(t *testing.T) { config.Current.SetDefault(config.FlagShaperBandwidth.Name, "6250") config.Current.SetDefault(config.FlagShaperEnabled.Name, "true") - InitUserspaceShaper(nil) + config.FlagFirewallProtectedNetworks.Value = "10.0.0.0/8,127.0.0.0/8" // 192.168.0.0/16, + + netstack_provider.InitUserspaceShaper(nil) privKey1, err := wgtypes.GeneratePrivateKey() if err != nil { @@ -136,6 +150,8 @@ func TestShaperEnabled(t *testing.T) { t.Error(err) return } + _, _ = privKey1, privKey2 + startServer(t, privKey1, privKey2.PublicKey()) startClient(t, privKey2, privKey1.PublicKey()) } diff --git a/e2e/shaper/websvc/Dockerfile b/e2e/shaper/websvc/Dockerfile new file mode 100644 index 0000000000..15126cac1a --- /dev/null +++ b/e2e/shaper/websvc/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:3.12 + +COPY ./build/e2e/shaper.websvc /usr/local/bin/shaper.websvc + +ENTRYPOINT ["/usr/local/bin/shaper.websvc"] diff --git a/e2e/shaper/websvc/main.go b/e2e/shaper/websvc/main.go new file mode 100644 index 0000000000..ae49399d0c --- /dev/null +++ b/e2e/shaper/websvc/main.go @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 The "MysteriumNetwork/node" Authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package main + +import ( + "fmt" + "net/http" +) + +func main() { + http.HandleFunc("/", handler) + http.ListenAndServe(":8083", nil) +} + +func handler(w http.ResponseWriter, r *http.Request) { + fmt.Println(r.URL.Path, r.RemoteAddr) + fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:]) +}