Revision 99e6329f

b/trunk/Pithos.Core.Test/Pithos.Core.Test.csproj
210 210
    <Compile Include="StatusCheckerTest.cs" />
211 211
    <Compile Include="MockSettings.cs" />
212 212
    <Compile Include="MockStatusKeeper.cs" />
213
    <Compile Include="TestDifferencer.cs" />
213
    <Compile Include="SnapshotDifferencerTest.cs" />
214 214
    <Compile Include="WorkflowFileStatusTest.cs" />
215 215
  </ItemGroup>
216 216
  <ItemGroup>
b/trunk/Pithos.Core.Test/SnapshotDifferencerTest.cs
1
// -----------------------------------------------------------------------
2
// <copyright file="TestDifferencer.cs" company="Microsoft">
3
// TODO: Update copyright text.
4
// </copyright>
5
// -----------------------------------------------------------------------
6

  
7
using System.Collections;
8
using NUnit.Framework;
9
using Pithos.Interfaces;
10
using Pithos.Network;
11

  
12
namespace Pithos.Core.Test
13
{
14
    using System;
15
    using System.Collections.Generic;
16
    using System.Linq;
17
    using System.Text;
18
    using Pithos.Core.Agents;
19
    
20
    [TestFixture]
21
    public class SnapshotDifferencerTest
22
    {
23
        private ObjectInfo[] _previous;
24
        private ObjectInfo[] _current;
25
        IEqualityComparer<ObjectInfo> _comparer = new ObjectInfoComparer();
26

  
27
        [SetUp]
28
        public void Setup()
29
        {
30
            _previous = new []{
31
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
32
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
33
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name3",Bytes=123,Hash="aa3",Version=1},
34
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name4",Bytes=123,Hash="aa4",Version=1},
35
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Folder1/Name1",Bytes=123,Hash="aa4",Version=1},
36
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
37
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
38
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name1",Bytes=123,Hash="aa1",Version=1},
39
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name2",Bytes=123,Hash="aa2",Version=1},
40
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name3",Bytes=123,Hash="aa3",Version=1},
41
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name4",Bytes=123,Hash="aa4",Version=1},
42
                                new ObjectInfo{Account="acc2",Container="Cont2",Name="Name1",Bytes=123,Hash="aa1",Version=1},
43
                                new ObjectInfo{Account="acc2",Container="Cont2",Name="Name2",Bytes=123,Hash="aa2",Version=1},
44
                            };
45
            _current = new []{
46
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
47
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name3",Bytes=123,Hash="aa3",Version=1},
48
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name4",Bytes=1234,Hash="aa45",Version=1},
49
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name5",Bytes=123,Hash="aa5",Version=1},
50
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Folder1/Name1",Bytes=123,Hash="aa4",Version=1},
51
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
52
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
53
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name2",Bytes=123,Hash="aa2",Version=1},
54
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name3",Bytes=123,Hash="aa3",Version=1},
55
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name4",Bytes=1234,Hash="aa45",Version=1},
56
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name5",Bytes=123,Hash="aa5",Version=1},
57
                                new ObjectInfo{Account="acc2",Container="Cont2",Name="Name1",Bytes=123,Hash="aa1",Version=1},
58
                                new ObjectInfo{Account="acc2",Container="Cont2",Name="Name2",Bytes=123,Hash="aa2",Version=1},
59
                           };
60
            
61
        }
62

  
63
        [Test]
64
        public void when_adding_a_snapshot_for_the_first_time()
65
        {
66
            var d1 = new SnapshotDifferencer();            
67
            var differencer=d1.Post(_previous);
68
            Assert.That(differencer.Deleted,Is.Empty);
69
            Assert.That(differencer.Created,Is.EquivalentTo(_previous));
70
            Assert.That(differencer.Changed,Is.Empty);
71
            Assert.That(differencer.Unchanged,Is.Empty);
72
        }
73

  
74
        [Test]
75
        public void when_adding_a_second_snapshot_with_a_deletion()
76
        {
77
            var d1 = new SnapshotDifferencer();            
78
            var differencer=d1.Post(_previous).Post(_current);
79
            var deleted=new[]
80
                            {
81
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
82
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name1",Bytes=123,Hash="aa1",Version=1},
83
                            };
84
            Assert.That(differencer.Deleted.ToList(),Is.EquivalentTo(deleted)
85
                .Using((IEqualityComparer) new ObjectInfoComparer()));
86
        }
87
        [Test]
88
        public void when_adding_a_second_snapshot_with_an_addition()
89
        {
90
            var d1 = new SnapshotDifferencer();            
91
            var differencer=d1.Post(_previous).Post(_current);
92
            var created = new[]
93
                              {
94
                                  new ObjectInfo { Account = "acc1", Container = "Cont1", Name = "Name5", Bytes = 123, Hash = "aa5", Version = 1 },
95
                                  new ObjectInfo { Account = "acc1", Container = "Cont2", Name = "Name5", Bytes = 123, Hash = "aa5", Version = 1 },
96
                              };
97
            Assert.That(differencer.Created.ToList(), Is.EquivalentTo(created)
98
                .Using((IEqualityComparer)new ObjectInfoComparer()));
99
        }
100
        [Test]
101
        public void when_adding_a_second_snapshot_with_a_change()
102
        {
103
            var d1 = new SnapshotDifferencer();            
104
            var differencer=d1.Post(_previous).Post(_current);
105
            var changed = new[] { 
106
                new ObjectInfo { Account = "acc1", Container = "Cont1", Name = "Name4", Bytes = 1234, Hash = "aa45", Version = 1 },
107
                new ObjectInfo { Account = "acc1", Container = "Cont2", Name = "Name4", Bytes = 1234, Hash = "aa45", Version = 1 },
108
            };
109
            Assert.That(differencer.Changed.ToList(), Is.EquivalentTo(changed)
110
                .Using((IEqualityComparer)new ObjectInfoComparer()));
111
        }
112

  
113
        [Test]
114
        public void when_adding_a_second_snapshot_with_unchanged()
115
        {
116
            var d1 = new SnapshotDifferencer();            
117
            var differencer=d1.Post(_previous).Post(_current);
118
            var unchanged = new[]
119
                                {
120
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
121
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name3",Bytes=123,Hash="aa3",Version=1},
122
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
123
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},  
124
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Folder1/Name1",Bytes=123,Hash="aa4",Version=1},  
125
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name2",Bytes=123,Hash="aa2",Version=1},
126
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name3",Bytes=123,Hash="aa3",Version=1},
127
                                new ObjectInfo{Account="acc2",Container="Cont2",Name="Name1",Bytes=123,Hash="aa1",Version=1},
128
                                new ObjectInfo{Account="acc2",Container="Cont2",Name="Name2",Bytes=123,Hash="aa2",Version=1},                                    
129
                                };            
130
            Assert.That(differencer.Unchanged.ToList(), Is.EquivalentTo(unchanged)
131
                .Using((IEqualityComparer)new ObjectInfoComparer()));
132
        }
133

  
134
        [Test]
135
        public void when_adding_a_null_first_snapshot()
136
        {
137
            var d1 = new SnapshotDifferencer();            
138
            var differencer=d1.Post(null);
139
            Assert.That(differencer.Deleted, Is.Empty);
140
            Assert.That(differencer.Created, Is.Empty);
141
            Assert.That(differencer.Changed, Is.Empty);
142
            Assert.That(differencer.Unchanged, Is.Empty);
143
        }
144

  
145
        [Test]
146
        public void when_adding_a_null_second_snapshot()
147
        {
148
            var d1 = new SnapshotDifferencer();            
149
            var differencer=d1.Post(_previous).Post(null);
150
            Assert.That(differencer.Deleted, Is.EquivalentTo(_previous));
151
            Assert.That(differencer.Created, Is.Empty);
152
            Assert.That(differencer.Changed, Is.Empty);
153
            Assert.That(differencer.Unchanged, Is.Empty);
154
        }
155

  
156
        [Test]
157
        public void when_adding_no_modifications()
158
        {
159
            var d1 = new SnapshotDifferencer();
160
            //NOTE: Must post nomods for all accounts and contaienrs, otherwise the missing
161
            //containers will appear deleted
162
            var noModItem = new[]{
163
                                    new NoModificationInfo("acc1", "Cont1"),
164
                                    new NoModificationInfo("acc1", "Cont2"),
165
                                    new NoModificationInfo("acc2", "Cont1"),
166
                                    new NoModificationInfo("acc2", "Cont2"),
167
                                };
168
            var differencer = d1.Post(_previous)
169
                .Post(noModItem);
170
            Assert.That(differencer.Deleted, Is.Empty,"should have no deletions");
171
            Assert.That(differencer.Created, Is.Empty,"should have no insertions");
172
            Assert.That(differencer.Changed, Is.Empty,"should have no changes");
173
            Assert.That(differencer.Unchanged, Is.EquivalentTo(_previous),"should be equivalent to previous");
174
            
175
        }
176

  
177
        [Test]
178
        public void when_adding_no_mod_for_a_folder()
179
        {
180
            var d1 = new SnapshotDifferencer();
181
            //NOTE: Must post nomods for all accounts and contaienrs, otherwise the missing
182
            //containers will appear deleted
183
            var noModItems = new[]{
184
                                    new NoModificationInfo("acc1", "Cont1","Folder1"),
185
                                    new NoModificationInfo("acc1", "Cont2"),
186
                                    new NoModificationInfo("acc2", "Cont1"),
187
                                    new NoModificationInfo("acc2", "Cont2"),
188
                                };
189
            var deleted = new[]
190
                            {
191
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
192
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
193
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name3",Bytes=123,Hash="aa3",Version=1},
194
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name4",Bytes=123,Hash="aa4",Version=1},
195
                            };
196
            var unchanged = new[]{
197
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Folder1/Name1",Bytes=123,Hash="aa4",Version=1},
198
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
199
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
200
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name1",Bytes=123,Hash="aa1",Version=1},
201
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name2",Bytes=123,Hash="aa2",Version=1},
202
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name3",Bytes=123,Hash="aa3",Version=1},
203
                                new ObjectInfo{Account="acc1",Container="Cont2",Name="Name4",Bytes=123,Hash="aa4",Version=1},
204
                                new ObjectInfo{Account="acc2",Container="Cont2",Name="Name1",Bytes=123,Hash="aa1",Version=1},
205
                                new ObjectInfo{Account="acc2",Container="Cont2",Name="Name2",Bytes=123,Hash="aa2",Version=1},
206
                            };
207
            var differencer = d1.Post(_previous)
208
                .Post(noModItems);
209

  
210
            
211
            Assert.That(differencer.Deleted.ToList(), Is.EquivalentTo(deleted).Using(_comparer), "should have deletions only from acc1/cont1");
212
            Assert.That(differencer.Created, Is.Empty,"should have no insertions");
213
            Assert.That(differencer.Changed, Is.Empty,"should have no changes");
214
            Assert.That(differencer.Unchanged, Is.EquivalentTo(unchanged).Using(_comparer),"should be equivalent to previous except the direct leafs of acc1/cont1");
215
            
216
        }
217

  
218
    }
