Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evlekht/e2e #83

Draft
wants to merge 37 commits into
base: dev
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8c0ac9d
wip
evlekht Jan 22, 2025
251f420
partner plugin
evlekht Jan 22, 2025
2321eb7
wip
evlekht Jan 27, 2025
1f8a43e
wip
evlekht Jan 27, 2025
9003e5f
wip
evlekht Jan 28, 2025
1fb8533
wip
evlekht Jan 28, 2025
8ba24da
wip
evlekht Jan 28, 2025
3c304c8
remove ginkgo
evlekht Feb 12, 2025
7047336
codegen / shellcheck wip
evlekht Feb 12, 2025
90d3b0a
remove ginkgo
evlekht Feb 12, 2025
4961f93
vs code readme
evlekht Feb 12, 2025
b1347c7
codegen
evlekht Feb 12, 2025
a42874c
codegen
evlekht Feb 12, 2025
02675dc
generated
evlekht Feb 12, 2025
b48c107
cleanup, script
evlekht Feb 12, 2025
4b51a94
lint
evlekht Feb 12, 2025
8582322
split shellcheck into its own job
evlekht Feb 12, 2025
a64fb0d
license headers
evlekht Feb 12, 2025
506a6ce
shellcheck
evlekht Feb 12, 2025
e6701ef
fix codegen
evlekht Feb 12, 2025
c3ed2d4
license headers
evlekht Feb 12, 2025
656016e
caminogo/caminoethvm license headers
evlekht Feb 12, 2025
8ea2efc
test golangci installation
mo-c4t Feb 14, 2025
4f8edbd
license
evlekht Feb 13, 2025
8a4e674
Move caminogo/eth duplicate to its own repo
evlekht Feb 13, 2025
5cfa6ce
fix shellcheck
mo-c4t Feb 14, 2025
f57cb92
fix shellcheck
mo-c4t Feb 14, 2025
206dd23
fix shellcheck issue with go test
mo-c4t Feb 14, 2025
d2d1552
fix shellcheck errors
mo-c4t Feb 17, 2025
e1b4f1d
test fixing geenrated files
mo-c4t Feb 17, 2025
96a95b4
test fixing generated files
mo-c4t Feb 17, 2025
f3fee66
test fixing generated files
mo-c4t Feb 17, 2025
c6ebc50
fix shellcheck
mo-c4t Feb 17, 2025
319d1e1
cleanup & rework port manager
evlekht Feb 14, 2025
b887406
wip
evlekht Feb 17, 2025
3e16d78
wip
evlekht Feb 17, 2025
6d609fb
cleanup
evlekht Feb 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
wip
evlekht committed Jan 27, 2025
commit 8c0ac9dc10f9e2a9f1330904892d90bb1297c15e
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
build
tests/e2e/e2e.test

.vscode
.idea
4 changes: 2 additions & 2 deletions internal/matrix/matrix_messenger.go
Original file line number Diff line number Diff line change
@@ -131,7 +131,7 @@ func (m *messenger) StartReceiver() (id.UserID, error) {
return "", err
}

signature, message, err := signPublicKey(m.botKey)
signature, message, err := SignPublicKey(m.botKey)
if err != nil {
return "", err
}
@@ -206,7 +206,7 @@ func (m *messenger) Inbound() chan types.Message {
return m.msgChannel
}

