mockserver-client 7.2.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2368,39 +2368,262 @@ module MockServer
2368
2368
  end
2369
2369
  end
2370
2370
 
2371
- # The traffic-shaping profile of a load scenario: an ordered list of {LoadStage}
2372
- # objects run in sequence, each holding or ramping a setpoint (virtual users, an
2373
- # arrival rate, or a pause) for its duration. The total run length is the sum of
2374
- # the stage durations.
2371
+ # A declarative named load shape that expands into ordinary {LoadStage} stages.
2372
+ # Set this as a {LoadProfile}'s +shape+ instead of an explicit +stages+ list;
2373
+ # only the parameters its +type+ needs are read. +type+ is one of +SPIKE+,
2374
+ # +STAIRS+ or +RAMP_HOLD+; +metric+ (+VU+ or +RATE+) selects what the shape
2375
+ # drives.
2376
+ class LoadShape
2377
+ attr_accessor :type, :metric, :curve, :baseline, :peak, :ramp_up_millis,
2378
+ :hold_millis, :ramp_down_millis, :recovery_hold_millis,
2379
+ :start, :step, :steps, :step_duration_millis, :target, :ramp_millis
2380
+
2381
+ def initialize(type:, metric: nil, curve: nil, baseline: nil, peak: nil,
2382
+ ramp_up_millis: nil, hold_millis: nil, ramp_down_millis: nil,
2383
+ recovery_hold_millis: nil, start: nil, step: nil, steps: nil,
2384
+ step_duration_millis: nil, target: nil, ramp_millis: nil)
2385
+ @type = type
2386
+ @metric = metric
2387
+ @curve = curve
2388
+ @baseline = baseline
2389
+ @peak = peak
2390
+ @ramp_up_millis = ramp_up_millis
2391
+ @hold_millis = hold_millis
2392
+ @ramp_down_millis = ramp_down_millis
2393
+ @recovery_hold_millis = recovery_hold_millis
2394
+ @start = start
2395
+ @step = step
2396
+ @steps = steps
2397
+ @step_duration_millis = step_duration_millis
2398
+ @target = target
2399
+ @ramp_millis = ramp_millis
2400
+ end
2401
+
2402
+ def to_h
2403
+ MockServer.strip_none({
2404
+ 'type' => @type,
2405
+ 'metric' => @metric,
2406
+ 'curve' => @curve,
2407
+ 'baseline' => @baseline,
2408
+ 'peak' => @peak,
2409
+ 'rampUpMillis' => @ramp_up_millis,
2410
+ 'holdMillis' => @hold_millis,
2411
+ 'rampDownMillis' => @ramp_down_millis,
2412
+ 'recoveryHoldMillis' => @recovery_hold_millis,
2413
+ 'start' => @start,
2414
+ 'step' => @step,
2415
+ 'steps' => @steps,
2416
+ 'stepDurationMillis' => @step_duration_millis,
2417
+ 'target' => @target,
2418
+ 'rampMillis' => @ramp_millis
2419
+ })
2420
+ end
2421
+
2422
+ def self.from_hash(data)
2423
+ return nil if data.nil?
2424
+
2425
+ new(
2426
+ type: data['type'],
2427
+ metric: data['metric'],
2428
+ curve: data['curve'],
2429
+ baseline: data['baseline'],
2430
+ peak: data['peak'],
2431
+ ramp_up_millis: data['rampUpMillis'],
2432
+ hold_millis: data['holdMillis'],
2433
+ ramp_down_millis: data['rampDownMillis'],
2434
+ recovery_hold_millis: data['recoveryHoldMillis'],
2435
+ start: data['start'],
2436
+ step: data['step'],
2437
+ steps: data['steps'],
2438
+ step_duration_millis: data['stepDurationMillis'],
2439
+ target: data['target'],
2440
+ ramp_millis: data['rampMillis']
2441
+ )
2442
+ end
2443
+ end
2444
+
2445
+ # The traffic-shaping profile of a load scenario: EITHER an ordered list of
2446
+ # {LoadStage} objects run in sequence, each holding or ramping a setpoint
2447
+ # (virtual users, an arrival rate, or a pause) for its duration, OR a single
2448
+ # named {LoadShape} that expands into stages. Set one, not both; if both are
2449
+ # set the explicit stages win. The total run length is the sum of the stage
2450
+ # durations.
2375
2451
  class LoadProfile
