cdnetworks-client 1.0.0 → 1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6bd4a440e05f7d4b6ef2660939e4bafbb0240170
4
+ data.tar.gz: 1420de6d854c4480b60253d76bf3dd74713bc5f8
5
+ SHA512:
6
+ metadata.gz: 028b8c3c57295fac38fd27b6c06646e49b4c4c5a17f919df5777ad7a4e506a7a87907dd9ea47d06a41be93b6b65cb8f4488561a4890a4f417e538667290d6272
7
+ data.tar.gz: d8b48ae6f09eba38d32c1b3dd422f2583d33cf0695053863e692b0b9644226329efc2627052073b2586657a98c397ead590b02abc89204039221b79795d418c6
data/LICENSE CHANGED
@@ -186,7 +186,7 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright [yyyy] [name of copyright owner]
189
+ Copyright [2013] [Blue Box, Inc., Nell Shamrell]
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -4,6 +4,7 @@ The Cdnetworks Client is a simple wrapper for three [Cdnetworks](http://www.cdne
4
4
  * Config Open API v1.0
5
5
  * Cache Purge Open API v2.0 (older cache flushing API)
6
6
  * Cache Flush Open API v2.3.2 (most current cache flushing API)
7
+ * Statistics Open API v2
7
8
 
8
9
  This gem allows a user to call methods from either of these APIs using the same syntax.
9
10
 
@@ -1,56 +1,114 @@
1
+ require "json"
2
+
3
+ require_relative "patches"
4
+
1
5
  require "cdnetworks-client/version"
2
6
  require "cdnetworks-client/cache_purge_api"
3
7
  require "cdnetworks-client/config_open_api"
4
8
  require "cdnetworks-client/cache_flush_open_api"
9
+ require "cdnetworks-client/open_api_error"
10
+ require "cdnetworks-client/auth_open_api"
11
+ require "cdnetworks-client/open_api_keys"
12
+ require "cdnetworks-client/statistics_open_api"
5
13
 
6
14
  class CdnetworksClient
7
15
  include ConfigOpenApi
8
16
  include CachePurgeApi
9
17
  include CacheFlushOpenApi
18
+ include StatisticsOpenApi
19
+ attr_accessor :user, :password, :location
10
20
 
21
+ MAX_SESSION_RETRIES = 2
11
22
 
12
23
  def initialize(credentials={})
13
- @user = credentials[:user]
14
- @password = credentials[:pass]
15
- @location = credentials[:location]
24
+ self.user = credentials[:user]
25
+ self.password = credentials[:pass]
26
+ self.location = credentials[:location]
16
27
  end
17
28
 
18
29
  def compose_request(path,options)
19
- request = Net::HTTP::Post.new("#{base_url(@location)}#{path}")
30
+ request = Net::HTTP::Post.new("#{base_url(location)}#{path}")
20
31
  request.set_form_data(options)
21
32
  request
22
33
  end
23
34
 
24
- def call(path,options)
25
- begin
26
- response = http.request(compose_request(path,options))
35
+ def call(path,options,session_retries=0)
36
+ response = http.request(compose_request(path,options))
37
+
38
+ if location == "Beta"
39
+ process_beta_response(path, options, response, session_retries)
40
+ else
27
41
  response_hash = { code: response.code, body: response.body }
28
- rescue StandardError=>e
29
- "An error has occurred connecting to the CDNetworks API (#{e})"
30
42
  end
31
43
  end
32
44
 
33
45
  private
34
46
 
35
- def base_url(location=nil)
47
+ def base_url(loc=nil)
36
48
  case
37
- when location == "Korea"
49
+ when loc == "Korea"
38
50
  "https://openapi.kr.cdnetworks.com"
39
- when location == "Japan"
51
+ when loc == "Japan"
40
52
  "https://openapi.jp.cdnetworks.com"
41
- when location == "China"
53
+ when loc == "China"
42
54
  "https://openapi.txnetworks.cn"
55
+ when loc == "Beta"
56
+ "https://openapi-beta.cdnetworks.com"
43
57
  else
44
58
  "https://openapi.us.cdnetworks.com"
45
59
  end
46
60
  end
47
61
 
62
+ def process_beta_response(path, options, response, session_retries)
63
+ if expired_session_response?(response)
64
+ if session_retries <= MAX_SESSION_RETRIES
65
+ new_session_token = get_session_token(true)
66
+ options[:sessionToken] = new_session_token
67
+ return call(path, options, session_retries + 1)
68
+ else
69
+ raise OpenApiError::CriticalApiError.new("Session expired and failed to be re-established after #{session_retries} tries")
70
+ end
71
+ end
72
+
73
+ begin
74
+ data = JSON.parse(response.body)
75
+
76
+ result_code = data.values.first['resultCode'] || data.values.first['returnCode']
77
+
78
+ if !%w{0 200 404}.include?(result_code.to_s)
79
+ OpenApiError::ErrorHandler.handle_error_response(result_code, response.body)
80
+ else
81
+ {code: result_code, body: data}
82
+ end
83
+ rescue JSON::ParserError
84
+ raise OpenApiError::CriticalApiError.new("Unparseable body: #{response.body}")
85
+ end
86
+ end
87
+
48
88
  def http
49
- uri = URI.parse(base_url)
89
+ uri = URI.parse(base_url(location))
50
90
 
51
91
  http = Net::HTTP.new(uri.host, uri.port)
52
92
  http.use_ssl = true
53
93
 
54
94
  http
55
95
  end
96
+
97
+ def expired_session_response?(response)
98
+ if response.code.to_s == "200"
99
+ begin
100
+ parsed = JSON.parse(response.body.to_s)
101
+ if parsed.values.first
102
+ parsed.values.first['returnCode'] == 102 ||
103
+ parsed.values.first['resultCode'] == 102
104
+ else
105
+ false
106
+ end
107
+ rescue JSON::ParserError
108
+ false
109
+ end
110
+ else
111
+ false
112
+ end
113
+ end
56
114
  end
@@ -0,0 +1,56 @@
1
+ module AuthOpenApi
2
+ LOGIN_URL = "/api/rest/login"
3
+ LOGOUT_URL = "/api/rest/logout"
4
+
5
+ class AuthSession
6
+ def raise_handled_error(code, desc)
7
+ raise OpenApiError::ApiError.new("Auth error: #{code} - #{desc}")
8
+ end
9
+
10
+ def initialize(user, pass, client)
11
+ @user = user
12
+ @pass = pass
13
+ @client = client
14
+ end
15
+
16
+ def session
17
+ @session ||= login
18
+ end
19
+
20
+ def login
21
+ params = {
22
+ user: @user,
23
+ pass: @pass,
24
+ output: "json"
25
+ }
26
+ resp = @client.call(LOGIN_URL, params)
27
+
28
+ resp[:body]['loginResponse']['session']
29
+ end
30
+
31
+ def logout
32
+ params = {
33
+ user: @user,
34
+ pass: @pass,
35
+ output: "json"
36
+ }
37
+
38
+ resp = @client.call(LOGOUT_URL, params)
39
+ resp[:body]['logoutResponse']
40
+ end
41
+ end
42
+
43
+ def get_session_token(reset_session = false, keynum = 0)
44
+ if !@auth_session || reset_session
45
+ @auth_session = AuthSession.new(@user, @password, self)
46
+ end
47
+
48
+ session = Array.wrap(@auth_session.session)[keynum]
49
+
50
+ if session.is_a?(Hash)
51
+ session['sessionToken']
52
+ else
53
+ nil
54
+ end
55
+ end
56
+ end
@@ -1,7 +1,11 @@
1
1
  module ConfigOpenApi
2
-
3
2
  def list(options={})
4
- call(config_open_path("list"),add_config_credentials(options))
3
+ response = call(config_open_path("list"), add_config_credentials(options))
4
+ if location == "Beta"
5
+ response[:body]["PadConfigResponse"]["data"]["data"]
6
+ else
7
+ response
8
+ end
5
9
  end
6
10
 
7
11
  def view(options={})
@@ -17,12 +21,25 @@ module ConfigOpenApi
17
21
  end
18
22
 
19
23
  def config_open_path(command)
20
- "/config/rest/pan/site/#{command}"
24
+ if location == "Beta"
25
+ "/api/rest/pan/site/#{command}"
26
+ else
27
+ "/config/rest/pan/site/#{command}"
28
+ end
21
29
  end
22
30
 
23
31
  def add_config_credentials(options)
24
- options[:user] = @user
25
- options[:pass] = @password
32
+ if location == "Beta"
33
+ session_token = get_session_token
34
+ keys = get_api_key_list(session_token)
35
+ api_key = keys.find{|k| k["type"] == 0}["apiKey"]
36
+
37
+ options[:sessionToken] = session_token
38
+ options[:apiKey] = api_key
39
+ else
40
+ options[:user] = @user
41
+ options[:pass] = @password
42
+ end
26
43
 
27
44
  options
28
45
  end
@@ -0,0 +1,31 @@
1
+ module OpenApiError
2
+ ERROR_CODES = {
3
+ "101" => "User login information error",
4
+ "102" => "Invalid session",
5
+ "103" => "Logout failure",
6
+ "104" => "Input parameter error (no entry is made or invalid value)",
7
+ "202" => "Inaccessible menu (Setting can be modified via Customer Portal)",
8
+ "203" => "Inaccessible service (Setting can be modified via Customer Portal)",
9
+ "204" => "Inaccessible Request (See Table-1. The Scope of CDNetworks Statistics Open API)",
10
+ "301" => "Unregistered API key (Registration information is provided in Customer Portal)",
11
+ "999" => "Temporary error"
12
+ }
13
+
14
+ class ApiError < StandardError
15
+
16
+ end
17
+
18
+ class CriticalApiError < StandardError
19
+
20
+ end
21
+
22
+ class ErrorHandler
23
+ def self.handle_error_response(code, body)
24
+ if desc = ERROR_CODES[code.to_s]
25
+ raise ApiError.new("Open API Error #{code}: #{desc}")
26
+ else
27
+ raise ApiError.new("Unknown Open API Response Code #{code} (body: #{body})")
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ module OpenApiKeys
2
+ GET_KEY_PATH = "/api/rest/getApiKeyList"
3
+
4
+ def get_api_key_list(session_token)
5
+ params = {
6
+ output: "json",
7
+ sessionToken: session_token
8
+ }
9
+ uri = URI("#{base_url(@location)}/#{GET_KEY_PATH}")
10
+ uri.query = URI.encode_www_form(params)
11
+
12
+ response = call(GET_KEY_PATH, params)
13
+
14
+ response[:body]['apiKeyInfo']['apiKeyInfoItem']
15
+ end
16
+
17
+ def get_api_key(session_token, service_name)
18
+
19
+ key_for_service = (get_api_key_list(session_token) || []).find do |service|
20
+ service['serviceName'] == service_name
21
+ end
22
+
23
+ unless key_for_service
24
+ raise "No key found for #{service_name}"
25
+ end
26
+
27
+ return key_for_service['apiKey']
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ module StatisticsOpenApi
2
+ include AuthOpenApi
3
+ include OpenApiKeys
4
+
5
+ BANDWIDTH_PATH = "/api/rest/traffic/edge"
6
+
7
+ def bandwidth_usage(service_name, from, to, time_interval = 2)
8
+ session_token = get_session_token
9
+
10
+ api_key = get_api_key(session_token, service_name)
11
+
12
+ opts = {
13
+ sessionToken: session_token,
14
+ apiKey: api_key,
15
+ fromDate: from.strftime("%Y%m%d"),
16
+ toDate: to.strftime("%Y%m%d"),
17
+ timeInterval: time_interval,
18
+ output: "json"
19
+ }
20
+
21
+ response = call(BANDWIDTH_PATH, opts)
22
+
23
+ if response[:code].to_s == "404"
24
+ nil
25
+ else
26
+ Array.wrap(response[:body]['trafficResponse']['trafficItem']).map{|i| i['dataTransferred']}.inject(&:+)
27
+ end
28
+ end
29
+ end
@@ -1,5 +1,5 @@
1
1
  module Cdnetworks
2
2
  module Client
3
- VERSION = "1.0.0"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
data/lib/patches.rb ADDED
@@ -0,0 +1,11 @@
1
+ class Array
2
+ def self.wrap(object)
3
+ if object.nil?
4
+ []
5
+ elsif object.respond_to?(:to_ary)
6
+ object.to_ary || [object]
7
+ else
8
+ [object]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe CdnetworksClient do
4
+ before(:all) do
5
+ @user = ENV['CDN_USER']
6
+ @pass = ENV['CDN_PASS']
7
+
8
+ unless @user && @pass
9
+ skip "either CDN_USER or CDN_PASS env var not set. skipping"
10
+ end
11
+
12
+ WebMock.allow_net_connect!
13
+
14
+ @client = CdnetworksClient.new(user: @user, pass: @pass, location: "Beta")
15
+ end
16
+
17
+ after(:all) do
18
+ WebMock.disable_net_connect!
19
+ end
20
+
21
+ it 'gets a session' do
22
+ expect(@client.get_session_token).not_to be_nil
23
+ end
24
+
25
+ it 'gets bandwidth usage' do
26
+ pad = ENV['CDN_PAD']
27
+ skip "must set CDN_PAD env var" unless pad
28
+ usage = @client.bandwidth_usage(pad, Date.today - 2, Date.today - 1)
29
+ expect(usage).to be > 0
30
+ end
31
+
32
+ it 'lists pads for a session' do
33
+ pads = @client.list
34
+
35
+ expect(pads.length).to be > 0
36
+ end
37
+ end
@@ -21,25 +21,25 @@ describe CdnetworksClient do
21
21
  it "calls the list method of the cdnetworks api" do
22
22
  @cdn_api.list
23
23
 
24
- a_request(:post, "#{@url}/config/rest/pan/site/list").
24
+ expect(a_request(:post, "#{@url}/config/rest/pan/site/list").
25
25
  with(:body => 'user=user%40user.com&pass=secret',
26
26
  :headers => {
27
27
  'Accept' =>'*/*',
28
28
  'Content-Type'=>'application/x-www-form-urlencoded',
29
- 'User-Agent' =>'Ruby'}).
30
- should have_been_made
29
+ 'User-Agent' =>'Ruby'})).
30
+ to have_been_made
31
31
  end
