コード例 #1
0
        public async void FileBackupSuccessCallsEncrypt()
        {
            if (File.Exists(this.tempFileName))
            {
                File.Delete(this.tempFileName);
            }

            var underlying = new Mock <IConfigSource>();

            underlying.SetupSequence(t => t.GetDeploymentConfigInfoAsync())
            .ReturnsAsync(ValidConfigInfo1);

            ISerde <DeploymentConfigInfo> serde = this.GetSerde();
            var encryptionProvider = new Mock <IEncryptionProvider>();

            encryptionProvider.Setup(ep => ep.EncryptAsync(It.IsAny <string>()))
            .ReturnsAsync(serde.Serialize(ValidConfigInfo1));
            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, encryptionProvider.Object))
            {
                DeploymentConfigInfo config1 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config1);

                Assert.True(File.Exists(this.tempFileName));
                string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

                string returnedJson = serde.Serialize(config1);

                Assert.Equal(backupJson, returnedJson, true);
                encryptionProvider.Verify(ep => ep.EncryptAsync(It.IsAny <string>()));
            }
        }
コード例 #2
0
        public async void FileBackupReadFromBackupCallsEncryptDecrypt()
        {
            if (File.Exists(this.tempFileName))
            {
                File.Delete(this.tempFileName);
            }

            ISerde <DeploymentConfigInfo> serde = this.GetSerde();
            var encryptionProvider = new Mock <IEncryptionProvider>();

            encryptionProvider.Setup(ep => ep.EncryptAsync(It.IsAny <string>()))
            .ReturnsAsync(serde.Serialize(ValidConfigInfo1));
            encryptionProvider.Setup(ep => ep.DecryptAsync(It.IsAny <string>()))
            .ReturnsAsync(serde.Serialize(ValidConfigInfo1));

            IDeploymentBackupSource fileBackup = new DeploymentFileBackup(this.tempFileName, serde, encryptionProvider.Object);

            await fileBackup.BackupDeploymentConfigAsync(ValidConfigInfo1);

            DeploymentConfigInfo config1 = await fileBackup.ReadFromBackupAsync();

            Assert.NotNull(config1);
            Assert.True(File.Exists(this.tempFileName));
            string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

            string returnedJson = serde.Serialize(config1);
            string expectedJson = serde.Serialize(ValidConfigInfo1);

            Assert.Equal(expectedJson, backupJson, ignoreCase: true);
            Assert.Equal(expectedJson, returnedJson, ignoreCase: true);

            encryptionProvider.Verify(ep => ep.EncryptAsync(It.IsAny <string>()));
            encryptionProvider.Verify(ep => ep.DecryptAsync(It.IsAny <string>()));
        }
コード例 #3
0
        public async void FileBackupSuccessWhenFileNotExists()
        {
            if (File.Exists(this.tempFileName))
            {
                File.Delete(this.tempFileName);
            }

            var underlying = new Mock <IConfigSource>();

            underlying.SetupSequence(t => t.GetDeploymentConfigInfoAsync())
            .ReturnsAsync(ValidConfigInfo1)
            .ThrowsAsync(new InvalidOperationException());
            ISerde <DeploymentConfigInfo> serde = this.GetSerde();

            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance))
            {
                DeploymentConfigInfo config1 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config1);

                Assert.True(File.Exists(this.tempFileName));
                string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

                string returnedJson = serde.Serialize(config1);

                Assert.True(string.Equals(backupJson, returnedJson, StringComparison.OrdinalIgnoreCase));

                DeploymentConfigInfo config2 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config2);

                Assert.Equal(serde.Serialize(config1), serde.Serialize(config2));
            }
        }
コード例 #4
0
        async Task <DeploymentConfigInfo> ReadFromBackup()
        {
            try
            {
                if (!File.Exists(this.configFilePath))
                {
                    Events.BackupFileDoesNotExist(this.configFilePath);
                }
                else
                {
                    using (await this.sync.LockAsync())
                    {
                        string encryptedJson = await DiskFile.ReadAllAsync(this.configFilePath);

                        string json = await this.encryptionProvider.DecryptAsync(encryptedJson);

                        DeploymentConfigInfo deploymentConfigInfo = this.serde.Deserialize(json);
                        Events.ObtainedDeploymentFromBackup(this.configFilePath);
                        return(deploymentConfigInfo);
                    }
                }
            }
            catch (Exception e)
            {
                Events.GetBackupFailed(e, this.configFilePath);
            }
            return(DeploymentConfigInfo.Empty);
        }
