defender 0.1.1 → 0.2.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.
- data/LICENSE +17 -17
- data/README.rdoc +5 -1
- data/Rakefile +9 -5
- data/VERSION +1 -1
- data/defender.gemspec +70 -0
- data/lib/defender.rb +51 -283
- data/lib/defender/document.rb +423 -0
- data/lib/defender/statistics.rb +176 -0
- data/spec/defender_spec.rb +17 -117
- data/spec/document_spec.rb +155 -0
- data/spec/spec_helper.rb +6 -2
- data/spec/statistics_spec.rb +37 -0
- metadata +25 -8
data/spec/defender_spec.rb
CHANGED
@@ -1,124 +1,24 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe Defender do
|
4
4
|
before(:each) do
|
5
|
-
|
5
|
+
FakeWeb.clean_registry
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
it "should correctly identify a valid API key" do
|
24
|
-
@defender.stubs(:call_action).with("validate-key").returns(
|
25
|
-
{"status" => "success", "message" => ""}
|
26
|
-
)
|
27
|
-
@defender.valid_key?.should be_true
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should correctly identify an invalid API key" do
|
31
|
-
@defender.stubs(:call_action).with("validate-key").returns(
|
32
|
-
{"status" => "fail", "message" => "Invalid key"}
|
33
|
-
)
|
34
|
-
@defender.valid_key?.should be_false
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should correctly identify a spammy comment" do
|
38
|
-
@defender.
|
39
|
-
stubs(:call_action).
|
40
|
-
with('audit-comment', {
|
41
|
-
"user-ip" => "127.0.0.1",
|
42
|
-
"article-date" => Time.now.strftime("%Y/%m/%d"),
|
43
|
-
"comment-author" => "Henrik Hodne",
|
44
|
-
"comment-type" => "comment",
|
45
|
-
"test-force" => "spam,0.5000",
|
46
|
-
}).
|
47
|
-
returns(
|
48
|
-
{"signature" => "abc123", "spam" => true, "spaminess" => 0.5}
|
49
|
-
)
|
50
|
-
@defender.audit_comment(
|
51
|
-
:user_ip => "127.0.0.1",
|
52
|
-
:article_date => Time.now,
|
53
|
-
:comment_author => "Henrik Hodne",
|
54
|
-
:comment_type => "comment",
|
55
|
-
:test_force => "spam,0.5000"
|
56
|
-
).spam?.should be_true
|
57
|
-
end
|
58
|
-
|
59
|
-
it "should correctly identify a meaty comment" do
|
60
|
-
@defender.
|
61
|
-
stubs(:call_action).
|
62
|
-
with('audit-comment', {
|
63
|
-
"user-ip" => "127.0.0.1",
|
64
|
-
"article-date" => Time.now.strftime("%Y/%m/%d"),
|
65
|
-
"comment-author" => "Henrik Hodne",
|
66
|
-
"comment-type" => "comment",
|
67
|
-
"test-force" => "ham,0.1000",
|
68
|
-
}).
|
69
|
-
returns(
|
70
|
-
{"signature" => "abc123", "spam" => false, "spaminess" => 0.1}
|
71
|
-
)
|
72
|
-
@defender.audit_comment(
|
73
|
-
:user_ip => "127.0.0.1",
|
74
|
-
:article_date => Time.now,
|
75
|
-
:comment_author => "Henrik Hodne",
|
76
|
-
:comment_type => "comment",
|
77
|
-
:test_force => "ham,0.1000"
|
78
|
-
).spam?.should be_false
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should correctly set the spaminess" do
|
82
|
-
@defender.
|
83
|
-
stubs(:call_action).
|
84
|
-
with('audit-comment', {
|
85
|
-
"user-ip" => "127.0.0.1",
|
86
|
-
"article-date" => Time.now.strftime("%Y/%m/%d"),
|
87
|
-
"comment-author" => "Henrik Hodne",
|
88
|
-
"comment-type" => "comment",
|
89
|
-
"test-force" => "spam,0.5000",
|
90
|
-
}).
|
91
|
-
returns(
|
92
|
-
{"signature" => "abc123", "spam" => true, "spaminess" => 0.5}
|
93
|
-
)
|
94
|
-
@defender.audit_comment(
|
95
|
-
:user_ip => "127.0.0.1",
|
96
|
-
:article_date => Time.now,
|
97
|
-
:comment_author => "Henrik Hodne",
|
98
|
-
:comment_type => "comment",
|
99
|
-
:test_force => "spam,0.5000"
|
100
|
-
).spaminess.should == 0.5
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should fail without valid API credentials" do
|
104
|
-
@defender.
|
105
|
-
stubs(:call_action).
|
106
|
-
with('audit-comment', {
|
107
|
-
"user-ip" => "127.0.0.1",
|
108
|
-
"article-date" => Time.now.strftime("%Y/%m/%d"),
|
109
|
-
"comment-author" => "Henrik Hodne",
|
110
|
-
"comment-type" => "comment",
|
111
|
-
"test-force" => "ham,0.1000",
|
112
|
-
}).
|
113
|
-
raises(StandardError)
|
114
|
-
lambda {
|
115
|
-
d.audit_comment(
|
116
|
-
:user_ip => "127.0.0.1",
|
117
|
-
:article_date => Time.now,
|
118
|
-
:comment_author => "Henrik Hodne",
|
119
|
-
:comment_type => "comment",
|
120
|
-
:test_force => "ham,0.1000"
|
121
|
-
)
|
122
|
-
}.should raise_error(StandardError)
|
8
|
+
context "api keys" do
|
9
|
+
it "returns false when given an invalid API key" do
|
10
|
+
FakeWeb.register_uri(:get, "http://api.defensio.com/2.0/users/foobar.json",
|
11
|
+
:body => '{"defensio-result":{"status":"failed","message":"API key not found","api-version":"2.0","owner-url":""}}',
|
12
|
+
:status => ['404', 'Not Found'])
|
13
|
+
Defender.api_key = "foobar"
|
14
|
+
Defender.check_api_key.should be_false
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns true when given a valid API key" do
|
18
|
+
FakeWeb.register_uri(:get, "http://api.defensio.com/2.0/users/barbaz.json",
|
19
|
+
:body => '{"defensio-result":{"status":"success","message":"","api-version":"2.0","owner-url":""}}')
|
20
|
+
Defender.api_key = "barbaz"
|
21
|
+
Defender.check_api_key.should be_true
|
22
|
+
end
|
123
23
|
end
|
124
24
|
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Defender::Document do
|
4
|
+
before(:each) do
|
5
|
+
FakeWeb.clean_registry
|
6
|
+
end
|
7
|
+
|
8
|
+
context "creating documents" do
|
9
|
+
it "should allow an innocent document to be posted when given only required options" do
|
10
|
+
FakeWeb.register_uri(:post, "http://api.defensio.com/2.0/users/foobar/documents.json",
|
11
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"success","message":"","signature":"baz",
|
12
|
+
"allow":true,"classification":"innocent","spaminess":0.1,
|
13
|
+
"profanity-match":false}}')
|
14
|
+
Defender.api_key = "foobar"
|
15
|
+
document = Defender::Document.new
|
16
|
+
document.content = "[innocent,0.1]"
|
17
|
+
document.type = :test
|
18
|
+
document.save
|
19
|
+
|
20
|
+
document.allow?.should be_true
|
21
|
+
document.classification.should == "innocent"
|
22
|
+
document.spaminess.should == 0.1
|
23
|
+
document.profane?.should be_false
|
24
|
+
document.signature.should == "baz"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "marks an asynchronously requested document as pending" do
|
28
|
+
FakeWeb.register_uri(:post, "http://api.defensio.com/2.0/users/foobar/documents.json",
|
29
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"pending","message":"","signature":"baz",
|
30
|
+
"allow":null,"classification":null,"spaminess":null,"profanity-match":null}}')
|
31
|
+
|
32
|
+
Defender.api_key = "foobar"
|
33
|
+
document = Defender::Document.new
|
34
|
+
document.content = "[innocent,0.1]"
|
35
|
+
document.type = :test
|
36
|
+
document.save(true)
|
37
|
+
|
38
|
+
document.pending?.should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should not allow a spammy document to be posted when given only required options" do
|
42
|
+
FakeWeb.register_uri(:post, "http://api.defensio.com/2.0/users/foobar/documents.json",
|
43
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"success","message":"","signature":"bar",
|
44
|
+
"allow":false,"classification":"spam","spaminess":0.89,"profanity-match":false}}')
|
45
|
+
|
46
|
+
Defender.api_key = "foobar"
|
47
|
+
document = Defender::Document.new
|
48
|
+
document.content = "[spam,0.89]"
|
49
|
+
document.type = :test
|
50
|
+
document.save
|
51
|
+
|
52
|
+
document.allow?.should be_false
|
53
|
+
document.classification.should == "spam"
|
54
|
+
document.spaminess.should == 0.89
|
55
|
+
document.profane?.should be_false
|
56
|
+
document.signature.should == "bar"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "accepts a string to parent-document-date" do
|
60
|
+
document = Defender::Document.new
|
61
|
+
document.parent_document_date = '1970-01-01'
|
62
|
+
document.attributes_hash['parent-document-date'].should == '1970-01-01'
|
63
|
+
end
|
64
|
+
|
65
|
+
it "accepts a Time to parent-document-date" do
|
66
|
+
time = Time.now
|
67
|
+
document = Defender::Document.new
|
68
|
+
document.parent_document_date = time
|
69
|
+
document.attributes_hash['parent-document-date'].should == time.strftime('%Y-%m-%d')
|
70
|
+
end
|
71
|
+
|
72
|
+
it "accepts a hash as headers" do
|
73
|
+
document = Defender::Document.new
|
74
|
+
document.http_headers = {"Foo" => "Bar", "Bar" => "Baz"}
|
75
|
+
document.attributes_hash['http-headers'].should == "Foo: Bar\nBar: Baz"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "accepts an array as headers" do
|
79
|
+
document = Defender::Document.new
|
80
|
+
document.http_headers = ["Foo: Bar", "Bar: Baz"]
|
81
|
+
document.attributes_hash['http-headers'].should == "Foo: Bar\nBar: Baz"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "returns false on server error" do
|
85
|
+
FakeWeb.register_uri(:post, "http://api.defensio.com/2.0/users/foobar/documents.json",
|
86
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"failed","message":"Oopsies"}}',
|
87
|
+
:status => ["500", "Server Error"])
|
88
|
+
Defender.api_key = "foobar"
|
89
|
+
document = Defender::Document.new
|
90
|
+
document.content = "[spam,0.89]"
|
91
|
+
document.type = :test
|
92
|
+
document.save.should be_false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "finding documents" do
|
97
|
+
it "sets the attributes for a found object" do
|
98
|
+
FakeWeb.register_uri(:get, "http://api.defensio.com/2.0/users/foobar/documents/baz.json",
|
99
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"success","message":"",
|
100
|
+
"signature":"baz","allow":false,"classification":"spam","spaminess":0.89,"profanity-match":false}}')
|
101
|
+
|
102
|
+
Defender.api_key = "foobar"
|
103
|
+
document = Defender::Document.find("baz")
|
104
|
+
document.allow?.should be_false
|
105
|
+
document.classification.should == "spam"
|
106
|
+
document.spaminess.should == 0.89
|
107
|
+
document.profane?.should be_false
|
108
|
+
document.signature.should == "baz"
|
109
|
+
end
|
110
|
+
|
111
|
+
it "raises a StandardError on server error" do
|
112
|
+
FakeWeb.register_uri(:get, "http://api.defensio.com/2.0/users/foobar/documents/baz.json",
|
113
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"failed","message":"oops"}}',
|
114
|
+
:status => ["500", "Server Error"])
|
115
|
+
|
116
|
+
Defender.api_key = "foobar"
|
117
|
+
lambda { Defender::Document.find("baz") }.should raise_error(StandardError, "oops")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "updating documents" do
|
122
|
+
it "only sets the allow attribute" do
|
123
|
+
FakeWeb.register_uri(:get, 'http://api.defensio.com/2.0/users/foobar/documents/baz.json',
|
124
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"success","message":"",
|
125
|
+
"signature":"baz","allow":false,"classification":"spam","spaminess":0.89,"profanity-match":false}}')
|
126
|
+
FakeWeb.register_uri(:put, 'http://api.defensio.com/2.0/users/foobar/documents/baz.json',
|
127
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"success","message":"",
|
128
|
+
"signature":"","allow":true,"classification":"spam","spaminess":0.89,"profanity-match":false"}}')
|
129
|
+
|
130
|
+
Defender.api_key = 'foobar'
|
131
|
+
document = Defender::Document.find('baz')
|
132
|
+
document.allow = true
|
133
|
+
oldcontent = document.content
|
134
|
+
lambda { document.content = 'foobar!' }.should raise_error(NameError)
|
135
|
+
document.save.should be_true
|
136
|
+
document.content.should == oldcontent
|
137
|
+
document.content.should_not == 'foobar!'
|
138
|
+
document.allow.should be_true
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'returns false when the server encounts an error' do
|
142
|
+
FakeWeb.register_uri(:get, 'http://api.defensio.com/2.0/users/foobar/documents/baz.json',
|
143
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"success","message":"",
|
144
|
+
"signature":"baz","allow":false,"classification":"spam","spaminess":0.89,"profanity-match":false}}')
|
145
|
+
FakeWeb.register_uri(:put, 'http://api.defensio.com/2.0/users/foobar/documents/baz.json',
|
146
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"failed","message":"UTTER FAIL!"}}',
|
147
|
+
:status => ['500', 'Server Error'])
|
148
|
+
|
149
|
+
Defender.api_key = 'foobar'
|
150
|
+
document = Defender::Document.find('baz')
|
151
|
+
document.allow = true
|
152
|
+
document.save.should be_false
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
2
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
|
3
6
|
require 'defender'
|
4
7
|
require 'spec'
|
5
8
|
require 'spec/autorun'
|
6
|
-
require '
|
9
|
+
require 'fakeweb'
|
10
|
+
|
11
|
+
FakeWeb.allow_net_connect = false
|
7
12
|
|
8
13
|
Spec::Runner.configure do |config|
|
9
|
-
|
10
14
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Defender::Statistics do
|
4
|
+
before(:each) do
|
5
|
+
FakeWeb.clean_registry
|
6
|
+
end
|
7
|
+
|
8
|
+
it "retrieves basic statistics from the server" do
|
9
|
+
FakeWeb.register_uri(:get, "http://api.defensio.com/2.0/users/foobar/basic-stats.json",
|
10
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"success","message":"",
|
11
|
+
"false-negatives":42,"false-positives":1,"learning":true,
|
12
|
+
"learning-status":"foo!","legitimate":{"total":15},
|
13
|
+
"recent-accuracy":0.9525,"unwanted":{"malicious":2,"spam":5,
|
14
|
+
"total":7}}}')
|
15
|
+
|
16
|
+
Defender.api_key = "foobar"
|
17
|
+
statistics = Defender::Statistics.new
|
18
|
+
statistics.api_version.should == "2.0"
|
19
|
+
statistics.false_negatives.should == 42
|
20
|
+
statistics.false_positives.should == 1
|
21
|
+
statistics.learning.should be_true
|
22
|
+
statistics.legitimate_total.should == 15
|
23
|
+
statistics.recent_accuracy.should == 0.9525
|
24
|
+
statistics.unwanted_malicious.should == 2
|
25
|
+
statistics.unwanted_spam.should == 5
|
26
|
+
statistics.unwanted_total.should == 7
|
27
|
+
end
|
28
|
+
|
29
|
+
it "raises a StandardError if the server fails" do
|
30
|
+
FakeWeb.register_uri(:get, "http://api.defensio.com/2.0/users/foobar/basic-stats.json",
|
31
|
+
:body => '{"defensio-result":{"api-version":"2.0","status":"failed","message":"Oops"}}',
|
32
|
+
:status => ["500", "Server Error"])
|
33
|
+
|
34
|
+
Defender.api_key = "foobar"
|
35
|
+
lambda { Defender::Statistics.new }.should raise_error(StandardError, "Oops")
|
36
|
+
end
|
37
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: defender
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henrik Hodne
|
@@ -9,16 +9,26 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-01-20 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: httparty
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.4.3
|
24
|
+
version:
|
15
25
|
- !ruby/object:Gem::Dependency
|
16
26
|
name: rspec
|
17
27
|
type: :development
|
18
28
|
version_requirement:
|
19
29
|
version_requirements: !ruby/object:Gem::Requirement
|
20
30
|
requirements:
|
21
|
-
- -
|
31
|
+
- - ~>
|
22
32
|
- !ruby/object:Gem::Version
|
23
33
|
version: 1.2.9
|
24
34
|
version:
|
@@ -28,19 +38,19 @@ dependencies:
|
|
28
38
|
version_requirement:
|
29
39
|
version_requirements: !ruby/object:Gem::Requirement
|
30
40
|
requirements:
|
31
|
-
- -
|
41
|
+
- - ~>
|
32
42
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
43
|
+
version: 0.4.0
|
34
44
|
version:
|
35
45
|
- !ruby/object:Gem::Dependency
|
36
|
-
name:
|
46
|
+
name: fakeweb
|
37
47
|
type: :development
|
38
48
|
version_requirement:
|
39
49
|
version_requirements: !ruby/object:Gem::Requirement
|
40
50
|
requirements:
|
41
|
-
- -
|
51
|
+
- - ~>
|
42
52
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
53
|
+
version: 1.2.7
|
44
54
|
version:
|
45
55
|
description: A wrapper of the Defensio spam filtering service.
|
46
56
|
email: henrik.hodne@binaryhex.com
|
@@ -58,10 +68,15 @@ files:
|
|
58
68
|
- README.rdoc
|
59
69
|
- Rakefile
|
60
70
|
- VERSION
|
71
|
+
- defender.gemspec
|
61
72
|
- lib/defender.rb
|
73
|
+
- lib/defender/document.rb
|
74
|
+
- lib/defender/statistics.rb
|
62
75
|
- spec/defender_spec.rb
|
76
|
+
- spec/document_spec.rb
|
63
77
|
- spec/spec.opts
|
64
78
|
- spec/spec_helper.rb
|
79
|
+
- spec/statistics_spec.rb
|
65
80
|
has_rdoc: true
|
66
81
|
homepage: http://github.com/dvyjones/defender
|
67
82
|
licenses: []
|
@@ -92,4 +107,6 @@ specification_version: 3
|
|
92
107
|
summary: Ruby API wrapper for Defensio
|
93
108
|
test_files:
|
94
109
|
- spec/spec_helper.rb
|
110
|
+
- spec/document_spec.rb
|
95
111
|
- spec/defender_spec.rb
|
112
|
+
- spec/statistics_spec.rb
|