예제 #1
0
        /// <summary>
        /// Allows callers to add a service via HTTP requests by providing a
        /// specially formatted service description.
        /// </summary>
        public static async Task AddService(HttpContext context, Func <Task> next)
        {
            RequiresArgument.NotNull(context, "context");
            RequiresArgument.NotNull(next, "next");

            if (!context.Request.Matches("POST", "/__vs/services"))
            {
                await next.Invoke();

                return;
            }

            var serviceDesc = await ParseServiceDescription(context.Request);

            RequestRequires.NotNullOrWhiteSpace(serviceDesc.Method, "An HTTP method, i.e. GET, POST, PUT, DELETE, etc., must be provided");
            RequestRequires.NotNullOrWhiteSpace(serviceDesc.Path, "A path must be provided. For example /api/myResources/53");

            var service = new Service(serviceDesc);

            if (services.TryAdd(service))
            {
                await context.Response.Ok(service.Id.ToString());
            }
            else
            {
                throw new BadRequestException("Unable to add service. A service with the same ID or the same request filter already exists.");
            }
        }
예제 #2
0
        /// <summary>
        /// Allows callers to query a service via HTTP to obtain information such as
        /// the number of times the service has been invoked and the body of the
        /// last request message that was used to invoke the service.
        /// </summary>
        public static async Task QueryService(HttpContext context, Func <Task> next)
        {
            RequiresArgument.NotNull(context, "context");
            RequiresArgument.NotNull(next, "next");

            if (context.Request.Method.ToUpperInvariant() != "GET" ||
                !IsAServicePath(context.Request.Path, out Guid serviceId))
            {
                await next.Invoke();

                return;
            }

            if (services.TryGetById(serviceId, out Service service))
            {
                var stats        = service.Stats;
                var responseBody = new StringBuilder()
                                   .AppendLine($"CallCount: {stats.CallCount}")
                                   .AppendLine()
                                   .AppendLine("LastRequestBody:")
                                   .Append(stats.LastRequestBody)
                                   .ToString();
                await context.Response.Ok(responseBody);
            }
            else
            {
                context.Response.NotFound();
            }
        }
예제 #3
0
        public void RequiresArgument_LengthEquals_ThrowsOnWrongSizeArray()
        {
            // Arrange
            var arr = new[] { 1, 2 };

            // Act
            RequiresArgument.LengthEquals(arr, 3, "Array should contain 3 elements.");
        }
예제 #4
0
파일: Service.cs 프로젝트: jprice628/Mimic
        /// <summary>
        /// Writes the services predefined response to the specified
        /// HttpResponse.
        /// </summary>
        public async Task WriteResponseTo(HttpResponse response)
        {
            RequiresArgument.NotNull(response, "response");

            response.StatusCode  = this.response.StatusCode;
            response.ContentType = this.response.ContentType;
            await response.WriteAsync(this.response.Body);
        }
예제 #5
0
파일: Service.cs 프로젝트: jprice628/Mimic
        /// <summary>
        /// Returns true if the specified service will respond to the same
        /// requests as this one.
        /// </summary>
        public bool HandlesSameRequests(Service other)
        {
            RequiresArgument.NotNull(other, "other");

            return(method == other.method &&
                   path == other.path &&
                   bodyFilter == other.bodyFilter);
        }
예제 #6
0
        public void RequiresArgument_LengthEquals_DoesNothingOnRightSizeArray()
        {
            // Arrange
            var arr = new[] { 1, 2, 3 };

            // Act
            RequiresArgument.LengthEquals(arr, 3, "Array should contain 3 elements.");
        }
예제 #7
0
        /// <summary>
        /// Returns true if the collection contains the specified service.
        /// </summary>
        public bool Contains(Service service)
        {
            RequiresArgument.NotNull(service, "service");

            lock (thisLock)
            {
                return(internalCollection.Contains(service));
            }
        }
예제 #8
0
파일: Service.cs 프로젝트: jprice628/Mimic
        /// <summary>
        /// Updates the service's Stats to reflect the fact that the service
        /// has been invoked.
        /// </summary>
        public void RecordCall(string requestBody)
        {
            RequiresArgument.NotNull(requestBody, "requestBody");

            lock (thisLock)
            {
                callCount++;
                lastRequestBody = requestBody;
            }
        }
예제 #9
0
        /// <summary>
        /// Gets the first service in the collection that matched the
        /// specified predicate. Returns true if a service is found;
        /// otherwise false.
        /// </summary>
        public bool TryGetWhere(Func <Service, bool> predicate, out Service service)
        {
            RequiresArgument.NotNull(predicate, "predicate");

            lock (thisLock)
            {
                service = internalCollection.FirstOrDefault(predicate);
                return(service != null);
            }
        }
