rapitapir 0.1.0

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.
Files changed (157) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +57 -0
  4. data/CHANGELOG.md +94 -0
  5. data/CLEANUP_SUMMARY.md +155 -0
  6. data/CONTRIBUTING.md +280 -0
  7. data/LICENSE +21 -0
  8. data/README.md +485 -0
  9. data/debug_hash.rb +20 -0
  10. data/docs/EXTENSION_COMPARISON.md +388 -0
  11. data/docs/SINATRA_EXTENSION.md +467 -0
  12. data/docs/archive/PHASE_1_2_COMPLETE.md +77 -0
  13. data/docs/archive/PHASE_1_3_COMPLETE.md +152 -0
  14. data/docs/archive/PHASE_2_1_OBSERVABILITY_COMPLETED.md +203 -0
  15. data/docs/archive/PHASE_2_SUMMARY.md +209 -0
  16. data/docs/archive/REFACTORING_SUMMARY.md +184 -0
  17. data/docs/archive/phase_1_3_plan.md +136 -0
  18. data/docs/archive/sinatra_extension_summary.md +188 -0
  19. data/docs/archive/sinatra_working_solution.md +113 -0
  20. data/docs/archive/typescript-client-generator-summary.md +259 -0
  21. data/docs/auto-derivation.md +146 -0
  22. data/docs/blueprint.md +1091 -0
  23. data/docs/endpoint-definition.md +211 -0
  24. data/docs/github_pages_fix.md +52 -0
  25. data/docs/github_pages_setup.md +49 -0
  26. data/docs/implementation-status.md +357 -0
  27. data/docs/observability.md +647 -0
  28. data/docs/phase3-plan.md +108 -0
  29. data/docs/sinatra_rapitapir.md +87 -0
  30. data/docs/type_shortcuts.md +146 -0
  31. data/examples/README_ENTERPRISE.md +202 -0
  32. data/examples/authentication_example.rb +192 -0
  33. data/examples/auto_derivation_ruby_friendly.rb +163 -0
  34. data/examples/cli/user_api_endpoints.rb +56 -0
  35. data/examples/client/typescript_client_example.rb +102 -0
  36. data/examples/client/user-api-client.ts +193 -0
  37. data/examples/demo_api.rb +41 -0
  38. data/examples/docs/documentation_example.rb +112 -0
  39. data/examples/docs/user-api-docs.html +789 -0
  40. data/examples/docs/user-api-docs.md +403 -0
  41. data/examples/enhanced_auto_derivation_test.rb +83 -0
  42. data/examples/enterprise_extension_demo.rb +417 -0
  43. data/examples/enterprise_rapitapir_api.rb +662 -0
  44. data/examples/getting_started_extension.rb +218 -0
  45. data/examples/hello_world.rb +74 -0
  46. data/examples/oauth2/.env.example +19 -0
  47. data/examples/oauth2/README.md +205 -0
  48. data/examples/oauth2/generic_oauth2_api.rb +226 -0
  49. data/examples/oauth2/get_token.rb +72 -0
  50. data/examples/oauth2/songs_api_with_auth0.rb +320 -0
  51. data/examples/oauth2/test_api.sh +16 -0
  52. data/examples/oauth2/test_songs_api.sh +110 -0
  53. data/examples/observability/.env.example +35 -0
  54. data/examples/observability/README.md +230 -0
  55. data/examples/observability/README_HONEYCOMB.md +332 -0
  56. data/examples/observability/advanced_setup.rb +384 -0
  57. data/examples/observability/basic_setup.rb +192 -0
  58. data/examples/observability/complete_test.rb +121 -0
  59. data/examples/observability/honeycomb_example.rb +523 -0
  60. data/examples/observability/honeycomb_rapitapir_clean.rb +488 -0
  61. data/examples/observability/honeycomb_rapitapir_example.rb +523 -0
  62. data/examples/observability/honeycomb_working_example.rb +489 -0
  63. data/examples/observability/quick_test.rb +78 -0
  64. data/examples/observability/simple_test.rb +14 -0
  65. data/examples/observability/test_honeycomb_demo.rb +354 -0
  66. data/examples/observability/test_live_honeycomb.rb +111 -0
  67. data/examples/observability/test_validation.rb +78 -0
  68. data/examples/observability/test_working_validation.rb +66 -0
  69. data/examples/openapi/user_api_schema.rb +132 -0
  70. data/examples/production_ready_example.rb +105 -0
  71. data/examples/rails/users_controller.rb +146 -0
  72. data/examples/readme/basic_sinatra_example.rb +128 -0
  73. data/examples/server/user_api.rb +179 -0
  74. data/examples/simple_auto_derivation_demo.rb +44 -0
  75. data/examples/simple_demo_api.rb +18 -0
  76. data/examples/sinatra/user_app.rb +127 -0
  77. data/examples/t_shortcut_demo.rb +59 -0
  78. data/examples/user_api.rb +190 -0
  79. data/examples/working_getting_started.rb +184 -0
  80. data/examples/working_simple_example.rb +195 -0
  81. data/lib/rapitapir/auth/configuration.rb +129 -0
  82. data/lib/rapitapir/auth/context.rb +122 -0
  83. data/lib/rapitapir/auth/errors.rb +104 -0
  84. data/lib/rapitapir/auth/middleware.rb +324 -0
  85. data/lib/rapitapir/auth/oauth2.rb +350 -0
  86. data/lib/rapitapir/auth/schemes.rb +420 -0
  87. data/lib/rapitapir/auth.rb +113 -0
  88. data/lib/rapitapir/cli/command.rb +535 -0
  89. data/lib/rapitapir/cli/server.rb +243 -0
  90. data/lib/rapitapir/cli/validator.rb +373 -0
  91. data/lib/rapitapir/client/generator_base.rb +272 -0
  92. data/lib/rapitapir/client/typescript_generator.rb +350 -0
  93. data/lib/rapitapir/core/endpoint.rb +158 -0
  94. data/lib/rapitapir/core/enhanced_endpoint.rb +235 -0
  95. data/lib/rapitapir/core/input.rb +182 -0
  96. data/lib/rapitapir/core/output.rb +164 -0
  97. data/lib/rapitapir/core/request.rb +19 -0
  98. data/lib/rapitapir/core/response.rb +17 -0
  99. data/lib/rapitapir/docs/html_generator.rb +780 -0
  100. data/lib/rapitapir/docs/markdown_generator.rb +464 -0
  101. data/lib/rapitapir/dsl/endpoint_dsl.rb +116 -0
  102. data/lib/rapitapir/dsl/enhanced_endpoint_dsl.rb +62 -0
  103. data/lib/rapitapir/dsl/enhanced_input.rb +73 -0
  104. data/lib/rapitapir/dsl/enhanced_output.rb +63 -0
  105. data/lib/rapitapir/dsl/enhanced_structures.rb +393 -0
  106. data/lib/rapitapir/dsl/fluent_dsl.rb +72 -0
  107. data/lib/rapitapir/dsl/fluent_endpoint_builder.rb +316 -0
  108. data/lib/rapitapir/dsl/http_verbs.rb +77 -0
  109. data/lib/rapitapir/dsl/input_methods.rb +47 -0
  110. data/lib/rapitapir/dsl/observability_methods.rb +81 -0
  111. data/lib/rapitapir/dsl/output_methods.rb +43 -0
  112. data/lib/rapitapir/dsl/type_resolution.rb +43 -0
  113. data/lib/rapitapir/observability/configuration.rb +108 -0
  114. data/lib/rapitapir/observability/health_check.rb +236 -0
  115. data/lib/rapitapir/observability/logging.rb +270 -0
  116. data/lib/rapitapir/observability/metrics.rb +203 -0
  117. data/lib/rapitapir/observability/middleware.rb +243 -0
  118. data/lib/rapitapir/observability/tracing.rb +143 -0
  119. data/lib/rapitapir/observability.rb +28 -0
  120. data/lib/rapitapir/openapi/schema_generator.rb +403 -0
  121. data/lib/rapitapir/schema.rb +136 -0
  122. data/lib/rapitapir/server/enhanced_rack_adapter.rb +379 -0
  123. data/lib/rapitapir/server/middleware.rb +120 -0
  124. data/lib/rapitapir/server/path_matcher.rb +45 -0
  125. data/lib/rapitapir/server/rack_adapter.rb +215 -0
  126. data/lib/rapitapir/server/rails_adapter.rb +17 -0
  127. data/lib/rapitapir/server/rails_adapter_class.rb +53 -0
  128. data/lib/rapitapir/server/rails_controller.rb +72 -0
  129. data/lib/rapitapir/server/rails_input_processor.rb +73 -0
  130. data/lib/rapitapir/server/rails_response_handler.rb +29 -0
  131. data/lib/rapitapir/server/sinatra_adapter.rb +200 -0
  132. data/lib/rapitapir/server/sinatra_integration.rb +93 -0
  133. data/lib/rapitapir/sinatra/configuration.rb +91 -0
  134. data/lib/rapitapir/sinatra/extension.rb +214 -0
  135. data/lib/rapitapir/sinatra/oauth2_helpers.rb +236 -0
  136. data/lib/rapitapir/sinatra/resource_builder.rb +152 -0
  137. data/lib/rapitapir/sinatra/swagger_ui_generator.rb +166 -0
  138. data/lib/rapitapir/sinatra_rapitapir.rb +40 -0
  139. data/lib/rapitapir/types/array.rb +163 -0
  140. data/lib/rapitapir/types/auto_derivation.rb +265 -0
  141. data/lib/rapitapir/types/base.rb +146 -0
  142. data/lib/rapitapir/types/boolean.rb +46 -0
  143. data/lib/rapitapir/types/date.rb +92 -0
  144. data/lib/rapitapir/types/datetime.rb +98 -0
  145. data/lib/rapitapir/types/email.rb +32 -0
  146. data/lib/rapitapir/types/float.rb +134 -0
  147. data/lib/rapitapir/types/hash.rb +161 -0
  148. data/lib/rapitapir/types/integer.rb +143 -0
  149. data/lib/rapitapir/types/object.rb +156 -0
  150. data/lib/rapitapir/types/optional.rb +65 -0
  151. data/lib/rapitapir/types/string.rb +185 -0
  152. data/lib/rapitapir/types/uuid.rb +32 -0
  153. data/lib/rapitapir/types.rb +155 -0
  154. data/lib/rapitapir/version.rb +5 -0
  155. data/lib/rapitapir.rb +173 -0
  156. data/rapitapir.gemspec +66 -0
  157. metadata +387 -0
