Fix check_service_client_function mock_args bug

A recent commit Ib066add5ff09bd3b32b293833ed6b7a3d5b43955
added a new `mock_args` argument to check_service_client_function
which, if provided, asserts that the mocked REST client is
called with `mock_args`.

The problem is that the payload passed to the REST client uses
json.dumps -- which outputs a dictionary as a string in a
non-deterministic ordering of key/values. This means that
using json.dumps can produce different strings for the same
dictionary. This is a problem because sometimes the strings
might be in a different order causing test failure [0].

The solution is to mock json.dumps and force it to use
sort_keys=True so that the response body is deterministic.
This should be done for create and update actions --
wherever json.dumps is used. This can be done by mocking
json.dumps in each test function that needs to mock out
the actual json.dumps to use sort_keys=True.

This commit mocks json.dumps to use sort_keys=True in
test cases that use mock_args and rely on json.dumps.

[0] http://logs.openstack.org/56/474356/9/check/gate-tempest-python27-ubuntu-xenial/2205abc/console.html#_2017-06-20_17_02_12_867914

Change-Id: I08bf3ac8c471a8112984dc52a2b5b143634d83b7
diff --git a/tempest/tests/lib/services/network/test_security_group_rules_client.py b/tempest/tests/lib/services/network/test_security_group_rules_client.py
index ebffcbe..b9c17a1 100644
--- a/tempest/tests/lib/services/network/test_security_group_rules_client.py
+++ b/tempest/tests/lib/services/network/test_security_group_rules_client.py
@@ -15,8 +15,10 @@
 
 import copy
 
+import mock
 from oslo_serialization import jsonutils as json
 
+from tempest.lib.services.network import base as network_base
 from tempest.lib.services.network import security_group_rules_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
@@ -80,16 +82,22 @@
         kwargs = {'direction': 'egress',
                   'security_group_id': '85cc3048-abc3-43cc-89b3-377341426ac5',
                   'remote_ip_prefix': None}
+        payload = json.dumps({"security_group_rule": kwargs}, sort_keys=True)
+        json_dumps = json.dumps
 
-        self.check_service_client_function(
-            self.client.create_security_group_rule,
-            'tempest.lib.common.rest_client.RestClient.post',
-            self.FAKE_SECURITY_GROUP_RULE,
-            bytes_body,
-            status=201,
-            mock_args=['v2.0/security-group-rules',
-                       json.dumps({"security_group_rule": kwargs})],
-            **kwargs)
+        # NOTE: Use sort_keys for json.dumps so that the expected and actual
+        # payloads are guaranteed to be identical for mock_args assert check.
+        with mock.patch.object(network_base.json, 'dumps') as mock_dumps:
+            mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
+
+            self.check_service_client_function(
+                self.client.create_security_group_rule,
+                'tempest.lib.common.rest_client.RestClient.post',
+                self.FAKE_SECURITY_GROUP_RULE,
+                bytes_body,
+                status=201,
+                mock_args=['v2.0/security-group-rules', payload],
+                **kwargs)
 
     def _test_show_security_group_rule(self, bytes_body=False):
         self.check_service_client_function(
diff --git a/tempest/tests/lib/services/network/test_security_groups_client.py b/tempest/tests/lib/services/network/test_security_groups_client.py
index d066378..f96805f 100644
--- a/tempest/tests/lib/services/network/test_security_groups_client.py
+++ b/tempest/tests/lib/services/network/test_security_groups_client.py
@@ -15,8 +15,10 @@
 
 import copy
 
+import mock
 from oslo_serialization import jsonutils as json
 
+from tempest.lib.services.network import base as network_base
 from tempest.lib.services.network import security_groups_client
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib.services import base
@@ -89,15 +91,22 @@
 
     def _test_create_security_group(self, bytes_body=False):
         kwargs = {'name': 'fake-security-group-name'}
-        self.check_service_client_function(
-            self.client.create_security_group,
-            'tempest.lib.common.rest_client.RestClient.post',
-            self.FAKE_SECURITY_GROUP,
-            bytes_body,
-            status=201,
-            mock_args=['v2.0/security-groups',
-                       json.dumps({"security_group": kwargs})],
-            **kwargs)
+        payload = json.dumps({"security_group": kwargs}, sort_keys=True)
+        json_dumps = json.dumps
+
+        # NOTE: Use sort_keys for json.dumps so that the expected and actual
+        # payloads are guaranteed to be identical for mock_args assert check.
+        with mock.patch.object(network_base.json, 'dumps') as mock_dumps:
+            mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
+
+            self.check_service_client_function(
+                self.client.create_security_group,
+                'tempest.lib.common.rest_client.RestClient.post',
+                self.FAKE_SECURITY_GROUP,
+                bytes_body,
+                status=201,
+                mock_args=['v2.0/security-groups', payload],
+                **kwargs)
 
     def _test_show_security_group(self, bytes_body=False):
         self.check_service_client_function(
@@ -113,15 +122,23 @@
         resp_body = copy.deepcopy(self.FAKE_SECURITY_GROUP)
         resp_body["security_group"]["name"] = 'updated-security-group-name'
 
-        self.check_service_client_function(
-            self.client.update_security_group,
-            'tempest.lib.common.rest_client.RestClient.put',
-            resp_body,
-            bytes_body,
-            security_group_id=self.FAKE_SEC_GROUP_ID,
-            mock_args=['v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID,
-                       json.dumps({'security_group': kwargs})],
-            **kwargs)
+        payload = json.dumps({'security_group': kwargs}, sort_keys=True)
+        json_dumps = json.dumps
+
+        # NOTE: Use sort_keys for json.dumps so that the expected and actual
+        # payloads are guaranteed to be identical for mock_args assert check.
+        with mock.patch.object(network_base.json, 'dumps') as mock_dumps:
+            mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True)
+
+            self.check_service_client_function(
+                self.client.update_security_group,
+                'tempest.lib.common.rest_client.RestClient.put',
+                resp_body,
+                bytes_body,
+                security_group_id=self.FAKE_SEC_GROUP_ID,
+                mock_args=['v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID,
+                           payload],
+                **kwargs)
 
     def test_list_security_groups_with_str_body(self):
         self._test_list_security_groups()