32
32
 
33
33
  it "includes options passed as a hash" do
34
34
  @cdn_api.list(:prod => true)
35
35
 
36
- a_request(:post, "#{@url}/config/rest/pan/site/list").
36
+ expect(a_request(:post, "#{@url}/config/rest/pan/site/list").
37
37
  with(:body => 'prod=true&user=user%40user.com&pass=secret',
38
38
  :headers => {
39
39
  'Accept' =>'*/*',
40
40
  'Content-Type'=>'application/x-www-form-urlencoded',
41
- 'User-Agent' =>'Ruby'}).
42
- should have_been_made
41
+ 'User-Agent' =>'Ruby'})).
42
+ to have_been_made
43
43
  end
44
44
  end
45
45
 
@@ -52,25 +52,25 @@ describe CdnetworksClient do
52
52
  it "calls the view method of the cdnetworks api" do
53
53
  @cdn_api.view
54
54
 
55
- a_request(:post, "#{@url}/config/rest/pan/site/view").
55
+ expect(a_request(:post, "#{@url}/config/rest/pan/site/view").
56
56
  with(:body => 'user=user%40user.com&pass=secret',
57
57
  :headers => {
58
58
  'Accept' =>'*/*',
59
59
  'Content-Type'=>'application/x-www-form-urlencoded',
60
- 'User-Agent' =>'Ruby'}).
61
- should have_been_made
60
+ 'User-Agent' =>'Ruby'})).
61
+ to have_been_made
62
62
  end