コード例 #5
0
ファイル: DiskFileTest.cs プロジェクト: rdivossen/iotedge
        public async Task InvalidInputFails()
        {
            await Assert.ThrowsAsync <ArgumentException>(() => DiskFile.ReadAllAsync(""));

            await Assert.ThrowsAsync <ArgumentException>(() => DiskFile.WriteAllAsync("", "test"));

            await Assert.ThrowsAsync <ArgumentException>(() => DiskFile.WriteAllAsync("temp", ""));
        }
コード例 #6
0
        static async Task <DeploymentConfigInfo> ReadFromDisk(string path, ISerde <DeploymentConfigInfo> serde)
        {
            string json = await DiskFile.ReadAllAsync(path);

            DeploymentConfigInfo deploymentConfig = serde.Deserialize(json);

            return(deploymentConfig);
        }
コード例 #7
0
ファイル: DiskFileTest.cs プロジェクト: rdivossen/iotedge
        public async Task ReadMatchesWrite()
        {
            string written = "edge hub content";
            await DiskFile.WriteAllAsync(this.tempFileName, written);

            string content = await DiskFile.ReadAllAsync(this.tempFileName);

            Assert.True(written == content);
        }
コード例 #8
0
ファイル: DiskFileTest.cs プロジェクト: rdivossen/iotedge
        public async Task TimeoutReadTest()
        {
            // Arrange
            string testString = new string('*', 5000000);
            await DiskFile.WriteAllAsync(this.tempFileName, testString);

            TimeSpan timeout = TimeSpan.Zero;

            // Assert
            await Assert.ThrowsAsync <TimeoutException>(() => DiskFile.ReadAllAsync(this.tempFileName, timeout));

            // To allow for the write operation to finish so that the file can be cleaned up
            await Task.Delay(TimeSpan.FromSeconds(5));
        }
コード例 #9
0
        public async void FileBackupReadFromBackupCallsEncryptDecrypt()
        {
            if (File.Exists(this.tempFileName))
            {
                File.Delete(this.tempFileName);
            }

            var underlying = new Mock <IConfigSource>();

            underlying.SetupSequence(t => t.GetDeploymentConfigInfoAsync())
            .ReturnsAsync(ValidConfigInfo1)
            .ThrowsAsync(new InvalidOperationException());
            ISerde <DeploymentConfigInfo> serde = this.GetSerde();
            var encryptionProvider = new Mock <IEncryptionProvider>();

            encryptionProvider.Setup(ep => ep.EncryptAsync(It.IsAny <string>()))
            .ReturnsAsync(serde.Serialize(ValidConfigInfo1));
            encryptionProvider.Setup(ep => ep.DecryptAsync(It.IsAny <string>()))
            .ReturnsAsync(serde.Serialize(ValidConfigInfo1));

            DeploymentConfigInfo config1;
            DeploymentConfigInfo config2;

            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, encryptionProvider.Object))
            {
                config1 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config1);

                Assert.True(File.Exists(this.tempFileName));
                string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

                string returnedJson = serde.Serialize(config1);

                Assert.True(string.Equals(backupJson, returnedJson, StringComparison.OrdinalIgnoreCase));
            }

            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, encryptionProvider.Object))
            {
                config2 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config2);
            }

            Assert.Equal(serde.Serialize(config1), serde.Serialize(config2));
            encryptionProvider.Verify(ep => ep.EncryptAsync(It.IsAny <string>()));
            encryptionProvider.Verify(ep => ep.DecryptAsync(It.IsAny <string>()));
        }
