|
13 | 13 | _MONITOR_DOMAIN_MAPPING,
|
14 | 14 | _format_storage_telemetry_item,
|
15 | 15 | _get_auth_policy,
|
| 16 | + _get_authentication_credential, |
16 | 17 | BaseExporter,
|
17 | 18 | ExportResult,
|
18 | 19 | )
|
19 | 20 | from azure.monitor.opentelemetry.exporter.statsbeat._state import _REQUESTS_MAP
|
| 21 | +from azure.monitor.opentelemetry.exporter.statsbeat._exporter import _StatsBeatExporter |
20 | 22 | from azure.monitor.opentelemetry.exporter._constants import (
|
21 | 23 | _DEFAULT_AAD_SCOPE,
|
22 | 24 | _REQ_DURATION_NAME,
|
@@ -72,6 +74,8 @@ def clean_folder(folder):
|
72 | 74 | class TestBaseExporter(unittest.TestCase):
|
73 | 75 | @classmethod
|
74 | 76 | def setUpClass(cls):
|
| 77 | + # Clear environ so the mocks from past tests do not interfere. |
| 78 | + os.environ.clear() |
75 | 79 | os.environ["APPINSIGHTS_INSTRUMENTATIONKEY"] = "1234abcd-5678-4efa-8abc-1234567890ab"
|
76 | 80 | os.environ["APPLICATIONINSIGHTS_STATSBEAT_DISABLED_ALL"] = "true"
|
77 | 81 | cls._base = BaseExporter()
|
@@ -937,25 +941,57 @@ def test_transmission_empty(self):
|
937 | 941 | status = self._base._transmit([])
|
938 | 942 | self.assertEqual(status, ExportResult.SUCCESS)
|
939 | 943 |
|
| 944 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base._get_authentication_credential") |
940 | 945 | @mock.patch("azure.monitor.opentelemetry.exporter.export._base._get_auth_policy")
|
941 |
| - def test_exporter_credential(self, mock_add_credential_policy): |
| 946 | + def test_exporter_credential(self, mock_add_credential_policy, mock_get_authentication_credential): |
942 | 947 | TEST_CREDENTIAL = "TEST_CREDENTIAL"
|
| 948 | + mock_get_authentication_credential.return_value = TEST_CREDENTIAL |
943 | 949 | base = BaseExporter(credential=TEST_CREDENTIAL, authentication_policy=TEST_AUTH_POLICY)
|
944 | 950 | self.assertEqual(base._credential, TEST_CREDENTIAL)
|
945 | 951 | mock_add_credential_policy.assert_called_once_with(TEST_CREDENTIAL, TEST_AUTH_POLICY, None)
|
946 | 952 |
|
| 953 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base._get_authentication_credential") |
947 | 954 | @mock.patch("azure.monitor.opentelemetry.exporter.export._base._get_auth_policy")
|
948 |
| - def test_exporter_credential_audience(self, mock_add_credential_policy): |
| 955 | + def test_exporter_credential_audience(self, mock_add_credential_policy, mock_get_authentication_credential): |
949 | 956 | test_cs = "AadAudience=test-aad"
|
950 | 957 | TEST_CREDENTIAL = "TEST_CREDENTIAL"
|
| 958 | + mock_get_authentication_credential.return_value = TEST_CREDENTIAL |
| 959 | + # TODO: replace with mock |
951 | 960 | base = BaseExporter(
|
952 | 961 | connection_string=test_cs,
|
953 | 962 | credential=TEST_CREDENTIAL,
|
954 | 963 | authentication_policy=TEST_AUTH_POLICY,
|
955 | 964 | )
|
956 | 965 | self.assertEqual(base._credential, TEST_CREDENTIAL)
|
957 | 966 | mock_add_credential_policy.assert_called_once_with(TEST_CREDENTIAL, TEST_AUTH_POLICY, "test-aad")
|
| 967 | + mock_get_authentication_credential.assert_called_once_with( |
| 968 | + connection_string=test_cs, |
| 969 | + credential=TEST_CREDENTIAL, |
| 970 | + authentication_policy=TEST_AUTH_POLICY, |
| 971 | + ) |
958 | 972 |
|
| 973 | + @mock.patch.dict("os.environ", { |
| 974 | + "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "TEST_CREDENTIAL_ENV_VAR" |
| 975 | + }) |
| 976 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base._get_authentication_credential") |
| 977 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base._get_auth_policy") |
| 978 | + def test_credential_env_var_and_arg(self, mock_add_credential_policy, mock_get_authentication_credential): |
| 979 | + mock_get_authentication_credential.return_value = "TEST_CREDENTIAL_ENV_VAR" |
| 980 | + base = BaseExporter(authentication_policy=TEST_AUTH_POLICY) |
| 981 | + self.assertEqual(base._credential, "TEST_CREDENTIAL_ENV_VAR") |
| 982 | + mock_add_credential_policy.assert_called_once_with("TEST_CREDENTIAL_ENV_VAR", TEST_AUTH_POLICY, None) |
| 983 | + mock_get_authentication_credential.assert_called_once_with(authentication_policy=TEST_AUTH_POLICY) |
| 984 | + |
| 985 | + @mock.patch.dict("os.environ", { |
| 986 | + "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "TEST_CREDENTIAL_ENV_VAR" |
| 987 | + }) |
| 988 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base._get_authentication_credential") |
| 989 | + def test_statsbeat_no_credential(self, mock_get_authentication_credential): |
| 990 | + mock_get_authentication_credential.return_value = "TEST_CREDENTIAL_ENV_VAR" |
| 991 | + statsbeat_exporter = _StatsBeatExporter() |
| 992 | + self.assertIsNone(statsbeat_exporter._credential) |
| 993 | + mock_get_authentication_credential.assert_not_called() |
| 994 | + |
959 | 995 | def test_get_auth_policy(self):
|
960 | 996 | class TestCredential:
|
961 | 997 | def get_token(self):
|
@@ -988,6 +1024,115 @@ def get_token():
|
988 | 1024 | self.assertEqual(result._credential, credential)
|
989 | 1025 | self.assertEqual(result._scopes, ("test_audience/.default",))
|
990 | 1026 |
|
| 1027 | + @mock.patch.dict("os.environ", { |
| 1028 | + "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "Authorization=AAD" |
| 1029 | + }) |
| 1030 | + def test_get_authentication_credential_arg(self): |
| 1031 | + TEST_CREDENTIAL = "TEST_CREDENTIAL" |
| 1032 | + result = _get_authentication_credential( |
| 1033 | + credential=TEST_CREDENTIAL, |
| 1034 | + ) |
| 1035 | + self.assertEqual(result, TEST_CREDENTIAL) |
| 1036 | + |
| 1037 | + @mock.patch.dict("os.environ", { |
| 1038 | + "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "Authorization=AAD" |
| 1039 | + }) |
| 1040 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base.logger") |
| 1041 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base.ManagedIdentityCredential") |
| 1042 | + def test_get_authentication_credential_system_assigned(self, mock_managed_identity, mock_logger): |
| 1043 | + MOCK_MANAGED_IDENTITY_CREDENTIAL = "MOCK_MANAGED_IDENTITY_CREDENTIAL" |
| 1044 | + mock_managed_identity.return_value = MOCK_MANAGED_IDENTITY_CREDENTIAL |
| 1045 | + result = _get_authentication_credential( |
| 1046 | + foo="bar" |
| 1047 | + ) |
| 1048 | + mock_logger.assert_not_called() |
| 1049 | + self.assertEqual(result, MOCK_MANAGED_IDENTITY_CREDENTIAL) |
| 1050 | + mock_managed_identity.assert_called_once_with() |
| 1051 | + |
| 1052 | + @mock.patch.dict("os.environ", { |
| 1053 | + "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "Authorization=AAD;ClientId=TEST_CLIENT_ID" |
| 1054 | + }) |
| 1055 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base.logger") |
| 1056 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base.ManagedIdentityCredential") |
| 1057 | + def test_get_authentication_credential_client_id(self, mock_managed_identity, mock_logger): |
| 1058 | + MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL = "MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL" |
| 1059 | + mock_managed_identity.return_value = MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL |
| 1060 | + result = _get_authentication_credential( |
| 1061 | + foo="bar" |
| 1062 | + ) |
| 1063 | + mock_logger.assert_not_called() |
| 1064 | + self.assertEqual(result, MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL) |
| 1065 | + mock_managed_identity.assert_called_once_with(client_id="TEST_CLIENT_ID") |
| 1066 | + |
| 1067 | + @mock.patch.dict("os.environ", { |
| 1068 | + "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "Authorization=AAD;ClientId=TEST_CLIENT_ID=bar" |
| 1069 | + }) |
| 1070 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base.logger") |
| 1071 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base.ManagedIdentityCredential") |
| 1072 | + def test_get_authentication_credential_misformatted(self, mock_managed_identity, mock_logger): |
| 1073 | + # Even a single misformatted pair means Entra ID auth is skipped. |
| 1074 | + MOCK_MANAGED_IDENTITY_CREDENTIAL = "MOCK_MANAGED_IDENTITY_CREDENTIAL" |
| 1075 | + mock_managed_identity.return_value = MOCK_MANAGED_IDENTITY_CREDENTIAL |
| 1076 | + result = _get_authentication_credential( |
| 1077 | + foo="bar" |
| 1078 | + ) |
| 1079 | + mock_logger.error.assert_called_once() |
| 1080 | + self.assertIsNone(result) |
| 1081 | + mock_managed_identity.assert_not_called() |
| 1082 | + |
| 1083 | + @mock.patch.dict("os.environ", { |
| 1084 | + "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "ClientId=TEST_CLIENT_ID" |
| 1085 | + }) |
| 1086 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base.ManagedIdentityCredential") |
| 1087 | + def test_get_authentication_credential_no_auth(self, mock_managed_identity): |
| 1088 | + MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL = "MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL" |
| 1089 | + mock_managed_identity.return_value = MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL |
| 1090 | + result = _get_authentication_credential( |
| 1091 | + foo="bar" |
| 1092 | + ) |
| 1093 | + self.assertIsNone(result) |
| 1094 | + mock_managed_identity.assert_not_called() |
| 1095 | + |
| 1096 | + @mock.patch.dict("os.environ", { |
| 1097 | + "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "Authorization=foobar;ClientId=TEST_CLIENT_ID" |
| 1098 | + }) |
| 1099 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base.ManagedIdentityCredential") |
| 1100 | + def test_get_authentication_credential_no_aad(self, mock_managed_identity): |
| 1101 | + MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL = "MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL" |
| 1102 | + mock_managed_identity.return_value = MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL |
| 1103 | + result = _get_authentication_credential( |
| 1104 | + foo="bar" |
| 1105 | + ) |
| 1106 | + self.assertIsNone(result) |
| 1107 | + mock_managed_identity.assert_not_called() |
| 1108 | + |
| 1109 | + @mock.patch.dict("os.environ", { |
| 1110 | + "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "Authorization=foobar;ClientId=TEST_CLIENT_ID" |
| 1111 | + }) |
| 1112 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base.ManagedIdentityCredential") |
| 1113 | + def test_get_authentication_credential_no_aad(self, mock_managed_identity): |
| 1114 | + MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL = "MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL" |
| 1115 | + mock_managed_identity.return_value = MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL |
| 1116 | + result = _get_authentication_credential( |
| 1117 | + foo="bar" |
| 1118 | + ) |
| 1119 | + self.assertIsNone(result) |
| 1120 | + mock_managed_identity.assert_not_called() |
| 1121 | + |
| 1122 | + @mock.patch.dict("os.environ", { |
| 1123 | + "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "Authorization=AAD;ClientId=TEST_CLIENT_ID" |
| 1124 | + }) |
| 1125 | + @mock.patch("azure.monitor.opentelemetry.exporter.export._base.ManagedIdentityCredential") |
| 1126 | + def test_get_authentication_credential_error(self, mock_managed_identity): |
| 1127 | + MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL = "MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL" |
| 1128 | + mock_managed_identity.return_value = MOCK_MANAGED_IDENTITY_CLIENT_ID_CREDENTIAL |
| 1129 | + mock_managed_identity.side_effect = ValueError("TEST ERROR") |
| 1130 | + result = _get_authentication_credential( |
| 1131 | + foo="bar" |
| 1132 | + ) |
| 1133 | + self.assertIsNone(result) |
| 1134 | + mock_managed_identity.assert_called_once_with(client_id="TEST_CLIENT_ID") |
| 1135 | + |
991 | 1136 |
|
992 | 1137 | def validate_telemetry_item(item1, item2):
|
993 | 1138 | return (
|
|
0 commit comments