Exemple #1
0
        public void ItCreatesTheRightNumberOfPartitions()
        {
            // Arrange
            var partitionSize = 3;
            var simulation    = new SimulationModel {
                Id = SIM_ID, PartitioningComplete = false
            };
            var deviceIdsByModel = new Dictionary <string, List <string> >
            {
                { "m1", new List <string> {
                      "d1", "d2", "d3"
                  } },
                { "m2", new List <string> {
                      "j3"
                  } },
                { "m3", new List <string> {
                      "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11"
                  } }
            };

            this.simulations.Setup(x => x.GetAsync(SIM_ID)).ReturnsAsync(simulation);
            this.simulations.Setup(x => x.GetDeviceIdsByModel(simulation)).Returns(deviceIdsByModel);

            // Act
            var instance = this.GetTargetInstance(partitionSize);

            instance.CreateAsync(SIM_ID).CompleteOrTimeout();

            // Assert
            this.partitionsStorage.Verify(x => x.CreateAsync(It.IsAny <StorageRecord>()), Times.Exactly(4));
        }
Exemple #2
0
        public void ItStartsTheDeviceDeletionOnlyIfNotStarted()
        {
            // Arrange
            var simulationId = Guid.NewGuid().ToString();
            var sim          = new SimulationModel
            {
                Id      = simulationId,
                Enabled = true,
                DevicesDeletionStarted = true,
                DeviceModels           = new List <SimulationModel.DeviceModelRef>
                {
                    new SimulationModel.DeviceModelRef {
                        Id = "some", Count = 3
                    }
                }
            };

            IDataRecord storageRecord = new DataRecord {
                Id = "foo"
            };

            storageRecord.SetData(JsonConvert.SerializeObject(sim)).SetETag("*");

            this.simulationsStorage.Setup(x => x.GetAsync(It.IsAny <string>()))
            .ReturnsAsync(storageRecord);

            // Act
            var result = this.target.TryToStartDevicesDeletionAsync(simulationId, this.devices.Object)
                         .CompleteOrTimeout().Result;

            // Assert
            Assert.True(result);
            this.devices.Verify(x => x.DeleteListUsingJobsAsync(It.IsAny <IEnumerable <string> >()), Times.Never);
        }
Exemple #3
0
        public void ItStartsTheDeviceCreationOnlyIfNotStarted()
        {
            // Arrange
            var simulationId = Guid.NewGuid().ToString();
            var sim          = new SimulationModel
            {
                Id           = simulationId, Enabled = true, DevicesCreationStarted = true,
                DeviceModels = new List <SimulationModel.DeviceModelRef>
                {
                    new SimulationModel.DeviceModelRef {
                        Id = "some", Count = 3
                    }
                }
            };

            // Create a DocumentDB Document that will be used to create a StorageRecord object
            var document = new Document();

            document.Id = "foo";
            document.SetPropertyValue("Data", JsonConvert.SerializeObject(sim));
            document.SetPropertyValue("ETag", "*");
            var storageRecord = StorageRecord.FromDocumentDb(document);

            this.mockStorageRecords.Setup(x => x.GetAsync(It.IsAny <string>()))
            .ReturnsAsync(storageRecord);

            // Act
            var result = this.target.TryToStartDevicesCreationAsync(simulationId, this.devices.Object)
                         .CompleteOrTimeout().Result;

            // Assert
            Assert.True(result);
            this.devices.Verify(x => x.CreateListUsingJobsAsync(It.IsAny <IEnumerable <string> >()), Times.Never);
        }
Exemple #4
0
        public void SimulationsCanBeUpserted()
        {
            // Arrange
            this.ThereAreSomeDeviceModels();
            this.ThereAreNoSimulationsInTheStorage();
            // Arrange the simulation data returned by the storage adapter
            var updatedValue = new ValueApiModel {
                ETag = "newETag"
            };

            this.storage.Setup(x => x.UpdateAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()))
            .ReturnsAsync(updatedValue);

            // Act
            var simulation = new SimulationModel
            {
                Id      = SIMULATION_ID,
                Enabled = false,
                ETag    = "oldETag"
            };

            this.target.UpsertAsync(simulation).Wait();

            // Assert
            this.storage.Verify(
                x => x.UpdateAsync(STORAGE_COLLECTION, SIMULATION_ID, It.IsAny <string>(), "oldETag"));
            Assert.Equal("newETag", simulation.ETag);
        }
