Repository: getmoto/moto
Pull request #5935 (2023-02-16 12:02:31)

implement create_group

dana-orca: > 

I ran `make format` this time.
hopefully that would do the trick 😄 
dana-orca: @ananhagyahya
dana-orca: @bblommers server tests failed because I didnt update backeds index 🤦‍♀️ 
codecov[bot]: # [Codecov](https://codecov.io/gh/getmoto/moto/pull/5935?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#5935](https://codecov.io/gh/getmoto/moto/pull/5935?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (54c3ba2) into [master](https://codecov.io/gh/getmoto/moto/commit/b241c16726cadfad572440402ee4d72d346f89b6?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (b241c16) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

```diff
@@           Coverage Diff           @@
##           master    #5935   +/-   ##
=======================================
  Coverage   96.22%   96.23%           
=======================================
  Files         756      760    +4     
  Lines       74701    74738   +37     
=======================================
+ Hits        71884    71921   +37     
  Misses       2817     2817           
```

| Flag | Coverage Δ | |
|---|---|---|
| servertests | `37.00% <32.43%> (-0.01%)` | :arrow_down: |
| unittests | `96.17% <100.00%> (+<0.01%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/getmoto/moto/pull/5935?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [moto/backend\_index.py](https://codecov.io/gh/getmoto/moto/pull/5935?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-bW90by9iYWNrZW5kX2luZGV4LnB5) | `100.00% <ø> (ø)` | |
| [moto/\_\_init\_\_.py](https://codecov.io/gh/getmoto/moto/pull/5935?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-bW90by9fX2luaXRfXy5weQ==) | `98.62% <100.00%> (+<0.01%)` | :arrow_up: |
| [moto/identitystore/\_\_init\_\_.py](https://codecov.io/gh/getmoto/moto/pull/5935?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-bW90by9pZGVudGl0eXN0b3JlL19faW5pdF9fLnB5) | `100.00% <100.00%> (ø)` | |
| [moto/identitystore/models.py](https://codecov.io/gh/getmoto/moto/pull/5935?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-bW90by9pZGVudGl0eXN0b3JlL21vZGVscy5weQ==) | `100.00% <100.00%> (ø)` | |
| [moto/identitystore/responses.py](https://codecov.io/gh/getmoto/moto/pull/5935?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-bW90by9pZGVudGl0eXN0b3JlL3Jlc3BvbnNlcy5weQ==) | `100.00% <100.00%> (ø)` | |
| [moto/identitystore/urls.py](https://codecov.io/gh/getmoto/moto/pull/5935?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-bW90by9pZGVudGl0eXN0b3JlL3VybHMucHk=) | `100.00% <100.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

bblommers: > @bblommers server tests failed because I didnt update backeds index woman_facepalming

Yeah, that's my bad - I should've mentioned that earlier. Thank you for this PR @dana-orca!

Patch:
diff --git a/moto/__init__.py b/moto/__init__.py
index da9810f47..9f38cba5e 100644
--- a/moto/__init__.py
+++ b/moto/__init__.py
@@ -167,6 +167,7 @@ mock_xray = lazy_load(".xray", "mock_xray")
 mock_xray_client = lazy_load(".xray", "mock_xray_client")
 mock_wafv2 = lazy_load(".wafv2", "mock_wafv2")
 mock_textract = lazy_load(".textract", "mock_textract")
+mock_identitystore = lazy_load(".identitystore", "mock_identitystore")
 
 
 class MockAll(ContextDecorator):
