customerio 2.2.1 → 4.0.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 +5 -15
- data/.github/workflows/main.yml +30 -0
- data/CHANGELOG.markdown +48 -0
- data/README.md +53 -19
- data/customerio.gemspec +2 -2
- data/lib/customerio.rb +4 -0
- data/lib/customerio/api.rb +35 -0
- data/lib/customerio/base_client.rb +87 -0
- data/lib/customerio/client.rb +83 -144
- data/lib/customerio/regions.rb +11 -0
- data/lib/customerio/requests/send_email_request.rb +49 -0
- data/lib/customerio/version.rb +1 -1
- data/spec/api_client_spec.rb +172 -0
- data/spec/base_client_spec.rb +67 -0
- data/spec/client_spec.rb +340 -230
- data/spec/spec_helper.rb +2 -2
- metadata +40 -33
- data/.travis.yml +0 -9
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'multi_json'
|
3
|
+
|
4
|
+
module Customerio
|
5
|
+
module Regions
|
6
|
+
Region = Struct.new(:track_url, :api_url)
|
7
|
+
|
8
|
+
US = Customerio::Regions::Region.new('https://track.customer.io', 'https://api.customer.io').freeze
|
9
|
+
EU = Customerio::Regions::Region.new('https://track-eu.customer.io', 'https://api-eu.customer.io').freeze
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Customerio
|
4
|
+
class SendEmailRequest
|
5
|
+
attr_reader :message
|
6
|
+
|
7
|
+
def initialize(opts)
|
8
|
+
@message = opts.delete_if { |field| invalid_field?(field) }
|
9
|
+
@message[:attachments] = {}
|
10
|
+
@message[:headers] = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def attach(name, data, encode: true)
|
14
|
+
raise "attachment #{name} already exists" if @message[:attachments].has_key?(name)
|
15
|
+
@message[:attachments][name] = encode ? Base64.strict_encode64(data) : data
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
REQUIRED_FIELDS = %i(to identifiers)
|
21
|
+
|
22
|
+
OPTIONAL_FIELDS = %i(
|
23
|
+
transactional_message_id
|
24
|
+
message_data
|
25
|
+
headers
|
26
|
+
preheader
|
27
|
+
from
|
28
|
+
reply_to
|
29
|
+
bcc
|
30
|
+
subject
|
31
|
+
body
|
32
|
+
plaintext_body
|
33
|
+
amp_body
|
34
|
+
fake_bcc
|
35
|
+
disable_message_retention
|
36
|
+
send_to_unsubscribed
|
37
|
+
tracked
|
38
|
+
queue_draft
|
39
|
+
)
|
40
|
+
|
41
|
+
def invalid_field?(field)
|
42
|
+
!REQUIRED_FIELDS.include?(field) && !OPTIONAL_FIELDS.include?(field)
|
43
|
+
end
|
44
|
+
|
45
|
+
def encode(data)
|
46
|
+
Base64.strict_encode64(data)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/customerio/version.rb
CHANGED
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'multi_json'
|
3
|
+
require 'base64'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
describe Customerio::APIClient do
|
7
|
+
let(:app_key) { "appkey" }
|
8
|
+
|
9
|
+
let(:client) { Customerio::APIClient.new(app_key) }
|
10
|
+
let(:response) { double("Response", code: 200) }
|
11
|
+
|
12
|
+
def api_uri(path)
|
13
|
+
"https://api.customer.io#{path}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def request_headers
|
17
|
+
{ 'Authorization': "Bearer #{app_key}", 'Content-Type': 'application/json' }
|
18
|
+
end
|
19
|
+
|
20
|
+
def json(data)
|
21
|
+
MultiJson.dump(data)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "the base client is initialised with the correct values when no region is passed in" do
|
25
|
+
app_key = "appkey"
|
26
|
+
|
27
|
+
expect(Customerio::BaseClient).to(
|
28
|
+
receive(:new)
|
29
|
+
.with(
|
30
|
+
{ app_key: app_key },
|
31
|
+
{
|
32
|
+
region: Customerio::Regions::US,
|
33
|
+
url: Customerio::Regions::US.api_url
|
34
|
+
}
|
35
|
+
)
|
36
|
+
)
|
37
|
+
|
38
|
+
client = Customerio::APIClient.new(app_key)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "raises an error when an incorrect region is passed in" do
|
42
|
+
expect {
|
43
|
+
Customerio::APIClient.new("appkey", region: :au)
|
44
|
+
}.to raise_error /region must be an instance of Customerio::Regions::Region/
|
45
|
+
end
|
46
|
+
|
47
|
+
[Customerio::Regions::US, Customerio::Regions::EU].each do |region|
|
48
|
+
it "the base client is initialised with the correct values when the region \"#{region}\" is passed in" do
|
49
|
+
app_key = "appkey"
|
50
|
+
|
51
|
+
expect(Customerio::BaseClient).to(
|
52
|
+
receive(:new)
|
53
|
+
.with(
|
54
|
+
{ app_key: app_key },
|
55
|
+
{
|
56
|
+
region: region,
|
57
|
+
url: region.api_url
|
58
|
+
}
|
59
|
+
)
|
60
|
+
)
|
61
|
+
|
62
|
+
client = Customerio::APIClient.new(app_key, { region: region })
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#send_email" do
|
67
|
+
it "sends a POST request to the /api/send/email path" do
|
68
|
+
req = Customerio::SendEmailRequest.new(
|
69
|
+
identifiers: {
|
70
|
+
id: 'c1',
|
71
|
+
},
|
72
|
+
transactional_message_id: 1,
|
73
|
+
)
|
74
|
+
|
75
|
+
stub_request(:post, api_uri('/v1/send/email'))
|
76
|
+
.with(headers: request_headers, body: req.message)
|
77
|
+
.to_return(status: 200, body: { delivery_id: 1 }.to_json, headers: {})
|
78
|
+
|
79
|
+
client.send_email(req).should eq({ "delivery_id" => 1 })
|
80
|
+
end
|
81
|
+
|
82
|
+
it "handles validation failures (400)" do
|
83
|
+
req = Customerio::SendEmailRequest.new(
|
84
|
+
identifiers: {
|
85
|
+
id: 'c1',
|
86
|
+
},
|
87
|
+
transactional_message_id: 1,
|
88
|
+
)
|
89
|
+
|
90
|
+
err_json = { meta: { error: "example error" } }.to_json
|
91
|
+
|
92
|
+
stub_request(:post, api_uri('/v1/send/email'))
|
93
|
+
.with(headers: request_headers, body: req.message)
|
94
|
+
.to_return(status: 400, body: err_json, headers: {})
|
95
|
+
|
96
|
+
lambda { client.send_email(req) }.should(
|
97
|
+
raise_error(Customerio::InvalidResponse) { |error|
|
98
|
+
error.message.should eq "example error"
|
99
|
+
error.code.should eq "400"
|
100
|
+
}
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "handles other failures (5xx)" do
|
105
|
+
req = Customerio::SendEmailRequest.new(
|
106
|
+
identifiers: {
|
107
|
+
id: 'c1',
|
108
|
+
},
|
109
|
+
transactional_message_id: 1,
|
110
|
+
)
|
111
|
+
|
112
|
+
stub_request(:post, api_uri('/v1/send/email'))
|
113
|
+
.with(headers: request_headers, body: req.message)
|
114
|
+
.to_return(status: 500, body: "Server unavailable", headers: {})
|
115
|
+
|
116
|
+
lambda { client.send_email(req) }.should(
|
117
|
+
raise_error(Customerio::InvalidResponse) { |error|
|
118
|
+
error.message.should eq "Server unavailable"
|
119
|
+
error.code.should eq "500"
|
120
|
+
}
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "allows attaching file content without encoding" do
|
125
|
+
content = 'sample content'
|
126
|
+
|
127
|
+
req = Customerio::SendEmailRequest.new(
|
128
|
+
customer_id: 'c1',
|
129
|
+
transactional_message_id: 1,
|
130
|
+
)
|
131
|
+
|
132
|
+
req.attach('test', content, encode: false)
|
133
|
+
req.message[:attachments]['test'].should eq content
|
134
|
+
|
135
|
+
stub_request(:post, api_uri('/v1/send/email'))
|
136
|
+
.with(headers: request_headers, body: req.message)
|
137
|
+
.to_return(status: 200, body: { delivery_id: 1 }.to_json, headers: {})
|
138
|
+
|
139
|
+
client.send_email(req)
|
140
|
+
end
|
141
|
+
|
142
|
+
it "allows attaching files with encoding (default)" do
|
143
|
+
content = 'sample content'
|
144
|
+
|
145
|
+
req = Customerio::SendEmailRequest.new(
|
146
|
+
customer_id: 'c1',
|
147
|
+
transactional_message_id: 1,
|
148
|
+
)
|
149
|
+
|
150
|
+
req.attach('test', content)
|
151
|
+
req.message[:attachments]['test'].should eq Base64.strict_encode64(content)
|
152
|
+
|
153
|
+
stub_request(:post, api_uri('/v1/send/email'))
|
154
|
+
.with(headers: request_headers, body: req.message)
|
155
|
+
.to_return(status: 200, body: { delivery_id: 1 }.to_json, headers: {})
|
156
|
+
|
157
|
+
client.send_email(req)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "raises error when attaching the same key again" do
|
161
|
+
req = Customerio::SendEmailRequest.new(
|
162
|
+
customer_id: 'c1',
|
163
|
+
transactional_message_id: 1,
|
164
|
+
)
|
165
|
+
|
166
|
+
req.attach('test', 'test-content')
|
167
|
+
|
168
|
+
lambda { req.attach('test', '') }.should raise_error(/attachment test already exists/)
|
169
|
+
req.message[:attachments].should eq({ "test" => Base64.strict_encode64("test-content") })
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'multi_json'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
describe Customerio::BaseClient do
|
6
|
+
let(:url) { "https://test.customer.io" }
|
7
|
+
|
8
|
+
let(:site_id) { "SITE_ID" }
|
9
|
+
let(:api_key) { "API_KEY" }
|
10
|
+
let(:track_client) { Customerio::BaseClient.new({ site_id: site_id, api_key: api_key }, { url: url }) }
|
11
|
+
|
12
|
+
let(:app_key) { "APP_KEY" }
|
13
|
+
let(:api_client) { Customerio::BaseClient.new({ app_key: app_key }, { url: url }) }
|
14
|
+
|
15
|
+
def api_uri(path)
|
16
|
+
"#{url}#{path}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def track_client_request_headers
|
20
|
+
token = Base64.strict_encode64("#{site_id}:#{api_key}")
|
21
|
+
{ 'Authorization': "Basic #{token}", 'Content-Type': 'application/json' }
|
22
|
+
end
|
23
|
+
|
24
|
+
def api_client_request_headers
|
25
|
+
{ 'Authorization': "Bearer #{app_key}", 'Content-Type': 'application/json' }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "with a site ID and API key" do
|
29
|
+
it "uses the correct basic auth" do
|
30
|
+
stub_request(:put, api_uri('/some/path')).
|
31
|
+
with(headers: track_client_request_headers).
|
32
|
+
to_return(status: 200, body: "", headers: {})
|
33
|
+
|
34
|
+
track_client.request(:put, '/some/path', "")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "with an app key" do
|
39
|
+
it "uses the correct bearer token" do
|
40
|
+
stub_request(:put, api_uri('/some/path')).
|
41
|
+
with(headers: api_client_request_headers).
|
42
|
+
to_return(status: 200, body: "", headers: {})
|
43
|
+
|
44
|
+
api_client.request(:put, '/some/path', "")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#verify_response" do
|
49
|
+
it "throws an error when the response isn't between 200 and 300" do
|
50
|
+
stub_request(:put, api_uri('/some/path')).
|
51
|
+
with(headers: api_client_request_headers).
|
52
|
+
to_return(status: 400, body: "", headers: {})
|
53
|
+
|
54
|
+
lambda { api_client.request_and_verify_response(:put, '/some/path', "") }.should(
|
55
|
+
raise_error(Customerio::InvalidResponse)
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns the response when the status is 200" do
|
60
|
+
stub_request(:put, api_uri('/some/path')).
|
61
|
+
with(headers: api_client_request_headers).
|
62
|
+
to_return(status: 200, body: "Test", headers: {})
|
63
|
+
|
64
|
+
api_client.request_and_verify_response(:put, '/some/path', "").body.should eq("Test")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/spec/client_spec.rb
CHANGED
@@ -1,39 +1,92 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'multi_json'
|
3
|
-
|
3
|
+
require 'base64'
|
4
4
|
|
5
5
|
describe Customerio::Client do
|
6
|
-
let(:
|
7
|
-
let(:
|
6
|
+
let(:site_id) { "SITE_ID" }
|
7
|
+
let(:api_key) { "API_KEY" }
|
8
|
+
|
9
|
+
let(:client) { Customerio::Client.new(site_id, api_key) }
|
10
|
+
let(:response) { double("Response", code: 200) }
|
8
11
|
|
9
12
|
def api_uri(path)
|
10
|
-
"https://
|
13
|
+
"https://track.customer.io#{path}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def request_headers
|
17
|
+
token = Base64.strict_encode64("#{site_id}:#{api_key}")
|
18
|
+
{ 'Authorization': "Basic #{token}", 'Content-Type': 'application/json' }
|
11
19
|
end
|
12
20
|
|
13
21
|
def json(data)
|
14
22
|
MultiJson.dump(data)
|
15
23
|
end
|
16
24
|
|
17
|
-
|
18
|
-
|
25
|
+
it "the base client is initialised with the correct values when no region is passed in" do
|
26
|
+
site_id = "SITE_ID"
|
27
|
+
api_key = "API_KEY"
|
28
|
+
|
29
|
+
expect(Customerio::BaseClient).to(
|
30
|
+
receive(:new)
|
31
|
+
.with(
|
32
|
+
{ site_id: site_id, api_key: api_key },
|
33
|
+
{
|
34
|
+
region: Customerio::Regions::US,
|
35
|
+
url: Customerio::Regions::US.track_url
|
36
|
+
}
|
37
|
+
)
|
38
|
+
)
|
19
39
|
|
20
|
-
|
21
|
-
|
40
|
+
client = Customerio::Client.new(site_id, api_key)
|
41
|
+
end
|
22
42
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
43
|
+
it "raises an error when an incorrect region is passed in" do
|
44
|
+
expect {
|
45
|
+
Customerio::Client.new("siteid", "apikey", region: :au)
|
46
|
+
}.to raise_error /region must be an instance of Customerio::Regions::Region/
|
47
|
+
end
|
27
48
|
|
28
|
-
|
49
|
+
[Customerio::Regions::US, Customerio::Regions::EU].each do |region|
|
50
|
+
it "the base client is initialised with the correct values when the region \"#{region}\" is passed in" do
|
51
|
+
site_id = "SITE_ID"
|
52
|
+
api_key = "API_KEY"
|
53
|
+
|
54
|
+
expect(Customerio::BaseClient).to(
|
55
|
+
receive(:new)
|
56
|
+
.with(
|
57
|
+
{ site_id: site_id, api_key: api_key },
|
58
|
+
{
|
59
|
+
region: region,
|
60
|
+
url: region.track_url
|
61
|
+
}
|
62
|
+
)
|
63
|
+
)
|
64
|
+
|
65
|
+
client = Customerio::Client.new(site_id, api_key, { region: region })
|
29
66
|
end
|
67
|
+
end
|
30
68
|
|
31
|
-
|
32
|
-
|
69
|
+
it "uses json by default" do
|
70
|
+
body = { id: 5, name: "Bob" }
|
71
|
+
client = Customerio::Client.new("SITE_ID", "API_KEY")
|
33
72
|
|
34
|
-
|
35
|
-
|
36
|
-
|
73
|
+
stub_request(:put, api_uri('/api/v1/customers/5')).
|
74
|
+
with(body: json(body),
|
75
|
+
headers: {'Content-Type'=>'application/json'}).
|
76
|
+
to_return(status: 200, body: "", headers: {})
|
77
|
+
|
78
|
+
client.identify(body)
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "headers" do
|
82
|
+
let(:body) { { id: 1, token: :test } }
|
83
|
+
|
84
|
+
it "sends the basic headers, base64 encoded with the request" do
|
85
|
+
client = Customerio::Client.new("SITE_ID", "API_KEY")
|
86
|
+
|
87
|
+
stub_request(:put, api_uri('/api/v1/customers/1')).
|
88
|
+
with(body: json(body), headers: request_headers).
|
89
|
+
to_return(status: 200, body: "", headers: {})
|
37
90
|
|
38
91
|
client.identify(body)
|
39
92
|
end
|
@@ -42,41 +95,54 @@ describe Customerio::Client do
|
|
42
95
|
describe "#identify" do
|
43
96
|
it "sends a PUT request to customer.io's customer API" do
|
44
97
|
stub_request(:put, api_uri('/api/v1/customers/5')).
|
45
|
-
with(:
|
46
|
-
to_return(:
|
98
|
+
with(body: json(id: "5")).
|
99
|
+
to_return(status: 200, body: "", headers: {})
|
47
100
|
|
48
|
-
client.identify(:
|
101
|
+
client.identify(id: "5")
|
102
|
+
end
|
103
|
+
|
104
|
+
it "escapes customer IDs" do
|
105
|
+
stub_request(:put, api_uri('/api/v1/customers/5%20')).
|
106
|
+
with(body: json({ id: "5 " })).
|
107
|
+
to_return(status: 200, body: "", headers: {})
|
108
|
+
|
109
|
+
client.identify(id: "5 ")
|
110
|
+
|
111
|
+
stub_request(:put, api_uri('/api/v1/customers/5%2F')).
|
112
|
+
with(body: { id: "5/" }).
|
113
|
+
to_return(status: 200, body: "", headers: {})
|
114
|
+
client.identify(id: "5/")
|
49
115
|
end
|
50
116
|
|
51
117
|
it "sends a PUT request to customer.io's customer API using json headers" do
|
52
|
-
client = Customerio::Client.new("SITE_ID", "API_KEY", :
|
53
|
-
body = { :
|
118
|
+
client = Customerio::Client.new("SITE_ID", "API_KEY", json: true)
|
119
|
+
body = { id: 5, name: "Bob" }
|
54
120
|
|
55
121
|
stub_request(:put, api_uri('/api/v1/customers/5')).
|
56
|
-
with(:
|
57
|
-
:
|
58
|
-
to_return(:
|
122
|
+
with(body: json(body),
|
123
|
+
headers: {'Content-Type'=>'application/json'}).
|
124
|
+
to_return(status: 200, body: "", headers: {})
|
59
125
|
|
60
126
|
client.identify(body)
|
61
127
|
end
|
62
128
|
|
63
129
|
it "raises an error if PUT doesn't return a 2xx response code" do
|
64
130
|
stub_request(:put, api_uri('/api/v1/customers/5')).
|
65
|
-
with(:
|
66
|
-
to_return(:
|
131
|
+
with(body: json(id: 5)).
|
132
|
+
to_return(status: 500, body: "", headers: {})
|
67
133
|
|
68
|
-
lambda { client.identify(:
|
134
|
+
lambda { client.identify(id: 5) }.should raise_error(Customerio::InvalidResponse)
|
69
135
|
end
|
70
136
|
|
71
137
|
it "includes the HTTP response with raised errors" do
|
72
138
|
stub_request(:put, api_uri('/api/v1/customers/5')).
|
73
|
-
with(:
|
74
|
-
to_return(:
|
139
|
+
with(body: json(id: 5)).
|
140
|
+
to_return(status: 500, body: "Server unavailable", headers: {})
|
75
141
|
|
76
|
-
lambda { client.identify(:
|
77
|
-
error.should be_a Customerio::
|
78
|
-
error.
|
79
|
-
error.
|
142
|
+
lambda { client.identify(id: 5) }.should raise_error {|error|
|
143
|
+
error.should be_a Customerio::InvalidResponse
|
144
|
+
error.code.should eq "500"
|
145
|
+
error.message.should eq "Server unavailable"
|
80
146
|
}
|
81
147
|
end
|
82
148
|
|
@@ -84,31 +150,34 @@ describe Customerio::Client do
|
|
84
150
|
time = Time.now.to_i
|
85
151
|
|
86
152
|
stub_request(:put, api_uri('/api/v1/customers/5')).with(
|
87
|
-
:
|
88
|
-
:
|
89
|
-
:
|
90
|
-
:
|
91
|
-
:
|
92
|
-
:
|
93
|
-
|
153
|
+
body: {
|
154
|
+
id: 5,
|
155
|
+
email: "customer@example.com",
|
156
|
+
created_at: time,
|
157
|
+
first_name: "Bob",
|
158
|
+
plan: "basic",
|
159
|
+
anonymous_id: "anon-id"
|
160
|
+
}).to_return(status: 200, body: "", headers: {})
|
94
161
|
|
95
162
|
client.identify({
|
96
|
-
:
|
97
|
-
:
|
98
|
-
:
|
99
|
-
:
|
100
|
-
:
|
163
|
+
id: 5,
|
164
|
+
anonymous_id: "anon-id",
|
165
|
+
email: "customer@example.com",
|
166
|
+
created_at: time,
|
167
|
+
first_name: "Bob",
|
168
|
+
plan: "basic"
|
101
169
|
})
|
102
170
|
end
|
103
171
|
|
104
172
|
it "requires an id attribute" do
|
105
|
-
lambda { client.identify(:
|
173
|
+
lambda { client.identify(email: "customer@example.com") }.should raise_error(Customerio::Client::MissingIdAttributeError)
|
174
|
+
lambda { client.identify(id: "") }.should raise_error(Customerio::Client::MissingIdAttributeError)
|
106
175
|
end
|
107
176
|
|
108
177
|
it 'should not raise errors when attribute keys are strings' do
|
109
178
|
stub_request(:put, api_uri('/api/v1/customers/5')).
|
110
|
-
with(:
|
111
|
-
to_return(:
|
179
|
+
with(body: json(id: 5)).
|
180
|
+
to_return(status: 200, body: "", headers: {})
|
112
181
|
|
113
182
|
attributes = { "id" => 5 }
|
114
183
|
|
@@ -119,257 +188,265 @@ describe Customerio::Client do
|
|
119
188
|
describe "#delete" do
|
120
189
|
it "sends a DELETE request to the customer.io's event API" do
|
121
190
|
stub_request(:delete, api_uri('/api/v1/customers/5')).
|
122
|
-
to_return(:
|
191
|
+
to_return(status: 200, body: "", headers: {})
|
123
192
|
|
124
193
|
client.delete(5)
|
125
194
|
end
|
195
|
+
|
196
|
+
it "throws an error when customer_id is missing" do
|
197
|
+
stub_request(:put, /track.customer.io/)
|
198
|
+
.to_return(status: 200, body: "", headers: {})
|
199
|
+
|
200
|
+
lambda { client.delete(" ") }.should raise_error(Customerio::Client::ParamError, "customer_id must be a non-empty string")
|
201
|
+
end
|
202
|
+
|
203
|
+
it "escapes customer IDs" do
|
204
|
+
stub_request(:delete, api_uri('/api/v1/customers/5%20')).
|
205
|
+
to_return(status: 200, body: "", headers: {})
|
206
|
+
|
207
|
+
client.delete("5 ")
|
208
|
+
end
|
126
209
|
end
|
127
210
|
|
128
211
|
describe "#suppress" do
|
129
212
|
it "sends a POST request to the customer.io's suppress API" do
|
130
213
|
stub_request(:post, api_uri('/api/v1/customers/5/suppress')).
|
131
|
-
to_return(:
|
214
|
+
to_return(status: 200, body: "", headers: {})
|
132
215
|
|
133
216
|
client.suppress(5)
|
134
217
|
end
|
218
|
+
|
219
|
+
it "throws an error when customer_id is missing" do
|
220
|
+
stub_request(:put, /track.customer.io/)
|
221
|
+
.to_return(status: 200, body: "", headers: {})
|
222
|
+
|
223
|
+
lambda { client.suppress(" ") }.should raise_error(Customerio::Client::ParamError, "customer_id must be a non-empty string")
|
224
|
+
end
|
135
225
|
end
|
136
226
|
|
137
227
|
describe "#unsuppress" do
|
138
228
|
it "sends a POST request to the customer.io's unsuppress API" do
|
139
229
|
stub_request(:post, api_uri('/api/v1/customers/5/unsuppress')).
|
140
|
-
to_return(:
|
230
|
+
to_return(status: 200, body: "", headers: {})
|
141
231
|
|
142
232
|
client.unsuppress(5)
|
143
233
|
end
|
234
|
+
|
235
|
+
it "throws an error when customer_id is missing" do
|
236
|
+
stub_request(:put, /track.customer.io/)
|
237
|
+
.to_return(status: 200, body: "", headers: {})
|
238
|
+
|
239
|
+
lambda { client.suppress(" ") }.should raise_error(Customerio::Client::ParamError, "customer_id must be a non-empty string")
|
240
|
+
end
|
144
241
|
end
|
145
242
|
|
146
243
|
describe "#track" do
|
147
244
|
it "raises an error if POST doesn't return a 2xx response code" do
|
148
245
|
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
149
|
-
with(:
|
150
|
-
to_return(:
|
246
|
+
with(body: json(name: "purchase", data: {})).
|
247
|
+
to_return(status: 500, body: "", headers: {})
|
248
|
+
|
249
|
+
lambda { client.track(5, "purchase") }.should raise_error(Customerio::InvalidResponse)
|
250
|
+
end
|
251
|
+
|
252
|
+
it "throws an error when customer_id or event_name is missing" do
|
253
|
+
stub_request(:put, /track.customer.io/)
|
254
|
+
.to_return(status: 200, body: "", headers: {})
|
151
255
|
|
152
|
-
lambda { client.track(
|
256
|
+
lambda { client.track(" ", "test_event") }.should raise_error(Customerio::Client::ParamError, "customer_id must be a non-empty string")
|
257
|
+
lambda { client.track(5, " ") }.should raise_error(Customerio::Client::ParamError, "event_name must be a non-empty string")
|
153
258
|
end
|
154
259
|
|
155
260
|
it "uses the site_id and api key for basic auth and sends the event name" do
|
156
261
|
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
157
|
-
with(:
|
158
|
-
to_return(:
|
262
|
+
with(body: json(name: "purchase", data: {})).
|
263
|
+
to_return(status: 200, body: "", headers: {})
|
159
264
|
|
160
265
|
client.track(5, "purchase")
|
161
266
|
end
|
162
267
|
|
163
268
|
it "sends any optional event attributes" do
|
164
269
|
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
165
|
-
with(:
|
166
|
-
:
|
167
|
-
:
|
168
|
-
:
|
169
|
-
:
|
270
|
+
with(body: json({
|
271
|
+
name: "purchase",
|
272
|
+
data: {
|
273
|
+
type: "socks",
|
274
|
+
price: "13.99"
|
170
275
|
}
|
171
|
-
}).
|
172
|
-
to_return(:
|
276
|
+
})).
|
277
|
+
to_return(status: 200, body: "", headers: {})
|
173
278
|
|
174
|
-
client.track(5, "purchase", :
|
279
|
+
client.track(5, "purchase", type: "socks", price: "13.99")
|
175
280
|
end
|
176
281
|
|
177
282
|
it "copes with arrays" do
|
178
283
|
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
179
|
-
with(:
|
180
|
-
:
|
181
|
-
:
|
182
|
-
:
|
284
|
+
with(body: {
|
285
|
+
name: "event",
|
286
|
+
data: {
|
287
|
+
things: ["a", "b", "c"]
|
183
288
|
}
|
184
289
|
}).
|
185
|
-
to_return(:
|
290
|
+
to_return(status: 200, body: "", headers: {})
|
186
291
|
|
187
|
-
client.track(5, "event", :
|
292
|
+
client.track(5, "event", things: ["a", "b", "c"])
|
188
293
|
end
|
189
294
|
|
190
295
|
it "copes with hashes" do
|
191
296
|
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
192
|
-
with(:
|
193
|
-
:
|
194
|
-
:
|
195
|
-
:
|
297
|
+
with(body: {
|
298
|
+
name: "event",
|
299
|
+
data: {
|
300
|
+
stuff: { a: "b" }
|
196
301
|
}
|
197
302
|
}).
|
198
|
-
to_return(:
|
303
|
+
to_return(status: 200, body: "", headers: {})
|
199
304
|
|
200
|
-
client.track(5, "event", :
|
305
|
+
client.track(5, "event", stuff: { a: "b" })
|
201
306
|
end
|
202
307
|
|
203
308
|
it "sends a POST request as json using json headers" do
|
204
|
-
client = Customerio::Client.new("SITE_ID", "API_KEY", :
|
205
|
-
data = { :
|
206
|
-
body = { :
|
309
|
+
client = Customerio::Client.new("SITE_ID", "API_KEY", json: true)
|
310
|
+
data = { type: "socks", price: "13.99" }
|
311
|
+
body = { name: "purchase", data: data }
|
207
312
|
|
208
313
|
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
209
|
-
with(:
|
210
|
-
:
|
211
|
-
to_return(:
|
314
|
+
with(body: json(body),
|
315
|
+
headers: {'Content-Type'=>'application/json'}).
|
316
|
+
to_return(status: 200, body: "", headers: {})
|
212
317
|
|
213
318
|
client.track(5, "purchase", data)
|
214
319
|
end
|
215
320
|
|
216
321
|
it "allows sending of a timestamp" do
|
217
322
|
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
218
|
-
with(:
|
219
|
-
:
|
220
|
-
:
|
221
|
-
:
|
222
|
-
:
|
223
|
-
:
|
323
|
+
with(body: json({
|
324
|
+
name: "purchase",
|
325
|
+
data: {
|
326
|
+
type: "socks",
|
327
|
+
price: "13.99",
|
328
|
+
timestamp: 1561231234
|
224
329
|
},
|
225
|
-
:
|
226
|
-
}).
|
227
|
-
to_return(:
|
330
|
+
timestamp: 1561231234
|
331
|
+
})).
|
332
|
+
to_return(status: 200, body: "", headers: {})
|
228
333
|
|
229
|
-
client.track(5, "purchase", :
|
334
|
+
client.track(5, "purchase", type: "socks", price: "13.99", timestamp: 1561231234)
|
230
335
|
end
|
231
336
|
|
232
337
|
it "doesn't send timestamp if timestamp is in milliseconds" do
|
233
338
|
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
234
|
-
with(:
|
235
|
-
:
|
236
|
-
:
|
237
|
-
:
|
238
|
-
:
|
239
|
-
:
|
339
|
+
with(body: json({
|
340
|
+
name: "purchase",
|
341
|
+
data: {
|
342
|
+
type: "socks",
|
343
|
+
price: "13.99",
|
344
|
+
timestamp: 1561231234000
|
240
345
|
}
|
241
|
-
}).
|
242
|
-
to_return(:
|
346
|
+
})).
|
347
|
+
to_return(status: 200, body: "", headers: {})
|
243
348
|
|
244
|
-
client.track(5, "purchase", :
|
349
|
+
client.track(5, "purchase", type: "socks", price: "13.99", timestamp: 1561231234000)
|
245
350
|
end
|
246
351
|
|
247
352
|
it "doesn't send timestamp if timestamp is a date" do
|
248
353
|
date = Time.now
|
249
354
|
|
250
355
|
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
251
|
-
with(:
|
252
|
-
:
|
253
|
-
:
|
254
|
-
:
|
255
|
-
:
|
256
|
-
:
|
356
|
+
with(body: {
|
357
|
+
name: "purchase",
|
358
|
+
data: {
|
359
|
+
type: "socks",
|
360
|
+
price: "13.99",
|
361
|
+
timestamp: Time.now.to_s
|
257
362
|
}
|
258
363
|
}).
|
259
|
-
to_return(:
|
364
|
+
to_return(status: 200, body: "", headers: {})
|
260
365
|
|
261
|
-
client.track(5, "purchase", :
|
366
|
+
client.track(5, "purchase", type: "socks", price: "13.99", timestamp: date)
|
262
367
|
end
|
263
368
|
|
264
369
|
it "doesn't send timestamp if timestamp isn't an integer" do
|
265
370
|
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
266
|
-
with(:
|
267
|
-
:
|
268
|
-
:
|
269
|
-
:
|
270
|
-
:
|
271
|
-
:
|
371
|
+
with(body: json({
|
372
|
+
name: "purchase",
|
373
|
+
data: {
|
374
|
+
type: "socks",
|
375
|
+
price: "13.99",
|
376
|
+
timestamp: "Hello world"
|
272
377
|
}
|
273
|
-
}).
|
378
|
+
})).
|
274
379
|
|
275
|
-
to_return(:
|
380
|
+
to_return(status: 200, body: "", headers: {})
|
276
381
|
|
277
|
-
client.track(5, "purchase", :
|
382
|
+
client.track(5, "purchase", type: "socks", price: "13.99", timestamp: "Hello world")
|
278
383
|
end
|
279
384
|
|
280
385
|
context "tracking an anonymous event" do
|
386
|
+
let(:anon_id) { "anon-id" }
|
387
|
+
|
281
388
|
it "sends a POST request to the customer.io's anonymous event API" do
|
282
389
|
stub_request(:post, api_uri('/api/v1/events')).
|
283
|
-
with(:
|
284
|
-
to_return(:
|
390
|
+
with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
|
391
|
+
to_return(status: 200, body: "", headers: {})
|
285
392
|
|
286
|
-
client.
|
393
|
+
client.track_anonymous(anon_id, "purchase")
|
287
394
|
end
|
288
395
|
|
289
396
|
it "sends any optional event attributes" do
|
290
397
|
stub_request(:post, api_uri('/api/v1/events')).
|
291
|
-
with(:
|
292
|
-
:
|
293
|
-
:
|
294
|
-
|
295
|
-
:
|
398
|
+
with(body: {
|
399
|
+
anonymous_id: anon_id,
|
400
|
+
name: "purchase",
|
401
|
+
data: {
|
402
|
+
type: "socks",
|
403
|
+
price: "13.99"
|
296
404
|
}
|
297
405
|
}).
|
298
|
-
to_return(:
|
406
|
+
to_return(status: 200, body: "", headers: {})
|
299
407
|
|
300
|
-
client.
|
408
|
+
client.track_anonymous(anon_id, "purchase", type: "socks", price: "13.99")
|
301
409
|
end
|
302
410
|
|
303
411
|
it "allows sending of a timestamp" do
|
304
412
|
stub_request(:post, api_uri('/api/v1/events')).
|
305
|
-
with(:
|
306
|
-
:
|
307
|
-
:
|
308
|
-
|
309
|
-
:
|
310
|
-
:
|
413
|
+
with(body: {
|
414
|
+
anonymous_id: anon_id,
|
415
|
+
name: "purchase",
|
416
|
+
data: {
|
417
|
+
type: "socks",
|
418
|
+
price: "13.99",
|
419
|
+
timestamp: 1561231234
|
311
420
|
},
|
312
|
-
:
|
421
|
+
timestamp: 1561231234
|
313
422
|
}).
|
314
|
-
to_return(:
|
423
|
+
to_return(status: 200, body: "", headers: {})
|
315
424
|
|
316
|
-
client.
|
425
|
+
client.track_anonymous(anon_id, "purchase", type: "socks", price: "13.99", timestamp: 1561231234)
|
317
426
|
end
|
318
|
-
end
|
319
|
-
end
|
320
427
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
to_return(:status => 500, :body => "", :headers => {})
|
326
|
-
|
327
|
-
lambda { client.anonymous_track("purchase") }.should raise_error(Customerio::Client::InvalidResponse)
|
328
|
-
end
|
428
|
+
it "raises an error if POST doesn't return a 2xx response code" do
|
429
|
+
stub_request(:post, api_uri('/api/v1/events')).
|
430
|
+
with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
|
431
|
+
to_return(status: 500, body: "", headers: {})
|
329
432
|
|
330
|
-
|
331
|
-
|
332
|
-
with(:body => "name=purchase").
|
333
|
-
to_return(:status => 200, :body => "", :headers => {})
|
334
|
-
|
335
|
-
client.anonymous_track("purchase")
|
336
|
-
end
|
337
|
-
|
338
|
-
it "sends any optional event attributes" do
|
339
|
-
stub_request(:post, api_uri('/api/v1/events')).
|
340
|
-
with(:body => {
|
341
|
-
:name => "purchase",
|
342
|
-
:data => {
|
343
|
-
:type => "socks",
|
344
|
-
:price => "27.99"
|
345
|
-
},
|
346
|
-
}).
|
347
|
-
|
348
|
-
to_return(:status => 200, :body => "", :headers => {})
|
349
|
-
|
350
|
-
client.anonymous_track("purchase", :type => "socks", :price => "27.99")
|
351
|
-
end
|
433
|
+
lambda { client.track_anonymous(anon_id, "purchase") }.should raise_error(Customerio::InvalidResponse)
|
434
|
+
end
|
352
435
|
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
:
|
357
|
-
:data => {
|
358
|
-
:type => "socks",
|
359
|
-
:price => "27.99",
|
360
|
-
:timestamp => "1561235678"
|
361
|
-
},
|
362
|
-
:timestamp => "1561235678"
|
363
|
-
}).
|
436
|
+
it "throws an error when anonymous_id is missing" do
|
437
|
+
stub_request(:post, api_uri('/api/v1/events')).
|
438
|
+
with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
|
439
|
+
to_return(status: 500, body: "", headers: {})
|
364
440
|
|
365
|
-
|
441
|
+
lambda { client.track_anonymous("", "some_event") }.should raise_error(Customerio::Client::ParamError)
|
442
|
+
end
|
366
443
|
|
367
|
-
|
368
|
-
|
444
|
+
it "throws an error when event_name is missing" do
|
445
|
+
stub_request(:post, api_uri('/api/v1/events')).
|
446
|
+
with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
|
447
|
+
to_return(status: 500, body: "", headers: {})
|
369
448
|
|
370
|
-
|
371
|
-
it "throws an error" do
|
372
|
-
lambda { client.anonymous_track("purchase", "text", :type => "socks", :price => "27.99") }.should raise_error(ArgumentError)
|
449
|
+
lambda { client.track_anonymous(anon_id, "") }.should raise_error(Customerio::Client::ParamError)
|
373
450
|
end
|
374
451
|
end
|
375
452
|
end
|
@@ -377,109 +454,142 @@ describe Customerio::Client do
|
|
377
454
|
describe "#devices" do
|
378
455
|
it "allows for the creation of a new device" do
|
379
456
|
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
380
|
-
to_return(:
|
457
|
+
to_return(status: 200, body: "", headers: {})
|
381
458
|
|
382
|
-
client.add_device(5, "androidDeviceID", "ios", {:
|
459
|
+
client.add_device(5, "androidDeviceID", "ios", {last_used: 1561235678})
|
383
460
|
client.add_device(5, "iosDeviceID", "android")
|
384
461
|
end
|
385
462
|
it "requires a valid customer_id when creating" do
|
386
463
|
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
387
|
-
to_return(:
|
464
|
+
to_return(status: 200, body: "", headers: {})
|
388
465
|
|
389
466
|
lambda { client.add_device("", "ios", "myDeviceID") }.should raise_error(Customerio::Client::ParamError)
|
390
|
-
lambda { client.add_device(nil, "ios", "myDeviceID", {:
|
467
|
+
lambda { client.add_device(nil, "ios", "myDeviceID", {last_used: 1561235678}) }.should raise_error(Customerio::Client::ParamError)
|
391
468
|
end
|
392
469
|
it "requires a valid token when creating" do
|
393
470
|
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
394
|
-
to_return(:
|
471
|
+
to_return(status: 200, body: "", headers: {})
|
395
472
|
|
396
473
|
lambda { client.add_device(5, "", "ios") }.should raise_error(Customerio::Client::ParamError)
|
397
|
-
lambda { client.add_device(5, nil, "ios", {:
|
474
|
+
lambda { client.add_device(5, nil, "ios", {last_used: 1561235678}) }.should raise_error(Customerio::Client::ParamError)
|
398
475
|
end
|
399
476
|
it "requires a valid platform when creating" do
|
400
477
|
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
401
|
-
to_return(:
|
478
|
+
to_return(status: 200, body: "", headers: {})
|
402
479
|
|
403
480
|
lambda { client.add_device(5, "token", "") }.should raise_error(Customerio::Client::ParamError)
|
404
|
-
lambda { client.add_device(5, "toke", nil, {:
|
481
|
+
lambda { client.add_device(5, "toke", nil, {last_used: 1561235678}) }.should raise_error(Customerio::Client::ParamError)
|
405
482
|
end
|
406
483
|
it "accepts a nil data param" do
|
407
484
|
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
408
|
-
to_return(:
|
485
|
+
to_return(status: 200, body: "", headers: {})
|
409
486
|
|
410
487
|
client.add_device(5, "ios", "myDeviceID", nil)
|
411
488
|
end
|
412
489
|
it "fails on invalid data param" do
|
413
490
|
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
414
|
-
to_return(:
|
491
|
+
to_return(status: 200, body: "", headers: {})
|
415
492
|
|
416
493
|
lambda { client.add_device(5, "ios", "myDeviceID", 1000) }.should raise_error(Customerio::Client::ParamError)
|
417
494
|
end
|
418
495
|
it "supports deletion of devices by token" do
|
419
496
|
stub_request(:delete, api_uri('/api/v1/customers/5/devices/myDeviceID')).
|
420
|
-
to_return(:
|
497
|
+
to_return(status: 200, body: "", headers: {})
|
421
498
|
|
422
499
|
client.delete_device(5, "myDeviceID")
|
423
500
|
end
|
424
501
|
it "requires a valid customer_id when deleting" do
|
425
502
|
stub_request(:delete, api_uri('/api/v1/customers/5/devices/myDeviceID')).
|
426
|
-
to_return(:
|
503
|
+
to_return(status: 200, body: "", headers: {})
|
427
504
|
|
428
505
|
lambda { client.delete_device("", "myDeviceID") }.should raise_error(Customerio::Client::ParamError)
|
429
506
|
lambda { client.delete_device(nil, "myDeviceID") }.should raise_error(Customerio::Client::ParamError)
|
430
507
|
end
|
431
508
|
it "requires a valid device_id when deleting" do
|
432
509
|
stub_request(:delete, api_uri('/api/v1/customers/5/devices/myDeviceID')).
|
433
|
-
to_return(:
|
510
|
+
to_return(status: 200, body: "", headers: {})
|
434
511
|
|
435
512
|
lambda { client.delete_device(5, "") }.should raise_error(Customerio::Client::ParamError)
|
436
513
|
lambda { client.delete_device(5, nil) }.should raise_error(Customerio::Client::ParamError)
|
437
514
|
end
|
438
515
|
end
|
439
516
|
|
440
|
-
describe "#
|
517
|
+
describe "#track_push_notification_event" do
|
518
|
+
attr_accessor :client, :attributes
|
441
519
|
|
442
|
-
|
520
|
+
before(:each) do
|
521
|
+
@client = Customerio::Client.new("SITE_ID", "API_KEY", :json => true)
|
522
|
+
@attributes = {
|
523
|
+
:delivery_id => 'foo',
|
524
|
+
:device_id => 'bar',
|
525
|
+
:timestamp => Time.now.to_i
|
526
|
+
}
|
527
|
+
end
|
443
528
|
|
444
|
-
it "
|
445
|
-
stub_request(:post, api_uri('/
|
529
|
+
it "sends a POST request to customer.io's /push/events endpoint" do
|
530
|
+
stub_request(:post, api_uri('/push/events')).
|
531
|
+
with(
|
532
|
+
:body => json(attributes.merge({
|
533
|
+
:event => 'opened'
|
534
|
+
})),
|
535
|
+
:headers => {
|
536
|
+
'Content-Type' => 'application/json'
|
537
|
+
}).
|
538
|
+
to_return(:status => 200, :body => "", :headers => {})
|
446
539
|
|
447
|
-
client.
|
540
|
+
client.track_push_notification_event('opened', attributes)
|
448
541
|
end
|
449
|
-
it "requires a valid segment id when adding customers" do
|
450
|
-
stub_request(:post, api_uri('/api/v1/segments/1/add_customers')).to_return(:status => 200, :body => "", :headers => {})
|
451
542
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
stub_request(:post, api_uri('/api/v1/segments/1/add_customers')).to_return(:status => 200, :body => "", :headers => {})
|
543
|
+
it "should raise if event is invalid" do
|
544
|
+
stub_request(:post, api_uri('/push/events')).
|
545
|
+
to_return(:status => 200, :body => "", :headers => {})
|
456
546
|
|
457
|
-
|
547
|
+
expect {
|
548
|
+
client.track_push_notification_event('closed', attributes.merge({ :delivery_id => nil }))
|
549
|
+
}.to raise_error(Customerio::Client::ParamError, 'event_name must be one of opened, converted, or delivered')
|
458
550
|
end
|
459
|
-
it "coerces non-string values to strings when adding customers" do
|
460
|
-
stub_request(:post, api_uri('/api/v1/segments/1/add_customers')).with(:body=>json({:ids=>["1", "2", "3"]})).to_return(:status => 200, :body => "", :headers => {})
|
461
551
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
stub_request(:post, api_uri('/api/v1/segments/1/remove_customers')).to_return(:status => 200, :body => "", :headers => {})
|
552
|
+
it "should raise if delivery_id is invalid" do
|
553
|
+
stub_request(:post, api_uri('/push/events')).
|
554
|
+
to_return(:status => 200, :body => "", :headers => {})
|
466
555
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
stub_request(:post, api_uri('/api/v1/segments/1/remove_customers')).to_return(:status => 200, :body => "", :headers => {})
|
556
|
+
expect {
|
557
|
+
client.track_push_notification_event('opened', attributes.merge({ :delivery_id => nil }))
|
558
|
+
}.to raise_error(Customerio::Client::ParamError, 'delivery_id must be a non-empty string')
|
471
559
|
|
472
|
-
|
560
|
+
expect {
|
561
|
+
client.track_push_notification_event('opened', attributes.merge({ :delivery_id => '' }))
|
562
|
+
}.to raise_error(Customerio::Client::ParamError, 'delivery_id must be a non-empty string')
|
473
563
|
end
|
474
|
-
it "requires a valid customer list when removing customers" do
|
475
|
-
stub_request(:post, api_uri('/api/v1/segments/1/remove_customers')).to_return(:status => 200, :body => "", :headers => {})
|
476
564
|
|
477
|
-
|
565
|
+
it "should raise if device_id is invalid" do
|
566
|
+
stub_request(:post, api_uri('/push/events')).
|
567
|
+
to_return(:status => 200, :body => "", :headers => {})
|
568
|
+
|
569
|
+
expect {
|
570
|
+
client.track_push_notification_event('opened', attributes.merge({ :device_id => nil }))
|
571
|
+
}.to raise_error(Customerio::Client::ParamError, 'device_id must be a non-empty string')
|
572
|
+
|
573
|
+
expect {
|
574
|
+
client.track_push_notification_event('opened', attributes.merge({ :device_id => '' }))
|
575
|
+
}.to raise_error(Customerio::Client::ParamError, 'device_id must be a non-empty string')
|
478
576
|
end
|
479
|
-
it "coerces non-string values to strings when removing customers" do
|
480
|
-
stub_request(:post, api_uri('/api/v1/segments/1/remove_customers')).with(:body=>json({:ids=>["1", "2", "3"]})).to_return(:status => 200, :body => "", :headers => {})
|
481
577
|
|
482
|
-
|
578
|
+
it "should raise if timestamp is invalid" do
|
579
|
+
stub_request(:post, api_uri('/push/events')).
|
580
|
+
to_return(:status => 200, :body => "", :headers => {})
|
581
|
+
|
582
|
+
expect {
|
583
|
+
client.track_push_notification_event('opened', attributes.merge({ :timestamp => nil }))
|
584
|
+
}.to raise_error(Customerio::Client::ParamError, 'timestamp must be a valid timestamp')
|
585
|
+
|
586
|
+
expect {
|
587
|
+
client.track_push_notification_event('opened', attributes.merge({ :timestamp => 999999999 }))
|
588
|
+
}.to raise_error(Customerio::Client::ParamError, 'timestamp must be a valid timestamp')
|
589
|
+
|
590
|
+
expect {
|
591
|
+
client.track_push_notification_event('opened', attributes.merge({ :timestamp => 100000000000 }))
|
592
|
+
}.to raise_error(Customerio::Client::ParamError, 'timestamp must be a valid timestamp')
|
483
593
|
end
|
484
594
|
end
|
485
595
|
end
|