diff --git a/yb-voyager/cmd/common_test.go b/yb-voyager/cmd/common_test.go new file mode 100644 index 0000000000..d0046ea7ad --- /dev/null +++ b/yb-voyager/cmd/common_test.go @@ -0,0 +1,429 @@ +package cmd + +import ( + "fmt" + "os" + "path/filepath" + "reflect" + "testing" + + "github.com/yugabyte/yb-voyager/yb-voyager/src/migassessment" + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" + "github.com/yugabyte/yb-voyager/yb-voyager/src/utils" + "github.com/yugabyte/yb-voyager/yb-voyager/src/ybversion" +) + +func TestAssessmentReportStructs(t *testing.T) { + tests := []struct { + name string + actualType reflect.Type + expectedType interface{} + }{ + { + name: "Validate DBObject Struct Definition", + actualType: reflect.TypeOf(utils.DBObject{}), + expectedType: struct { + ObjectType string `json:"ObjectType"` + TotalCount int `json:"TotalCount"` + InvalidCount int `json:"InvalidCount"` + ObjectNames string `json:"ObjectNames"` + Details string `json:"Details,omitempty"` + }{}, + }, + { + name: "Validate SchemaSummary Struct Definition", + actualType: reflect.TypeOf(utils.SchemaSummary{}), + expectedType: struct { + Description string `json:"Description"` + DBName string `json:"DbName"` + SchemaNames []string `json:"SchemaNames"` + DBVersion string `json:"DbVersion"` + Notes []string `json:"Notes,omitempty"` + DBObjects []utils.DBObject `json:"DatabaseObjects"` + }{}, + }, + { + name: "Validate SizingRecommendation Struct Definition", + actualType: reflect.TypeOf(migassessment.SizingRecommendation{}), + expectedType: struct { + ColocatedTables []string + ColocatedReasoning string + ShardedTables []string + NumNodes float64 + VCPUsPerInstance int + MemoryPerInstance int + OptimalSelectConnectionsPerNode int64 + OptimalInsertConnectionsPerNode int64 + EstimatedTimeInMinForImport float64 + ParallelVoyagerJobs float64 + }{}, + }, + { + name: "Validate TableColumnsDataTypes Struct Definition", + actualType: reflect.TypeOf(utils.TableColumnsDataTypes{}), + expectedType: struct { + SchemaName string `json:"SchemaName"` + TableName string `json:"TableName"` + ColumnName string `json:"ColumnName"` + DataType string `json:"DataType"` + }{}, + }, + { + name: "Validate UnsupportedFeature Struct Definition", + actualType: reflect.TypeOf(UnsupportedFeature{}), + expectedType: struct { + FeatureName string `json:"FeatureName"` + Objects []ObjectInfo `json:"Objects"` + DisplayDDL bool `json:"-"` + DocsLink string `json:"DocsLink,omitempty"` + FeatureDescription string `json:"FeatureDescription,omitempty"` + MinimumVersionsFixedIn map[string]*ybversion.YBVersion `json:"MinimumVersionsFixedIn"` + }{}, + }, + { + name: "Validate UnsupportedQueryConstruct Struct Definition", + actualType: reflect.TypeOf(utils.UnsupportedQueryConstruct{}), + expectedType: struct { + ConstructTypeName string + Query string + DocsLink string + MinimumVersionsFixedIn map[string]*ybversion.YBVersion + }{}, + }, + { + name: "Validate TableIndexStats Struct Definition", + actualType: reflect.TypeOf(migassessment.TableIndexStats{}), + expectedType: struct { + SchemaName string `json:"SchemaName"` + ObjectName string `json:"ObjectName"` + RowCount *int64 `json:"RowCount"` // Pointer to allows null values + ColumnCount *int64 `json:"ColumnCount"` + Reads *int64 `json:"Reads"` + Writes *int64 `json:"Writes"` + ReadsPerSecond *int64 `json:"ReadsPerSecond"` + WritesPerSecond *int64 `json:"WritesPerSecond"` + IsIndex bool `json:"IsIndex"` + ObjectType string `json:"ObjectType"` + ParentTableName *string `json:"ParentTableName"` + SizeInBytes *int64 `json:"SizeInBytes"` + }{}, + }, + { + name: "Validate AssessmentReport Struct Definition", + actualType: reflect.TypeOf(AssessmentReport{}), + expectedType: struct { + VoyagerVersion string `json:"VoyagerVersion"` + TargetDBVersion *ybversion.YBVersion `json:"TargetDBVersion"` + MigrationComplexity string `json:"MigrationComplexity"` + SchemaSummary utils.SchemaSummary `json:"SchemaSummary"` + Sizing *migassessment.SizingAssessmentReport `json:"Sizing"` + UnsupportedDataTypes []utils.TableColumnsDataTypes `json:"UnsupportedDataTypes"` + UnsupportedDataTypesDesc string `json:"UnsupportedDataTypesDesc"` + UnsupportedFeatures []UnsupportedFeature `json:"UnsupportedFeatures"` + UnsupportedFeaturesDesc string `json:"UnsupportedFeaturesDesc"` + UnsupportedQueryConstructs []utils.UnsupportedQueryConstruct `json:"UnsupportedQueryConstructs"` + UnsupportedPlPgSqlObjects []UnsupportedFeature `json:"UnsupportedPlPgSqlObjects"` + MigrationCaveats []UnsupportedFeature `json:"MigrationCaveats"` + TableIndexStats *[]migassessment.TableIndexStats `json:"TableIndexStats"` + Notes []string `json:"Notes"` + }{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testutils.CompareStructs(t, tt.actualType, reflect.TypeOf(tt.expectedType), tt.name) + }) + } +} + +func TestAssessmentReportJson(t *testing.T) { + reportDir := filepath.Join(os.TempDir(), "assessment_report_test") + reportPath := filepath.Join(reportDir, fmt.Sprintf("%s%s", ASSESSMENT_FILE_NAME, JSON_EXTENSION)) + + newYbVersion, err := ybversion.NewYBVersion("2024.1.1.1") + if err != nil { + t.Fatalf("Failed to create new YBVersion: %v", err) + } + + assessmentReport = AssessmentReport{ + VoyagerVersion: "v1.0.0", + TargetDBVersion: newYbVersion, + MigrationComplexity: "High", + SchemaSummary: utils.SchemaSummary{ + Description: "Test Schema Summary", + DBName: "test_db", + SchemaNames: []string{"public"}, + DBVersion: "13.3", + DBObjects: []utils.DBObject{ + { + ObjectType: "Table", + TotalCount: 1, + InvalidCount: 0, + ObjectNames: "test_table", + }, + }, + }, + Sizing: &migassessment.SizingAssessmentReport{ + SizingRecommendation: migassessment.SizingRecommendation{ + ColocatedTables: []string{"test_table"}, + ColocatedReasoning: "Test reasoning", + ShardedTables: []string{"test_table"}, + NumNodes: 3, + VCPUsPerInstance: 4, + MemoryPerInstance: 16, + OptimalSelectConnectionsPerNode: 10, + OptimalInsertConnectionsPerNode: 10, + EstimatedTimeInMinForImport: 10, + ParallelVoyagerJobs: 10, + }, + FailureReasoning: "Test failure reasoning", + }, + UnsupportedDataTypes: []utils.TableColumnsDataTypes{ + { + SchemaName: "public", + TableName: "test_table", + ColumnName: "test_column", + DataType: "test_type", + }, + }, + UnsupportedDataTypesDesc: "Test unsupported data types", + UnsupportedFeatures: []UnsupportedFeature{ + { + FeatureName: "test_feature", + Objects: []ObjectInfo{ + { + ObjectName: "test_object", + ObjectType: "test_type", + SqlStatement: "test_sql", + }, + }, + DisplayDDL: true, + DocsLink: "https://test.com", + FeatureDescription: "Test feature description", + MinimumVersionsFixedIn: map[string]*ybversion.YBVersion{"2024.1.1": newYbVersion}, + }, + }, + UnsupportedFeaturesDesc: "Test unsupported features", + UnsupportedQueryConstructs: []utils.UnsupportedQueryConstruct{ + { + ConstructTypeName: "test_construct", + Query: "test_query", + DocsLink: "https://test.com", + MinimumVersionsFixedIn: map[string]*ybversion.YBVersion{"2024.1.1": newYbVersion}, + }, + }, + UnsupportedPlPgSqlObjects: []UnsupportedFeature{ + { + FeatureName: "test_feature", + Objects: []ObjectInfo{ + { + ObjectName: "test_object", + ObjectType: "test_type", + SqlStatement: "test_sql", + }, + }, + DisplayDDL: true, + DocsLink: "https://test.com", + FeatureDescription: "Test feature description", + MinimumVersionsFixedIn: map[string]*ybversion.YBVersion{"2024.1.1": newYbVersion}, + }, + }, + MigrationCaveats: []UnsupportedFeature{ + { + FeatureName: "test_feature", + Objects: []ObjectInfo{ + { + ObjectName: "test_object", + ObjectType: "test_type", + SqlStatement: "test_sql", + }, + }, + DisplayDDL: true, + DocsLink: "https://test.com", + FeatureDescription: "Test feature description", + MinimumVersionsFixedIn: map[string]*ybversion.YBVersion{"2024.1.1": newYbVersion}, + }, + }, + TableIndexStats: &[]migassessment.TableIndexStats{ + { + SchemaName: "public", + ObjectName: "test_table", + RowCount: Int64Ptr(100), + ColumnCount: Int64Ptr(10), + Reads: Int64Ptr(100), + Writes: Int64Ptr(100), + ReadsPerSecond: Int64Ptr(10), + WritesPerSecond: Int64Ptr(10), + IsIndex: true, + ObjectType: "Table", + ParentTableName: StringPtr("parent_table"), + SizeInBytes: Int64Ptr(1024), + }, + }, + Notes: []string{"Test note"}, + } + + // Make the report directory + err = os.MkdirAll(reportDir, 0755) + if err != nil { + t.Fatalf("Failed to create report directory: %v", err) + } + + // Clean up the report directory + defer func() { + err := os.RemoveAll(reportDir) + if err != nil { + t.Fatalf("Failed to remove report directory: %v", err) + } + }() + + // Write the assessment report to a JSON file + err = generateAssessmentReportJson(reportDir) + if err != nil { + t.Fatalf("Failed to write assessment report to JSON file: %v", err) + } + + // expected JSON + expectedJSON := `{ + "VoyagerVersion": "v1.0.0", + "TargetDBVersion": "2024.1.1.1", + "MigrationComplexity": "High", + "SchemaSummary": { + "Description": "Test Schema Summary", + "DbName": "test_db", + "SchemaNames": [ + "public" + ], + "DbVersion": "13.3", + "DatabaseObjects": [ + { + "ObjectType": "Table", + "TotalCount": 1, + "InvalidCount": 0, + "ObjectNames": "test_table" + } + ] + }, + "Sizing": { + "SizingRecommendation": { + "ColocatedTables": [ + "test_table" + ], + "ColocatedReasoning": "Test reasoning", + "ShardedTables": [ + "test_table" + ], + "NumNodes": 3, + "VCPUsPerInstance": 4, + "MemoryPerInstance": 16, + "OptimalSelectConnectionsPerNode": 10, + "OptimalInsertConnectionsPerNode": 10, + "EstimatedTimeInMinForImport": 10, + "ParallelVoyagerJobs": 10 + }, + "FailureReasoning": "Test failure reasoning" + }, + "UnsupportedDataTypes": [ + { + "SchemaName": "public", + "TableName": "test_table", + "ColumnName": "test_column", + "DataType": "test_type" + } + ], + "UnsupportedDataTypesDesc": "Test unsupported data types", + "UnsupportedFeatures": [ + { + "FeatureName": "test_feature", + "Objects": [ + { + "ObjectType": "test_type", + "ObjectName": "test_object", + "SqlStatement": "test_sql" + } + ], + "DocsLink": "https://test.com", + "FeatureDescription": "Test feature description", + "MinimumVersionsFixedIn": { + "2024.1.1": "2024.1.1.1" + } + } + ], + "UnsupportedFeaturesDesc": "Test unsupported features", + "UnsupportedQueryConstructs": [ + { + "ConstructTypeName": "test_construct", + "Query": "test_query", + "DocsLink": "https://test.com", + "MinimumVersionsFixedIn": { + "2024.1.1": "2024.1.1.1" + } + } + ], + "UnsupportedPlPgSqlObjects": [ + { + "FeatureName": "test_feature", + "Objects": [ + { + "ObjectType": "test_type", + "ObjectName": "test_object", + "SqlStatement": "test_sql" + } + ], + "DocsLink": "https://test.com", + "FeatureDescription": "Test feature description", + "MinimumVersionsFixedIn": { + "2024.1.1": "2024.1.1.1" + } + } + ], + "MigrationCaveats": [ + { + "FeatureName": "test_feature", + "Objects": [ + { + "ObjectType": "test_type", + "ObjectName": "test_object", + "SqlStatement": "test_sql" + } + ], + "DocsLink": "https://test.com", + "FeatureDescription": "Test feature description", + "MinimumVersionsFixedIn": { + "2024.1.1": "2024.1.1.1" + } + } + ], + "TableIndexStats": [ + { + "SchemaName": "public", + "ObjectName": "test_table", + "RowCount": 100, + "ColumnCount": 10, + "Reads": 100, + "Writes": 100, + "ReadsPerSecond": 10, + "WritesPerSecond": 10, + "IsIndex": true, + "ObjectType": "Table", + "ParentTableName": "parent_table", + "SizeInBytes": 1024 + } + ], + "Notes": [ + "Test note" + ] +}` + + testutils.CompareJson(t, reportPath, expectedJSON, reportDir) + +} + +func Int64Ptr(i int64) *int64 { + return &i +} + +func StringPtr(s string) *string { + return &s +} diff --git a/yb-voyager/cmd/exportDataStatus_test.go b/yb-voyager/cmd/exportDataStatus_test.go new file mode 100644 index 0000000000..beec85005c --- /dev/null +++ b/yb-voyager/cmd/exportDataStatus_test.go @@ -0,0 +1,95 @@ +package cmd + +import ( + "os" + "path/filepath" + "reflect" + "testing" + + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" + "github.com/yugabyte/yb-voyager/yb-voyager/src/utils/sqlname" +) + +func TestExportSnapshotStatusStructs(t *testing.T) { + + test := []struct { + name string + actualType reflect.Type + expectedType interface{} + }{ + { + name: "Validate TableExportStatus Struct Definition", + actualType: reflect.TypeOf(TableExportStatus{}), + expectedType: struct { + TableName string `json:"table_name"` + FileName string `json:"file_name"` + Status string `json:"status"` + ExportedRowCountSnapshot int64 `json:"exported_row_count_snapshot"` + }{}, + }, + { + name: "Validate ExportSnapshotStatus Struct Definition", + actualType: reflect.TypeOf(ExportSnapshotStatus{}), + expectedType: struct { + Tables map[string]*TableExportStatus `json:"tables"` + }{}, + }, + } + + for _, tt := range test { + t.Run(tt.name, func(t *testing.T) { + testutils.CompareStructs(t, tt.actualType, reflect.TypeOf(tt.expectedType), tt.name) + }) + } +} + +func TestExportSnapshotStatusJson(t *testing.T) { + // Create a table list of type []sqlname.NameTuple + o1 := sqlname.NewObjectName(POSTGRESQL, "public", "public", "table1") + o2 := sqlname.NewObjectName(POSTGRESQL, "public", "schema1", "table2") + tableList := []sqlname.NameTuple{ + {CurrentName: o1, SourceName: o1, TargetName: o1}, + {CurrentName: o2, SourceName: o2, TargetName: o2}, + } + + exportDir = filepath.Join(os.TempDir(), "export_snapshot_status_test") + + // Make export directory + err := os.MkdirAll(filepath.Join(exportDir, "metainfo"), 0755) + if err != nil { + t.Fatalf("failed to create export directory: %v", err) + } + + // Clean up the export directory + defer func() { + err := os.RemoveAll(exportDir) + if err != nil { + t.Fatalf("failed to remove export directory: %v", err) + } + }() + + outputFilePath := filepath.Join(exportDir, "metainfo", "export_snapshot_status.json") + + // Call initializeExportTableMetadata to create the export_snapshot_status.json file + initializeExportTableMetadata(tableList) + + expectedExportSnapshotStatusJSON := `{ + "tables": { + "public.\"table1\"": { + "table_name": "public.\"table1\"", + "file_name": "", + "status": "NOT-STARTED", + "exported_row_count_snapshot": 0 + }, + "schema1.\"table2\"": { + "table_name": "schema1.\"table2\"", + "file_name": "", + "status": "NOT-STARTED", + "exported_row_count_snapshot": 0 + } + } +}` + + // Compare the JSON representation of the sample ExportSnapshotStatus instance + testutils.CompareJson(t, outputFilePath, expectedExportSnapshotStatusJSON, exportDir) +} diff --git a/yb-voyager/go.mod b/yb-voyager/go.mod index 8f4c858131..b761c2d4a7 100644 --- a/yb-voyager/go.mod +++ b/yb-voyager/go.mod @@ -3,7 +3,7 @@ module github.com/yugabyte/yb-voyager/yb-voyager go 1.23.1 require ( - cloud.google.com/go/storage v1.29.0 + cloud.google.com/go/storage v1.38.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 github.com/DATA-DOG/go-sqlmock v1.5.2 @@ -13,11 +13,13 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.13.0 + github.com/fergusstrange/embedded-postgres v1.29.0 github.com/go-sql-driver/mysql v1.7.0 github.com/godror/godror v0.30.2 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.6.0 github.com/gosuri/uilive v0.0.4 github.com/gosuri/uitable v0.0.4 + github.com/hashicorp/go-version v1.7.0 github.com/jackc/pgconn v1.13.0 github.com/jackc/pgx/v4 v4.17.2 github.com/jackc/pgx/v5 v5.0.3 @@ -27,35 +29,76 @@ require ( github.com/nightlyone/lockfile v1.0.0 github.com/pganalyze/pg_query_go/v5 v5.1.0 github.com/samber/lo v1.38.1 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.13.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/tebeka/atexit v0.3.0 + github.com/testcontainers/testcontainers-go v0.34.0 github.com/vbauerster/mpb/v8 v8.4.0 gocloud.dev v0.29.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/term v0.24.0 - google.golang.org/api v0.118.0 + google.golang.org/api v0.169.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( - github.com/fergusstrange/embedded-postgres v1.29.0 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect + 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.2 // 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/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/jackc/puddle v1.3.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/klauspost/compress v1.17.4 // indirect github.com/lib/pq v1.10.9 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // 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/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/shirou/gopsutil/v3 v3.23.12 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // 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 go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect ) require ( - cloud.google.com/go v0.110.2 // indirect - cloud.google.com/go/compute v1.19.0 // indirect + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute v1.25.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v0.13.0 // indirect + cloud.google.com/go/iam v1.1.6 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect @@ -86,12 +129,12 @@ require ( github.com/godror/knownpb v0.1.0 // indirect github.com/golang-jwt/jwt/v4 v4.4.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/s2a-go v0.1.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/go-cmp v0.6.0 + github.com/google/s2a-go v0.1.7 // indirect github.com/google/wire v0.5.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.8.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect @@ -102,7 +145,7 @@ require ( github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect github.com/jackc/pgtype v1.12.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/magiconair/properties v1.8.6 + github.com/magiconair/properties v1.8.7 github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect @@ -120,17 +163,17 @@ require ( github.com/spf13/pflag v1.0.5 github.com/subosito/gotenv v1.4.1 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.15.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.55.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/grpc v1.64.1 // indirect + google.golang.org/protobuf v1.33.0 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/yb-voyager/go.sum b/yb-voyager/go.sum index 58e148305e..a0de897915 100644 --- a/yb-voyager/go.sum +++ b/yb-voyager/go.sum @@ -39,8 +39,8 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.109.0/go.mod h1:2sYycXt75t/CSB5R9M2wPU1tJmire7AQZTPtITcGBVE= -cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA= -cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= @@ -124,8 +124,8 @@ cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARy cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= @@ -218,8 +218,8 @@ cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHD cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= cloud.google.com/go/iam v0.10.0/go.mod h1:nXAECrMt2qHpF6RZUZseteD6QyanL68reN4OXPw0UWM= -cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= @@ -240,8 +240,6 @@ cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9 cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= cloud.google.com/go/longrunning v0.4.0/go.mod h1:eF3Qsw58iX/bkKtVjMTYpH0LRjQ2goDkjkNQTlzq/ZM= -cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= @@ -369,8 +367,9 @@ cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= -cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storage v1.38.0 h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg= +cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= @@ -417,8 +416,12 @@ code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/stackdriver v0.13.14/go.mod h1:5pSSGY0Bhuk7waTHuDf4aQ8D2DrhgETRo9fy6k3Xlzc= contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= +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/azure-amqp-common-go/v3 v3.2.3/go.mod h1:7rPmbSfszeovxGfc5fSAXE4ehlXQZHpMja2OtxC2Tas= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v63.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= @@ -448,6 +451,7 @@ github.com/Azure/go-amqp v0.17.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fw github.com/Azure/go-amqp v0.18.1/go.mod h1:+bg0x3ce5+Q3ahCEXnCsGG3ETpDQe3MEVnOuT2ywPwc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +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/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -494,6 +498,8 @@ github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JP github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= @@ -641,6 +647,8 @@ github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRt github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +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/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= @@ -725,6 +733,8 @@ github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTV github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE= +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/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= @@ -753,9 +763,13 @@ github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6T github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= github.com/containerd/imgcrypt v1.1.3/go.mod h1:/TPA1GIDXMzbj01yd8pIbQiLdQxed5ue1wb8bP7PQu4= +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/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +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/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= @@ -803,12 +817,16 @@ github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= @@ -827,6 +845,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/digitalocean/godo v1.78.0/go.mod h1:GBmu8MkjZmNARE7IXRPmkbbnocNN8+uBm0xbEVw2LCs= github.com/digitalocean/godo v1.95.0/go.mod h1:NRpFznZFvhHjBoqZAaOD3khVzsJ3EibzKqFL4R60dmA= +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/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= @@ -839,13 +859,18 @@ github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4Kfc github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.23+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +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/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +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-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +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/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= @@ -890,6 +915,8 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fergusstrange/embedded-postgres v1.29.0 h1:Uv8hdhoiaNMuH0w8UuGXDHr60VoAQPFdgx7Qf3bzXJM= github.com/fergusstrange/embedded-postgres v1.29.0/go.mod h1:t/MLs0h9ukYM6FSt99R7InCHs1nW0ordoVCcnzmpTYw= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= @@ -938,8 +965,13 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/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.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= +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-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= @@ -1043,6 +1075,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= @@ -1089,8 +1122,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -1154,23 +1187,25 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20220318212150-b2ab0324ddda/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/pprof v0.0.0-20230111200839-76d1ae5aea2b/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.0 h1:3Qm0liEiCErViKERO2Su5wp+9PfMRiuS6XB5FvpKnYQ= -github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -1181,8 +1216,8 @@ github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= +github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= @@ -1217,10 +1252,13 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.1/go.mod h1:G+WkljZi4mflcqVxYSgvt8MNctRQHjEH8ubKtt1Ka3w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hanwen/go-fuse/v2 v2.2.0/go.mod h1:B1nGE/6RBFyBRC1RRnf23UpwCdyJ31eukw34oAKukAc= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= @@ -1405,6 +1443,8 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -1432,19 +1472,21 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/linode/linodego v1.4.0/go.mod h1:PVsRxSlOiJyvG4/scTszpmZDTdgS+to3X6eS8pRrWI8= github.com/linode/linodego v1.12.0/go.mod h1:NJlzvlNtdMRRkXb0oN6UWzUkj6t+IBsyveHgZ5Ppjyk= github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= +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/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -1522,17 +1564,27 @@ github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +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/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +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/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +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/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= +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.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -1541,6 +1593,7 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.6.6/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/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -1608,11 +1661,14 @@ github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1 github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +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.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +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/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= @@ -1669,6 +1725,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +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/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/alertmanager v0.24.0/go.mod h1:r6fy/D7FRuZh5YbnX6J3MBY0eI4Pb5yPYS7/bPSXXqI= @@ -1761,7 +1819,13 @@ github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +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.0/go.mod h1:xYtyGBC5Q3kzCNyJg/SjgNpfAa2kvmgA0i5+lQso8x0= +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/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -1777,8 +1841,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -1829,6 +1893,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 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 v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -1840,8 +1906,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 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/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= @@ -1852,7 +1919,13 @@ github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ github.com/tebeka/atexit v0.3.0 h1:jleL99H7Ywt80oJKR+VWmJNnezcCOG0CuzcN3CIpsdI= github.com/tebeka/atexit v0.3.0/go.mod h1:WJmSUSmMT7WoR7etUOaGBVXk+f5/ZJ+67qwuedq7Fbs= github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0= +github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo= +github.com/testcontainers/testcontainers-go v0.34.0/go.mod h1:6P/kMkQe8yqPHfPWNulFGdFHTD8HB2vLq/231xY2iPQ= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +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/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -1899,6 +1972,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/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= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= @@ -1938,15 +2013,22 @@ go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0/go.mod h1:PFmBsWbldL1kiWZk9+0LBZz2brhByaGsvp6pRICMlPE= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0/go.mod h1:+ARmXlUlc51J7sZeCBkBJNdHGySrdOzgzxp6VWRWM1U= +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 v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ= go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ= go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI= +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 v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg= go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.1/go.mod h1:NEu79Xo32iVb+0gVNV8PMd7GoWqnyDXRlj04yFjqz40= @@ -1954,21 +2036,29 @@ go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2/go.mod h1:rqbht/L go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.1/go.mod h1:YJ/JbY5ag/tSQFXzH3mtDmHqzF3aFn3DI/aB1n7pt4w= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.2/go.mod h1:5Qn6qvgkMsLDX+sYK64rHb1FPhpn0UtxF+ouX1uhyJE= +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/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.1/go.mod h1:UJJXJj0rltNIemDMwkOJyggsvyMG9QHfJeFH0HS5JjM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.2/go.mod h1:jWZUM2MWhWCJ9J9xVbRx7tzK1mXKpAlze4CeulycwVY= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.1/go.mod h1:DAKwdo06hFLc0U88O10x4xnb5sc7dDRDqRuiN+io8JE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.2/go.mod h1:GZWSQQky8AgdJj50r1KJm8oiQiIPaAX7uZCFQX9GzC8= +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 v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9hm+GoQq/ekE9Iw= go.opentelemetry.io/otel/metric v0.34.0/go.mod h1:ZFuI4yQGNCupurTXCwkeD/zHBt+C2bR7bw5JqUm/AP8= +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/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= go.opentelemetry.io/otel/sdk v1.6.1/go.mod h1:IVYrddmFZ+eJqu2k38qD3WezFR2pymCzm8tdxyh3R4E= go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= go.opentelemetry.io/otel/sdk v1.11.2/go.mod h1:wZ1WxImwpq+lVRo4vsmSOxdd+xwoUJ6rqyLc3SyX9aU= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= @@ -1977,11 +2067,15 @@ go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qE go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0= go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA= +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 v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= go.opentelemetry.io/proto/otlp v0.12.1/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +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.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1995,6 +2089,7 @@ go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= @@ -2054,8 +2149,8 @@ golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +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/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2194,8 +2289,8 @@ golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmL golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2227,8 +2322,8 @@ golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2329,6 +2424,7 @@ golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2400,6 +2496,9 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -2428,8 +2527,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +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.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2443,6 +2542,8 @@ golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2540,8 +2641,9 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -2607,16 +2709,17 @@ google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/ google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= -google.golang.org/api v0.118.0 h1:FNfHq9Z2GKULxu7cEhCaB0wWQHg43UpomrrN+24ZRdE= -google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= +google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY= +google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -2753,8 +2856,12 @@ google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -2799,8 +2906,8 @@ google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/grpc v1.52.1/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -2817,8 +2924,9 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2868,9 +2976,12 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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 v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/yb-voyager/src/callhome/diagnostics_test.go b/yb-voyager/src/callhome/diagnostics_test.go new file mode 100644 index 0000000000..2575a8e405 --- /dev/null +++ b/yb-voyager/src/callhome/diagnostics_test.go @@ -0,0 +1,204 @@ +package callhome + +import ( + "reflect" + "testing" + + "github.com/google/uuid" + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" +) + +func TestCallhomeStructs(t *testing.T) { + + tests := []struct { + name string + actualType reflect.Type + expectedType interface{} + }{ + { + name: "Validate Payload Struct Definition", + actualType: reflect.TypeOf(Payload{}), + expectedType: struct { + MigrationUUID uuid.UUID `json:"migration_uuid"` + PhaseStartTime string `json:"phase_start_time"` + CollectedAt string `json:"collected_at"` + SourceDBDetails string `json:"source_db_details"` + TargetDBDetails string `json:"target_db_details"` + YBVoyagerVersion string `json:"yb_voyager_version"` + MigrationPhase string `json:"migration_phase"` + PhasePayload string `json:"phase_payload"` + MigrationType string `json:"migration_type"` + TimeTakenSec int `json:"time_taken_sec"` + Status string `json:"status"` + }{}, + }, + { + name: "Validate SourceDBDetails Struct Definition", + actualType: reflect.TypeOf(SourceDBDetails{}), + expectedType: struct { + Host string `json:"host"` + DBType string `json:"db_type"` + DBVersion string `json:"db_version"` + DBSize int64 `json:"total_db_size_bytes"` + Role string `json:"role,omitempty"` + }{}, + }, + { + name: "Validate TargetDBDetails Struct Definition", + actualType: reflect.TypeOf(TargetDBDetails{}), + expectedType: struct { + Host string `json:"host"` + DBVersion string `json:"db_version"` + NodeCount int `json:"node_count"` + Cores int `json:"total_cores"` + }{}, + }, + { + name: "Validate UnsupportedFeature Struct Definition", + actualType: reflect.TypeOf(UnsupportedFeature{}), + expectedType: struct { + FeatureName string `json:"FeatureName"` + Objects []string `json:"Objects,omitempty"` + ObjectCount int `json:"ObjectCount"` + TotalOccurrences int `json:"TotalOccurrences"` + }{}, + }, + { + name: "Validate AssessMigrationPhasePayload Struct Definition", + actualType: reflect.TypeOf(AssessMigrationPhasePayload{}), + expectedType: struct { + MigrationComplexity string `json:"migration_complexity"` + UnsupportedFeatures string `json:"unsupported_features"` + UnsupportedDatatypes string `json:"unsupported_datatypes"` + UnsupportedQueryConstructs string `json:"unsupported_query_constructs"` + MigrationCaveats string `json:"migration_caveats"` + UnsupportedPlPgSqlObjects string `json:"unsupported_plpgsql_objects"` + Error string `json:"error,omitempty"` + TableSizingStats string `json:"table_sizing_stats"` + IndexSizingStats string `json:"index_sizing_stats"` + SchemaSummary string `json:"schema_summary"` + SourceConnectivity bool `json:"source_connectivity"` + IopsInterval int64 `json:"iops_interval"` + }{}, + }, + { + name: "Validate AssessMigrationBulkPhasePayload Struct Definition", + actualType: reflect.TypeOf(AssessMigrationBulkPhasePayload{}), + expectedType: struct { + FleetConfigCount int `json:"fleet_config_count"` + }{}, + }, + { + name: "Validate ObjectSizingStats Struct Definition", + actualType: reflect.TypeOf(ObjectSizingStats{}), + expectedType: struct { + SchemaName string `json:"schema_name,omitempty"` + ObjectName string `json:"object_name"` + ReadsPerSecond int64 `json:"reads_per_second"` + WritesPerSecond int64 `json:"writes_per_second"` + SizeInBytes int64 `json:"size_in_bytes"` + }{}, + }, + { + name: "Validate ExportSchemaPhasePayload Struct Definition", + actualType: reflect.TypeOf(ExportSchemaPhasePayload{}), + expectedType: struct { + StartClean bool `json:"start_clean"` + AppliedRecommendations bool `json:"applied_recommendations"` + UseOrafce bool `json:"use_orafce"` + CommentsOnObjects bool `json:"comments_on_objects"` + }{}, + }, + { + name: "Validate AnalyzePhasePayload Struct Definition", + actualType: reflect.TypeOf(AnalyzePhasePayload{}), + expectedType: struct { + Issues string `json:"issues"` + DatabaseObjects string `json:"database_objects"` + }{}, + }, + { + name: "Validate ExportDataPhasePayload Struct Definition", + actualType: reflect.TypeOf(ExportDataPhasePayload{}), + expectedType: struct { + ParallelJobs int64 `json:"parallel_jobs"` + TotalRows int64 `json:"total_rows_exported"` + LargestTableRows int64 `json:"largest_table_rows_exported"` + StartClean bool `json:"start_clean"` + ExportSnapshotMechanism string `json:"export_snapshot_mechanism,omitempty"` + Phase string `json:"phase,omitempty"` + TotalExportedEvents int64 `json:"total_exported_events,omitempty"` + EventsExportRate int64 `json:"events_export_rate_3m,omitempty"` + LiveWorkflowType string `json:"live_workflow_type,omitempty"` + }{}, + }, + { + name: "Validate ImportSchemaPhasePayload Struct Definition", + actualType: reflect.TypeOf(ImportSchemaPhasePayload{}), + expectedType: struct { + ContinueOnError bool `json:"continue_on_error"` + EnableOrafce bool `json:"enable_orafce"` + IgnoreExist bool `json:"ignore_exist"` + RefreshMviews bool `json:"refresh_mviews"` + ErrorCount int `json:"errors"` + PostSnapshotImport bool `json:"post_snapshot_import"` + StartClean bool `json:"start_clean"` + }{}, + }, + { + name: "Validate ImportDataPhasePayload Struct Definition", + actualType: reflect.TypeOf(ImportDataPhasePayload{}), + expectedType: struct { + ParallelJobs int64 `json:"parallel_jobs"` + TotalRows int64 `json:"total_rows_imported"` + LargestTableRows int64 `json:"largest_table_rows_imported"` + StartClean bool `json:"start_clean"` + Phase string `json:"phase,omitempty"` + TotalImportedEvents int64 `json:"total_imported_events,omitempty"` + EventsImportRate int64 `json:"events_import_rate_3m,omitempty"` + LiveWorkflowType string `json:"live_workflow_type,omitempty"` + EnableUpsert bool `json:"enable_upsert"` + }{}, + }, + { + name: "Validate ImportDataFilePhasePayload Struct Definition", + actualType: reflect.TypeOf(ImportDataFilePhasePayload{}), + expectedType: struct { + ParallelJobs int64 `json:"parallel_jobs"` + TotalSize int64 `json:"total_size_imported"` + LargestTableSize int64 `json:"largest_table_size_imported"` + FileStorageType string `json:"file_storage_type"` + StartClean bool `json:"start_clean"` + DataFileParameters string `json:"data_file_parameters"` + }{}, + }, + { + name: "Validate DataFileParameters Struct Definition", + actualType: reflect.TypeOf(DataFileParameters{}), + expectedType: struct { + FileFormat string `json:"FileFormat"` + Delimiter string `json:"Delimiter"` + HasHeader bool `json:"HasHeader"` + QuoteChar string `json:"QuoteChar,omitempty"` + EscapeChar string `json:"EscapeChar,omitempty"` + NullString string `json:"NullString,omitempty"` + }{}, + }, + { + name: "Validate EndMigrationPhasePayload Struct Definition", + actualType: reflect.TypeOf(EndMigrationPhasePayload{}), + expectedType: struct { + BackupDataFiles bool `json:"backup_data_files"` + BackupLogFiles bool `json:"backup_log_files"` + BackupSchemaFiles bool `json:"backup_schema_files"` + SaveMigrationReports bool `json:"save_migration_reports"` + }{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testutils.CompareStructs(t, tt.actualType, reflect.TypeOf(tt.expectedType), tt.name) + }) + } +} diff --git a/yb-voyager/src/cp/yugabyted/yugabyted_test.go b/yb-voyager/src/cp/yugabyted/yugabyted_test.go new file mode 100644 index 0000000000..1c6690999d --- /dev/null +++ b/yb-voyager/src/cp/yugabyted/yugabyted_test.go @@ -0,0 +1,174 @@ +package yugabyted + +import ( + "context" + "database/sql" + "fmt" + "os" + "path/filepath" + "reflect" + "strings" + "sync" + "testing" + "time" + + "github.com/google/uuid" + "github.com/jackc/pgx/v4/pgxpool" + _ "github.com/lib/pq" // PostgreSQL driver + "github.com/stretchr/testify/assert" + controlPlane "github.com/yugabyte/yb-voyager/yb-voyager/src/cp" + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" + "github.com/yugabyte/yb-voyager/yb-voyager/testcontainers" +) + +func TestYugabyteDTableSchema(t *testing.T) { + ctx := context.Background() + + // Start a YugabyteDB container + ybContainer, host, port, err := testcontainers.StartDBContainer(ctx, testcontainers.YUGABYTEDB) + assert.NoError(t, err, "Failed to start YugabyteDB container") + defer ybContainer.Terminate(ctx) + + // Connect to the database + dsn := fmt.Sprintf("host=%s port=%s user=yugabyte password=yugabyte dbname=yugabyte sslmode=disable", host, port.Port()) + db, err := sql.Open("postgres", dsn) + assert.NoError(t, err) + defer db.Close() + + // Wait for the database to be ready + err = testcontainers.WaitForDBToBeReady(db) + assert.NoError(t, err) + // Export the database connection string to env variable YUGABYTED_DB_CONN_STRING + err = os.Setenv("YUGABYTED_DB_CONN_STRING", dsn) + + exportDir := filepath.Join(os.TempDir(), "yugabyted") + + // Create a temporary export directory for testing + err = os.MkdirAll(exportDir, 0755) + assert.NoError(t, err, "Failed to create temporary export directory") + // Ensure the directory is removed after the test + defer func() { + err := os.RemoveAll(exportDir) + assert.NoError(t, err, "Failed to remove temporary export directory") + }() + + controlPlane := New(exportDir) + controlPlane.eventChan = make(chan MigrationEvent, 100) + controlPlane.rowCountUpdateEventChan = make(chan []VisualizerTableMetrics, 200) + + err = controlPlane.connect() + assert.NoError(t, err, "Failed to connect to YugabyteDB") + + err = controlPlane.setupDatabase() + assert.NoError(t, err, "Failed to setup YugabyteDB database") + + expectedTables := map[string]map[string]testutils.ColumnPropertiesPG{ + QUALIFIED_YUGABYTED_METADATA_TABLE_NAME: { + "migration_uuid": {Type: "uuid", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "migration_phase": {Type: "integer", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "invocation_sequence": {Type: "integer", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "migration_dir": {Type: "character varying", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "database_name": {Type: "character varying", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "schema_name": {Type: "character varying", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "payload": {Type: "text", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "complexity": {Type: "character varying", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "db_type": {Type: "character varying", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "status": {Type: "character varying", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "invocation_timestamp": {Type: "timestamp with time zone", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "host_ip": {Type: "character varying", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "port": {Type: "integer", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "db_version": {Type: "character varying", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "voyager_info": {Type: "character varying", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + }, + YUGABYTED_TABLE_METRICS_TABLE_NAME: { + "migration_uuid": {Type: "uuid", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "table_name": {Type: "character varying", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "schema_name": {Type: "character varying", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "migration_phase": {Type: "integer", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "status": {Type: "integer", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "count_live_rows": {Type: "integer", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "count_total_rows": {Type: "integer", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "invocation_timestamp": {Type: "timestamp with time zone", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + }, + } + + // Validate the schema and tables + t.Run("Check all the expected tables and no extra tables", func(t *testing.T) { + testutils.CheckTableExistencePG(t, db, VISUALIZER_METADATA_SCHEMA, expectedTables) + }) + + // Validate columns for each table + for tableName, expectedColumns := range expectedTables { + t.Run(fmt.Sprintf("Check columns for %s table", tableName), func(t *testing.T) { + table := strings.Split(tableName, ".")[1] + testutils.CheckTableStructurePG(t, db, VISUALIZER_METADATA_SCHEMA, table, expectedColumns) + }) + } +} + +func TestYugabyteDStructs(t *testing.T) { + // Test the structs used in YugabyteD + + expectedVoyagerInstance := struct { + IP string + OperatingSystem string + DiskSpaceAvailable uint64 + ExportDirectory string + }{} + + t.Run("Validate VoyagerInstance Struct Definition", func(t *testing.T) { + testutils.CompareStructs(t, reflect.TypeOf(controlPlane.VoyagerInstance{}), reflect.TypeOf(expectedVoyagerInstance), "VoyagerInstance") + }) + + expectedMigrationEvent := struct { + MigrationUUID uuid.UUID `json:"migration_uuid"` + MigrationPhase int `json:"migration_phase"` + InvocationSequence int `json:"invocation_sequence"` + MigrationDirectory string `json:"migration_dir"` + DatabaseName string `json:"database_name"` + SchemaName string `json:"schema_name"` + DBIP string `json:"db_ip"` + Port int `json:"port"` + DBVersion string `json:"db_version"` + Payload string `json:"payload"` + VoyagerInfo string `json:"voyager_info"` + DBType string `json:"db_type"` + Status string `json:"status"` + InvocationTimestamp string `json:"invocation_timestamp"` + }{} + + t.Run("Validate MigrationEvent Struct Definition", func(t *testing.T) { + testutils.CompareStructs(t, reflect.TypeOf(MigrationEvent{}), reflect.TypeOf(expectedMigrationEvent), "MigrationEvent") + }) + + expectedVisualizerTableMetrics := struct { + MigrationUUID uuid.UUID `json:"migration_uuid"` + TableName string `json:"table_name"` + Schema string `json:"schema_name"` + MigrationPhase int `json:"migration_phase"` + Status int `json:"status"` + CountLiveRows int64 `json:"count_live_rows"` + CountTotalRows int64 `json:"count_total_rows"` + InvocationTimestamp string `json:"invocation_timestamp"` + }{} + + t.Run("Validate VisualizerTableMetrics Struct Definition", func(t *testing.T) { + testutils.CompareStructs(t, reflect.TypeOf(VisualizerTableMetrics{}), reflect.TypeOf(expectedVisualizerTableMetrics), "VisualizerTableMetrics") + }) + + expectedYugabyteD := struct { + sync.Mutex + migrationDirectory string + voyagerInfo *controlPlane.VoyagerInstance + waitGroup sync.WaitGroup + eventChan chan (MigrationEvent) + rowCountUpdateEventChan chan ([]VisualizerTableMetrics) + connPool *pgxpool.Pool + lastRowCountUpdate map[string]time.Time + latestInvocationSequence int + }{} + + t.Run("Validate YugabyteD Struct Definition", func(t *testing.T) { + testutils.CompareStructs(t, reflect.TypeOf(&YugabyteD{}).Elem(), reflect.TypeOf(&expectedYugabyteD).Elem(), "YugabyteD") + }) +} diff --git a/yb-voyager/src/datafile/descriptor_test.go b/yb-voyager/src/datafile/descriptor_test.go new file mode 100644 index 0000000000..dc617d0909 --- /dev/null +++ b/yb-voyager/src/datafile/descriptor_test.go @@ -0,0 +1,111 @@ +package datafile + +import ( + "os" + "path/filepath" + "reflect" + "testing" + + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" +) + +func TestDescriptorStructs(t *testing.T) { + // Define the expected structure for FileEntry + expectedFileEntry := struct { + FilePath string `json:"FilePath"` + TableName string `json:"TableName"` + RowCount int64 `json:"RowCount"` + FileSize int64 `json:"FileSize"` + }{} + + // Define the expected structure for Descriptor + expectedDescriptor := struct { + FileFormat string `json:"FileFormat"` + Delimiter string `json:"Delimiter"` + HasHeader bool `json:"HasHeader"` + ExportDir string `json:"-"` + QuoteChar byte `json:"QuoteChar,omitempty"` + EscapeChar byte `json:"EscapeChar,omitempty"` + NullString string `json:"NullString,omitempty"` + DataFileList []*FileEntry `json:"FileList"` + TableNameToExportedColumns map[string][]string `json:"TableNameToExportedColumns"` + }{} + + t.Run("Validate FileEntry Struct Definition", func(t *testing.T) { + testutils.CompareStructs(t, reflect.TypeOf(FileEntry{}), reflect.TypeOf(expectedFileEntry), "FileEntry") + }) + + t.Run("Validate Descriptor Struct Definition", func(t *testing.T) { + testutils.CompareStructs(t, reflect.TypeOf(Descriptor{}), reflect.TypeOf(expectedDescriptor), "Descriptor") + }) +} + +func TestDescriptorJson(t *testing.T) { + // Set up the temporary export directory + exportDir := filepath.Join(os.TempDir(), "descriptor_test") + outputFilePath := filepath.Join(exportDir, DESCRIPTOR_PATH) + + // Create a sample Descriptor instance + descriptor := Descriptor{ + FileFormat: "csv", + Delimiter: ",", + HasHeader: true, + ExportDir: exportDir, + QuoteChar: '"', + EscapeChar: '\\', + NullString: "NULL", + DataFileList: []*FileEntry{ + { + FilePath: "file.csv", // Use relative path for testing absolute path handling. + TableName: "public.my_table", + RowCount: 100, + FileSize: 2048, + }, + }, + TableNameToExportedColumns: map[string][]string{ + "public.my_table": {"id", "name", "age"}, + }, + } + + // Ensure the export directory exists + if err := os.MkdirAll(filepath.Join(exportDir, "metainfo"), 0755); err != nil { + t.Fatalf("Failed to create export directory: %v", err) + } + + // Clean up the export directory + defer func() { + if err := os.RemoveAll(exportDir); err != nil { + t.Fatalf("Failed to remove export directory: %v", err) + } + }() + + // Save the Descriptor to JSON + descriptor.Save() + + expectedJSON := `{ + "FileFormat": "csv", + "Delimiter": ",", + "HasHeader": true, + "QuoteChar": 34, + "EscapeChar": 92, + "NullString": "NULL", + "FileList": [ + { + "FilePath": "file.csv", + "TableName": "public.my_table", + "RowCount": 100, + "FileSize": 2048 + } + ], + "TableNameToExportedColumns": { + "public.my_table": [ + "id", + "name", + "age" + ] + } +}` + + // Compare the output JSON with the expected JSON + testutils.CompareJson(t, outputFilePath, expectedJSON, exportDir) +} diff --git a/yb-voyager/src/dbzm/status_test.go b/yb-voyager/src/dbzm/status_test.go new file mode 100644 index 0000000000..9b384e9ad4 --- /dev/null +++ b/yb-voyager/src/dbzm/status_test.go @@ -0,0 +1,50 @@ +package dbzm + +import ( + "reflect" + "testing" + + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" +) + +func TestExportStatusStructs(t *testing.T) { + test := []struct { + name string + actualType reflect.Type + expectedType interface{} + }{ + { + name: "Validate TableExportStatus Struct Definition", + actualType: reflect.TypeOf(TableExportStatus{}), + expectedType: struct { + Sno int `json:"sno"` + DatabaseName string `json:"database_name"` + SchemaName string `json:"schema_name"` + TableName string `json:"table_name"` + FileName string `json:"file_name"` + ExportedRowCountSnapshot int64 `json:"exported_row_count_snapshot"` + }{}, + }, + { + name: "Validate ExportStatus Struct Definition", + actualType: reflect.TypeOf(ExportStatus{}), + expectedType: struct { + Mode string `json:"mode"` + Tables []TableExportStatus `json:"tables"` + Sequences map[string]int64 `json:"sequences"` + }{}, + }, + } + + for _, tt := range test { + t.Run(tt.name, func(t *testing.T) { + testutils.CompareStructs(t, tt.actualType, reflect.TypeOf(tt.expectedType), tt.name) + }) + } +} + +// TODO: Implement this test +// The export status json file is created by debezium and currently we dont have infrastructure to test it. +// To test this we need to create a json file (using dbzm code) and read it back (here) and compare the values. +// func TestReadExportStatus(t *testing.T) { +//} diff --git a/yb-voyager/src/metadb/metadataDB_test.go b/yb-voyager/src/metadb/metadataDB_test.go new file mode 100644 index 0000000000..89648a26b7 --- /dev/null +++ b/yb-voyager/src/metadb/metadataDB_test.go @@ -0,0 +1,101 @@ +package metadb + +import ( + "database/sql" + "fmt" + "os" + "testing" + + _ "github.com/mattn/go-sqlite3" + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" +) + +// Test the initMetaDB function +func TestInitMetaDB(t *testing.T) { + // Define the expected columns and their types for each table + expectedTables := map[string]map[string]testutils.ColumnPropertiesSqlite{ + QUEUE_SEGMENT_META_TABLE_NAME: { + "segment_no": {Type: "INTEGER", PrimaryKey: 1}, + "file_path": {Type: "TEXT"}, + "size_committed": {Type: "INTEGER"}, + "total_events": {Type: "INTEGER"}, + "exporter_role": {Type: "TEXT"}, + "imported_by_target_db_importer": {Type: "INTEGER", Default: sql.NullString{String: "0", Valid: true}}, + "imported_by_source_replica_db_importer": {Type: "INTEGER", Default: sql.NullString{String: "0", Valid: true}}, + "imported_by_source_db_importer": {Type: "INTEGER", Default: sql.NullString{String: "0", Valid: true}}, + "archived": {Type: "INTEGER", Default: sql.NullString{String: "0", Valid: true}}, + "deleted": {Type: "INTEGER", Default: sql.NullString{String: "0", Valid: true}}, + "archive_location": {Type: "TEXT"}, + }, + EXPORTED_EVENTS_STATS_TABLE_NAME: { + // TODO: We have a composite primary key here (run_id, exporter_role, timestamp) + "run_id": {Type: "TEXT", PrimaryKey: 1}, + "exporter_role": {Type: "TEXT", PrimaryKey: 2}, + "timestamp": {Type: "INTEGER", PrimaryKey: 3}, + "num_total": {Type: "INTEGER"}, + "num_inserts": {Type: "INTEGER"}, + "num_updates": {Type: "INTEGER"}, + "num_deletes": {Type: "INTEGER"}, + }, + EXPORTED_EVENTS_STATS_PER_TABLE_TABLE_NAME: { + "exporter_role": {Type: "TEXT", PrimaryKey: 1}, + "schema_name": {Type: "TEXT", PrimaryKey: 2}, + "table_name": {Type: "TEXT", PrimaryKey: 3}, + "num_total": {Type: "INTEGER"}, + "num_inserts": {Type: "INTEGER"}, + "num_updates": {Type: "INTEGER"}, + "num_deletes": {Type: "INTEGER"}, + }, + JSON_OBJECTS_TABLE_NAME: { + "key": {Type: "TEXT", PrimaryKey: 1}, + "json_text": {Type: "TEXT"}, + }, + } + + // Create a temporary SQLite database file for testing + tempFile, err := os.CreateTemp(os.TempDir(), "test_meta_db_*.db") + if err != nil { + t.Fatalf("Failed to create temporary file: %v", err) + } + + // remove the temporary file + defer func() { + err := os.Remove(tempFile.Name()) + if err != nil { + t.Fatalf("Failed to remove temporary file: %v", err) + } + }() + + // Call initMetaDB with the path to the temporary file + err = initMetaDB(tempFile.Name()) // Pass the temp file path to initMetaDB + if err != nil { + t.Fatalf("Failed to initialize database: %v", err) + } else { + t.Logf("Database initialized successfully") + } + + // Open the temporary database for verification + db, err := sql.Open("sqlite3", tempFile.Name()) + if err != nil { + t.Fatalf("Failed to open temporary database: %v", err) + } + defer db.Close() + + // Verify the existence of each table and no extra tables + t.Run("Check table existence and no extra tables", func(t *testing.T) { + err := testutils.CheckTableExistenceSqlite(t, db, expectedTables) + if err != nil { + t.Errorf("Table existence mismatch: %v", err) + } + }) + + // Verify the structure of each table + for table, expectedColumns := range expectedTables { + t.Run(fmt.Sprintf("Check structure of %s table", table), func(t *testing.T) { + err := testutils.CheckTableStructureSqlite(db, table, expectedColumns) + if err != nil { + t.Errorf("Table %s structure mismatch: %v", table, err) + } + }) + } +} diff --git a/yb-voyager/src/migassessment/assessmentDB.go b/yb-voyager/src/migassessment/assessmentDB.go index c4700ccb63..687919122a 100644 --- a/yb-voyager/src/migassessment/assessmentDB.go +++ b/yb-voyager/src/migassessment/assessmentDB.go @@ -59,7 +59,7 @@ type TableIndexStats struct { SizeInBytes *int64 `json:"SizeInBytes"` } -func GetSourceMetadataDBFilePath() string { +var GetSourceMetadataDBFilePath = func() string { return filepath.Join(AssessmentDir, "dbs", "assessment.db") } diff --git a/yb-voyager/src/migassessment/assessmentDB_test.go b/yb-voyager/src/migassessment/assessmentDB_test.go new file mode 100644 index 0000000000..843d1cca06 --- /dev/null +++ b/yb-voyager/src/migassessment/assessmentDB_test.go @@ -0,0 +1,131 @@ +package migassessment + +import ( + "database/sql" + "fmt" + "os" + "testing" + + _ "github.com/mattn/go-sqlite3" + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" +) + +func TestInitAssessmentDB(t *testing.T) { + expectedTables := map[string]map[string]testutils.ColumnPropertiesSqlite{ + TABLE_INDEX_IOPS: { + "schema_name": {Type: "TEXT", PrimaryKey: 1}, + "object_name": {Type: "TEXT", PrimaryKey: 2}, + "object_type": {Type: "TEXT"}, + "seq_reads": {Type: "INTEGER"}, + "row_writes": {Type: "INTEGER"}, + "measurement_type": {Type: "TEXT", PrimaryKey: 3}, + }, + TABLE_INDEX_SIZES: { + "schema_name": {Type: "TEXT", PrimaryKey: 1}, + "object_name": {Type: "TEXT", PrimaryKey: 2}, + "object_type": {Type: "TEXT"}, + "size_in_bytes": {Type: "INTEGER"}, + }, + TABLE_ROW_COUNTS: { + "schema_name": {Type: "TEXT", PrimaryKey: 1}, + "table_name": {Type: "TEXT", PrimaryKey: 2}, + "row_count": {Type: "INTEGER"}, + }, + TABLE_COLUMNS_COUNT: { + "schema_name": {Type: "TEXT", PrimaryKey: 1}, + "object_name": {Type: "TEXT", PrimaryKey: 2}, + "object_type": {Type: "TEXT"}, + "column_count": {Type: "INTEGER"}, + }, + INDEX_TO_TABLE_MAPPING: { + "index_schema": {Type: "TEXT", PrimaryKey: 1}, + "index_name": {Type: "TEXT", PrimaryKey: 2}, + "table_schema": {Type: "TEXT"}, + "table_name": {Type: "TEXT"}, + }, + OBJECT_TYPE_MAPPING: { + "schema_name": {Type: "TEXT", PrimaryKey: 1}, + "object_name": {Type: "TEXT", PrimaryKey: 2}, + "object_type": {Type: "TEXT"}, + }, + TABLE_COLUMNS_DATA_TYPES: { + "schema_name": {Type: "TEXT", PrimaryKey: 1}, + "table_name": {Type: "TEXT", PrimaryKey: 2}, + "column_name": {Type: "TEXT", PrimaryKey: 3}, + "data_type": {Type: "TEXT"}, + }, + TABLE_INDEX_STATS: { + "schema_name": {Type: "TEXT", PrimaryKey: 1}, + "object_name": {Type: "TEXT", PrimaryKey: 2}, + "row_count": {Type: "INTEGER"}, + "column_count": {Type: "INTEGER"}, + "reads": {Type: "INTEGER"}, + "writes": {Type: "INTEGER"}, + "reads_per_second": {Type: "INTEGER"}, + "writes_per_second": {Type: "INTEGER"}, + "is_index": {Type: "BOOLEAN"}, + "object_type": {Type: "TEXT"}, + "parent_table_name": {Type: "TEXT"}, + "size_in_bytes": {Type: "INTEGER"}, + }, + DB_QUERIES_SUMMARY: { + "queryid": {Type: "BIGINT"}, + "query": {Type: "TEXT"}, + }, + } + + // Create a temporary SQLite database file for testing + tempFile, err := os.CreateTemp(os.TempDir(), "test_assessment_db_*.db") + if err != nil { + t.Fatalf("Failed to create temporary file: %v", err) + } + // Ensure the file is removed after the test + defer func() { + err := os.Remove(tempFile.Name()) + if err != nil { + t.Fatalf("Failed to remove temporary file: %v", err) + } + }() + + GetSourceMetadataDBFilePath = func() string { + return tempFile.Name() + } + + err = InitAssessmentDB() + if err != nil { + t.Fatalf("Failed to initialize database: %v", err) + } else { + t.Logf("Database initialized successfully") + } + + // Open the temporary database for verification + db, err := sql.Open("sqlite3", tempFile.Name()) + if err != nil { + t.Fatalf("Failed to open temporary database: %v", err) + } + defer db.Close() + + // Verify the existence of each table and no extra tables + t.Run("Check table existence and no extra tables", func(t *testing.T) { + err := testutils.CheckTableExistenceSqlite(t, db, expectedTables) + if err != nil { + t.Errorf("Table existence mismatch: %v", err) + } + }) + + // Verify the structure of each table + for table, expectedColumns := range expectedTables { + t.Run(fmt.Sprintf("Check structure of %s table", table), func(t *testing.T) { + err := testutils.CheckTableStructureSqlite(db, table, expectedColumns) + if err != nil { + t.Errorf("Table %s structure mismatch: %v", table, err) + } + }) + } + +} + +// Helper function to create a string pointer +func stringPointer(s string) *string { + return &s +} diff --git a/yb-voyager/src/namereg/namereg_test.go b/yb-voyager/src/namereg/namereg_test.go index 279ae9a919..0a0951581b 100644 --- a/yb-voyager/src/namereg/namereg_test.go +++ b/yb-voyager/src/namereg/namereg_test.go @@ -3,12 +3,16 @@ package namereg import ( "fmt" "os" + "path/filepath" + "reflect" + "strings" "testing" "github.com/samber/lo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" "github.com/yugabyte/yb-voyager/yb-voyager/src/utils/sqlname" ) @@ -377,7 +381,7 @@ func TestDifferentSchemaInSameDBAsSourceReplica2(t *testing.T) { //===================================================== type dummySourceDB struct { - tableNames map[string][]string // schemaName -> tableNames + tableNames map[string][]string // schemaName -> tableNames sequenceNames map[string][]string // schemaName -> sequenceNames } @@ -398,8 +402,8 @@ func (db *dummySourceDB) GetAllSequencesRaw(schemaName string) ([]string, error) } type dummyTargetDB struct { - tableNames map[string][]string // schemaName -> tableNames - sequenceNames map[string][]string // schemaName -> sequenceNames + tableNames map[string][]string // schemaName -> tableNames + sequenceNames map[string][]string // schemaName -> sequenceNames } func (db *dummyTargetDB) GetAllSchemaNamesRaw() ([]string, error) { @@ -414,7 +418,6 @@ func (db *dummyTargetDB) GetAllTableNamesRaw(schemaName string) ([]string, error return tableNames, nil } - func (db *dummyTargetDB) GetAllSequencesRaw(schemaName string) ([]string, error) { sequenceNames, ok := db.sequenceNames[schemaName] if !ok { @@ -448,18 +451,18 @@ func TestNameRegistryWithDummyDBs(t *testing.T) { } sourceNamesMap := make(map[string][]string) - for k,v := range dummySdb.tableNames { + for k, v := range dummySdb.tableNames { sourceNamesMap[k] = append(sourceNamesMap[k], v...) } - for k,v := range dummySdb.sequenceNames { + for k, v := range dummySdb.sequenceNames { sourceNamesMap[k] = append(sourceNamesMap[k], v...) } targetNamesMap := make(map[string][]string) - for k,v := range dummyTdb.tableNames { + for k, v := range dummyTdb.tableNames { targetNamesMap[k] = append(targetNamesMap[k], v...) } - for k,v := range dummyTdb.sequenceNames { + for k, v := range dummyTdb.sequenceNames { targetNamesMap[k] = append(targetNamesMap[k], v...) } @@ -497,7 +500,7 @@ func TestNameRegistryWithDummyDBs(t *testing.T) { seq1 := buildNameTuple(reg, "SAKILA", "SEQ1", "", "") stup, err := reg.LookupTableName("SEQ1") require.Nil(err) - assert.Equal(seq1, stup) + assert.Equal(seq1, stup) // When `export data` restarts, the registry should be reloaded from the file. reg = newNameRegistry("") @@ -549,3 +552,132 @@ func TestNameRegistryWithDummyDBs(t *testing.T) { assert.Equal(table1, ntup) assert.Equal(`SAKILA_FF."TABLE1"`, table1.ForUserQuery()) } + +// Unit tests for breaking changes in NameRegistry. + +func TestNameRegistryStructs(t *testing.T) { + + tests := []struct { + name string + actualType reflect.Type + expectedType interface{} + }{ + { + name: "Validate NameRegistryParams Struct Definition", + actualType: reflect.TypeOf(NameRegistryParams{}), + expectedType: struct { + FilePath string + Role string + SourceDBType string + SourceDBSchema string + SourceDBName string + SDB SourceDBInterface + TargetDBSchema string + YBDB YBDBInterface + }{}, + }, + { + name: "Validate NameRegistry Struct Definition", + actualType: reflect.TypeOf(NameRegistry{}), + expectedType: struct { + SourceDBType string + SourceDBSchemaNames []string + DefaultSourceDBSchemaName string + SourceDBTableNames map[string][]string + YBSchemaNames []string + DefaultYBSchemaName string + YBTableNames map[string][]string + DefaultSourceReplicaDBSchemaName string + params NameRegistryParams + }{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testutils.CompareStructs(t, tt.actualType, reflect.TypeOf(tt.expectedType), tt.name) + }) + } +} + +func TestNameRegistryJson(t *testing.T) { + exportDir := filepath.Join(os.TempDir(), "namereg") + outputFilePath := filepath.Join(exportDir, "test_dummy_name_registry.json") + + // Create a sample NameRegistry instance + reg := &NameRegistry{ + SourceDBType: ORACLE, + params: NameRegistryParams{ + FilePath: outputFilePath, + Role: TARGET_DB_IMPORTER_ROLE, + SourceDBType: ORACLE, + SourceDBSchema: "SAKILA", + SourceDBName: "ORCLPDB1", + TargetDBSchema: "ybsakila", + }, + SourceDBSchemaNames: []string{"SAKILA"}, + DefaultSourceDBSchemaName: "SAKILA", + SourceDBTableNames: map[string][]string{ + "SAKILA": {"TABLE1", "TABLE2", "MixedCaps", "lower_caps"}, + }, + YBSchemaNames: []string{"ybsakila"}, + DefaultYBSchemaName: "ybsakila", + YBTableNames: map[string][]string{ + "ybsakila": {"table1", "table2", "mixedcaps", "lower_caps"}, + }, + DefaultSourceReplicaDBSchemaName: "SAKILA_FF", + } + + // Ensure the export directory exists + if err := os.MkdirAll(exportDir, 0755); err != nil { + t.Fatalf("Failed to create export directory: %v", err) + } + + // Clean up the export directory + defer func() { + if err := os.RemoveAll(exportDir); err != nil { + t.Fatalf("Failed to remove export directory: %v", err) + } + }() + + // Marshal the NameRegistry instance to JSON + err := reg.save() + if err != nil { + t.Fatalf("Failed to save NameRegistry to JSON: %v", err) + } + + // TODO: Use a single string instead of a slice of strings for the expected JSON + expectedJSON := strings.Join([]string{ + "{", + ` "SourceDBType": "oracle",`, + ` "SourceDBSchemaNames": [`, + ` "SAKILA"`, + " ],", + ` "DefaultSourceDBSchemaName": "SAKILA",`, + ` "SourceDBTableNames": {`, + ` "SAKILA": [`, + ` "TABLE1",`, + ` "TABLE2",`, + ` "MixedCaps",`, + ` "lower_caps"`, + " ]", + " },", + ` "YBSchemaNames": [`, + ` "ybsakila"`, + " ],", + ` "DefaultYBSchemaName": "ybsakila",`, + ` "YBTableNames": {`, + ` "ybsakila": [`, + ` "table1",`, + ` "table2",`, + ` "mixedcaps",`, + ` "lower_caps"`, + " ]", + " },", + ` "DefaultSourceReplicaDBSchemaName": "SAKILA_FF"`, + "}", + }, "\n") + + // Read the JSON file and compare it with the expected JSON + testutils.CompareJson(t, outputFilePath, expectedJSON, exportDir) +} diff --git a/yb-voyager/src/testutils/testing_utils.go b/yb-voyager/src/testutils/testing_utils.go new file mode 100644 index 0000000000..2a10007dee --- /dev/null +++ b/yb-voyager/src/testutils/testing_utils.go @@ -0,0 +1,352 @@ +package testutils + +import ( + "database/sql" + "fmt" + "os" + "reflect" + "regexp" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/assert" +) + +type ColumnPropertiesSqlite struct { + Type string // Data type (e.g., INTEGER, TEXT) + PrimaryKey int // Whether it's a primary key values can be 0,1,2,3. If 1 then it is primary key. 2,3 etc. are used for composite primary key + NotNull bool // Whether the column has a NOT NULL constraint + Default sql.NullString // Default value, if any (nil means no default) +} + +// Column represents a column's expected metadata +type ColumnPropertiesPG struct { + Type string + IsPrimary bool + IsNullable string + Default sql.NullString +} + +// CompareStructs compares two struct types and reports any mismatches. +func CompareStructs(t *testing.T, actual, expected reflect.Type, structName string) { + assert.Equal(t, reflect.Struct, actual.Kind(), "%s: Actual type must be a struct. There is some breaking change!", structName) + assert.Equal(t, reflect.Struct, expected.Kind(), "%s: Expected type must be a struct. There is some breaking change!", structName) + + for i := 0; i < max(actual.NumField(), expected.NumField()); i++ { + var actualField, expectedField reflect.StructField + var actualExists, expectedExists bool + + if i < actual.NumField() { + actualField = actual.Field(i) + actualExists = true + } + if i < expected.NumField() { + expectedField = expected.Field(i) + expectedExists = true + } + + // Assert field names match + if actualExists && expectedExists { + assert.Equal(t, expectedField.Name, actualField.Name, "%s: Field name mismatch at position %d. There is some breaking change!", structName, i) + assert.Equal(t, expectedField.Type.String(), actualField.Type.String(), "%s: Field type mismatch for field %s. There is some breaking change!", structName, expectedField.Name) + assert.Equal(t, expectedField.Tag, actualField.Tag, "%s: Field tag mismatch for field %s. There is some breaking change!", structName, expectedField.Name) + } + + // Report missing or extra fields + if !actualExists && expectedExists { + t.Errorf("%s: Missing field %s of type %s. There is some breaking change!", structName, expectedField.Name, expectedField.Type) + } + if actualExists && !expectedExists { + t.Errorf("%s: Unexpected field %s of type %s. There is some breaking change!", structName, actualField.Name, actualField.Type) + } + } +} + +// CompareJson compares two structs by marshalling them into JSON and reports any differences. +func CompareJson(t *testing.T, outputFilePath string, expectedJSON string, exportDir string) { + // Read the output JSON file + outputBytes, err := os.ReadFile(outputFilePath) + if err != nil { + t.Fatalf("Failed to read output JSON file: %v", err) + } + + // Compare the output JSON with the expected JSON + if diff := cmp.Diff(expectedJSON, string(outputBytes)); diff != "" { + t.Errorf("JSON file mismatch (-expected +actual):\n%s", diff) + } + + // Can be used if we don't want to compare pretty printed JSON + // assert.JSONEqf(t, expectedJSON, string(outputBytes), "JSON file mismatch. There is some breaking change!") +} + +// Helper function to check table structure +func CheckTableStructureSqlite(db *sql.DB, tableName string, expectedColumns map[string]ColumnPropertiesSqlite) error { + // Query to get table info + rows, err := db.Query(fmt.Sprintf("PRAGMA table_info(%s);", tableName)) + if err != nil { + return fmt.Errorf("failed to get table info for %s: %w", tableName, err) + } + defer rows.Close() + + // Check if columns match expected ones + actualColumns := make(map[string]ColumnPropertiesSqlite) + for rows.Next() { + var cid int + var name string + var cp ColumnPropertiesSqlite + if err := rows.Scan(&cid, &name, &cp.Type, &cp.NotNull, &cp.Default, &cp.PrimaryKey); err != nil { + return err + } + actualColumns[name] = ColumnPropertiesSqlite{ + Type: cp.Type, + PrimaryKey: cp.PrimaryKey, + NotNull: cp.NotNull, + Default: cp.Default, + } + } + + // Compare actual columns with expected columns + for colName, expectedProps := range expectedColumns { + actualProps, exists := actualColumns[colName] + if !exists { + return fmt.Errorf("table %s missing expected column: %s. There is some breaking change!", tableName, colName) + } + + // Check type + if actualProps.Type != expectedProps.Type { + return fmt.Errorf("table %s column %s: expected type %s, got %s. There is some breaking change!", tableName, colName, expectedProps.Type, actualProps.Type) + } + + // Check if it's part of the primary key + if actualProps.PrimaryKey != expectedProps.PrimaryKey { + return fmt.Errorf("table %s column %s: expected primary key to be %v, got %v. There is some breaking change!", tableName, colName, expectedProps.PrimaryKey, actualProps.PrimaryKey) + } + + // Check NOT NULL constraint + if actualProps.NotNull != expectedProps.NotNull { + return fmt.Errorf("table %s column %s: expected NOT NULL to be %v, got %v. There is some breaking change!", tableName, colName, expectedProps.NotNull, actualProps.NotNull) + } + + // Check default value + if (expectedProps.Default.Valid && !actualProps.Default.Valid) || (!expectedProps.Default.Valid && actualProps.Default.Valid) || (expectedProps.Default.Valid && actualProps.Default.Valid && expectedProps.Default.String != actualProps.Default.String) { + return fmt.Errorf("table %s column %s: expected default value %v, got %v. There is some breaking change!", tableName, colName, expectedProps.Default, actualProps.Default) + } + } + + // Check for any additional unexpected columns + for colName := range actualColumns { + if _, exists := expectedColumns[colName]; !exists { + return fmt.Errorf("table %s has unexpected additional column: %s. There is some breaking change!", tableName, colName) + } + } + + return nil +} + +// Helper function to check table structure +func CheckTableStructurePG(t *testing.T, db *sql.DB, schema, table string, expectedColumns map[string]ColumnPropertiesPG) { + queryColumns := ` + SELECT column_name, data_type, is_nullable, column_default + FROM information_schema.columns + WHERE table_name = $1;` + + rows, err := db.Query(queryColumns, table) + if err != nil { + t.Fatalf("Failed to query columns for table %s.%s: %v", schema, table, err) + } + defer rows.Close() + + actualColumns := make(map[string]ColumnPropertiesPG) + for rows.Next() { + var colName string + var col ColumnPropertiesPG + err := rows.Scan(&colName, &col.Type, &col.IsNullable, &col.Default) + if err != nil { + t.Fatalf("Failed to scan column metadata: %v", err) + } + actualColumns[colName] = col + } + + // Compare columns + for colName, expectedProps := range expectedColumns { + actual, found := actualColumns[colName] + if !found { + t.Errorf("Missing expected column in table %s.%s: %s.\nThere is some breaking change!", schema, table, colName) + continue + } + if actual.Type != expectedProps.Type || actual.IsNullable != expectedProps.IsNullable || actual.Default != expectedProps.Default { + t.Errorf("Column mismatch in table %s.%s: \nexpected %+v, \ngot %+v.\nThere is some breaking change!", schema, table, expectedProps, actual) + } + } + + // Check for extra columns + for actualName := range actualColumns { + found := false + for expectedName, _ := range expectedColumns { + if actualName == expectedName { + found = true + break + } + } + if !found { + t.Errorf("Unexpected column in table %s.%s: %s.\nThere is some breaking change!", schema, table, actualName) + } + } + + // Check primary keys + checkPrimaryKeyOfTablePG(t, db, schema, table, expectedColumns) +} + +func checkPrimaryKeyOfTablePG(t *testing.T, db *sql.DB, schema, table string, expectedColumns map[string]ColumnPropertiesPG) { + // Validate primary keys + queryPrimaryKeys := ` + SELECT conrelid::regclass AS table_name, + conname AS primary_key, + pg_get_constraintdef(oid) + FROM pg_constraint + WHERE contype = 'p' -- 'p' indicates primary key + AND conrelid::regclass::text = $1 + ORDER BY conrelid::regclass::text, contype DESC;` + + rows, err := db.Query(queryPrimaryKeys, fmt.Sprintf("%s.%s", schema, table)) + if err != nil { + t.Fatalf("Failed to query primary keys for table %s.%s: %v", schema, table, err) + } + defer rows.Close() + + // Map to store primary key columns (not just the constraint name) + // Output is like: + // table_name | primary_key | primary_key_definition + // ybvoyager_metadata.ybvoyager_import_data_batches_metainfo_v3 | ybvoyager_import_data_batches_metainfo_v3_pkey | PRIMARY KEY (migration_uuid, data_file_name, batch_number, schema_name, table_name) + primaryKeyColumns := map[string]bool{} + for rows.Next() { + var tableName, pk, constraintDef string + if err := rows.Scan(&tableName, &pk, &constraintDef); err != nil { + t.Fatalf("Failed to scan primary key: %v", err) + } + + // Parse the columns from the constraint definition (e.g., "PRIMARY KEY (col1, col2, ...)") + columns := parsePrimaryKeyColumnsPG(constraintDef) + for _, col := range columns { + primaryKeyColumns[col] = true + } + } + + // Check if the primary key columns match the expected primary key columns + for expectedName, expectedParams := range expectedColumns { + if expectedParams.IsPrimary { + if _, found := primaryKeyColumns[expectedName]; !found { + t.Errorf("Missing expected primary key column in table %s.%s: %s.\nThere is some breaking change!", schema, table, expectedName) + } + } + } + + // Check if there are any extra primary key columns + for col := range primaryKeyColumns { + found := false + for expectedName, expectedParams := range expectedColumns { + if expectedName == col && expectedParams.IsPrimary { + found = true + break + } + } + if !found { + t.Errorf("Unexpected primary key column in table %s.%s: %s.\nThere is some breaking change!", schema, table, col) + } + } +} + +// Helper function to parse primary key columns from the constraint definition +func parsePrimaryKeyColumnsPG(constraintDef string) []string { + // Define the regex pattern + re := regexp.MustCompile(`PRIMARY KEY\s*\((.*?)\)`) + + // Extract the column list inside "PRIMARY KEY(...)" + matches := re.FindStringSubmatch(constraintDef) + if len(matches) < 2 { + return nil // Return nil if no match is found + } + + // Split by commas to get individual column names + columns := strings.Split(matches[1], ",") + for i := range columns { + columns[i] = strings.TrimSpace(columns[i]) // Remove extra spaces around column names + } + + return columns +} + +// Helper function to check table existence and no extra tables +func CheckTableExistenceSqlite(t *testing.T, db *sql.DB, expectedTables map[string]map[string]ColumnPropertiesSqlite) error { + // Query to get table names + rows, err := db.Query("SELECT name FROM sqlite_master WHERE type='table';") + if err != nil { + return fmt.Errorf("failed to get table names: %w", err) + } + defer rows.Close() + + // Check if tables match expected ones + actualTables := make(map[string]struct{}) + for rows.Next() { + var tableName string + if err := rows.Scan(&tableName); err != nil { + return err + } + actualTables[tableName] = struct{}{} + } + + // Compare actual tables with expected tables + for tableName := range expectedTables { + if _, exists := actualTables[tableName]; !exists { + return fmt.Errorf("expected table %s not found. There is some breaking change!", tableName) + } else { + t.Logf("Found table: %s", tableName) + } + } + + // Check for any additional unexpected tables + for tableName := range actualTables { + if _, exists := expectedTables[tableName]; !exists { + return fmt.Errorf("unexpected additional table: %s. There is some breaking change!", tableName) + } + } + + return nil +} + +// validateSchema validates the schema, tables, and columns +func CheckTableExistencePG(t *testing.T, db *sql.DB, schema string, expectedTables map[string]map[string]ColumnPropertiesPG) { + // Check all tables in the schema + queryTables := `SELECT table_schema || '.' || table_name AS qualified_table_name + FROM information_schema.tables + WHERE table_schema = $1;` + rows, err := db.Query(queryTables, schema) + if err != nil { + t.Fatalf("Failed to query tables in schema %s: %v", schema, err) + } + defer rows.Close() + + actualTables := make(map[string]bool) + for rows.Next() { + var tableName string + if err := rows.Scan(&tableName); err != nil { + t.Fatalf("Failed to scan table name: %v", err) + } + actualTables[tableName] = true + } + + // Compare tables + for expectedTable := range expectedTables { + if !actualTables[expectedTable] { + t.Errorf("Missing expected table: %s", expectedTable) + } + } + + // Check for extra tables + for actualTable := range actualTables { + if _, found := expectedTables[actualTable]; !found { + t.Errorf("Unexpected table found: %s", actualTable) + } + } +} diff --git a/yb-voyager/src/tgtdb/postgres_test.go b/yb-voyager/src/tgtdb/postgres_test.go new file mode 100644 index 0000000000..251ced5a63 --- /dev/null +++ b/yb-voyager/src/tgtdb/postgres_test.go @@ -0,0 +1,82 @@ +package tgtdb + +import ( + "context" + "database/sql" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" + "github.com/yugabyte/yb-voyager/yb-voyager/testcontainers" +) + +func TestCreateVoyagerSchemaPG(t *testing.T) { + ctx := context.Background() + + // Start a PostgreSQL container + pgContainer, host, port, err := testcontainers.StartDBContainer(ctx, testcontainers.POSTGRESQL) + assert.NoError(t, err, "Failed to start PostgreSQL container") + defer pgContainer.Terminate(ctx) + + // Connect to the database + dsn := fmt.Sprintf("host=%s port=%s user=testuser password=testpassword dbname=testdb sslmode=disable", host, port.Port()) + db, err := sql.Open("postgres", dsn) + assert.NoError(t, err) + defer db.Close() + + // Wait for the database to be ready + err = testcontainers.WaitForDBToBeReady(db) + assert.NoError(t, err) + + // Initialize the TargetYugabyteDB instance + pg := &TargetPostgreSQL{ + db: db, + } + + // Call CreateVoyagerSchema + err = pg.CreateVoyagerSchema() + assert.NoError(t, err, "CreateVoyagerSchema failed") + + expectedTables := map[string]map[string]testutils.ColumnPropertiesPG{ + BATCH_METADATA_TABLE_NAME: { + "migration_uuid": {Type: "uuid", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "data_file_name": {Type: "character varying", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "batch_number": {Type: "integer", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "schema_name": {Type: "character varying", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "table_name": {Type: "character varying", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "rows_imported": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + }, + EVENT_CHANNELS_METADATA_TABLE_NAME: { + "migration_uuid": {Type: "uuid", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "channel_no": {Type: "integer", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "last_applied_vsn": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_inserts": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_deletes": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_updates": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + }, + EVENTS_PER_TABLE_METADATA_TABLE_NAME: { + "migration_uuid": {Type: "uuid", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "table_name": {Type: "character varying", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "channel_no": {Type: "integer", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "total_events": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_inserts": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_deletes": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_updates": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + }, + } + + // Validate the schema and tables + t.Run("Check all the expected tables and no extra tables", func(t *testing.T) { + testutils.CheckTableExistencePG(t, db, BATCH_METADATA_TABLE_SCHEMA, expectedTables) + }) + + // Validate columns for each table + for tableName, expectedColumns := range expectedTables { + t.Run(fmt.Sprintf("Check columns for %s table", tableName), func(t *testing.T) { + table := strings.Split(tableName, ".")[1] + testutils.CheckTableStructurePG(t, db, BATCH_METADATA_TABLE_SCHEMA, table, expectedColumns) + }) + } +} diff --git a/yb-voyager/src/tgtdb/yugabytedb_test.go b/yb-voyager/src/tgtdb/yugabytedb_test.go new file mode 100644 index 0000000000..af22664460 --- /dev/null +++ b/yb-voyager/src/tgtdb/yugabytedb_test.go @@ -0,0 +1,82 @@ +package tgtdb + +import ( + "context" + "database/sql" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/yugabyte/yb-voyager/yb-voyager/src/testutils" + "github.com/yugabyte/yb-voyager/yb-voyager/testcontainers" +) + +func TestCreateVoyagerSchemaYB(t *testing.T) { + ctx := context.Background() + + // Start a YugabyteDB container + ybContainer, host, port, err := testcontainers.StartDBContainer(ctx, testcontainers.YUGABYTEDB) + assert.NoError(t, err, "Failed to start YugabyteDB container") + defer ybContainer.Terminate(ctx) + + // Connect to the database + dsn := fmt.Sprintf("host=%s port=%s user=yugabyte password=yugabyte dbname=yugabyte sslmode=disable", host, port.Port()) + db, err := sql.Open("postgres", dsn) + assert.NoError(t, err) + defer db.Close() + + // Wait for the database to be ready + err = testcontainers.WaitForDBToBeReady(db) + assert.NoError(t, err) + + // Initialize the TargetYugabyteDB instance + yb := &TargetYugabyteDB{ + db: db, + } + + // Call CreateVoyagerSchema + err = yb.CreateVoyagerSchema() + assert.NoError(t, err, "CreateVoyagerSchema failed") + + expectedTables := map[string]map[string]testutils.ColumnPropertiesPG{ + BATCH_METADATA_TABLE_NAME: { + "migration_uuid": {Type: "uuid", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "data_file_name": {Type: "character varying", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "batch_number": {Type: "integer", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "schema_name": {Type: "character varying", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "table_name": {Type: "character varying", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "rows_imported": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + }, + EVENT_CHANNELS_METADATA_TABLE_NAME: { + "migration_uuid": {Type: "uuid", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "channel_no": {Type: "integer", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "last_applied_vsn": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_inserts": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_deletes": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_updates": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + }, + EVENTS_PER_TABLE_METADATA_TABLE_NAME: { + "migration_uuid": {Type: "uuid", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "table_name": {Type: "character varying", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "channel_no": {Type: "integer", IsNullable: "NO", Default: sql.NullString{Valid: false}, IsPrimary: true}, + "total_events": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_inserts": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_deletes": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + "num_updates": {Type: "bigint", IsNullable: "YES", Default: sql.NullString{Valid: false}, IsPrimary: false}, + }, + } + + // Validate the schema and tables + t.Run("Check all the expected tables and no extra tables", func(t *testing.T) { + testutils.CheckTableExistencePG(t, db, BATCH_METADATA_TABLE_SCHEMA, expectedTables) + }) + + // Validate columns for each table + for tableName, expectedColumns := range expectedTables { + t.Run(fmt.Sprintf("Check columns for %s table", tableName), func(t *testing.T) { + table := strings.Split(tableName, ".")[1] + testutils.CheckTableStructurePG(t, db, BATCH_METADATA_TABLE_SCHEMA, table, expectedColumns) + }) + } +} diff --git a/yb-voyager/testcontainers/testcontainers.go b/yb-voyager/testcontainers/testcontainers.go new file mode 100644 index 0000000000..336d7b2e30 --- /dev/null +++ b/yb-voyager/testcontainers/testcontainers.go @@ -0,0 +1,108 @@ +package testcontainers + +import ( + "context" + "database/sql" + "fmt" + "time" + + "github.com/docker/go-connections/nat" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" +) + +const ( + POSTGRESQL = "postgresql" + YUGABYTEDB = "yugabytedb" +) + +func StartDBContainer(ctx context.Context, dbType string) (testcontainers.Container, string, nat.Port, error) { + switch dbType { + case POSTGRESQL: + return startPostgresContainer(ctx) + case YUGABYTEDB: + return startYugabyteDBContainer(ctx) + default: + return nil, "", "", fmt.Errorf("unsupported database type: %s", dbType) + } +} + +func startPostgresContainer(ctx context.Context) (container testcontainers.Container, host string, port nat.Port, err error) { + // Create a PostgreSQL TestContainer + req := testcontainers.ContainerRequest{ + Image: "postgres:latest", // Use the latest PostgreSQL image + ExposedPorts: []string{"5432/tcp"}, + Env: map[string]string{ + "POSTGRES_USER": "testuser", // Set PostgreSQL username + "POSTGRES_PASSWORD": "testpassword", // Set PostgreSQL password + "POSTGRES_DB": "testdb", // Set PostgreSQL database name + }, + WaitingFor: wait.ForListeningPort("5432/tcp").WithStartupTimeout(30 * 1e9), // Wait for PostgreSQL to be ready + } + + // Start the container + pgContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + + if err != nil { + return nil, "", "", err + } + + // Get the container's host and port + host, err = pgContainer.Host(ctx) + if err != nil { + return nil, "", "", err + } + + port, err = pgContainer.MappedPort(ctx, "5432") + if err != nil { + return nil, "", "", err + } + + return pgContainer, host, port, nil +} + +func startYugabyteDBContainer(ctx context.Context) (container testcontainers.Container, host string, port nat.Port, err error) { + // Create a YugabyteDB TestContainer + req := testcontainers.ContainerRequest{ + Image: "yugabytedb/yugabyte:latest", + ExposedPorts: []string{"5433/tcp"}, + WaitingFor: wait.ForListeningPort("5433/tcp"), + Cmd: []string{"bin/yugabyted", "start", "--daemon=false"}, + } + + // Start the container + ybContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, "", "", err + } + + // Get the container's host and port + host, err = ybContainer.Host(ctx) + if err != nil { + return nil, "", "", err + } + + port, err = ybContainer.MappedPort(ctx, "5433") + if err != nil { + return nil, "", "", err + } + + return ybContainer, host, port, nil +} + +// waitForDBConnection waits until the database is ready for connections. +func WaitForDBToBeReady(db *sql.DB) error { + for i := 0; i < 12; i++ { + if err := db.Ping(); err == nil { + return nil + } + time.Sleep(5 * time.Second) + } + return fmt.Errorf("database did not become ready in time") +}