コード例 #10
0
        public async void FileBackupShouldNotThrowWhenDecryptFails()
        {
            if (File.Exists(this.tempFileName))
            {
                File.Delete(this.tempFileName);
            }

            var underlying = new Mock <IConfigSource>();

            underlying.SetupSequence(t => t.GetDeploymentConfigInfoAsync())
            .ReturnsAsync(ValidConfigInfo1)
            .ThrowsAsync(new InvalidOperationException());
            ISerde <DeploymentConfigInfo> serde = this.GetSerde();
            var encryptionProvider = new Mock <IEncryptionProvider>();

            encryptionProvider.Setup(ep => ep.EncryptAsync(It.IsAny <string>()))
            .ReturnsAsync(serde.Serialize(ValidConfigInfo1));
            encryptionProvider.Setup(ep => ep.DecryptAsync(It.IsAny <string>()))
            .ThrowsAsync(new WorkloadCommunicationException("failed", 404));

            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, encryptionProvider.Object))
            {
                DeploymentConfigInfo config1 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config1);

                Assert.True(File.Exists(this.tempFileName));
                string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

                string returnedJson = serde.Serialize(config1);

                Assert.Equal(backupJson, returnedJson, ignoreCase: true);
            }

            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, encryptionProvider.Object))
            {
                DeploymentConfigInfo config2 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config2);

                Assert.Equal(DeploymentConfigInfo.Empty, config2);
                encryptionProvider.Verify(ep => ep.EncryptAsync(It.IsAny <string>()));
                encryptionProvider.Verify(ep => ep.DecryptAsync(It.IsAny <string>()));
            }
        }
コード例 #11
0
ファイル: DiskFileTest.cs プロジェクト: rdivossen/iotedge
        public async Task OverwriteSuccess()
        {
            string written = "edge hub content";
            await DiskFile.WriteAllAsync(this.tempFileName, written);

            string content = await DiskFile.ReadAllAsync(this.tempFileName);

            Assert.True(content.Length == written.Length);
            Assert.True(written == content);

            written = "edge hub";
            await DiskFile.WriteAllAsync(this.tempFileName, written);

            content = await DiskFile.ReadAllAsync(this.tempFileName);

            Assert.True(content.Length == written.Length);
            Assert.True(written == content);
        }
コード例 #12
0
        public async Task <DeploymentConfigInfo> ReadFromBackupAsync()
        {
            if (!File.Exists(this.Name))
            {
                Events.BackupFileDoesNotExist(this.Name);
                return(DeploymentConfigInfo.Empty);
            }
            else
            {
                string encryptedJson = await DiskFile.ReadAllAsync(this.Name);

                string json = await this.encryptionProvider.DecryptAsync(encryptedJson);

                DeploymentConfigInfo deploymentConfigInfo = this.serde.Deserialize(json);
                Events.ObtainedDeploymentFromBackup(this.Name);
                this.lastBackedUpConfig = Option.Some(deploymentConfigInfo);
                return(deploymentConfigInfo);
            }
        }
コード例 #13
0
        public async void FileBackupSuccessWhenFileNotExists()
        {
            if (File.Exists(this.tempFileName))
            {
                File.Delete(this.tempFileName);
            }

            ISerde <DeploymentConfigInfo> serde      = this.GetSerde();
            IDeploymentBackupSource       fileBackup = new DeploymentFileBackup(this.tempFileName, serde, NullEncryptionProvider.Instance);

            await fileBackup.BackupDeploymentConfigAsync(ValidConfigInfo1);

            Assert.True(File.Exists(this.tempFileName));
            string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

            string expectedJson = serde.Serialize(ValidConfigInfo1);

            Assert.Equal(expectedJson, backupJson, ignoreCase: true);
        }
コード例 #14
0
        public static async Task <EncryptionProvider> CreateAsync(string storagePath, Uri workloadUri, string edgeletWorkloadApiVersion, string moduleId, string genId, string initializationVectorFileName)
        {
            string ivFile = $"{storagePath}/{initializationVectorFileName}";
            string iv;

            using (await asyncLock.LockAsync())
            {
                if (!File.Exists(ivFile))
                {
                    iv = Guid.NewGuid().ToString("N");
                    await DiskFile.WriteAllAsync(ivFile, iv);
                }
                else
                {
                    iv = await DiskFile.ReadAllAsync(ivFile);
                }
            }

            return(new EncryptionProvider(workloadUri, edgeletWorkloadApiVersion, moduleId, genId, iv));
        }
