mashery_rails 0.6.2
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.
- data/.gitignore +6 -0
- data/.travis.yml +12 -0
- data/.yardoc/checksums +17 -0
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -0
- data/Gemfile +21 -0
- data/Gemfile.devtools +55 -0
- data/Gemfile.lock +215 -0
- data/LICENSE.txt +21 -0
- data/README.md +63 -0
- data/Rakefile +9 -0
- data/VERSION +1 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +103 -0
- data/config/rubocop.yml +58 -0
- data/config/yardstick.yml +2 -0
- data/lib/mashery.rb +55 -0
- data/lib/mashery/config.rb +71 -0
- data/lib/mashery/exceptions.rb +46 -0
- data/lib/mashery/key.rb +7 -0
- data/lib/mashery/local.rb +3 -0
- data/lib/mashery/member.rb +8 -0
- data/lib/mashery/query_builder.rb +173 -0
- data/lib/mashery/rails.rb +19 -0
- data/lib/mashery/rest_client.rb +31 -0
- data/lib/mashery/rest_client/query.rb +77 -0
- data/lib/mashery/rpc_client.rb +58 -0
- data/lib/mashery/rpc_client/base.rb +51 -0
- data/lib/mashery/rpc_client/response.rb +79 -0
- data/lib/mashery/service.rb +9 -0
- data/masheri.gemspec +26 -0
- data/mashery_rails.gemspec +25 -0
- data/spec/fixtures/config.no_host.yml +4 -0
- data/spec/fixtures/config.no_key.yml +4 -0
- data/spec/fixtures/config.no_secret.yml +4 -0
- data/spec/fixtures/config.no_site_id.yml +4 -0
- data/spec/fixtures/config.yml +5 -0
- data/spec/fixtures/services.json +3 -0
- data/spec/mashery/config_spec.rb +38 -0
- data/spec/mashery/member_spec.rb +47 -0
- data/spec/mashery/query_builder_spec.rb +13 -0
- data/spec/mashery/rest_client_spec.rb +47 -0
- data/spec/mashery/rpc_client_spec.rb +28 -0
- data/spec/mashery/service_spec.rb +101 -0
- data/spec/mashery_spec.rb +5 -0
- data/spec/spec_helper.rb +50 -0
- data/tasks/mashery.thor +200 -0
- metadata +147 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mashery::Member do
|
4
|
+
let(:url) { Mashery.rpc.url }
|
5
|
+
|
6
|
+
let(:items) {
|
7
|
+
[{"name" => "Name"}] * 10
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:params) {
|
11
|
+
{
|
12
|
+
'method' => "object.query",
|
13
|
+
'params' => [query],
|
14
|
+
'id' => 1
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:headers) {
|
19
|
+
{
|
20
|
+
"Content-Type" => "application/json",
|
21
|
+
"Accept" => "text/plain",
|
22
|
+
"Content-Length" => params.size
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
let(:json) {
|
27
|
+
{
|
28
|
+
"result" => {
|
29
|
+
"items" => items
|
30
|
+
}
|
31
|
+
}.to_json
|
32
|
+
}
|
33
|
+
|
34
|
+
|
35
|
+
context "with standard query" do
|
36
|
+
let(:query) {
|
37
|
+
"SELECT * FROM members ITEMS 100"
|
38
|
+
}
|
39
|
+
|
40
|
+
it "should grab all the members" do
|
41
|
+
::RestClient.should_receive(:post).with(url, params.to_json, headers).and_return(json)
|
42
|
+
objects = Mashery::Member.all
|
43
|
+
objects.length.should == 10
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mashery::QueryBuilder do
|
4
|
+
it "should build a simple query" do
|
5
|
+
builder = Mashery::QueryBuilder.new
|
6
|
+
builder.from("members").to_s.should == "SELECT * FROM members"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should build a query with pagination" do
|
10
|
+
builder = Mashery::QueryBuilder.new
|
11
|
+
builder.from("members").page(25).items(100).to_s.should == "SELECT * FROM members PAGE 25 ITEMS 100"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mashery::RestClient do
|
4
|
+
let(:service_key) do
|
5
|
+
"12345"
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:url) do
|
9
|
+
Mashery::RestClient::Query.new(query_params).url
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:query_params) do
|
13
|
+
{service_id: service_key}.merge(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
context "reasonable date range" do
|
18
|
+
let(:options) do
|
19
|
+
{
|
20
|
+
start_date: 1.day.ago,
|
21
|
+
end_date: 0.days.ago,
|
22
|
+
resource: "developer_activity"
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should request the service data, given a service key" do
|
27
|
+
::RestClient.should_receive(:get).with(url).and_return("whatever")
|
28
|
+
Mashery.activity("developer_activity", service_key, options).should == "whatever"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "invalid date range" do
|
33
|
+
let(:options) do
|
34
|
+
{
|
35
|
+
start_date: 8.day.ago,
|
36
|
+
end_date: 0.days.ago,
|
37
|
+
resource: "developer_activity"
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should raise an InvalidDateRange error" do
|
42
|
+
expect do
|
43
|
+
Mashery.activity("developer_activity", service_key, options)
|
44
|
+
end.to raise_error(Mashery::InvalidDateRange)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mashery::RpcClient do
|
4
|
+
let(:query) {
|
5
|
+
"SELECT * FROM whatevers"
|
6
|
+
}
|
7
|
+
|
8
|
+
let(:params) {
|
9
|
+
{
|
10
|
+
'method' => "object.query",
|
11
|
+
'params' => [query],
|
12
|
+
'id' => 1
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
let(:headers) {
|
17
|
+
{
|
18
|
+
"Content-Type" => "application/json",
|
19
|
+
"Accept" => "text/plain",
|
20
|
+
"Content-Length" => params.size
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
it "should post to RpcClient with the proper arguments" do
|
25
|
+
::RestClient.should_receive(:post).with(Mashery.rpc.url, params.to_json, headers).and_return({hello: 'world'}.to_json)
|
26
|
+
Mashery.rpc.query(query)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mashery::Service do
|
4
|
+
let(:url) { Mashery.rpc.url }
|
5
|
+
|
6
|
+
let(:items) {
|
7
|
+
[{"name" => "Name"}] * 10
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:params) {
|
11
|
+
{
|
12
|
+
'method' => "object.query",
|
13
|
+
'params' => [query],
|
14
|
+
'id' => 1
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:headers) {
|
19
|
+
{
|
20
|
+
"Content-Type" => "application/json",
|
21
|
+
"Accept" => "text/plain",
|
22
|
+
"Content-Length" => params.size
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
let(:json) {
|
27
|
+
{
|
28
|
+
"result" => {
|
29
|
+
"items" => items
|
30
|
+
}
|
31
|
+
}.to_json
|
32
|
+
}
|
33
|
+
|
34
|
+
context "with standard query" do
|
35
|
+
let(:query) { "SELECT * FROM services ITEMS 100" }
|
36
|
+
|
37
|
+
it "should grab all the services" do
|
38
|
+
::RestClient.should_receive(:post).with(url, params.to_json, headers).and_return(json)
|
39
|
+
objects = Mashery::Service.all
|
40
|
+
objects.length.should == 10
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "with pagination query" do
|
45
|
+
let(:query) { "SELECT * FROM services PAGE 3 ITEMS 100"}
|
46
|
+
|
47
|
+
it "should grab the 3rd page of services" do
|
48
|
+
::RestClient.should_receive(:post).with(url, params.to_json, headers).and_return(json)
|
49
|
+
objects = Mashery::Service.page(3).all
|
50
|
+
objects.length.should == 10
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "with auto-pagination via find_each" do
|
55
|
+
let(:total_pages) { 5 }
|
56
|
+
|
57
|
+
def query(page)
|
58
|
+
if page == 1
|
59
|
+
"SELECT * FROM services ITEMS 100"
|
60
|
+
else
|
61
|
+
"SELECT * FROM services PAGE #{page} ITEMS 100"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def params(page)
|
66
|
+
{
|
67
|
+
'method' => "object.query",
|
68
|
+
'params' => [query(page)],
|
69
|
+
'id' => 1
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def json(page)
|
74
|
+
{
|
75
|
+
"result" => {
|
76
|
+
"total_pages" => total_pages,
|
77
|
+
"current_page" => page,
|
78
|
+
"items" => items
|
79
|
+
}
|
80
|
+
}.to_json
|
81
|
+
end
|
82
|
+
|
83
|
+
def headers(page)
|
84
|
+
{
|
85
|
+
"Content-Type" => "application/json",
|
86
|
+
"Accept" => "text/plain",
|
87
|
+
"Content-Length" => params(page).size
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should invoke a new query for each page" do
|
92
|
+
(1..total_pages).each do |n|
|
93
|
+
::RestClient.should_receive(:post).with(url, params(n).to_json, headers(n)).and_return(json(n))
|
94
|
+
end
|
95
|
+
|
96
|
+
Mashery::Service.find_each do |entry|
|
97
|
+
entry.should be_a(Mashery::Service)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'simplecov'
|
3
|
+
|
4
|
+
SimpleCov.start
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift File.expand_path("./lib")
|
7
|
+
require 'mashery'
|
8
|
+
|
9
|
+
Bundler.require(:test)
|
10
|
+
|
11
|
+
require 'coveralls'
|
12
|
+
Coveralls.wear!
|
13
|
+
|
14
|
+
RSpec.configure do |config|
|
15
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
16
|
+
config.run_all_when_everything_filtered = true
|
17
|
+
config.filter_run :focus
|
18
|
+
|
19
|
+
# Run specs in random order to surface order dependencies. If you find an
|
20
|
+
# order dependency and want to debug it, you can fix the order by providing
|
21
|
+
# the seed, which is printed after each run.
|
22
|
+
# --seed 1234
|
23
|
+
config.order = 'random'
|
24
|
+
|
25
|
+
config.before do
|
26
|
+
Timecop.freeze Time.now
|
27
|
+
end
|
28
|
+
|
29
|
+
config.before do
|
30
|
+
config = double("config")
|
31
|
+
|
32
|
+
key = "regular_key"
|
33
|
+
secret = "super_long_secret"
|
34
|
+
signature = Digest::MD5.hexdigest(key + secret + Time.now.to_f.to_i.to_s)
|
35
|
+
|
36
|
+
config.stub({
|
37
|
+
site_id: "987",
|
38
|
+
key: key,
|
39
|
+
secret: secret,
|
40
|
+
signature: signature,
|
41
|
+
host: "masheri.example.com",
|
42
|
+
})
|
43
|
+
|
44
|
+
Mashery.config = config
|
45
|
+
end
|
46
|
+
|
47
|
+
config.after do
|
48
|
+
Timecop.return
|
49
|
+
end
|
50
|
+
end
|
data/tasks/mashery.thor
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
Bundler.setup
|
4
|
+
|
5
|
+
# XXX: only do this when the task has not been installed
|
6
|
+
$: << 'lib'
|
7
|
+
|
8
|
+
require 'mashery'
|
9
|
+
|
10
|
+
module Mashery
|
11
|
+
class CLI < Thor
|
12
|
+
namespace :mashery
|
13
|
+
|
14
|
+
desc "echo VALUE", "Echo the provided value (tests connectivity and authentication)"
|
15
|
+
def echo(value)
|
16
|
+
run { ok(::Mashery.client.echo(value)) }
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
def run(&block)
|
21
|
+
site_id = ENV['MASHERY_SITE_ID'] or
|
22
|
+
raise Exception, "Please set the MASHERY_SITE_ID environment variable."
|
23
|
+
key = ENV['MASHERY_API_KEY'] or
|
24
|
+
raise Exception, "Please set the MASHERY_API_KEY environment variable."
|
25
|
+
secret = ENV['MASHERY_SHARED_SECRET'] or
|
26
|
+
raise Exception, "Please set the MASHERY_SHARED_SECRET environment variable."
|
27
|
+
::Mashery.test_mode = ENV['MASHERY_PRODUCTION_MODE'].blank?
|
28
|
+
::Mashery.logger.level = Logger::DEBUG
|
29
|
+
::Mashery.client = ::Mashery::Client.new(site_id, key, secret)
|
30
|
+
begin
|
31
|
+
yield
|
32
|
+
rescue ::Mashery::HttpException => e
|
33
|
+
error("HTTP error: #{e.message}")
|
34
|
+
rescue ::Mashery::JsonRpcException => e
|
35
|
+
error(e.message)
|
36
|
+
rescue ::Mashery::ValidationException => e
|
37
|
+
e.errors.each {|err| warn("#{err['field']}: #{err['message']}")}
|
38
|
+
error("Unable to execute method due to validation errors")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def warn(msg)
|
43
|
+
say_status :WARN, msg, :yellow
|
44
|
+
end
|
45
|
+
|
46
|
+
def ok(msg)
|
47
|
+
say_status :OK, msg
|
48
|
+
end
|
49
|
+
|
50
|
+
def error(msg)
|
51
|
+
say_status :ERROR, msg, :red
|
52
|
+
end
|
53
|
+
|
54
|
+
def debug(msg)
|
55
|
+
say_status :DEBUG, msg, :cyan
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class MemberCLI < CLI
|
60
|
+
namespace 'mashery:member'
|
61
|
+
|
62
|
+
desc "create USERNAME DISPLAY_NAME EMAIL [--fields ...]", "Create a member"
|
63
|
+
method_option :fields, :type => :hash
|
64
|
+
def create(username, display_name, email)
|
65
|
+
run do
|
66
|
+
begin
|
67
|
+
member = ::Mashery::Member.create(username, display_name, email, options[:fields])
|
68
|
+
ok("Member #{member.username} created")
|
69
|
+
rescue ::Mashery::DuplicateObjectException
|
70
|
+
error("The username #{username} has already been claimed")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
desc "fetch USERNAME", "Fetch a member"
|
76
|
+
def fetch(username)
|
77
|
+
run do
|
78
|
+
member = ::Mashery::Member.fetch(username)
|
79
|
+
if member
|
80
|
+
ok("Member #{username} found")
|
81
|
+
say(member.to_yaml)
|
82
|
+
else
|
83
|
+
warn("Member #{username} not found")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
desc "addrole USERNAME ROLE_ID", "Assign a role to a member"
|
89
|
+
def addrole(username, role_id)
|
90
|
+
run do
|
91
|
+
member = ::Mashery::Member.fetch(username)
|
92
|
+
if member
|
93
|
+
role = ::Mashery::Role.fetch(role_id.to_i)
|
94
|
+
if role
|
95
|
+
member.add_role(role)
|
96
|
+
ok("Role #{role.name} assigned to member #{username}")
|
97
|
+
else
|
98
|
+
warn("Role #{role_id} not found")
|
99
|
+
end
|
100
|
+
else
|
101
|
+
warn("Member #{username} not found")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
desc "rmrole USERNAME ROLE_ID", "Revoke a role from a member"
|
107
|
+
def rmrole(username, role_id)
|
108
|
+
run do
|
109
|
+
member = ::Mashery::Member.fetch(username)
|
110
|
+
if member
|
111
|
+
role = ::Mashery::Role.fetch(role_id.to_i)
|
112
|
+
if role
|
113
|
+
member.remove_role(role)
|
114
|
+
ok("Role #{role.name} revoked from member #{username}")
|
115
|
+
else
|
116
|
+
warn("Role #{role_id} not found")
|
117
|
+
end
|
118
|
+
else
|
119
|
+
warn("Member #{username} not found")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
desc "delete USERNAME", "Delete a member"
|
125
|
+
def delete(username)
|
126
|
+
run do
|
127
|
+
::Mashery::Member.delete(username)
|
128
|
+
ok("Member #{username} deleted")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class KeyCLI < CLI
|
134
|
+
namespace 'mashery:key'
|
135
|
+
|
136
|
+
desc "create SERVICE_KEY USERNAME [--fields ...]", "Create a key"
|
137
|
+
method_option :fields, :type => :hash
|
138
|
+
def create(service_key, username)
|
139
|
+
run do
|
140
|
+
key = ::Mashery::Key.create(service_key, username, options[:fields])
|
141
|
+
ok("Key #{key.id} created for member #{username} and service #{service_key}")
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
desc "fetch ID", "Fetch a key"
|
146
|
+
def fetch(id)
|
147
|
+
run do
|
148
|
+
key = ::Mashery::Key.fetch(id.to_i)
|
149
|
+
if key
|
150
|
+
ok("Key #{id} found")
|
151
|
+
say(key.to_yaml)
|
152
|
+
else
|
153
|
+
warn("Key #{id} not found")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
desc "delete ID", "Delete a key"
|
159
|
+
def delete(id)
|
160
|
+
run do
|
161
|
+
::Mashery::Key.delete(id.to_i)
|
162
|
+
ok("Key #{id} deleted")
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class RoleCLI < CLI
|
168
|
+
namespace 'mashery:role'
|
169
|
+
|
170
|
+
desc "create NAME [--fields ...]", "Create a role"
|
171
|
+
method_option :fields, :type => :hash
|
172
|
+
def create(name)
|
173
|
+
run do
|
174
|
+
role = ::Mashery::Role.create(name, options[:fields])
|
175
|
+
ok("Role #{role.id} created with name #{name}")
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
desc "fetch ID", "Fetch a role"
|
180
|
+
def fetch(id)
|
181
|
+
run do
|
182
|
+
role = ::Mashery::Role.fetch(id.to_i)
|
183
|
+
if role
|
184
|
+
ok("Role #{id} found")
|
185
|
+
say(role.to_yaml)
|
186
|
+
else
|
187
|
+
warn("Role #{id} not found")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
desc "delete ID", "Delete a role"
|
193
|
+
def delete(id)
|
194
|
+
run do
|
195
|
+
::Mashery::Role.delete(id.to_i)
|
196
|
+
ok("Role #{id} deleted")
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|