Exemple #5
0
        public void ItCreatesNewSimulationsWithPartitioningStateNotComplete()
        {
            // Arrange
            this.simulationsStorage.Setup(x => x.GetAsync(It.IsAny <string>()))
            .ReturnsAsync((DataRecord)null);
            var sim = new SimulationModel
            {
                Id      = "1",
                Enabled = true,
                PartitioningComplete = true
            };

            IDataRecord record = new DataRecord();

            record.SetData(JsonConvert.SerializeObject(sim));

            this.simulationsStorage.Setup(x => x.UpsertAsync(It.IsAny <IDataRecord>()))
            .ReturnsAsync(record);

            // Act
            SimulationModel result = this.target.UpsertAsync(sim, false)
                                     .CompleteOrTimeout().Result;

            // Assert
            Assert.False(result.PartitioningComplete);
        }
Exemple #6
0
        public void ItTriggersPartitionsDeletionWhenASimulationIsDisabled()
        {
            // Arrange
            var sim = new SimulationModel
            {
                Id      = "1",
                Enabled = true,
                PartitioningComplete = true,
                ETag = "*"
            };

            IDataRecord storageRecord = new DataRecord();

            storageRecord.SetData(JsonConvert.SerializeObject(sim)).SetETag("*");

            this.simulationsStorage.Setup(x => x.GetAsync(It.IsAny <string>()))
            .ReturnsAsync(storageRecord);
            this.simulationsStorage.Setup(x => x.UpsertAsync(It.IsAny <IDataRecord>(), It.IsAny <string>()))
            .ReturnsAsync(storageRecord);

            // Act
            var update = new SimulationModel
            {
                Id      = sim.Id,
                Enabled = false,
                PartitioningComplete = true,
                ETag = "*"
            };
            var result = this.target.UpsertAsync(update, false).CompleteOrTimeout().Result;

            // Assert
            Assert.False(result.Enabled);
            Assert.False(result.PartitioningComplete);
        }
        private async Task <Models.Simulation> SaveAsync(Models.Simulation simulation, string eTag)
        {
            simulation.Modified = DateTimeOffset.UtcNow;

            // When a simulation is disabled, its partitions are deleted - this triggers the deletion
            if (!simulation.Enabled)
            {
                simulation.PartitioningComplete = false;
            }

            var result = await this.simulationsStorage.UpsertAsync(
                new StorageRecord
            {
                Id   = simulation.Id,
                Data = JsonConvert.SerializeObject(simulation)
            },
                eTag
                );

            // Use the new ETag provided by the storage
            simulation.ETag = result.ETag;
            simulation.Id   = result.Id;

            this.log.Info("Simulation written to storage",
                          () => new
            {
                simulation.Id,
                simulation.Enabled,
                simulation.PartitioningComplete
            });

            return(simulation);
        }
Exemple #8
0
        public void UpsertFailsWhenETagsDoNotMatch()
        {
            // Arrange
            const string ETAG1 = "ETag 001";
            const string ETAG2 = "ETag 002";

            // Mock simulation that will be returned from storage
            // Create a mock Cosmos DB SQL Document object that will contain a
            // different ETag than the one we're trying to use to upsert
            var updatedSimulation = new SimulationModel
            {
                Id   = SIMULATION_ID,
                Name = "Test Simulation 2",
                ETag = ETAG2
            };
            var record = new DataRecord {
                Id = "foo"
            };

            record.SetETag(ETAG2);
            record.SetData(JsonConvert.SerializeObject(updatedSimulation));
            this.simulationsStorage.Setup(x => x.GetAsync(It.IsAny <string>())).ReturnsAsync(record);

            // Act + Assert
            var initialSimulation = new SimulationModel
            {
                Id   = SIMULATION_ID,
                Name = "Test Simulation 1",
                ETag = ETAG1
            };

            Assert.ThrowsAsync <ResourceOutOfDateException>(
                async() => await this.target.UpsertAsync(initialSimulation, false))
            .CompleteOrTimeout();
        }
