code: def test_add_remove_tag_api(self):
      matching_runs = self.repo.structured_db.search_runs(
          f"Run number 5 {self.test_id}"
      )
      run = next(iter(matching_runs))
      tags = [tag for tag in run.tags_obj]
      self.assertEqual(2, len(run.tags_obj))
  
      self.assertListEqual(
          [f"first runs {self.test_id}", f"last runs {self.test_id}"],
          run.tags,
      )
  
      client = self.client
      # remove tag # 1
      resp = client.delete(f"/api/runs/{run.hash}/tags/{tags[0].uuid}")
      self.assertEqual(200, resp.status_code)
  
      resp = client.get(f"/api/runs/{run.hash}/info/").json()
      self.assertEqual(1, len(resp["props"]["tags"]))
      tag_names = [tag["name"] for tag in resp["props"]["tags"]]
      self.assertListEqual([f"last runs {self.test_id}"], tag_names)
  
      # add new tag
      resp = client.post(
          f"/api/runs/{run.hash}/tags/new",
          json={"tag_name": f"new tag {self.test_id}"},
      )
      self.assertEqual(200, resp.status_code)
  
      resp = client.get(f"/api/runs/{run.hash}/info/").json()
      self.assertEqual(2, len(resp["props"]["tags"]))
      tag_names = [tag["name"] for tag in resp["props"]["tags"]]
      self.assertListEqual(
          [f"last runs {self.test_id}", f"new tag {self.test_id}"],
          tag_names,
      )
  
imports: import uuid
  from tests.base import PrefilledDataApiTestBase
label_desc: Use image node_id 3 for calling the TestStructuredRunApi obj's underlying member method code with example usage: obj.test_add_remove_tag_api() without return types