#region License Information
/* HeuristicLab
* Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace HeuristicLab.Services.Deployment.Test {
///
///This is a test class for PluginStoreTest and is intended
///to contain all PluginStoreTest Unit Tests
///
[TestClass()]
public class PluginStoreTest {
private System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
private TestContext testContextInstance;
///
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///
public TestContext TestContext {
get {
return testContextInstance;
}
set {
testContextInstance = value;
}
}
#region Additional test attributes
//
//You can use the following additional attributes as you write your tests:
//
//Use ClassInitialize to run code before running the first test in the class
//[ClassInitialize()]
//public static void MyClassInitialize(TestContext testContext)
//{
//}
//
//Use ClassCleanup to run code after all tests in a class have run
//[ClassCleanup()]
//public static void MyClassCleanup()
//{
//}
//
//Use TestInitialize to run code before running each test
//[TestInitialize()]
//public void MyTestInitialize()
//{
//}
//
//Use TestCleanup to run code after each test has run
//[TestCleanup()]
//public void MyTestCleanup()
//{
//}
//
#endregion
///
///A test for PluginFile
///
[TestMethod()]
public void PluginFileTest() {
PluginStore target = new PluginStore();
#region insert and retrieve a plugin file
int oldCount = target.Plugins.Count();
// store a new entry in the db
string name = RandomName();
target.Persist(new PluginDescription(name, new Version(0, 1)), enc.GetBytes("Zipped " + name));
int newCount = target.Plugins.Count();
// make sure the new entry was added to the db
Assert.AreEqual(oldCount + 1, newCount);
// get matching description from db and try to retrieve the stored file
PluginDescription pluginDescription = target.Plugins.Where(p => p.Name == name).Single();
byte[] expected = enc.GetBytes("Zipped " + name);
byte[] actual = target.PluginFile(pluginDescription);
// check retrieved file
Assert.AreEqual(expected.Length, actual.Length);
for (int i = 0; i < expected.Length; i++) {
Assert.AreEqual(expected[i], actual[i]);
}
#endregion
}
///
///A test for Persist
///
[TestMethod()]
public void PersistPluginTest() {
var vers01 = new Version(0, 1);
PluginStore target = new PluginStore();
#region persist single plugin without dependencies
{
string name = RandomName();
int oldCount = target.Plugins.Count();
PluginDescription pluginDescription = new PluginDescription(name, vers01);
byte[] pluginPackage = enc.GetBytes("Zipped " + name);
target.Persist(pluginDescription, pluginPackage);
int newCount = target.Plugins.Count();
Assert.AreEqual(oldCount + 1, newCount);
}
#endregion
#region persist a product with same name and version as an existent product
{
string name = RandomName();
int oldCount = target.Plugins.Count();
PluginDescription pluginDescription = new PluginDescription(name, vers01);
byte[] pluginPackage = enc.GetBytes("Zipped " + name);
target.Persist(pluginDescription, pluginPackage);
int newCount = target.Plugins.Count();
Assert.AreEqual(oldCount + 1, newCount);
// insert same name and version
oldCount = target.Plugins.Count();
pluginDescription = new PluginDescription(name, vers01);
pluginPackage = enc.GetBytes("Zipped " + name);
target.Persist(pluginDescription, pluginPackage);
newCount = target.Plugins.Count();
// make sure old entry was updated
Assert.AreEqual(oldCount, newCount);
// insert new with different version
oldCount = target.Plugins.Count();
pluginDescription = new PluginDescription(name, new Version(0, 2));
pluginPackage = enc.GetBytes("Zipped " + name);
target.Persist(pluginDescription, pluginPackage);
newCount = target.Plugins.Count();
// make sure a new entry was created
Assert.AreEqual(oldCount + 1, newCount);
}
#endregion
#region persist a plugin with an already persisted dependency
{
string name = RandomName();
PluginDescription dependency = new PluginDescription(name, vers01);
// insert dependency first
target.Persist(dependency, enc.GetBytes("Zipped " + name));
// persist another plugin that has a dependency on the first plugin
string name2 = RandomName();
int oldCount = target.Plugins.Count();
PluginDescription newEntity = new PluginDescription(name2, vers01, Enumerable.Repeat(dependency, 1));
byte[] newEntityPackage = enc.GetBytes("Zipped " + name2);
target.Persist(newEntity, newEntityPackage);
int newCount = target.Plugins.Count();
Assert.AreEqual(oldCount + 1, newCount); // only one new plugin should be added
// retrieve second plugin and check dependencies
newEntity = target.Plugins.Where(p => p.Name == name2).Single();
Assert.AreEqual(newEntity.Dependencies.Count(), 1);
Assert.AreEqual(newEntity.Dependencies.First().Name, name);
}
#endregion
#region try to persist a new plugin with a non-existant dependency and check the expected exception
{
// try to persist a new plugin with a non-existant dependency
try {
string pluginName = RandomName();
string dependencyName = RandomName();
var dependency = new PluginDescription(dependencyName, vers01);
var newEntity = new PluginDescription(pluginName, vers01, Enumerable.Repeat(dependency, 1));
target.Persist(newEntity, enc.GetBytes("Zipped " + pluginName));
Assert.Fail("persist should fail with ArgumentException");
}
catch (ArgumentException) {
// this is expected
Assert.IsTrue(true, "expected exception");
}
}
#endregion
#region update the plugin file of an existing plugin
{
// insert new plugin
string pluginName = RandomName();
var newPlugin = new PluginDescription(pluginName, vers01);
target.Persist(newPlugin, enc.GetBytes("Zipped " + pluginName));
// update the plugin file
byte[] expected = enc.GetBytes("Zipped2 " + pluginName);
target.Persist(newPlugin, expected);
// check if the updated file is returned
byte[] actual = target.PluginFile(newPlugin);
// check retrieved file
Assert.AreEqual(expected.Length, actual.Length);
for (int i = 0; i < expected.Length; i++) {
Assert.AreEqual(expected[i], actual[i]);
}
}
#endregion
#region update the dependencies of an existing plugin
{
string dependency1Name = RandomName();
var newDependency1 = new PluginDescription(dependency1Name, vers01);
target.Persist(newDependency1, enc.GetBytes("Zipped " + dependency1Name));
string pluginName = RandomName();
var newPlugin = new PluginDescription(pluginName, vers01, Enumerable.Repeat(newDependency1, 1));
target.Persist(newPlugin, enc.GetBytes("Zipped " + pluginName));
// retrieve plugin
var dbPlugin = target.Plugins.Where(p => p.Name == pluginName).Single();
Assert.AreEqual(dbPlugin.Dependencies.Count(), 1);
Assert.AreEqual(dbPlugin.Dependencies.First().Name, dependency1Name);
// change dependencies
string dependency2Name = RandomName();
var newDependency2 = new PluginDescription(dependency2Name, vers01);
target.Persist(newDependency2, enc.GetBytes("Zipped " + pluginName));
newPlugin = new PluginDescription(pluginName, vers01, new PluginDescription[] { newDependency1, newDependency2 });
target.Persist(newPlugin, enc.GetBytes("Zipped " + pluginName));
// retrieve plugin
dbPlugin = target.Plugins.Where(p => p.Name == pluginName).Single();
Assert.AreEqual(dbPlugin.Dependencies.Count(), 2);
}
#endregion
#region try to insert a plugin that references the same dependency twice and check if the correct exception is thrown
{
string depName = RandomName();
var depPlugin = new PluginDescription(depName, vers01);
target.Persist(depPlugin, enc.GetBytes("Zipped " + depName));
// insert new plugin
string pluginName = RandomName();
var plugin = new PluginDescription(pluginName, vers01, new PluginDescription[] { depPlugin, depPlugin });
try {
target.Persist(plugin, enc.GetBytes("Zipped " + depName));
Assert.Fail("Expected ArgumentException");
}
catch (ArgumentException) {
Assert.IsTrue(true, "Exception thrown as expected");
}
}
#endregion
#region try to insert a plugin that with a cyclic reference
{
string depName = RandomName();
var depPlugin = new PluginDescription(depName, vers01);
target.Persist(depPlugin, enc.GetBytes("Zipped " + depName));
// update the plugin so that it has a dependency on itself
var plugin = new PluginDescription(depName, vers01, new PluginDescription[] { depPlugin });
try {
target.Persist(plugin, enc.GetBytes("Zipped " + depName));
Assert.Fail("Expected ArgumentException");
}
catch (ArgumentException) {
Assert.IsTrue(true, "Exception thrown as expected");
}
}
#endregion
}
///
///A test for Persist
///
[TestMethod()]
public void PersistProductTest() {
Version vers01 = new Version(0, 1);
PluginStore target = new PluginStore();
#region persist a product without plugins to the db
{
string prodName = RandomName();
int oldCount = target.Products.Count();
ProductDescription product = new ProductDescription(prodName, vers01);
target.Persist(product);
int newCount = target.Products.Count();
Assert.AreEqual(oldCount + 1, newCount);
}
#endregion
#region persist a product with the same name and version as an existant product
{
string prodName = RandomName();
int oldCount = target.Products.Count();
ProductDescription product = new ProductDescription(prodName, vers01);
target.Persist(product);
int newCount = target.Products.Count();
Assert.AreEqual(oldCount + 1, newCount);
// write a product with same name and version
oldCount = target.Products.Count();
product = new ProductDescription(prodName, vers01);
target.Persist(product);
newCount = target.Products.Count();
// make sure that the old entry was updated
Assert.AreEqual(oldCount, newCount);
// write a product with same name and different version
oldCount = target.Products.Count();
product = new ProductDescription(prodName, new Version(0, 2));
target.Persist(product);
newCount = target.Products.Count();
// make sure that a new entry was created
Assert.AreEqual(oldCount + 1, newCount);
}
#endregion
#region try to persist a product referencing an non-existant plugin and check the expected exception
{
// try to persist a product referencing a non-existant plugin
string prodName = RandomName();
string pluginName = RandomName();
var plugin = new PluginDescription(pluginName, vers01);
var product = new ProductDescription(prodName, vers01, Enumerable.Repeat(plugin, 1));
try {
target.Persist(product);
Assert.Fail("persist should fail with ArgumentException");
}
catch (ArgumentException) {
// this is expected
Assert.IsTrue(true, "expected exception");
}
}
#endregion
#region persist a product with a single plugin reference
{
string prodName = RandomName();
string pluginName = RandomName();
var plugin = new PluginDescription(pluginName, vers01);
var product = new ProductDescription(prodName, vers01, Enumerable.Repeat(plugin, 1));
// persist the plugin first
int oldCount = target.Products.Count();
target.Persist(plugin, enc.GetBytes("Zipped " + plugin.Name));
target.Persist(product);
int newCount = target.Products.Count();
// make sure the store went through
Assert.AreEqual(oldCount + 1, newCount);
// retrieve the product and check if the plugin list was stored/retrieved correctly
var dbProd = target.Products.Where(p => p.Name == prodName).Single();
Assert.AreEqual(dbProd.Plugins.Count(), 1);
Assert.AreEqual(dbProd.Plugins.First().Name, pluginName);
}
#endregion
#region update the plugin list of an existing product
{
string prodName = RandomName();
string plugin1Name = RandomName();
var plugin1 = new PluginDescription(plugin1Name, vers01);
var product = new ProductDescription(prodName, vers01, Enumerable.Repeat(plugin1, 1));
// persist the plugin first
int oldCount = target.Products.Count();
target.Persist(plugin1, enc.GetBytes("Zipped " + plugin1.Name));
target.Persist(product);
int newCount = target.Products.Count();
// make sure the store went through
Assert.AreEqual(oldCount + 1, newCount);
var plugin2Name = RandomName();
var plugin2 = new PluginDescription(plugin2Name, vers01);
target.Persist(plugin2, enc.GetBytes("Zipped " + plugin2.Name));
product = new ProductDescription(prodName, vers01, new PluginDescription[] { plugin1, plugin2 });
oldCount = target.Products.Count();
target.Persist(product);
newCount = target.Products.Count();
// make sure that a new entry was not created
Assert.AreEqual(oldCount, newCount);
// check the plugin list of the product
var dbProduct = target.Products.Where(p => p.Name == prodName).Single();
Assert.AreEqual(dbProduct.Plugins.Count(), 2);
}
#endregion
#region insert a product which references the same plugin twice and check if the correct exception is thrown
{
string prodName = RandomName();
string plugin1Name = RandomName();
var plugin1 = new PluginDescription(plugin1Name, vers01);
var product = new ProductDescription(prodName, vers01, Enumerable.Repeat(plugin1, 2));
// persist the plugin first
target.Persist(plugin1, enc.GetBytes("Zipped " + plugin1.Name));
try {
target.Persist(product);
Assert.Fail("Expected ArgumentException");
}
catch (ArgumentException) {
Assert.IsTrue(true, "Expected exception was thrown.");
}
}
#endregion
}
[TestMethod]
public void InsertPluginPerformanceTest() {
int nPlugins = 100;
int maxDependencies = 10;
int avgZipFileLength = 32000;
var store = new PluginStore();
Version vers01 = new Version(0, 1);
// create a random byte array to represent file length
byte[] zippedConstant = new byte[avgZipFileLength];
Random r = new Random();
r.NextBytes(zippedConstant);
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
// create plugins
List plugins = new List();
for (int i = 0; i < nPlugins; i++) {
string name = RandomName();
var dependencies = store.Plugins;
if (dependencies.Count() > maxDependencies) dependencies = dependencies.Take(maxDependencies);
var plugin = new PluginDescription(name, vers01, dependencies);
store.Persist(plugin, zippedConstant);
plugins.Add(plugin);
}
stopWatch.Stop();
Assert.Inconclusive("Created " + nPlugins + " plugins in " + stopWatch.ElapsedMilliseconds +
" ms (" + (double)stopWatch.ElapsedMilliseconds / nPlugins + " ms / plugin )");
}
[TestMethod]
public void InsertProductPerformanceTest() {
int nProducts = 50;
int avgProductPlugins = 30;
var store = new PluginStore();
Version vers01 = new Version(0, 1);
Stopwatch stopWatch = new Stopwatch();
Random r = new Random();
var plugins = store.Plugins.ToList();
stopWatch.Start();
// create products
for (int i = 0; i < nProducts; i++) {
string name = RandomName();
List prodPlugins = new List();
for (int j = 0; j < avgProductPlugins; j++) {
var selectedPlugin = plugins[r.Next(0, plugins.Count)];
if (!prodPlugins.Contains(selectedPlugin)) prodPlugins.Add(selectedPlugin);
}
var prod = new ProductDescription(name, vers01, prodPlugins);
store.Persist(prod);
}
stopWatch.Stop();
Assert.Inconclusive("Created " + nProducts + " products in " + stopWatch.ElapsedMilliseconds +
" ms (" + (double)stopWatch.ElapsedMilliseconds / nProducts + " ms / product )");
}
private string RandomName() {
return Guid.NewGuid().ToString();
}
}
}