コード例 #15
0
        public async void FileBackupDoesNotHappenIfConfigSourceReportsException()
        {
            if (File.Exists(this.tempFileName))
            {
                File.Delete(this.tempFileName);
            }

            // Arrange
            var underlying = new Mock <IConfigSource>();

            underlying.SetupSequence(cs => cs.GetDeploymentConfigInfoAsync())
            .ReturnsAsync(ValidConfigInfo1)
            .ReturnsAsync(new DeploymentConfigInfo(10, new InvalidOperationException()));

            ISerde <DeploymentConfigInfo> serde = this.GetSerde();

            // Act
            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance))
            {
                // this call should fetch the config properly
                DeploymentConfigInfo config1 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config1);
                Assert.Equal(0, config1.Version);
                Assert.False(config1.Exception.HasValue);

                // this should cause the version with the exception to be returned
                DeploymentConfigInfo config2 = await configSource.GetDeploymentConfigInfoAsync();

                // Assert
                Assert.NotNull(config2);
                Assert.True(config2.Exception.HasValue);
                Assert.IsType <InvalidOperationException>(config2.Exception.OrDefault());

                // this should still be the JSON from the first config - config1
                string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

                string returnedJson = serde.Serialize(config1);
                Assert.True(string.Equals(backupJson, returnedJson, StringComparison.OrdinalIgnoreCase));
            }
        }
コード例 #16
0
        public Task <IEnumerable <Metric> > GetAllMetricsAsync()
        {
            return(Directory.GetFiles(this.directory)
                   .OrderBy(filename => filename)
                   .SelectManyAsync <string, Metric>(async filename =>
            {
                Metric[] fileMetrics;
                try
                {
                    string rawMetrics = await DiskFile.ReadAllAsync(filename);
                    fileMetrics = JsonConvert.DeserializeObject <Metric[]>(rawMetrics) ?? new Metric[0];
                    this.filesToDelete.Add(filename);
                }
                catch
                {
                    fileMetrics = new Metric[0];
                }

                return fileMetrics;
            }));
        }
コード例 #17
0
        public async void FileBackupDoesNotHappenIfConfigSourceEmpty()
        {
            if (File.Exists(this.tempFileName))
            {
                File.Delete(this.tempFileName);
            }

            // Arrange
            var underlying = new Mock <IConfigSource>();

            underlying.SetupSequence(cs => cs.GetDeploymentConfigInfoAsync())
            .ReturnsAsync(ValidConfigInfo1)
            .ReturnsAsync(DeploymentConfigInfo.Empty);

            ISerde <DeploymentConfigInfo> serde = this.GetSerde();

            // Act
            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance))
            {
                // this call should fetch the config properly
                DeploymentConfigInfo config1 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config1);
                Assert.Equal(0, config1.Version);

                // this should cause the version with the exception to be returned
                DeploymentConfigInfo config2 = await configSource.GetDeploymentConfigInfoAsync();

                // Assert
                Assert.NotNull(config2);
                Assert.Equal(0, config2.Version);
                Assert.Equal(config2.DeploymentConfig.Modules, config1.DeploymentConfig.Modules);

                // this should still be the JSON from the first config - config1
                string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

                string returnedJson = serde.Serialize(config1);
                Assert.Equal(backupJson, returnedJson, ignoreCase: true);
            }
        }
コード例 #18
0
        async Task <DeploymentConfigInfo> ReadFromBackup()
        {
            DeploymentConfigInfo backedUpDeploymentConfigInfo = DeploymentConfigInfo.Empty;

            try
            {
                backedUpDeploymentConfigInfo = await this.lastBackedUpConfig
                                               .Map(v => Task.FromResult(v))
                                               .GetOrElse(
                    async() =>
                {
                    if (!File.Exists(this.configFilePath))
                    {
                        Events.BackupFileDoesNotExist(this.configFilePath);
                        return(DeploymentConfigInfo.Empty);
                    }
                    else
                    {
                        using (await this.sync.LockAsync())
                        {
                            string encryptedJson = await DiskFile.ReadAllAsync(this.configFilePath);
                            string json          = await this.encryptionProvider.DecryptAsync(encryptedJson);
                            DeploymentConfigInfo deploymentConfigInfo = this.serde.Deserialize(json);
                            Events.ObtainedDeploymentFromBackup(this.configFilePath);
                            this.lastBackedUpConfig = Option.Some(deploymentConfigInfo);
                            return(deploymentConfigInfo);
                        }
                    }
                });
            }
            catch (Exception e)
            {
                Events.GetBackupFailed(e, this.configFilePath);
            }

            return(backedUpDeploymentConfigInfo);
        }