219

  
220
    
221
}
/dev/null
1
// -----------------------------------------------------------------------
2
// <copyright file="TestDifferencer.cs" company="Microsoft">
3
// TODO: Update copyright text.
4
// </copyright>
5
// -----------------------------------------------------------------------
6

  
7
using System.Collections;
8
using NUnit.Framework;
9
using Pithos.Interfaces;
10

  
11
namespace Pithos.Core.Test
12
{
13
    using System;
14
    using System.Collections.Generic;
15
    using System.Linq;
16
    using System.Text;
17
    using Pithos.Core.Agents;
18
    
19
    [TestFixture]
20
    public class TestDifferencer
21
    {
22
        private ObjectInfo[] _previous;
23
        private ObjectInfo[] _current;
24

  
25
        [SetUp]
26
        public void Setup()
27
        {
28
            _previous = new []{
29
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
30
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
31
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name3",Bytes=123,Hash="aa3",Version=1},
32
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name4",Bytes=123,Hash="aa4",Version=1},
33
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
34
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
35
                            };
36
            _current = new []{
37
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
38
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name3",Bytes=123,Hash="aa3",Version=1},
39
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name4",Bytes=1234,Hash="aa45",Version=1},
40
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name5",Bytes=123,Hash="aa5",Version=1},
41
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
42
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
43
                           };
44
            
45
        }
46

  
47
        [Test]
48
        public void when_adding_a_snapshot_for_the_first_time()
49
        {
50
            var d1 = new SnapshotDifferencer();            
51
            var differencer=d1.Post(_previous);
52
            Assert.That(differencer.Deleted,Is.Empty);
53
            Assert.That(differencer.Created,Is.EquivalentTo(_previous));
54
            Assert.That(differencer.Changed,Is.Empty);
55
            Assert.That(differencer.Unchanged,Is.Empty);
56
        }
57

  
58
        [Test]
59
        public void when_adding_a_second_snapshot_with_a_deletion()
60
        {
61
            var d1 = new SnapshotDifferencer();            
62
            var differencer=d1.Post(_previous).Post(_current);
63
            var deleted=new[]{new ObjectInfo{Account="acc1",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1}};
64
            Assert.That(differencer.Deleted.ToList(),Is.EquivalentTo(deleted)
65
                .Using((IEqualityComparer) new ObjectInfoComparer()));
66
        }
67
        [Test]
68
        public void when_adding_a_second_snapshot_with_an_addition()
69
        {
70
            var d1 = new SnapshotDifferencer();            
71
            var differencer=d1.Post(_previous).Post(_current);
72
            var created = new[] { new ObjectInfo { Account = "acc1", Container = "Cont1", Name = "Name5", Bytes = 123, Hash = "aa5", Version = 1 } };
73
            Assert.That(differencer.Created.ToList(), Is.EquivalentTo(created)
74
                .Using((IEqualityComparer)new ObjectInfoComparer()));
75
        }
76
        [Test]
77
        public void when_adding_a_second_snapshot_with_a_change()
78
        {
79
            var d1 = new SnapshotDifferencer();            
80
            var differencer=d1.Post(_previous).Post(_current);
81
            var changed = new[] { new ObjectInfo { Account = "acc1", Container = "Cont1", Name = "Name4", Bytes = 1234, Hash = "aa45", Version = 1 } };
82
            Assert.That(differencer.Changed.ToList(), Is.EquivalentTo(changed)
83
                .Using((IEqualityComparer)new ObjectInfoComparer()));
84
        }
85

  
86
        [Test]
87
        public void when_adding_a_second_snapshot_with_unchanged()
88
        {
89
            var d1 = new SnapshotDifferencer();            
90
            var differencer=d1.Post(_previous).Post(_current);
91
            var unchanged = new[]
92
                                {
93
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},
94
                                new ObjectInfo{Account="acc1",Container="Cont1",Name="Name3",Bytes=123,Hash="aa3",Version=1},
95
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name1",Bytes=123,Hash="aa1",Version=1},
96
                                new ObjectInfo{Account="acc2",Container="Cont1",Name="Name2",Bytes=123,Hash="aa2",Version=1},                                    
97
                                };            
98
            Assert.That(differencer.Unchanged.ToList(), Is.EquivalentTo(unchanged)
99
                .Using((IEqualityComparer)new ObjectInfoComparer()));
100
        }
101

  
102
        [Test]
103
        public void when_adding_a_null_first_snapshot()
104
        {
105
            var d1 = new SnapshotDifferencer();            
106
            var differencer=d1.Post(null);
107
            Assert.That(differencer.Deleted, Is.Empty);
108
            Assert.That(differencer.Created, Is.Empty);
109
            Assert.That(differencer.Changed, Is.Empty);
110
            Assert.That(differencer.Unchanged, Is.Empty);
111
        }
112

  
113
        [Test]
114
        public void when_adding_a_null_second_snapshot()
115
        {
116
            var d1 = new SnapshotDifferencer();            
117
            var differencer=d1.Post(_previous).Post(null);
118
            Assert.That(differencer.Deleted, Is.EquivalentTo(_previous));
119
            Assert.That(differencer.Created, Is.Empty);
120
            Assert.That(differencer.Changed, Is.Empty);
121
            Assert.That(differencer.Unchanged, Is.Empty);
122
        }
123
    }
