test_identity.js
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2011 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
29 // ============================================================================
30 // GLOBALS & CONSTS
31 // ============================================================================
32 
33 Components.utils.import("resource://app/jsmodules/sbProperties.jsm");
34 Components.utils.import("resource://app/jsmodules/sbLibraryUtils.jsm");
35 
36 const SEPARATOR = '|';
37 const CONTENT_TYPES = ['audio', 'video'];
38 
41 var gTestData = {
42  "NoTags": { trackName: "",
43  artistName: "",
44  albumName: "",
45  genre: "",
46  producerName: "",
47  audioMediaItem: null,
48  videoMediaItem: null,
49  audioExpectedIdentity: null,
50  videoExpectedIdentity: null},
51  "OnlyName": { trackName: "OnlyAName",
52  artistName: "",
53  albumName: "",
54  genre: "",
55  producerName: "",
56  audioMediaItem: null,
57  videoMediaItem: null,
58  audioExpectedIdentity: "edW9P0emhROCprpy6YdiXg==",
59  videoExpectedIdentity: "8DHNDFkX6afo03hmmInR6w==" },
60  "Tagged": { trackName: "A fully tagged track",
61  artistName: "with an artist name",
62  albumName: "and an album name",
63  genre: "and even a genre",
64  producerName: "some producer",
65  audioMediaItem: null,
66  videoMediaItem: null,
67  audioExpectedIdentity: "4C9SB69gL6pB/NZ/2UQbsw==",
68  videoExpectedIdentity: "gPL0UOMSMv08yHcuLA+peg==" },
69  "ForeignChar": { trackName: "太陽",
70  artistName: "理多",
71  albumName: "moment 〜もぉめんと〜",
72  genre: "Game",
73  producerName: "まちあわせ",
74  audioMediaItem: null,
75  videoMediaItem: null,
76  audioExpectedIdentity: "1giivr/B90byHVMftVlFmQ==",
77  videoExpectedIdentity: "Ki4O6mqLlA+cNCHutxjVOw=="}
78 }
79 
80 // ============================================================================
81 // ENTRY POINT
82 // ============================================================================
83 
84 function runTest () {
85  log("Testing Identity Service:");
86 
87  // Setup our globals
88  gIdentityService = Cc["@songbirdnest.com/Songbird/IdentityService;1"]
89  .getService(Ci.sbIIdentityService);
90  gTestLibrary = createLibrary("test-identity", null, false);
91 
92  /* Create audio and video mediaItems for our test data and attach those
93  * mediaitems to our test data objects */
94  for (var dataName in gTestData) {
95  var currData = gTestData[dataName];
96 
97  CONTENT_TYPES.forEach( function (contentType) {
98  var props =
99  Cc["@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1"]
100  .createInstance(Ci.sbIMutablePropertyArray);
101  props.appendProperty(SBProperties.trackName, currData.trackName);
102  props.appendProperty(SBProperties.artistName, currData.artistName);
103  props.appendProperty(SBProperties.albumName, currData.albumName);
104  props.appendProperty(SBProperties.genre, currData.genre);
105  props.appendProperty(SBProperties.producerName, currData.producerName);
106  props.appendProperty(SBProperties.contentType, contentType);
107  var newItem = gTestLibrary.createMediaItem
108  (newURI("http://foo.test.com/" +
109  dataName + "_" + contentType),
110  props);
111  currData[contentType + "MediaItem"] = newItem;
112  });
113  }
114 
115  testHashString();
116  testCalculateIdentity();
117  testSaveAndGetItemWithSameIdentity();
118  gTestLibrary.clear();
119  log("OK");
120 }
121 
122 // ============================================================================
123 // TESTS
124 // ============================================================================
125 
126 function testHashString() {
127  log("Testing sbIIdentityService.hashString...");
128 
129  /* First check that our hashing mechanism is working properly for a string
130  * with a known hash. */
131  var testString = "hello, world";
132  var expectedHash = "5NfxtO0uQtFYmPSyewGdpA==";
133  var actualHash = gIdentityService.hashString(testString);
134 
135  assertEqual(actualHash, expectedHash);
136 
137  /* Next we check that we can get the expected identity when we manually put
138  * together the metadata string that is hashed to form the identity.
139  * This assumes that the metadata string, before it is hashed to calculate
140  * the identity, is of the form:
141  * <contentType>|<trackName>|<artistName>|<albumName>|<genre>
142  * and that mediaitems without any of the relevant metadata are not given
143  * an identity.
144  */
145  for (var dataName in gTestData) {
146  var currData = gTestData[dataName];
147 
148  /* The contentType is the first property used in the metadataString that
149  * we hash, so we need to handle them individually */
150  CONTENT_TYPES.forEach( function (contentType) {
151  var identityProperties = [];
152  identityProperties.push(contentType);
153  identityProperties.push(currData.trackName);
154  identityProperties.push(currData.artistName);
155  identityProperties.push(currData.albumName);
156  identityProperties.push(currData.genre);
157 
158  var metadataString = identityProperties.join(SEPARATOR);
159 
160  /* We'll add identityProperties.length - 1 separators to the contentType
161  * so we only know that we have metadata to hash if the string is longer
162  * than that */
163  var hasMetadata = (metadataString.length >
164  (contentType.length + identityProperties.length - 1));
165 
166  var expectedMetadataHash = currData[contentType + "ExpectedIdentity"];
167 
168  /* If we have metadata to hash, hash it and we'll compare that string.
169  * If we don't have metadata, though, the identity service will not give
170  * an identity so be sure that we expected null. */
171  var actualMetadataHash = ((hasMetadata) ?
172  gIdentityService.hashString(metadataString) :
173  null);
174  assertEqual(actualMetadataHash, expectedMetadataHash);
175  });
176  }
177 
178 }
179 
180 function testCalculateIdentity() {
181  log("Testing sbIIdentityService.calculateIdentity...");
182 
183  /* We will check that we calculate identities properly for our test data items
184  * with each of the contentTypes */
185  for (var dataName in gTestData) {
186  var currData = gTestData[dataName];
187 
188  CONTENT_TYPES.forEach( function (contentType) {
189  // Check that we calculate the identity correctly for the test data item
190  var testMediaItem = currData[contentType + "MediaItem"];
191  var expectedHash = currData[contentType + "ExpectedIdentity"];
192  var actualMediaItemHash = gIdentityService.calculateIdentityForMediaItem
193  (testMediaItem);
194  assertEqual(actualMediaItemHash, expectedHash);
195 
196  /* Check that changing an irrelevant metadata field does not change the
197  * identity. producerName is not used in the identity calculation */
198  testMediaItem.setProperty(SBProperties.producerName, "A new producer!");
199  var irrelevantChangeHash =
200  gIdentityService.calculateIdentityForMediaItem(testMediaItem);
201  assertEqual(irrelevantChangeHash, expectedHash);
202 
203  /* Check that changing a relevant metadata field changes the identity.
204  * We change to the otherContentType because we already know what the
205  * identity should be for this data with that contentType */
206  var otherContentType = (contentType == "video") ? "audio" : "video";
207  testMediaItem.setProperty(SBProperties.contentType, otherContentType);
208 
209  var actualContentTypeSwitchHash =
210  gIdentityService.calculateIdentityForMediaItem(testMediaItem);
211 
212  var expectedContentTypeSwitchHash =
213  currData[otherContentType + "ExpectedIdentity"];
214  assertEqual(actualContentTypeSwitchHash, expectedContentTypeSwitchHash);
215 
216  // Change the contentType back and make sure everything is still good
217  testMediaItem.setProperty(SBProperties.contentType, contentType);
218  actualMediaItemHash = gIdentityService.calculateIdentityForMediaItem
219  (testMediaItem);
220  assertEqual(actualMediaItemHash, expectedHash);
221 
222  });
223  }
224 }
225 
226 function testSaveAndGetItemWithSameIdentity() {
227  log("Testing sbIIdentityService saving and retrieving items by identity...");
228  var secondaryLibrary = createLibrary("test-identity-secondary", null , false);
229 
230  /* First we'll try to get an item with the same identity as each of our test
231  * data items. We'll try to get them from the secondary library, which
232  * doesn't have anything in it yet, so those should not return anything.
233  *
234  * Then, we try to get an item with the same identity from gTestLibrary.
235  * Though gTestLibrary holds the test data items, it should still not return
236  * anything because we screen out items with the same guid as the param item.
237  *
238  * Last, we add a new item to the secondaryLibrary with the same metadata
239  * as the test data items. Then we search for items with the same identity
240  * as our test data item in the secondLibrary and ensure that it retrieves
241  * the newly created item. This is then repeated vice-versa in gTestLibrary
242  */
243  var finishedCount = 0;
244  for (var dataName in gTestData) {
245  var currData = gTestData[dataName];
246 
247  CONTENT_TYPES.forEach( function (contentType) {
248  var testMediaItem = currData[contentType + "MediaItem"];
249  var expectedHash = currData[contentType + "ExpectedIdentity"];
250 
251  /* If the expectedHash is null then we didn't have enough information to
252  * generate an identity, so we'll get less predictable results because
253  * items in the test data have the same identity (i.e. no identity).
254  * We just won't worry about those items here */
255  if (expectedHash != null) {
256  // secondaryLibrary shouldn't have any identity matches, yet
257  var found = secondaryLibrary.containsItemWithSameIdentity(testMediaItem);
258  assertTrue(!found);
259 
260  /* gTestLibrary has something with the same identity, testMediaItem, but
261  * we screen out items with the same guid so we shoudln't find anything
262  * here */
263  found = gTestLibrary.containsItemWithSameIdentity(testMediaItem);
264  assertTrue(!found);
265 
266  /* Now we'll insert an item with the same metadata into the secondary
267  * library and then look for an item with the same identity as the one in
268  * our test data. We should find the created item. */
269  var props =
270  Cc["@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1"]
271  .createInstance(Ci.sbIMutablePropertyArray);
272  props.appendProperty(SBProperties.trackName, currData.trackName);
273  props.appendProperty(SBProperties.artistName, currData.artistName);
274  props.appendProperty(SBProperties.albumName, currData.albumName);
275  props.appendProperty(SBProperties.genre, currData.genre);
276  props.appendProperty(SBProperties.producerName, currData.producerName);
277  props.appendProperty(SBProperties.contentType, contentType);
278  var secondaryItem = secondaryLibrary.createMediaItem
279  (newURI("http://foo.secondarytest.com/" +
280  dataName + "_" + contentType),
281  props);
282 
283  /* Look for an item with the same identity as testMediaItem. We just
284  * created an item with the same metadata, so we should find one */
285  found = secondaryLibrary.containsItemWithSameIdentity(testMediaItem);
286  assertTrue(found);
287 
288  /* The same should be true for the reverse, looking for an item with
289  * the same identity as secondaryItem in gTestLibrary */
290  found = gTestLibrary.containsItemWithSameIdentity(secondaryItem);
291  assertTrue(found);
292 
293  // Ensure that we can find items in a library with an identity string
294  var hashPropID = SBProperties.metadataHashIdentity;
295  var testIdentity = testMediaItem.getProperty(hashPropID);
296  var foundItems = null;
297  try {
298  foundItems = gTestLibrary.getItemsByProperty(hashPropID,
299  testIdentity);
300  }
301  catch (e) {
302  if (e.result == Components.results.NS_ERROR_NOT_AVAILABLE) {
303  // We didn't find anything. Ignore the exception and let the test
304  // fail with the next assertion so we get a more informative failure
305  // message.
306  }
307  }
308 
309  assertTrue(foundItems.length == 1,
310  'could not find item using identity and getItemsByProperty()');
311 
312  /* We verified that we found items with the same identity, make sure
313  * we retrieve the items that we expect */
314  var foundItems = secondaryLibrary.getItemsWithSameIdentity(testMediaItem);
315  assertEqual(foundItems.length, 1);
316  assertEqual(foundItems.queryElementAt(0, Ci.sbIMediaItem).guid, secondaryItem.guid);
317 
318  foundItems = gTestLibrary.getItemsWithSameIdentity(secondaryItem);
319  assertEqual(foundItems.length, 1);
320  assertEqual(foundItems.queryElementAt(0, Ci.sbIMediaItem).guid, testMediaItem.guid);
321 
322  /* Lastly test that we can manually submit an identity using
323  * SaveIdentityToMediaItem. */
324  gIdentityService.saveIdentityToMediaItem(secondaryItem, "finished");
325  var foundItems = secondaryLibrary.getItemsWithSameIdentity(testMediaItem);
326  assertEqual(foundItems.length, 0);
327  }
328  });
329  }
330 
331  secondaryLibrary.clear();
332 }
const Cc
var gIdentityService
function log(s)
function assertTrue(aTest, aMessage)
function assertEqual(aExpected, aActual, aMessage)
const SEPARATOR
const CONTENT_TYPES
return null
Definition: FeedWriter.js:1143
function createLibrary(databaseGuid, databaseLocation)
Definition: test_load.js:151
function newURI(aURLString)
const Ci
function runTest()
var gTestLibrary