It is funny how things work out, a disaster can lead to opportunities. Last month my main pc at home somehow got a corrupt hard drive and at first I thought I had lost all my private data (family pictures, documents etc), the drive wasn’t backed up as it was a mirrored drive, which I had thought would be an alright disaster recovery mechanism. It happened while I was upgrading to Server 2008. I broke the mirror and disconnected them. So the drives themselves weren’t connected at the time of upgrade, it was when I reconnected them after the upgrade was successful, the OS just couldn’t see them, maybe a corrupt partition table. I even rolled back to Server 2003, but nothing. The most important thing was that I had to recover that data somehow. This lead me to a piece of software called Active File Recovery which is just so simple to use. To cut a long story short I managed to recover all my missing data. But one thing that really made me think was the fact that this software could see my data and all previous owners data (it was a 2nd hand drive bought from a computer fair).
I have learnt several things from this experience, these being:-
- I need to use a more reliable medium. Using new hard drives instead of 2nd hand ones may have prevented this issue, but at the time (2002) I made the purchase there wasn’t a lot of data and it was the only viable option.
- I need a disaster recovery plan. Yes even for your home pc. I chose not to use a backup tool for my data for the simple fact that as there was around 13000 files, it would have took too long to run a back up on a machine which wasn’t permanently powered up.
- Be aware of old data. If upgrading an old hard drive, keep in mind that the data may still be recoverable. Dispose with care.
Now I have my data back I needed to find a mechanism which would protect my data with the least amount of administration work. That is I don’t want to have to remember to run a back up every time I add a file to my important documents drive. This is what has lead me to the Synchronization Framework. Using an expanded on version of the file synchronization example I now have a mechanism which will synchronize my important docs with my NAS, running in the background as a service. I can sleep better at night now, but what if we have a flood or worse? All my data is still in the same location. My next personal project is to also get it to synchronize with the cloud; hello Live Mesh.
This morning I read a post by Davy Brion who was explaining a technique to test private methods. Although the post was interesting, it was a comment by Rafferty Uy that got me thinking. He suggests that you make your method protected instead of private and have the testing class inherit from this class. There is much debate as to whether you should be testing private methods at all, and as I am fairly new to unit testing, I have only ever tested my public methods.
From Microsoft:-
protected
The type or member can only be accessed by code in the same class or struct, or in a derived class.
(http://msdn.microsoft.com/en-us/library/ms173121.aspx) So that is fine if your tests live in the same project as the code being tested. You just inherit from the class. If however you have all your tests in a separate project, then you simply need to have a reference to the .dll or .exe of your main project with the methods that need testing. Add the namespace to your using list and inherit the class in your test class.
1: using NUnit.Framework;
2: using Spike.PrivateMethodTest;
3:
4: namespace Spike.UnitTests
5: {
6: [TestFixture()]
7: public class Class1 : Spike.PrivateMethodTest.Program
8: {
9: [Test()]
10: public void TestPublicMethod()
11: {
12: string expectedValue = "this is public";
13: string actualValue = Program.MyPublicMethod();
14: Assert.AreEqual(expectedValue, actualValue);
15: }
16:
17: [Test()]
18: public void TestPrivateMethod()
19: {
20: string expectedValue = "this is private";
21: string actualValue = Program.MyPrivateMethod();
22: Assert.AreEqual(expectedValue, actualValue);
23: }
24: }
25: }
This technique seems by far the simplest I have come across to allow you to test private methods.
If you don't already know, the Synchronization Framework team has just released the CTP for v2.0
There are 3 core areas of the framework:-
- Sync Services for ADO.NET: Synchronization for ADO.NET enabled data sources
- Sync Services for File Systems: Synchronization for files and folders
- Sync Services for FeedSync: Synchronization for RSS and ATOM feeds
The framework home page contains links to lots of decent resources. The introduction to the framework, discusses file synchronization between two directories. This for me was a great place to start. As the document was written in November 2007, there was bound to be a few changes as to how you call various methods. I will cover here some of those changes for anybody who is interested.
1: // Set options for the sync operation
2: FileSyncOptions options = FileSyncOptions.ExplicitDetectChanges | FileSyncOptions.RecycleDeletes | FileSyncOptions.RecycleOverwrites;
Becomes
1: // Set options for the sync operation
2: FileSyncOptions options = FileSyncOptions.ExplicitDetectChanges | FileSyncOptions.RecycleDeletedFiles | FileSyncOptions.RecycleConflictLoserFiles;
1: SyncAgent agent = new SyncAgent();
2: agent.LocalProvider = sourceProvider;
3: agent.RemoteProvider = destinationProvider;
4: agent.Direction = SyncDirection.Upload; // Sync source to destination
5: Console .WriteLine( "Synchronizing changes to replica: " + destinationProvider.RootDirectoryPath);
6: agent.Synchronize();
Becomes
1: SyncOrchestrator agent = new SyncOrchestrator();
2: agent.LocalProvider = sourceProvider;
3: agent.RemoteProvider = destinationProvider;
4: agent.Direction = SyncDirectionOrder.Upload; // Sync source to destination
5: Console.WriteLine("Synchronizing changes to replica: " + destinationProvider.RootDirectoryPath);
6: agent.Synchronize();
1: switch (args.ChangeType)
2: {
3: case ChangeType.Create:
4: Console .WriteLine( "-- Applied CREATE for file " + args.NewFilePath);
5: break ;
6: case ChangeType.Delete:
7: Console .WriteLine( "-- Applied DELETE for file " + args.OldFilePath);
8: break ;
9: case ChangeType.Overwrite:
10: Console .WriteLine( "-- Applied OVERWRITE for file " + args.OldFilePath);
11: break ;
12: case ChangeType.Rename:
13: Console .WriteLine( "-- Applied RENAME for file " + args.OldFilePath +
14: " as " + args.NewFilePath);
15: break ;
16: }
Becomes
1: switch (args.ChangeType)
2: {
3: case ChangeType.Create:
4: Console.WriteLine("-- Applied CREATE for file " + args.NewFilePath);
5: break;
6: case ChangeType.Delete:
7: Console.WriteLine("-- Applied DELETE for file " + args.OldFilePath);
8: break;
9: case ChangeType.Update:
10: Console.WriteLine("-- Applied OVERWRITE for file " + args.OldFilePath);
11: break;
12: case ChangeType.Rename:
13: Console.WriteLine("-- Applied RENAME for file " + args.OldFilePath +
14: " as " + args.NewFilePath);
15: break;
16: }
However the biggest change I have come across with this example is that the FileSyncProvider takes in a GUID as a parameter, not a Synchronization.SyncId
The SyncId does have a public method which returns a guid like so:-
Guid guidSourceReplicaId = sourceReplicaId.GetGuidId();
So just use this instead, what is the difference you may ask? Well a guid comprises of 5 blocks of hex separated with hyphens, and the SyncId is just the hex without any hyphen.
The whole Synchronization Framework seems such a fantastic technology I hope to delve in a bit deeper in the coming months.