63
63
 
64
64
  it "includes options passed as a hash" do
65
65
  @cdn_api.view(:pad => "cache.foo.com")
66
66
 
67
- a_request(:post, "#{@url}/config/rest/pan/site/view").
67
+ expect(a_request(:post, "#{@url}/config/rest/pan/site/view").
68
68
  with(:body => 'pad=cache.foo.com&user=user%40user.com&pass=secret',
69
69
  :headers => {
70
70
  'Accept' =>'*/*',
71
71
  'Content-Type'=>'application/x-www-form-urlencoded',
72
- 'User-Agent' =>'Ruby'}).
73
- should have_been_made
72
+ 'User-Agent' =>'Ruby'})).
73
+ to have_been_made
74
74
  end
75
75
 
76
76
  end
@@ -84,25 +84,25 @@ describe CdnetworksClient do
84
84
  it "calls the add method of the cdnetworks api" do
85
85
  @cdn_api.add
86
86
 
87
- a_request(:post, "#{@url}/config/rest/pan/site/add").
87
+ expect(a_request(:post, "#{@url}/config/rest/pan/site/add").
88
88
  with(:body => 'user=user%40user.com&pass=secret',
89
89
  :headers => {
90
90
  'Accept' =>'*/*',
91
91
  'Content-Type'=>'application/x-www-form-urlencoded',
92
- 'User-Agent' =>'Ruby'}).
93
- should have_been_made
92
+ 'User-Agent' =>'Ruby'})).
93
+ to have_been_made
94
94
  end