@@ -0,0 +1,354 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'net/http'
5
+ require 'json'
6
+ require 'uri'
7
+
8
+ # Test script to generate sample data for Honeycomb.io observability demo
9
+ class HoneycombDemoTester
10
+ def initialize(base_url = 'http://localhost:4567')
11
+ @base_url = base_url
12
+ @users = []
13
+ end
14
+
15
+ def run_comprehensive_test
16
+ puts "๐Ÿฏ Starting comprehensive Honeycomb.io observability test"
17
+ puts "๐Ÿ“Š This will generate various traces to demonstrate RapiTapir + Honeycomb integration"
18
+ puts ""
19
+
20
+ # Test health checks
21
+ test_health_checks
22
+
23
+ # Create sample users
24
+ create_sample_users
25
+
26
+ # Test different query patterns
27
+ test_user_queries
28
+
29
+ # Test analytics endpoints
30
+ test_analytics
31
+
32
+ # Test error scenarios
33
+ test_error_scenarios
34
+
35
+ # Test performance scenarios
36
+ test_performance_scenarios
37
+
38
+ puts ""
39
+ puts "โœ… Comprehensive test completed!"
40
+ puts "๐Ÿ” Check your Honeycomb.io dashboard to see the traces"
41
+ puts "๐Ÿ“ˆ Recommended queries to try in Honeycomb:"
42
+ puts " - WHERE business.operation EXISTS"
43
+ puts " - WHERE duration_ms > 50"
44
+ puts " - GROUP BY business.operation"
45
+ puts " - WHERE error.type EXISTS"
46
+ puts " - WHERE db.operation = 'SELECT'"
47
+ end
48
+
49
+ private
50
+
51
+ def test_health_checks
52
+ puts "๐Ÿฅ Testing health checks..."
53
+
54
+ # Basic health check
55
+ make_request('GET', '/health')
56
+
57
+ # Multiple health checks to show consistency
58
+ 3.times { make_request('GET', '/health') }
59
+
60
+ puts " โœ“ Health checks completed"
61
+ end
62
+
63
+ def create_sample_users
64
+ puts "๐Ÿ‘ฅ Creating sample users..."
65
+
66
+ sample_users = [
67
+ {
68
+ name: 'Alice Johnson',
69
+ email: 'alice.johnson@techcorp.com',
70
+ age: 28,
71
+ department: 'engineering'
72
+ },
73
+ {
74
+ name: 'Bob Smith',
75
+ email: 'bob.smith@techcorp.com',
76
+ age: 34,
77
+ department: 'sales'
78
+ },
79
+ {
80
+ name: 'Carol Wilson',
81
+ email: 'carol.wilson@techcorp.com',
82
+ age: 29,
83
+ department: 'marketing'
84
+ },
85
+ {
86
+ name: 'David Brown',
87
+ email: 'david.brown@techcorp.com',
88
+ age: 31,
89
+ department: 'engineering'
90
+ },
91
+ {
92
+ name: 'Eve Davis',
93
+ email: 'eve.davis@techcorp.com',
94
+ age: 27,
95
+ department: 'support'
96
+ },
97
+ {
98
+ name: 'Frank Miller',
99
+ email: 'frank.miller@techcorp.com',
100
+ age: 35,
101
+ department: 'sales'
102
+ },
103
+ {
104
+ name: 'Grace Lee',
105
+ email: 'grace.lee@techcorp.com',
106
+ age: 26,
107
+ department: 'engineering'
108
+ },
109
+ {
110
+ name: 'Henry Clark',
111
+ email: 'henry.clark@techcorp.com',
112
+ age: 33,
113
+ department: 'marketing'
114
+ }
115
+ ]
116
+
117
+ sample_users.each_with_index do |user_data, index|
118
+ puts " Creating user #{index + 1}/#{sample_users.length}: #{user_data[:name]}"
119
+ response = make_request('POST', '/users', user_data)
120
+
121
+ if response && response.code == '201'
122
+ user = JSON.parse(response.body)
123
+ @users << user
124
+ puts " โœ“ Created user with ID: #{user['id']}"
125
+ else
126
+ puts " โŒ Failed to create user: #{user_data[:name]}"
127
+ end
128
+
129
+ # Small delay to spread out the requests
130
+ sleep(0.1)
131
+ end
132
+
133
+ puts " โœ“ Created #{@users.length} users"
134
+ end
135
+
136
+ def test_user_queries
137
+ puts "๐Ÿ” Testing user query patterns..."
138
+
139
+ # Basic user listing
140
+ puts " Testing pagination..."
141
+ make_request('GET', '/users')
142
+ make_request('GET', '/users?page=1&limit=3')
143
+ make_request('GET', '/users?page=2&limit=3')
144
+
145
+ # Department filtering
146
+ puts " Testing department filtering..."
147
+ %w[engineering sales marketing support].each do |dept|
148
+ make_request('GET', "/users?department=#{dept}")
149
+ end
150
+
151
+ # Combined filtering and pagination
152
+ puts " Testing combined filtering..."
153
+ make_request('GET', '/users?department=engineering&page=1&limit=2')
154
+
155
+ # Individual user lookups
156
+ puts " Testing individual user lookups..."
157
+ @users.first(3).each do |user|
158
+ make_request('GET', "/users/#{user['id']}")
159
+ end
160
+
161
+ puts " โœ“ User query tests completed"
162
+ end
163
+
164
+ def test_analytics
165
+ puts "๐Ÿ“Š Testing analytics endpoints..."
166
+
167
+ # Department statistics
168
+ 3.times do |i|
169
+ puts " Running analytics query #{i + 1}/3..."
170
+ make_request('GET', '/analytics/department-stats')
171
+ sleep(0.2)
172
+ end
173
+
174
+ puts " โœ“ Analytics tests completed"
175
+ end
176
+
177
+ def test_error_scenarios
178
+ puts "โŒ Testing error scenarios..."
179
+
180
+ # Invalid JSON
181
+ puts " Testing invalid JSON..."
182
+ make_request('POST', '/users', '{"invalid": json}', content_type: 'application/json', raw: true)
183
+
184
+ # Validation errors
185
+ puts " Testing validation errors..."
186
+
187
+ invalid_users = [
188
+ { name: '', email: 'invalid', age: 15, department: 'invalid' }, # Multiple validation errors
189
+ { name: 'John', email: 'not-an-email', age: 25, department: 'engineering' }, # Bad email
190
+ { name: 'Jane', email: 'jane@example.com', age: 16, department: 'engineering' }, # Too young
191
+ { name: 'Bob', email: 'bob@example.com', age: 30, department: 'nonexistent' } # Invalid department
192
+ ]
193
+
194
+ invalid_users.each_with_index do |user_data, index|
195
+ puts " Testing validation error #{index + 1}/#{invalid_users.length}..."
196
+ make_request('POST', '/users', user_data)
197
+ sleep(0.1)
198
+ end
199
+
200
+ # Not found errors
201
+ puts " Testing not found errors..."
202
+ fake_uuid = '12345678-1234-1234-1234-123456789999'
203
+ make_request('GET', "/users/#{fake_uuid}")
204
+ make_request('PUT', "/users/#{fake_uuid}", { name: 'Updated Name' })
205
+ make_request('DELETE', "/users/#{fake_uuid}")
206
+
207
+ puts " โœ“ Error scenario tests completed"
208
+ end
209
+
210
+ def test_performance_scenarios
211
+ puts "โšก Testing performance scenarios..."
212
+
213
+ # Concurrent requests simulation
214
+ puts " Simulating concurrent user listing requests..."
215
+ threads = []
216
+
217
+ 5.times do |i|
218
+ threads << Thread.new do
219
+ make_request('GET', '/users', nil, thread_id: i)
220
+ end
221
+ end
222
+
223
+ threads.each(&:join)
224
+
225
+ # Update operations
226
+ puts " Testing update operations..."
227
+ if @users.any?
228
+ user = @users.first
229
+ update_data = {
230
+ name: "#{user['name']} (Updated)",
231
+ age: user['age'] + 1
232
+ }
233
+ make_request('PUT', "/users/#{user['id']}", update_data)
234
+ end
235
+
236
+ # Delete operations
237
+ puts " Testing delete operations..."
238
+ if @users.length > 1
239
+ user_to_delete = @users.last
240
+ make_request('DELETE', "/users/#{user_to_delete['id']}")
241
+ end
242
+
243
+ puts " โœ“ Performance scenario tests completed"
244
+ end
245
+
246
+ def make_request(method, path, body = nil, content_type: 'application/json', raw: false, thread_id: nil)
247
+ uri = URI("#{@base_url}#{path}")
248
+
249
+ http = Net::HTTP.new(uri.host, uri.port)
250
+
251
+ request = case method.upcase
252
+ when 'GET'
253
+ Net::HTTP::Get.new(uri)
254
+ when 'POST'
255
+ Net::HTTP::Post.new(uri)
256
+ when 'PUT'
257
+ Net::HTTP::Put.new(uri)
258
+ when 'DELETE'
259
+ Net::HTTP::Delete.new(uri)
260
+ else
261
+ raise "Unsupported method: #{method}"
262
+ end
263
+
264
+ if body
265
+ if raw
266
+ request.body = body
267
+ else
268
+ request.body = body.to_json
269
+ end
270
+ request['Content-Type'] = content_type
271
+ end
272
+
273
+ # Add custom headers for tracing
274
+ request['X-Test-Scenario'] = 'honeycomb-demo'
275
+ request['X-Thread-Id'] = thread_id.to_s if thread_id
276
+
277
+ begin
278
+ response = http.request(request)
279
+
280
+ status_symbol = case response.code.to_i
281
+ when 200..299
282
+ 'โœ“'
283
+ when 400..499
284
+ 'โš '
285
+ else
286
+ 'โŒ'
287
+ end
288
+
289
+ thread_info = thread_id ? " [T#{thread_id}]" : ""
290
+ puts " #{status_symbol} #{method.upcase} #{path} โ†’ #{response.code}#{thread_info}"
291
+
292
+ response
293
+ rescue StandardError => e
294
+ puts " โŒ #{method.upcase} #{path} โ†’ Error: #{e.message}"
295
+ nil
296
+ end
297
+ end
298
+ end
299
+
300
+ # Run the test if this file is executed directly
301
+ if __FILE__ == $PROGRAM_NAME
302
+ if ARGV.include?('--help') || ARGV.include?('-h')
303
+ puts "Honeycomb.io Observability Demo Test Script"
304
+ puts ""
305
+ puts "Usage: ruby test_honeycomb_demo.rb [URL]"
306
+ puts ""
307
+ puts "Arguments:"
308
+ puts " URL Base URL of the API server (default: http://localhost:4567)"
309
+ puts ""
310
+ puts "Examples:"
311
+ puts " ruby test_honeycomb_demo.rb"
312
+ puts " ruby test_honeycomb_demo.rb http://localhost:4567"
313
+ puts ""
314
+ puts "This script will:"
315
+ puts " 1. Test health check endpoints"
316
+ puts " 2. Create sample users with various departments"
317
+ puts " 3. Test different query patterns (pagination, filtering)"
318
+ puts " 4. Test analytics endpoints"
319
+ puts " 5. Generate error scenarios for testing"
320
+ puts " 6. Simulate performance scenarios"
321
+ puts ""
322
+ puts "All requests will generate traces in Honeycomb.io for analysis."
323
+ puts ""
324
+ puts "โš ๏ธ Make sure to start the server first:"
325
+ puts " ruby honeycomb_working_example.rb"
326
+ exit 0
327
+ end
328
+
329
+ base_url = ARGV[0] || 'http://localhost:4567'
330
+
331
+ puts "๐ŸŽฏ Target URL: #{base_url}"
332
+ puts ""
333
+
334
+ # Check if server is running
335
+ begin
336
+ uri = URI("#{base_url}/health")
337
+ response = Net::HTTP.get_response(uri)
338
+ if response.code != '200'
339
+ puts "โŒ Server not responding correctly at #{base_url}"
340
+ puts " Make sure the Honeycomb demo server is running:"
341
+ puts " ruby examples/observability/honeycomb_working_example.rb"
342
+ exit 1
343
+ end
344
+ rescue StandardError => e
345
+ puts "โŒ Cannot connect to server at #{base_url}"
346
+ puts " Error: #{e.message}"
347
+ puts " Make sure the Honeycomb demo server is running:"
348
+ puts " ruby examples/observability/honeycomb_working_example.rb"
349
+ exit 1
350
+ end
351
+
352
+ tester = HoneycombDemoTester.new(base_url)
353
+ tester.run_comprehensive_test
354
+ end
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Quick test to verify Honeycomb integration is working
5
+ require 'net/http'
6
+ require 'json'
7
+ require 'uri'
8
+
9
+ puts "๐Ÿฏ Testing Honeycomb.io Integration"
10
+ puts "=================================="
11
+
12
+ # Start server in background
13
+ puts "๐Ÿ“ก Starting server..."
14
+ server_pid = spawn("bundle exec ruby honeycomb_working_example.rb",
15
+ out: "/dev/null", err: "/dev/null")
16
+
17
+ # Wait for server to start
18
+ sleep(3)
19
+ puts "โœ… Server started (PID: #{server_pid})"
20
+
21
+ begin
22
+ base_url = 'http://localhost:4567'
23
+
24
+ # Test health endpoint
25
+ puts "\n๐Ÿฅ Testing health endpoint..."
26
+ uri = URI("#{base_url}/health")
27
+ response = Net::HTTP.get_response(uri)
28
+
29
+ if response.code == '200'
30
+ puts "โœ… Health check successful (#{response.code})"
31
+ health_data = JSON.parse(response.body)
32
+ puts " Status: #{health_data['status']}"
33
+ puts " Service: #{health_data['service']}"
34
+ else
35
+ puts "โŒ Health check failed (#{response.code})"
36
+ end
37
+
38
+ # Test user creation (will generate traces)
39
+ puts "\n๐Ÿ‘ค Testing user creation..."
40
+ uri = URI("#{base_url}/users")
41
+ http = Net::HTTP.new(uri.host, uri.port)
42
+
43
+ request = Net::HTTP::Post.new(uri)
44
+ request['Content-Type'] = 'application/json'
45
+ request.body = {
46
+ name: 'Test User for Honeycomb',
47
+ email: 'test@honeycomb-demo.com',
48
+ age: 30,
49
+ department: 'engineering'
50
+ }.to_json
51
+
52
+ response = http.request(request)
53
+
54
+ if response.code == '201'
55
+ puts "โœ… User creation successful (#{response.code})"
56
+ user_data = JSON.parse(response.body)
57
+ puts " Created user: #{user_data['name']} (ID: #{user_data['id']})"
58
+
59
+ # Test getting the user back
60
+ puts "\n๐Ÿ” Testing user retrieval..."
61
+ get_uri = URI("#{base_url}/users/#{user_data['id']}")
62
+ get_response = Net::HTTP.get_response(get_uri)
63
+
64
+ if get_response.code == '200'
65
+ puts "โœ… User retrieval successful (#{get_response.code})"
66
+ else
67
+ puts "โŒ User retrieval failed (#{get_response.code})"
68
+ end
69
+ else
70
+ puts "โŒ User creation failed (#{response.code})"
71
+ puts " Response: #{response.body}"
72
+ end
73
+
74
+ # Test analytics endpoint (complex operation)
75
+ puts "\n๐Ÿ“Š Testing analytics endpoint..."
76
+ analytics_uri = URI("#{base_url}/analytics/department-stats")
77
+ analytics_response = Net::HTTP.get_response(analytics_uri)
78
+
79
+ if analytics_response.code == '200'
80
+ puts "โœ… Analytics successful (#{analytics_response.code})"
81
+ analytics_data = JSON.parse(analytics_response.body)
82
+ puts " Total users: #{analytics_data['total_users']}"
83
+ else
84
+ puts "โŒ Analytics failed (#{analytics_response.code})"
85
+ end
86
+
87
+ puts "\n๐ŸŽ‰ Test completed successfully!"
88
+ puts ""
89
+ puts "๐Ÿ“Š Traces should now be visible in your Honeycomb dashboard:"
90
+ puts " 1. Go to https://ui.honeycomb.io/"
91
+ puts " 2. Look for dataset: 'rapitapir-demo'"
92
+ puts " 3. You should see traces for:"
93
+ puts " - GET /health"
94
+ puts " - POST /users"
95
+ puts " - GET /users/:id"
96
+ puts " - GET /analytics/department-stats"
97
+ puts ""
98
+ puts "๐Ÿ” Try these queries in Honeycomb:"
99
+ puts " - WHERE business.operation EXISTS"
100
+ puts " - WHERE http.method = 'POST'"
101
+ puts " - WHERE db.operation EXISTS"
102
+ puts " - GROUP BY business.operation"
103
+
104
+ rescue StandardError => e
105
+ puts "โŒ Error during testing: #{e.message}"
106
+ ensure
107
+ puts "\n๐Ÿ›‘ Stopping server..."
108
+ Process.kill('TERM', server_pid) if server_pid
109
+ sleep(1)
110
+ puts "โœ… Server stopped"
111
+ end
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Test script to validate Honeycomb.io observability example
5
+ require 'bundler/setup'
6
+
7
+ # Add local lib to load path for RapiTapir
8
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __dir__))
9
+
10
+ # Set mock environment variables
11
+ ENV['OTEL_EXPORTER_OTLP_HEADERS'] = 'x-honeycomb-team=test-key'
12
+ ENV['OTEL_SERVICE_NAME'] = 'rapitapir-demo'
13
+ ENV['OTEL_EXPORTER_OTLP_ENDPOINT'] = 'https://api.honeycomb.io'
14
+
15
+ # Override $PROGRAM_NAME to avoid server startup
16
+ original_program_name = $PROGRAM_NAME
17
+ $PROGRAM_NAME = 'test_validation'
18
+
19
+ begin
20
+ puts "๐Ÿงช Testing Honeycomb.io observability example..."
21
+
22
+ # Test individual gem loading
23
+ puts " Loading OpenTelemetry SDK..."
24
+ require 'opentelemetry/sdk'
25
+
26
+ puts " Loading OpenTelemetry OTLP exporter..."
27
+ require 'opentelemetry/exporter/otlp'
28
+
29
+ puts " Loading OpenTelemetry instrumentation..."
30
+ require 'opentelemetry/instrumentation/all'
31
+
32
+ puts " Loading OpenTelemetry baggage processor..."
33
+ require 'opentelemetry/processor/baggage/baggage_span_processor'
34
+
35
+ puts " Loading Sinatra..."
36
+ require 'sinatra/base'
37
+
38
+ puts " Loading JSON..."
39
+ require 'json'
40
+
41
+ # Now load the main example file
42
+ puts " Loading honeycomb_example.rb..."
43
+ load File.join(__dir__, 'honeycomb_example.rb')
44
+
45
+ # Test that the class was defined
46
+ unless defined?(HoneycombDemoAPI)
47
+ raise "HoneycombDemoAPI class not defined"
48
+ end
49
+
50
+ puts ""
51
+ puts "โœ… Success! All components loaded correctly:"
52
+ puts " โœ“ OpenTelemetry SDK initialized"
53
+ puts " โœ“ OTLP exporter configured"
54
+ puts " โœ“ Automatic instrumentation enabled"
55
+ puts " โœ“ Baggage processor configured"
56
+ puts " โœ“ RapiTapir configuration loaded"
57
+ puts " โœ“ Sinatra app class defined: #{HoneycombDemoAPI.name}"
58
+ puts ""
59
+ puts "๐Ÿš€ Ready to run the Honeycomb.io observability demo!"
60
+ puts " Usage: ruby honeycomb_example.rb"
61
+ puts ""
62
+ puts "๐Ÿ“‹ Next steps:"
63
+ puts " 1. Get a Honeycomb.io API key from https://ui.honeycomb.io/account"
64
+ puts " 2. Copy .env.example to .env and add your API key"
65
+ puts " 3. Run: ruby honeycomb_example.rb"
66
+ puts " 4. Make requests to generate traces"
67
+ puts " 5. View traces in Honeycomb.io dashboard"
68
+
69
+ rescue LoadError => e
70
+ puts "โŒ LoadError: #{e.message}"
71
+ puts " Make sure all gems are installed: bundle install"
72
+ rescue StandardError => e
73
+ puts "โŒ Error: #{e.message}"
74
+ puts " Backtrace:"
75
+ puts e.backtrace.first(5).map { |line| " #{line}" }
76
+ ensure
77
+ $PROGRAM_NAME = original_program_name
78
+ end
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Test script for the working Honeycomb example
5
+ require 'bundler/setup'
6
+
7
+ # Set mock environment variables
8
+ ENV['OTEL_EXPORTER_OTLP_HEADERS'] = 'x-honeycomb-team=test-key'
9
+ ENV['OTEL_SERVICE_NAME'] = 'rapitapir-demo'
10
+ ENV['OTEL_EXPORTER_OTLP_ENDPOINT'] = 'https://api.honeycomb.io'
11
+
12
+ # Override $PROGRAM_NAME to avoid server startup
13
+ original_program_name = $PROGRAM_NAME
14
+ $PROGRAM_NAME = 'test_validation'
15
+
16
+ begin
17
+ puts "๐Ÿงช Testing working Honeycomb.io observability example..."
18
+
19
+ # Load the working example
20
+ puts " Loading honeycomb_working_example.rb..."
21
+ load File.join(__dir__, 'honeycomb_working_example.rb')
22
+
23
+ # Test that the class was defined
24
+ unless defined?(HoneycombDemoAPI)
25
+ raise "HoneycombDemoAPI class not defined"
26
+ end
27
+
28
+ puts ""
29
+ puts "โœ… Success! Working Honeycomb example loaded correctly:"
30
+ puts " โœ“ OpenTelemetry SDK initialized"
31
+ puts " โœ“ OTLP exporter configured for Honeycomb.io"
32
+ puts " โœ“ Automatic instrumentation enabled (Sinatra, Rack, HTTP)"
33
+ puts " โœ“ Baggage processor configured for context propagation"
34
+ puts " โœ“ Custom RapiTapir observability extension loaded"
35
+ puts " โœ“ Sinatra app class defined: #{HoneycombDemoAPI.name}"
36
+ puts ""
37
+ puts "๐Ÿš€ Ready to run the Honeycomb.io observability demo!"
38
+ puts " Usage: ruby honeycomb_working_example.rb"
39
+ puts ""
40
+ puts "๐Ÿ“‹ Next steps:"
41
+ puts " 1. Get a Honeycomb.io API key from https://ui.honeycomb.io/account"
42
+ puts " 2. Copy .env.example to .env and add your API key"
43
+ puts " 3. Load environment: source .env"
44
+ puts " 4. Run: ruby honeycomb_working_example.rb"
45
+ puts " 5. Make requests to generate traces"
46
+ puts " 6. View traces in Honeycomb.io dashboard"
47
+ puts ""
48
+ puts "๐Ÿ”ง Available endpoints:"
49
+ puts " GET /health - Health check with tracing"
50
+ puts " GET /users - List users with pagination"
51
+ puts " POST /users - Create user with validation"
52
+ puts " GET /users/:id - Get user by ID"
53
+ puts " PUT /users/:id - Update user"
54
+ puts " DELETE /users/:id - Delete user"
55
+ puts " GET /analytics/department-stats - Complex analytics operation"
56
+
57
+ rescue LoadError => e
58
+ puts "โŒ LoadError: #{e.message}"
59
+ puts " Make sure all gems are installed: bundle install"
60
+ rescue StandardError => e
61
+ puts "โŒ Error: #{e.message}"
62
+ puts " Backtrace:"
63
+ puts e.backtrace.first(5).map { |line| " #{line}" }
64
+ ensure
65
+ $PROGRAM_NAME = original_program_name
66
+ end