124
}
b/trunk/Pithos.Core/Agents/CollectionExtensions.cs
55 55
    /// </summary>
56 56
    public static class CollectionExtensions
57 57
    {
58
        public static IEnumerable<T> Replace<T>(this IEnumerable<T> list,Func<T,bool> match, Func<T,IEnumerable<T>> replace)
59
        {
60
            foreach (var item in list)
61
            {
62
                if (match(item))
63
                    foreach (var newItem in replace(item))
64
                    {
65
                        yield return newItem;
66
                    }
67
                else
68
                    yield return item;
69
            }
70
        }
71

  
72

  
58 73
        /// <summary>
59 74
        /// Remove the first message in a queue that matches the predicate
60 75
        /// </summary>
......
85 100
        }
86 101

  
87 102

  
103
        /// <summary>
104
        /// Return only the info objects that are below one of the filter Uris
105
        /// </summary>
106
        /// <param name="infos">ObjectInfo items to filter</param>
107
        /// <param name="filterUris">List of filter Uris</param>
108
        /// <returns>An enumerable of ObjectInfo items. If the list of filter Uris is empty or null, the original list is returned</returns>
88 109
        public static IEnumerable<ObjectInfo> FilterBelow(this IEnumerable<ObjectInfo> infos,List<Uri> filterUris  )
