code: def test_actors(disable_aiohttp_cache, ray_start_with_dashboard):
      @ray.remote
      class Foo:
          def __init__(self, num):
              self.num = num
  
          def do_task(self):
              return self.num
  
          def get_node_id(self):
              return ray.get_runtime_context().get_node_id()
  
          def get_pid(self):
              import os
  
              return os.getpid()
  
          def __repr__(self) -> str:
              return "Foo1"
  
      @ray.remote(num_cpus=0, resources={"infeasible_actor": 1})
      class InfeasibleActor:
          pass
  
      foo_actors = [Foo.options(name="first").remote(4), Foo.remote(5)]
      infeasible_actor = InfeasibleActor.options(
          name="infeasible"
      ).remote()  # noqa
      dead_actor = Foo.options(name="dead").remote(1)
      ray.kill(dead_actor)
      results = [actor.do_task.remote() for actor in foo_actors]  # noqa
      webui_url = ray_start_with_dashboard["webui_url"]
      assert wait_until_server_available(webui_url)
      webui_url = format_web_url(webui_url)
      job_id = ray.get_runtime_context().get_job_id()
      node_id = ray.get(foo_actors[0].get_node_id.remote())
      pid = ray.get(foo_actors[0].get_pid.remote())
  
      timeout_seconds = 5
      start_time = time.time()
      last_ex = None
      while True:
          time.sleep(1)
          try:
              resp = requests.get(f"{webui_url}/logical/actors")
              resp_json = resp.json()
              resp_data = resp_json["data"]
              actors = resp_data["actors"]
              assert len(actors) == 4
              for a in actors.values():
                  if a["name"] == "first":
                      actor_response = a
              assert actor_response["jobId"] == job_id
              assert "Foo" in actor_response["className"]
              assert "address" in actor_response
              assert type(actor_response["address"]) is dict
              assert actor_response["address"]["rayletId"] == node_id
              assert actor_response["state"] == "ALIVE"
              assert actor_response["name"] == "first"
              assert actor_response["numRestarts"] == "0"
              assert actor_response["pid"] == pid
              assert actor_response["startTime"] > 0
              assert actor_response["requiredResources"] == {}
              assert actor_response["endTime"] == 0
              assert actor_response["exitDetail"] == "-"
              assert actor_response["reprName"] == "Foo1"
              for a in actors.values():
                  # "exitDetail always exits from the response"
                  assert "exitDetail" in a
  
              # Check the dead actor metadata.
              for a in actors.values():
                  if a["name"] == "dead":
                      dead_actor_response = a
              assert dead_actor_response["endTime"] > 0
              assert "ray.kill" in dead_actor_response["exitDetail"]
              assert dead_actor_response["state"] == "DEAD"
              assert dead_actor_response["name"] == "dead"
  
              # Check the infeasible actor metadata.
              for a in actors.values():
                  if a["name"] == "infeasible":
                      infeasible_actor_response = a
              # Make sure the infeasible actor's resource name is correct.
              assert infeasible_actor_response["requiredResources"] == {
                  "infeasible_actor": 1
              }
              assert infeasible_actor_response["pid"] == 0
              all_pids = {entry["pid"] for entry in actors.values()}
              assert 0 in all_pids  # The infeasible actor
              assert len(all_pids) > 1
              break
          except Exception as ex:
              last_ex = ex
          finally:
              if time.time() > start_time + timeout_seconds:
                  ex_stack = (
                      traceback.format_exception(
                          type(last_ex), last_ex, last_ex.__traceback__
                      )
                      if last_ex
                      else []
                  )
                  ex_stack = "".join(ex_stack)
                  raise Exception(
                      f"Timed out while testing, {ex_stack}"
                  )
  
file_path: ray/python/ray/dashboard/modules/actor/tests/test_actor.py
imports: import logging
  import sys
  import time
  import traceback
  import pytest
  import requests
  import ray
  import ray.dashboard.utils
  from ray._private.test_utils import format_web_url, wait_until_server_available
  from ray.dashboard.modules.actor import actor_consts
  from ray.dashboard.tests.conftest import *
label_desc: Use image node_id 1 for calling a global function with example usage: test_actors(disable_aiohttp_cache, ray_start_with_dashboard) and returns: self, ray, os, str