rdf-spec 1.99.0 → 2.0.0.beta1
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 +4 -4
- data/{README → README.md} +2 -0
- data/VERSION +1 -1
- data/lib/rdf/spec.rb +18 -0
- data/lib/rdf/spec/countable.rb +5 -28
- data/lib/rdf/spec/dataset.rb +47 -0
- data/lib/rdf/spec/durable.rb +8 -23
- data/lib/rdf/spec/enumerable.rb +118 -102
- data/lib/rdf/spec/format.rb +4 -26
- data/lib/rdf/spec/http_adapter.rb +1 -23
- data/lib/rdf/spec/indexable.rb +1 -23
- data/lib/rdf/spec/inferable.rb +0 -16
- data/lib/rdf/spec/inspects.rb +4 -5
- data/lib/rdf/spec/matchers.rb +95 -4
- data/lib/rdf/spec/mutable.rb +227 -81
- data/lib/rdf/spec/queryable.rb +122 -165
- data/lib/rdf/spec/readable.rb +0 -22
- data/lib/rdf/spec/reader.rb +21 -29
- data/lib/rdf/spec/repository.rb +80 -40
- data/lib/rdf/spec/transactable.rb +43 -0
- data/lib/rdf/spec/transaction.rb +294 -71
- data/lib/rdf/spec/version.rb +2 -2
- data/lib/rdf/spec/writable.rb +78 -100
- data/lib/rdf/spec/writer.rb +51 -28
- data/spec/countable_spec.rb +11 -0
- data/spec/dataset_spec.rb +14 -0
- data/spec/durable_spec.rb +12 -0
- data/spec/enumerable_spec.rb +11 -0
- data/spec/format_spec.rb +12 -0
- data/spec/http_adapter_spec.rb +15 -0
- data/spec/indexable.rb +15 -0
- data/spec/literal_spec.rb +75 -0
- data/spec/mutable_spec.rb +11 -0
- data/spec/queryable_spec.rb +13 -0
- data/spec/readable.rb +11 -0
- data/spec/reader_spec.rb +17 -0
- data/spec/repository_spec.rb +11 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/transaction_spec.rb +7 -0
- data/spec/version_spec.rb +2 -0
- data/spec/writable_spec.rb +13 -0
- data/spec/writer_spec.rb +11 -0
- metadata +56 -12
data/lib/rdf/spec/repository.rb
CHANGED
@@ -15,65 +15,105 @@ RSpec.shared_examples 'an RDF::Repository' do
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
let(:countable) { repository }
|
19
|
-
let(:enumerable) { repository }
|
20
|
-
let(:queryable) { repository }
|
21
18
|
let(:mutable) { repository }
|
19
|
+
let(:dataset) { repository.supports?(:snapshots) ? repository.snapshot : repository }
|
20
|
+
subject { repository }
|
22
21
|
|
23
|
-
context
|
24
|
-
require 'rdf/spec/
|
25
|
-
it_behaves_like 'an RDF::
|
22
|
+
context 'as dataset' do
|
23
|
+
require 'rdf/spec/dataset'
|
24
|
+
it_behaves_like 'an RDF::Dataset'
|
26
25
|
end
|
27
26
|
|
28
|
-
context
|
29
|
-
require 'rdf/spec/
|
30
|
-
|
27
|
+
context 'as transactable' do
|
28
|
+
require 'rdf/spec/transactable'
|
29
|
+
let(:transactable) { repository }
|
30
|
+
it_behaves_like 'an RDF::Transactable'
|
31
31
|
end
|
32
|
-
|
33
|
-
context "when querying statements" do
|
34
|
-
require 'rdf/spec/queryable'
|
35
|
-
it_behaves_like 'an RDF::Queryable'
|
36
|
-
end
|
37
|
-
|
38
|
-
# FIXME: This should be condition on the repository being mutable
|
32
|
+
|
39
33
|
context "when updating" do
|
40
34
|
require 'rdf/spec/mutable'
|
41
35
|
|
42
|
-
before { mutable.clear }
|
43
|
-
|
36
|
+
before { mutable.clear if mutable.mutable? }
|
44
37
|
it_behaves_like 'an RDF::Mutable'
|
38
|
+
|
39
|
+
describe '#delete_insert' do
|
40
|
+
it 'updates transactionally' do
|
41
|
+
if mutable.mutable? && mutable.supports?(:atomic_writes)
|
42
|
+
expect(mutable).to receive(:commit_transaction).and_call_original
|
43
|
+
statement = RDF::Statement(:s, RDF::URI.new("urn:predicate:1"), :o)
|
44
|
+
|
45
|
+
mutable.delete_insert([statement], [statement])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
45
49
|
end
|
46
50
|
|
47
|
-
#
|
48
|
-
|
49
|
-
|
51
|
+
describe "#transaction" do
|
52
|
+
it 'gives an immutable transaction' do
|
53
|
+
expect { subject.transaction { insert([]) } }.to raise_error TypeError
|
54
|
+
end
|
50
55
|
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
it 'commits a successful transaction' do
|
57
|
+
statement = RDF::Statement(:s, RDF.type, :o)
|
58
|
+
expect(subject).to receive(:commit_transaction).and_call_original
|
59
|
+
|
60
|
+
expect do
|
61
|
+
subject.transaction(mutable: true) { insert(statement) }
|
62
|
+
end.to change { subject.statements }.to include(statement)
|
54
63
|
end
|
55
64
|
|
56
|
-
|
57
|
-
|
58
|
-
|
65
|
+
it 'rolls back a failed transaction' do
|
66
|
+
original_contents = subject.statements
|
67
|
+
expect(subject).to receive(:rollback_transaction).and_call_original
|
59
68
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
69
|
+
expect do
|
70
|
+
subject.transaction(mutable: true) do
|
71
|
+
delete(*@statements)
|
72
|
+
raise 'my error'
|
73
|
+
end
|
74
|
+
end.to raise_error RuntimeError
|
65
75
|
|
66
|
-
|
67
|
-
|
68
|
-
"Please use `it_behaves_like 'an RDF::Repository'`"
|
76
|
+
expect(subject.statements).to contain_exactly(*original_contents)
|
77
|
+
end
|
69
78
|
end
|
70
79
|
|
71
|
-
|
72
|
-
|
73
|
-
|
80
|
+
context "with snapshot support" do
|
81
|
+
|
82
|
+
describe '#snapshot' do
|
83
|
+
it 'is not implemented when #supports(:snapshots) is false' do
|
84
|
+
unless subject.supports?(:snapshots)
|
85
|
+
expect { subject.snapshot }.to raise_error NotImplementedError
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'returns a queryable #snapshot' do
|
91
|
+
if subject.supports? :snapshots
|
92
|
+
expect(subject.snapshot).to be_a RDF::Queryable
|
93
|
+
expect(mutable.snapshot).to be_a RDF::Dataset
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'has repeatable read isolation or better' do
|
98
|
+
if repository.supports? :snapshots
|
99
|
+
good_isolation = [:repeatable_read, :snapshot, :serializable]
|
100
|
+
expect(good_isolation).to include repository.isolation_level
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'gives an accurate snapshot' do
|
105
|
+
if subject.supports? :snapshots
|
106
|
+
snap = subject.snapshot
|
107
|
+
expect(snap.query([:s, :p, :o]))
|
108
|
+
.to contain_exactly(*subject.query([:s, :p, :o]))
|
109
|
+
end
|
110
|
+
end
|
74
111
|
|
75
|
-
|
76
|
-
|
112
|
+
it 'gives static snapshot' do
|
113
|
+
if subject.supports? :snapshots
|
114
|
+
snap = subject.snapshot
|
115
|
+
expect { subject.clear }
|
116
|
+
.not_to change { snap.query([:s, :p, :o]).to_a }
|
77
117
|
end
|
78
118
|
end
|
79
119
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rdf/spec'
|
2
|
+
|
3
|
+
RSpec.shared_examples 'an RDF::Transactable' do
|
4
|
+
include RDF::Spec::Matchers
|
5
|
+
|
6
|
+
let(:statements) { RDF::Spec.quads }
|
7
|
+
|
8
|
+
before do
|
9
|
+
raise '`transactable` must be set with `let(:transactable)`' unless
|
10
|
+
defined? transactable
|
11
|
+
end
|
12
|
+
|
13
|
+
subject { transactable }
|
14
|
+
|
15
|
+
describe "#transaction" do
|
16
|
+
it 'gives an immutable transaction' do
|
17
|
+
expect { subject.transaction { insert([]) } }.to raise_error TypeError
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'commits a successful transaction' do
|
21
|
+
statement = RDF::Statement(:s, RDF.type, :o)
|
22
|
+
expect(subject).to receive(:commit_transaction).and_call_original
|
23
|
+
|
24
|
+
expect do
|
25
|
+
subject.transaction(mutable: true) { insert(statement) }
|
26
|
+
end.to change { subject.statements }.to include(statement)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'rolls back a failed transaction' do
|
30
|
+
original_contents = subject.statements
|
31
|
+
expect(subject).to receive(:rollback_transaction).and_call_original
|
32
|
+
|
33
|
+
expect do
|
34
|
+
subject.transaction(mutable: true) do
|
35
|
+
delete(*@statements)
|
36
|
+
raise 'my error'
|
37
|
+
end
|
38
|
+
end.to raise_error RuntimeError
|
39
|
+
|
40
|
+
expect(subject.statements).to contain_exactly(*original_contents)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/rdf/spec/transaction.rb
CHANGED
@@ -2,118 +2,341 @@ require 'rdf/spec'
|
|
2
2
|
|
3
3
|
# Pass in an instance of RDF::Transaction as follows:
|
4
4
|
#
|
5
|
-
# it_behaves_like "RDF::Transaction", RDF::Transaction
|
5
|
+
# it_behaves_like "an RDF::Transaction", RDF::Transaction
|
6
6
|
shared_examples "an RDF::Transaction" do |klass|
|
7
7
|
include RDF::Spec::Matchers
|
8
8
|
|
9
|
-
|
9
|
+
before do
|
10
|
+
raise 'repository must be set with `let(:repository)' unless
|
11
|
+
defined? repository
|
12
|
+
end
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
subject { klass.new(repository, mutable: true) }
|
15
|
+
|
16
|
+
it { is_expected.to be_readable }
|
17
|
+
it { is_expected.to be_queryable }
|
18
|
+
|
19
|
+
context "when querying statements" do
|
20
|
+
require 'rdf/spec/queryable'
|
21
|
+
let(:queryable) do
|
22
|
+
repository.insert(*RDF::Spec.quads)
|
23
|
+
klass.new(repository)
|
24
|
+
end
|
25
|
+
it_behaves_like 'an RDF::Queryable'
|
26
|
+
|
27
|
+
context 'with a graph_name' do
|
28
|
+
let(:queryable) do
|
29
|
+
graph_name = RDF::URI('http://example.com/g')
|
30
|
+
graph = RDF::Graph.new(graph_name: graph_name, data: repository)
|
31
|
+
graph.insert(*RDF::Spec.quads)
|
32
|
+
klass.new(repository, graph_name: graph_name)
|
33
|
+
end
|
34
|
+
it_behaves_like 'an RDF::Queryable'
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with a false graph_name' do
|
38
|
+
let(:queryable) do
|
39
|
+
graph = RDF::Graph.new(data: repository)
|
40
|
+
graph.insert(*RDF::Spec.quads)
|
41
|
+
graph_name = false
|
42
|
+
klass.new(repository, graph_name: graph_name)
|
43
|
+
end
|
44
|
+
it_behaves_like 'an RDF::Queryable'
|
17
45
|
end
|
46
|
+
end
|
18
47
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
expect(this.context).to eq c
|
48
|
+
describe "#initialize" do
|
49
|
+
it 'accepts a repository' do
|
50
|
+
repo = double('repository')
|
51
|
+
allow(repo).to receive_messages(:supports? => false)
|
24
52
|
|
25
|
-
|
26
|
-
expect(this.graph).to eq c
|
27
|
-
expect(this.context).to eq c
|
53
|
+
expect(klass.new(repo).repository).to eq repo
|
28
54
|
end
|
29
55
|
|
30
|
-
it
|
31
|
-
|
32
|
-
|
33
|
-
expect(this.graph).to eq c
|
34
|
-
expect(this.graph_name).to eq c
|
56
|
+
it 'defaults immutable (read only)' do
|
57
|
+
expect(klass.new(repository).mutable?).to be false
|
58
|
+
end
|
35
59
|
|
36
|
-
|
37
|
-
expect(
|
38
|
-
expect(this.graph_name).to eq c
|
60
|
+
it 'allows mutability' do
|
61
|
+
expect(klass.new(repository, mutable: true)).to be_mutable
|
39
62
|
end
|
40
63
|
|
41
|
-
it
|
42
|
-
|
43
|
-
|
44
|
-
expect(
|
64
|
+
it 'accepts a graph_name' do
|
65
|
+
graph_uri = RDF::URI('http://example.com/graph_1')
|
66
|
+
|
67
|
+
expect(klass.new(repository, graph_name: graph_uri).graph_name)
|
68
|
+
.to eq graph_uri
|
45
69
|
end
|
46
70
|
|
47
|
-
it
|
48
|
-
|
49
|
-
this = subject.new(delete: g)
|
50
|
-
expect(this.deletes).to eq g
|
71
|
+
it 'defaults graph_name to nil' do
|
72
|
+
expect(klass.new(repository).graph_name).to be_nil
|
51
73
|
end
|
52
74
|
end
|
53
75
|
|
54
|
-
its(:deletes) {is_expected.to be_a(RDF::Enumerable)}
|
55
|
-
its(:inserts) {is_expected.to be_a(RDF::Enumerable)}
|
56
|
-
it {is_expected.to be_mutable}
|
57
|
-
it {is_expected.to_not be_readable}
|
58
|
-
|
59
76
|
it "does not respond to #load" do
|
60
|
-
expect {subject.load("http://example/")}.to raise_error(NoMethodError)
|
77
|
+
expect { subject.load("http://example/") }.to raise_error(NoMethodError)
|
61
78
|
end
|
62
79
|
|
63
80
|
it "does not respond to #update" do
|
64
|
-
expect {subject.update(RDF::Statement.new)}.to raise_error(NoMethodError)
|
81
|
+
expect { subject.update(RDF::Statement.new) }.to raise_error(NoMethodError)
|
65
82
|
end
|
66
83
|
|
67
84
|
it "does not respond to #clear" do
|
68
|
-
expect {subject.clear}.to raise_error(NoMethodError)
|
85
|
+
expect { subject.clear }.to raise_error(NoMethodError)
|
69
86
|
end
|
70
87
|
|
71
|
-
describe
|
72
|
-
|
73
|
-
|
88
|
+
describe '#changes' do
|
89
|
+
it 'is a changeset' do
|
90
|
+
expect(subject.changes).to be_a RDF::Changeset
|
91
|
+
end
|
74
92
|
|
75
|
-
it
|
76
|
-
expect(
|
77
|
-
expect(r).not_to receive(:insert)
|
78
|
-
subject.delete(s)
|
79
|
-
subject.execute(r)
|
93
|
+
it 'is initially empty' do
|
94
|
+
expect(subject.changes).to be_empty
|
80
95
|
end
|
96
|
+
end
|
81
97
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
98
|
+
describe "#delete" do
|
99
|
+
let(:st) { RDF::Statement(:s, RDF::URI('http://example.com/p'), 'o') }
|
100
|
+
|
101
|
+
it 'adds to deletes' do
|
102
|
+
repository.insert(st)
|
103
|
+
|
104
|
+
expect do
|
105
|
+
subject.delete(st)
|
106
|
+
subject.execute
|
107
|
+
end.to change { subject.repository.empty? }.from(false).to(true)
|
87
108
|
end
|
88
109
|
|
89
|
-
it
|
90
|
-
|
91
|
-
|
110
|
+
it 'adds multiple to deletes' do
|
111
|
+
sts = [st] << RDF::Statement(:x, RDF::URI('http://example.com/y'), 'z')
|
112
|
+
repository.insert(*sts)
|
113
|
+
|
114
|
+
expect do
|
115
|
+
subject.delete(*sts)
|
116
|
+
subject.execute
|
117
|
+
end.to change { subject.repository.empty? }.from(false).to(true)
|
92
118
|
end
|
93
119
|
|
94
|
-
it
|
95
|
-
|
96
|
-
|
120
|
+
it 'adds enumerable to deletes' do
|
121
|
+
sts = [st] << RDF::Statement(:x, RDF::URI('http://example.com/y'), 'z')
|
122
|
+
sts.extend(RDF::Enumerable)
|
123
|
+
repository.insert(sts)
|
124
|
+
|
125
|
+
expect do
|
126
|
+
subject.delete(sts)
|
127
|
+
subject.execute
|
128
|
+
end.to change { subject.repository.empty? }.from(false).to(true)
|
97
129
|
end
|
98
130
|
|
99
|
-
|
100
|
-
|
131
|
+
context 'with a graph_name' do
|
132
|
+
subject { klass.new(repository, mutable: true, graph_name: graph_uri) }
|
133
|
+
|
134
|
+
let(:graph_uri) { RDF::URI('http://example.com/graph_1') }
|
135
|
+
|
136
|
+
it 'adds the graph_name to statements' do
|
137
|
+
repository.insert(st)
|
138
|
+
with_name = st.dup
|
139
|
+
with_name.graph_name = graph_uri
|
140
|
+
repository.insert(with_name)
|
141
|
+
|
142
|
+
expect do
|
143
|
+
subject.delete(st)
|
144
|
+
subject.execute
|
145
|
+
end.to change { subject.repository.statements }
|
146
|
+
|
147
|
+
expect(subject.repository).not_to have_statement(with_name)
|
148
|
+
expect(subject.repository).to have_statement(st)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'overwrites existing graph names' do
|
152
|
+
st.graph_name = RDF::URI('http://example.com/g')
|
153
|
+
repository.insert(st)
|
154
|
+
|
155
|
+
expect do
|
156
|
+
subject.delete(st)
|
157
|
+
subject.execute
|
158
|
+
end.not_to change { subject.repository.statements }
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'overwrites existing default graph name' do
|
162
|
+
st.graph_name = false
|
163
|
+
|
164
|
+
repository.insert(st)
|
165
|
+
|
166
|
+
expect do
|
167
|
+
subject.delete(st)
|
168
|
+
subject.execute
|
169
|
+
end.not_to change { subject.repository.statements }
|
170
|
+
end
|
101
171
|
end
|
102
172
|
end
|
103
173
|
|
104
|
-
describe "#
|
105
|
-
let(:
|
106
|
-
|
107
|
-
|
108
|
-
expect
|
174
|
+
describe "#insert" do
|
175
|
+
let(:st) { RDF::Statement(:s, RDF::URI('http://example.com/p'), 'o') }
|
176
|
+
|
177
|
+
it 'adds to inserts' do
|
178
|
+
expect do
|
179
|
+
subject.insert(st)
|
180
|
+
subject.execute
|
181
|
+
end.to change { subject.repository.statements }
|
182
|
+
.to contain_exactly(st)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'adds multiple to inserts' do
|
186
|
+
sts = [st] << RDF::Statement(:x, RDF::URI('http://example.com/y'), 'z')
|
187
|
+
|
188
|
+
expect do
|
189
|
+
subject.insert(*sts)
|
190
|
+
subject.execute
|
191
|
+
end.to change { subject.repository.statements }
|
192
|
+
.to contain_exactly(*sts)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'adds enumerable to inserts' do
|
196
|
+
sts = [st] << RDF::Statement(:x, RDF::URI('http://example.com/y'), 'z')
|
197
|
+
sts.extend(RDF::Enumerable)
|
198
|
+
|
199
|
+
expect do
|
200
|
+
subject.insert(sts)
|
201
|
+
subject.execute
|
202
|
+
end.to change { subject.repository.statements }
|
203
|
+
.to contain_exactly(*sts)
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'with a graph_name' do
|
207
|
+
subject { klass.new(repository, mutable: true, graph_name: graph_uri) }
|
208
|
+
|
209
|
+
let(:graph_uri) { RDF::URI('http://example.com/graph_1') }
|
210
|
+
|
211
|
+
it 'adds the graph_name to statements' do
|
212
|
+
with_name = st.dup
|
213
|
+
with_name.graph_name = graph_uri
|
214
|
+
|
215
|
+
expect do
|
216
|
+
subject.insert(st)
|
217
|
+
subject.execute
|
218
|
+
end.to change { subject.repository }
|
219
|
+
|
220
|
+
expect(subject.repository).to have_statement(with_name)
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'overwrites existing graph names' do
|
224
|
+
st.graph_name = RDF::URI('http://example.com/g')
|
225
|
+
with_name = st.dup
|
226
|
+
with_name.graph_name = graph_uri
|
227
|
+
|
228
|
+
expect do
|
229
|
+
subject.insert(st)
|
230
|
+
subject.execute
|
231
|
+
end.to change { subject.repository.statements }
|
232
|
+
|
233
|
+
expect(subject.repository).not_to have_statement(st)
|
234
|
+
expect(subject.repository).to have_statement(with_name)
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'overwrites existing default graph name' do
|
238
|
+
st.graph_name = false
|
239
|
+
with_name = st.dup
|
240
|
+
with_name.graph_name = graph_uri
|
241
|
+
|
242
|
+
expect do
|
243
|
+
subject.insert(st)
|
244
|
+
subject.execute
|
245
|
+
end.to change { subject.repository.statements }
|
246
|
+
|
247
|
+
expect(subject.repository).not_to have_statement(st)
|
248
|
+
expect(subject.repository).to have_statement(with_name)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe '#execute' do
|
254
|
+
let(:st) { RDF::Statement(:s, RDF::URI('http://example.com/p'), 'o') }
|
255
|
+
|
256
|
+
context 'after rollback' do
|
257
|
+
before { subject.rollback }
|
258
|
+
|
259
|
+
it 'does not execute' do
|
260
|
+
expect { subject.execute }
|
261
|
+
.to raise_error RDF::Transaction::TransactionError
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'when :read_committed' do
|
266
|
+
it 'does not read uncommitted statements' do
|
267
|
+
unless subject.isolation_level == :read_uncommitted
|
268
|
+
read_tx = klass.new(repository, mutable: true)
|
269
|
+
subject.insert(st)
|
270
|
+
|
271
|
+
expect(read_tx.statements).not_to include(st)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'reads committed statements' do
|
276
|
+
if subject.isolation_level == :read_committed
|
277
|
+
read_tx = klass.new(repository)
|
278
|
+
subject.insert(st)
|
279
|
+
subject.execute
|
280
|
+
|
281
|
+
expect(read_tx.statements).to include(st)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
context 'when :repeatable_read' do
|
287
|
+
it 'does not read committed statements already read' do
|
288
|
+
if subject.isolation_level == :repeatable_read ||
|
289
|
+
subject.isolation_level == :snapshot ||
|
290
|
+
subject.isolation_level == :serializable
|
291
|
+
read_tx = klass.new(repository)
|
292
|
+
subject.insert(st)
|
293
|
+
subject.execute
|
294
|
+
|
295
|
+
expect(read_tx.statements).not_to include(st)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
context 'when :snapshot' do
|
301
|
+
it 'does not read committed statements' do
|
302
|
+
if subject.isolation_level == :snapshot ||
|
303
|
+
subject.isolation_level == :serializable
|
304
|
+
read_tx = klass.new(repository)
|
305
|
+
subject.insert(st)
|
306
|
+
subject.execute
|
307
|
+
|
308
|
+
expect(read_tx.statements).not_to include(st)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
it 'reads current transaction state' do
|
313
|
+
if subject.isolation_level == :snapshot ||
|
314
|
+
subject.isolation_level == :serializable
|
315
|
+
subject.insert(st)
|
316
|
+
expect(subject.statements).to include(st)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
context 'when :serializable' do
|
322
|
+
it 'raises an error if conflicting changes are present' do
|
323
|
+
if subject.isolation_level == :serializable
|
324
|
+
subject.insert(st)
|
325
|
+
repository.insert(st)
|
326
|
+
|
327
|
+
expect { subject.execute }
|
328
|
+
.to raise_error RDF::Transaction::TransactionError
|
329
|
+
end
|
330
|
+
end
|
109
331
|
end
|
110
332
|
end
|
111
333
|
|
112
|
-
describe
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
334
|
+
describe '#rollback' do
|
335
|
+
before { subject.insert(st); subject.delete(st) }
|
336
|
+
let(:st) { RDF::Statement(:s, RDF::URI('http://example.com/p'), 'o') }
|
337
|
+
|
338
|
+
it 'empties changes when available' do
|
339
|
+
expect { subject.rollback }.to change { subject.changes }.to be_empty
|
117
340
|
end
|
118
341
|
end
|
119
342
|
end
|