Exemple #9
0
        public void CreateDefaultSimulation()
        {
            // Arrange
            const int DEFAULT_DEVICE_COUNT = 1;

            this.ThereAreNoSimulationsInTheStorage();
            this.ThereAreSomeDeviceModels();
            var simulation = new SimulationModel();

            this.StorageReturnsSimulationRecordOnCreate(simulation);

            // Return the StorageRecord object that will be passed to StorageRecords
            this.mockStorageRecords.Setup(
                x => x.UpsertAsync(
                    It.IsAny <StorageRecord>(),
                    It.IsAny <string>()))
            .ReturnsAsync((StorageRecord storageRecord, string eTag) => storageRecord);

            // Act
            SimulationModel result = this.target.InsertAsync(simulation, "default").Result;

            // Assert
            Assert.False(result.PartitioningComplete);
            Assert.Equal(this.models.Count, result.DeviceModels.Count);
            for (var i = 0; i < this.models.Count; i++)
            {
                Assert.Equal(this.models[i].Id, result.DeviceModels[i].Id);
                Assert.Equal(DEFAULT_DEVICE_COUNT, result.DeviceModels[i].Count);
            }
        }
Exemple #10
0
        public void ThereAreNoNullPropertiesInTheDeviceModel()
        {
            // Arrange
            this.ThereAreSomeDeviceModels();
            this.ThereAreNoSimulationsInTheStorage();

            // Arrange the simulation data returned by the storage adapter
            var simulation = new SimulationModel
            {
                Id      = SIMULATION_ID,
                ETag    = "ETag0",
                Enabled = true,
                Version = 1
            };
            var updatedValue = new ValueApiModel
            {
                Key  = SIMULATION_ID,
                Data = JsonConvert.SerializeObject(simulation),
                ETag = simulation.ETag
            };

            this.storage.Setup(x => x.UpdateAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()))
            .ReturnsAsync(updatedValue);

            // Act
            this.target.UpsertAsync(simulation).Wait();

            // Assert
            this.storage.Verify(x => x.UpdateAsync(
                                    STORAGE_COLLECTION,
                                    SIMULATION_ID,
                                    It.Is <string>(s => !s.Contains("null")),
                                    "ETag0"));
        }
Exemple #11
0
        public void UpsertRequiresIdWhileInsertDoesNot()
        {
            // Arrange
            var s1 = new SimulationModel()
            {
                Name = "Test Simulation 1"
            };
            var s2 = new SimulationModel()
            {
                Name = "Test Simulation 2"
            };

            this.ThereAreNoSimulationsInTheStorage();
            this.StorageReturnsSimulationRecordOnCreate(s1);
            var s2StorageRecord = new StorageRecord
            {
                Id   = s2.Id,
                Data = JsonConvert.SerializeObject(s2),
            };

            this.mockStorageRecords.Setup(x => x.UpsertAsync(It.IsAny <StorageRecord>()))
            .ReturnsAsync(s2StorageRecord);

            // Act - No exception occurs
            this.target.InsertAsync(s1).Wait(Constants.TEST_TIMEOUT);

            // Act + Assert
            Assert.ThrowsAsync <InvalidInputException>(async() => await this.target.UpsertAsync(s2))
            .Wait(Constants.TEST_TIMEOUT);
        }
Exemple #12
0
        public void ItCreatesNewSimulationsWithPartitioningStateNotComplete()
        {
            // Arrange
            this.mockStorageRecords.Setup(x => x.GetAsync(It.IsAny <string>()))
            .ReturnsAsync((StorageRecord)null);
            var sim = new SimulationModel
            {
                Id      = "1",
                Enabled = true,
                PartitioningComplete = true
            };
            var record = new ValueApiModel
            {
                Key  = "1",
                Data = JsonConvert.SerializeObject(sim),
            };

            // Create a DocumentDB Document that will be used to create a StorageRecord object
            var document = new Document();

            document.Id = "foo";
            document.SetPropertyValue("Data", JsonConvert.SerializeObject(sim));
            var storageRecord = StorageRecord.FromDocumentDb(document);

            this.mockStorageRecords.Setup(x => x.UpsertAsync(It.IsAny <StorageRecord>()))
            .ReturnsAsync(storageRecord);

            // Act
            SimulationModel result = this.target.UpsertAsync(sim).CompleteOrTimeout().Result;

            // Assert
            Assert.False(result.PartitioningComplete);
        }
