diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 5d08764..5559891 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -32,9 +32,14 @@ jobs: - name: Build run: go build ./cmd/oms - - - name: Test + + - name: Unit Tests run: go test ./... + - name: Integration Tests + if: matrix.os == 'ubuntu-latest' + run: go test -tags=integration ./... + - name: Coverage - run: make unit-test-coverage functional-test-coverage coverage-report + if: matrix.os == 'ubuntu-latest' + run: make unit-test-coverage integration-test-coverage coverage-report diff --git a/Dockerfile b/Dockerfile index fefcbcd..7007b49 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,8 +26,6 @@ EXPOSE 8081 EXPOSE 8082 EXPOSE 8083 EXPOSE 8084 -VOLUME /data -ENV DATA_DIR=/data COPY --from=oms-builder /usr/local/bin/oms /usr/local/bin/oms diff --git a/Makefile b/Makefile index c5cdd7d..d713dea 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,21 @@ TEST_COVERAGE_OUTPUT_ROOT := $(CURDIR)/.coverage/unit -FUNCTIONAL_COVERAGE_OUTPUT_ROOT := $(CURDIR)/.coverage/functional +INTEGRATION_COVERAGE_OUTPUT_ROOT := $(CURDIR)/.coverage/integration COVERAGE_PROFILE := $(CURDIR)/.coverage/profile COVERAGE_REPORT := $(CURDIR)/.coverage/report.html -test: unit-test functional-test +test: unit-test integration-test unit-test: go test ./app/{billing,order,shipment} -functional-test: - go test ./app/test - +integration-test: + go test -tags=integration ./app/test + $(TEST_COVERAGE_OUTPUT_ROOT): mkdir -p $(TEST_COVERAGE_OUTPUT_ROOT) -$(FUNCTIONAL_COVERAGE_OUTPUT_ROOT): - mkdir -p $(FUNCTIONAL_COVERAGE_OUTPUT_ROOT) +$(INTEGRATION_COVERAGE_OUTPUT_ROOT): + mkdir -p $(INTEGRATION_COVERAGE_OUTPUT_ROOT) $(SUMMARY_COVERAGE_OUTPUT_ROOT): mkdir -p $(SUMMARY_COVERAGE_OUTPUT_ROOT) @@ -26,12 +26,12 @@ unit-test-coverage: $(TEST_COVERAGE_OUTPUT_ROOT) go test -cover ./app/order -args -test.gocoverdir=$(TEST_COVERAGE_OUTPUT_ROOT) go test -cover ./app/shipment -args -test.gocoverdir=$(TEST_COVERAGE_OUTPUT_ROOT) -functional-test-coverage: $(FUNCTIONAL_COVERAGE_OUTPUT_ROOT) - @echo Functional test coverage - go test -cover ./app/test -coverpkg ./... -args -test.gocoverdir=$(FUNCTIONAL_COVERAGE_OUTPUT_ROOT) +integration-test-coverage: $(INTEGRATION_COVERAGE_OUTPUT_ROOT) + @echo Integration test coverage + go test -tags integration -cover ./app/test -coverpkg ./... -args -test.gocoverdir=$(INTEGRATION_COVERAGE_OUTPUT_ROOT) -coverage-report: $(TEST_COVERAGE_OUTPUT_ROOT) $(FUNCTIONAL_COVERAGE_OUTPUT_ROOT) $(SUMMARY_COVERAGE_OUTPUT_ROOT) +coverage-report: $(TEST_COVERAGE_OUTPUT_ROOT) $(INTEGRATION_COVERAGE_OUTPUT_ROOT) $(SUMMARY_COVERAGE_OUTPUT_ROOT) @echo Summary coverage report - go tool covdata textfmt -i $(TEST_COVERAGE_OUTPUT_ROOT),$(FUNCTIONAL_COVERAGE_OUTPUT_ROOT) -o $(COVERAGE_PROFILE) - go tool covdata percent -i $(TEST_COVERAGE_OUTPUT_ROOT),$(FUNCTIONAL_COVERAGE_OUTPUT_ROOT) - go tool cover -html=$(COVERAGE_PROFILE) -o $(COVERAGE_REPORT) \ No newline at end of file + go tool covdata textfmt -i $(TEST_COVERAGE_OUTPUT_ROOT),$(INTEGRATION_COVERAGE_OUTPUT_ROOT) -o $(COVERAGE_PROFILE) + go tool covdata percent -i $(TEST_COVERAGE_OUTPUT_ROOT),$(INTEGRATION_COVERAGE_OUTPUT_ROOT) + go tool cover -html=$(COVERAGE_PROFILE) -o $(COVERAGE_REPORT) diff --git a/app/config/config.go b/app/config/config.go index 5748875..90e3e67 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -9,7 +9,7 @@ import ( // AppConfig is a struct that holds the configuration for the Order/Shipment/Fraud/Billing system. type AppConfig struct { BindOnIP string - DataDir string + MongoURL string BillingPort int32 BillingURL string OrderPort int32 @@ -44,7 +44,7 @@ func (c *AppConfig) ServiceHostPort(service string) (string, error) { func AppConfigFromEnv() (AppConfig, error) { conf := AppConfig{ BindOnIP: "127.0.0.1", - DataDir: "./", + MongoURL: "", BillingPort: 8081, BillingURL: "http://127.0.0.1:8081", OrderPort: 8082, @@ -59,8 +59,8 @@ func AppConfigFromEnv() (AppConfig, error) { conf.BindOnIP = ip } - if p := os.Getenv("DATA_DIR"); p != "" { - conf.DataDir = p + if p := os.Getenv("MONGO_URL"); p != "" { + conf.MongoURL = p } if p := os.Getenv("BILLING_API_URL"); p != "" { diff --git a/app/db/db.go b/app/db/db.go new file mode 100644 index 0000000..a9e5ca8 --- /dev/null +++ b/app/db/db.go @@ -0,0 +1,211 @@ +package db + +import ( + "context" + _ "embed" + "fmt" + "time" + + "github.com/jmoiron/sqlx" + "github.com/temporalio/reference-app-orders-go/app/config" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + mongodb "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + _ "modernc.org/sqlite" // SQLite driver +) + +// OrdersCollection is the name of the MongoDB collection to use for Orders. +const OrdersCollection = "orders" + +// OrderStatus is a struct that represents the status of an Order +type OrderStatus struct { + ID string `db:"id" bson:"id"` + CustomerID string `db:"customer_id" bson:"customer_id"` + Status string `db:"status" bson:"status"` + + ReceivedAt time.Time `db:"received_at" bson:"received_at"` +} + +// ShipmentStatus is a struct that represents the status of a Shipment +type ShipmentStatus struct { + ID string `db:"id" bson:"id"` + Status string `db:"status" bson:"status"` +} + +// ShipmentCollection is the name of the MongoDB collection to use for Shipment data. +const ShipmentCollection = "shipments" + +// DB is an interface that defines the methods that a database driver must implement +type DB interface { + Connect(ctx context.Context) error + Setup() error + Close() error + InsertOrder(context.Context, *OrderStatus) error + UpdateOrderStatus(context.Context, string, string) error + GetOrders(context.Context, *[]OrderStatus) error + UpdateShipmentStatus(context.Context, string, string) error + GetShipments(context.Context, *[]ShipmentStatus) error +} + +// CreateDB creates a new DB instance based on the configuration +func CreateDB(config config.AppConfig) DB { + if config.MongoURL != "" { + return &MongoDB{uri: config.MongoURL} + } + + return &SQLiteDB{path: "./api-store.db"} +} + +// MongoDB is a struct that implements the DB interface for MongoDB +type MongoDB struct { + uri string + client *mongo.Client + db *mongo.Database +} + +// Connect connects to a MongoDB instance +func (m *MongoDB) Connect(ctx context.Context) error { + client, err := mongo.Connect(ctx, options.Client().ApplyURI(m.uri)) + if err != nil { + return err + } + m.client = client + m.db = client.Database("orders") + return nil +} + +// Setup sets up the MongoDB instance +func (m *MongoDB) Setup() error { + orders := m.db.Collection(OrdersCollection) + _, err := orders.Indexes().CreateOne(context.TODO(), mongodb.IndexModel{ + Keys: map[string]interface{}{"received_at": 1}, + }) + if err != nil { + return fmt.Errorf("failed to create orders index: %w", err) + } + + shipments := m.db.Collection(ShipmentCollection) + _, err = shipments.Indexes().CreateOne(context.TODO(), mongodb.IndexModel{ + Keys: map[string]interface{}{"booked_at": 1}, + }) + if err != nil { + return fmt.Errorf("failed to create shipment index: %w", err) + } + + return nil +} + +// InsertOrder inserts an Order into the MongoDB instance +func (m *MongoDB) InsertOrder(ctx context.Context, order *OrderStatus) error { + _, err := m.db.Collection(OrdersCollection).InsertOne(ctx, order) + return err +} + +// UpdateOrderStatus updates an Order in the MongoDB instance +func (m *MongoDB) UpdateOrderStatus(ctx context.Context, id string, status string) error { + _, err := m.db.Collection(OrdersCollection).UpdateOne(ctx, bson.M{"id": id}, bson.M{"$set": bson.M{"status": status}}) + return err +} + +// GetOrders returns a list of Orders from the MongoDB instance +func (m *MongoDB) GetOrders(ctx context.Context, result *[]OrderStatus) error { + res, err := m.db.Collection(OrdersCollection).Find(ctx, bson.M{}, &options.FindOptions{ + Sort: bson.M{"received_at": 1}, + }) + if err != nil { + return err + } + + return res.All(ctx, result) +} + +// UpdateShipmentStatus updates a Shipment in the MongoDB instance +func (m *MongoDB) UpdateShipmentStatus(ctx context.Context, id string, status string) error { + _, err := m.db.Collection(ShipmentCollection).UpdateOne( + ctx, + bson.M{"id": id}, + bson.M{ + "$set": bson.M{"status": status}, + "$setOnInsert": bson.M{"booked_at": time.Now().UTC()}, + }, + options.Update().SetUpsert(true), + ) + return err +} + +// GetShipments returns a list of Shipments from the MongoDB instance +func (m *MongoDB) GetShipments(ctx context.Context, result *[]ShipmentStatus) error { + res, err := m.db.Collection(ShipmentCollection).Find(ctx, bson.M{}, &options.FindOptions{ + Sort: bson.M{"booked_at": 1}, + }) + if err != nil { + return err + } + + return res.All(ctx, result) +} + +// Close closes the connection to the MongoDB instance +func (m *MongoDB) Close() error { + return m.client.Disconnect(context.Background()) +} + +// SQLiteDB is a struct that implements the DB interface for SQLite +type SQLiteDB struct { + path string + db *sqlx.DB +} + +//go:embed schema.sql +var sqliteSchema string + +// Connect connects to a SQLite instance +func (s *SQLiteDB) Connect(_ context.Context) error { + db, err := sqlx.Connect("sqlite", s.path) + if err != nil { + return err + } + s.db = db + db.SetMaxOpenConns(1) // SQLite does not support concurrent writes + return nil +} + +// Setup sets up the SQLite instance +func (s *SQLiteDB) Setup() error { + _, err := s.db.Exec(sqliteSchema) + return err +} + +// Close closes the connection to the SQLite instance +func (s *SQLiteDB) Close() error { + return s.db.Close() +} + +// InsertOrder inserts an Order into the SQLite instance +func (s *SQLiteDB) InsertOrder(ctx context.Context, order *OrderStatus) error { + _, err := s.db.NamedExecContext(ctx, "INSERT OR IGNORE INTO orders (id, customer_id, received_at, status) VALUES (:id, :customer_id, :received_at, :status)", order) + return err +} + +// UpdateOrderStatus updates an Order in the SQLite instance +func (s *SQLiteDB) UpdateOrderStatus(ctx context.Context, id string, status string) error { + _, err := s.db.ExecContext(ctx, "UPDATE orders SET status = ? WHERE id = ?", status, id) + return err +} + +// GetOrders returns a list of Orders from the SQLite instance +func (s *SQLiteDB) GetOrders(ctx context.Context, result *[]OrderStatus) error { + return s.db.SelectContext(ctx, result, "SELECT id, status, received_at FROM orders ORDER BY received_at DESC") +} + +// UpdateShipmentStatus updates a Shipment in the SQLite instance +func (s *SQLiteDB) UpdateShipmentStatus(ctx context.Context, id string, status string) error { + _, err := s.db.ExecContext(ctx, "INSERT INTO shipments (id, booked_at, status) VALUES (?, ?, ?) ON CONFLICT(id) DO UPDATE SET status = ?", id, time.Now().UTC(), status, status) + return err +} + +// GetShipments returns a list of Shipments from the SQLite instance +func (s *SQLiteDB) GetShipments(ctx context.Context, result *[]ShipmentStatus) error { + return s.db.SelectContext(ctx, result, "SELECT id, status FROM shipments ORDER BY booked_at DESC") +} diff --git a/app/server/schema.sql b/app/db/schema.sql similarity index 100% rename from app/server/schema.sql rename to app/db/schema.sql diff --git a/app/fraud/api_test.go b/app/fraud/api_test.go index 96ede6b..a219bbc 100644 --- a/app/fraud/api_test.go +++ b/app/fraud/api_test.go @@ -9,7 +9,6 @@ import ( "github.com/stretchr/testify/require" "github.com/temporalio/reference-app-orders-go/app/fraud" - _ "modernc.org/sqlite" ) func TestMaintenanceMode(t *testing.T) { diff --git a/app/order/api.go b/app/order/api.go index b30fa9b..cb397ca 100644 --- a/app/order/api.go +++ b/app/order/api.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/jmoiron/sqlx" + "github.com/temporalio/reference-app-orders-go/app/db" "go.temporal.io/api/enums/v1" "go.temporal.io/api/serviceerror" "go.temporal.io/sdk/client" @@ -48,8 +48,8 @@ type OrderInput struct { // OrderStatus holds the status of an Order workflow. type OrderStatus struct { ID string `json:"id"` - CustomerID string `json:"customerId" db:"customer_id"` - ReceivedAt time.Time `json:"receivedAt" db:"received_at"` + CustomerID string `json:"customerId"` + ReceivedAt time.Time `json:"receivedAt"` Status string `json:"status"` @@ -196,12 +196,12 @@ type OrderResult struct { type handlers struct { temporal client.Client - db *sqlx.DB + db db.DB logger *slog.Logger } // Router implements the http.Handler interface for the Billing API -func Router(client client.Client, db *sqlx.DB, logger *slog.Logger) http.Handler { +func Router(client client.Client, db db.DB, logger *slog.Logger) http.Handler { r := http.NewServeMux() h := handlers{temporal: client, db: db, logger: logger} @@ -216,18 +216,26 @@ func Router(client client.Client, db *sqlx.DB, logger *slog.Logger) http.Handler } func (h *handlers) handleListOrders(w http.ResponseWriter, _ *http.Request) { - orders := []ListOrderEntry{} - - err := h.db.Select(&orders, `SELECT id, status, received_at FROM orders ORDER BY received_at DESC`) + orders := []db.OrderStatus{} + err := h.db.GetOrders(context.Background(), &orders) if err != nil { h.logger.Error("Failed to list orders", "error", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } + list := make([]ListOrderEntry, len(orders)) + for i, o := range orders { + list[i] = ListOrderEntry{ + ID: o.ID, + Status: o.Status, + ReceivedAt: o.ReceivedAt, + } + } + w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(orders) + err = json.NewEncoder(w).Encode(list) if err != nil { h.logger.Error("Failed to encode orders", "error", err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -259,14 +267,14 @@ func (h *handlers) handleCreateOrder(w http.ResponseWriter, r *http.Request) { return } - status := &OrderStatus{ + status := &db.OrderStatus{ ID: input.ID, CustomerID: input.CustomerID, ReceivedAt: time.Now().UTC(), Status: OrderStatusPending, } - _, err = h.db.NamedExec(`INSERT OR IGNORE INTO orders (id, customer_id, received_at, status) VALUES (:id, :customer_id, :received_at, :status)`, status) + err = h.db.InsertOrder(context.Background(), status) if err != nil { h.logger.Error("Failed to record workflow status", "error", err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -318,7 +326,7 @@ func (h *handlers) handleUpdateOrderStatus(w http.ResponseWriter, r *http.Reques return } - _, err = h.db.NamedExec(`UPDATE orders SET status = :status WHERE id = :id`, status) + err = h.db.UpdateOrderStatus(context.Background(), status.ID, status.Status) if err != nil { h.logger.Error("Failed to update order status", "error", err) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/app/server/server.go b/app/server/server.go index 725c246..d8b4ea1 100644 --- a/app/server/server.go +++ b/app/server/server.go @@ -3,18 +3,16 @@ package server import ( "context" "crypto/tls" - _ "embed" "fmt" "log/slog" "net/http" "os" - "path" "slices" "strings" - "github.com/jmoiron/sqlx" "github.com/temporalio/reference-app-orders-go/app/billing" "github.com/temporalio/reference-app-orders-go/app/config" + "github.com/temporalio/reference-app-orders-go/app/db" "github.com/temporalio/reference-app-orders-go/app/fraud" "github.com/temporalio/reference-app-orders-go/app/order" "github.com/temporalio/reference-app-orders-go/app/shipment" @@ -68,19 +66,6 @@ func CreateClientOptionsFromEnv() (client.Options, error) { return clientOpts, nil } -//go:embed schema.sql -var schema string - -// SetupDB creates the necessary tables in the database. -func SetupDB(db *sqlx.DB) error { - _, err := db.Exec(schema) - if err != nil { - return fmt.Errorf("failed to create the database schema: %w", err) - } - - return nil -} - // RunWorkers runs workers for the requested services. func RunWorkers(ctx context.Context, config config.AppConfig, client client.Client, services []string) error { ctx, cancel := context.WithCancel(ctx) @@ -176,18 +161,15 @@ func RunAPIServers(ctx context.Context, config config.AppConfig, client client.C g, ctx := errgroup.WithContext(ctx) - var db *sqlx.DB - var err error + db := db.CreateDB(config) if slices.Contains(services, "orders") || slices.Contains(services, "shipment") { - dbPath := path.Join(config.DataDir, "api-store.db") - db, err = sqlx.Connect("sqlite", dbPath) - db.SetMaxOpenConns(1) // SQLite does not support concurrent writes + err := db.Connect(context.TODO()) if err != nil { - return fmt.Errorf("failed to open database: %w", err) + return fmt.Errorf("failed to connect to database: %w", err) } - if err := SetupDB(db); err != nil { + if err := db.Setup(); err != nil { return err } } diff --git a/app/shipment/api.go b/app/shipment/api.go index 7ac2e39..b587c83 100644 --- a/app/shipment/api.go +++ b/app/shipment/api.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/jmoiron/sqlx" + "github.com/temporalio/reference-app-orders-go/app/db" "go.temporal.io/api/serviceerror" "go.temporal.io/sdk/client" ) @@ -31,7 +31,7 @@ func ShipmentIDFromWorkflowID(id string) string { type handlers struct { temporal client.Client - db *sqlx.DB + db db.DB logger *slog.Logger } @@ -51,13 +51,14 @@ type ShipmentStatusUpdate struct { // ListShipmentEntry is an entry in the Shipment list. type ListShipmentEntry struct { - ID string `json:"id"` - Status string `json:"status"` + ID string `json:"id" db:"id" bson:"id"` + Status string `json:"status" db:"status" bson:"status"` } // Router implements the http.Handler interface for the Shipment API -func Router(client client.Client, db *sqlx.DB, logger *slog.Logger) http.Handler { +func Router(client client.Client, db db.DB, logger *slog.Logger) http.Handler { r := http.NewServeMux() + h := handlers{temporal: client, db: db, logger: logger} r.HandleFunc("GET /shipments", h.handleListShipments) @@ -69,18 +70,26 @@ func Router(client client.Client, db *sqlx.DB, logger *slog.Logger) http.Handler } func (h *handlers) handleListShipments(w http.ResponseWriter, _ *http.Request) { - orders := []ListShipmentEntry{} + shipments := []db.ShipmentStatus{} - err := h.db.Select(&orders, `SELECT id, status FROM shipments ORDER BY booked_at DESC`) + err := h.db.GetShipments(context.Background(), &shipments) if err != nil { h.logger.Error("Failed to list shipments: %v", "error", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } + list := make([]ListShipmentEntry, len(shipments)) + for i, s := range shipments { + list[i] = ListShipmentEntry{ + ID: s.ID, + Status: s.Status, + } + } + w.Header().Set("Content-Type", "application/json") - if err := json.NewEncoder(w).Encode(orders); err != nil { + if err := json.NewEncoder(w).Encode(list); err != nil { h.logger.Error("Failed to encode orders: %v", "error", err) http.Error(w, err.Error(), http.StatusInternalServerError) } @@ -128,11 +137,7 @@ func (h *handlers) handleUpdateShipmentStatus(w http.ResponseWriter, r *http.Req return } - if status.Status == ShipmentStatusBooked { - _, err = h.db.NamedExec(`INSERT INTO shipments (id, status) VALUES(:id, :status)`, status) - } else { - _, err = h.db.NamedExec(`UPDATE shipments SET status = :status WHERE id = :id`, status) - } + err = h.db.UpdateShipmentStatus(context.Background(), status.ID, status.Status) if err != nil { h.logger.Error("Failed to update shipment status: %v", "error", err) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/app/shipment/api_test.go b/app/shipment/api_test.go index 8ee025a..750e0fd 100644 --- a/app/shipment/api_test.go +++ b/app/shipment/api_test.go @@ -1,32 +1,47 @@ +//go:build integration + package shipment_test import ( + "context" + "fmt" "log/slog" "net/http" "net/http/httptest" "strings" "testing" - "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/temporalio/reference-app-orders-go/app/server" + "github.com/temporalio/reference-app-orders-go/app/config" + "github.com/temporalio/reference-app-orders-go/app/db" "github.com/temporalio/reference-app-orders-go/app/shipment" + "github.com/testcontainers/testcontainers-go/modules/mongodb" "go.temporal.io/sdk/mocks" - _ "modernc.org/sqlite" ) func TestShipmentUpdate(t *testing.T) { + ctx := context.Background() c := mocks.NewClient(t) c.On("SignalWorkflow", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - db, err := sqlx.Open("sqlite", ":memory:") + mongoDBContainer, err := mongodb.Run(ctx, "mongo:6") require.NoError(t, err) - err = server.SetupDB(db) + defer mongoDBContainer.Terminate(ctx) + + port, err := mongoDBContainer.MappedPort(ctx, "27017/tcp") require.NoError(t, err) + uri := fmt.Sprintf("mongodb://localhost:%s", port.Port()) + + config := config.AppConfig{MongoURL: uri} + + db := db.CreateDB(config) + require.NoError(t, db.Connect(ctx)) + require.NoError(t, db.Setup()) + logger := slog.Default() r := shipment.Router(c, db, logger) diff --git a/app/test/order_test.go b/app/test/order_test.go index d49595e..384ebde 100644 --- a/app/test/order_test.go +++ b/app/test/order_test.go @@ -1,3 +1,5 @@ +//go:build integration + package test import ( @@ -12,19 +14,18 @@ import ( "testing" "time" - "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/temporalio/reference-app-orders-go/app/billing" "github.com/temporalio/reference-app-orders-go/app/config" + "github.com/temporalio/reference-app-orders-go/app/db" "github.com/temporalio/reference-app-orders-go/app/fraud" "github.com/temporalio/reference-app-orders-go/app/order" - "github.com/temporalio/reference-app-orders-go/app/server" "github.com/temporalio/reference-app-orders-go/app/shipment" + "github.com/testcontainers/testcontainers-go/modules/mongodb" "go.temporal.io/sdk/client" "go.temporal.io/sdk/testsuite" "golang.org/x/sync/errgroup" - _ "modernc.org/sqlite" ) func postJSON(url string, input interface{}) (*http.Response, error) { @@ -84,12 +85,10 @@ func Test_Order(t *testing.T) { c client.Client ) - options := client.Options{ + c, err = client.Dial(client.Options{ HostPort: s.FrontendHostPort(), Namespace: "default", - } - - c, err = client.Dial(options) + }) require.NoError(t, err) defer c.Close() @@ -100,22 +99,32 @@ func Test_Order(t *testing.T) { billingAPI := httptest.NewServer(billing.Router(c, logger)) defer billingAPI.Close() - db, err := sqlx.Open("sqlite", ":memory:") + mongoDBContainer, err := mongodb.Run(ctx, "mongo:6") require.NoError(t, err) - err = server.SetupDB(db) + defer mongoDBContainer.Terminate(ctx) + + port, err := mongoDBContainer.MappedPort(ctx, "27017/tcp") require.NoError(t, err) + uri := fmt.Sprintf("mongodb://localhost:%s", port.Port()) + + config := config.AppConfig{ + MongoURL: uri, + BillingURL: billingAPI.URL, + FraudURL: fraudAPI.URL, + } + + db := db.CreateDB(config) + require.NoError(t, db.Connect(ctx)) + require.NoError(t, db.Setup()) + orderAPI := httptest.NewServer(order.Router(c, db, logger)) defer orderAPI.Close() shipmentAPI := httptest.NewServer(shipment.Router(c, db, logger)) defer shipmentAPI.Close() - config := config.AppConfig{ - BillingURL: billingAPI.URL, - OrderURL: orderAPI.URL, - ShipmentURL: shipmentAPI.URL, - FraudURL: fraudAPI.URL, - } + config.OrderURL = orderAPI.URL + config.ShipmentURL = shipmentAPI.URL g, ctx := errgroup.WithContext(ctx) diff --git a/cmd/oms/main.go b/cmd/oms/main.go index 0ba1535..900c493 100644 --- a/cmd/oms/main.go +++ b/cmd/oms/main.go @@ -15,7 +15,6 @@ import ( "github.com/temporalio/reference-app-orders-go/app/temporalutil" "go.temporal.io/sdk/client" "go.temporal.io/sdk/converter" - _ "modernc.org/sqlite" ) const ( diff --git a/deployments/create-k8s.sh b/deployments/create-k8s.sh index 7cfec3c..d217705 100755 --- a/deployments/create-k8s.sh +++ b/deployments/create-k8s.sh @@ -9,7 +9,7 @@ mkdir -p ./k8s # Set controller type to statefulset for apis, which maintain a cache on disk yq \ '(del(.services[].restart)) | - ((.services | (.billing-api, .main-api)).labels += {"kompose.controller.type":"statefulset"})' \ + (.services.mongo.labels += {"kompose.controller.type":"statefulset"})' \ docker-compose-split.yaml | \ kompose -f - -o k8s convert -n oms --with-kompose-annotation=false @@ -26,7 +26,7 @@ for f in ./k8s/*-worker-deployment.yaml; do yq -i '.spec.template.spec.containers[0].image |= "ghcr.io/temporalio/reference-app-orders-go-worker:latest" | .spec.template.spec.containers[0].imagePullPolicy = "Always"' $f done -for f in ./k8s/*-api-statefulset.yaml; do +for f in ./k8s/*-api-deployment.yaml; do yq -i '.spec.template.spec.containers[0].image |= "ghcr.io/temporalio/reference-app-orders-go-api:latest" | .spec.template.spec.containers[0].imagePullPolicy = "Always"' $f done @@ -34,7 +34,7 @@ yq -i '.spec.template.spec.containers[0].image |= "ghcr.io/temporalio/reference- .spec.template.spec.containers[0].imagePullPolicy = "Always"' k8s/codec-server-deployment.yaml # We don't rely on service links, so disable them to avoid collisions with our configuration environment variables. -for f in ./k8s/*-{deployment,statefulset}.yaml; do +for f in ./k8s/*-deployment.yaml; do yq -i '.spec.template.spec.enableServiceLinks = false' $f done @@ -44,6 +44,6 @@ for f in ./k8s/*.yaml; do done # Update Temporal Address to assume Temporal is deployed in this Kubernetes cluster -for f in ./k8s/*-{statefulset,deployment}.yaml; do +for f in ./k8s/*-deployment.yaml; do yq -i '(.spec.template.spec.containers[0].env[] | select(.name == "TEMPORAL_ADDRESS").value) |= "temporal-frontend.temporal:7233"' $f done diff --git a/deployments/docker-compose-split.yaml b/deployments/docker-compose-split.yaml index 33fca67..75c0a68 100644 --- a/deployments/docker-compose-split.yaml +++ b/deployments/docker-compose-split.yaml @@ -1,4 +1,10 @@ services: + mongo: + image: mongo:6 + ports: + - "27017:27017" + volumes: + - mongo:/data/db billing-worker: build: context: ../ @@ -15,6 +21,7 @@ services: environment: - TEMPORAL_ADDRESS=host.docker.internal:7233 - BIND_ON_IP=0.0.0.0 + - MONGO_URL=mongodb://mongo:27017 - BILLING_API_PORT=8081 - FRAUD_API_PORT=8084 command: ["-k", "supersecretkey", "-s", "billing,fraud"] @@ -40,23 +47,22 @@ services: environment: - TEMPORAL_ADDRESS=host.docker.internal:7233 - BIND_ON_IP=0.0.0.0 + - MONGO_URL=mongodb://mongo:27017 - ORDER_API_PORT=8082 - SHIPMENT_API_PORT=8083 command: ["-k", "supersecretkey", "-s", "order,shipment"] ports: - "8082:8082" - "8083:8083" - volumes: - - main-api-data:/data restart: on-failure codec-server: build: context: ../ target: oms-codec-server # Adjust the web server URL to point to your Temporal Web instance. - command: ["-p", "8089", "-u", "http://localhost:8080"] + # command: ["-p", "8089", "-u", "http://localhost:8080"] # If you are using a Temporal CLI's start-dev you can use this: - # command: ["codec-server", "-p", "8089", "-u", "http://localhost:8233"] + command: ["-p", "8089", "-u", "http://localhost:8233"] ports: - "8089:8089" restart: on-failure @@ -74,4 +80,4 @@ services: - "3000:3000" restart: on-failure volumes: - main-api-data: + mongo: \ No newline at end of file diff --git a/deployments/docker-compose.yaml b/deployments/docker-compose.yaml index 9617eeb..60e3cfd 100644 --- a/deployments/docker-compose.yaml +++ b/deployments/docker-compose.yaml @@ -1,11 +1,16 @@ services: + mongo: + image: mongo:6 + ports: + - "27017:27017" + volumes: + - mongo:/data/db worker: build: context: ../ target: oms-worker environment: - TEMPORAL_ADDRESS=host.docker.internal:7233 - - DEBUG=true - BILLING_API_URL=http://api:8081 - ORDER_API_URL=http://api:8082 - SHIPMENT_API_URL=http://api:8083 @@ -19,14 +24,12 @@ services: environment: - TEMPORAL_ADDRESS=host.docker.internal:7233 - BIND_ON_IP=0.0.0.0 - - DEBUG=true + - MONGO_URL=mongodb://mongo:27017 - BILLING_API_PORT=8081 - ORDER_API_PORT=8082 - SHIPMENT_API_PORT=8083 - FRAUD_API_PORT=8084 command: ["-k", "supersecretkey"] - volumes: - - api-data:/data restart: on-failure codec-server: build: @@ -53,4 +56,4 @@ services: - "3000:3000" restart: on-failure volumes: - api-data: \ No newline at end of file + mongo: \ No newline at end of file diff --git a/deployments/install-temporal.sh b/deployments/install-temporal.sh index 8060ca9..72e2f53 100755 --- a/deployments/install-temporal.sh +++ b/deployments/install-temporal.sh @@ -2,10 +2,11 @@ echo "Installing Temporal via Helm..." -helm install \ +helm install --wait \ --namespace temporal \ --create-namespace \ --set server.replicaCount=1 \ + --set server.config.namespaces.create=true \ --set cassandra.config.cluster_size=1 \ --set elasticsearch.replicas=1 \ --set prometheus.enabled=false \ @@ -13,13 +14,4 @@ helm install \ --repo https://go.temporal.io/helm-charts \ temporal temporal --timeout 15m -echo "Waiting for Temporal admintools to be ready..." - -kubectl rollout status -n temporal deployment/temporal-admintools - -echo "Creating default namespace..." - -kubectl exec -ti -n temporal deployment/temporal-admintools -- \ - temporal operator namespace create -n default - echo "Done." diff --git a/deployments/k8s/billing-api-statefulset.yaml b/deployments/k8s/billing-api-deployment.yaml similarity index 92% rename from deployments/k8s/billing-api-statefulset.yaml rename to deployments/k8s/billing-api-deployment.yaml index aeb20cf..e1e36a4 100644 --- a/deployments/k8s/billing-api-statefulset.yaml +++ b/deployments/k8s/billing-api-deployment.yaml @@ -1,5 +1,5 @@ apiVersion: apps/v1 -kind: StatefulSet +kind: Deployment metadata: labels: app.kubernetes.io/component: billing-api @@ -12,7 +12,6 @@ spec: matchLabels: app.kubernetes.io/component: billing-api app.kubernetes.io/name: oms - serviceName: billing-api template: metadata: labels: @@ -32,6 +31,8 @@ spec: value: 0.0.0.0 - name: FRAUD_API_PORT value: "8084" + - name: MONGO_URL + value: mongodb://mongo:27017 - name: TEMPORAL_ADDRESS value: temporal-frontend.temporal:7233 image: ghcr.io/temporalio/reference-app-orders-go-api:latest diff --git a/deployments/k8s/codec-server-deployment.yaml b/deployments/k8s/codec-server-deployment.yaml index 223c31a..f083eae 100644 --- a/deployments/k8s/codec-server-deployment.yaml +++ b/deployments/k8s/codec-server-deployment.yaml @@ -23,7 +23,7 @@ spec: - -p - "8089" - -u - - http://localhost:8080 + - http://localhost:8233 image: ghcr.io/temporalio/reference-app-orders-go-codec-server:latest name: codec-server ports: diff --git a/deployments/k8s/main-api-statefulset.yaml b/deployments/k8s/main-api-deployment.yaml similarity index 67% rename from deployments/k8s/main-api-statefulset.yaml rename to deployments/k8s/main-api-deployment.yaml index c86f05e..09a967e 100644 --- a/deployments/k8s/main-api-statefulset.yaml +++ b/deployments/k8s/main-api-deployment.yaml @@ -1,5 +1,5 @@ apiVersion: apps/v1 -kind: StatefulSet +kind: Deployment metadata: labels: app.kubernetes.io/component: main-api @@ -12,7 +12,6 @@ spec: matchLabels: app.kubernetes.io/component: main-api app.kubernetes.io/name: oms - serviceName: main-api template: metadata: labels: @@ -28,6 +27,8 @@ spec: env: - name: BIND_ON_IP value: 0.0.0.0 + - name: MONGO_URL + value: mongodb://mongo:27017 - name: ORDER_API_PORT value: "8082" - name: SHIPMENT_API_PORT @@ -41,24 +42,5 @@ spec: protocol: TCP - containerPort: 8083 protocol: TCP - volumeMounts: - - mountPath: /data - name: main-api-data imagePullPolicy: Always - volumes: - - name: main-api-data - persistentVolumeClaim: - claimName: main-api-data enableServiceLinks: false - volumeClaimTemplates: - - metadata: - labels: - app.kubernetes.io/component: main-api-data - app.kubernetes.io/name: oms - name: main-api-data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Mi diff --git a/deployments/k8s/main-api-data-persistentvolumeclaim.yaml b/deployments/k8s/mongo-persistentvolumeclaim.yaml similarity index 74% rename from deployments/k8s/main-api-data-persistentvolumeclaim.yaml rename to deployments/k8s/mongo-persistentvolumeclaim.yaml index faa8bd1..0b9eaff 100644 --- a/deployments/k8s/main-api-data-persistentvolumeclaim.yaml +++ b/deployments/k8s/mongo-persistentvolumeclaim.yaml @@ -2,9 +2,9 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: labels: - app.kubernetes.io/component: main-api-data + app.kubernetes.io/component: mongo app.kubernetes.io/name: oms - name: main-api-data + name: mongo namespace: oms spec: accessModes: diff --git a/deployments/k8s/mongo-service.yaml b/deployments/k8s/mongo-service.yaml new file mode 100644 index 0000000..d4ae12b --- /dev/null +++ b/deployments/k8s/mongo-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: mongo + app.kubernetes.io/name: oms + name: mongo + namespace: oms +spec: + ports: + - name: "27017" + port: 27017 + targetPort: 27017 + selector: + app.kubernetes.io/component: mongo + app.kubernetes.io/name: oms diff --git a/deployments/k8s/mongo-statefulset.yaml b/deployments/k8s/mongo-statefulset.yaml new file mode 100644 index 0000000..8515615 --- /dev/null +++ b/deployments/k8s/mongo-statefulset.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + app.kubernetes.io/component: mongo + app.kubernetes.io/name: oms + name: mongo + namespace: oms +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: mongo + app.kubernetes.io/name: oms + serviceName: mongo + template: + metadata: + labels: + app.kubernetes.io/component: mongo + app.kubernetes.io/name: oms + spec: + containers: + - image: mongo:6 + name: mongo + ports: + - containerPort: 27017 + protocol: TCP + volumeMounts: + - mountPath: /data/db + name: mongo + volumes: + - name: mongo + persistentVolumeClaim: + claimName: mongo + volumeClaimTemplates: + - metadata: + labels: + app.kubernetes.io/component: mongo + app.kubernetes.io/name: oms + name: mongo + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi diff --git a/deployments/port-forward-temporal-ui.sh b/deployments/port-forward-temporal-ui.sh index cf21ef8..a1f9006 100755 --- a/deployments/port-forward-temporal-ui.sh +++ b/deployments/port-forward-temporal-ui.sh @@ -1,3 +1,3 @@ #!/bin/sh -kubectl port-forward -n temporal deployment/temporal-web 8080 +kubectl port-forward -n temporal deployment/temporal-web 8233:8080 diff --git a/docs/deploy-on-k8s.md b/docs/deploy-on-k8s.md index 2822611..ee18a6e 100644 --- a/docs/deploy-on-k8s.md +++ b/docs/deploy-on-k8s.md @@ -12,7 +12,7 @@ The scripts will help you: We have provided a script to create a new EKS cluster on AWS, but using EKS is not a requirement. If you already have a Kubernetes cluster you would like to use, from AWS or any other provider, please feel free to skip this step. Any Kubernetes cluster will work. -In order to use the script please ensure you have valid credentials setup to use the AWS APIs. Setting up authentication is beyond the scope of this document, but you can find some details on what IAM policies you may need in the [`eksctl` documentation](https://eksctl.io/usage/minimum-iam-policies/). +In order to use the script please ensure you have valid credentials set up to use the AWS APIs. Setting up authentication is beyond the scope of this document, but you can find some details on what IAM policies you may need in the [`eksctl` documentation](https://eksctl.io/usage/minimum-iam-policies/). To create the cluster (called "temporal-oms"): @@ -59,13 +59,13 @@ installing anything into it, use the `kubectl` command to create the namespace: ```sh -kubectl apply -f ./deployments/oms-namespace.yaml +kubectl apply -f ./deployments/k8s/oms-namespace.yaml ``` Once that has completed, you can then install all of the application: ```sh -kubectl apply -f ./deployments/ +kubectl apply -f ./deployments/k8s ``` You can check pod status to verify that the application is running: @@ -78,12 +78,13 @@ You should see output similar to the following: ``` NAME READY STATUS RESTARTS AGE -billing-api-0 1/1 Running 0 24h +billing-api-5fdc8b9d8f-tm2tl 1/1 Running 0 24h billing-worker-5498c6ffd4-klfwk 1/1 Running 0 24h codec-server-847b59b84f-9ct54 1/1 Running 0 24h -main-api-0 1/1 Running 0 24h +main-api-777cd87b47-bsw6h 1/1 Running 0 24h main-worker-777c59ccdb-jx46w 1/1 Running 0 24h web-557c8dc97-p5fkq 1/1 Running 0 24h +mongo-0 1/1 Running 0 24h ``` You'll know that the application is up when the READY column shows diff --git a/go.mod b/go.mod index fa5ee82..06b2b1d 100644 --- a/go.mod +++ b/go.mod @@ -9,35 +9,84 @@ require ( github.com/jmoiron/sqlx v1.4.0 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 + github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0 + go.mongodb.org/mongo-driver v1.17.0 go.temporal.io/api v1.36.0 go.temporal.io/sdk v1.28.1 - golang.org/x/sync v0.7.0 - modernc.org/sqlite v1.31.1 + golang.org/x/sync v0.8.0 + modernc.org/sqlite v1.34.1 ) require ( + dario.cat/mergo v1.0.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/containerd/containerd v1.7.18 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v27.1.1+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/mock v1.6.0 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/klauspost/compress v1.17.4 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/user v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect + github.com/morikuni/aec v1.0.0 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/nexus-rpc/sdk-go v0.0.9 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pborman/uuid v1.2.1 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/robfig/cron v1.2.0 // indirect + github.com/shirou/gopsutil/v3 v3.23.12 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect + github.com/testcontainers/testcontainers-go v0.33.0 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + golang.org/x/crypto v0.26.0 // indirect golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect golang.org/x/net v0.27.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect diff --git a/go.sum b/go.sum index c06c63f..ade7ecc 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,43 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao= +github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= +github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= 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/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -18,8 +46,17 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +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/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -34,7 +71,11 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= @@ -54,6 +95,8 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= 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.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -64,20 +107,46 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= +github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/nexus-rpc/sdk-go v0.0.9 h1:yQ16BlDWZ6EMjim/SMd8lsUGTj6TPxFioqLGP8/PJDQ= github.com/nexus-rpc/sdk-go v0.0.9/go.mod h1:TpfkM2Cw0Rlk9drGkoiSMpFqflKTiQLWUNyKJjF8mKQ= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -86,24 +155,74 @@ github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfm github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= +github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= +github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= +github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0 h1:iXVA84s5hKMS5gn01GWOYHE3ymy/2b+0YkpFeTxB2XY= +github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0/go.mod h1:R6tMjTojRiaoo89fh/hf7tOmfzohdqSU17R9DwSVSog= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.mongodb.org/mongo-driver v1.17.0 h1:Hp4q2MCjvY19ViwimTs00wHi7G4yzxh4/2+nTx8r40k= +go.mongodb.org/mongo-driver v1.17.0/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +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.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= +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.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +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.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.temporal.io/api v1.36.0 h1:WdntOw9m38lFvMdMXuOO+3BQ0R8HpVLgtk9+f+FwiDk= go.temporal.io/api v1.36.0/go.mod h1:0nWIrFRVPlcrkopXqxir/UWOtz/NZCo+EE9IX4UwVxw= go.temporal.io/sdk v1.28.1 h1:PsexsNDWXyWdJp4KWTOD+DfSZD1z0k5U/dIJF05akT4= @@ -115,6 +234,9 @@ go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +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-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= @@ -125,6 +247,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl 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/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -135,7 +258,9 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -145,25 +270,41 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= 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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +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.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -176,6 +317,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -210,6 +352,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= @@ -232,8 +376,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.31.1 h1:XVU0VyzxrYHlBhIs1DiEgSl0ZtdnPtbLVy8hSkzxGrs= -modernc.org/sqlite v1.31.1/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= +modernc.org/sqlite v1.34.1 h1:u3Yi6M0N8t9yKRDwhXcyp1eS5/ErhPTBggxWFuR6Hfk= +modernc.org/sqlite v1.34.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=