95
95
 
96
96
  it "includes options passed as a hash" do
97
97
  @cdn_api.add(:pad => "cache.foo.com", :origin => "neworigin.foo.com")
98
98
 
99
- a_request(:post, "#{@url}/config/rest/pan/site/add").
99
+ expect(a_request(:post, "#{@url}/config/rest/pan/site/add").
100
100
  with(:body => 'pad=cache.foo.com&origin=neworigin.foo.com&user=user%40user.com&pass=secret',
101
101
  :headers => {
102
102
  'Accept' =>'*/*',
103
103
  'Content-Type'=>'application/x-www-form-urlencoded',
104
- 'User-Agent' =>'Ruby'}).
105
- should have_been_made
104
+ 'User-Agent' =>'Ruby'})).
105
+ to have_been_made
106
106
  end
107
107
  end
108
108
 
@@ -115,25 +115,25 @@ describe CdnetworksClient do
115
115
  it "calls the edit method of the cdnetworks api" do
116
116
  @cdn_api.edit
117
117
 
118
- a_request(:post, "#{@url}/config/rest/pan/site/edit").
118
+ expect(a_request(:post, "#{@url}/config/rest/pan/site/edit").
119
119
  with(:body => 'user=user%40user.com&pass=secret',
120
120
  :headers => {
121
121
  'Accept' =>'*/*',
122
122
  'Content-Type'=>'application/x-www-form-urlencoded',
123
- 'User-Agent' =>'Ruby'}).
124
- should have_been_made
123
+ 'User-Agent' =>'Ruby'})).
124
+ to have_been_made
125
125
  end
126
126
 
127
127
  it "includes the options passed as a hash" do
128
128
  @cdn_api.edit(:pad => "cache.foo.com", :honor_byte_range => "1")
129
129
 
130
- a_request(:post, "#{@url}/config/rest/pan/site/edit").
130
+ expect(a_request(:post, "#{@url}/config/rest/pan/site/edit").
131
131
  with(:body => 'pad=cache.foo.com&honor_byte_range=1&user=user%40user.com&pass=secret',
132
132
  :headers => {
133
133
  'Accept' =>'*/*',
134
134
  'Content-Type'=>'application/x-www-form-urlencoded',
135
- 'User-Agent' =>'Ruby'}).
136
- should have_been_made
135
+ 'User-Agent' =>'Ruby'})).
136
+ to have_been_made
137
137
  end
138
138
  end
139
139
 
@@ -147,56 +147,56 @@ describe CdnetworksClient do
147
147
  it "calls the purge method of the cdnetworks api" do
148
148
  @cdn_api.execute_cache_purge
149
149
 
150
- a_request(:post, "#{@url}/OpenAPI/services/CachePurgeAPI/executeCachePurge").
150
+ expect(a_request(:post, "#{@url}/OpenAPI/services/CachePurgeAPI/executeCachePurge").
151
151
  with(:body => 'userId=user%40user.com&password=secret',
152
152
  :headers => {
153
153
  'Accept' =>'*/*',
154
154
  'Content-Type'=>'application/x-www-form-urlencoded',
155
- 'User-Agent' =>'Ruby'}).
156
- should have_been_made
155
+ 'User-Agent' =>'Ruby'})).
156
+ to have_been_made
157
157
  end
