paygent-sdk 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tests/test_client.py ADDED
@@ -0,0 +1,277 @@
1
+ """
2
+ Tests for the Paygent SDK client.
3
+ """
4
+
5
+ import json
6
+ import logging
7
+ import unittest
8
+ from unittest.mock import Mock, patch, MagicMock
9
+
10
+ import requests
11
+
12
+ from paygent_sdk.client import Client
13
+ from paygent_sdk.models import UsageData, UsageDataWithStrings, APIRequest, ModelPricing, MODEL_PRICING
14
+
15
+
16
+ class TestClient(unittest.TestCase):
17
+ """Test cases for the Client class."""
18
+
19
+ def setUp(self):
20
+ """Set up test fixtures."""
21
+ self.api_key = "test-api-key"
22
+ self.base_url = "https://api.paygent.com"
23
+ self.client = Client(self.api_key, self.base_url)
24
+
25
+ def test_new_client(self):
26
+ """Test creating a new client with default URL."""
27
+ client = Client.new_client(self.api_key)
28
+ self.assertIsNotNone(client)
29
+ self.assertEqual(client.api_key, self.api_key)
30
+ self.assertEqual(client.base_url, "https://api.paygent.com")
31
+
32
+ def test_new_client_with_url(self):
33
+ """Test creating a new client with custom URL."""
34
+ custom_url = "https://custom-api.paygent.com"
35
+ client = Client.new_client_with_url(self.api_key, custom_url)
36
+ self.assertIsNotNone(client)
37
+ self.assertEqual(client.api_key, self.api_key)
38
+ self.assertEqual(client.base_url, custom_url)
39
+
40
+ def test_calculate_cost_llama(self):
41
+ """Test cost calculation for Llama model."""
42
+ usage_data = UsageData(
43
+ service_provider="openai",
44
+ model="llama",
45
+ prompt_tokens=1000,
46
+ completion_tokens=500,
47
+ total_tokens=1500
48
+ )
49
+
50
+ cost = self.client._calculate_cost("llama", usage_data)
51
+ expected = 0.00015 # (1000/1000 + 500/1000) * 0.0001
52
+ self.assertAlmostEqual(cost, expected, places=6)
53
+
54
+ def test_calculate_cost_gpt4(self):
55
+ """Test cost calculation for GPT-4 model."""
56
+ usage_data = UsageData(
57
+ service_provider="openai",
58
+ model="gpt-4",
59
+ prompt_tokens=1000,
60
+ completion_tokens=500,
61
+ total_tokens=1500
62
+ )
63
+
64
+ cost = self.client._calculate_cost("gpt-4", usage_data)
65
+ expected = 0.06 # (1000/1000) * 0.03 + (500/1000) * 0.06
66
+ self.assertEqual(cost, expected)
67
+
68
+ def test_calculate_cost_unknown_model(self):
69
+ """Test cost calculation for unknown model (default pricing)."""
70
+ usage_data = UsageData(
71
+ service_provider="custom",
72
+ model="unknown-model",
73
+ prompt_tokens=1000,
74
+ completion_tokens=500,
75
+ total_tokens=1500
76
+ )
77
+
78
+ cost = self.client._calculate_cost("unknown-model", usage_data)
79
+ expected = 0.00015 # (1000/1000 + 500/1000) * 0.0001 (default pricing)
80
+ self.assertAlmostEqual(cost, expected, places=6)
81
+
82
+ @patch('paygent_sdk.client.requests.Session.post')
83
+ def test_send_usage_success(self, mock_post):
84
+ """Test successful usage data sending."""
85
+ # Mock successful response
86
+ mock_response = Mock()
87
+ mock_response.status_code = 200
88
+ mock_response.text = "Success"
89
+ mock_post.return_value = mock_response
90
+
91
+ usage_data = UsageData(
92
+ service_provider="openai",
93
+ model="llama",
94
+ prompt_tokens=1000,
95
+ completion_tokens=500,
96
+ total_tokens=1500
97
+ )
98
+
99
+ # Should not raise any exception
100
+ self.client.send_usage("agent-123", "customer-456", "test-indicator", usage_data)
101
+
102
+ # Verify the request was made correctly
103
+ mock_post.assert_called_once()
104
+ call_args = mock_post.call_args
105
+
106
+ # Check URL
107
+ self.assertEqual(call_args[0][0], "https://api.paygent.com/api/v1/usage")
108
+
109
+ # Check headers
110
+ headers = call_args[1]['headers']
111
+ self.assertEqual(headers['Content-Type'], 'application/json')
112
+ self.assertEqual(headers['paygent-api-key'], 'test-api-key')
113
+
114
+ # Check request data
115
+ request_data = call_args[1]['json']
116
+ self.assertEqual(request_data['agentId'], 'agent-123')
117
+ self.assertEqual(request_data['customerId'], 'customer-456')
118
+ self.assertEqual(request_data['indicator'], 'test-indicator')
119
+ self.assertAlmostEqual(request_data['amount'], 0.00015, places=6) # Expected cost for llama model
120
+ self.assertEqual(request_data['inputToken'], 1000) # prompt_tokens
121
+ self.assertEqual(request_data['outputToken'], 500) # completion_tokens
122
+ self.assertEqual(request_data['model'], 'llama') # model
123
+ self.assertEqual(request_data['serviceProvider'], 'openai') # service_provider
124
+
125
+ @patch('paygent_sdk.client.requests.Session.post')
126
+ def test_send_usage_http_error(self, mock_post):
127
+ """Test handling of HTTP errors."""
128
+ # Mock HTTP error response
129
+ mock_response = Mock()
130
+ mock_response.status_code = 400
131
+ mock_response.text = "Bad Request"
132
+ mock_response.raise_for_status.side_effect = requests.HTTPError("400 Bad Request")
133
+ mock_post.return_value = mock_response
134
+
135
+ usage_data = UsageData(
136
+ service_provider="openai",
137
+ model="llama",
138
+ prompt_tokens=1000,
139
+ completion_tokens=500,
140
+ total_tokens=1500
141
+ )
142
+
143
+ # Should raise HTTPError
144
+ with self.assertRaises(requests.HTTPError):
145
+ self.client.send_usage("agent-123", "customer-456", "test-indicator", usage_data)
146
+
147
+ @patch('paygent_sdk.client.requests.Session.post')
148
+ def test_send_usage_network_error(self, mock_post):
149
+ """Test handling of network errors."""
150
+ # Mock network error
151
+ mock_post.side_effect = requests.ConnectionError("Network error")
152
+
153
+ usage_data = UsageData(
154
+ service_provider="openai",
155
+ model="llama",
156
+ prompt_tokens=1000,
157
+ completion_tokens=500,
158
+ total_tokens=1500
159
+ )
160
+
161
+ # Should raise ConnectionError
162
+ with self.assertRaises(requests.ConnectionError):
163
+ self.client.send_usage("agent-123", "customer-456", "test-indicator", usage_data)
164
+
165
+ def test_set_log_level(self):
166
+ """Test setting log level."""
167
+ self.client.set_log_level(logging.DEBUG)
168
+ self.assertEqual(self.client.logger.level, logging.DEBUG)
169
+
170
+ def test_get_logger(self):
171
+ """Test getting logger instance."""
172
+ logger = self.client.get_logger()
173
+ self.assertIsNotNone(logger)
174
+ self.assertEqual(logger, self.client.logger)
175
+
176
+ @patch('paygent_sdk.client.requests.Session.post')
177
+ def test_send_usage_with_token_string_success(self, mock_post):
178
+ """Test successful usage data sending with token strings."""
179
+ # Mock successful response
180
+ mock_response = Mock()
181
+ mock_response.status_code = 200
182
+ mock_response.text = "Success"
183
+ mock_post.return_value = mock_response
184
+
185
+ usage_data = UsageDataWithStrings(
186
+ service_provider="openai",
187
+ model="llama",
188
+ prompt_string="Hello, world!",
189
+ output_string="Hi there!"
190
+ )
191
+
192
+ # Should not raise any exception
193
+ self.client.send_usage_with_token_string("agent-123", "customer-456", "test-indicator", usage_data)
194
+
195
+ # Verify the request was made correctly
196
+ mock_post.assert_called_once()
197
+ call_args = mock_post.call_args
198
+
199
+ # Check URL
200
+ self.assertEqual(call_args[0][0], "https://api.paygent.com/api/v1/usage")
201
+
202
+ # Check headers
203
+ headers = call_args[1]['headers']
204
+ self.assertEqual(headers['Content-Type'], 'application/json')
205
+ self.assertEqual(headers['paygent-api-key'], 'test-api-key')
206
+
207
+ # Check request data
208
+ request_data = call_args[1]['json']
209
+ self.assertEqual(request_data['agentId'], 'agent-123')
210
+ self.assertEqual(request_data['customerId'], 'customer-456')
211
+ self.assertEqual(request_data['indicator'], 'test-indicator')
212
+ self.assertIn('amount', request_data) # Amount should be calculated
213
+ self.assertIn('inputToken', request_data) # inputToken should be present
214
+ self.assertIn('outputToken', request_data) # outputToken should be present
215
+ self.assertIsInstance(request_data['inputToken'], int) # inputToken should be integer
216
+ self.assertIsInstance(request_data['outputToken'], int) # outputToken should be integer
217
+ self.assertEqual(request_data['model'], 'llama') # model
218
+ self.assertEqual(request_data['serviceProvider'], 'openai') # service_provider
219
+
220
+
221
+ class TestModels(unittest.TestCase):
222
+ """Test cases for data models."""
223
+
224
+ def test_usage_data(self):
225
+ """Test UsageData model."""
226
+ usage_data = UsageData(
227
+ service_provider="openai",
228
+ model="llama",
229
+ prompt_tokens=1000,
230
+ completion_tokens=500,
231
+ total_tokens=1500
232
+ )
233
+
234
+ self.assertEqual(usage_data.service_provider, "openai")
235
+ self.assertEqual(usage_data.model, "llama")
236
+ self.assertEqual(usage_data.prompt_tokens, 1000)
237
+ self.assertEqual(usage_data.completion_tokens, 500)
238
+ self.assertEqual(usage_data.total_tokens, 1500)
239
+
240
+ def test_api_request(self):
241
+ """Test APIRequest model."""
242
+ api_request = APIRequest(
243
+ agent_id="agent-123",
244
+ customer_id="customer-456",
245
+ indicator="test-indicator",
246
+ amount=0.15
247
+ )
248
+
249
+ self.assertEqual(api_request.agent_id, "agent-123")
250
+ self.assertEqual(api_request.customer_id, "customer-456")
251
+ self.assertEqual(api_request.indicator, "test-indicator")
252
+ self.assertEqual(api_request.amount, 0.15)
253
+
254
+ def test_model_pricing(self):
255
+ """Test ModelPricing model."""
256
+ pricing = ModelPricing(
257
+ prompt_tokens_cost=0.0001,
258
+ completion_tokens_cost=0.0001
259
+ )
260
+
261
+ self.assertEqual(pricing.prompt_tokens_cost, 0.0001)
262
+ self.assertEqual(pricing.completion_tokens_cost, 0.0001)
263
+
264
+ def test_model_pricing_constants(self):
265
+ """Test that MODEL_PRICING contains expected models."""
266
+ expected_models = [
267
+ "llama", "gpt-3.5-turbo", "gpt-4",
268
+ "claude-3-sonnet", "claude-3-opus"
269
+ ]
270
+
271
+ for model in expected_models:
272
+ self.assertIn(model, MODEL_PRICING)
273
+ self.assertIsInstance(MODEL_PRICING[model], ModelPricing)
274
+
275
+
276
+ if __name__ == '__main__':
277
+ unittest.main()