89 110
        {
90 111
            if (filterUris == null)
......
98 119
            return filteredUris;
99 120
        }
100 121

  
101
        public static IEnumerable<ObjectInfo> FilterDirectlyBelow(this IEnumerable<ObjectInfo> infos,List<Uri> filterUris  )
122
        /// <summary>
123
        /// Return only the info objects that are directly below one of the filter Uris
124
        /// </summary>
125
        /// <param name="infos">ObjectInfo items to filter</param>
126
        /// <param name="filterUris">List of filter Uris</param>
127
        /// <returns>An enumerable of ObjectInfo items. If the list of filter Uris is empty or null, the original list is returned</returns>
128
        public static IEnumerable<ObjectInfo> FilterDirectlyBelow(this IEnumerable<ObjectInfo> infos, List<Uri> filterUris)
102 129
        {
103 130
            if (filterUris == null)
104 131
                return infos;
......
111 138
            return filteredUris;
112 139
        }
113 140

  
141
        /// <summary>
142
        /// Checkes whether a Uri is below a root Uri
143
        /// </summary>
144
        /// <param name="target"></param>
145
        /// <param name="root"></param>
146
        /// <returns></returns>
114 147
        public static bool IsAtOrBelow(this Uri target,Uri root)
115 148
        {
116 149
            Contract.Requires(root != null);
......
137 170
        }