158
158
 
159
159
  it "includes the options passed as a hash" do
160
160
  @cdn_api.execute_cache_purge(:purgeUriList => "cdn.example.com")
161
161
 
162
- a_request(:post, "#{@url}/OpenAPI/services/CachePurgeAPI/executeCachePurge").
162
+ expect(a_request(:post, "#{@url}/OpenAPI/services/CachePurgeAPI/executeCachePurge").
163
163
  with(:body => 'purgeUriList=cdn.example.com&userId=user%40user.com&password=secret',
164
164
  :headers => {
165
165
  'Accept' =>'*/*',
166
166
  'Content-Type'=>'application/x-www-form-urlencoded',
167
- 'User-Agent' =>'Ruby'}).
168
- should have_been_made
167
+ 'User-Agent' =>'Ruby'})).
168
+ to have_been_made
169
169
  end
170
170
 
171
171
  it "handles options passed as an array" do
172
172
  @cdn_api.execute_cache_purge(:purgeUriList => ["cdn.example.com", "pad.foo.com"])
173
173
 
174
- a_request(:post, "#{@url}/OpenAPI/services/CachePurgeAPI/executeCachePurge").
174
+ expect(a_request(:post, "#{@url}/OpenAPI/services/CachePurgeAPI/executeCachePurge").
175
175
  with(:body => 'purgeUriList=cdn.example.com&purgeUriList=pad.foo.com&userId=user%40user.com&password=secret',
176
176
  :headers => {
177
177
  'Accept' =>'*/*',
178
178
  'Content-Type'=>'application/x-www-form-urlencoded',
179
- 'User-Agent' =>'Ruby'}).
180
- should have_been_made
179
+ 'User-Agent' =>'Ruby'})).
180
+ to have_been_made
181
181
  end
182
182
  end
183
183
 
184
184
  context "getting a cache domain list" do
185
185
  before(:each) do
186
- stub_request(:post, "https://openapi.us.cdnetworks.com/OpenAPI/services/CachePurgeAPI/getCacheDomainList").
186
+ stub_request(:post, "#{@url}/OpenAPI/services/CachePurgeAPI/getCacheDomainList").
187
187
  to_return(:status => 200, :body => "", :headers => {})
188
188
  end
189
189
 
190
190
  it "calls the cache domain list method of the cdnetworks api" do
191
191
  @cdn_api.get_cache_domain_list
192
192
 
193
- a_request(:post, "#{@url}/OpenAPI/services/CachePurgeAPI/getCacheDomainList").
193
+ expect(a_request(:post, "#{@url}/OpenAPI/services/CachePurgeAPI/getCacheDomainList").
194
194
  with(:body => 'userId=user%40user.com&password=secret',
195
195
  :headers => {
196
196
  'Accept' =>'*/*',
197
197
  'Content-Type'=>'application/x-www-form-urlencoded',
198
- 'User-Agent' =>'Ruby'}).
199
- should have_been_made
198
+ 'User-Agent' =>'Ruby'})).
199
+ to have_been_made
200
200
  end
201
201
  end
202
202
  end
@@ -211,76 +211,87 @@ describe CdnetworksClient do
211
211
  it "calls the purge method" do
212
212
  @cdn_api.do_purge
213
213
 
214
- a_request(:post, "#{@url}/purge/rest/doPurge").
214
+ expect(a_request(:post, "#{@url}/purge/rest/doPurge").
215
215
  with(:body => 'user=user%40user.com&pass=secret',
216
216
  :headers => {
217
217
  'Accept' =>'*/*',
218
218
  'Content-Type'=>'application/x-www-form-urlencoded',
219
- 'User-Agent' =>'Ruby'}).
220
- should have_been_made
219
+ 'User-Agent' =>'Ruby'})).
220
+ to have_been_made
221
221
  end
222
222
 
223
223
  it "handles options passed as a hash" do
224
224
  @cdn_api.do_purge(:pad => "cdn.example.com", :type => "all")
225
225
 
226
- a_request(:post, "#{@url}/purge/rest/doPurge").
226
+ expect(a_request(:post, "#{@url}/purge/rest/doPurge").
227
227
  with(:body => 'pad=cdn.example.com&type=all&user=user%40user.com&pass=secret',
228
228
  :headers => {
229
229
  'Accept' =>'*/*',
230
230
  'Content-Type'=>'application/x-www-form-urlencoded',
231
- 'User-Agent' =>'Ruby'}).
232
- should have_been_made
231
+ 'User-Agent' =>'Ruby'})).
232
+ to have_been_made
233
233
  end
234
234
 
235
235
  it "handles options passed as an array" do
236
236
  @cdn_api.do_purge(:path => ["/images/one.jpg", "/images/two.jpg"])
237
- a_request(:post, "#{@url}/purge/rest/doPurge").
237
+ expect(a_request(:post, "#{@url}/purge/rest/doPurge").
238
238
  with(:body => 'path=%2Fimages%2Fone.jpg&path=%2Fimages%2Ftwo.jpg&user=user%40user.com&pass=secret',
239
239
  :headers => {
240
240
  'Accept' =>'*/*',
241
241
  'Content-Type'=>'application/x-www-form-urlencoded',
242
- 'User-Agent' =>'Ruby'}).
243
- should have_been_made
242
+ 'User-Agent' =>'Ruby'})).
243
+ to have_been_made
244
244
  end
