congo 0.1.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.
Binary file
Binary file
@@ -0,0 +1,152 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/functional_spec_helper')
2
+
3
+ describe 'ContentType' do
4
+
5
+ before(:each) do
6
+ Account.destroy_all
7
+ Congo::ProxyScoper.destroy_all
8
+ Congo::ContentType.destroy_all
9
+
10
+ @account = Account.create(:email => 'layne_stanley@acme.org')
11
+ @website = Website.new(42, 'My simple website')
12
+ end
13
+
14
+ it 'should be valid' do
15
+ build_content_type.should be_valid
16
+ end
17
+
18
+ it 'should not be valid without a name' do
19
+ type = build_content_type(:name => nil)
20
+ type.should_not be_valid
21
+ type.errors.on(:name).should_not be_nil
22
+ type.errors.on(:collection_name).should_not be_nil
23
+ end
24
+
25
+ [' BlogPost ', ' My projects', 'active posts '].each do |name|
26
+ it "should be valid with name included leading or trailing spaces (#{name})" do
27
+ type = build_content_type(:name => name)
28
+ type.should be_valid
29
+ end
30
+ end
31
+
32
+ ['42BlogPosts', ' !cool', 'Great!', 'Super-PRoject43'].each do |name|
33
+ it "should not be valid with an invalid name (#{name})" do
34
+ type = build_content_type(:name => name)
35
+ type.should_not be_valid
36
+ type.errors.on(:name).should_not be_nil
37
+ end
38
+ end
39
+
40
+ it 'should be valid without a name but with a provided collection name' do
41
+ type = build_content_type(:name => nil, :collection_name => 'My projects')
42
+ type.should be_valid
43
+ type.name.should == "MyProject"
44
+ type.slug.should == "my_projects"
45
+ end
46
+
47
+ it 'should not valid if another content type with the same name' do
48
+ type_1 = build_content_type
49
+ type_1.save.should be_true
50
+
51
+ type_2 = build_content_type
52
+ type_2.should_not be_valid
53
+ type_2.errors.on(:name).should_not be_nil
54
+ type_2.name = 'Team'
55
+ type_2.should be_valid
56
+ end
57
+
58
+ it 'should not valid if the scoper instance already has a method identical to its name' do
59
+ type = build_content_type(:name => 'Person')
60
+ type.should_not be_valid
61
+ type.errors.on(:name).should_not be_nil
62
+
63
+ type = @website.content_types.build(:name => 'Page', :metadata_keys => [{ :name => 'title' }])
64
+ type.should_not be_valid
65
+ type.errors.on(:name).should_not be_nil
66
+
67
+ type.name = nil
68
+ type.collection_name = 'pages'
69
+ type.should_not be_valid
70
+ type.errors.on(:collection_name).should_not be_nil
71
+ end
72
+
73
+ it 'should not valid if another content type with the same collection name' do
74
+ type_1 = build_content_type(:name => nil, :collection_name => 'My projects')
75
+ type_1.save.should be_true
76
+
77
+ type_2 = build_content_type(:name => nil, :collection_name => 'My projects')
78
+ type_2.should_not be_valid
79
+ type_2.errors.on(:name).should_not be_nil
80
+ type_2.errors.on(:collection_name).should_not be_nil
81
+ type_2.name = nil
82
+ type_2.collection_name = 'My team'
83
+ type_2.should be_valid
84
+ end
85
+
86
+ it 'should not valid without keys' do
87
+ type = build_content_type(:metadata_keys => [])
88
+ type.should_not be_valid
89
+ type.errors.on(:metadata_keys).should_not be_nil
90
+ end
91
+
92
+ it 'should not be valid without a scope' do
93
+ type = build_content_type
94
+ type.scope = nil
95
+ type.should_not be_valid
96
+ type.errors.on(:scope).should_not be_nil
97
+ end
98
+
99
+ it 'should not be valid with 2 identical keys (same name)' do
100
+ type = build_content_type(:metadata_keys => [ { :name => 'name' }, { :name => 'name' }, { :name => 'description' } ])
101
+ type.should_not be_valid
102
+ type.errors.on(:metadata_keys).should_not be_nil
103
+ type.metadata_keys.first.should be_valid
104
+ type.metadata_keys.last.should be_valid
105
+ type.metadata_keys[1].errors.on(:name).should_not be_nil
106
+ end
107
+
108
+ it 'should be retrieved once saved' do
109
+ type = build_content_type
110
+ type.metadata_keys.should_not be_empty
111
+ type.save!.should be_true
112
+ type.save
113
+
114
+ type = type.reload
115
+ type.metadata_keys.size.should == 2
116
+ Congo::ContentType.first.metadata_keys.size.should == 2
117
+ end
118
+
119
+ it 'should remove contents as well when removed' do
120
+ type = build_content_type
121
+ type.save!
122
+ @account.projects.create(:name => 'project #1', :description => 'bla bla')
123
+ collection_name = type.send(:mongodb_collection_name)
124
+ MongoMapper.database.collection(collection_name).count.should == 1
125
+
126
+ another_type = build_content_type(:name => 'Foo')
127
+ another_type.save
128
+
129
+ @account = @account.reload
130
+ @account.content_types.count.should == 2
131
+
132
+ type.destroy
133
+
134
+ @account = @account.reload
135
+ @account.content_types.count.should == 1
136
+ MongoMapper.database.collection(collection_name).count.should == 0
137
+ @account.foos.count.should == 0
138
+ end
139
+
140
+ def build_content_type(options = {})
141
+ default_options = {
142
+ :name => 'Project',
143
+ :embedded => false,
144
+ :metadata_keys => [
145
+ { :name => 'name' },
146
+ { :name => 'description' }
147
+ ] }
148
+
149
+ @account.content_types.build(default_options.merge(options))
150
+ end
151
+
152
+ end
@@ -0,0 +1,11 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
+
3
+ MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {
4
+ :logger => Logger.new(TEST_DIR + '/test.log')
5
+ })
6
+ MongoMapper.database = 'congotest'
7
+
8
+ MongoMapper.database.collection_names.each do |collection|
9
+ next if collection == 'system.indexes'
10
+ MongoMapper.database.collection(collection).drop
11
+ end
@@ -0,0 +1,47 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/functional_spec_helper')
2
+
3
+ describe 'Grip' do
4
+
5
+ before(:each) do
6
+ Account.destroy_all
7
+ Congo::ContentType.destroy_all
8
+
9
+ @account = Account.create(:email => 'layne_stanley@acme.org')
10
+ end
11
+
12
+ it 'should attach a file to a content' do
13
+ create_content_type
14
+ developer = @account.developers.create({
15
+ :name => 'Layne Stanley',
16
+ :bio => 'foo bar',
17
+ :picture => open_file('avatar.jpeg')
18
+ })
19
+ developer.should be_valid
20
+ developer.picture_name.should == 'avatar.jpeg'
21
+ developer.picture_content_type.should == 'image/jpeg'
22
+ developer.picture_path.should == "developer/#{developer._id}"
23
+ end
24
+
25
+ def create_content_type(options = {})
26
+ type = build_content_type
27
+ type.save!
28
+ type
29
+ end
30
+
31
+ def build_content_type(options = {})
32
+ default_options = {
33
+ :name => 'Developer',
34
+ :embedded => false,
35
+ :metadata_keys => [
36
+ { :name => 'name', :type => 'String' },
37
+ { :name => 'bio', :type => 'Text' },
38
+ { :name => 'picture', :type => 'File' }
39
+ ] }
40
+
41
+ @account.content_types.build(default_options.merge(options))
42
+ end
43
+
44
+ def open_file(name)
45
+ File.open(File.join(File.dirname(__FILE__), '..', 'assets', name))
46
+ end
47
+ end
@@ -0,0 +1,94 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/functional_spec_helper')
2
+
3
+ describe 'Key' do
4
+
5
+ before(:each) do
6
+ I18n.locale = :en
7
+
8
+ Account.destroy_all
9
+ Congo::ContentType.destroy_all
10
+
11
+ @account = Account.create(:email => 'layne_stanley@acme.org')
12
+ end
13
+
14
+ it 'should add items' do
15
+ create_content_type
16
+
17
+ person = build_person
18
+ person.valid?.should be_true
19
+ person.name.should == 'Layne Stanley'
20
+ person.bio.should == "That's great"
21
+ person.email.should == 'layne_stanley@acme.org'
22
+ person.save
23
+
24
+ @account = Account.first # hard reload
25
+ person = @account.developers.first
26
+ person.email.should == 'layne_stanley@acme.org'
27
+ end
28
+
29
+ it 'should not add items with invalid data (incorrect e-mail)' do
30
+ create_content_type
31
+
32
+ person = build_person(:email => 'layne_stanley-acme.org')
33
+ person.valid?.should be_false
34
+ person.errors.on(:email).should_not be_nil
35
+ end
36
+
37
+ it 'should convert date into the locale' do
38
+ create_content_type
39
+ person = build_person
40
+ person.save
41
+
42
+ @account = Account.first # hard reload
43
+ person = @account.developers.first
44
+ person.birthday.strftime(I18n.t('congo.date.formats.default')).should == '06/28/1979'
45
+
46
+ I18n.locale = :fr
47
+ person.birthday.strftime(I18n.t('congo.date.formats.default')).should == '28/06/1979'
48
+
49
+ person.birthday = '16/09/1982'
50
+ person.save
51
+
52
+ @account = Account.first # hard reload
53
+ person = @account.developers.first
54
+ person.birthday.strftime(I18n.t('congo.date.formats.default')).should == '16/09/1982'
55
+ person.localized_birthday.should == '16/09/1982'
56
+
57
+ person.localized_birthday = '29/06/2007'
58
+ person.save
59
+ @account = Account.first # hard reload
60
+ person = @account.developers.first
61
+ person.localized_birthday.should == '29/06/2007'
62
+ end
63
+
64
+ def create_content_type(options = {})
65
+ type = build_content_type
66
+ type.save!
67
+ type
68
+ end
69
+
70
+ def build_content_type(options = {})
71
+ default_options = {
72
+ :name => 'Developer',
73
+ :embedded => false,
74
+ :metadata_keys => [
75
+ { :name => 'name', :type => 'String' },
76
+ { :name => 'bio', :type => 'Text' },
77
+ { :name => 'email', :type => 'Email' },
78
+ { :name => 'birthday', :type => 'Date' }
79
+ ] }
80
+
81
+ @account.content_types.build(default_options.merge(options))
82
+ end
83
+
84
+ def build_person(options = {})
85
+ attributes = {
86
+ :name => 'Layne Stanley',
87
+ :bio => "That's great",
88
+ :email => 'layne_stanley@acme.org',
89
+ :birthday => '06/28/1979'
90
+ }
91
+ @account.developers.build attributes.merge(options)
92
+ end
93
+
94
+ end
@@ -0,0 +1,67 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/functional_spec_helper')
2
+
3
+ describe 'List' do
4
+
5
+ before(:all) do
6
+ class Congo::ContentType
7
+ include Congo::List
8
+ end
9
+ end
10
+
11
+ before(:each) do
12
+ Account.destroy_all
13
+ Congo::ContentType.destroy_all
14
+
15
+ @account = Account.create(:email => 'layne_stanley@acme.org')
16
+ end
17
+
18
+ it 'should increment item position once saved' do
19
+ create_content_type
20
+ person = @account.developers.create :name => 'Layne Stanley', :bio => "That's great"
21
+ person._position.should == 1
22
+ person = @account.developers.create :name => 'Kurt Cobain', :bio => "Suicide #2"
23
+ person._position.should == 2
24
+ end
25
+
26
+ it 'should decrement item position once deleted' do
27
+ populate
28
+ @account.developers.first(:conditions => { :name => 'River Phoenix' }).destroy
29
+ @account.developers.first(:conditions => { :name => 'Layne Stanley' })._position.should == 1
30
+ @account.developers.first(:conditions => { :name => 'Kurt Cobain' })._position.should == 2
31
+ end
32
+
33
+ it 'should reorder all the items of a collection' do
34
+ populate
35
+ klass = @account.content_types.first.to_const
36
+ klass.reorder_all(@account.developers.all(:order => 'name ASC').collect(&:_id))
37
+ @account.developers.first(:conditions => { :name => 'River Phoenix' })._position.should == 3
38
+ @account.developers.first(:conditions => { :name => 'Layne Stanley' })._position.should == 2
39
+ @account.developers.first(:conditions => { :name => 'Kurt Cobain' })._position.should == 1
40
+ end
41
+
42
+ def create_content_type(options = {})
43
+ type = build_content_type
44
+ type.save!
45
+ type
46
+ end
47
+
48
+ def build_content_type(options = {})
49
+ default_options = {
50
+ :name => 'Developer',
51
+ :embedded => false,
52
+ :metadata_keys => [
53
+ { :name => 'name', :type => 'String' },
54
+ { :name => 'bio', :type => 'Text' }
55
+ ] }
56
+
57
+ @account.content_types.build(default_options.merge(options))
58
+ end
59
+
60
+ def populate
61
+ create_content_type
62
+ @account.developers.create :name => 'River Phoenix', :bio => "Life is good"
63
+ @account.developers.create :name => 'Layne Stanley', :bio => "That's great"
64
+ @account.developers.create :name => 'Kurt Cobain', :bio => "Suicide #2"
65
+ end
66
+
67
+ end
@@ -0,0 +1,167 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/functional_spec_helper')
2
+
3
+ describe 'ContentType' do
4
+
5
+ before(:each) do
6
+ Account.destroy_all
7
+ Congo::ProxyScoper.destroy_all
8
+ Congo::ContentType.destroy_all
9
+
10
+ @account = Account.create(:email => 'layne_stanley@acme.org')
11
+ @content_type = @account.content_types.create!({
12
+ :name => 'Project',
13
+ :embedded => false,
14
+ :metadata_keys => [
15
+ { :name => 'name' },
16
+ { :name => 'description' },
17
+ { :name => 'date' }
18
+ ]
19
+ })
20
+ @content_type = @content_type.reload
21
+ end
22
+
23
+ it 'should create new record' do
24
+ project = @account.projects.create(:name => 'Project #1', :description => 'bla bla')
25
+ @account.projects.count.should == 1
26
+ project.out_dated?.should be_false
27
+ project.migrate!.should be_false
28
+ end
29
+
30
+ it 'should not create incremented migration since there are no documents in the collection' do
31
+ (type = build_content_type).save
32
+ type.version.should == 0
33
+ type.migrations.should be_empty
34
+
35
+ type = Congo::ContentType.first
36
+ new_metadata_keys = [type.metadata_keys.pop, Congo::Metadata::Key.new({ :name => 'date' }), type.metadata_keys.pop]
37
+ new_metadata_keys.last.name = 'title'
38
+ type.metadata_keys = new_metadata_keys
39
+ type.save
40
+ type.version.should == 0
41
+ type.migrations.should be_empty
42
+ end
43
+
44
+ it 'should create incremented migration once it has been updated AND there is at least one document in the collection' do
45
+ (type = build_content_type).save
46
+ @account.tasks.create(:name => 'foo', :description => 'bla bla')
47
+ type.version.should == 0
48
+ type.migrations.should be_empty
49
+
50
+ type = @account.content_types.all[1]
51
+ new_metadata_keys = [type.metadata_keys.pop, Congo::Metadata::Key.new({ :name => 'date' })]
52
+ new_metadata_keys.first.name = 'a_description'
53
+ type.metadata_keys = new_metadata_keys
54
+ type.save
55
+ type.version.should == 1
56
+ type.migrations.size.should == 1
57
+ type.migrations.first.tasks.size.should == 2
58
+
59
+ type.migrations.first.tasks[0][:action].should == 'rename'
60
+ type.migrations.first.tasks[0][:previous].should == 'description'
61
+ type.migrations.first.tasks[0][:next].should == 'a_description'
62
+ type.migrations.first.tasks[1][:action].should == 'drop'
63
+ type.migrations.first.tasks[1][:previous].should == 'name'
64
+
65
+ type = @account.content_types.all[1]
66
+ new_metadata_keys = [type.metadata_keys.pop]
67
+ type.metadata_keys = new_metadata_keys
68
+ type.save
69
+ type.version.should == 2
70
+ type.migrations.size.should == 2
71
+ type.migrations.last.tasks.size.should == 1
72
+ type.migrations.last.tasks[0][:action].should == 'drop'
73
+ end
74
+
75
+ it 'should migrate smoothly (renaming and dropping columns)' do
76
+ project = @account.projects.create(:name => 'Project #1', :description => 'bla bla', :date => '10/09/2009')
77
+
78
+ # renaming and droppping keys
79
+ new_keys = [@content_type.metadata_keys.first, @content_type.metadata_keys[1]]
80
+ new_keys.first.name = 'title'
81
+ @content_type.metadata_keys = new_keys
82
+ @content_type.save
83
+
84
+ @content_type.reload
85
+ @account = Account.first # we need a hard refresh :-)
86
+
87
+ project = @account.projects.first
88
+ project.title.should == 'Project #1'
89
+ project._version.should == 1
90
+ lambda { project.name }.should_not raise_error
91
+ lambda { project.date }.should raise_error
92
+
93
+ @account = Account.first # we need a hard refresh :-)
94
+ @account.associations[:projects].instance_variable_set "@klass", @account.content_types.first.to_const
95
+
96
+ another_project = @account.projects.create!(:title => 'Project #2', :description => 'bla bla')
97
+ lambda { another_project.name }.should raise_error
98
+ lambda { another_project.date }.should raise_error
99
+ end
100
+
101
+ it 'should run 2 pending migrations' do
102
+ project = @account.projects.create(:name => 'Project #1', :description => 'bla bla', :date => '10/09/2009')
103
+
104
+ new_keys = [@content_type.metadata_keys.first, @content_type.metadata_keys[1]]
105
+ new_keys.first.name = 'title'
106
+ @content_type.metadata_keys = new_keys
107
+ @content_type.save
108
+
109
+ @content_type = @content_type.reload # necessary
110
+
111
+ new_keys = [@content_type.metadata_keys.first]
112
+ new_keys.first.name = 'name'
113
+ @content_type.metadata_keys = new_keys
114
+ @content_type.save
115
+
116
+ @account = Account.first # we need a hard refresh :-)
117
+ project = @account.projects.first # two pending migrations
118
+
119
+ project._version.should == 2
120
+ project.name.should == 'Project #1'
121
+ lambda { project.title }.should raise_error
122
+ lambda { project.description }.should raise_error
123
+ lambda { project.date }.should raise_error
124
+ end
125
+
126
+ it 'should update validation if key name changes' do
127
+ @account.projects.create(:name => 'Project #1', :description => 'bla bla', :date => '10/09/2009')
128
+
129
+ @content_type.metadata_validations = [{ :key => 'name', :type => 'presence_of' }]
130
+ @content_type.save
131
+
132
+ new_keys = [@content_type.metadata_keys.first, @content_type.metadata_keys.last]
133
+ new_keys.first.name = 'title'
134
+ @content_type.metadata_keys = new_keys
135
+ @content_type.save
136
+
137
+ @content_type = Congo::ContentType.first # hard refresh
138
+ @content_type.metadata_validations.first.key.should == 'title'
139
+ end
140
+
141
+ it 'should update validation if key is droppped' do
142
+ @account.projects.create(:name => 'Project #1', :description => 'bla bla', :date => '10/09/2009')
143
+
144
+ @content_type.metadata_validations = [{ :key => 'description', :type => 'presence_of' }]
145
+ @content_type.save
146
+
147
+ new_keys = [@content_type.metadata_keys.first, @content_type.metadata_keys.last]
148
+ @content_type.metadata_keys = new_keys
149
+ @content_type.save
150
+
151
+ @content_type = Congo::ContentType.first # hard refresh
152
+ @content_type.metadata_validations.should be_empty
153
+ end
154
+
155
+ def build_content_type(options = {})
156
+ default_options = {
157
+ :name => 'Task',
158
+ :embedded => false,
159
+ :metadata_keys => [
160
+ { :name => 'name' },
161
+ { :name => 'description' }
162
+ ] }
163
+
164
+ @account.content_types.build(default_options.merge(options))
165
+ end
166
+
167
+ end