138 171

  
139 172

  
173
        /// <summary>
174
        /// Checks whether a Uri is directly below a root Uri
175
        /// </summary>
176
        /// <param name="target"></param>
177
        /// <param name="root"></param>
178
        /// <returns></returns>
140 179
        public static bool IsAtOrDirectlyBelow(this Uri target,Uri root)
141 180
        {
142 181
            Contract.Requires(root!=null);
......
150 189
                && target.IsAtOrBelow(root);
151 190
        }
152 191

  
192
        /// <summary>
193
        /// Checkes whether a file path is below a root path
194
        /// </summary>
195
        /// <param name="targetPath"></param>
196
        /// <param name="rootPath"></param>
197
        /// <returns></returns>
153 198
        public static bool IsAtOrBelow(this string targetPath, string rootPath)
154 199
        {
155 200
            Contract.Requires(!String.IsNullOrWhiteSpace(targetPath));
......
161 206
            return InnerAtOrBelow(targetSegments, rootSegments);
162 207
        }
163 208

  
209
        /// <summary>
210
        /// Checks whether a file path is directly below a root path
211
        /// </summary>
212
        /// <param name="targetPath"></param>
213
        /// <param name="rootPath"></param>
214
        /// <returns></returns>
164 215
        public static bool IsAtOrDirectlyBelow(this string targetPath, string rootPath)
