max_bot 0.1.1 → 0.2.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +67 -0
- data/LICENSE.txt +21 -0
- data/README.md +242 -0
- data/Rakefile +11 -0
- data/examples/polling_bot.rb +46 -0
- data/lib/max/bot/api/request_builders.rb +98 -0
- data/lib/max/bot/api.rb +150 -0
- data/lib/max/bot/attachments.rb +109 -0
- data/lib/max/bot/client.rb +83 -0
- data/lib/max/bot/configuration.rb +15 -0
- data/lib/max/bot/errors.rb +24 -0
- data/lib/max/bot/http.rb +54 -0
- data/lib/max/bot/json.rb +39 -0
- data/lib/max/bot/multipart_upload.rb +54 -0
- data/lib/max/bot/update_helpers.rb +47 -0
- data/lib/max/bot/version.rb +7 -0
- data/lib/max/bot/webhook.rb +38 -0
- data/lib/max/bot.rb +33 -0
- data/lib/max_bot.rb +2 -2
- data/test/max/bot/api/request_builders_test.rb +56 -0
- data/test/max/bot/api_send_test.rb +128 -0
- data/test/max/bot/api_test.rb +26 -0
- data/test/max/bot/attachments_test.rb +40 -0
- data/test/max/bot/client_test.rb +60 -0
- data/test/max/bot/errors_test.rb +21 -0
- data/test/max/bot/http_test.rb +82 -0
- data/test/max/bot/json_test.rb +44 -0
- data/test/max/bot/update_helpers_test.rb +29 -0
- data/test/max/bot/webhook_test.rb +35 -0
- data/test/test_helper.rb +6 -0
- metadata +96 -6
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'faraday'
|
|
5
|
+
|
|
6
|
+
module Max
|
|
7
|
+
module Bot
|
|
8
|
+
class RecordingHttp
|
|
9
|
+
attr_reader :posts, :gets, :deletes
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@posts = []
|
|
13
|
+
@gets = []
|
|
14
|
+
@deletes = []
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def post(path, query: nil, body: nil)
|
|
18
|
+
@posts << { path: path, query: query, body: body }
|
|
19
|
+
{ ok: true }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def get(path, query: {})
|
|
23
|
+
@gets << { path: path, query: query }
|
|
24
|
+
{ updates: [] }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def delete(path, query: nil)
|
|
28
|
+
@deletes << { path: path, query: query }
|
|
29
|
+
{ success: true }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class ApiSendTest < Minitest::Test
|
|
34
|
+
def test_send_message_merges_attachment_and_attachments
|
|
35
|
+
rec = RecordingHttp.new
|
|
36
|
+
api = Api.new('token', http: rec)
|
|
37
|
+
|
|
38
|
+
api.send_message(
|
|
39
|
+
'Hello',
|
|
40
|
+
chat_id: 10,
|
|
41
|
+
attachment: Attachments.sticker(code: 'smile'),
|
|
42
|
+
attachments: [Attachments.share(url: 'https://a.example')]
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
atts = rec.posts.first[:body][:attachments]
|
|
46
|
+
assert_equal 2, atts.size
|
|
47
|
+
assert_equal 'sticker', atts[0][:type]
|
|
48
|
+
assert_equal 'share', atts[1][:type]
|
|
49
|
+
assert_equal 10, rec.posts.first[:query][:chat_id]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_get_updates_forwards_query
|
|
53
|
+
rec = RecordingHttp.new
|
|
54
|
+
api = Api.new('tok', http: rec)
|
|
55
|
+
api.get_updates(marker: 7, limit: 50, timeout: 15, types: %w[message_created])
|
|
56
|
+
|
|
57
|
+
q = rec.gets.first[:query]
|
|
58
|
+
assert_equal 7, q[:marker]
|
|
59
|
+
assert_equal 50, q[:limit]
|
|
60
|
+
assert_equal 15, q[:timeout]
|
|
61
|
+
assert_equal 'message_created', q[:types]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_set_webhook_json_body
|
|
65
|
+
rec = RecordingHttp.new
|
|
66
|
+
api = Api.new('tok', http: rec)
|
|
67
|
+
api.set_webhook(url: 'https://hook', update_types: %w[a], secret: 'sec')
|
|
68
|
+
|
|
69
|
+
body = rec.posts.first[:body]
|
|
70
|
+
assert_equal 'https://hook', body[:url]
|
|
71
|
+
assert_equal %w[a], body[:update_types]
|
|
72
|
+
assert_equal 'sec', body[:secret]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_delete_webhook_query
|
|
76
|
+
rec = RecordingHttp.new
|
|
77
|
+
api = Api.new('tok', http: rec)
|
|
78
|
+
api.delete_webhook('https://hook')
|
|
79
|
+
|
|
80
|
+
assert_equal({ url: 'https://hook' }, rec.deletes.first[:query])
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_chats_query
|
|
84
|
+
rec = RecordingHttp.new
|
|
85
|
+
api = Api.new('tok', http: rec)
|
|
86
|
+
api.chats(count: 25, marker: 3)
|
|
87
|
+
|
|
88
|
+
assert_equal({ count: 25, marker: 3 }, rec.gets.first[:query])
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def test_create_upload_posts_type
|
|
92
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
|
93
|
+
stub.post('/uploads') do |env|
|
|
94
|
+
assert_equal 'image', env.params['type']
|
|
95
|
+
[200, { 'Content-Type' => 'application/json' }, '{"url":"https://cdn.example/up"}']
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
conn = Faraday.new do |f|
|
|
100
|
+
f.adapter :test, stubs
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
http = Http.new('tok', 'https://platform-api.max.ru', connection: conn)
|
|
104
|
+
api = Api.new('tok', http: http)
|
|
105
|
+
|
|
106
|
+
result = api.create_upload(type: :image)
|
|
107
|
+
assert_equal 'https://cdn.example/up', result[:url]
|
|
108
|
+
stubs.verify_stubbed_calls
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def test_create_upload_rejects_unknown_type
|
|
112
|
+
api = Api.new('tok', http: RecordingHttp.new)
|
|
113
|
+
assert_raises(ArgumentError) { api.create_upload(type: :photo) }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_upload_file_raises_when_slot_has_no_url
|
|
117
|
+
api = Api.new('tok', http: RecordingHttp.new)
|
|
118
|
+
|
|
119
|
+
def api.create_upload(*)
|
|
120
|
+
{ token: 'only' }
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
err = assert_raises(ApiError) { api.upload_file(type: :image, path: __FILE__) }
|
|
124
|
+
assert_match(/url/i, err.message)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
module Max
|
|
6
|
+
module Bot
|
|
7
|
+
class ApiTest < Minitest::Test
|
|
8
|
+
def test_rejects_blank_token
|
|
9
|
+
assert_raises(ArgumentError) { Api.new(nil) }
|
|
10
|
+
assert_raises(ArgumentError) { Api.new(' ') }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_send_message_requires_recipient
|
|
14
|
+
api = Api.new('token')
|
|
15
|
+
err = assert_raises(ArgumentError) { api.send_message('hi') }
|
|
16
|
+
assert_match(/chat_id|user_id/, err.message)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_send_message_requires_payload
|
|
20
|
+
api = Api.new('token')
|
|
21
|
+
err = assert_raises(ArgumentError) { api.send_message(nil, chat_id: 1) }
|
|
22
|
+
assert_match(/text|attachments|attachment|link/, err.message)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
module Max
|
|
6
|
+
module Bot
|
|
7
|
+
class AttachmentsTest < Minitest::Test
|
|
8
|
+
def test_image_with_token
|
|
9
|
+
att = Attachments.image(token: 'abc')
|
|
10
|
+
assert_equal 'image', att[:type]
|
|
11
|
+
assert_equal({ token: 'abc' }, att[:payload])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_inline_keyboard_structure
|
|
15
|
+
rows = [
|
|
16
|
+
[
|
|
17
|
+
Attachments.callback_button('OK', 'payload-1', intent: 'positive'),
|
|
18
|
+
Attachments.link_button('Site', 'https://example.com')
|
|
19
|
+
]
|
|
20
|
+
]
|
|
21
|
+
att = Attachments.inline_keyboard(rows)
|
|
22
|
+
assert_equal 'inline_keyboard', att[:type]
|
|
23
|
+
assert_equal rows, att[:payload][:buttons]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_location_top_level_coordinates
|
|
27
|
+
att = Attachments.location(latitude: 55.75, longitude: 37.61)
|
|
28
|
+
assert_equal 'location', att[:type]
|
|
29
|
+
assert_in_delta 55.75, att[:latitude]
|
|
30
|
+
assert_in_delta 37.61, att[:longitude]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_share_payload
|
|
34
|
+
att = Attachments.share(url: 'https://example.com')
|
|
35
|
+
assert_equal 'share', att[:type]
|
|
36
|
+
assert_equal 'https://example.com', att[:payload][:url]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
module Max
|
|
6
|
+
module Bot
|
|
7
|
+
class ClientTest < Minitest::Test
|
|
8
|
+
class DummyApi
|
|
9
|
+
attr_reader :get_updates_calls
|
|
10
|
+
|
|
11
|
+
def initialize(responses)
|
|
12
|
+
@responses = responses.dup
|
|
13
|
+
@get_updates_calls = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def get_updates(**kwargs)
|
|
17
|
+
@get_updates_calls << kwargs
|
|
18
|
+
@responses.shift || { updates: [], marker: nil }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_initialize_accepts_injected_api
|
|
23
|
+
dummy = DummyApi.new([])
|
|
24
|
+
client = Client.new('token', api: dummy)
|
|
25
|
+
assert_same dummy, client.api
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_run_requires_block
|
|
29
|
+
client = Client.new('token', api: DummyApi.new([]))
|
|
30
|
+
err = assert_raises(ArgumentError) { client.run }
|
|
31
|
+
assert_match(/block/, err.message)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_class_run_requires_block
|
|
35
|
+
assert_raises(ArgumentError) { Client.run('token') }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_run_yields_updates_and_passes_marker_on_next_poll
|
|
39
|
+
responses = [
|
|
40
|
+
{ updates: [{ id: 1 }], marker: 10 },
|
|
41
|
+
{ updates: [{ id: 2 }], marker: 20 }
|
|
42
|
+
]
|
|
43
|
+
dummy = DummyApi.new(responses)
|
|
44
|
+
seen = []
|
|
45
|
+
client = Client.new('token', api: dummy, sleep: ->(_) {})
|
|
46
|
+
|
|
47
|
+
client.run do |u|
|
|
48
|
+
seen << u
|
|
49
|
+
raise StopIteration if seen.size >= 2
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
assert_equal 2, seen.size
|
|
53
|
+
assert_equal({ id: 1 }, seen[0])
|
|
54
|
+
assert_equal({ id: 2 }, seen[1])
|
|
55
|
+
assert_nil dummy.get_updates_calls[0][:marker]
|
|
56
|
+
assert_equal 10, dummy.get_updates_calls[1][:marker]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
module Max
|
|
6
|
+
module Bot
|
|
7
|
+
class ErrorsTest < Minitest::Test
|
|
8
|
+
def test_api_error_to_s_includes_message_field
|
|
9
|
+
err = ApiError.new('HTTP 400', status: 400, body: { message: 'bad request' })
|
|
10
|
+
assert_match(/HTTP 400/, err.to_s)
|
|
11
|
+
assert_match(/bad request/, err.to_s)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_api_error_attributes
|
|
15
|
+
err = ApiError.new('x', status: 404, body: { code: 1 })
|
|
16
|
+
assert_equal 404, err.status
|
|
17
|
+
assert_equal({ code: 1 }, err.body)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'faraday'
|
|
5
|
+
|
|
6
|
+
module Max
|
|
7
|
+
module Bot
|
|
8
|
+
class HttpTest < Minitest::Test
|
|
9
|
+
def test_get_parses_json
|
|
10
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
|
11
|
+
stub.get('/updates') { [200, { 'Content-Type' => 'application/json' }, '{"updates":[],"marker":null}'] }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
conn = Faraday.new do |f|
|
|
15
|
+
f.adapter :test, stubs
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
http = Http.new('secret-token', 'https://platform-api.max.ru', connection: conn)
|
|
19
|
+
result = http.get('/updates', query: {})
|
|
20
|
+
|
|
21
|
+
assert_equal [], result[:updates]
|
|
22
|
+
assert_nil result[:marker]
|
|
23
|
+
stubs.verify_stubbed_calls
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_post_sends_json_body_and_auth
|
|
27
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
|
28
|
+
stub.post('/messages', '{"text":"hi"}') do |env|
|
|
29
|
+
assert_equal 'secret-token', env.request_headers['Authorization']
|
|
30
|
+
assert_match %r{application/json}, env.request_headers['Content-Type']
|
|
31
|
+
[200, { 'Content-Type' => 'application/json' }, '{"message":{"body":{}}}']
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
conn = Faraday.new do |f|
|
|
36
|
+
f.adapter :test, stubs
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
http = Http.new('secret-token', 'https://platform-api.max.ru', connection: conn)
|
|
40
|
+
result = http.post('/messages', query: { chat_id: 1 }, body: { text: 'hi' })
|
|
41
|
+
|
|
42
|
+
assert result.key?(:message)
|
|
43
|
+
stubs.verify_stubbed_calls
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_raises_api_error_on_http_error
|
|
47
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
|
48
|
+
stub.get('/updates') { [401, {}, '{"message":"unauthorized"}'] }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
conn = Faraday.new do |f|
|
|
52
|
+
f.adapter :test, stubs
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
http = Http.new('bad', 'https://platform-api.max.ru', connection: conn)
|
|
56
|
+
|
|
57
|
+
err = assert_raises(ApiError) { http.get('/updates') }
|
|
58
|
+
assert_equal 401, err.status
|
|
59
|
+
assert_equal 'unauthorized', err.body[:message]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_delete_sends_query_and_auth
|
|
63
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
|
64
|
+
stub.delete('/subscriptions') do |env|
|
|
65
|
+
assert_equal 'tok', env.request_headers['Authorization']
|
|
66
|
+
assert_equal 'https://h', env.params['url']
|
|
67
|
+
[200, { 'Content-Type' => 'application/json' }, '{"success":true}']
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
conn = Faraday.new do |f|
|
|
72
|
+
f.adapter :test, stubs
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
http = Http.new('tok', 'https://platform-api.max.ru', connection: conn)
|
|
76
|
+
result = http.delete('/subscriptions', query: { url: 'https://h' })
|
|
77
|
+
assert_equal true, result[:success]
|
|
78
|
+
stubs.verify_stubbed_calls
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
module Max
|
|
6
|
+
module Bot
|
|
7
|
+
class JsonTest < Minitest::Test
|
|
8
|
+
FakeResponse = Struct.new(:status, :body) do
|
|
9
|
+
def success?
|
|
10
|
+
status >= 200 && status < 300
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_deep_symbolize_nested
|
|
15
|
+
input = { 'a' => 1, 'b' => [{ 'c' => 'd' }] }
|
|
16
|
+
out = Json.deep_symbolize(input)
|
|
17
|
+
|
|
18
|
+
assert_equal({ a: 1, b: [{ c: 'd' }] }, out)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_decode_response_success
|
|
22
|
+
r = FakeResponse.new(200, '{"a":1}')
|
|
23
|
+
assert_equal({ a: 1 }, Json.decode_response(r))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_decode_response_empty_body
|
|
27
|
+
r = FakeResponse.new(200, '')
|
|
28
|
+
assert_equal({}, Json.decode_response(r))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_decode_response_error_raises_api_error
|
|
32
|
+
r = FakeResponse.new(422, '{"message":"nope"}')
|
|
33
|
+
err = assert_raises(ApiError) { Json.decode_response(r) }
|
|
34
|
+
assert_equal 422, err.status
|
|
35
|
+
assert_equal 'nope', err.body[:message]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_decode_response_invalid_json
|
|
39
|
+
r = FakeResponse.new(200, '{')
|
|
40
|
+
assert_raises(ApiError) { Json.decode_response(r) }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
module Max
|
|
6
|
+
module Bot
|
|
7
|
+
class UpdateHelpersTest < Minitest::Test
|
|
8
|
+
def test_message_created_predicate
|
|
9
|
+
assert UpdateHelpers.message_created?(update_type: 'message_created')
|
|
10
|
+
refute UpdateHelpers.message_created?(update_type: 'other')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_message_text_from_body_hash
|
|
14
|
+
msg = { body: { text: 'hello' } }
|
|
15
|
+
assert_equal 'hello', UpdateHelpers.message_text(msg)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_message_destination_chat_id
|
|
19
|
+
msg = { recipient: { chat_id: -100 } }
|
|
20
|
+
assert_equal [:chat_id, -100], UpdateHelpers.message_destination(msg)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_message_destination_user_id_fallback
|
|
24
|
+
msg = { recipient: { user_id: 42 } }
|
|
25
|
+
assert_equal [:user_id, 42], UpdateHelpers.message_destination(msg)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
module Max
|
|
6
|
+
module Bot
|
|
7
|
+
class WebhookTest < Minitest::Test
|
|
8
|
+
def test_secret_valid_when_no_secret_configured
|
|
9
|
+
assert Webhook.secret_valid?('anything', nil)
|
|
10
|
+
assert Webhook.secret_valid?('anything', '')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_secret_valid_compares_constant_time
|
|
14
|
+
assert Webhook.secret_valid?('abc', 'abc')
|
|
15
|
+
refute Webhook.secret_valid?('abc', 'abd')
|
|
16
|
+
refute Webhook.secret_valid?('abc', 'ab')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_extract_secret_header_rack_style
|
|
20
|
+
env = { 'HTTP_X_MAX_BOT_API_SECRET' => 'sekret' }
|
|
21
|
+
assert_equal 'sekret', Webhook.extract_secret_header(env)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_parse_json_empty
|
|
25
|
+
assert_equal({}, Webhook.parse_json(nil))
|
|
26
|
+
assert_equal({}, Webhook.parse_json(''))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_parse_json_object
|
|
30
|
+
h = Webhook.parse_json('{"update_type":"message_created"}')
|
|
31
|
+
assert_equal 'message_created', h[:update_type]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
|
@@ -1,23 +1,113 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: max_bot
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sergey Syabrenko
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
-
dependencies:
|
|
13
|
-
|
|
11
|
+
date: 2026-04-12 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: faraday
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.0'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '3.0'
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '1.0'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3.0'
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: minitest
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '5.0'
|
|
40
|
+
- - "<"
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '7'
|
|
43
|
+
type: :development
|
|
44
|
+
prerelease: false
|
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '5.0'
|
|
50
|
+
- - "<"
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '7'
|
|
53
|
+
- !ruby/object:Gem::Dependency
|
|
54
|
+
name: rake
|
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '13.0'
|
|
60
|
+
- - "<"
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '15'
|
|
63
|
+
type: :development
|
|
64
|
+
prerelease: false
|
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - ">="
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '13.0'
|
|
70
|
+
- - "<"
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: '15'
|
|
73
|
+
description: Send messages, long-poll GET /updates, manage webhook subscriptions.
|
|
74
|
+
See https://dev.max.ru/docs-api
|
|
14
75
|
email: darthpains@gmail.com
|
|
15
76
|
executables: []
|
|
16
77
|
extensions: []
|
|
17
78
|
extra_rdoc_files: []
|
|
18
79
|
files:
|
|
80
|
+
- CHANGELOG.md
|
|
81
|
+
- LICENSE.txt
|
|
82
|
+
- README.md
|
|
83
|
+
- Rakefile
|
|
84
|
+
- examples/polling_bot.rb
|
|
85
|
+
- lib/max/bot.rb
|
|
86
|
+
- lib/max/bot/api.rb
|
|
87
|
+
- lib/max/bot/api/request_builders.rb
|
|
88
|
+
- lib/max/bot/attachments.rb
|
|
89
|
+
- lib/max/bot/client.rb
|
|
90
|
+
- lib/max/bot/configuration.rb
|
|
91
|
+
- lib/max/bot/errors.rb
|
|
92
|
+
- lib/max/bot/http.rb
|
|
93
|
+
- lib/max/bot/json.rb
|
|
94
|
+
- lib/max/bot/multipart_upload.rb
|
|
95
|
+
- lib/max/bot/update_helpers.rb
|
|
96
|
+
- lib/max/bot/version.rb
|
|
97
|
+
- lib/max/bot/webhook.rb
|
|
19
98
|
- lib/max_bot.rb
|
|
20
|
-
|
|
99
|
+
- test/max/bot/api/request_builders_test.rb
|
|
100
|
+
- test/max/bot/api_send_test.rb
|
|
101
|
+
- test/max/bot/api_test.rb
|
|
102
|
+
- test/max/bot/attachments_test.rb
|
|
103
|
+
- test/max/bot/client_test.rb
|
|
104
|
+
- test/max/bot/errors_test.rb
|
|
105
|
+
- test/max/bot/http_test.rb
|
|
106
|
+
- test/max/bot/json_test.rb
|
|
107
|
+
- test/max/bot/update_helpers_test.rb
|
|
108
|
+
- test/max/bot/webhook_test.rb
|
|
109
|
+
- test/test_helper.rb
|
|
110
|
+
homepage: https://github.com/Syabr/max_bot
|
|
21
111
|
licenses:
|
|
22
112
|
- MIT
|
|
23
113
|
metadata: {}
|
|
@@ -39,5 +129,5 @@ requirements: []
|
|
|
39
129
|
rubygems_version: 3.5.22
|
|
40
130
|
signing_key:
|
|
41
131
|
specification_version: 4
|
|
42
|
-
summary:
|
|
132
|
+
summary: Ruby client for the MAX messenger Bot API
|
|
43
133
|
test_files: []
|