|
13 | 13 | # limitations under the License. |
14 | 14 | # type: ignore |
15 | 15 |
|
16 | | -import threading |
17 | 16 | from logging import WARNING |
18 | 17 | from unittest import TestCase |
19 | 18 | from unittest.mock import Mock, patch |
20 | 19 |
|
21 | | -from opentelemetry.metrics import Meter, NoOpMeter |
| 20 | +from opentelemetry.metrics import ( |
| 21 | + Counter, |
| 22 | + Histogram, |
| 23 | + Meter, |
| 24 | + NoOpMeter, |
| 25 | + ObservableCounter, |
| 26 | + ObservableGauge, |
| 27 | + ObservableUpDownCounter, |
| 28 | + UpDownCounter, |
| 29 | + _Gauge, |
| 30 | +) |
| 31 | +from opentelemetry.test.concurrency_test import ConcurrencyTestBase |
22 | 32 |
|
23 | 33 |
|
24 | 34 | class ChildMeter(Meter): |
@@ -196,71 +206,74 @@ def test_create_observable_up_down_counter(self): |
196 | 206 | ) |
197 | 207 |
|
198 | 208 |
|
199 | | -class TestConcurrency(TestCase): |
200 | | - def _run_concurrently(self, fn, num_threads=10, calls_per_thread=100): |
201 | | - """Helper: run fn concurrently across threads and assert no exceptions.""" |
202 | | - errors = [] |
203 | | - |
204 | | - def worker(): |
205 | | - try: |
206 | | - for _ in range(calls_per_thread): |
207 | | - fn() |
208 | | - except Exception as exc: # pylint: disable=broad-except |
209 | | - errors.append(exc) |
210 | | - |
211 | | - threads = [threading.Thread(target=worker) for _ in range(num_threads)] |
212 | | - for thread in threads: |
213 | | - thread.start() |
214 | | - for thread in threads: |
215 | | - thread.join() |
216 | | - |
217 | | - self.assertEqual([], errors) |
218 | | - |
| 209 | +class TestConcurrency(ConcurrencyTestBase): |
219 | 210 | def test_create_counter_concurrent(self): |
220 | 211 | """Test that Meter.create_counter can be called concurrently safely.""" |
221 | 212 | meter = NoOpMeter("name") |
222 | | - self._run_concurrently(lambda: meter.create_counter("counter")) |
| 213 | + results = self.run_with_many_threads( |
| 214 | + lambda: meter.create_counter("counter") |
| 215 | + ) |
| 216 | + self.assertEqual(len(results), 100) |
| 217 | + self.assertTrue(all(isinstance(r, Counter) for r in results)) |
223 | 218 |
|
224 | 219 | def test_create_up_down_counter_concurrent(self): |
225 | 220 | """Test that Meter.create_up_down_counter can be called concurrently safely.""" |
226 | 221 | meter = NoOpMeter("name") |
227 | | - self._run_concurrently( |
| 222 | + results = self.run_with_many_threads( |
228 | 223 | lambda: meter.create_up_down_counter("up_down_counter") |
229 | 224 | ) |
| 225 | + self.assertEqual(len(results), 100) |
| 226 | + self.assertTrue(all(isinstance(r, UpDownCounter) for r in results)) |
230 | 227 |
|
231 | 228 | def test_create_observable_counter_concurrent(self): |
232 | 229 | """Test that Meter.create_observable_counter can be called concurrently safely.""" |
233 | 230 | meter = NoOpMeter("name") |
234 | | - self._run_concurrently( |
| 231 | + results = self.run_with_many_threads( |
235 | 232 | lambda: meter.create_observable_counter( |
236 | 233 | "observable_counter", lambda options: [] |
237 | 234 | ) |
238 | 235 | ) |
| 236 | + self.assertEqual(len(results), 100) |
| 237 | + self.assertTrue(all(isinstance(r, ObservableCounter) for r in results)) |
239 | 238 |
|
240 | 239 | def test_create_histogram_concurrent(self): |
241 | 240 | """Test that Meter.create_histogram can be called concurrently safely.""" |
242 | 241 | meter = NoOpMeter("name") |
243 | | - self._run_concurrently(lambda: meter.create_histogram("histogram")) |
| 242 | + results = self.run_with_many_threads( |
| 243 | + lambda: meter.create_histogram("histogram") |
| 244 | + ) |
| 245 | + self.assertEqual(len(results), 100) |
| 246 | + self.assertTrue(all(isinstance(r, Histogram) for r in results)) |
244 | 247 |
|
245 | 248 | def test_create_gauge_concurrent(self): |
246 | 249 | """Test that Meter.create_gauge can be called concurrently safely.""" |
247 | 250 | meter = NoOpMeter("name") |
248 | | - self._run_concurrently(lambda: meter.create_gauge("gauge")) |
| 251 | + results = self.run_with_many_threads( |
| 252 | + lambda: meter.create_gauge("gauge") |
| 253 | + ) |
| 254 | + self.assertEqual(len(results), 100) |
| 255 | + self.assertTrue(all(isinstance(r, _Gauge) for r in results)) |
249 | 256 |
|
250 | 257 | def test_create_observable_gauge_concurrent(self): |
251 | 258 | """Test that Meter.create_observable_gauge can be called concurrently safely.""" |
252 | 259 | meter = NoOpMeter("name") |
253 | | - self._run_concurrently( |
| 260 | + results = self.run_with_many_threads( |
254 | 261 | lambda: meter.create_observable_gauge( |
255 | 262 | "observable_gauge", lambda options: [] |
256 | 263 | ) |
257 | 264 | ) |
| 265 | + self.assertEqual(len(results), 100) |
| 266 | + self.assertTrue(all(isinstance(r, ObservableGauge) for r in results)) |
258 | 267 |
|
259 | 268 | def test_create_observable_up_down_counter_concurrent(self): |
260 | 269 | """Test that Meter.create_observable_up_down_counter can be called concurrently safely.""" |
261 | 270 | meter = NoOpMeter("name") |
262 | | - self._run_concurrently( |
| 271 | + results = self.run_with_many_threads( |
263 | 272 | lambda: meter.create_observable_up_down_counter( |
264 | 273 | "observable_up_down_counter", lambda options: [] |
265 | 274 | ) |
266 | 275 | ) |
| 276 | + self.assertEqual(len(results), 100) |
| 277 | + self.assertTrue( |
| 278 | + all(isinstance(r, ObservableUpDownCounter) for r in results) |
| 279 | + ) |
0 commit comments