Exemple #13
0
        public void ItGenerateDevicesIdGroupedByModel()
        {
            // Arrange
            var sim = new SimulationModel
            {
                Id      = "1",
                Enabled = true,
                PartitioningComplete = true,
                DeviceModels         = new List <SimulationModel.DeviceModelRef>
                {
                    new SimulationModel.DeviceModelRef {
                        Id = "modelA", Count = 5
                    },
                    new SimulationModel.DeviceModelRef {
                        Id = "modelB", Count = 2
                    },
                    new SimulationModel.DeviceModelRef {
                        Id = "modelC", Count = 4
                    }
                }
            };

            // Act
            Dictionary <string, List <string> > result = this.target.GetDeviceIdsByModel(sim);

            // Assert
            Assert.Equal(3, result.Count);
            Assert.True(result.ContainsKey("modelA"));
            Assert.True(result.ContainsKey("modelB"));
            Assert.True(result.ContainsKey("modelC"));
            Assert.Equal(5, result["modelA"].Count);
            Assert.Equal(2, result["modelB"].Count);
            Assert.Equal(4, result["modelC"].Count);
        }
Exemple #14
0
        public void ItStartsTheDeviceBulkDeletionUsingJobs()
        {
            // Arrange
            var eTagValue = "*";
            var sim       = new SimulationModel
            {
                Id      = "1",
                Enabled = true,
                PartitioningComplete = true,
                ETag = eTagValue
            };

            IDataRecord storageRecord = new DataRecord {
                Id = sim.Id
            };

            storageRecord.SetData(JsonConvert.SerializeObject(sim)).SetETag(eTagValue);

            this.simulationsStorage.Setup(x => x.GetAsync(It.IsAny <string>()))
            .ReturnsAsync(storageRecord);

            // Act
            var result = this.target.TryToStartDevicesDeletionAsync(sim.Id, this.devices.Object)
                         .CompleteOrTimeout().Result;

            // Assert
            Assert.True(result);
            this.devices.Verify(x => x.DeleteListUsingJobsAsync(It.IsAny <IEnumerable <string> >()), Times.Once);
            this.simulationsStorage.Verify(
                x => x.UpsertAsync(
                    It.Is <IDataRecord>(
                        sr => JsonConvert.DeserializeObject <SimulationModel>(sr.GetData()).DevicesDeletionStarted),
                    It.IsAny <string>()), Times.Once());
        }
        /// <summary>
        /// Create or Replace a simulation.
        /// The logic works under the assumption that there is only one simulation with id "1".
        /// </summary>
        public async Task <Models.Simulation> UpsertAsync(Models.Simulation simulation)
        {
            if (simulation.Id != SIMULATION_ID)
            {
                this.log.Warn("Invalid simulation ID. Only one simulation is allowed", () => { });
                throw new InvalidInputException("Invalid simulation ID. Use ID '" + SIMULATION_ID + "'.");
            }

            var simulations = await this.GetListAsync();

            if (simulations.Count > 0)
            {
                this.log.Info("Modifying simulation via PUT.", () => { });

                if (simulation.ETag == "*")
                {
                    simulation.ETag = simulations[0].ETag;
                    this.log.Info("The client used ETag='*' choosing to overwrite the current simulation", () => { });
                }

                if (simulation.ETag != simulations[0].ETag)
                {
                    this.log.Error("Invalid ETag. Running simulation ETag is:'", () => new { simulations });
                    throw new ResourceOutOfDateException("Invalid ETag. Running simulation ETag is:'" + simulations[0].ETag + "'.");
                }

                simulation.Created  = simulations[0].Created;
                simulation.Modified = DateTimeOffset.UtcNow;
                simulation.Version  = simulations[0].Version + 1;
            }
            else
            {
                this.log.Info("Creating new simulation via PUT.", () => { });
                // new simulation
                simulation.Created  = DateTimeOffset.UtcNow;
                simulation.Modified = simulation.Created;
                simulation.Version  = 1;
            }

            // Note: forcing the ID because only one simulation can be created
            simulation.Id = SIMULATION_ID;

            // TODO if write to storage adapter fails, the iothub connection string
            //      will still be stored to disk. Storing the encrypted string using
            //      storage adapter would address this
            //      https://github.com/Azure/device-simulation-dotnet/issues/129
            simulation.IotHubConnectionString = await this.connectionStringManager.RedactAndStoreAsync(simulation.IotHubConnectionString);

            var result = await this.storage.UpdateAsync(
                STORAGE_COLLECTION,
                SIMULATION_ID,
                JsonConvert.SerializeObject(simulation),
                simulation.ETag);

            // Return the new ETag provided by the storage
            simulation.ETag = result.ETag;

            return(simulation);
        }
        /// <summary>
        /// Create a simulation.
        /// </summary>
        public async Task <Models.Simulation> InsertAsync(Models.Simulation simulation, string template = "")
        {
            // TODO: complete validation
            if (!string.IsNullOrEmpty(template) && template.ToLowerInvariant() != "default")
            {
                this.log.Warn("Unknown template name", () => new { template });
                throw new InvalidInputException("Unknown template name. Try 'default'.");
            }

            var simulations = await this.GetListAsync();

            if (simulations.Count > 0)
            {
                this.log.Warn("There is already a simulation", () => { });
                throw new ConflictingResourceException(
                          "There is already a simulation. Only one simulation can be created.");
            }

            // Note: forcing the ID because only one simulation can be created
            simulation.Id       = SIMULATION_ID;
            simulation.Created  = DateTimeOffset.UtcNow;
            simulation.Modified = simulation.Created;
            simulation.Version  = 1;

            // Create default simulation
            if (!string.IsNullOrEmpty(template) && template.ToLowerInvariant() == "default")
            {
                var types = await this.deviceModels.GetListAsync();

                simulation.DeviceModels = new List <Models.Simulation.DeviceModelRef>();
                foreach (var type in types)
                {
                    simulation.DeviceModels.Add(new Models.Simulation.DeviceModelRef
                    {
                        Id    = type.Id,
                        Count = DEVICES_PER_MODEL_IN_DEFAULT_TEMPLATE
                    });
                }
            }

            // TODO if write to storage adapter fails, the iothub connection string
            //      will still be stored to disk. Storing the encrypted string using
            //      storage adapter would address this
            //      https://github.com/Azure/device-simulation-dotnet/issues/129
            simulation.IotHubConnectionString = await this.connectionStringManager.RedactAndStoreAsync(simulation.IotHubConnectionString);

            // Note: using UpdateAsync because the service generates the ID
            var result = await this.storage.UpdateAsync(
                STORAGE_COLLECTION,
                SIMULATION_ID,
                JsonConvert.SerializeObject(simulation),
                "*");

            simulation.ETag = result.ETag;

            return(simulation);
        }
        /// <summary>
        /// Create a simulation.
        /// </summary>
        public async Task <Models.Simulation> InsertAsync(Models.Simulation simulation, string template = "")
        {
            var usingDefaultTemplate = !string.IsNullOrEmpty(template) && template.ToLowerInvariant() == DEFAULT_TEMPLATE_NAME;

            if (!string.IsNullOrEmpty(template) && template.ToLowerInvariant() != DEFAULT_TEMPLATE_NAME)
            {
                this.log.Warn("Unknown template name", () => new { template });
                throw new InvalidInputException("Unknown template name. Try 'default'.");
            }

            if (!usingDefaultTemplate && string.IsNullOrEmpty(simulation.Name))
            {
                this.log.Warn("Missing simulation name", () => new { });
                throw new InvalidInputException("Simulation name is required.");
            }

            // Note: forcing the ID because only one simulation can be created
            simulation.Id      = usingDefaultTemplate ? DEFAULT_SIMULATION_ID : Guid.NewGuid().ToString();
            simulation.Created = DateTimeOffset.UtcNow;

            // Create default simulation
            if (usingDefaultTemplate)
            {
                simulation.Name = "Default Simulation";
                var types = await this.deviceModels.GetListAsync();

                simulation.DeviceModels = new List <Models.Simulation.DeviceModelRef>();
                foreach (var type in types)
                {
                    simulation.DeviceModels.Add(new Models.Simulation.DeviceModelRef
                    {
                        Id    = type.Id,
                        Count = DEVICES_PER_MODEL_IN_DEFAULT_TEMPLATE
                    });
                }

                simulation.IotHubConnectionStrings = new List <string> {
                    ServicesConfig.USE_DEFAULT_IOTHUB
                };
            }

            for (var index = 0; index < simulation.IotHubConnectionStrings.Count; index++)
            {
                var connString = await this.connectionStringManager.RedactAndSaveAsync(simulation.IotHubConnectionStrings[index]);

                if (!simulation.IotHubConnectionStrings.Contains(connString))
                {
                    simulation.IotHubConnectionStrings[index] = connString;
                }
            }

            // This value cannot be set by the user, we set it here and make sure it's "false"
            simulation.PartitioningComplete = false;

            return(await this.SaveAsync(simulation, "*"));
        }
