nfcollector 3.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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.rvmrc +1 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/nfcollector.rb +41 -0
- data/lib/nfcollector/attribute_validator.rb +59 -0
- data/lib/nfcollector/attributes.rb +99 -0
- data/lib/nfcollector/categoriser.rb +43 -0
- data/lib/nfcollector/category_partition.rb +17 -0
- data/lib/nfcollector/configuration.rb +24 -0
- data/lib/nfcollector/copy_file_writer.rb +47 -0
- data/lib/nfcollector/domain_parser.rb +49 -0
- data/lib/nfcollector/input_definition.rb +31 -0
- data/lib/nfcollector/mapping.rb +7 -0
- data/lib/nfcollector/mapping/categories_processor.rb +36 -0
- data/lib/nfcollector/mapping/column_transpiler.rb +29 -0
- data/lib/nfcollector/mapping/default_output.rb +45 -0
- data/lib/nfcollector/mapping/effective_tld_names.dat +4394 -0
- data/lib/nfcollector/mapping/indexer.rb +21 -0
- data/lib/nfcollector/mapping/mapped_row.rb +21 -0
- data/lib/nfcollector/mapping/output.rb +59 -0
- data/lib/nfcollector/mapping/transpiler.rb +92 -0
- data/lib/nfcollector/nfcollector_exception.rb +4 -0
- data/lib/nfcollector/partition.rb +76 -0
- data/lib/nfcollector/partitioner.rb +37 -0
- data/lib/nfcollector/payload_processor.rb +46 -0
- data/lib/nfcollector/sequence_generator.rb +11 -0
- data/lib/nfcollector/version.rb +3 -0
- data/lib/nfcollector/weblog_partition.rb +26 -0
- data/nfcollector.gemspec +30 -0
- data/spec/attribute_validator_spec.rb +23 -0
- data/spec/attributes_spec.rb +15 -0
- data/spec/command_parser_spec.rb +81 -0
- data/spec/copy_file_writer_spec.rb +95 -0
- data/spec/input_definition_spec.rb +18 -0
- data/spec/nfcollector/category_partitioner_spec.rb +51 -0
- data/spec/nfcollector/date_partitioner_spec.rb +19 -0
- data/spec/nfcollector/input_definition_spec.rb +32 -0
- data/spec/nfcollector/mapping/column_transpiler_spec.rb +26 -0
- data/spec/nfcollector/mapping/output_spec.rb +76 -0
- data/spec/nfcollector/mapping/transpiler_spec.rb +47 -0
- data/spec/payload_job_spec.rb +11 -0
- data/spec/payload_processor_spec.rb +114 -0
- data/spec/spec_helper.rb +89 -0
- data/test/domains_hosts +194826 -0
- data/test/generate_input.rb +79 -0
- data/test/input/input-1000.csv +1000 -0
- data/test/input/input-100000.csv +100000 -0
- data/test/input/input-100000.dat +64039 -0
- data/test/input/input-no-tags.csv +3 -0
- data/test/input/input-no-tags.dat +3 -0
- data/test/input/input-no-tags.gz +0 -0
- data/test/input/input-with-tags.csv.gz +0 -0
- data/test/test_helper.rb +15 -0
- data/test/tester.rb +32 -0
- metadata +252 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nfcollector::Attributes do
|
4
|
+
describe '::parse' do
|
5
|
+
let(:attributes_string) { '>a,Rh,Rp' }
|
6
|
+
subject { described_class.parse(attributes_string) }
|
7
|
+
|
8
|
+
specify do
|
9
|
+
expect(subject).to be_a(Nfcollector::InputDefinition)
|
10
|
+
expect(subject.column_index(:client_ip)).to eq(0)
|
11
|
+
expect(subject.column_index(:host)).to eq(1)
|
12
|
+
expect(subject.column_index(:path)).to eq(2)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nfcollector::CommandParser do
|
4
|
+
|
5
|
+
describe "Instance" do
|
6
|
+
specify "raise if account_id is not an int" do
|
7
|
+
expect {
|
8
|
+
cp = described_class.new("abc", "/file/path", ">a")
|
9
|
+
cp.validate!
|
10
|
+
}.to raise_error(Nfcollector::InvalidCommand, "Account ID is not an Integer")
|
11
|
+
end
|
12
|
+
|
13
|
+
specify "raise if file not found" do
|
14
|
+
allow(File).to receive(:file?).and_return(false)
|
15
|
+
expect {
|
16
|
+
cp = described_class.new(10, "/file/path", ">a")
|
17
|
+
cp.validate!
|
18
|
+
}.to raise_error(Nfcollector::InvalidCommand, "No such file for payload")
|
19
|
+
end
|
20
|
+
|
21
|
+
specify "raise if attributes are not valid" do
|
22
|
+
allow(File).to receive(:file?).and_return(true)
|
23
|
+
allow(
|
24
|
+
Nfcollector::AttributeValidator
|
25
|
+
).to receive(:validate!).
|
26
|
+
with(">a").and_raise(Nfcollector::UnknownAttribute)
|
27
|
+
|
28
|
+
expect {
|
29
|
+
cp = described_class.new(10, "/file/path", 'X')
|
30
|
+
cp.validate!
|
31
|
+
}.to raise_error(Nfcollector::UnknownAttribute)
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "raise if attributes are missing" do
|
35
|
+
allow(File).to receive(:file?).and_return(true)
|
36
|
+
expect {
|
37
|
+
cp = described_class.new(10, "/file/path", nil)
|
38
|
+
cp.validate!
|
39
|
+
}.to raise_error(Nfcollector::InvalidCommand)
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "raise if attributes are empty" do
|
43
|
+
allow(File).to receive(:file?).and_return(true)
|
44
|
+
expect {
|
45
|
+
cp = described_class.new(10, "/file/path", "")
|
46
|
+
cp.validate!
|
47
|
+
}.to raise_error(Nfcollector::InvalidCommand)
|
48
|
+
end
|
49
|
+
|
50
|
+
specify "not raise if data is correct (string account id)" do
|
51
|
+
allow(File).to receive(:file?).and_return(true)
|
52
|
+
allow(Nfcollector::AttributeValidator).to receive(:validate!).and_return(true)
|
53
|
+
cp = described_class.new("100", "/file/path", Nfcollector::Attributes::REQUIRED.join(','))
|
54
|
+
cp.validate!
|
55
|
+
end
|
56
|
+
|
57
|
+
specify "not raise if data is correct (numeric account id)" do
|
58
|
+
allow(File).to receive(:file?).and_return(true)
|
59
|
+
allow(Nfcollector::AttributeValidator).to receive(:validate!).and_return(true)
|
60
|
+
expect {
|
61
|
+
cp = described_class.new(100, "/file/path", Nfcollector::Attributes::REQUIRED.join(','))
|
62
|
+
cp.validate!
|
63
|
+
}.to_not raise_error
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "Class" do
|
68
|
+
specify "raise if not all tokens are provided" do
|
69
|
+
expect {
|
70
|
+
described_class.parse("10:")
|
71
|
+
}.to raise_error(Nfcollector::InvalidCommand)
|
72
|
+
end
|
73
|
+
|
74
|
+
specify "validate! provided tokens" do
|
75
|
+
cp = stub(:parser)
|
76
|
+
expect(cp).to receive(:validate)
|
77
|
+
expect(described_class).to receive(:new).with(10, '/foo/bar', '>a').and_return(cp)
|
78
|
+
described_class.parse("10:/foo/bar:>a")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nfcollector::CopyFileWriter do
|
4
|
+
describe "Adding rows" do
|
5
|
+
# TODO: Test too few columns as well? Will this just result in NULLs?
|
6
|
+
specify "ignore additional data if a row is added that has more columns set in the constructor" do
|
7
|
+
expect {
|
8
|
+
copy = described_class.new(%w(created_at username bytes), 10, 0)
|
9
|
+
copy.add_row([Time.now, "daniel", 1000, "foo"])
|
10
|
+
}.to_not raise_error
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Table Name" do
|
15
|
+
# be correct for the given date" do
|
16
|
+
pending "Something needs to happen here but I don't know what"
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "File Name" do
|
20
|
+
specify "that it is correct" do
|
21
|
+
Nfcollector::Configuration.output_dir = "/tmp/"
|
22
|
+
date = stub(:date)
|
23
|
+
copy = described_class.new(%w(created_at username bytes), 10, 0)
|
24
|
+
expect(copy).to receive(:table_name).and_return("mocked_table_name")
|
25
|
+
allow(copy).to receive(:randstr).and_return('randstr')
|
26
|
+
expect(copy.file_name(Date.today)).to eq("/tmp/mocked_table_name_randstr.copy")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "Writing" do
|
31
|
+
before do
|
32
|
+
allow_any_instance_of(described_class).to receive(:table_name).and_return('mocked_table_name')
|
33
|
+
Timecop.freeze(Time.new(2011, 7, 11, 0, 0, 0, "+10:00"))
|
34
|
+
end
|
35
|
+
|
36
|
+
after do
|
37
|
+
Timecop.return
|
38
|
+
end
|
39
|
+
|
40
|
+
specify "write the file" do
|
41
|
+
copy = described_class.new(%w(created_at username bytes), 10, 0)
|
42
|
+
copy.add_row([Time.now.utc, "daniel", 1000])
|
43
|
+
io = StringIO.new
|
44
|
+
expect(File).to receive(:open).and_yield(io)
|
45
|
+
allow(copy).to receive(:randstr).and_return('randstr')
|
46
|
+
expect(FileUtils).to receive(:mv).with('/tmp/mocked_table_name_randstr.copy.lock', '/tmp/mocked_table_name_randstr.copy')
|
47
|
+
copy.write
|
48
|
+
expect(io.string).to eq <<-COPY
|
49
|
+
-- Created at: 2011-07-10 14:00:00 UTC
|
50
|
+
COPY mocked_table_name (created_at,username,bytes) FROM stdin WITH csv;
|
51
|
+
"2011-07-10 14:00:00 UTC","daniel","1000"
|
52
|
+
COPY
|
53
|
+
end
|
54
|
+
|
55
|
+
specify "write the file and handle NULLs" do
|
56
|
+
copy = described_class.new(%w(created_at username bytes user_group), 10, 0)
|
57
|
+
copy.add_row([Time.now.utc, 'daniel', '1000', nil])
|
58
|
+
io = StringIO.new
|
59
|
+
expect(File).to receive(:open).and_yield(io)
|
60
|
+
expect(copy).to receive(:randstr).and_return('randstr')
|
61
|
+
expect(FileUtils).to receive(:mv).with('/tmp/mocked_table_name_randstr.copy.lock', '/tmp/mocked_table_name_randstr.copy')
|
62
|
+
copy.write
|
63
|
+
expect(io.string).to eq <<-COPY
|
64
|
+
-- Created at: 2011-07-10 14:00:00 UTC
|
65
|
+
COPY mocked_table_name (created_at,username,bytes,user_group) FROM stdin WITH csv;
|
66
|
+
"2011-07-10 14:00:00 UTC","daniel","1000",""
|
67
|
+
COPY
|
68
|
+
end
|
69
|
+
|
70
|
+
specify "delete the resultant file if there is an exception" do
|
71
|
+
copy = described_class.new(%w(created_at username bytes user_group), 10, 0)
|
72
|
+
copy.add_row([Time.now, 'daniel', '1000', nil])
|
73
|
+
expect(CSV).to receive(:new).and_raise(RuntimeError)
|
74
|
+
allow(File).to receive(:file?).and_return(true)
|
75
|
+
expect(File).to receive(:delete)
|
76
|
+
expect { copy.write }.to raise_error(RuntimeError)
|
77
|
+
end
|
78
|
+
|
79
|
+
specify "raise if there are no rows" do
|
80
|
+
copy = described_class.new(%w(created_at username bytes user_group), 10, 0)
|
81
|
+
expect { copy.write }.to raise_error(Nfcollector::FileEmpty)
|
82
|
+
end
|
83
|
+
|
84
|
+
# TODO: This is not tested effectively
|
85
|
+
specify "return false if a new copy file should be generated (date barrier)" do
|
86
|
+
copy = described_class.new(%w(created_at username bytes), 10, 0)
|
87
|
+
copy.add_row([Time.gm(2011, 7, 11, 0, 0, 0), 'daniel', '1000'])
|
88
|
+
copy.add_row([Time.gm(2011, 7, 12, 0, 0, 0), 'daniel', '1000'])
|
89
|
+
allow(copy).to receive(:randstr).and_return('randstr')
|
90
|
+
expect(FileUtils).to receive(:mv).with('/tmp/mocked_table_name_randstr.copy.lock', '/tmp/mocked_table_name_randstr.copy').twice
|
91
|
+
expect(File).to receive(:open).twice
|
92
|
+
copy.write
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nfcollector::InputDefinition do
|
4
|
+
describe '#set' do
|
5
|
+
let(:definition) { described_class.new }
|
6
|
+
before { definition.set(1, :username) }
|
7
|
+
|
8
|
+
specify do
|
9
|
+
expect(definition.column_index(:username)).to eq(1)
|
10
|
+
end
|
11
|
+
|
12
|
+
specify 'that an error is raised if there is no index for the column' do
|
13
|
+
expect {
|
14
|
+
definition.column_index(:foo)
|
15
|
+
}.to raise_error(Nfcollector::InputDefinition::MissingDefinition)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nfcollector::CategoryPartitioner do
|
4
|
+
let(:partitioner) { described_class.new(2) }
|
5
|
+
|
6
|
+
describe '#partition_id' do
|
7
|
+
subject { partitioner.partition_id(row) }
|
8
|
+
|
9
|
+
context 'both columns available' do
|
10
|
+
let(:row) { %w(1000 100 10) }
|
11
|
+
specify { expect(subject).to eq('10') }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#add_row' do
|
16
|
+
let(:row) { %w(1000 100 10) }
|
17
|
+
subject { partitioner }
|
18
|
+
|
19
|
+
before { subject.add_row(row) }
|
20
|
+
|
21
|
+
specify do
|
22
|
+
expect(subject.data).to eq({
|
23
|
+
'10' => [row]
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'adding a second row with the same partition id' do
|
28
|
+
let(:row2) { %w(1001 100 10) }
|
29
|
+
before { subject.add_row(row2) }
|
30
|
+
|
31
|
+
specify do
|
32
|
+
expect(subject.data).to eq({
|
33
|
+
'10' => [row, row2]
|
34
|
+
})
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'adding a second row with the a different partition id' do
|
39
|
+
let(:row3) { %w(1001 100 11) }
|
40
|
+
before { subject.add_row(row3) }
|
41
|
+
|
42
|
+
specify do
|
43
|
+
expect(subject.data).to eq({
|
44
|
+
'10' => [row],
|
45
|
+
'11' => [row3]
|
46
|
+
})
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nfcollector::DatePartitioner do
|
4
|
+
let(:partitioner) { described_class.new(2) }
|
5
|
+
|
6
|
+
describe '#partition_id' do
|
7
|
+
subject { partitioner.partition_id(row) }
|
8
|
+
|
9
|
+
context 'the timestamp in UTC is on the same day' do
|
10
|
+
let(:row) { [ 1000, 100, '2014-06-16 10:29:52 +1000'.to_time ] }
|
11
|
+
specify { expect(subject.to_s).to eq('2014-06-16') }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'the timestamp in UTC is on the previous day' do
|
15
|
+
let(:row) { [ 1000, 100, '2014-06-16 9:29:52 +1000'.to_time ] }
|
16
|
+
specify { expect(subject.to_s).to eq('2014-06-15') }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nfcollector::InputDefinition do
|
4
|
+
let(:input) { described_class.new }
|
5
|
+
|
6
|
+
describe '#set' do
|
7
|
+
before { input.set(0, :username) }
|
8
|
+
specify { expect(input.column_index(:username)).to eq(0) }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#has_index_for?' do
|
12
|
+
context 'no column present' do
|
13
|
+
specify { expect(input.has_index_for?(:username)).to be(false) }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'column is present' do
|
17
|
+
before { input.set(0, :username) }
|
18
|
+
specify { expect(input.has_index_for?(:username)).to be(true) }
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'mulitple columns present' do
|
22
|
+
before do
|
23
|
+
input.set(0, :username)
|
24
|
+
input.set(1, :client_ip)
|
25
|
+
end
|
26
|
+
|
27
|
+
specify do
|
28
|
+
expect(input.has_index_for?([:username, :client_ip])).to be(true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nfcollector::Mapping::ColumnTranspiler do
|
4
|
+
let(:output) { Nfcollector::Mapping::Output.new(:username) }
|
5
|
+
let(:input_row) { [ '2013-10-10 00:30', 'daniel' ] }
|
6
|
+
subject(:column_transpiler) { described_class.new(output) }
|
7
|
+
|
8
|
+
describe '#go' do
|
9
|
+
context 'not yet built' do
|
10
|
+
specify do
|
11
|
+
expect {
|
12
|
+
subject.go(input_row)
|
13
|
+
}.to raise_error(Nfcollector::Mapping::ColumnTranspiler::NotYetBuilt)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'has been built' do
|
18
|
+
let(:input_definition) { Nfcollector::Attributes.parse('t,Un') }
|
19
|
+
before { subject.build(input_definition) }
|
20
|
+
|
21
|
+
specify do
|
22
|
+
expect(subject.go(input_row)).to eq('daniel')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nfcollector::Mapping::Output do
|
4
|
+
describe 'class DSL' do
|
5
|
+
describe 'base state' do
|
6
|
+
before do
|
7
|
+
class MyMapperA < Nfcollector::Mapping::Output; end
|
8
|
+
end
|
9
|
+
|
10
|
+
specify { expect(MyMapperA.outputs).to eq([]) }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'with outputs defined' do
|
14
|
+
before do
|
15
|
+
class MyMapperB < Nfcollector::Mapping::Output
|
16
|
+
output :created_at
|
17
|
+
output :username
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
specify do
|
22
|
+
expect(MyMapperB.outputs.size).to eq(2)
|
23
|
+
expect(MyMapperB.outputs.first).to be_a(Nfcollector::Mapping::Output)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#compile' do
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#initialize' do
|
33
|
+
context 'defaults' do
|
34
|
+
subject { described_class.new(:username) }
|
35
|
+
|
36
|
+
specify do
|
37
|
+
expect(subject.name).to eq(:username)
|
38
|
+
expect(subject.inputs).to eq([:username])
|
39
|
+
expect(subject.process_with).to eq(:username)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'one using specific input' do
|
44
|
+
subject { described_class.new(:username, inputs: :user) }
|
45
|
+
specify { expect(subject.inputs).to eq([:user]) }
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'several specific inputs' do
|
49
|
+
subject { described_class.new(:username, inputs: [:user, :group]) }
|
50
|
+
specify { expect(subject.inputs).to eq([:user, :group]) }
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with a custom processing method' do
|
54
|
+
subject { described_class.new(:username, process_with: :do_stuff) }
|
55
|
+
specify { expect(subject.process_with).to eq(:do_stuff) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#optional' do
|
60
|
+
context 'unset' do
|
61
|
+
specify { expect(described_class.new(:username)).to_not be_optional }
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'set' do
|
65
|
+
specify { expect(described_class.new(:username, optional: true)).to be_optional }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#compile' do
|
70
|
+
pending
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#method_missing' do
|
74
|
+
pending
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nfcollector::Mapping::Transpiler do
|
4
|
+
# TODO: Rename to add_output
|
5
|
+
describe '#add_column' do
|
6
|
+
let(:transpiler) { described_class.new(input_definition) }
|
7
|
+
let(:input_definition) { Nfcollector::Attributes.parse('>a,Rh,Rp') }
|
8
|
+
subject { transpiler.add_column(output) }
|
9
|
+
|
10
|
+
context 'input definition has index for column' do
|
11
|
+
let(:output) { Nfcollector::Mapping::Output.new(:client_ip) }
|
12
|
+
|
13
|
+
specify 'that we add an output' do
|
14
|
+
expect { subject }.to change { transpiler.outputs.size }.by(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
specify 'that the added output is valid column transpiler' do
|
18
|
+
subject
|
19
|
+
expect(transpiler.outputs[0]).to be_a(Nfcollector::Mapping::ColumnTranspiler)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'input definition does not have index for column' do
|
24
|
+
context 'and output is required' do
|
25
|
+
let(:output) { Nfcollector::Mapping::Output.new(:username) }
|
26
|
+
|
27
|
+
specify 'that we DO NOT add an output' do
|
28
|
+
expect {
|
29
|
+
subject
|
30
|
+
}.to raise_error(Nfcollector::InputDefinition::MissingDefinition)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'and output is not required' do
|
35
|
+
let(:output) { Nfcollector::Mapping::Output.new(:username, optional: true) }
|
36
|
+
|
37
|
+
specify 'that we DO NOT add an output' do
|
38
|
+
expect { subject }.to_not change { transpiler.outputs.size }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#transpile' do
|
45
|
+
pending
|
46
|
+
end
|
47
|
+
end
|