2376
- attr_accessor :stages
2452
+ attr_accessor :stages, :shape
2453
+
2454
+ def initialize(stages: nil, shape: nil)
2455
+ @stages = stages
2456
+ @shape = shape
2457
+ end
2458
+
2459
+ def to_h
2460
+ MockServer.strip_none({
2461
+ 'stages' => @stages.nil? ? nil : @stages.map(&:to_h),
2462
+ 'shape' => @shape&.to_h
2463
+ })
2464
+ end
2465
+
2466
+ def self.from_hash(data)
2467
+ return nil if data.nil?
2468
+
2469
+ stages_data = data['stages']
2470
+ new(
2471
+ stages: stages_data ? stages_data.map { |s| LoadStage.from_hash(s) } : nil,
2472
+ shape: LoadShape.from_hash(data['shape'])
2473
+ )
2474
+ end
2475
+ end
2476
+
2477
+ # A declarative cross-step capture / correlation rule: extracts a value from a
2478
+ # step's response and binds it to +name+, which a later step in the same
2479
+ # iteration can reference from its templated request fields. +source+ is one of
2480
+ # +BODY_JSONPATH+, +HEADER+ or +BODY_REGEX+; +expression+ drives the extraction;
2481
+ # +default_value+ is an optional fallback when extraction yields nothing.
2482
+ class LoadCapture
2483
+ attr_accessor :name, :source, :expression, :default_value
2377
2484
 
2378
- def initialize(stages: [])
2379
- @stages = stages || []
2485
+ def initialize(name:, source:, expression:, default_value: nil)
2486
+ @name = name
2487
+ @source = source
2488
+ @expression = expression
2489
+ @default_value = default_value
2380
2490
  end
2381
2491
 
2382
2492
  def to_h
2383
- { 'stages' => @stages.map(&:to_h) }
2493
+ MockServer.strip_none({
2494
+ 'name' => @name,
2495
+ 'source' => @source,
2496
+ 'expression' => @expression,
2497
+ 'defaultValue' => @default_value
2498
+ })
2384
2499
  end
2385
2500
 
2386
2501
  def self.from_hash(data)
2387
2502
  return nil if data.nil?
2388
2503
 
2389
- stages_data = data['stages'] || []
2390
- new(stages: stages_data.map { |s| LoadStage.from_hash(s) })
2504
+ new(
2505
+ name: data['name'],
2506
+ source: data['source'],
2507
+ expression: data['expression'],
2508
+ default_value: data['defaultValue']
2509
+ )
2510
+ end
2511
+ end
2512
+
2513
+ # An in-run pass/fail threshold for a load scenario: a per-run +metric+ compared
2514
+ # with +comparator+ against +threshold+. All thresholds must hold for the run
2515
+ # verdict to be +PASS+; any breach makes it +FAIL+. +metric+ is one of
2516
+ # +LATENCY_P50+/+LATENCY_P95+/+LATENCY_P99+/+LATENCY_P999+/+ERROR_RATE+/
2517
+ # +THROUGHPUT_RPS+; +comparator+ is one of +LESS_THAN+/+LESS_THAN_OR_EQUAL+/
2518
+ # +GREATER_THAN+/+GREATER_THAN_OR_EQUAL+.
2519
+ class LoadThreshold
2520
+ attr_accessor :metric, :comparator, :threshold
2521
+
2522
+ def initialize(metric:, comparator:, threshold:)
2523
+ @metric = metric
2524
+ @comparator = comparator
2525
+ @threshold = threshold
2526
+ end
2527
+
2528
+ def to_h
2529
+ MockServer.strip_none({
2530
+ 'metric' => @metric,
2531
+ 'comparator' => @comparator,
2532
+ 'threshold' => @threshold
2533
+ })
2534
+ end
2535
+
2536
+ def self.from_hash(data)
2537
+ return nil if data.nil?
2538
+
2539
+ new(
2540
+ metric: data['metric'],
2541
+ comparator: data['comparator'],
2542
+ threshold: data['threshold']
2543
+ )
2544
+ end
2545
+ end
2546
+
2547
+ # Adaptive iteration pacing (think-time) for a load scenario: a target
2548
+ # per-virtual-user iteration cycle time. +mode+ is one of +NONE+,
2549
+ # +CONSTANT_PACING+ (+value+ is the target cycle in milliseconds) or
2550
+ # +CONSTANT_THROUGHPUT+ (+value+ is the target iterations/second per VU).
2551
+ class LoadPacing
2552
+ attr_accessor :mode, :value
2553
+
2554
+ def initialize(mode:, value: nil)
2555
+ @mode = mode
2556
+ @value = value
2557
+ end
2558
+
2559
+ def to_h
2560
+ MockServer.strip_none({
2561
+ 'mode' => @mode,
2562
+ 'value' => @value
2563
+ })
2564
+ end
2565
+
2566
+ def self.from_hash(data)
2567
+ return nil if data.nil?
2568
+
2569
+ new(
2570
+ mode: data['mode'],
2571
+ value: data['value']
2572
+ )
2573
+ end
2574
+ end
2575
+
2576
+ # Parameterized test data (a data feeder) for a load scenario: an inline dataset
2577
+ # from which one row is selected per iteration and exposed to the templated
2578
+ # request. Supply EITHER +rows+ (inline list of column-name to value maps, the
2579
+ # primary form) OR +data+ + +format+ (raw CSV/JSON parsed server-side).
2580
+ # +strategy+ (+CIRCULAR+, +RANDOM+ or +SEQUENTIAL+) chooses how a row is picked.
2581
+ class LoadFeeder
2582
+ attr_accessor :rows, :data, :format, :strategy
2583
+
2584
+ def initialize(rows: nil, data: nil, format: nil, strategy: nil)
2585
+ @rows = rows
2586
+ @data = data
2587
+ @format = format
2588
+ @strategy = strategy
2589
+ end
2590
+
2591
+ def to_h
2592
+ MockServer.strip_none({
2593
+ 'rows' => @rows,
2594
+ 'data' => @data,
2595
+ 'format' => @format,
2596
+ 'strategy' => @strategy
2597
+ })
2598
+ end
2599
+
2600
+ def self.from_hash(data)
2601
+ return nil if data.nil?
2602
+
2603
+ new(
2604
+ rows: data['rows'],
2605
+ data: data['data'],
2606
+ format: data['format'],
2607
+ strategy: data['strategy']
2608
+ )
2391
2609
  end