예제 #10
0
파일: Service.cs 프로젝트: jprice628/Mimic
        /// <summary>
        /// Returns true when the service's method, path, and body filter
        /// match the specified request and body.
        /// </summary>
        public bool MatchesRequest(HttpRequest request, string body)
        {
            // This method is called in a loop. While is it possible to read
            // the body from the request itself, it would be very inefficient.
            // For this reason, the body is required as a separate argument
            // to the method.
            RequiresArgument.NotNull(request, "request");
            RequiresArgument.NotNull(body, "body");

            return(method == request.Method &&
                   path == WebUtility.UrlDecode(request.Path + request.QueryString).ToUpperInvariant() &&
                   MatchesBodyFilter(body));
        }
예제 #11
0
        /// <summary>
        /// Allow callers to delete all services via HTTP. This is useful for
        /// cleaning up after a set of tests have been run.
        /// </summary>
        public static Task DeleteAllServices(HttpContext context, Func <Task> next)
        {
            RequiresArgument.NotNull(context, "context");
            RequiresArgument.NotNull(next, "next");

            if (!context.Request.Matches("DELETE", "/__vs/services"))
            {
                return(next.Invoke());
            }

            services.Clear();
            context.Response.Ok();
            return(Task.CompletedTask);
        }
예제 #12
0
        /// <summary>
        /// Allows callers to delete a service via HTTP using the service's ID.
        /// </summary>
        public static Task DeleteService(HttpContext context, Func <Task> next)
        {
            RequiresArgument.NotNull(context, "context");
            RequiresArgument.NotNull(next, "next");

            if (context.Request.Method.ToUpperInvariant() != "DELETE" ||
                !IsAServicePath(context.Request.Path, out Guid serviceId))
            {
                return(next.Invoke());
            }

            services.TryRemove(serviceId);
            context.Response.Ok();
            return(Task.CompletedTask);
        }
예제 #13
0
        /// <summary>
        /// Allows callers to invoke services that have been added.
        /// </summary>
        public static async Task InvokeService(HttpContext context, Func <Task> next)
        {
            RequiresArgument.NotNull(context, "context");
            RequiresArgument.NotNull(next, "next");

            string body = context.Request.ReadBody();

            if (services.TryGetWhere(x => x.MatchesRequest(context.Request, body), out Service service))
            {
                service.RecordCall(body);
                await service.WriteResponseTo(context.Response);
            }
            else
            {
                context.Response.NotFound();
            }
        }
예제 #14
0
        /// <summary>
        /// Attempts to add a service to the collection. Returns true if the
        /// service is added. Returns false when another service either has
        /// the same ID or handles the same requests.
        /// </summary>
        public bool TryAdd(Service service)
        {
            RequiresArgument.NotNull(service, "service");

            lock (thisLock)
            {
                if (internalCollection.Any(x =>
                                           x.Id == service.Id ||
                                           x.HandlesSameRequests(service)
                                           ))
                {
                    return(false);
                }
                else
                {
                    internalCollection.Add(service);
                    return(true);
                }
            }
        }
예제 #15
0
파일: Service.cs 프로젝트: jprice628/Mimic
        /// <summary>
        /// Creates a new service using the specified service description. See
        /// the ServiceDesc class for more information.
        /// </summary>
        public Service(ServiceDesc desc)
        {
            RequiresArgument.NotNullOrWhiteSpace(desc.Method, "Method");
            RequiresArgument.NotNullOrWhiteSpace(desc.Path, "Path");
            RequiresArgument.NotNullOrWhiteSpace(desc.ContentType, "ContentType");
            RequiresArgument.NotNullOrWhiteSpace(desc.StatusCode, "StatusCode");
            RequiresArgument.NotNull(desc.Body, "Body");

            thisLock = new object();
            Id       = ParseId(desc.Id);
            // The method and path values are use for string matching, so
            //convert them to upper invariant.
            method     = desc.Method.ToUpperInvariant();
            path       = desc.Path.ToUpperInvariant();
            bodyFilter = desc.BodyContains;
            response   = new ServiceResponse()
            {
                Body        = desc.Body,
                ContentType = desc.ContentType,
                StatusCode  = ParseStatusCode(desc.StatusCode)
            };
            callCount       = 0;
            lastRequestBody = string.Empty;
        }
예제 #16
0
 public void RequiresArgument_NotNull_ThrowsOnNullValue()
 {
     // Act
     RequiresArgument.NotNull(null, "Value cannot be null.");
 }
예제 #17
0
 public void RequiresArgument_NotNull_DoesNothingOnNonNullValue()
 {
     // Act
     RequiresArgument.NotNull(new object(), "Value cannot be null.");
 }
예제 #18
0
 public void RequiresArgument_NotNullOrWhiteSpace_ThrowsOnNullOrWhiteSpaceValue()
 {
     // Act
     RequiresArgument.NotNullOrWhiteSpace("   \t  ", "Value cannot be null or white space.");
 }
예제 #19
0
 public void RequiresArgument_NotNullOrWhiteSpace_DoesNothingOnNonNullValue()
 {
     // Act
     RequiresArgument.NotNullOrWhiteSpace("lorem ipsum", "Value cannot be null.");
 }