@@ -46,6 +46,11 @@ import (
4646
4747const (
4848 anyErrorIndicator = "<any-error-of-any-kind>"
49+
50+ // Migration metric names as exposed via /debug/vars
51+ metricStartedMigrations = "StartedMigrations"
52+ metricSuccessfulMigrations = "SuccessfulMigrations"
53+ metricFailedMigrations = "FailedMigrations"
4954)
5055
5156type testOnlineDDLStatementParams struct {
@@ -3049,3 +3054,164 @@ func runInTransaction(t *testing.T, ctx context.Context, tablet *cluster.Vttable
30493054 }
30503055 return err
30513056}
3057+
3058+ // TestMigrationMetrics tests that migration metrics are correctly incremented
3059+ // when migrations are executed end-to-end. This verifies that the metrics
3060+ // tracking works correctly in a real cluster environment.
3061+ func TestMigrationMetrics (t * testing.T ) {
3062+ throttler .EnableLagThrottlerAndWaitForStatus (t , clusterInstance )
3063+
3064+ shards = clusterInstance .Keyspaces [0 ].Shards
3065+ require .Equal (t , 1 , len (shards ))
3066+
3067+ // Helper function to get metric value from /debug/vars
3068+ getMetric := func (metricName string ) int64 {
3069+ vars := primaryTablet .VttabletProcess .GetVars ()
3070+ if val , ok := vars [metricName ]; ok {
3071+ switch v := val .(type ) {
3072+ case float64 :
3073+ return int64 (v )
3074+ case int64 :
3075+ return v
3076+ case int :
3077+ return int64 (v )
3078+ }
3079+ }
3080+ return 0
3081+ }
3082+
3083+ // Create the stress_test table for our tests
3084+ t .Run ("setup table" , func (t * testing.T ) {
3085+ createStatement := `
3086+ CREATE TABLE IF NOT EXISTS stress_test (
3087+ id bigint(20) not null,
3088+ rand_val varchar(32) null default '',
3089+ hint_col varchar(64) not null default 'just-created',
3090+ created_timestamp timestamp not null default current_timestamp,
3091+ updates int unsigned not null default 0,
3092+ PRIMARY KEY (id),
3093+ key created_idx(created_timestamp),
3094+ key updates_idx(updates)
3095+ ) ENGINE=InnoDB
3096+ `
3097+ uuid := testOnlineDDLStatement (t , & testOnlineDDLStatementParams {
3098+ ddlStatement : createStatement ,
3099+ ddlStrategy : "direct" ,
3100+ executeStrategy : "vtgate" ,
3101+ })
3102+ // For direct strategy, uuid may be empty
3103+ _ = uuid
3104+ })
3105+
3106+ // Test 1: Successful migration increments metrics
3107+ t .Run ("successful migration increments metrics" , func (t * testing.T ) {
3108+ // Get baseline metrics
3109+ startedBefore := getMetric (metricStartedMigrations )
3110+ successfulBefore := getMetric (metricSuccessfulMigrations )
3111+
3112+ // Execute a simple migration
3113+ uuid := testOnlineDDLStatement (t , & testOnlineDDLStatementParams {
3114+ ddlStatement : "ALTER TABLE stress_test ENGINE=InnoDB" ,
3115+ ddlStrategy : "vitess" ,
3116+ executeStrategy : "vtgate" ,
3117+ })
3118+ require .NotEmpty (t , uuid )
3119+
3120+ // Wait for migration to complete
3121+ onlineddl .WaitForMigrationStatus (t , & vtParams , shards , uuid ,
3122+ normalWaitTime , schema .OnlineDDLStatusComplete )
3123+
3124+ // Check metrics incremented correctly using assert.Eventually
3125+ assert .EventuallyWithT (t , func (c * assert.CollectT ) {
3126+ startedAfter := getMetric (metricStartedMigrations )
3127+ successfulAfter := getMetric (metricSuccessfulMigrations )
3128+
3129+ assert .Equal (c , startedBefore + 1 , startedAfter ,
3130+ "StartedMigrations should increment by 1" )
3131+ assert .Equal (c , successfulBefore + 1 , successfulAfter ,
3132+ "SuccessfulMigrations should increment by 1" )
3133+ }, 10 * time .Second , time .Second , "metrics did not increment correctly" )
3134+ })
3135+
3136+ // Test 2: Failed migration increments metrics
3137+ t .Run ("failed migration increments metrics" , func (t * testing.T ) {
3138+ failedBefore := getMetric (metricFailedMigrations )
3139+ startedBefore := getMetric (metricStartedMigrations )
3140+
3141+ // Execute a migration that will fail (invalid column)
3142+ uuid := testOnlineDDLStatement (t , & testOnlineDDLStatementParams {
3143+ ddlStatement : "ALTER TABLE stress_test DROP COLUMN nonexistent_column" ,
3144+ ddlStrategy : "vitess" ,
3145+ executeStrategy : "vtgate" ,
3146+ })
3147+ require .NotEmpty (t , uuid )
3148+
3149+ // Wait for migration to fail
3150+ onlineddl .WaitForMigrationStatus (t , & vtParams , shards , uuid ,
3151+ normalWaitTime , schema .OnlineDDLStatusFailed )
3152+
3153+ // Verify metrics
3154+ assert .EventuallyWithT (t , func (c * assert.CollectT ) {
3155+ failedAfter := getMetric (metricFailedMigrations )
3156+ startedAfter := getMetric (metricStartedMigrations )
3157+
3158+ assert .Equal (c , failedBefore + 1 , failedAfter ,
3159+ "FailedMigrations should increment by 1" )
3160+ assert .Equal (c , startedBefore + 1 , startedAfter ,
3161+ "StartedMigrations should increment by 1 even for failed migrations" )
3162+ }, 10 * time .Second , time .Second , "metrics did not increment correctly" )
3163+ })
3164+
3165+ // Test 3: Multiple migrations increment metrics correctly
3166+ t .Run ("multiple migrations increment metrics correctly" , func (t * testing.T ) {
3167+ startedBefore := getMetric (metricStartedMigrations )
3168+ successfulBefore := getMetric (metricSuccessfulMigrations )
3169+
3170+ // Run 3 migrations
3171+ uuids := make ([]string , 3 )
3172+ for i := range 3 {
3173+ uuids [i ] = testOnlineDDLStatement (t , & testOnlineDDLStatementParams {
3174+ ddlStatement : "ALTER TABLE stress_test ENGINE=InnoDB" ,
3175+ ddlStrategy : "vitess" ,
3176+ executeStrategy : "vtgate" ,
3177+ })
3178+ require .NotEmpty (t , uuids [i ])
3179+ }
3180+
3181+ // Wait for all to complete
3182+ for _ , uuid := range uuids {
3183+ onlineddl .WaitForMigrationStatus (t , & vtParams , shards , uuid ,
3184+ extendedWaitTime , schema .OnlineDDLStatusComplete )
3185+ }
3186+
3187+ // Verify metrics
3188+ assert .EventuallyWithT (t , func (c * assert.CollectT ) {
3189+ startedAfter := getMetric (metricStartedMigrations )
3190+ successfulAfter := getMetric (metricSuccessfulMigrations )
3191+
3192+ assert .Equal (c , startedBefore + 3 , startedAfter ,
3193+ "StartedMigrations should increment by 3" )
3194+ assert .Equal (c , successfulBefore + 3 , successfulAfter ,
3195+ "SuccessfulMigrations should increment by 3" )
3196+ }, 15 * time .Second , time .Second , "metrics did not increment correctly" )
3197+ })
3198+
3199+ // Test 4: Verify metrics are accessible via /debug/vars
3200+ t .Run ("metrics are exposed via debug vars" , func (t * testing.T ) {
3201+ vars := primaryTablet .VttabletProcess .GetVars ()
3202+ require .NotNil (t , vars )
3203+
3204+ // Verify all three metrics exist
3205+ assert .Contains (t , vars , metricStartedMigrations ,
3206+ "StartedMigrations metric should be exposed" )
3207+ assert .Contains (t , vars , metricSuccessfulMigrations ,
3208+ "SuccessfulMigrations metric should be exposed" )
3209+ assert .Contains (t , vars , metricFailedMigrations ,
3210+ "FailedMigrations metric should be exposed" )
3211+
3212+ // Verify metrics are non-negative
3213+ assert .GreaterOrEqual (t , getMetric (metricStartedMigrations ), int64 (0 ))
3214+ assert .GreaterOrEqual (t , getMetric (metricSuccessfulMigrations ), int64 (0 ))
3215+ assert .GreaterOrEqual (t , getMetric (metricFailedMigrations ), int64 (0 ))
3216+ })
3217+ }
0 commit comments