#region License Information /* HeuristicLab * Copyright (C) 2002-2011 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.Linq; using HeuristicLab.Services.Hive.Common; using HeuristicLab.Services.Hive.Common.DataTransfer; using HeuristicLab.Services.Hive.Common.ServiceContracts; using HeuristicLab.Services.Hive.Tests.Mocks; using Microsoft.VisualStudio.TestTools.UnitTesting; using DT = HeuristicLab.Services.Hive.Common.DataTransfer; namespace HeuristicLab.Services.Hive.Tests { [TestClass] public class ServiceTests { // use the mock service locator to modify service properties (such as current user) private static MockServiceLocator mockServiceLocator; [ClassInitialize] public static void MyClassInitialize(TestContext testContext) { mockServiceLocator = new MockServiceLocator(ServiceLocator.Instance); ServiceLocator.Instance = mockServiceLocator; } private IHiveService GetLocalService() { return new HiveService(); } [TestMethod] public void TestJobs() { var service = GetLocalService(); // create hive experiment DT.HiveExperiment experiment = new DT.HiveExperiment() { Name = "TestExperiment", Description = "" }; // create job DT.Job job = new DT.Job() { CoresNeeded = 1, MemoryNeeded = 0, Priority = 0 }; job.State = JobState.Offline; job.StateLog.Add(new StateLog { State = JobState.Offline, DateTime = DateTime.Now }); DT.JobData jobData = new DT.JobData() { //Data = PersistenceUtil.Serialize(new MockJob(500, true)) Data = new byte[10000] }; // delete plugin first (otherwise the system would not allow it because of the same hash code var hash = new byte[] { 1, 2, 3 }; var p = service.GetPluginByHash(hash); if (p != null) service.DeletePlugin(p.Id); // create plugin DT.Plugin plugin1 = new DT.Plugin(); plugin1.Name = "Tests.MyPlugin"; plugin1.Version = new Version("1.0.0.0"); plugin1.UserId = Guid.Empty; plugin1.DateCreated = DateTime.Now; plugin1.Hash = hash; DT.PluginData pluginData1 = new DT.PluginData(); pluginData1.FileName = "Tests.MyPlugin-1.0.dll"; pluginData1.Data = new byte[] { 0, 1, 2, 3, 4, 5 }; plugin1.Id = service.AddPlugin(plugin1, new List { pluginData1 }); pluginData1.PluginId = plugin1.Id; // add plugin job.PluginsNeededIds.Add(plugin1.Id); // create slave DT.Slave slave = new Slave(); slave.Id = Guid.NewGuid(); slave.Name = "TestSlave"; slave.Memory = 1024; slave.Cores = 4; slave.CpuSpeed = 2800; slave.OperatingSystem = "Windows 3.11"; slave.CpuArchitecture = CpuArchitecture.x64; // add slave service.AddSlave(slave); // add hive experiment experiment.Id = service.AddHiveExperiment(experiment); // add job job.HiveExperimentId = experiment.Id; job.Id = service.AddJob(job, jobData, new List { slave.Id }); // test job DT.Job jobLoaded = service.GetJob(job.Id); Assert.AreEqual(job.Id, jobLoaded.Id); Assert.AreEqual(job.CoresNeeded, jobLoaded.CoresNeeded); Assert.AreEqual(job.MemoryNeeded, jobLoaded.MemoryNeeded); Assert.AreEqual(job.Priority, jobLoaded.Priority); Assert.AreEqual(JobState.Waiting, jobLoaded.State); Assert.IsTrue(job.PluginsNeededIds.SequenceEqual(jobLoaded.PluginsNeededIds)); Assert.AreEqual(job.HiveExperimentId, jobLoaded.HiveExperimentId); DT.JobData jobDataLoaded = service.GetJobData(job.Id); Assert.AreEqual(job.Id, jobDataLoaded.JobId); Assert.IsTrue(jobData.Data.SequenceEqual(jobDataLoaded.Data)); // test hive experiment DT.HiveExperiment experimentLoaded = service.GetHiveExperiment(experiment.Id); Assert.AreEqual(experiment.Id, experimentLoaded.Id); Assert.AreEqual(experiment.Name, experimentLoaded.Name); Assert.AreEqual(experiment.Description, experimentLoaded.Description); // test assigned ressources var actions = service.Heartbeat(new Heartbeat() { SlaveId = slave.Id, AssignJob = true, FreeCores = 4, FreeMemory = 1024, JobProgress = new Dictionary() }); Assert.AreEqual(1, actions.Count); Assert.AreEqual(MessageContainer.MessageType.CalculateJob, actions[0].Message); Assert.AreEqual(job.Id, actions[0].JobId); jobLoaded = service.GetJob(job.Id); Assert.AreEqual(JobState.Transferring, jobLoaded.State); // slave is responsible for updating state to 'Calculating' service.UpdateJobState(jobLoaded.Id, JobState.Calculating, slave.Id, null, null); // send progress var progress = new Dictionary(); progress.Add(job.Id, new TimeSpan(1, 5, 10, 20, 30)); actions = service.Heartbeat(new Heartbeat() { SlaveId = slave.Id, AssignJob = true, FreeCores = 3, FreeMemory = 1024, JobProgress = progress }); Assert.AreEqual(0, actions.Count); // the job should be in state 'Calculating' now jobLoaded = service.GetJob(job.Id); Assert.AreEqual(JobState.Calculating, jobLoaded.State); Assert.AreEqual(new TimeSpan(1, 5, 10, 20, 30), jobLoaded.ExecutionTime); // test if the job is returned for the resource var jobsBySlave = service.GetJobsByResourceId(slave.Id); Assert.AreEqual(1, jobsBySlave.Count()); Assert.AreEqual(job.Id, jobsBySlave.Single().Id); // set it to finished service.UpdateJobState(jobLoaded.Id, JobState.Finished, slave.Id, null, null); // test if the job is returned for the resource (it should not be) var jobsBySlave2 = service.GetJobsByResourceId(slave.Id); Assert.AreEqual(0, jobsBySlave2.Count()); // set job waiting again service.UpdateJobState(job.Id, JobState.Waiting, null, null, string.Empty); // get job again actions = service.Heartbeat(new Heartbeat() { SlaveId = slave.Id, AssignJob = true, FreeCores = 4, FreeMemory = 1024, JobProgress = new Dictionary() }); Assert.AreEqual(1, actions.Count); Assert.AreEqual(MessageContainer.MessageType.CalculateJob, actions[0].Message); Assert.AreEqual(job.Id, actions[0].JobId); // create downtime which should make slave unavailable for calculation Guid downtimeId = service.AddDowntime(new Downtime { ResourceId = slave.Id, StartDate = DateTime.Now - TimeSpan.FromMinutes(1), EndDate = DateTime.Now + TimeSpan.FromMinutes(1), Recurring = false }); progress.Clear(); progress.Add(job.Id, new TimeSpan(1, 5, 10, 20, 30)); actions = service.Heartbeat(new Heartbeat() { SlaveId = slave.Id, AssignJob = true, FreeCores = 4, FreeMemory = 1024, JobProgress = new Dictionary() }); Assert.AreEqual(1, actions.Count); Assert.AreEqual(MessageContainer.MessageType.PauseAll, actions[0].Message); Assert.AreEqual(Guid.Empty, actions[0].JobId); service.DeleteDowntime(downtimeId); // delete service.DeleteHiveExperiment(experiment.Id); Assert.AreEqual(null, service.GetHiveExperiment(experiment.Id)); Assert.AreEqual(null, service.GetJob(job.Id)); Assert.AreEqual(null, service.GetJobData(job.Id)); // send another heartbeat with the deleted job; the server should command the abortion of the job actions = service.Heartbeat(new Heartbeat() { SlaveId = slave.Id, AssignJob = true, FreeCores = 3, FreeMemory = 1024, JobProgress = progress }); Assert.AreEqual(1, actions.Count); Assert.AreEqual(MessageContainer.MessageType.AbortJob, actions[0].Message); Assert.AreEqual(job.Id, actions[0].JobId); // delete slave service.DeleteSlave(slave.Id); } [TestMethod] public void TestParentJobs() { var service = GetLocalService(); // create hive experiment DT.HiveExperiment experiment = new DT.HiveExperiment() { Name = "TestExperiment", Description = "" }; // create parent job DT.Job parentJob = new DT.Job() { CoresNeeded = 1, MemoryNeeded = 0, Priority = 0, IsParentJob = true, FinishWhenChildJobsFinished = true }; parentJob.State = JobState.Offline; parentJob.StateLog.Add(new StateLog { State = JobState.Offline, DateTime = DateTime.Now }); DT.JobData parentJobData = new DT.JobData() { Data = new byte[0] }; // create child job DT.Job childJob = new DT.Job() { CoresNeeded = 1, MemoryNeeded = 0, Priority = 0 }; childJob.State = JobState.Offline; childJob.StateLog.Add(new StateLog { State = JobState.Offline, DateTime = DateTime.Now }); DT.JobData childJobData = new DT.JobData() { Data = new byte[1000] }; // create slave DT.Slave slave = new Slave(); slave.Id = Guid.NewGuid(); slave.Name = "TestSlave"; slave.Memory = 1024; slave.Cores = 4; slave.CpuSpeed = 2800; slave.OperatingSystem = "Windows 3.11"; slave.CpuArchitecture = CpuArchitecture.x64; // add slave service.AddSlave(slave); // add hive experiment experiment.Id = service.AddHiveExperiment(experiment); // add parent job parentJob.HiveExperimentId = experiment.Id; parentJob.Id = service.AddJob(parentJob, parentJobData, new List { slave.Id }); // add child job childJob.HiveExperimentId = experiment.Id; childJob.Id = service.AddChildJob(parentJob.Id, childJob, childJobData); childJob.ParentJobId = parentJob.Id; // test child job var childJobLoaded = service.GetJob(childJob.Id); Assert.AreEqual(childJob.ParentJobId, childJobLoaded.ParentJobId); Assert.AreEqual(childJob.HiveExperimentId, childJobLoaded.HiveExperimentId); Assert.AreEqual(JobState.Waiting, childJobLoaded.State); Assert.AreEqual(false, childJobLoaded.FinishWhenChildJobsFinished); Assert.AreEqual(false, childJobLoaded.IsParentJob); // test parent job var parentJobLoaded = service.GetJob(parentJob.Id); Assert.AreEqual(parentJob.HiveExperimentId, parentJobLoaded.HiveExperimentId); Assert.AreEqual(JobState.Waiting, parentJobLoaded.State); Assert.AreEqual(true, parentJobLoaded.FinishWhenChildJobsFinished); Assert.AreEqual(true, parentJobLoaded.IsParentJob); // test heartbeat var actions = service.Heartbeat(new Heartbeat() { SlaveId = slave.Id, AssignJob = true, FreeCores = 4, FreeMemory = 1024, JobProgress = new Dictionary() }); Assert.AreEqual(1, actions.Count); // only the child job should be assigned Assert.AreEqual(MessageContainer.MessageType.CalculateJob, actions[0].Message); Assert.AreEqual(childJob.Id, actions[0].JobId); // lifecycle - let it process one server-heartbeat; the parent job must NOT be set to finished service.TriggerLifecycle(true); parentJobLoaded = service.GetJob(parentJob.Id); Assert.AreEqual(JobState.Waiting, parentJobLoaded.State); // set child job to finished childJobLoaded = service.UpdateJobState(childJobLoaded.Id, JobState.Finished, slave.Id, null, null); // lifecycle - let it process one server-heartbeat; this should set the parent job to finished service.TriggerLifecycle(true); // test if parent job is finished parentJobLoaded = service.GetJob(parentJob.Id); Assert.AreEqual(JobState.Finished, parentJobLoaded.State); // delete experiment service.DeleteHiveExperiment(experiment.Id); Assert.AreEqual(null, service.GetJob(parentJob.Id)); Assert.AreEqual(null, service.GetJob(childJob.Id)); service.DeleteSlave(slave.Id); } [TestMethod] public void TestHiveExperimentPermissions() { var service = GetLocalService(); mockServiceLocator.SetCurrentUserId(MockUserManager.MockUserId1); // create hive experiment DT.HiveExperiment e1 = new DT.HiveExperiment() { Name = "TestExperiment", Description = "" }; e1.Id = service.AddHiveExperiment(e1); var e1loaded = service.GetHiveExperiment(e1.Id); Assert.AreEqual(Permission.Full, e1loaded.Permission); var allExp = service.GetHiveExperiments(); Assert.AreEqual(1, allExp.Count(x => x.Id == e1.Id)); // change to user2 mockServiceLocator.SetCurrentUserId(MockUserManager.MockUserId2); try { e1loaded = service.GetHiveExperiment(e1.Id); Assert.Fail("Access should not be possible"); } catch { /* ok, cool */ } allExp = service.GetHiveExperiments(); Assert.AreEqual(0, allExp.Count(x => x.Id == e1.Id)); // user2 should not be able to grant permissions try { service.GrantPermission(e1.Id, MockUserManager.MockUserId2, Permission.Read); Assert.Fail("Should not be possible to grant permission due to missing permission for User2"); } catch { /* ok, cool */ } // switch back to user1 (owner) and grant user2 permissions mockServiceLocator.SetCurrentUserId(MockUserManager.MockUserId1); service.GrantPermission(e1.Id, MockUserManager.MockUserId2, Permission.Read); // back to user2 mockServiceLocator.SetCurrentUserId(MockUserManager.MockUserId2); e1loaded = service.GetHiveExperiment(e1.Id); Assert.AreEqual(Permission.Read, e1loaded.Permission); allExp = service.GetHiveExperiments(); Assert.AreEqual(1, allExp.Count(x => x.Id == e1.Id)); // user2 should still not be able to grant permissions try { service.GrantPermission(e1.Id, MockUserManager.MockUserId2, Permission.Read); Assert.Fail("Should not be possible to grant permission due to missing permission for User2"); } catch { /* ok, cool */ } // back to user1 mockServiceLocator.SetCurrentUserId(MockUserManager.MockUserId1); service.GrantPermission(e1.Id, MockUserManager.MockUserId2, Permission.Full); // back to user2 mockServiceLocator.SetCurrentUserId(MockUserManager.MockUserId2); e1loaded = service.GetHiveExperiment(e1.Id); Assert.AreEqual(Permission.Full, e1loaded.Permission); allExp = service.GetHiveExperiments(); Assert.AreEqual(1, allExp.Count(x => x.Id == e1.Id)); // grant rights to user3, now this should be possible due to full permissions service.GrantPermission(e1.Id, MockUserManager.MockUserId3, Permission.Read); // back to user1 and revoke rights for user2 mockServiceLocator.SetCurrentUserId(MockUserManager.MockUserId1); service.RevokePermission(e1.Id, MockUserManager.MockUserId2); // back to user2 mockServiceLocator.SetCurrentUserId(MockUserManager.MockUserId2); try { e1loaded = service.GetHiveExperiment(e1.Id); Assert.Fail("Access should not be possible"); } catch { /* ok, cool */ } allExp = service.GetHiveExperiments(); Assert.AreEqual(0, allExp.Count(x => x.Id == e1.Id)); // back to user1 mockServiceLocator.SetCurrentUserId(MockUserManager.MockUserId1); service.DeleteHiveExperiment(e1.Id); } } }