165 216
        {
166 217
            Contract.Requires(!String.IsNullOrWhiteSpace(targetPath));
b/trunk/Pithos.Core/Agents/PollAgent.cs
194 194
                Log.Info("Scheduled");
195 195
                var client = new CloudFilesClient(accountInfo);
196 196

  
197
                var containers = client.ListContainers(accountInfo.UserName);
197
                //We don't need to check the trash container
198
                var containers = client.ListContainers(accountInfo.UserName).Where(c=>c.Name!="trash");
198 199

  
199 200

  
200 201
                CreateContainerFolders(accountInfo, containers);
......
214 215
                                             client.ListObjects(accountInfo.UserName, container.Name, since), container.Name)).ToList();
215 216
                    //BUG: Can't detect difference between no changes or no objects
216 217
                    //ListObjects returns nothing if there are no changes since the last check time (since value)                    
217
                    //TODO: Must detect the difference between no server objects an
218
                    var listShared = Task<IList<ObjectInfo>>.Factory.StartNew(_ => client.ListSharedObjects(since), "shared");
218
                    //TODO: Must detect the difference between no server objects and no change
219

  
220
                    //NOTE: One option is to "mark" all result lists with their container name, or 
221
                    //rather the url of the container
222
                    //Another option 
223

  
224
                    var listShared = Task<IList<ObjectInfo>>.Factory.StartNew(_ => 
225
                        client.ListSharedObjects(since), "shared");
219 226
                    listObjects.Add(listShared);
220 227
                    var listTasks = await Task.Factory.WhenAll(listObjects.ToArray());
221 228

  
......
229 236
                                            from obj in objectList.Result
230 237
                                            select obj;
231 238

  
232
                        var trashObjects = dict["trash"].Result;
233 239
                        var sharedObjects = dict["shared"].Result;
234 240

  
235 241
                        //DON'T process trashed files
b/trunk/Pithos.Core/Agents/SnapshotDifferencer.cs
75 75
        public SnapshotDifferencer Post(IEnumerable<ObjectInfo> list)
76 76
        {
77 77
            _previous = _current;
78
            _current = list ?? new List<ObjectInfo>();
78
            if (list == null)
79
            {
80
                _current = new List<ObjectInfo>();
81
                return this;
82
            }
83

  
84
            //Replace any NoModification entries with previous values that have
85
            //the same account, container and possibly, folder
86
            _current=list.Replace(
87
                info => info is NoModificationInfo, 
88
                noMod => from info in _previous
89
                        where 
90
                            info.Account==noMod.Account 
91
                            && info.Container==noMod.Container 
92
                            //If the NoModification specifies a folder, use it to match items below this folder
93
                            && (noMod.Name==null || info.Name.StartsWith(noMod.Name))
94
                        select info);
95

  
79 96
            return this;
80 97
        }
81 98
        