245
245
  end
246
246
 
247
247
  context "getting a list of PADs" do
248
+ before do
249
+ stub_request(:post, "#{@url}/purge/rest/padList").
250
+ with(:body => {"pass"=>"secret", "user"=>"user@user.com"}).
251
+ to_return(:status => 200, :body => "", :headers => {})
252
+ end
253
+
248
254
  it "calls the list method" do
249
255
  @cdn_api.pad_list
250
256
 
251
- a_request(:post, "#{@url}/purge/rest/padList").
257
+ expect(a_request(:post, "#{@url}/purge/rest/padList").
252
258
  with(:body => 'user=user%40user.com&pass=secret',
253
259
  :headers => {
254
260
  'Accept' =>'*/*',
255
261
  'Content-Type'=>'application/x-www-form-urlencoded',
256
- 'User-Agent' =>'Ruby'}).
257
- should have_been_made
262
+ 'User-Agent' =>'Ruby'})).
263
+ to have_been_made
258
264
  end
259
265
  end
260
266
 
261
267
  context "get the status of a purge" do
268
+ before do
269
+ stub_request(:post, "#{@url}/purge/rest/status").
270
+ to_return(status: 200, body: "", headers: {})
271
+ end
272
+
262
273
  it "calls the status method" do
263
274
  @cdn_api.status
264
275
 
265
- a_request(:post, "#{@url}/purge/rest/status").
276
+ expect(a_request(:post, "#{@url}/purge/rest/status").
266
277
  with(:body => 'user=user%40user.com&pass=secret',
267
278
  :headers => {
268
279
  'Accept' =>'*/*',
269
280
  'Content-Type'=>'application/x-www-form-urlencoded',
270
- 'User-Agent' =>'Ruby'}).
271
- should have_been_made
281
+ 'User-Agent' =>'Ruby'})).
282
+ to have_been_made
272
283
  end
273
284
 
274
285
  it "handles options passsed as a hash" do
275
286
  @cdn_api.status(pid: 1234)
276
287
 
277
- a_request(:post, "#{@url}/purge/rest/status").
288
+ expect(a_request(:post, "#{@url}/purge/rest/status").
278
289
  with(:body => 'pid=1234&user=user%40user.com&pass=secret',
279
290
  :headers => {
280
291
  'Accept' =>'*/*',
281
292
  'Content-Type'=>'application/x-www-form-urlencoded',
282
- 'User-Agent' =>'Ruby'}).
283
- should have_been_made
293
+ 'User-Agent' =>'Ruby'})).
294
+ to have_been_made
284
295
  end
285
296
  end
286
297
  end
@@ -288,7 +299,7 @@ describe CdnetworksClient do
288
299
  context "locations" do
289
300
  it "uses the US access domain by default" do
290
301
  request = @cdn_api.compose_request("/some/path",{})
291
- request.path.should include("openapi.us.cdnetworks.com")
302
+ expect(request.path).to include("openapi.us.cdnetworks.com")
292
303
  end
293
304
 
294
305
  it "uses the Korean access domain when specified" do
@@ -299,7 +310,7 @@ describe CdnetworksClient do
299
310
  )
300
311
 
301
312
  request = korean_cdn.compose_request("/some/path",{})
302
- request.path.should include("openapi.kr.cdnetworks.com")
313
+ expect(request.path).to include("openapi.kr.cdnetworks.com")
303
314
  end
304
315
 
305
316
  it "uses the Japanese access domain when specified" do
@@ -310,7 +321,7 @@ describe CdnetworksClient do
310
321
  )
311
322
 
312
323
  request = japanese_cdn.compose_request("/some/path",{})
313
- request.path.should include("openapi.jp.cdnetworks.com")
324
+ expect(request.path).to include("openapi.jp.cdnetworks.com")
314
325
  end
315
326
 
316
327
  it "uses the Chinese access domain when specified" do
@@ -321,7 +332,7 @@ describe CdnetworksClient do
321
332
  )
322
333
 
323
334
  request = chinese_cdn.compose_request("/some/path",{})
324
- request.path.should include("openapi.txnetworks.cn")
335
+ expect(request.path).to include("openapi.txnetworks.cn")
325
336
  end
326
337
  end
327
338
 
@@ -338,10 +349,104 @@ describe CdnetworksClient do
338
349
  end
339
350
 
340
351
  it "returns an error" do
341
- error_result = @cdn_api.list
342
- error_result.should include("An error has occurred")
343
- error_result.should include("execution expired")
352
+ expect { @cdn_api.list }.to raise_error(Timeout::Error)
344
353
  end
345
354
  end
346
355
 