2392
2610
  end
2393
2611
 
2394
2612
  # A single step within a load scenario. Each step fires +request+ (an HttpRequest)
2395
2613
  # against the target, optionally pausing for +think_time+ (a Delay) afterwards.
2614
+ # +captures+ binds values from this step's response for later steps in the same
2615
+ # iteration; +weight+ is the relative selection weight when the scenario's
2616
+ # +step_selection+ is +WEIGHTED+.
2396
2617
  class LoadStep
2397
- attr_accessor :name, :labels, :think_time, :request
2618
+ attr_accessor :name, :labels, :think_time, :request, :captures, :weight
2398
2619
 
2399
- def initialize(request:, name: nil, labels: nil, think_time: nil)
2620
+ def initialize(request:, name: nil, labels: nil, think_time: nil, captures: nil, weight: nil)
2400
2621
  @request = request
2401
2622
  @name = name
2402
2623
  @labels = labels
2403
2624
  @think_time = think_time
2625
+ @captures = captures
2626
+ @weight = weight
2404
2627
  end
2405
2628
 
2406
2629
  def to_h
@@ -2408,18 +2631,23 @@ module MockServer
2408
2631
  'name' => @name,
2409
2632
  'labels' => @labels,
2410
2633
  'thinkTime' => @think_time&.to_h,
2411
- 'request' => @request&.to_h
2634
+ 'request' => @request&.to_h,
2635
+ 'captures' => @captures.nil? ? nil : @captures.map(&:to_h),
2636
+ 'weight' => @weight
2412
2637
  })
2413
2638
  end
2414
2639
 
2415
2640
  def self.from_hash(data)
2416
2641
  return nil if data.nil?
2417
2642
 
2643
+ captures_data = data['captures']
2418
2644
  new(
2419
2645
  name: data['name'],
2420
2646
  labels: data['labels'],
2421
2647
  think_time: Delay.from_hash(data['thinkTime']),
2422
- request: HttpRequest.from_hash(data['request'])
2648
+ request: HttpRequest.from_hash(data['request']),
2649
+ captures: captures_data ? captures_data.map { |c| LoadCapture.from_hash(c) } : nil,
2650
+ weight: data['weight']
2423
2651
  )
2424
2652
  end
2425
2653
  end
@@ -2427,11 +2655,18 @@ module MockServer
2427
2655
  # A load-injection scenario: a named set of +steps+ driven by a traffic +profile+.
2428
2656
  # +template_type+ selects the templating engine (+VELOCITY+ or +MUSTACHE+) used to
2429
2657
  # render step requests; +max_requests+ caps the total requests issued.