func signPublicKey(key *ecdsa.PrivateKey) (signature string, message string, err error) {
func SignPublicKey(key *ecdsa.PrivateKey) (signature string, message string, err error) {
pubKeyBytes := crypto.FromECDSAPub(&key.PublicKey)
signatureBytes, err := sign(pubKeyBytes, key)
if err != nil {
229 changes: 229 additions & 0 deletions tests/e2e/bot/bot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
package bot

import (
"context"
"fmt"
"io"
"log"
"os"
"os/exec"
"path"
"time"

"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/accommodation/v1/accommodationv1grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/accommodation/v2/accommodationv2grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/activity/v1/activityv1grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/activity/v2/activityv2grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/book/v1/bookv1grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/book/v2/bookv2grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/info/v1/infov1grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/info/v2/infov2grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/insurance/v1/insurancev1grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/ping/v1/pingv1grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/seat_map/v1/seat_mapv1grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/seat_map/v2/seat_mapv2grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/transport/v1/transportv1grpc"
"buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/transport/v2/transportv2grpc"
"github.com/chain4travel/camino-messenger-bot/config"
"github.com/chain4travel/camino-messenger-bot/proto/pb/readiness"
"github.com/chain4travel/camino-messenger-bot/tests/e2e/process"
"github.com/go-viper/mapstructure/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"gopkg.in/yaml.v3"
)

const botRequestTickerInterval = 500 * time.Millisecond

func StartNewBot(
ctx context.Context,
botDir string,
botBinPath string,
config config.UnparsedConfig,
w io.Writer,
) (*Bot, chan error, error) {
// TODO@ ensure that no other cmb is running on this port ?
if err := os.RemoveAll(botDir); err != nil {
return nil, nil, fmt.Errorf("failed to remove bot data dir: %w", err)
}

if err := os.MkdirAll(botDir, 0755); err != nil {
return nil, nil, fmt.Errorf("failed to create bot data dir: %w", err)
}

unparsedMap := &map[string]any{}
if err := mapstructure.Decode(config, unparsedMap); err != nil {
return nil, nil, fmt.Errorf("failed to parse config into map: %w", err)
}
configBytes, err := yaml.Marshal(unparsedMap)
if err != nil {
return nil, nil, fmt.Errorf("failed to marshal config map into yaml: %w", err)
}

configPath := path.Join(botDir, "config.yaml")

if err := os.WriteFile(configPath, configBytes, 0644); err != nil {
return nil, nil, fmt.Errorf("failed to write config file: %w", err)
}

cmd := exec.Command(botBinPath, "--config", configPath)
cmd.Stdout = w

if err := cmd.Start(); err != nil {
return nil, nil, fmt.Errorf("failed to start bot (%d): %w", cmd.Process.Pid, err)
}

clientConnection, err := grpc.NewClient(
fmt.Sprintf("localhost:%d", config.RPCServer.Port),
grpc.WithTransportCredentials(insecure.NewCredentials()), // TODO@ configure from config
)
if err != nil {
return nil, nil, fmt.Errorf("failed to create grpc client: %w", err)
}

b := &Bot{
pid: cmd.Process.Pid,
rpcClient: newRPCClient(clientConnection),
}

b.awaitReady(ctx)

log.Printf("bot (%d) started\n", cmd.Process.Pid)

return b, process.ListenForProcessError(cmd), nil
}

type Bot struct {
pid int

*rpcClient
}

func (b *Bot) Stop(ctx context.Context) error {
if err := process.StopProcess(ctx, b.pid); err != nil {
return fmt.Errorf("failed to stop cmb process with pid %d: %w", b.pid, err)
}
return nil
}

func (b *Bot) Client() *rpcClient {
return b.rpcClient
}

func (b *Bot) awaitReady(ctx context.Context) error {
ticker := time.NewTicker(botRequestTickerInterval)
defer ticker.Stop()

for {
res, err := b.rpcClient.Readiness(ctx, nil)
if err == nil && res.Status == "ready" {
return nil
}

select {
case <-ticker.C:
case <-ctx.Done():
return ctx.Err()
}
}
}

// TODO@ codegen
func newRPCClient(connection *grpc.ClientConn) *rpcClient {
return &rpcClient{
ReadinessServiceClient: readiness.NewReadinessServiceClient(connection),

accommodationProductInfoV1: accommodationv1grpc.NewAccommodationProductInfoServiceClient(connection),
accommodationProductListV1: accommodationv1grpc.NewAccommodationProductListServiceClient(connection),
accommodationSearchV1: accommodationv1grpc.NewAccommodationSearchServiceClient(connection),

accommodationProductInfoV2: accommodationv2grpc.NewAccommodationProductInfoServiceClient(connection),
accommodationProductListV2: accommodationv2grpc.NewAccommodationProductListServiceClient(connection),
accommodationSearchV2: accommodationv2grpc.NewAccommodationSearchServiceClient(connection),

activityProductInfoV1: activityv1grpc.NewActivityProductInfoServiceClient(connection),
activityProductListV1: activityv1grpc.NewActivityProductListServiceClient(connection),
activitySearchV1: activityv1grpc.NewActivitySearchServiceClient(connection),

activityProductInfoV2: activityv2grpc.NewActivityProductInfoServiceClient(connection),
activityProductListV2: activityv2grpc.NewActivityProductListServiceClient(connection),
activitySearchV2: activityv2grpc.NewActivitySearchServiceClient(connection),

mintV1: bookv1grpc.NewMintServiceClient(connection),
validationV1: bookv1grpc.NewValidationServiceClient(connection),

mintV2: bookv2grpc.NewMintServiceClient(connection),
validationV2: bookv2grpc.NewValidationServiceClient(connection),

countryEntryRequirementsV1: infov1grpc.NewCountryEntryRequirementsServiceClient(connection),

countryEntryRequirementsV2: infov2grpc.NewCountryEntryRequirementsServiceClient(connection),

insuranceProductInfoV1: insurancev1grpc.NewInsuranceProductInfoServiceClient(connection),
insuranceProductListV1: insurancev1grpc.NewInsuranceProductListServiceClient(connection),
insuranceSearchV1: insurancev1grpc.NewInsuranceSearchServiceClient(connection),

pingV1: pingv1grpc.NewPingServiceClient(connection),

seatMapAvailabilityV1: seat_mapv1grpc.NewSeatMapAvailabilityServiceClient(connection),

seatMapAvailabilityV2: seat_mapv2grpc.NewSeatMapAvailabilityServiceClient(connection),

transportSearchV1: transportv1grpc.NewTransportSearchServiceClient(connection),

transportSearchV2: transportv2grpc.NewTransportSearchServiceClient(connection),
}
}

// TODO@ codegen
type rpcClient struct {
readiness.ReadinessServiceClient

// accommodation
accommodationProductInfoV1 accommodationv1grpc.AccommodationProductInfoServiceClient
accommodationProductListV1 accommodationv1grpc.AccommodationProductListServiceClient
accommodationSearchV1 accommodationv1grpc.AccommodationSearchServiceClient

accommodationProductInfoV2 accommodationv2grpc.AccommodationProductInfoServiceClient
accommodationProductListV2 accommodationv2grpc.AccommodationProductListServiceClient
accommodationSearchV2 accommodationv2grpc.AccommodationSearchServiceClient

// activity
activityProductInfoV1 activityv1grpc.ActivityProductInfoServiceClient
activityProductListV1 activityv1grpc.ActivityProductListServiceClient
activitySearchV1 activityv1grpc.ActivitySearchServiceClient

activityProductInfoV2 activityv2grpc.ActivityProductInfoServiceClient
activityProductListV2 activityv2grpc.ActivityProductListServiceClient
activitySearchV2 activityv2grpc.ActivitySearchServiceClient

// book
mintV1 bookv1grpc.MintServiceClient
validationV1 bookv1grpc.ValidationServiceClient

mintV2 bookv2grpc.MintServiceClient
validationV2 bookv2grpc.ValidationServiceClient

// info
countryEntryRequirementsV1 infov1grpc.CountryEntryRequirementsServiceClient

countryEntryRequirementsV2 infov2grpc.CountryEntryRequirementsServiceClient

// insurance
insuranceProductInfoV1 insurancev1grpc.InsuranceProductInfoServiceClient
insuranceProductListV1 insurancev1grpc.InsuranceProductListServiceClient
insuranceSearchV1 insurancev1grpc.InsuranceSearchServiceClient

// ping
pingV1 pingv1grpc.PingServiceClient

// seat map
seatMapAvailabilityV1 seat_mapv1grpc.SeatMapAvailabilityServiceClient

seatMapAvailabilityV2 seat_mapv2grpc.SeatMapAvailabilityServiceClient

// transport
transportSearchV1 transportv1grpc.TransportSearchServiceClient

transportSearchV2 transportv2grpc.TransportSearchServiceClient
}
106 changes: 106 additions & 0 deletions tests/e2e/bot/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package bot

import (
"context"
"crypto/ecdsa"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"math/big"
"path"
"strconv"

"github.com/chain4travel/camino-messenger-bot/config"
"github.com/chain4travel/camino-messenger-bot/tests/e2e/conduit"
"github.com/chain4travel/camino-messenger-bot/tests/e2e/node"
"github.com/ethereum/go-ethereum/crypto"
)

var DefaultCMAccountOwnerFunds = big.NewInt(0).Mul(node.CAM, big.NewInt(100))

type Factory struct {
dir string
binPath string
migrationsPath string
networkClient *node.Client
matrix *conduit.MatrixServer
}

// NewFactory creates a new bot factory.
func NewFactory(
e2eTmpDir string,
binPath string,
migrationsDir string,
networkClient *node.Client,
matrix *conduit.MatrixServer,
) *Factory {
return &Factory{
dir: path.Join(e2eTmpDir, "cmb"),
binPath: binPath,
migrationsPath: "file://" + migrationsDir,
networkClient: networkClient,
matrix: matrix,
}
}

// CreateBot creates a new bot.
func (f *Factory) CreateBot(ctx context.Context, port uint64, out io.Writer) (*Bot, chan error, error) {
key, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate key: %w", err)
}

ownerAddr := crypto.PubkeyToAddress(key.PublicKey)

cmAccountAddress, _, err := f.networkClient.CreateCMAccount(ctx, key)
if err != nil {
return nil, nil, fmt.Errorf("failed to create CM account: %w", err)
}

if err := f.networkClient.Transfer(ctx, f.networkClient.PrefundedKeys()[0], ownerAddr, DefaultCMAccountOwnerFunds); err != nil {
return nil, nil, fmt.Errorf("failed to transfer funds to cm account owner: %w", err)
}

if err := f.networkClient.AddBotToCMAccount(ctx, cmAccountAddress, key, ownerAddr); err != nil {
return nil, nil, fmt.Errorf("failed to add bot to CM account: %w", err)
}

botDir := path.Join(f.dir, strconv.FormatUint(port, 10)) // TODO@ add some more suffix to make bots form different tests unique 100%

return StartNewBot(
ctx,
botDir,
f.binPath,
config.UnparsedConfig{
DeveloperMode: true,
BotKey: hex.EncodeToString(crypto.FromECDSA(key)),
CMAccountAddress: cmAccountAddress.Hex(),
ChainRPCURL: f.networkClient.ChainRPCURL(),
BookingTokenAddress: f.networkClient.BookingTokenContractAddress().Hex(),
NetworkFeeRecipientBotAddress: f.matrix.NetworkFeeRecipientBotAddress().Hex(),
NetworkFeeRecipientCMAccountAddress: f.matrix.NetworkFeeRecipientCMAccountAddress().Hex(),
ChequeExpirationTime: 3600 * 24 * 30 * 7, // 7 months
MinChequeDurationUntilExpiration: 3600 * 24 * 30 * 6, // 6 months
CashInPeriod: 3600, // 1h
ResponseTimeout: 30000, // 30s
PartnerPlugin: config.PartnerPluginConfig{
Enabled: false,
Host: "",
Unencrypted: true,
},
RPCServer: config.RPCServerConfig{
Enabled: true,
Port: port,
Unencrypted: true,
},
Matrix: config.UnparsedMatrixConfig{Host: f.matrix.Host().String()},
DB: config.UnparsedSQLiteDBConfig{
DBPath: path.Join(botDir, "db"),
MigrationsPath: f.migrationsPath,
},
Tracing: config.TracingConfig{Enabled: false},
},
out,
)
}
1 change: 1 addition & 0 deletions tests/e2e/caminogo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
We had to copy all those files because of packages incompatiblity. Once we'll update caminogo with latest cortinas, so it will switch to x/exp 2023, the issue will resolve most likely and we can then use caminogo/evm packages.
Loading