Exemple #18
0
        public void UpsertWillSucceedWhenETagsMatch()
        {
            // Arrange
            const string ETAG1 = "ETag 001";
            const string ETAG2 = "ETag 002";

            // Mock simulation that will be returned from storage
            var existingSimulation = new SimulationModel {
                Id = SIMULATION_ID, Name = "Test Simulation 2", ETag = ETAG1
            };
            var updatedStorageRecord = new StorageRecord
            {
                Id   = SIMULATION_ID,
                Data = JsonConvert.SerializeObject(existingSimulation),
            };

            // Create a mock DocumentDB Document object that will contain the
            // same ETag value as the one we're trying to use to upsert with.
            var document = new Document();

            document.Id = "foo";
            document.SetPropertyValue("_etag", ETAG1);
            document.SetPropertyValue("Data", JsonConvert.SerializeObject(existingSimulation));
            var mockStorageRecord = StorageRecord.FromDocumentDb(document);

            // Initial simulation
            var initialSimulation = new SimulationModel {
                Id = SIMULATION_ID, Name = "Test Simulation 1", ETag = ETAG1
            };
            var initialStorageRecord = new StorageRecord
            {
                Id   = SIMULATION_ID,
                Data = JsonConvert.SerializeObject(initialSimulation),
            };

            // Create a second document that will be returned after the upsert,
            // which will contain an updated ETag
            var upsertResultDocument = new Document();

            upsertResultDocument.Id = "bar";
            upsertResultDocument.SetPropertyValue("_etag", ETAG2);
            upsertResultDocument.SetPropertyValue("Data", JsonConvert.SerializeObject(initialSimulation));
            var upsertResultStorageRecord = StorageRecord.FromDocumentDb(upsertResultDocument);

            this.mockStorageRecords.Setup(x => x.GetAsync(It.IsAny <string>())).ReturnsAsync(mockStorageRecord);
            this.mockStorageRecords.Setup(x => x.UpsertAsync(It.IsAny <StorageRecord>(), It.IsAny <string>())).ReturnsAsync(upsertResultStorageRecord);

            // Act
            var returnedSimulationTask = this.target.UpsertAsync(initialSimulation);

            returnedSimulationTask.Wait(Constants.TEST_TIMEOUT);

            // Assert
            Assert.Matches(ETAG2, returnedSimulationTask.Result.ETag);
        }
