< Summary

Class:Microsoft.Azure.Batch.Conventions.Files.Utilities.ContainerNameUtils
Assembly:Microsoft.Azure.Batch.Conventions.Files
File(s):C:\Git\azure-sdk-for-net\sdk\batch\Microsoft.Azure.Batch.Conventions.Files\src\Utilities\ContainerNameUtils.cs
Covered lines:30
Uncovered lines:0
Coverable lines:30
Total lines:111
Line coverage:100% (30 of 30)
Covered branches:14
Total branches:14
Branch coverage:100% (14 of 14)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-100%100%
GetSafeContainerName(...)-100%100%
GetUnprefixedSafeContainerName(...)-100%100%
TransformToContainerName(...)-100%100%
MakeSafe(...)-100%100%
ToHex(...)-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\batch\Microsoft.Azure.Batch.Conventions.Files\src\Utilities\ContainerNameUtils.cs

#LineLine coverage
 1// Copyright (c) Microsoft and contributors.  All rights reserved.
 2//
 3// Licensed under the Apache License, Version 2.0 (the "License");
 4// you may not use this file except in compliance with the License.
 5// You may obtain a copy of the License at
 6// http://www.apache.org/licenses/LICENSE-2.0
 7//
 8// Unless required by applicable law or agreed to in writing, software
 9// distributed under the License is distributed on an "AS IS" BASIS,
 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11//
 12// See the License for the specific language governing permissions and
 13// limitations under the License.
 14
 15using System;
 16using System.Collections.Generic;
 17using System.Linq;
 18using System.Security.Cryptography;
 19using System.Text;
 20using System.Text.RegularExpressions;
 21using System.Threading.Tasks;
 22
 23namespace Microsoft.Azure.Batch.Conventions.Files.Utilities
 24{
 25    internal static class ContainerNameUtils
 26    {
 127        private static readonly Regex PermittedContainerNamePattern = new Regex("^[a-z0-9][-a-z0-9]*$");
 28
 29        // new instance each time because a shared instance would not be thread-safe
 30#if FullNetFx
 31        private static readonly Func<HashAlgorithm> hasher = () => new SHA1CryptoServiceProvider();
 32#else
 51433        private static readonly Func<HashAlgorithm> hasher = () => SHA1.Create();
 34#endif
 135        private static readonly int MaxJobIdLengthInMungedContainerName = 15;  // must be <= 63 - "job-".Length - 1 (hyp
 136        private static readonly char[] ForbiddenLeadingTrailingContainerNameChars = new[] { '-' };
 137        private static readonly Regex InvalidContainerCharacters = new Regex("[:_-]+");
 38        private const string ContainerPrefix = "job-";
 139        private static readonly int MaxUsableJobIdLength = 63 - ContainerPrefix.Length;
 40
 41        internal static string GetSafeContainerName(string jobId)
 42        {
 91243            return ContainerPrefix + GetUnprefixedSafeContainerName(jobId);
 44        }
 45
 46        private static string GetUnprefixedSafeContainerName(string jobId)
 47        {
 91248            jobId = jobId.ToLowerInvariant();  // it's safe to do this early as job ids cannot differ only by case, so t
 49
 50            // Check that job-{jobId} won't overflow the maximum container name length.
 51            // We don't need a minimum length check because the "job-" prefix ensures
 52            // that the actual container name will be >= 3 characters.
 91253            if (jobId.Length > MaxUsableJobIdLength)
 54            {
 7055                return TransformToContainerName(jobId);
 56            }
 57
 58            // Check that the jobId contains only characters that are valid in a container
 59            // name, and doesn't start with a '-'.
 84260            if (!PermittedContainerNamePattern.IsMatch(jobId))
 61            {
 44062                return TransformToContainerName(jobId);
 63            }
 64
 65            // Check that jobId doesn't end with a '-', and doesn't contain consecutive hyphens.
 40266            if (jobId[jobId.Length - 1] == '-' || jobId.Contains("--"))
 67            {
 368                return TransformToContainerName(jobId);
 69            }
 70
 39971            return jobId;
 72        }
 73
 74        private static string TransformToContainerName(string str)
 75        {
 51376            var hash = hasher().ComputeHash(Encoding.UTF8.GetBytes(str));
 51377            var hashText = ToHex(hash);
 78
 51379            var safeStr = MakeSafe(str);
 80
 51381            safeStr = safeStr.Trim(ForbiddenLeadingTrailingContainerNameChars);
 82
 51383            if (safeStr.Length > MaxJobIdLengthInMungedContainerName)
 84            {
 45485                safeStr = safeStr.Substring(0, MaxJobIdLengthInMungedContainerName)
 45486                                 .Trim(ForbiddenLeadingTrailingContainerNameChars);  // do this again as truncation may 
 87            }
 5988            else if (safeStr.Length == 0)
 89            {
 490                safeStr = "job";
 91            }
 92
 51393            return safeStr + "-" + hashText;
 94        }
 95
 96        private static string MakeSafe(string rawString)
 97        {
 51398            return InvalidContainerCharacters.Replace(rawString, "-");
 99        }
 100
 101        private static string ToHex(byte[] bytes)
 102        {
 513103            var sb = new StringBuilder(bytes.Length * 2);
 21546104            foreach (var b in bytes)
 105            {
 10260106                sb.AppendFormat(b.ToString("x2"));
 107            }
 513108            return sb.ToString();
 109        }
 110    }
 111}