2658
+ # +thresholds+ are in-run pass/fail checks; +abort_on_fail+/+abort_grace_millis+
2659
+ # control early-abort behaviour; +pacing+ shapes inter-iteration timing; +feeder+
2660
+ # supplies per-iteration data; +step_selection+ (+SEQUENTIAL+ or +WEIGHTED+)
2661
+ # controls how each iteration selects steps.
2430
2662
  class LoadScenario
2431
- attr_accessor :name, :template_type, :labels, :max_requests, :start_delay_millis, :profile, :steps
2663
+ attr_accessor :name, :template_type, :labels, :max_requests, :start_delay_millis,
2664
+ :profile, :steps, :thresholds, :abort_on_fail, :abort_grace_millis,
2665
+ :pacing, :feeder, :step_selection
2432
2666
 
2433
2667
  def initialize(name:, profile:, steps:, template_type: nil, labels: nil, max_requests: nil,
2434
- start_delay_millis: nil)
2668
+ start_delay_millis: nil, thresholds: nil, abort_on_fail: nil,
2669
+ abort_grace_millis: nil, pacing: nil, feeder: nil, step_selection: nil)
2435
2670
  @name = name
2436
2671
  @profile = profile
2437
2672
  @steps = steps
@@ -2439,6 +2674,12 @@ module MockServer
2439
2674
  @labels = labels
2440
2675
  @max_requests = max_requests
2441
2676
  @start_delay_millis = start_delay_millis
2677
+ @thresholds = thresholds
2678
+ @abort_on_fail = abort_on_fail
2679
+ @abort_grace_millis = abort_grace_millis
2680
+ @pacing = pacing
2681
+ @feeder = feeder
2682
+ @step_selection = step_selection
2442
2683
  end
2443
2684
 
2444
2685
  def to_h
@@ -2448,6 +2689,12 @@ module MockServer
2448
2689
  'labels' => @labels,
2449
2690
  'maxRequests' => @max_requests,
2450
2691
  'startDelayMillis' => @start_delay_millis,
2692
+ 'thresholds' => @thresholds.nil? ? nil : @thresholds.map(&:to_h),
2693
+ 'abortOnFail' => @abort_on_fail,
2694
+ 'abortGraceMillis' => @abort_grace_millis,
2695
+ 'pacing' => @pacing&.to_h,
2696
+ 'feeder' => @feeder&.to_h,
2697
+ 'stepSelection' => @step_selection,
2451
2698
  'profile' => @profile&.to_h,
2452
2699
  'steps' => @steps&.map(&:to_h)
2453
2700
  })
@@ -2457,12 +2704,19 @@ module MockServer
2457
2704
  return nil if data.nil?
2458
2705
 
2459
2706
  steps_data = data['steps']
2707
+ thresholds_data = data['thresholds']
2460
2708
  new(
2461
2709
  name: data['name'],
2462
2710
  template_type: data['templateType'],
2463
2711
  labels: data['labels'],
2464
2712
  max_requests: data['maxRequests'],
2465
2713
  start_delay_millis: data['startDelayMillis'],
2714
+ thresholds: thresholds_data ? thresholds_data.map { |t| LoadThreshold.from_hash(t) } : nil,
2715
+ abort_on_fail: data['abortOnFail'],
2716
+ abort_grace_millis: data['abortGraceMillis'],
2717
+ pacing: LoadPacing.from_hash(data['pacing']),
2718
+ feeder: LoadFeeder.from_hash(data['feeder']),
2719
+ step_selection: data['stepSelection'],
2466
2720
  profile: LoadProfile.from_hash(data['profile']),
2467
2721
  steps: steps_data ? steps_data.map { |s| LoadStep.from_hash(s) } : nil
2468
2722
  )
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MockServer
4
- VERSION = '7.2.0'
4
+ VERSION = '7.3.0'
5
5
  end
@@ -8,4 +8,5 @@ require_relative 'mockserver/forward_chain_expectation'
8
8
  require_relative 'mockserver/client'
9
9
  require_relative 'mockserver/llm'
10
10
  require_relative 'mockserver/mcp'
11
+ require_relative 'mockserver/a2a'
11
12
  require_relative 'mockserver/binary_launcher'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mockserver-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.0
4
+ version: 7.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Bloom
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-22 00:00:00.000000000 Z
11
+ date: 2026-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logger
@@ -91,6 +91,7 @@ files:
91
91
  - Gemfile
92
92
  - README.md
93
93
  - lib/mockserver-client.rb
94
+ - lib/mockserver/a2a.rb
94
95
  - lib/mockserver/binary_launcher.rb
95
96
  - lib/mockserver/client.rb
96
97
  - lib/mockserver/errors.rb