Exemple #19
0
        public void UpsertUsesOptimisticConcurrency()
        {
            // Arrange
            const string ETAG1 = "001";
            const string ETAG2 = "002";

            // Initial simulation
            var simulation1 = new SimulationModel {
                Id = SIMULATION_ID, ETag = ETAG1
            };
            var storageRecord1 = new ValueApiModel
            {
                Key  = SIMULATION_ID,
                Data = JsonConvert.SerializeObject(simulation1),
                ETag = simulation1.ETag
            };
            var storageList1 = new ValueListApiModel();

            storageList1.Items.Add(storageRecord1);

            // Simulation after update
            var simulation2 = new SimulationModel {
                Id = SIMULATION_ID, ETag = ETAG2
            };
            var storageRecord2 = new ValueApiModel
            {
                Key  = SIMULATION_ID,
                Data = JsonConvert.SerializeObject(simulation2),
                ETag = simulation2.ETag
            };
            var storageList2 = new ValueListApiModel();

            storageList2.Items.Add(storageRecord2);

            // Initial setup - the ETag matches
            this.storage.Setup(x => x.GetAllAsync(STORAGE_COLLECTION)).ReturnsAsync(storageList1);
            this.storage.Setup(x => x.UpdateAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()))
            .ReturnsAsync(storageRecord2);

            // Act - No exception because ETag matches
            // Note: the call to UpsertAsync modifies the object, don't reuse the variable later
            this.target.UpsertAsync(simulation1).Wait(Constants.TEST_TIMEOUT);

            // Arrange - the ETag won't match
            this.storage.Setup(x => x.GetAllAsync(STORAGE_COLLECTION)).ReturnsAsync(storageList2);

            // Act + Assert
            var simulationOutOfDate = new SimulationModel {
                Id = SIMULATION_ID, ETag = ETAG1
            };

            Assert.ThrowsAsync <ResourceOutOfDateException>(
                async() => await this.target.UpsertAsync(simulationOutOfDate))
            .Wait(Constants.TEST_TIMEOUT);
        }
        // This creates sample simulations that will be shown on simulation dashboard by default
        private async Task SeedSimulationsAsync(string templateName)
        {
            string content;
            var    fileName = templateName + ".json";
            var    filePath = Path.Combine(this.config.SeedTemplateFolder, fileName);

            if (this.fileSystem.Exists(filePath))
            {
                content = this.fileSystem.ReadAllText(filePath);
            }
            else
            {
                this.log.Debug("Template not found for setting sample simulations.");
                return;
            }

            Models.Simulation simulation = null;

            try
            {
                var simulationList = JsonConvert.DeserializeObject <List <Models.Simulation> >(content);
                if (simulationList == null || simulationList.Count == 0)
                {
                    return;
                }

                for (int index = 0; index < simulationList.Count; index++)
                {
                    // We need to start creating simulations starting with id 1 as it is treated as default simulation
                    // and is referenced in Welcome page on UI
                    simulation = simulationList[index];
                    var simulationId = index + 1;
                    simulation.Id = simulationId.ToString();

                    try
                    {
                        // Check if there is an existing simulation with the given id
                        // if it exists then skip creating a new simulation
                        await this.GetAsync(simulation.Id);
                    }
                    catch (ResourceNotFoundException)
                    {
                        // create a simulation if no sample simulation exists with provided id.
                        simulation.StartTime = DateTimeOffset.UtcNow;
                        await this.UpsertAsync(simulation);
                    }
                }
            }
            catch (Exception ex)
            {
                var message = "Failed to create sample simulation. " + " template: " + JsonConvert.SerializeObject(simulation);
                this.log.Error(message, ex);
            }
        }