diff --git a/moto/backend_index.py b/moto/backend_index.py
index 1d19b6184..7e2831c35 100644
--- a/moto/backend_index.py
+++ b/moto/backend_index.py
@@ -1,4 +1,4 @@
-# autogenerated by scripts/update_backend_index.py
+# autogenerated by /Users/danaronson/GitHub/forks/moto/scripts/update_backend_index.py
 import re
 
 backend_url_patterns = [
@@ -79,10 +79,13 @@ backend_url_patterns = [
     ("greengrass", re.compile("https?://greengrass\\.(.+)\\.amazonaws.com")),
     ("guardduty", re.compile("https?://guardduty\\.(.+)\\.amazonaws\\.com")),
     ("iam", re.compile("https?://iam\\.(.*\\.)?amazonaws\\.com")),
+    ("identitystore", re.compile("https?://identitystore\\.(.+)\\.amazonaws\\.com")),
     ("iot", re.compile("https?://iot\\.(.+)\\.amazonaws\\.com")),
     ("iot-data", re.compile("https?://data\\.iot\\.(.+)\\.amazonaws.com")),
     ("iot-data", re.compile("https?://data-ats\\.iot\\.(.+)\\.amazonaws.com")),
     ("kinesis", re.compile("https?://kinesis\\.(.+)\\.amazonaws\\.com")),
+    ("kinesis", re.compile("https?://(.+)\\.control-kinesis\\.(.+)\\.amazonaws\\.com")),
+    ("kinesis", re.compile("https?://(.+)\\.data-kinesis\\.(.+)\\.amazonaws\\.com")),
     ("kinesisvideo", re.compile("https?://kinesisvideo\\.(.+)\\.amazonaws.com")),
     (
         "kinesis-video-archived-media",
diff --git a/moto/identitystore/__init__.py b/moto/identitystore/__init__.py
new file mode 100644
index 000000000..072589539
--- /dev/null
+++ b/moto/identitystore/__init__.py
@@ -0,0 +1,5 @@
+"""identitystore module initialization; sets value for base decorator."""
+from .models import identitystore_backends
+from ..core.models import base_decorator
+
+mock_identitystore = base_decorator(identitystore_backends)
diff --git a/moto/identitystore/exceptions.py b/moto/identitystore/exceptions.py
new file mode 100644
index 000000000..65060b557
--- /dev/null
+++ b/moto/identitystore/exceptions.py
@@ -0,0 +1,1 @@
+"""Exceptions raised by the identitystore service."""
diff --git a/moto/identitystore/models.py b/moto/identitystore/models.py
new file mode 100644
index 000000000..287610f21
--- /dev/null
+++ b/moto/identitystore/models.py
@@ -0,0 +1,28 @@
+"""IdentityStoreBackend class with methods for supported APIs."""
+from moto.moto_api._internal import mock_random
+
+from moto.core import BaseBackend, BackendDict
+
+
+class IdentityStoreBackend(BaseBackend):
+    """Implementation of IdentityStore APIs."""
+
+    def __init__(self, region_name, account_id):
+        super().__init__(region_name, account_id)
+        self.groups = {}
+
+    # add methods from here
+
+    def create_group(self, identity_store_id, display_name, description):
+        group_id = str(mock_random.uuid4())
+        group_dict = {
+            "GroupId": group_id,
+            "IdentityStoreId": identity_store_id,
+            "DisplayName": display_name,
+            "Description": description,
+        }
+        self.groups[group_id] = group_dict
+        return group_id, identity_store_id
+
+
+identitystore_backends = BackendDict(IdentityStoreBackend, "identitystore")
diff --git a/moto/identitystore/responses.py b/moto/identitystore/responses.py
new file mode 100644
index 000000000..0308631a2
--- /dev/null
+++ b/moto/identitystore/responses.py
@@ -0,0 +1,34 @@
+"""Handles incoming identitystore requests, invokes methods, returns responses."""
+import json
+
+from moto.core.responses import BaseResponse
+from .models import identitystore_backends
+
+
+class IdentityStoreResponse(BaseResponse):
+    """Handler for IdentityStore requests and responses."""
+
+    def __init__(self):
+        super().__init__(service_name="identitystore")
+
+    @property
+    def identitystore_backend(self):
+        """Return backend instance specific for this region."""
+        return identitystore_backends[self.current_account][self.region]
+
+    # add methods from here
+
+    def create_group(self):
+        params = self._get_params()
+        identity_store_id = params.get("IdentityStoreId")
+        display_name = params.get("DisplayName")
+        description = params.get("Description")
+        group_id, identity_store_id = self.identitystore_backend.create_group(
+            identity_store_id=identity_store_id,
+            display_name=display_name,
+            description=description,
+        )
+        return json.dumps(dict(GroupId=group_id, IdentityStoreId=identity_store_id))
+
+    def _get_params(self):
+        return json.loads(self.body)
diff --git a/moto/identitystore/urls.py b/moto/identitystore/urls.py
new file mode 100644
index 000000000..11696e6dd
--- /dev/null
+++ b/moto/identitystore/urls.py
@@ -0,0 +1,10 @@
+"""identitystore base URL and path."""
+from .responses import IdentityStoreResponse
+
+url_bases = [
+    r"https?://identitystore\.(.+)\.amazonaws\.com",
+]
+
+url_paths = {
+    "{0}/$": IdentityStoreResponse.dispatch,
+}


Test patch:
diff --git a/tests/test_identitystore/__init__.py b/tests/test_identitystore/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/test_identitystore/test_identitystore.py b/tests/test_identitystore/test_identitystore.py
new file mode 100644
index 000000000..440889e06
--- /dev/null
+++ b/tests/test_identitystore/test_identitystore.py
@@ -0,0 +1,24 @@
+"""Unit tests for identitystore-supported APIs."""
+from uuid import UUID
+
+import boto3
+import sure  # noqa # pylint: disable=unused-import
+
+from moto import mock_identitystore
+
+
+# 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_identitystore
+def test_create_group():
+    client = boto3.client("identitystore", region_name="ap-southeast-1")
+    identity_store_id = "d-9067028cf5"
+    create_resp = client.create_group(
+        IdentityStoreId=identity_store_id,
+        DisplayName="test_group",
+        Description="description",
+    )
+    assert create_resp["IdentityStoreId"] == identity_store_id
+    assert UUID(create_resp["GroupId"])