mashery_rails 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|