Exemple #21
0
        public void UpsertRequiresIdWhileInsertDoesNot()
        {
            // Act
            var s1 = new SimulationModel();
            var s2 = new SimulationModel();

            this.target.InsertAsync(s1);

            // Act + Assert
            Assert.ThrowsAsync <InvalidInputException>(() => this.target.UpsertAsync(s2));
        }
        public void InitialMetadataAfterCreation()
        {
            // Arrange
            this.ThereAreNoSimulationsInTheStorage();
            this.ThereAreSomeDeviceModels();

            // Act
            SimulationModel result = this.target.InsertAsync(new SimulationModel(), "default").Result;

            // Assert
            Assert.Equal(result.Created, result.Modified);
        }
        private async Task <Models.Simulation> ResetSimulationStatisticsAsync(Models.Simulation simulation)
        {
            // Reset ActualStartTime, which is used to calculate statistics
            // from the moment when the simulation starts connecting devices and sending telemetry,
            // i.e. after the devices have been created.
            simulation.ActualStartTime = null;

            // Delete statistics records on simulation start
            await this.simulationStatistics.DeleteSimulationStatisticsAsync(simulation.Id);

            return(simulation);
        }
Exemple #24
0
        public void CreateSimulationWithoutId()
        {
            // Arrange
            this.ThereAreNoSimulationsInTheStorage();
            this.ThereAreSomeDeviceModels();

            // Act
            SimulationModel result = this.target.InsertAsync(new SimulationModel(), "default").Result;

            // Assert
            Assert.NotEmpty(result.Id);
        }
        private async Task <bool> TryToUpdateSimulationAsync(Models.Simulation simulation)
        {
            try
            {
                await this.SaveAsync(simulation, simulation.ETag);
            }
            catch (ConflictingResourceException e)
            {
                this.log.Warn("Update failed, another client modified the simulation record", e);
                return(false);
            }

            return(true);
        }
Exemple #26
0
        public async Task <Models.Simulation> InsertAsync(Models.Simulation simulation, string template = "")
        {
            // TODO: complete validation
            if (!string.IsNullOrEmpty(template) && template.ToLowerInvariant() != "default")
            {
                this.log.Warn("Unknown template name", () => new { template });
                throw new InvalidInputException("Unknown template name. Try 'default'.");
            }

            var simulations = await this.GetListAsync();

            if (simulations.Count > 0)
            {
                this.log.Warn("There is already a simulation", () => { });
                throw new ConflictingResourceException(
                          "There is already a simulation. Only one simulation can be created.");
            }

            // Note: forcing the ID because only one simulation can be created
            simulation.Id       = SIMULATION_ID;
            simulation.Created  = DateTimeOffset.UtcNow;
            simulation.Modified = simulation.Created;
            simulation.Version  = 1;

            // Create default simulation
            if (!string.IsNullOrEmpty(template) && template.ToLowerInvariant() == "default")
            {
                var types = this.deviceModels.GetList();
                simulation.DeviceModels = new List <Models.Simulation.DeviceModelRef>();
                foreach (var type in types)
                {
                    simulation.DeviceModels.Add(new Models.Simulation.DeviceModelRef
                    {
                        Id    = type.Id,
                        Count = DEVICES_PER_MODEL_IN_DEFAULT_TEMPLATE
                    });
                }
            }

            // Note: using UpdateAsync because the service generates the ID
            var result = await this.storage.UpdateAsync(
                STORAGE_COLLECTION,
                SIMULATION_ID,
                JsonConvert.SerializeObject(simulation),
                "*");

            simulation.Etag = result.ETag;

            return(simulation);
        }
