From ad362c6111b800c694131649f90a814283e7296e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20SZKIBA?= Date: Tue, 15 Oct 2024 17:41:32 +0200 Subject: [PATCH] feat: separate extension and driver registration --- drivers/drivers.go | 23 +++ examples/mysql_secure_test.js | 37 ----- go.mod | 56 ++++---- go.sum | 128 +++++++++-------- register.go | 15 ++ sql.go | 254 ---------------------------------- sql/drivers.go | 51 +++++++ sql/module.go | 111 +++++++++++++++ sql/module_test.go | 91 ++++++++++++ sql_test.go | 137 ------------------ 10 files changed, 394 insertions(+), 509 deletions(-) create mode 100644 drivers/drivers.go delete mode 100644 examples/mysql_secure_test.js create mode 100644 register.go delete mode 100644 sql.go create mode 100644 sql/drivers.go create mode 100644 sql/module.go create mode 100644 sql/module_test.go delete mode 100644 sql_test.go diff --git a/drivers/drivers.go b/drivers/drivers.go new file mode 100644 index 0000000..f6bf280 --- /dev/null +++ b/drivers/drivers.go @@ -0,0 +1,23 @@ +// Package drivers contains SQL driver initializations. +package drivers + +import ( + "github.com/grafana/xk6-sql/sql" + + // Blank imports required for initialization of drivers + _ "github.com/ClickHouse/clickhouse-go/v2" + _ "github.com/go-sql-driver/mysql" + _ "github.com/lib/pq" + _ "github.com/mattn/go-sqlite3" + _ "github.com/microsoft/go-mssqldb" + _ "github.com/microsoft/go-mssqldb/azuread" +) + +func init() { + sql.RegisterDriver("mysql") + sql.RegisterDriver("postgres") + sql.RegisterDriver("sqlite3") + sql.RegisterDriver("sqlserver") + sql.RegisterDriver("azuresql") + sql.RegisterDriver("clickhouse") +} diff --git a/examples/mysql_secure_test.js b/examples/mysql_secure_test.js deleted file mode 100644 index 2ad207a..0000000 --- a/examples/mysql_secure_test.js +++ /dev/null @@ -1,37 +0,0 @@ -import sql from 'k6/x/sql'; - -sql.loadTLS({ - enableTLS: true, - insecureSkipTLSverify: true, - minVersion: sql.TLS_1_2, - // Possible values: sql.TLS_1_0, sql.TLS_1_1, sql.TLS_1_2, sql.TLS_1_3 - caCertFile: 'ca.pem', - clientCertFile: 'client-cert.pem', - clientKeyFile: 'client-key.pem', -}); - -const db = sql.open('mysql', 'root:password@tcp(localhost:3306)/mysql') - -export function setup() { - db.exec(` - CREATE TABLE IF NOT EXISTS keyvalues ( - id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, - \`key\` VARCHAR(50) NOT NULL, - value VARCHAR(50) NULL - ); - `); -} - -export function teardown() { - db.close(); -} - -export default function () { - db.exec("INSERT INTO keyvalues (`key`, value) VALUES('plugin-name', 'k6-plugin-sql');"); - - let results = sql.query(db, "SELECT * FROM keyvalues WHERE `key` = ?;", 'plugin-name'); - for (const row of results) { - // Convert array of ASCII integers into strings. See https://github.com/grafana/xk6-sql/issues/12 - console.log(`key: ${String.fromCharCode(...row.key)}, value: ${String.fromCharCode(...row.value)}`); - } -} diff --git a/go.mod b/go.mod index 070f31b..dc63359 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/grafana/xk6-sql -go 1.21 +go 1.22 require ( github.com/go-sql-driver/mysql v1.7.1 @@ -8,14 +8,14 @@ require ( github.com/mattn/go-sqlite3 v1.14.18 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 - go.k6.io/k6 v0.51.1-0.20240610082146-1f01a9bc2365 + go.k6.io/k6 v0.54.0 ) require ( github.com/ClickHouse/clickhouse-go/v2 v2.22.0 - github.com/grafana/sobek v0.0.0-20240607083612-4f0cd64f4e78 + github.com/grafana/sobek v0.0.0-20240927094302-19dd311f018f github.com/microsoft/go-mssqldb v1.6.0 - github.com/spf13/afero v1.11.0 + github.com/proullon/ramsql v0.1.4 ) require ( @@ -25,15 +25,15 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 // indirect github.com/ClickHouse/ch-go v0.61.5 // indirect github.com/andybalholm/brotli v1.1.0 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dlclark/regexp2 v1.10.0 // indirect + github.com/dlclark/regexp2 v1.11.4 // indirect github.com/dop251/goja v0.0.0-20240516125602-ccbae20bcec2 // indirect github.com/evanw/esbuild v0.21.2 // indirect - github.com/fatih/color v1.16.0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/go-faster/city v1.0.1 // indirect github.com/go-faster/errors v0.7.1 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect github.com/golang-jwt/jwt/v5 v5.0.0 // indirect @@ -41,9 +41,9 @@ require ( github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/google/pprof v0.0.0-20231127191134-f3a68a39ae15 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.17.7 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -60,23 +60,25 @@ require ( github.com/segmentio/asm v1.2.0 // indirect github.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e // indirect github.com/shopspring/decimal v1.3.1 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect - go.opentelemetry.io/proto/otlp v1.1.0 // indirect - golang.org/x/crypto v0.24.0 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.33.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/sdk v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/time v0.6.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/guregu/null.v3 v3.5.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index f106da3..fe92ef0 100644 --- a/go.sum +++ b/go.sum @@ -14,23 +14,25 @@ github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeE github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg= github.com/ClickHouse/clickhouse-go/v2 v2.22.0 h1:LAdk0qT125PpSPnYepFQs5X5z1EwpAtIX10SUELPgi0= github.com/ClickHouse/clickhouse-go/v2 v2.22.0/go.mod h1:tBhdF3f3RdP7sS59+oBAtTyhWpy0024ZxDMhgxra0QE= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= -github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= +github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dop251/goja v0.0.0-20240516125602-ccbae20bcec2 h1:OFTHt+yJDo/uaIKMGjEKzc3DGhrpQZoqvMUIloZv6ZY= github.com/dop251/goja v0.0.0-20240516125602-ccbae20bcec2/go.mod h1:o31y53rb/qiIAONF7w3FHJZRqqP3fzHUr1HqanthByw= github.com/evanw/esbuild v0.21.2 h1:CLplcGi794CfHLVmUbvVfTMKkykm+nyIHU8SU60KUTA= github.com/evanw/esbuild v0.21.2/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= @@ -39,9 +41,11 @@ github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= +github.com/go-gorp/gorp v2.2.0+incompatible h1:xAUh4QgEeqPPhK3vxZN+bzrim1z5Av6q837gtjUlshc= +github.com/go-gorp/gorp v2.2.0+incompatible/go.mod h1:7IfkAQnO7jfT/9IQ3R9wL1dFhukN6aQxzKTHnkxzA/E= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q= @@ -80,18 +84,28 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/grafana/sobek v0.0.0-20240607083612-4f0cd64f4e78 h1:rVCZdB+13G+aQoGm3CBVaDGl0uxZxfjvQgEJy4IeHTA= -github.com/grafana/sobek v0.0.0-20240607083612-4f0cd64f4e78/go.mod h1:6ZH0b0iOxyigeTh+/IlGoL0Hd3lVXA94xoXf0ldNgCM= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= +github.com/grafana/sobek v0.0.0-20240927094302-19dd311f018f h1:9r05Uxs+Pq1UqZqGG/PoCUWd6xk2ab+mRWAM5xZgM9I= +github.com/grafana/sobek v0.0.0-20240927094302-19dd311f018f/go.mod h1:FmcutBFPLiGgroH42I4/HBahv7GxVjODcVWFTw1ISes= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -145,8 +159,10 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/proullon/ramsql v0.1.4 h1:yTFRTn46gFH/kPbzCx+mGjuFlyTBUeDr3h2ldwxddl0= +github.com/proullon/ramsql v0.1.4/go.mod h1:CFGqeQHQpdRfWqYmWD3yXqPTEaHkF4zgXy1C6qDWc9E= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e h1:zWKUYT07mGmVBH+9UgnHXd/ekCK99C8EbDSAt5qsjXE= @@ -170,33 +186,35 @@ github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgk github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.k6.io/k6 v0.51.1-0.20240610082146-1f01a9bc2365 h1:ZXlJs5hXt1hbY4k3jHVJS8xrgypgTZAwbMBVH1EMCgY= -go.k6.io/k6 v0.51.1-0.20240610082146-1f01a9bc2365/go.mod h1:LJKmFwUODAYoxitsJ3Xk+wsyVJDpyQiLyJAVn+oGyVQ= +go.k6.io/k6 v0.54.0 h1:ajkfOD5RiNocHD01+qk4Yr+Mlnn3nY+D9x8DQyhVpck= +go.k6.io/k6 v0.54.0/go.mod h1:FvmG/4rcYTMvNdi3EGYvZEr1OxINTtwTcMne8Q3bLQM= go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0Jwtl01UFiyWZEMiJZBiTlv5A50zNs8lsthXqIio= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -206,8 +224,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -229,17 +247,17 @@ golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -249,14 +267,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= +google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -265,8 +281,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -284,3 +300,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= +gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= diff --git a/register.go b/register.go new file mode 100644 index 0000000..ac52a9c --- /dev/null +++ b/register.go @@ -0,0 +1,15 @@ +// Package sql is the primary go package of the xk6-sql extension. +// Contains the registration of the xk6-sql extension as a k6 extension. +package sql + +import ( + // Blank imports required for initialization of drivers + _ "github.com/grafana/xk6-sql/drivers" + + "github.com/grafana/xk6-sql/sql" + "go.k6.io/k6/js/modules" +) + +func init() { + modules.Register(sql.ImportPath, sql.New()) +} diff --git a/sql.go b/sql.go deleted file mode 100644 index 0804717..0000000 --- a/sql.go +++ /dev/null @@ -1,254 +0,0 @@ -// Package sql provides a javascript module for performing SQL actions against relational databases -package sql - -import ( - "crypto/tls" - "crypto/x509" - dbsql "database/sql" - "encoding/json" - "fmt" - "os" - "strings" - - "github.com/go-sql-driver/mysql" - "github.com/grafana/sobek" - - // Blank imports required for initialization of drivers - _ "github.com/ClickHouse/clickhouse-go/v2" - _ "github.com/lib/pq" - _ "github.com/mattn/go-sqlite3" - _ "github.com/microsoft/go-mssqldb" - _ "github.com/microsoft/go-mssqldb/azuread" - "go.k6.io/k6/js/common" - "go.k6.io/k6/js/modules" - "go.k6.io/k6/lib/netext" -) - -// supportedTLSVersions is a map of TLS versions to their numeric values. -var supportedTLSVersions = map[string]uint16{ //nolint: gochecknoglobals - netext.TLS_1_0: tls.VersionTLS10, - netext.TLS_1_1: tls.VersionTLS11, - netext.TLS_1_2: tls.VersionTLS12, - netext.TLS_1_3: tls.VersionTLS13, -} - -func init() { - modules.Register("k6/x/sql", new(RootModule)) -} - -// RootModule is the global module object type. It is instantiated once per test -// run and will be used to create `k6/x/sql` module instances for each VU. -type RootModule struct{} - -// SQL represents an instance of the SQL module for every VU. -type SQL struct { - vu modules.VU - exports *sobek.Object - tlsConfig TLSConfig -} - -// Ensure the interfaces are implemented correctly. -var ( - _ modules.Module = &RootModule{} - _ modules.Instance = &SQL{} -) - -// NewModuleInstance implements the modules.Module interface to return -// a new instance for each VU. -func (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance { - runtime := vu.Runtime() - - moduleInstance := &SQL{ - vu: vu, - exports: runtime.NewObject(), - tlsConfig: TLSConfig{}, - } - // Export constants to the JS code. - moduleInstance.defineConstants() - - mustExport := func(name string, value interface{}) { - if err := moduleInstance.exports.Set(name, value); err != nil { - common.Throw(runtime, err) - } - } - mustExport("loadTLS", moduleInstance.LoadTLS) - mustExport("open", moduleInstance.Open) - mustExport("query", moduleInstance.Query) - - return moduleInstance -} - -// Exports implements the modules.Instance interface and returns the exports -// of the JS module. -func (sql *SQL) Exports() modules.Exports { - return modules.Exports{ - Default: sql.exports, - } -} - -// KeyValue is a simple key-value pair. -type KeyValue map[string]interface{} - -func contains(array []string, element string) bool { - for _, item := range array { - if item == element { - return true - } - } - return false -} - -// defineConstants defines the constants that can be used in the JS code. -func (sql *SQL) defineConstants() { - runtime := sql.vu.Runtime() - mustAddProp := func(name string, val interface{}) { - err := sql.exports.DefineDataProperty( - name, runtime.ToValue(val), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE, - ) - if err != nil { - common.Throw(runtime, err) - } - } - - // TLS versions - mustAddProp("TLS_1_0", netext.TLS_1_0) - mustAddProp("TLS_1_1", netext.TLS_1_1) - mustAddProp("TLS_1_2", netext.TLS_1_2) - mustAddProp("TLS_1_3", netext.TLS_1_3) -} - -// TLSConfig contains all the TLS configuration options passed between the JS and Go code. -type TLSConfig struct { - EnableTLS bool `json:"enableTLS"` - InsecureSkipTLSverify bool `json:"insecureSkipTLSverify"` - MinVersion string `json:"minVersion"` - CAcertFile string `json:"caCertFile"` - ClientCertFile string `json:"clientCertFile"` - ClientKeyFile string `json:"clientKeyFile"` -} - -// LoadTLS loads the TLS configuration for the SQL module. -func (sql *SQL) LoadTLS(params map[string]interface{}) { - runtime := sql.vu.Runtime() - var tlsConfig *TLSConfig - if b, err := json.Marshal(params); err != nil { - common.Throw(runtime, err) - } else { - if err := json.Unmarshal(b, &tlsConfig); err != nil { - common.Throw(runtime, err) - } - } - if _, ok := supportedTLSVersions[tlsConfig.MinVersion]; !ok { - common.Throw(runtime, fmt.Errorf("unsupported TLS version: %s", tlsConfig.MinVersion)) - } - sql.tlsConfig = *tlsConfig -} - -// Open establishes a connection to the specified database type using -// the provided connection string. -func (sql *SQL) Open(database string, connectionString string) (*dbsql.DB, error) { - supportedDatabases := []string{"mysql", "postgres", "sqlite3", "sqlserver", "azuresql", "clickhouse"} - if !contains(supportedDatabases, database) { - return nil, fmt.Errorf("database %s is not supported", database) - } - - if database == "mysql" && sql.tlsConfig.EnableTLS { - const tlsConfigKey = "custom" - if err := registerTLS(tlsConfigKey, sql.tlsConfig); err != nil { - return nil, err - } - connectionString = prefixConnectionString(connectionString, tlsConfigKey) - } - - db, err := dbsql.Open(database, connectionString) - if err != nil { - return nil, err - } - return db, nil -} - -// prefixConnectionString prefixes the connection string with the TLS configuration key. -func prefixConnectionString(connectionString string, tlsConfigKey string) string { - tlsParam := fmt.Sprintf("tls=%s", tlsConfigKey) - if strings.Contains(connectionString, tlsParam) { - return connectionString - } - var separator string - if strings.Contains(connectionString, "?") { - separator = "&" - } else { - separator = "?" - } - return fmt.Sprintf("%s%s%s", connectionString, separator, tlsParam) -} - -// registerTLS loads the ca-cert and registers the TLS configuration with the MySQL driver. -func registerTLS(tlsConfigKey string, tlsConfig TLSConfig) error { - rootCAs := x509.NewCertPool() - pem, err := os.ReadFile(tlsConfig.CAcertFile) //nolint: forbidigo - if err != nil { - return err - } - if ok := rootCAs.AppendCertsFromPEM(pem); !ok { - return fmt.Errorf("failed to append PEM") - } - - clientCerts := make([]tls.Certificate, 0, 1) - certs, err := tls.LoadX509KeyPair(tlsConfig.ClientCertFile, tlsConfig.ClientKeyFile) - if err != nil { - return err - } - clientCerts = append(clientCerts, certs) - - mysqlTLSConfig := &tls.Config{ - RootCAs: rootCAs, - Certificates: clientCerts, - MinVersion: supportedTLSVersions[tlsConfig.MinVersion], - InsecureSkipVerify: tlsConfig.InsecureSkipTLSverify, // #nosec G402 - } - return mysql.RegisterTLSConfig(tlsConfigKey, mysqlTLSConfig) -} - -// Query executes the provided query string against the database, while -// providing results as a slice of KeyValue instance(s) if available. -func (*SQL) Query(db *dbsql.DB, query string, args ...interface{}) ([]KeyValue, error) { - rows, err := db.Query(query, args...) - if err != nil { - return nil, err - } - - defer func() { - _ = rows.Close() - }() - if rows.Err() != nil { - return nil, rows.Err() - } - - cols, err := rows.Columns() - if err != nil { - return nil, err - } - - values := make([]interface{}, len(cols)) - valuePtrs := make([]interface{}, len(cols)) - result := make([]KeyValue, 0) - - for rows.Next() { - for i := range values { - valuePtrs[i] = &values[i] - } - - err = rows.Scan(valuePtrs...) - if err != nil { - return nil, err - } - - data := make(KeyValue, len(cols)) - for i, colName := range cols { - data[colName] = *valuePtrs[i].(*interface{}) //nolint:forcetypeassert - } - result = append(result, data) - } - - return result, nil -} diff --git a/sql/drivers.go b/sql/drivers.go new file mode 100644 index 0000000..97c3387 --- /dev/null +++ b/sql/drivers.go @@ -0,0 +1,51 @@ +package sql + +import ( + "sync" +) + +type registry struct { + mu sync.RWMutex + drivers map[string]struct{} +} + +var driverRegistry *registry //nolint:gochecknoglobals + +func init() { + driverRegistry = ®istry{ + drivers: make(map[string]struct{}), + } +} + +func (r *registry) register(driverName string) { + r.mu.Lock() + defer r.mu.Unlock() + + id := driverName + + r.drivers[id] = struct{}{} +} + +func (r *registry) lookup(id string) (bool, string) { + r.mu.RLock() + defer r.mu.RUnlock() + + _, found := r.drivers[id] + if !found { + return false, "" + } + + return true, id +} + +// RegisterDriver registers an SQL database driver. +func RegisterDriver(driverName string) { + driverRegistry.register(driverName) +} + +// lookupDriver search SQL database driver by id in the registry. +// Returns true and the driver name if the driver is registered, +// otherwise returns false and an empty string. +func lookupDriver(id string) (bool, string) { + return driverRegistry.lookup(id) +} diff --git a/sql/module.go b/sql/module.go new file mode 100644 index 0000000..7aea1b3 --- /dev/null +++ b/sql/module.go @@ -0,0 +1,111 @@ +// Package sql provides a javascript module for performing SQL actions against relational databases. +package sql + +import ( + "database/sql" + "errors" + "fmt" + + "go.k6.io/k6/js/modules" +) + +// ImportPath contains module's JavaScript import path. +const ImportPath = "k6/x/sql" + +// New creates a new instance of the extension's JavaScript module. +func New() modules.Module { + return new(rootModule) +} + +// rootModule is the global module object type. It is instantiated once per test +// run and will be used to create `k6/x/sql` module instances for each VU. +type rootModule struct{} + +// NewModuleInstance implements the modules.Module interface to return +// a new instance for each VU. +func (*rootModule) NewModuleInstance(_ modules.VU) modules.Instance { + instance := &module{} + + instance.exports.Default = instance + instance.exports.Named = map[string]interface{}{ + "open": instance.Open, + "query": instance.Query, + } + + return instance +} + +// module represents an instance of the JavaScript module for every VU. +type module struct { + exports modules.Exports +} + +// Exports is representation of ESM exports of a module. +func (mod *module) Exports() modules.Exports { + return mod.exports +} + +// KeyValue is a simple key-value pair. +type KeyValue map[string]interface{} + +// open establishes a connection to the specified database type using +// the provided connection string. +func (mod *module) Open(driverName string, connectionString string) (*sql.DB, error) { + registered, database := lookupDriver(driverName) + if !registered { + return nil, fmt.Errorf("%w: %s", errUnsupportedDatabase, database) + } + + db, err := sql.Open(database, connectionString) + if err != nil { + return nil, err + } + + return db, nil +} + +// query executes the provided query string against the database, while +// providing results as a slice of KeyValue instance(s) if available. +func (*module) Query(db *sql.DB, query string, args ...interface{}) ([]KeyValue, error) { + rows, err := db.Query(query, args...) + if err != nil { + return nil, err + } + + defer func() { + _ = rows.Close() + }() + if rows.Err() != nil { + return nil, rows.Err() + } + + cols, err := rows.Columns() + if err != nil { + return nil, err + } + + values := make([]interface{}, len(cols)) + valuePtrs := make([]interface{}, len(cols)) + result := make([]KeyValue, 0) + + for rows.Next() { + for i := range values { + valuePtrs[i] = &values[i] + } + + err = rows.Scan(valuePtrs...) + if err != nil { + return nil, err + } + + data := make(KeyValue, len(cols)) + for i, colName := range cols { + data[colName] = *valuePtrs[i].(*interface{}) //nolint:forcetypeassert + } + result = append(result, data) + } + + return result, nil +} + +var errUnsupportedDatabase = errors.New("unsupported database") diff --git a/sql/module_test.go b/sql/module_test.go new file mode 100644 index 0000000..f503eb0 --- /dev/null +++ b/sql/module_test.go @@ -0,0 +1,91 @@ +package sql_test + +import ( + "context" + "io" + "testing" + + "github.com/grafana/sobek" + "github.com/grafana/xk6-sql/sql" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + "go.k6.io/k6/js/common" + "go.k6.io/k6/js/modulestest" + "go.k6.io/k6/lib" + "go.k6.io/k6/lib/testutils" + "go.k6.io/k6/metrics" + + _ "github.com/proullon/ramsql/driver" +) + +// TestIntegration performs an integration test creating an ramsql database +func TestIntegration(t *testing.T) { + t.Parallel() + + rt := setupTestEnv(t) + + _, err := rt.RunString(` +const db = sql.open("ramsql", "testdb"); + +db.exec("CREATE TABLE test_table (id integer PRIMARY KEY AUTOINCREMENT, name varchar NOT NULL, value varchar);") + +for (let i = 0; i < 5; i++) { + db.exec("INSERT INTO test_table (name, value) VALUES ('name-" + i + "', 'value-" + i + "');") +} + +let all_rows = sql.query(db, "SELECT * FROM test_table;") +if (all_rows.length != 5) { + throw new Error("Expected all five rows to be returned; got " + all_rows.length) +} + +let one_row = sql.query(db, "SELECT * FROM test_table WHERE name = $1;", "name-2"); +if (one_row.length != 1) { + throw new Error("Expected single row to be returned; got " + one_row.length) +} + +let no_rows = sql.query(db, "SELECT * FROM test_table WHERE name = $1;", 'bogus-name'); +if (no_rows.length != 0) { + throw new Error("Expected no rows to be returned; got " + no_rows.length) +} + +db.close() +`) + require.NoError(t, err) +} + +func setupTestEnv(t *testing.T) *sobek.Runtime { + t.Helper() + + sql.RegisterDriver("ramsql") + + rt := sobek.New() + rt.SetFieldNameMapper(common.FieldNameMapper{}) + + testLog := logrus.New() + testLog.AddHook(&testutils.SimpleLogrusHook{ + HookedLevels: []logrus.Level{logrus.WarnLevel}, + }) + testLog.SetOutput(io.Discard) + + state := &lib.State{ + Options: lib.Options{ + SystemTags: metrics.NewSystemTagSet(metrics.TagVU), + }, + Logger: testLog, + Tags: lib.NewVUStateTags(metrics.NewRegistry().RootTagSet()), + } + + root := sql.New() + m := root.NewModuleInstance( + &modulestest.VU{ + RuntimeField: rt, + InitEnvField: &common.InitEnvironment{}, + CtxField: context.Background(), + StateField: state, + }, + ) + + require.NoError(t, rt.Set("sql", m.Exports().Default)) + + return rt +} diff --git a/sql_test.go b/sql_test.go deleted file mode 100644 index 89db9c9..0000000 --- a/sql_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package sql - -import ( - "context" - "io" - "testing" - - "github.com/spf13/afero" - - "github.com/grafana/sobek" - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.k6.io/k6/js/common" - "go.k6.io/k6/js/modulestest" - "go.k6.io/k6/lib" - "go.k6.io/k6/lib/testutils" - "go.k6.io/k6/metrics" -) - -// TestSQLiteIntegration performs an integration test creating an SQLite database -func TestSQLiteIntegration(t *testing.T) { - t.Parallel() - - fs := afero.NewOsFs() - - dbname := "intg_test.db" - t.Cleanup(func() { - if err := fs.Remove(dbname); err != nil { - logrus.Warn(err) - } - }) - - rt := setupTestEnv(t) - - _, err := rt.RunString(` -const db = sql.open("sqlite3", "` + dbname + `"); - -db.exec("DROP TABLE IF EXISTS test_table;") -db.exec("CREATE TABLE test_table (id integer PRIMARY KEY AUTOINCREMENT, key varchar NOT NULL, value varchar);") - -for (let i = 0; i < 5; i++) { - db.exec("INSERT INTO test_table (key, value) VALUES ('key-" + i + "', 'value-" + i + "');") -} - -let all_rows = sql.query(db, "SELECT * FROM test_table;") -if (all_rows.length != 5) { - throw new Error("Expected all five rows to be returned; got " + all_rows.length) -} - -let one_row = sql.query(db, "SELECT * FROM test_table WHERE key = $1;", "key-2"); -if (one_row.length != 1) { - throw new Error("Expected single row to be returned; got " + one_row.length) -} - -let no_rows = sql.query(db, "SELECT * FROM test_table WHERE key = $1;", 'bogus-key'); -if (no_rows.length != 0) { - throw new Error("Expected no rows to be returned; got " + no_rows.length) -} - -db.close() -`) - require.NoError(t, err) -} - -func setupTestEnv(t *testing.T) *sobek.Runtime { - rt := sobek.New() - rt.SetFieldNameMapper(common.FieldNameMapper{}) - - testLog := logrus.New() - testLog.AddHook(&testutils.SimpleLogrusHook{ - HookedLevels: []logrus.Level{logrus.WarnLevel}, - }) - testLog.SetOutput(io.Discard) - - state := &lib.State{ - Options: lib.Options{ - SystemTags: metrics.NewSystemTagSet(metrics.TagVU), - }, - Logger: testLog, - Tags: lib.NewVUStateTags(metrics.NewRegistry().RootTagSet()), - } - - root := &RootModule{} - m, ok := root.NewModuleInstance( - &modulestest.VU{ - RuntimeField: rt, - InitEnvField: &common.InitEnvironment{}, - CtxField: context.Background(), - StateField: state, - }, - ).(*SQL) - require.True(t, ok) - require.NoError(t, rt.Set("sql", m.Exports().Default)) - - return rt -} - -func TestPrefixConnectionString(t *testing.T) { - t.Parallel() - - testCases := []struct { - name string - connectionString string - want string - }{ - { - name: "HappyPath", - connectionString: "root:password@tcp(localhost:3306)/mysql", - want: "root:password@tcp(localhost:3306)/mysql?tls=custom", - }, - { - name: "WithExistingParams", - connectionString: "root:password@tcp(localhost:3306)/mysql?param=value", - want: "root:password@tcp(localhost:3306)/mysql?param=value&tls=custom", - }, - { - name: "WithExistingTLSparam", - connectionString: "root:password@tcp(localhost:3306)/mysql?tls=custom", - want: "root:password@tcp(localhost:3306)/mysql?tls=custom", - }, - { - name: "WithExistingTLSparam", - connectionString: "root:password@tcp(localhost:3306)/mysql?tls=notcustom", - want: "root:password@tcp(localhost:3306)/mysql?tls=notcustom&tls=custom", - }, - } - - for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - got := prefixConnectionString(tc.connectionString, "custom") - assert.Equal(t, tc.want, got) - }) - } -}