diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md
index 27a3fe290..9c9ede371 100644
--- a/IMPLEMENTATION_COVERAGE.md
+++ b/IMPLEMENTATION_COVERAGE.md
@@ -5804,6 +5804,69 @@
- [ ] untag_resources
+## robomaker
+
+7% implemented
+
+- [ ] batch_delete_worlds
+- [ ] batch_describe_simulation_job
+- [ ] cancel_deployment_job
+- [ ] cancel_simulation_job
+- [ ] cancel_simulation_job_batch
+- [ ] cancel_world_export_job
+- [ ] cancel_world_generation_job
+- [ ] create_deployment_job
+- [ ] create_fleet
+- [ ] create_robot
+- [X] create_robot_application
+- [ ] create_robot_application_version
+- [ ] create_simulation_application
+- [ ] create_simulation_application_version
+- [ ] create_simulation_job
+- [ ] create_world_export_job
+- [ ] create_world_generation_job
+- [ ] create_world_template
+- [ ] delete_fleet
+- [ ] delete_robot
+- [X] delete_robot_application
+- [ ] delete_simulation_application
+- [ ] delete_world_template
+- [ ] deregister_robot
+- [ ] describe_deployment_job
+- [ ] describe_fleet
+- [ ] describe_robot
+- [X] describe_robot_application
+- [ ] describe_simulation_application
+- [ ] describe_simulation_job
+- [ ] describe_simulation_job_batch
+- [ ] describe_world
+- [ ] describe_world_export_job
+- [ ] describe_world_generation_job
+- [ ] describe_world_template
+- [ ] get_world_template_body
+- [ ] list_deployment_jobs
+- [ ] list_fleets
+- [X] list_robot_applications
+- [ ] list_robots
+- [ ] list_simulation_applications
+- [ ] list_simulation_job_batches
+- [ ] list_simulation_jobs
+- [ ] list_tags_for_resource
+- [ ] list_world_export_jobs
+- [ ] list_world_generation_jobs
+- [ ] list_world_templates
+- [ ] list_worlds
+- [ ] register_robot
+- [ ] restart_simulation_job
+- [ ] start_simulation_job_batch
+- [ ] sync_deployment_job
+- [ ] tag_resource
+- [ ] untag_resource
+- [ ] update_robot_application
+- [ ] update_simulation_application
+- [ ] update_world_template
+
+
## route53
41% implemented
@@ -7485,7 +7548,6 @@
- redshift-serverless
- resiliencehub
- resource-explorer-2
-- robomaker
- rolesanywhere
- route53-recovery-cluster
- route53-recovery-control-config
diff --git a/docs/docs/services/robomaker.rst b/docs/docs/services/robomaker.rst
new file mode 100644
index 000000000..70df30899
--- /dev/null
+++ b/docs/docs/services/robomaker.rst
@@ -0,0 +1,95 @@
+.. _implementedservice_robomaker:
+
+.. |start-h3| raw:: html
+
+
+
+.. |end-h3| raw:: html
+
+
+
+=========
+robomaker
+=========
+
+.. autoclass:: moto.robomaker.models.RoboMakerBackend
+
+|start-h3| Example usage |end-h3|
+
+.. sourcecode:: python
+
+ @mock_robomaker
+ def test_robomaker_behaviour:
+ boto3.client("robomaker")
+ ...
+
+
+
+|start-h3| Implemented features for this service |end-h3|
+
+- [ ] batch_delete_worlds
+- [ ] batch_describe_simulation_job
+- [ ] cancel_deployment_job
+- [ ] cancel_simulation_job
+- [ ] cancel_simulation_job_batch
+- [ ] cancel_world_export_job
+- [ ] cancel_world_generation_job
+- [ ] create_deployment_job
+- [ ] create_fleet
+- [ ] create_robot
+- [X] create_robot_application
+
+ The tags and environment parameters are not yet implemented
+
+
+- [ ] create_robot_application_version
+- [ ] create_simulation_application
+- [ ] create_simulation_application_version
+- [ ] create_simulation_job
+- [ ] create_world_export_job
+- [ ] create_world_generation_job
+- [ ] create_world_template
+- [ ] delete_fleet
+- [ ] delete_robot
+- [X] delete_robot_application
+- [ ] delete_simulation_application
+- [ ] delete_world_template
+- [ ] deregister_robot
+- [ ] describe_deployment_job
+- [ ] describe_fleet
+- [ ] describe_robot
+- [X] describe_robot_application
+- [ ] describe_simulation_application
+- [ ] describe_simulation_job
+- [ ] describe_simulation_job_batch
+- [ ] describe_world
+- [ ] describe_world_export_job
+- [ ] describe_world_generation_job
+- [ ] describe_world_template
+- [ ] get_world_template_body
+- [ ] list_deployment_jobs
+- [ ] list_fleets
+- [X] list_robot_applications
+
+ Currently returns all applications - none of the parameters are taken into account
+
+
+- [ ] list_robots
+- [ ] list_simulation_applications
+- [ ] list_simulation_job_batches
+- [ ] list_simulation_jobs
+- [ ] list_tags_for_resource
+- [ ] list_world_export_jobs
+- [ ] list_world_generation_jobs
+- [ ] list_world_templates
+- [ ] list_worlds
+- [ ] register_robot
+- [ ] restart_simulation_job
+- [ ] start_simulation_job_batch
+- [ ] sync_deployment_job
+- [ ] tag_resource
+- [ ] untag_resource
+- [ ] update_robot_application
+- [ ] update_simulation_application
+- [ ] update_world_template
+
diff --git a/moto/__init__.py b/moto/__init__.py
index 1e80fd257..4be50ec86 100644
--- a/moto/__init__.py
+++ b/moto/__init__.py
@@ -148,6 +148,7 @@ mock_resourcegroups = lazy_load(
mock_resourcegroupstaggingapi = lazy_load(
".resourcegroupstaggingapi", "mock_resourcegroupstaggingapi"
)
+mock_robomaker = lazy_load(".robomaker", "mock_robomaker")
mock_route53 = lazy_load(".route53", "mock_route53")
mock_route53resolver = lazy_load(
".route53resolver", "mock_route53resolver", boto3_name="route53resolver"
diff --git a/moto/backend_index.py b/moto/backend_index.py
index fdc603b74..faf763d1d 100644
--- a/moto/backend_index.py
+++ b/moto/backend_index.py
@@ -136,6 +136,7 @@ backend_url_patterns = [
re.compile("https?://resource-groups(-fips)?\\.(.+)\\.amazonaws.com"),
),
("resourcegroupstaggingapi", re.compile("https?://tagging\\.(.+)\\.amazonaws.com")),
+ ("robomaker", re.compile("https?://robomaker\\.(.+)\\.amazonaws\\.com")),
("route53", re.compile("https?://route53(\\..+)?\\.amazonaws.com")),
(
"route53resolver",
diff --git a/moto/robomaker/__init__.py b/moto/robomaker/__init__.py
new file mode 100644
index 000000000..99dc70c6f
--- /dev/null
+++ b/moto/robomaker/__init__.py
@@ -0,0 +1,5 @@
+"""robomaker module initialization; sets value for base decorator."""
+from .models import robomaker_backends
+from ..core.models import base_decorator
+
+mock_robomaker = base_decorator(robomaker_backends)
diff --git a/moto/robomaker/models.py b/moto/robomaker/models.py
new file mode 100644
index 000000000..a03234d4e
--- /dev/null
+++ b/moto/robomaker/models.py
@@ -0,0 +1,73 @@
+from moto.core import BaseBackend, BackendDict, BaseModel
+from moto.core.utils import unix_time
+
+from typing import Any, Dict, List, Iterable
+
+
+class RobotApplication(BaseModel):
+ def __init__(
+ self,
+ account_id: str,
+ region: str,
+ name: str,
+ sources: List[Dict[str, str]],
+ robot_software_suite: Dict[str, str],
+ ):
+ self.account_id = account_id
+ self.region = region
+ self.name = name
+ self.sources = sources
+ self.robot_software_suite = robot_software_suite
+ self.created_on = unix_time()
+
+ @property
+ def arn(self) -> str:
+ return f"arn:aws:robomaker:{self.region}:{self.account_id}:robot-application/{self.name}/{self.created_on}"
+
+ def to_dict(self) -> Dict[str, Any]:
+ return {
+ "arn": self.arn,
+ "name": self.name,
+ "sources": self.sources,
+ "robotSoftwareSuite": self.robot_software_suite,
+ }
+
+
+class RoboMakerBackend(BaseBackend):
+ def __init__(self, region_name: str, account_id: str):
+ super().__init__(region_name, account_id)
+ self.robot_applications: Dict[str, RobotApplication] = {}
+
+ def create_robot_application(
+ self,
+ name: str,
+ sources: List[Dict[str, str]],
+ robot_software_suite: Dict[str, str],
+ ) -> RobotApplication:
+ """
+ The tags and environment parameters are not yet implemented
+ """
+ app = RobotApplication(
+ account_id=self.account_id,
+ region=self.region_name,
+ name=name,
+ sources=sources,
+ robot_software_suite=robot_software_suite,
+ )
+ self.robot_applications[name] = app
+ return app
+
+ def describe_robot_application(self, application: str) -> RobotApplication:
+ return self.robot_applications[application]
+
+ def delete_robot_application(self, application: str) -> None:
+ self.robot_applications.pop(application)
+
+ def list_robot_applications(self) -> Iterable[RobotApplication]:
+ """
+ Currently returns all applications - none of the parameters are taken into account
+ """
+ return self.robot_applications.values()
+
+
+robomaker_backends = BackendDict(RoboMakerBackend, "robomaker")
diff --git a/moto/robomaker/responses.py b/moto/robomaker/responses.py
new file mode 100644
index 000000000..59d44e76b
--- /dev/null
+++ b/moto/robomaker/responses.py
@@ -0,0 +1,46 @@
+import json
+
+from moto.core.responses import BaseResponse
+from .models import robomaker_backends, RoboMakerBackend
+
+
+class RoboMakerResponse(BaseResponse):
+ def __init__(self) -> None:
+ super().__init__(service_name="robomaker")
+
+ @property
+ def robomaker_backend(self) -> RoboMakerBackend:
+ return robomaker_backends[self.current_account][self.region]
+
+ def create_robot_application(self) -> str:
+ name = self._get_param("name")
+ sources = self._get_param("sources")
+ robot_software_suite = self._get_param("robotSoftwareSuite")
+ app = self.robomaker_backend.create_robot_application(
+ name=name,
+ sources=sources,
+ robot_software_suite=robot_software_suite,
+ )
+ return json.dumps(app.to_dict())
+
+ def describe_robot_application(self) -> str:
+ application = self._get_param("application")
+ app = self.robomaker_backend.describe_robot_application(
+ application=application,
+ )
+ return json.dumps(app.to_dict())
+
+ def delete_robot_application(self) -> str:
+ application = self._get_param("application")
+ self.robomaker_backend.delete_robot_application(
+ application=application,
+ )
+ return "{}"
+
+ def list_robot_applications(self) -> str:
+ robot_applications = self.robomaker_backend.list_robot_applications()
+ return json.dumps(
+ dict(
+ robotApplicationSummaries=[app.to_dict() for app in robot_applications]
+ )
+ )
diff --git a/moto/robomaker/urls.py b/moto/robomaker/urls.py
new file mode 100644
index 000000000..ac8656616
--- /dev/null
+++ b/moto/robomaker/urls.py
@@ -0,0 +1,16 @@
+from .responses import RoboMakerResponse
+
+url_bases = [
+ r"https?://robomaker\.(.+)\.amazonaws\.com",
+]
+
+
+response = RoboMakerResponse()
+
+
+url_paths = {
+ "{0}/createRobotApplication$": response.dispatch,
+ "{0}/deleteRobotApplication$": response.dispatch,
+ "{0}/describeRobotApplication$": response.dispatch,
+ "{0}/listRobotApplications$": response.dispatch,
+}
diff --git a/tests/test_robomaker/__init__.py b/tests/test_robomaker/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/test_robomaker/test_robomaker.py b/tests/test_robomaker/test_robomaker.py
new file mode 100644
index 000000000..48c952a54
--- /dev/null
+++ b/tests/test_robomaker/test_robomaker.py
@@ -0,0 +1,36 @@
+"""Unit tests for robomaker-supported APIs."""
+import boto3
+
+from moto import mock_robomaker
+
+# See our Development Tips on writing tests for hints on how to write good tests:
+# http://docs.getmoto.org/en/latest/docs/contributing/development_tips/tests.html
+
+
+@mock_robomaker
+def test_robot_application():
+ client = boto3.client("robomaker", region_name="eu-west-1")
+ app = client.create_robot_application(
+ name="viki",
+ sources=[{"s3Bucket": "sth", "s3Key": "else"}],
+ robotSoftwareSuite={"name": "ROS", "version": "Kinetic"},
+ )
+ assert "robot-application/viki" in app["arn"]
+ assert app["name"] == "viki"
+ assert app["sources"] == [{"s3Bucket": "sth", "s3Key": "else"}]
+ assert app["robotSoftwareSuite"] == {"name": "ROS", "version": "Kinetic"}
+
+ app = client.describe_robot_application(application="viki")
+ assert "robot-application/viki" in app["arn"]
+ assert app["name"] == "viki"
+ assert app["sources"] == [{"s3Bucket": "sth", "s3Key": "else"}]
+ assert app["robotSoftwareSuite"] == {"name": "ROS", "version": "Kinetic"}
+
+ apps = client.list_robot_applications()["robotApplicationSummaries"]
+ assert len(apps) == 1
+ assert apps[0]["name"] == "viki"
+
+ client.delete_robot_application(application="viki")
+
+ apps = client.list_robot_applications()["robotApplicationSummaries"]
+ assert len(apps) == 0