Exemple #27
0
        public void InitialMetadataAfterCreation()
        {
            // Arrange
            this.ThereAreNoSimulationsInTheStorage();
            this.ThereAreSomeDeviceModels();
            this.StorageReturnsSimulationRecordOnCreate();

            // Act
            SimulationModel result = this.target.InsertAsync(new SimulationModel(), "default").Result;

            // Assert
            Assert.False(result.PartitioningComplete);
            Assert.True(Math.Abs(result.Modified.ToUnixTimeSeconds() - result.Created.ToUnixTimeSeconds()) < 10);
        }
Exemple #28
0
        public void ItChangesTheSimulationStatusWhenTheDeviceCreationIsComplete()
        {
            // Arrange
            var simulationId = Guid.NewGuid().ToString();
            var sim          = new SimulationModel
            {
                Id      = simulationId,
                Enabled = true,
                DevicesCreationStarted = false,
                DeviceModels           = new List <SimulationModel.DeviceModelRef>
                {
                    new SimulationModel.DeviceModelRef {
                        Id = "some", Count = 3
                    }
                }
            };

            IDataRecord storageRecord = new DataRecord {
                Id = simulationId
            };

            storageRecord.SetData(JsonConvert.SerializeObject(sim)).SetETag("*");

            this.simulationsStorage.Setup(x => x.GetAsync(It.IsAny <string>()))
            .ReturnsAsync(storageRecord);

            // Act
            var result = this.target.TryToSetDeviceCreationCompleteAsync(simulationId)
                         .CompleteOrTimeout().Result;

            // Assert - operation succeeded
            Assert.True(result);

            // Assert - DevicesCreationComplete is set to true
            Func <string, SimulationModel> deserialize = JsonConvert.DeserializeObject <SimulationModel>;

            this.simulationsStorage.Verify(x => x.BuildRecord(sim.Id, It.Is <string>(
                                                                  sr => deserialize(sr).DevicesCreationComplete == true)), Times.Once());

            // Assert - DevicesDeletionComplete, DeviceDeletionJobId and DevicesDeletionStarted are reset
            this.simulationsStorage.Verify(x => x.BuildRecord(sim.Id, It.Is <string>(
                                                                  sr => deserialize(sr).DevicesDeletionComplete == false)), Times.Once());
            this.simulationsStorage.Verify(x => x.BuildRecord(sim.Id, It.Is <string>(
                                                                  sr => deserialize(sr).DeviceDeletionJobId == null)), Times.Once());
            this.simulationsStorage.Verify(x => x.BuildRecord(sim.Id, It.Is <string>(
                                                                  sr => deserialize(sr).DevicesDeletionStarted == false)), Times.Once());

            // Assert - only one write
            this.simulationsStorage.Verify(x => x.UpsertAsync(It.IsAny <IDataRecord>(), It.IsAny <string>()), Times.Once());
        }
Exemple #29
0
        public void CreatingMultipleSimulationsIsNotAllowed()
        {
            // Arrange
            this.ThereAreSomeDeviceModels();
            this.ThereIsAnEnabledSimulationInTheStorage();

            // Act + Assert
            var s = new SimulationModel {
                Id = Guid.NewGuid().ToString(), Enabled = false
            };

            Assert.ThrowsAsync <ConflictingResourceException>(() => this.target.InsertAsync(s));
            Assert.ThrowsAsync <ConflictingResourceException>(() => this.target.UpsertAsync(s));
        }
Exemple #30
0
        public void CreateSimulationWithId()
        {
            // Arrange
            this.ThereAreSomeDeviceModels();
            this.ThereAreNoSimulationsInTheStorage();

            // Act
            var simulation = new SimulationModel {
                Id = "123"
            };
            SimulationModel result = this.target.InsertAsync(simulation, "default").Result;

            // Assert
            Assert.Equal(simulation.Id, result.Id);
        }