b/trunk/Pithos.Network/CloudFilesClient.cs
46 46

  
47 47

  
48 48
using System;
49
using System.Collections;
49 50
using System.Collections.Generic;
50 51
using System.Collections.Specialized;
51 52
using System.ComponentModel.Composition;
......
317 318
            using (ThreadContext.Stacks["Share"].Push("List Objects"))
318 319
            {
319 320
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
320

  
321
                var accounts = ListSharingAccounts(since);
321
                //'since' is not used here because we need to have ListObjects return a NoChange result
322
                //for all shared accounts,containers
323
                var accounts = ListSharingAccounts();
322 324
                var items = from account in accounts 
323 325
                            let containers = ListContainers(account.name) 
324 326
                            from container in containers 
325
                            select ListObjects(account.name, container.Name);
327
                            select ListObjects(account.name, container.Name,since);
326 328
                var objects=items.SelectMany(r=> r).ToList();
327 329
/*
328 330
                var objects = new List<ObjectInfo>();
......
605 607

  
606 608
                    client.AssertStatusOK("ListObjects failed");
607 609

  
608
                    //HACK: Must add it to all other operations as well
609
                    StatusCode = client.StatusCode;
610
                    if (client.StatusCode==HttpStatusCode.NotModified)
611
                        return new[]{new NoModificationInfo(account,container)};
610 612
                    //If the result is empty, return an empty list,
611 613
                    var infos = String.IsNullOrWhiteSpace(content)
612 614
                                    ? new List<ObjectInfo>()
......
625 627
            }
626 628
        }
627 629

  
628
        public HttpStatusCode StatusCode { get; set; }
629

  
630

  
631 630
        public IList<ObjectInfo> ListObjects(string account, string container, string folder, DateTime? since = null)
632 631
        {
633 632
            if (String.IsNullOrWhiteSpace(container))
......
654 653
                    var content = client.DownloadStringWithRetry(container, 3);
655 654
                    client.AssertStatusOK("ListObjects failed");
656 655

  
656
                    if (client.StatusCode==HttpStatusCode.NotModified)
657
                        return new[]{new NoModificationInfo(account,container,folder)};
658

  
657 659
                    var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
658 660
                    foreach (var info in infos)
659 661
                    {
b/trunk/Pithos.Network/NoModificationInfo.cs
1
// -----------------------------------------------------------------------
2
// <copyright file="NoModificationInfo.cs" company="Microsoft">
3
// TODO: Update copyright text.
4
// </copyright>
5
// -----------------------------------------------------------------------
6

  
7
using System.Diagnostics.Contracts;
8
using Pithos.Interfaces;
9

  
10
namespace Pithos.Network
11
{
12
    using System;
13
    using System.Collections.Generic;
14
    using System.Linq;
15
    using System.Text;
16

  
17
    /// <summary>
18
    /// A special ObjectInfo that represents a NotModified HTTP Status (304)
19
    /// </summary>
20
    public class NoModificationInfo:ObjectInfo
21
    {
22
        public NoModificationInfo(string account,string container)
23
        {
24
            Contract.Requires(!String.IsNullOrWhiteSpace(account));
25
            Contract.Requires(!String.IsNullOrWhiteSpace(container));
26

  
27
            Account = account;
28
            Container = container;
29
        }
30

  
31
        public NoModificationInfo(string account, string container,string folder)
32
            :this(account,container)
33
        {
34
            Name = folder + '/';
35
        }
36
    }
37
}
b/trunk/Pithos.Network/Pithos.Network.csproj
233 233
    <Compile Include="CloudFilesClient.cs" />
234 234
    <Compile Include="ContainerInfo.cs" />
235 235
    <Compile Include="ICloudClient.cs" />
236
    <Compile Include="NoModificationInfo.cs" />
236 237
    <Compile Include="RestClient.cs">
237 238
      <SubType>Component</SubType>
238 239
    </Compile>

Also available in: Unified diff