code: def setup_class(cls):
      cls.num_total_cpus = 2
      cls.num_total_gpus = 2
      cls.num_cpus_per_spark_task = 1
      cls.num_gpus_per_spark_task = 1
      cls.max_spark_tasks = 2
      gpu_discovery_script_path = os.path.join(
          os.path.dirname(os.path.abspath(__file__)),
          "discover_2_gpu.sh",
      )
      os.environ["SPARK_WORKER_CORES"] = "4"
      cls.spark = (
          SparkSession.builder.master("local-cluster[1, 2, 1024]")
          .config("spark.task.cpus", "1")
          .config("spark.task.resource.gpu.amount", "1")
          .config("spark.executor.cores", "2")
          .config("spark.worker.resource.gpu.amount", "2")
          .config("spark.executor.resource.gpu.amount", "2")
          .config("spark.task.maxFailures", "1")
          .config(
              "spark.worker.resource.gpu.discoveryScript",
              gpu_discovery_script_path,
          )
          .config(
              "spark.executorEnv.RAY_ON_SPARK_WORKER_CPU_CORES", "2"
          )
          .config("spark.executorEnv.RAY_ON_SPARK_WORKER_GPU_NUM", "2")
          .getOrCreate()
      )
  
imports: import sys
  import pytest
  import os
  import time
  import functools
  from abc import ABC
  from pyspark.sql import SparkSession
  from ray.tests.spark.test_basic import RayOnSparkCPUClusterTestBase, _setup_ray_cluster, _setup_ray_on_spark_envs, _RAY_ON_SPARK_WORKER_PHYSICAL_MEMORY_BYTES, _RAY_ON_SPARK_WORKER_SHARED_MEMORY_BYTES
  from ray.util.spark.utils import _calc_mem_per_ray_worker_node
  from ray._private.test_utils import wait_for_condition
  import ray
label_desc: Use image node_id 1 for calling the TestBasicSparkGPUCluster obj's underlying member method code with example usage: obj.setup_class(cls) without return types