356
+
357
+ context 'OpenApiV2' do
358
+ before do
359
+ @cdn_api = CdnetworksClient.new(
360
+ user: @user,
361
+ pass: @password,
362
+ location: "Beta"
363
+ )
364
+
365
+ @url = "https://openapi-beta.cdnetworks.com"
366
+
367
+ @fake_token, @fake_key, _, @fake_service = stub_auth_calls
368
+ end
369
+
370
+ context "Session Management" do
371
+ let(:bad_token) { "oldtoken12345" }
372
+ let(:expired_session_resp) { JSON.pretty_unparse(apiKeyInfo: {returnCode: 102}) }
373
+
374
+ before do
375
+ @good_token, _ = stub_auth_calls
376
+ stub_request(:post, "#{@url}/api/rest/getApiKeyList").with(body: {"output"=>"json", "sessionToken"=>bad_token}).to_return(body: expired_session_resp)
377
+ end
378
+
379
+ it "re-establishes session if it expires" do
380
+ session_keys = @cdn_api.get_api_key_list(bad_token)
381
+
382
+ expect(a_request(:post, "#{@url}/api/rest/login")).to have_been_made
383
+ expect(session_keys.length).to be > 0
384
+ end
385
+
386
+ it "doesn't infinite loop if session can't be re-established" do
387
+ stub_request(:post, "#{@url}/api/rest/login").to_return(body: JSON.pretty_unparse(loginResponse: {resultCode: 101}))
388
+ expect { @cdn_api.get_api_key_list(bad_token) }.to raise_error(OpenApiError::ApiError)
389
+ end
390
+
391
+ it "gives up if session is not re-established after MAX_SESSION_RETRIES tries" do
392
+ stub_request(:post, "#{@url}/api/rest/getApiKeyList").with(body: {"output"=>"json", "sessionToken"=>@good_token}).to_return(body: expired_session_resp)
393
+
394
+ expect { @cdn_api.get_api_key_list(bad_token) }.to raise_error(OpenApiError::CriticalApiError)
395
+
396
+ expect(a_request(:post, "#{@url}/api/rest/login")).to have_been_made.times(3)
397
+ end
398
+ end
399
+
400
+ describe ConfigOpenApi do
401
+ before { stub_pad_list(@fake_service) }
402
+
403
+ it "fetches list using api key endpoint for OpenApiV2" do
404
+ expect(@cdn_api.list.first["origin"]).to eq(@fake_service)
405
+ end
406
+ end
407
+
408
+ describe AuthOpenApi do
409
+ it "raises error on failed login" do
410
+ stub_failed_login
411
+ expect{ @cdn_api.get_session_token }.to raise_error(OpenApiError::ApiError)
412
+ end
413
+
414
+ it "gets a session token" do
415
+ session_token = @cdn_api.get_session_token
416
+
417
+ expect(session_token).to eq(@fake_token)
418
+ end
419
+
420
+ skip "gets a service identifier" do
421
+ session = @cdn_api.get_session_token
422
+
423
+ expect(session[0]["svcGroupIdentifier"]).to eq(@fake_identifier)
424
+ end
425
+ end
426
+
427
+ describe OpenApiKeys do
428
+ it "gets api keys" do
429
+ api_key = @cdn_api.get_api_key(@fake_token, @fake_service)
430
+
431
+ expect(api_key).to eq(@fake_key)
432
+ end
433
+ end
434
+
435
+ describe StatisticsOpenApi do
436
+ describe "#bandwidth_usage" do
437
+ let(:end_time) { Time.now }
438
+ let(:start_time) { end_time - 1*60*60*24 }
439
+ let(:expected_bandwidth) { 1.23456 }
440
+
441
+ before do
442
+ stub_get_edge_traffic(expected_bandwidth)
443
+ end
444
+
445
+ it "returns bandwidth usage for a given time period" do
446
+ expect(@cdn_api.bandwidth_usage @fake_service, start_time, end_time).to eq expected_bandwidth
447
+ end
448
+ end
449
+ end
450
+
451
+ end
347
452
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,72 @@
1
1
  require 'webmock/rspec'
2
2
 
3
3
  require File.expand_path('../../lib/cdnetworks-client.rb', __FILE__)