コード例 #19
0
        public async Task FileBackupReadOnlyWhenUninitialized()
        {
            if (File.Exists(this.tempFileName))
            {
                File.Delete(this.tempFileName);
            }

            var underlying = new Mock <IConfigSource>();

            underlying.SetupSequence(t => t.GetDeploymentConfigInfoAsync())
            .ReturnsAsync(ValidConfigInfo1)
            .ReturnsAsync(DeploymentConfigInfo.Empty)
            .ThrowsAsync(new InvalidOperationException())
            .ReturnsAsync(ValidConfigInfo1)
            .ReturnsAsync(DeploymentConfigInfo.Empty)
            .ThrowsAsync(new InvalidOperationException());

            ISerde <DeploymentConfigInfo> serde = this.GetSerde();
            DeploymentConfigInfo          config1;

            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance))
            {
                config1 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config1);

                Assert.True(File.Exists(this.tempFileName));
                string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

                string returnedJson = serde.Serialize(config1);

                Assert.Equal(backupJson, returnedJson, ignoreCase: true);
                File.Delete(this.tempFileName);

                DeploymentConfigInfo config2 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config2);

                Assert.Equal(serde.Serialize(config1), serde.Serialize(config2));

                DeploymentConfigInfo config3 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config3);

                Assert.Equal(serde.Serialize(config1), serde.Serialize(config3));
            }

            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance))
            {
                config1 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config1);

                Assert.True(File.Exists(this.tempFileName));
                string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

                string returnedJson = serde.Serialize(config1);

                Assert.Equal(backupJson, returnedJson, ignoreCase: true);
            }

            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance))
            {
                DeploymentConfigInfo config5 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config5);

                Assert.Equal(serde.Serialize(config1), serde.Serialize(config5));
            }

            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance))
            {
                DeploymentConfigInfo config5 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config5);

                Assert.Equal(serde.Serialize(config1), serde.Serialize(config5));
            }

            File.Delete(this.tempFileName);
            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance))
            {
                DeploymentConfigInfo config6 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config6);

                Assert.Equal(config6, DeploymentConfigInfo.Empty);
            }
        }
コード例 #20
0
        public async void FileBackupWriteOnlyWhenConfigurationChanges()
        {
            if (File.Exists(this.tempFileName))
            {
                File.Delete(this.tempFileName);
            }

            var underlying = new Mock <IConfigSource>();

            underlying.SetupSequence(t => t.GetDeploymentConfigInfoAsync())
            .ReturnsAsync(ValidConfigInfo1)
            .ReturnsAsync(ValidConfigInfo1)
            .ReturnsAsync(ValidConfigInfo2)
            .ReturnsAsync(ValidConfigInfo2);

            ISerde <DeploymentConfigInfo> serde = this.GetSerde();

            using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance))
            {
                DeploymentConfigInfo config1 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config1);

                Assert.True(File.Exists(this.tempFileName));
                string backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

                string returnedJson = serde.Serialize(config1);

                Assert.True(string.Equals(backupJson, returnedJson, StringComparison.OrdinalIgnoreCase));

                DateTime modifiedTime1 = File.GetLastWriteTimeUtc(this.tempFileName);
                Assert.True(DateTime.UtcNow - modifiedTime1 < TimeSpan.FromSeconds(5));

                DeploymentConfigInfo config2 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config2);

                Assert.Equal(serde.Serialize(config1), serde.Serialize(config2));

                DateTime modifiedTime2 = File.GetLastWriteTimeUtc(this.tempFileName);
                Assert.Equal(modifiedTime2, modifiedTime1);

                DeploymentConfigInfo config3 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config3);

                Assert.True(File.Exists(this.tempFileName));
                backupJson = await DiskFile.ReadAllAsync(this.tempFileName);

                returnedJson = serde.Serialize(config3);

                Assert.True(string.Equals(backupJson, returnedJson, StringComparison.OrdinalIgnoreCase));

                DateTime modifiedTime3 = File.GetLastWriteTimeUtc(this.tempFileName);
                Assert.True(DateTime.UtcNow - modifiedTime1 < TimeSpan.FromSeconds(5));
                Assert.NotEqual(modifiedTime1, modifiedTime3);

                DeploymentConfigInfo config4 = await configSource.GetDeploymentConfigInfoAsync();

                Assert.NotNull(config4);

                Assert.Equal(serde.Serialize(config4), serde.Serialize(config4));

                DateTime modifiedTime4 = File.GetLastWriteTimeUtc(this.tempFileName);
                Assert.Equal(modifiedTime4, modifiedTime3);
            }
        }