code: def test_gen_multiple(self) -> None:
      exp = get_experiment_with_multi_objective()
      sobol_GPEI_gs = GenerationStrategy(
          steps=[
              GenerationStep(
                  model=Models.SOBOL,
                  num_trials=5,
                  model_kwargs=self.step_model_kwargs,
              ),
              GenerationStep(
                  model=Models.GPEI,
                  num_trials=-1,
                  model_kwargs=self.step_model_kwargs,
              ),
          ]
      )
      with mock_patch_method_original(
          mock_path=f"{ModelSpec.__module__}.ModelSpec.gen",
          original_method=ModelSpec.gen,
      ) as model_spec_gen_mock, mock_patch_method_original(
          mock_path=f"{ModelSpec.__module__}.ModelSpec.fit",
          original_method=ModelSpec.fit,
      ) as model_spec_fit_mock:
          # Generate first four Sobol GRs (one more to gen after that if
          # first four become trials.
          grs = sobol_GPEI_gs._gen_multiple(
              experiment=exp, num_generator_runs=3
          )
          self.assertEqual(len(grs), 3)
          # We should only fit once; refitting for each `gen` would be
          # wasteful as there is no new data.
          model_spec_fit_mock.assert_called_once()
          self.assertEqual(model_spec_gen_mock.call_count, 3)
          pending_in_each_gen = enumerate(
              args_and_kwargs.kwargs.get("pending_observations")
              for args_and_kwargs in model_spec_gen_mock.call_args_list
          )
          for gr, (idx, pending) in zip(grs, pending_in_each_gen):
              exp.new_trial(generator_run=gr).mark_running(
                  no_runner_required=True
              )
              if idx > 0:
                  prev_gr = grs[idx - 1]
                  for arm in prev_gr.arms:
                      for m in pending:
                          self.assertIn(
                              ObservationFeatures.from_arm(arm),
                              pending[m],
                          )
          model_spec_gen_mock.reset_mock()
  
          # Check case with pending features initially specified; we should get two
          # GRs now (remaining in Sobol step) even though we requested 3.
          original_pending = not_none(get_pending(experiment=exp))
          first_3_trials_obs_feats = [
              ObservationFeatures.from_arm(arm=a, trial_index=idx)
              for idx, trial in exp.trials.items()
              for a in trial.arms
          ]
          for m in original_pending:
              self.assertTrue(
                  same_elements(
                      original_pending[m], first_3_trials_obs_feats
                  )
              )
  
          grs = sobol_GPEI_gs._gen_multiple(
              experiment=exp,
              num_generator_runs=3,
              pending_observations=get_pending(experiment=exp),
          )
          self.assertEqual(len(grs), 2)
  
          pending_in_each_gen = enumerate(
              args_and_kwargs[1].get("pending_observations")
              for args_and_kwargs in model_spec_gen_mock.call_args_list
          )
          for gr, (idx, pending) in zip(grs, pending_in_each_gen):
              exp.new_trial(generator_run=gr).mark_running(
                  no_runner_required=True
              )
              if idx > 0:
                  prev_gr = grs[idx - 1]
                  for arm in prev_gr.arms:
                      for m in pending:
                          # In this case, we should see both the originally-pending
                          # and the new arms as pending observation features.
                          self.assertIn(
                              ObservationFeatures.from_arm(arm),
                              pending[m],
                          )
                          for p in original_pending[m]:
                              self.assertIn(p, pending[m])
  
imports: import logging
  from typing import cast, List
  from unittest import mock
  from unittest.mock import MagicMock, patch
  from ax.core.arm import Arm
  from ax.core.base_trial import TrialStatus
  from ax.core.experiment import Experiment
  from ax.core.generator_run import GeneratorRun
  from ax.core.observation import ObservationFeatures
  from ax.core.parameter import ChoiceParameter, FixedParameter, Parameter, ParameterType
  from ax.core.search_space import SearchSpace
  from ax.core.utils import get_pending_observation_features_based_on_trial_status
  from ax.exceptions.core import DataRequiredError, UnsupportedError, UserInputError
  from ax.exceptions.generation_strategy import GenerationStrategyCompleted, GenerationStrategyMisconfiguredException, GenerationStrategyRepeatedPoints, MaxParallelismReachedException
  from ax.modelbridge.discrete import DiscreteModelBridge
  from ax.modelbridge.factory import get_sobol
  from ax.modelbridge.generation_node import GenerationNode
  from ax.modelbridge.generation_strategy import GenerationStep, GenerationStrategy
  from ax.modelbridge.model_spec import ModelSpec
  from ax.modelbridge.random import RandomModelBridge
  from ax.modelbridge.registry import Cont_X_trans, MODEL_KEY_TO_MODEL_SETUP, Models
  from ax.modelbridge.torch import TorchModelBridge
  from ax.modelbridge.transition_criterion import MaxGenerationParallelism, MaxTrials, MinTrials
  from ax.models.random.sobol import SobolGenerator
  from ax.utils.common.equality import same_elements
  from ax.utils.common.mock import mock_patch_method_original
  from ax.utils.common.testutils import TestCase
  from ax.utils.common.typeutils import not_none
  from ax.utils.testing.core_stubs import get_branin_data, get_branin_experiment, get_choice_parameter, get_data, get_experiment_with_multi_objective, get_hierarchical_search_space_experiment
label_desc: Use image node_id 26 for calling the TestGenerationStrategy obj's underlying member method code with example usage: obj.test_gen_multiple() without return types