4
+
5
+ module ApiStubs
6
+ def stub_auth_calls
7
+ fake_token = "12345thetoken"
8
+ fake_api_key = "EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
9
+ fake_identifier = "90525E70B7842930586545C6F1C9310C"
10
+ fake_service_name = 'cdn.example-app.host.com'
11
+ stub_login(fake_token, fake_identifier)
12
+ stub_get_api_keys(fake_token, fake_service_name, fake_api_key)
13
+
14
+ [fake_token, fake_api_key, fake_identifier, fake_service_name]
15
+ end
16
+
17
+ def stub_login(return_token, svc_identifier)
18
+ resp = JSON.pretty_unparse({loginResponse: {returnCode: 0,
19
+ session: [{sessionToken: return_token,
20
+ svcGroupName: "Service Group Name",
21
+ svcGroupIdentifier: svc_identifier}]}})
22
+
23
+ stub_request(:post, "#{@url}/api/rest/login").to_return(body: resp)
24
+ end
25
+
26
+ def stub_failed_login
27
+ stub_request(:post, "#{@url}/api/rest/login").to_return(body: JSON.pretty_unparse(loginResponse: {returnCode: 101}))
28
+ end
29
+
30
+ def stub_get_api_keys(session_token, service_name, return_key)
31
+ resp = JSON.pretty_unparse({apiKeyInfo: {returnCode: 0,
32
+ apiKeyInfoItem: [{type: 0,
33
+ serviceName: "Content Acceleration",
34
+ apiKey: "SERVICECATEGORY_CA",
35
+ parentApiKey: "SERVICECATEGORY_CA"},
36
+ {type: 1,
37
+ serviceName: service_name,
38
+ apiKey: return_key,
39
+ parentApiKey: "SERVICECATEGORY_CA"},
40
+ {type: 1,
41
+ serviceName: "cdn.another.app.com",
42
+ apiKey: "55555555555555555555555555555555",
43
+ parentApiKey: "SERVICECATEGORY_CA"}]}})
44
+
45
+ stub_request(:post, "#{@url}/api/rest/getApiKeyList").with(body: {"output"=>"json", "sessionToken"=>session_token}).to_return(body: resp)
46
+ end
47
+
48
+ def stub_get_edge_traffic(expected_bandwidth)
49
+ # TODO - take date as input and strftime it in output
50
+ resp = JSON.pretty_unparse(trafficResponse: {returnCode: 0,
51
+ trafficItem:
52
+ [{dateTime: '200809162305', bandwidth: 10, dataTransferred: expected_bandwidth}]})
53
+ stub_request(:post, "#{@url}/api/rest/traffic/edge").to_return(body: resp)
54
+ end
55
+
56
+ def stub_pad_list(expected_service)
57
+ resp = { "PadConfigResponse" => {
58
+ "resultCode" => 200,
59
+ "data"=> {
60
+ "errors" => "",
61
+ "data" => [ {"origin"=>expected_service, "pad"=>"pad.#{expected_service}", "id"=>11111},
62
+ {"origin"=>"another-site.com", "pad"=>"assets.another-site.com", "id"=>22222},
63
+ {"origin"=>"some.site.with.many.subdomains.com", "pad"=>"assets.many.subdomains.com", "id"=>33333},
64
+ {"origin"=>"somesite.s3.amazonaws.com", "pad"=>"assets.somesite.com", "id"=>44444} ]}}}
65
+
66
+ stub_request(:post, "#{@url}/api/rest/pan/site/list").to_return(body: JSON.pretty_unparse(resp))
67
+ end
68
+ end
69
+
70
+ RSpec.configure do |config|
71
+ config.include ApiStubs
72
+ end
metadata CHANGED
@@ -1,46 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cdnetworks-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
5
- prerelease:
4
+ version: 1.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Nell Shamrell
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-09-06 00:00:00.000000000 Z
11
+ date: 2015-10-27 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rspec
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: webmock
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  description: Simple wrapper for the CDNetworks Config Open API v1.0 and Cache Purge
@@ -51,45 +46,50 @@ executables: []
51
46
  extensions: []
52
47
  extra_rdoc_files: []
53
48
  files:
54
- - .gitignore
49
+ - ".gitignore"
55
50
  - Gemfile
56
51
  - LICENSE
57
- - LICENSE.txt
58
52
  - README.md
59
53
  - Rakefile
60
54
  - cdnetworks-client.gemspec
61
55
  - lib/cdnetworks-client.rb
56
+ - lib/cdnetworks-client/auth_open_api.rb
62
57
  - lib/cdnetworks-client/cache_flush_open_api.rb
63
58
  - lib/cdnetworks-client/cache_purge_api.rb
64
59
  - lib/cdnetworks-client/config_open_api.rb
60
+ - lib/cdnetworks-client/open_api_error.rb
61
+ - lib/cdnetworks-client/open_api_keys.rb
62
+ - lib/cdnetworks-client/statistics_open_api.rb
65
63
  - lib/cdnetworks-client/version.rb
64
+ - lib/patches.rb
65
+ - spec/integration_spec.rb
66
66
  - spec/lib/cdnetworks-client/cdnetworks_client_spec.rb
67
67
  - spec/spec_helper.rb
68
68
  homepage: https://github.com/blueboxgroup/cdnetworks-client
69
69
  licenses:
70
70
  - Apache
71
+ metadata: {}
71
72
  post_install_message:
72
73
  rdoc_options: []
73
74
  require_paths:
74
75
  - lib
75
76
  required_ruby_version: !ruby/object:Gem::Requirement
76
- none: false
77
77
  requirements:
78
- - - ! '>='
78
+ - - ">="
79
79
  - !ruby/object:Gem::Version
80
80
  version: '0'
81
81
  required_rubygems_version: !ruby/object:Gem::Requirement
82
- none: false
83
82
  requirements:
84
- - - ! '>='
83
+ - - ">="
85
84
  - !ruby/object:Gem::Version
86
85
  version: '0'
87
86
  requirements: []
88
87
  rubyforge_project:
89
- rubygems_version: 1.8.25
88
+ rubygems_version: 2.4.5.1
90
89
  signing_key:
91
- specification_version: 3
90
+ specification_version: 4
92
91
  summary: CDNetworks API Wrapper
93
92
  test_files:
93
+ - spec/integration_spec.rb
94
94
  - spec/lib/cdnetworks-client/cdnetworks_client_spec.rb
95
95
  - spec/spec_helper.rb
data/LICENSE.txt DELETED
@@ -1,22 +0,0 @@
1
- Copyright (c) 2013 Nell Shamrell
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.