├── .github ├── dependabot.yml ├── github-release.js └── workflows │ ├── cicd.yaml │ ├── cut-release.yaml │ ├── distroless.yaml │ ├── docs.yaml │ ├── examples.yaml │ ├── integ-test.yaml │ ├── maven-publish.yaml │ ├── pipeline.yaml │ ├── release.yaml │ └── validate.yaml ├── .gitignore ├── CHANGELOG.md ├── COPYING ├── COPYING.LESSER ├── LICENSE ├── README.md ├── adapter ├── awslambda │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── awslambda │ │ │ ├── AbstractHandler.kt │ │ │ ├── Handler.kt │ │ │ ├── HandlerV2.kt │ │ │ ├── config │ │ │ └── Settings.kt │ │ │ ├── impl │ │ │ ├── LambdaServer.kt │ │ │ ├── LambdaServerFactory.kt │ │ │ ├── ServerV1.kt │ │ │ ├── ServerV2.kt │ │ │ └── model │ │ │ │ ├── LambdaHttpExchange.kt │ │ │ │ ├── LambdaHttpRequestV1.kt │ │ │ │ ├── LambdaHttpRequestV2.kt │ │ │ │ └── LambdaHttpResponse.kt │ │ │ └── util │ │ │ ├── FormParserUtil.kt │ │ │ ├── ImposterBuilderKt.kt │ │ │ ├── LambdaModule.kt │ │ │ └── PluginUtil.kt │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── awslambda │ │ │ ├── AbstractHandlerTest.kt │ │ │ ├── Handled404Test.kt │ │ │ ├── HandlerTest.kt │ │ │ ├── HandlerV2Test.kt │ │ │ ├── OpenApiSimpleTest.kt │ │ │ ├── RequestWithQueryTest.kt │ │ │ ├── S3DownloadTest.kt │ │ │ ├── SoapDuplicateEndpointTest.kt │ │ │ ├── SoapSimpleTest.kt │ │ │ └── util │ │ │ └── FormParserUtilTest.kt │ │ └── resources │ │ ├── handled-404 │ │ ├── config │ │ │ └── mock-config.yaml │ │ ├── requests_v1 │ │ │ └── request.json │ │ └── requests_v2 │ │ │ └── request.json │ │ ├── openapi-simple │ │ ├── config │ │ │ ├── imposter-config.yaml │ │ │ └── petstore.yaml │ │ └── requests │ │ │ ├── spec_ui.json │ │ │ └── success.json │ │ ├── request-with-query │ │ ├── config │ │ │ ├── mock-config.yaml │ │ │ └── response.json │ │ ├── requests_v1 │ │ │ └── request_with_query.json │ │ └── requests_v2 │ │ │ └── request_with_query.json │ │ ├── simple │ │ ├── config │ │ │ ├── assets │ │ │ │ └── styles.css │ │ │ ├── imposter-config.yaml │ │ │ ├── pet-api.yaml │ │ │ ├── subdir │ │ │ │ └── response.json │ │ │ └── www │ │ │ │ └── index.html │ │ ├── requests_v1 │ │ │ ├── request_404_html.json │ │ │ ├── request_file.json │ │ │ ├── request_no_route.json │ │ │ ├── request_nonexistent_static_asset.json │ │ │ ├── request_spec_example.json │ │ │ ├── request_static_asset.json │ │ │ ├── request_static_index.json │ │ │ └── request_status.json │ │ └── requests_v2 │ │ │ ├── request_404_html.json │ │ │ ├── request_file.json │ │ │ ├── request_no_route.json │ │ │ ├── request_nonexistent_static_asset.json │ │ │ ├── request_spec_example.json │ │ │ ├── request_static_asset.json │ │ │ ├── request_static_index.json │ │ │ └── request_status.json │ │ ├── soap-duplicate-endpoints │ │ ├── config │ │ │ ├── imposter-config.yaml │ │ │ └── petstore.wsdl │ │ └── requests │ │ │ └── duplicate_endpoints.json │ │ └── soap-simple │ │ ├── config │ │ ├── imposter-config.yaml │ │ └── petstore.wsdl │ │ └── requests │ │ └── success.json └── vertxweb │ ├── build.gradle │ └── src │ ├── main │ └── java │ │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── server │ │ └── vertxweb │ │ ├── VertxWebServerFactoryImpl.kt │ │ ├── impl │ │ ├── VertxHttpExchange.kt │ │ ├── VertxHttpRequest.kt │ │ ├── VertxHttpResponse.kt │ │ └── VertxHttpServer.kt │ │ └── util │ │ └── VertxResourceUtil.kt │ └── test │ └── java │ └── io │ └── gatehill │ └── imposter │ └── server │ └── vertxweb │ └── util │ └── VertxResourceUtilTest.kt ├── build.gradle ├── cmd ├── build.gradle └── src │ └── main │ └── java │ └── io │ └── gatehill │ └── imposter │ └── cmd │ ├── ImposterLauncher.kt │ └── LifecycleAwareLauncher.kt ├── core ├── api │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ ├── ImposterConfig.kt │ │ │ ├── config │ │ │ ├── ConfigReference.kt │ │ │ ├── LoadedConfig.kt │ │ │ └── ResolvedResourceConfig.kt │ │ │ ├── expression │ │ │ └── eval │ │ │ │ └── ExpressionEvaluator.kt │ │ │ ├── http │ │ │ ├── DefaultResponseBehaviourFactory.kt │ │ │ ├── DefaultStatusCodeFactory.kt │ │ │ ├── ResourceMatcher.kt │ │ │ ├── ResponseBehaviourFactory.kt │ │ │ ├── StatusCodeFactory.kt │ │ │ └── UniqueRoute.kt │ │ │ ├── lifecycle │ │ │ ├── EngineLifecycleHooks.kt │ │ │ ├── EngineLifecycleListener.kt │ │ │ ├── LifecycleHooks.kt │ │ │ ├── ScriptLifecycleHooks.kt │ │ │ ├── ScriptLifecycleListener.kt │ │ │ ├── SecurityLifecycleHooks.kt │ │ │ └── SecurityLifecycleListener.kt │ │ │ ├── plugin │ │ │ ├── Plugin.kt │ │ │ ├── PluginDependencies.kt │ │ │ ├── PluginDiscoveryStrategy.kt │ │ │ ├── PluginInfo.kt │ │ │ ├── PluginManager.kt │ │ │ ├── PluginProvider.kt │ │ │ ├── RequireModules.kt │ │ │ ├── RoutablePlugin.kt │ │ │ └── config │ │ │ │ ├── CommonPluginConfig.kt │ │ │ │ ├── ConfigurablePlugin.kt │ │ │ │ ├── ContentTypedConfig.kt │ │ │ │ ├── InterceptorsHolder.kt │ │ │ │ ├── PluginConfig.kt │ │ │ │ ├── PluginConfigImpl.kt │ │ │ │ ├── ResourcesHolder.kt │ │ │ │ ├── capture │ │ │ │ ├── BodyCaptureConfig.kt │ │ │ │ ├── CaptureConfig.kt │ │ │ │ ├── CaptureConfigHolder.kt │ │ │ │ └── ItemCaptureConfig.kt │ │ │ │ ├── flex │ │ │ │ ├── FlexibleTypeUtil.kt │ │ │ │ └── TypeParser.kt │ │ │ │ ├── resource │ │ │ │ ├── AbstractResourceConfig.kt │ │ │ │ ├── BasePathHolder.kt │ │ │ │ ├── BasicResourceConfig.kt │ │ │ │ ├── EvalResourceConfig.kt │ │ │ │ ├── InterceptorConfigHolder.kt │ │ │ │ ├── PassthroughResourceConfig.kt │ │ │ │ ├── ResourceConfig.kt │ │ │ │ ├── ResponseConfig.kt │ │ │ │ ├── ResponseConfigHolder.kt │ │ │ │ ├── RestResourceConfig.kt │ │ │ │ ├── StableResourceIdHolder.kt │ │ │ │ ├── UpstreamsHolder.kt │ │ │ │ ├── conditional │ │ │ │ │ ├── ConditionalNameValuePair.kt │ │ │ │ │ └── MatchOperator.kt │ │ │ │ ├── expression │ │ │ │ │ ├── ExpressionMatcherConfig.kt │ │ │ │ │ └── ExpressionMatchersConfigHolder.kt │ │ │ │ └── request │ │ │ │ │ ├── FormParamsResourceConfig.kt │ │ │ │ │ ├── LegacyQueryParamsResourceConfig.kt │ │ │ │ │ ├── MethodResourceConfig.kt │ │ │ │ │ ├── PathParamsResourceConfig.kt │ │ │ │ │ ├── QueryParamsResourceConfig.kt │ │ │ │ │ ├── RequestBodyConfig.kt │ │ │ │ │ ├── RequestBodyResourceConfig.kt │ │ │ │ │ └── RequestHeadersResourceConfig.kt │ │ │ │ ├── security │ │ │ │ ├── CorsConfig.kt │ │ │ │ ├── CorsConfigHolder.kt │ │ │ │ ├── SecurityCondition.kt │ │ │ │ ├── SecurityConfig.kt │ │ │ │ ├── SecurityConfigHolder.kt │ │ │ │ └── SecurityEffect.kt │ │ │ │ ├── steps │ │ │ │ └── StepsConfigHolder.kt │ │ │ │ └── system │ │ │ │ ├── StoreConfig.kt │ │ │ │ ├── SystemConfig.kt │ │ │ │ └── SystemConfigHolder.kt │ │ │ ├── script │ │ │ ├── ExecutionContext.kt │ │ │ ├── FailureSimulationType.kt │ │ │ ├── LowercaseKeysMap.kt │ │ │ ├── MutableResponseBehaviour.kt │ │ │ ├── PerformanceSimulationConfig.kt │ │ │ ├── ReadWriteResponseBehaviour.kt │ │ │ ├── ReadWriteResponseBehaviourImpl.kt │ │ │ ├── ResponseBehaviour.kt │ │ │ ├── ResponseBehaviourType.kt │ │ │ ├── ScriptBindings.kt │ │ │ ├── ScriptRequest.kt │ │ │ └── dsl │ │ │ │ ├── Dsl.kt │ │ │ │ ├── DslImpl.kt │ │ │ │ └── FunctionHolder.kt │ │ │ ├── server │ │ │ ├── HttpServer.kt │ │ │ └── ServerFactory.kt │ │ │ ├── service │ │ │ ├── CaptureService.kt │ │ │ ├── HandlerService.kt │ │ │ ├── InterceptorService.kt │ │ │ ├── ResponseRoutingService.kt │ │ │ ├── ResponseService.kt │ │ │ ├── ScriptService.kt │ │ │ ├── ScriptSource.kt │ │ │ ├── ScriptedResponseService.kt │ │ │ └── SecurityService.kt │ │ │ └── util │ │ │ ├── CollectionUtil.kt │ │ │ ├── MatchUtil.kt │ │ │ ├── ResourceUtil.kt │ │ │ └── StringUtil.kt │ │ └── test │ │ └── java │ │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── util │ │ ├── MatchUtilTest.kt │ │ └── ResourceUtilTest.kt ├── config-dynamic │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── plugin │ │ │ └── DynamicPluginDiscoveryStrategyImpl.kt │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── config │ │ │ └── DynamicConfigUtilTest.kt │ │ └── resources │ │ ├── config │ │ ├── test-config.json │ │ └── test-config.yaml │ │ └── log4j2.xml ├── config-resolver-s3 │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── gatehill │ │ │ │ └── imposter │ │ │ │ └── config │ │ │ │ ├── S3FileDownloader.kt │ │ │ │ └── resolver │ │ │ │ └── S3ConfigResolver.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── config-resolver.properties │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── config │ │ │ ├── S3FileDownloaderTest.kt │ │ │ ├── resolver │ │ │ └── S3ConfigResolverTest.kt │ │ │ └── support │ │ │ └── TestSupport.kt │ │ └── resources │ │ └── config │ │ ├── imposter-config.yaml │ │ ├── pet-api.yaml │ │ └── subdir │ │ └── response.json ├── config │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── gatehill │ │ │ │ └── imposter │ │ │ │ ├── config │ │ │ │ ├── ConfigHolder.kt │ │ │ │ ├── expression │ │ │ │ │ ├── EnvEvaluator.kt │ │ │ │ │ └── SystemEvaluator.kt │ │ │ │ ├── model │ │ │ │ │ ├── LightweightConfig.kt │ │ │ │ │ └── PluginMetadata.kt │ │ │ │ ├── resolver │ │ │ │ │ ├── ConfigResolver.kt │ │ │ │ │ └── LocalFileConfigResolver.kt │ │ │ │ └── util │ │ │ │ │ ├── ConfigUtil.kt │ │ │ │ │ ├── EnvVars.kt │ │ │ │ │ └── MetaUtil.kt │ │ │ │ ├── plugin │ │ │ │ ├── ChildFirstClassLoader.kt │ │ │ │ ├── PluginManagerImpl.kt │ │ │ │ └── StaticPluginDiscoveryStrategyImpl.kt │ │ │ │ └── util │ │ │ │ ├── ArchiveUtil.kt │ │ │ │ ├── ClassLoaderUtil.kt │ │ │ │ ├── MapUtil.kt │ │ │ │ └── mapper │ │ │ │ └── VertxJsonModule.kt │ │ └── resources │ │ │ ├── .imposterignore │ │ │ └── META-INF │ │ │ └── config-resolver.properties │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ ├── config │ │ │ ├── ConfigUtilTest.kt │ │ │ ├── EnvVarsTest.kt │ │ │ ├── expression │ │ │ │ └── SystemEvaluatorTest.kt │ │ │ └── support │ │ │ │ └── BasePathSupportingPluginConfig.kt │ │ │ └── util │ │ │ └── MapUtilTest.kt │ │ └── resources │ │ ├── .env │ │ ├── basepath │ │ └── test-config.yaml │ │ ├── interpolated │ │ └── test-config.yaml │ │ ├── log4j2.xml │ │ ├── recursive │ │ ├── subdir1 │ │ │ └── test-config.yaml │ │ ├── subdir2 │ │ │ └── test-config.yaml │ │ └── test-config.yaml │ │ └── simple │ │ └── test-config.yaml ├── engine │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ ├── EngineBuilder.kt │ │ │ ├── Imposter.kt │ │ │ ├── exception │ │ │ └── ResponseException.kt │ │ │ ├── http │ │ │ ├── AbstractResourceMatcher.kt │ │ │ ├── ResourceMatchResult.kt │ │ │ └── SingletonResourceMatcher.kt │ │ │ ├── inject │ │ │ ├── BootstrapModule.kt │ │ │ └── EngineModule.kt │ │ │ ├── model │ │ │ ├── script │ │ │ │ ├── LazyContextBuilder.kt │ │ │ │ └── LazyScriptRequest.kt │ │ │ └── steps │ │ │ │ ├── ProcessingStep.kt │ │ │ │ ├── RemoteProcessingStep.kt │ │ │ │ ├── ScriptProcessingStep.kt │ │ │ │ └── http │ │ │ │ ├── RemoteHttpExchange.kt │ │ │ │ ├── RemoteHttpRequest.kt │ │ │ │ └── RemoteHttpResponse.kt │ │ │ ├── placeholder │ │ │ ├── ContextEvaluator.kt │ │ │ ├── DateTimeEvaluator.kt │ │ │ ├── HttpExpressionEvaluator.kt │ │ │ └── QueryProviderImpl.kt │ │ │ ├── plugin │ │ │ ├── config │ │ │ │ └── ConfiguredPlugin.kt │ │ │ └── internal │ │ │ │ └── MetaInfPluginDetectorImpl.kt │ │ │ ├── script │ │ │ ├── ScriptUtil.kt │ │ │ ├── annotation │ │ │ │ ├── GroovyImpl.kt │ │ │ │ └── JavascriptImpl.kt │ │ │ └── listener │ │ │ │ └── ScriptListener.kt │ │ │ ├── service │ │ │ ├── CharacteristicsService.kt │ │ │ ├── DeferredOperationService.kt │ │ │ ├── FileCacheService.kt │ │ │ ├── FileCacheServiceImpl.kt │ │ │ ├── HandlerServiceImpl.kt │ │ │ ├── InterceptorServiceImpl.kt │ │ │ ├── RemoteService.kt │ │ │ ├── ResponseFileService.kt │ │ │ ├── ResponseFileServiceImpl.kt │ │ │ ├── ResponseRoutingServiceImpl.kt │ │ │ ├── ResponseServiceImpl.kt │ │ │ ├── StepService.kt │ │ │ ├── UpstreamService.kt │ │ │ ├── script │ │ │ │ ├── EmbeddedScriptService.kt │ │ │ │ ├── EmbeddedScriptServiceImpl.kt │ │ │ │ ├── EvalScriptService.kt │ │ │ │ ├── ScriptServiceFactory.kt │ │ │ │ └── ScriptedResponseServiceImpl.kt │ │ │ └── security │ │ │ │ ├── CorsService.kt │ │ │ │ ├── SecurityLifecycleListenerImpl.kt │ │ │ │ └── SecurityServiceImpl.kt │ │ │ └── util │ │ │ ├── AsyncUtil.kt │ │ │ ├── BodyQueryUtil.kt │ │ │ ├── CryptoUtil.kt │ │ │ ├── DateTimeUtil.kt │ │ │ ├── FeatureUtil.kt │ │ │ ├── FileUtil.kt │ │ │ ├── Globals.kt │ │ │ ├── HttpUtil.kt │ │ │ ├── InjectorUtil.kt │ │ │ ├── LogUtil.kt │ │ │ ├── MetricsUtil.kt │ │ │ └── PlaceholderUtil.kt │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ ├── http │ │ │ └── AbstractResourceMatcherTest.kt │ │ │ ├── script │ │ │ └── impl │ │ │ │ └── ReadWriteResponseBehaviourImplTest.kt │ │ │ ├── service │ │ │ ├── CharacteristicsServiceTest.kt │ │ │ ├── DeferredOperationServiceTest.kt │ │ │ ├── ResponseFileServiceImplTest.kt │ │ │ └── ResponseServiceImplTest.kt │ │ │ └── util │ │ │ ├── BodyQueryUtilTest.kt │ │ │ ├── FileUtilTest.kt │ │ │ ├── HttpUtilTest.kt │ │ │ └── PlaceholderUtilTest.kt │ │ └── resources │ │ ├── log4j2.xml │ │ ├── mockito-extensions │ │ └── org.mockito.plugins.MockMaker │ │ ├── response-file.txt │ │ └── test-array.json ├── expression │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── expression │ │ │ ├── QueryProvider.kt │ │ │ ├── eval │ │ │ └── RandomEvaluator.kt │ │ │ └── util │ │ │ └── ExpressionUtil.kt │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── expression │ │ │ ├── eval │ │ │ └── RandomEvaluatorTest.kt │ │ │ └── util │ │ │ └── ExpressionUtilTest.kt │ │ └── resources │ │ └── log4j2.xml ├── http │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── http │ │ │ ├── ExchangePhase.kt │ │ │ ├── HttpExchange.kt │ │ │ ├── HttpMethod.kt │ │ │ ├── HttpRequest.kt │ │ │ ├── HttpResponse.kt │ │ │ ├── HttpRoute.kt │ │ │ ├── HttpRouter.kt │ │ │ └── util │ │ │ └── PathNormaliser.kt │ │ └── test │ │ └── java │ │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── http │ │ ├── HttpRouteTest.kt │ │ ├── HttpRouterTest.kt │ │ └── util │ │ └── PathNormaliserTest.kt └── plugin-detector │ ├── build.gradle │ └── src │ └── main │ └── java │ └── io │ └── gatehill │ └── imposter │ └── plugin │ └── detector │ └── ConfigPluginDetectorImpl.kt ├── distro ├── all │ ├── .dockerignore │ ├── Dockerfile │ └── build.gradle ├── awslambda │ ├── README.md │ ├── build.gradle │ ├── deploy │ │ ├── example │ │ │ ├── bucket-policy.json │ │ │ └── config │ │ │ │ ├── imposter-config.yaml │ │ │ │ ├── pet-api.yaml │ │ │ │ └── response.json │ │ ├── serverless-api-gateway │ │ │ ├── package.json │ │ │ └── serverless.yml │ │ └── serverless-function-url │ │ │ ├── package.json │ │ │ └── serverless.yml │ └── src │ │ └── main │ │ └── resources │ │ └── log4j2.xml ├── base │ ├── .dockerignore │ ├── Dockerfile │ ├── build.gradle │ └── src │ │ └── main │ │ └── resources │ │ └── META-INF │ │ └── imposter.properties ├── core │ ├── .dockerignore │ ├── Dockerfile │ └── build.gradle ├── distroless-multistage │ ├── .dockerignore │ └── Dockerfile ├── distroless │ ├── .dockerignore │ └── Dockerfile └── embedded │ ├── README.md │ └── build.gradle ├── docs ├── CNAME ├── README.md ├── benchmarks.md ├── build.md ├── bundle.md ├── config_discovery.md ├── config_location.md ├── configuration.md ├── cors.md ├── data_capture.md ├── deploy_aws_lambda_cli.md ├── deploy_aws_lambda_console.md ├── deploy_aws_lambda_serverless_framework.md ├── deployment_patterns.md ├── directory_responses.md ├── embed_jvm.md ├── environment_variables.md ├── examples │ └── README.md ├── extend.md ├── external │ └── short_description.md ├── failure_simulation.md ├── fake_data.md ├── features.md ├── getting_started.md ├── github_actions.md ├── groovy_debugging.md ├── groovy_tips.md ├── hack │ └── README.md ├── hbase_plugin.md ├── images │ ├── api-sandbox.png │ ├── composite_logo13_cropped.png │ ├── favicon.ico │ ├── groovy_debug.png │ ├── groovy_jvm_debug_config.png │ ├── lambda.png │ ├── lambda_config_env.png │ ├── lambda_create.png │ ├── lambda_handler.png │ ├── lambda_url.png │ └── plain_logo14.png ├── index.md ├── infrastructure │ ├── Dockerfile │ ├── constraints.txt │ └── requirements.txt ├── interceptors.md ├── javascript_tips.md ├── metrics_logs_telemetry.md ├── openapi_plugin.md ├── openapi_validation.md ├── performance_simulation.md ├── performance_tuning.md ├── plugins.md ├── proxy_endpoint.md ├── request_matching.md ├── rest_plugin.md ├── roadmap.md ├── run_imposter_aws_lambda.md ├── run_imposter_cli.md ├── run_imposter_docker.md ├── run_imposter_jar.md ├── scaffold.md ├── scripting.md ├── scripting_legacy_js.md ├── scripting_modern_js.md ├── security.md ├── sfdc_plugin.md ├── soap_plugin.md ├── steps.md ├── stores.md ├── stores_graphql.md ├── summary.md ├── template_queries.md ├── templates.md ├── tips_tricks.md ├── tls_ssl.md ├── usage.md ├── usage_jar.md └── wiremock_plugin.md ├── embedded ├── core │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── embedded │ │ │ ├── ImposterBuilder.java │ │ │ ├── ImposterLaunchException.java │ │ │ └── MockEngine.java │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── embedded │ │ │ └── ImposterBuilderTest.java │ │ └── resources │ │ └── config │ │ ├── petstore-simple-config.yaml │ │ └── petstore-simple.yaml └── openapi │ ├── build.gradle │ └── src │ ├── main │ └── java │ │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── openapi │ │ └── embedded │ │ ├── ConfigGenerator.java │ │ ├── OpenApiImposterBuilder.java │ │ └── OpenApiMockEngine.java │ └── test │ ├── java │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── embedded │ │ └── OpenApiImposterBuilderTest.java │ └── resources │ └── config │ ├── petstore-simple-config.yaml │ └── petstore-simple.yaml ├── examples └── README.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lib ├── fake-data │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── gatehill │ │ │ │ └── imposter │ │ │ │ └── plugin │ │ │ │ └── fakedata │ │ │ │ ├── FakeDataPlugin.kt │ │ │ │ ├── FakeEvaluator.kt │ │ │ │ ├── FakeExampleProvider.kt │ │ │ │ └── FakeGenerator.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── plugin.properties │ │ └── test │ │ └── java │ │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── plugin │ │ └── fakedata │ │ ├── FakeEvaluatorTest.kt │ │ └── FakeExampleProviderTest.kt └── micrometer-log4j2 │ ├── build.gradle │ └── src │ └── main │ └── java │ └── io │ └── micrometer │ └── common │ └── util │ └── internal │ └── logging │ ├── Log4J2Logger.java │ └── Log4J2LoggerFactory.java ├── mkdocs.yml ├── mock ├── hbase │ ├── Samples.md │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── gatehill │ │ │ │ └── imposter │ │ │ │ └── plugin │ │ │ │ └── hbase │ │ │ │ ├── HBasePluginImpl.kt │ │ │ │ ├── HBasePluginModule.kt │ │ │ │ ├── config │ │ │ │ └── HBasePluginConfig.kt │ │ │ │ ├── model │ │ │ │ ├── InMemoryScanner.kt │ │ │ │ ├── MockScanner.kt │ │ │ │ ├── RecordInfo.kt │ │ │ │ ├── ResponsePhase.kt │ │ │ │ ├── ResultCell.kt │ │ │ │ └── ResultCellComparator.kt │ │ │ │ └── service │ │ │ │ ├── ScannerService.kt │ │ │ │ ├── ScannerServiceImpl.kt │ │ │ │ └── serialisation │ │ │ │ ├── DeserialisationService.kt │ │ │ │ ├── JsonSerialisationServiceImpl.kt │ │ │ │ ├── ProtobufSerialisationServiceImpl.kt │ │ │ │ └── SerialisationService.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── plugin.properties │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── plugin │ │ │ └── hbase │ │ │ └── HBasePluginTest.kt │ │ └── resources │ │ └── config │ │ ├── hbase-config.json │ │ ├── hbase-data.json │ │ ├── hbase-plugin.groovy │ │ └── hbase-scripted-config.json ├── openapi │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── gatehill │ │ │ │ └── imposter │ │ │ │ └── plugin │ │ │ │ └── openapi │ │ │ │ ├── OpenApiModule.kt │ │ │ │ ├── OpenApiPluginImpl.kt │ │ │ │ ├── config │ │ │ │ ├── OpenApiPluginConfig.kt │ │ │ │ ├── OpenApiPluginValidationConfig.kt │ │ │ │ ├── OpenApiResourceConfig.kt │ │ │ │ ├── OpenApiResponseConfig.kt │ │ │ │ └── Settings.kt │ │ │ │ ├── http │ │ │ │ └── OpenApiResponseBehaviourFactory.kt │ │ │ │ ├── model │ │ │ │ ├── ContentTypedHolder.kt │ │ │ │ ├── ParsedSpec.kt │ │ │ │ └── ResponseEntities.kt │ │ │ │ ├── service │ │ │ │ ├── ExampleService.kt │ │ │ │ ├── ExampleServiceImpl.kt │ │ │ │ ├── ResponseTransmissionService.kt │ │ │ │ ├── ResponseTransmissionServiceImpl.kt │ │ │ │ ├── SchemaService.kt │ │ │ │ ├── SchemaServiceImpl.kt │ │ │ │ ├── SpecificationLoaderService.kt │ │ │ │ ├── SpecificationService.kt │ │ │ │ ├── SpecificationServiceImpl.kt │ │ │ │ └── valueprovider │ │ │ │ │ ├── DefaultExampleProviders.kt │ │ │ │ │ ├── ExampleProvider.kt │ │ │ │ │ └── StringExampleProvider.kt │ │ │ │ └── util │ │ │ │ ├── RefUtil.kt │ │ │ │ └── ValidationReportUtil.kt │ │ └── resources │ │ │ ├── META-INF │ │ │ └── plugin.properties │ │ │ └── swagger-ui │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── index.html │ │ │ ├── oauth2-redirect.html │ │ │ ├── swagger-ui-bundle.js │ │ │ ├── swagger-ui-bundle.js.map │ │ │ ├── swagger-ui-es-bundle-core.js │ │ │ ├── swagger-ui-es-bundle-core.js.map │ │ │ ├── swagger-ui-es-bundle.js │ │ │ ├── swagger-ui-es-bundle.js.map │ │ │ ├── swagger-ui-standalone-preset.js │ │ │ ├── swagger-ui-standalone-preset.js.map │ │ │ ├── swagger-ui.css │ │ │ ├── swagger-ui.css.map │ │ │ ├── swagger-ui.js │ │ │ └── swagger-ui.js.map │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── plugin │ │ │ └── openapi │ │ │ ├── ComplexPathParamsTest.kt │ │ │ ├── CustomSpecPathTest.kt │ │ │ ├── DefaultResponseTest.kt │ │ │ ├── ExampleRefTest.kt │ │ │ ├── OAS2BasePathTest.kt │ │ │ ├── OAS31Test.kt │ │ │ ├── OAS3BasePathTest.kt │ │ │ ├── ObjectExamplesTest.kt │ │ │ ├── OpenApiPluginImplTest.kt │ │ │ ├── OverrideStatusCodeTest.kt │ │ │ ├── ReferenceResponseTest.kt │ │ │ ├── RequestValidationTest.kt │ │ │ ├── SchemaExamplesTest.kt │ │ │ ├── ScriptedNamedExamplesTest.kt │ │ │ ├── ScriptedResponseTest.kt │ │ │ ├── SecuritySchemesTest.kt │ │ │ ├── SlashBasePathWithHostTest.kt │ │ │ ├── StaticNamedExamplesTest.kt │ │ │ ├── UndefinedResourceTest.kt │ │ │ └── service │ │ │ └── SpecificationLoaderServiceTest.kt │ │ └── resources │ │ ├── log4j2.xml │ │ ├── openapi2 │ │ ├── base-path │ │ │ ├── example-swagger2.yaml │ │ │ └── imposter-config.yaml │ │ ├── complex-path-params │ │ │ ├── behaviour.groovy │ │ │ ├── complex-path-params-config.json │ │ │ └── kfp_api_single_file.json │ │ ├── model-examples │ │ │ ├── model-examples-config.yaml │ │ │ └── model-examples.yaml │ │ ├── object-examples │ │ │ ├── object-examples.yaml │ │ │ └── openapi-plugin-objects-config.json │ │ ├── scripted │ │ │ ├── custom.groovy │ │ │ ├── openapi2-with-examples.yaml │ │ │ └── scripted-config.json │ │ ├── simple │ │ │ ├── openapi2-config.json │ │ │ ├── openapi2-petstore-config.json │ │ │ ├── openapi2-with-examples.yaml │ │ │ └── petstore-expanded.yaml │ │ └── slash-base-path-with-host │ │ │ ├── slash-base-path-with-host-config.json │ │ │ └── slash-base-path-with-host.yaml │ │ ├── openapi3 │ │ ├── base-path │ │ │ ├── order-api.yaml │ │ │ ├── order-config.yaml │ │ │ ├── pet-api.yaml │ │ │ └── pet-config.yaml │ │ ├── default-response │ │ │ ├── default-response-config.yaml │ │ │ └── default-response.yaml │ │ ├── example-ref │ │ │ ├── openapi3-example-ref.yaml │ │ │ └── test-config.yaml │ │ ├── override-status-code │ │ │ ├── openapi3-with-multiple-status-codes.yaml │ │ │ └── override-status-code-config.yaml │ │ ├── reference-response │ │ │ ├── reference-response-config.yaml │ │ │ └── reference-response.yaml │ │ ├── request-validation │ │ │ ├── openapi3-request-validation.yaml │ │ │ └── request-validation-config.yaml │ │ ├── scripted-named-example │ │ │ ├── named-example.groovy │ │ │ ├── openapi3-with-multiple-examples.yaml │ │ │ └── scripted-config.json │ │ ├── security-schemes │ │ │ ├── imposter-config.yaml │ │ │ └── spec.yaml │ │ ├── simple │ │ │ ├── openapi3-config.json │ │ │ └── openapi3-with-examples.yaml │ │ ├── spec-endpoint │ │ │ ├── imposter-config.yaml │ │ │ └── spec.yaml │ │ ├── static-named-example │ │ │ ├── openapi3-with-multiple-examples.yaml │ │ │ └── test-config.yaml │ │ └── undefined-resource │ │ │ ├── mock-config.yaml │ │ │ └── spec.yaml │ │ ├── openapi31 │ │ └── simple │ │ │ ├── mock-config.yaml │ │ │ └── openapi.yaml │ │ └── util │ │ └── spec-loader │ │ └── order_service.yaml ├── rest │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── gatehill │ │ │ │ └── imposter │ │ │ │ └── plugin │ │ │ │ └── rest │ │ │ │ ├── RestPluginImpl.kt │ │ │ │ └── config │ │ │ │ ├── ResourceConfigType.kt │ │ │ │ ├── RestPluginConfig.kt │ │ │ │ └── RestPluginResourceConfig.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── plugin.properties │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── plugin │ │ │ └── rest │ │ │ ├── FormParamsTest.kt │ │ │ ├── PathParamsTest.kt │ │ │ ├── QueryParamsTest.kt │ │ │ ├── RequestHeaderTest.kt │ │ │ └── RestPluginTest.kt │ │ └── resources │ │ ├── config │ │ ├── rest-plugin-config.json │ │ ├── rest-plugin-data1.json │ │ ├── rest-plugin-data2.json │ │ ├── rest-plugin-list-data.json │ │ ├── rest-plugin-scripted-config.json │ │ ├── rest-plugin.groovy │ │ ├── static-full-multi-config.yaml │ │ └── static-full-single-config.yaml │ │ ├── form-params │ │ └── imposter-config.yaml │ │ ├── path-params │ │ └── imposter-config.yaml │ │ ├── query-params │ │ └── imposter-config.yaml │ │ └── request-headers │ │ └── imposter-config.yaml ├── sfdc │ ├── Sample.md │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── gatehill │ │ │ │ └── imposter │ │ │ │ └── plugin │ │ │ │ └── sfdc │ │ │ │ ├── SfdcPluginImpl.kt │ │ │ │ └── config │ │ │ │ └── SfdcPluginConfig.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── plugin.properties │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── plugin │ │ │ └── sfdc │ │ │ ├── SfdcPluginImplTest.kt │ │ │ └── support │ │ │ └── Account.kt │ │ └── resources │ │ ├── config │ │ ├── sfdc-plugin-config.json │ │ └── sfdc-plugin-data.json │ │ └── keystore │ │ └── ssl.jks ├── soap │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── gatehill │ │ │ │ └── imposter │ │ │ │ └── plugin │ │ │ │ └── soap │ │ │ │ ├── SoapModule.kt │ │ │ │ ├── SoapPluginImpl.kt │ │ │ │ ├── SoapResourceMatcher.kt │ │ │ │ ├── config │ │ │ │ ├── SoapPluginConfig.kt │ │ │ │ ├── SoapPluginResourceConfig.kt │ │ │ │ └── SoapResponseConfig.kt │ │ │ │ ├── http │ │ │ │ └── SoapResponseBehaviourFactory.kt │ │ │ │ ├── model │ │ │ │ ├── MessageBodyHolder.kt │ │ │ │ ├── OperationMessage.kt │ │ │ │ ├── ParsedRawBody.kt │ │ │ │ ├── ParsedSoapMessage.kt │ │ │ │ └── WsdlModel.kt │ │ │ │ ├── parser │ │ │ │ ├── AbstractWsdlParser.kt │ │ │ │ ├── VersionAwareWsdlParser.kt │ │ │ │ ├── Wsdl1Parser.kt │ │ │ │ ├── Wsdl2Parser.kt │ │ │ │ ├── WsdlParser.kt │ │ │ │ └── WsdlRelativeXsdEntityResolver.kt │ │ │ │ ├── service │ │ │ │ └── SoapExampleService.kt │ │ │ │ └── util │ │ │ │ ├── SchemaUtil.kt │ │ │ │ └── SoapUtil.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── plugin.properties │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── plugin │ │ │ └── soap │ │ │ ├── AbstractEndToEndTest.kt │ │ │ ├── FaultExampleTest.kt │ │ │ ├── JAXWSTest.kt │ │ │ ├── NoEnvelopeTest.kt │ │ │ ├── RequestBodyMatchTest.kt │ │ │ ├── TemplateResponseTest.kt │ │ │ ├── Wsdl1Soap11CompositeMessageEndToEndTest.kt │ │ │ ├── Wsdl1Soap11DocumentBareEndToEndTest.kt │ │ │ ├── Wsdl1Soap11DocumentWrappedEndToEndTest.kt │ │ │ ├── Wsdl1Soap11FilterMessagePartsEndToEndTest.kt │ │ │ ├── Wsdl1Soap11RpcEndToEndTest.kt │ │ │ ├── Wsdl1Soap11WithXsdImportIncludeEndToEndTest.kt │ │ │ ├── Wsdl1Soap12EndToEndTest.kt │ │ │ ├── Wsdl2Soap12EndToEndTest.kt │ │ │ └── parser │ │ │ ├── AbstractWsdlParserTest.kt │ │ │ ├── VersionAwareWsdlParserTest.kt │ │ │ ├── Wsdl1Soap11ParserTest.kt │ │ │ ├── Wsdl1Soap12ParserTest.kt │ │ │ └── Wsdl2Soap12ParserTest.kt │ │ └── resources │ │ ├── fault-example │ │ ├── imposter-config.yaml │ │ └── service.wsdl │ │ ├── log4j2.xml │ │ ├── no-envelope │ │ ├── imposter-config.yaml │ │ └── service.wsdl │ │ ├── request-body-match │ │ ├── imposter-config.yaml │ │ └── service.wsdl │ │ ├── template-response │ │ ├── imposter-config.yaml │ │ └── service.wsdl │ │ ├── wsdl1-soap11-composite-message │ │ ├── getPetByNameResponse.xml │ │ ├── service.wsdl │ │ └── test-config.yaml │ │ ├── wsdl1-soap11-document-bare │ │ ├── getPetByNameResponse.xml │ │ ├── imposter-config.yaml │ │ ├── schema.xsd │ │ └── service.wsdl │ │ ├── wsdl1-soap11-document-wrapped │ │ ├── getPetByNameResponse.xml │ │ ├── imposter-config.yaml │ │ └── service.wsdl │ │ ├── wsdl1-soap11-filter-message-parts │ │ ├── getPetByNameResponse.xml │ │ ├── imposter-config.yaml │ │ └── service.wsdl │ │ ├── wsdl1-soap11-rpc │ │ ├── getPetByNameResponse.xml │ │ ├── service.wsdl │ │ └── test-config.yaml │ │ ├── wsdl1-soap11-xsd-import-include │ │ ├── PetService │ │ │ ├── schema-include.xsd │ │ │ └── service.wsdl │ │ ├── getPetByNameResponse.xml │ │ ├── import │ │ │ ├── import.xsd │ │ │ └── schema-import.xsd │ │ ├── imposter-config.yaml │ │ └── include │ │ │ └── include.xsd │ │ ├── wsdl1-soap12 │ │ ├── getPetByNameResponse.xml │ │ ├── imposter-config.yaml │ │ ├── schema.xsd │ │ └── service.wsdl │ │ └── wsdl2-soap12 │ │ ├── getPetByNameResponse.xml │ │ ├── imposter-config.yaml │ │ ├── schema.xsd │ │ └── service.wsdl └── wiremock │ ├── build.gradle │ └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── plugin │ │ │ └── wiremock │ │ │ ├── WiremockPluginImpl.kt │ │ │ ├── model │ │ │ ├── MappingRequest.kt │ │ │ ├── MappingResponse.kt │ │ │ └── WiremockMappings.kt │ │ │ └── util │ │ │ └── ConversionUtil.kt │ └── resources │ │ └── META-INF │ │ └── plugin.properties │ └── test │ ├── java │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── plugin │ │ └── wiremock │ │ ├── WiremockEndToEndTest.kt │ │ └── WiremockPluginTest.kt │ └── resources │ ├── wiremock-nowrap │ ├── imposter-config.yaml │ └── mappings │ │ └── mappings.json │ ├── wiremock-simple │ ├── __files │ │ └── response.json │ ├── imposter-config.yaml │ └── mappings │ │ ├── mappings1.json │ │ └── mappings2.json │ ├── wiremock-templated │ ├── __files │ │ └── response.xml │ ├── imposter-config.yaml │ └── mappings │ │ └── mappings.json │ └── wiremock-xpath-request │ └── mappings │ ├── imposter-config.yaml │ └── mappings │ └── mappings.json ├── scripting ├── common │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── scripting │ │ │ └── common │ │ │ ├── CommonScriptingModule.kt │ │ │ ├── JsPluginDetectorImpl.kt │ │ │ ├── service │ │ │ └── DelegatingJsScriptServiceImpl.kt │ │ │ ├── shim │ │ │ └── ConsoleShim.kt │ │ │ └── util │ │ │ ├── CompiledJsScript.kt │ │ │ ├── JavaScriptUtil.kt │ │ │ ├── ScriptMetadata.kt │ │ │ └── WrappedScript.kt │ │ └── test │ │ ├── kotlin │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── scripting │ │ │ └── common │ │ │ └── util │ │ │ └── JavaScriptUtilTest.kt │ │ └── resources │ │ └── log4j2.xml ├── graalvm │ ├── README.md │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── scripting │ │ │ └── graalvm │ │ │ ├── GraalvmCompatScriptingModule.kt │ │ │ ├── GraalvmScriptingModule.kt │ │ │ ├── proxy │ │ │ ├── DeepProxy.kt │ │ │ ├── InterceptingList.kt │ │ │ ├── InterceptingMap.kt │ │ │ ├── ObjectProxyingStore.kt │ │ │ ├── PojoProxyObject.kt │ │ │ └── RequestProxy.kt │ │ │ └── service │ │ │ ├── GraalvmCompatScriptServiceImpl.kt │ │ │ └── GraalvmScriptServiceImpl.kt │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ ├── scripting │ │ │ └── graalvm │ │ │ │ └── proxy │ │ │ │ └── RequestProxyTest.kt │ │ │ └── service │ │ │ ├── AdditionalContextPropertiesTest.kt │ │ │ ├── GraalvmCompatContextPropertiesTest.kt │ │ │ ├── GraalvmCompatScriptServiceImplTest.kt │ │ │ ├── GraalvmContextPropertiesTest.kt │ │ │ ├── GraalvmScriptServiceImplTest.kt │ │ │ ├── RequireTypesTest.kt │ │ │ └── StoreJsonTest.kt │ │ └── resources │ │ └── script │ │ ├── additional_context_properties.js │ │ ├── context_properties.js │ │ ├── context_properties_compat.js │ │ ├── require_types.js │ │ ├── store_json.js │ │ └── test.js ├── groovy │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── scripting │ │ │ └── groovy │ │ │ ├── GroovyScriptingModule.kt │ │ │ ├── impl │ │ │ └── GroovyDsl.kt │ │ │ ├── service │ │ │ └── GroovyScriptServiceImpl.kt │ │ │ └── util │ │ │ └── ScriptLoader.kt │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── service │ │ │ ├── GroovyContextPropertiesTest.kt │ │ │ ├── GroovyScriptClosureTest.kt │ │ │ ├── GroovyScriptIncludeFileTest.kt │ │ │ ├── GroovyScriptJsonTest.kt │ │ │ └── GroovyScriptServiceImplTest.kt │ │ └── resources │ │ └── script │ │ ├── closure.groovy │ │ ├── context_properties.groovy │ │ ├── entrypoint.groovy │ │ ├── included.groovy │ │ ├── json-parse.groovy │ │ └── test.groovy └── nashorn │ ├── build.gradle │ └── src │ ├── main │ └── java │ │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── scripting │ │ └── nashorn │ │ ├── NashornScriptingModule.kt │ │ └── service │ │ └── NashornScriptServiceImpl.kt │ └── test │ ├── java │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── service │ │ ├── NashornContextPropertiesTest.kt │ │ ├── NashornScriptServiceImplTest.kt │ │ └── RequireTypesTest.kt │ └── resources │ └── script │ ├── context_properties.js │ ├── require_types.js │ └── test.js ├── scripts ├── dev-current.sh ├── docker-build.sh ├── get-effective-branch.sh ├── get-version.sh ├── integration-tests.sh ├── local-docs.sh ├── release-current.sh ├── release-trigger.sh └── tag-latest-to-release-version.sh ├── server ├── build.gradle └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── server │ │ │ └── ImposterVerticle.kt │ └── resources │ │ ├── keystore │ │ └── ssl.jks │ │ └── log4j2.xml │ └── test │ ├── java │ └── io │ │ └── gatehill │ │ └── imposter │ │ ├── plugin │ │ └── test │ │ │ ├── TestPluginConfig.kt │ │ │ ├── TestPluginImpl.kt │ │ │ └── TestPluginResourceConfig.kt │ │ └── server │ │ ├── CaptureTest.kt │ │ ├── CorsTest.kt │ │ ├── DeprecatedResponseConfigTest.kt │ │ ├── ExpressionMatcherTest.kt │ │ ├── FailureSimulationTest.kt │ │ ├── HttpsTest.kt │ │ ├── ImposterVerticleTest.kt │ │ ├── InheritRootResponseConfigTest.kt │ │ ├── InlineScriptEvalTest.kt │ │ ├── InterceptorTest.kt │ │ ├── KebabCaseParamsTest.kt │ │ ├── PerformanceSimulationTest.kt │ │ ├── PreferExactPathTest.kt │ │ ├── RequestBodyJsonPathTest.kt │ │ ├── RequestBodyStringTest.kt │ │ ├── RequestBodyXPathTest.kt │ │ ├── RequestMatchingTest.kt │ │ ├── ReservedCharsInPathTest.kt │ │ ├── ResponseTemplateTest.kt │ │ ├── SecurityConfigRegexTest.kt │ │ ├── SecurityConfigTest.kt │ │ ├── SecurityQueryParamsTest.kt │ │ ├── SecurityWithResourcesTest.kt │ │ ├── StaticContentTest.kt │ │ ├── StepsRemoteTest.kt │ │ ├── StepsScriptTest.kt │ │ ├── StoreApiTest.kt │ │ ├── StorePreloadTest.kt │ │ ├── StoreScriptTest.kt │ │ └── TrailingWildcardPathTest.kt │ └── resources │ ├── capture │ ├── test-plugin-config.yaml │ └── user.json │ ├── cors │ └── test-plugin-config.yaml │ ├── deprecated-response-config │ ├── example.groovy │ ├── example.txt │ └── test-plugin-config.yaml │ ├── expression-matcher │ └── test-plugin-config.yaml │ ├── failure-simulation │ └── test-plugin-config.yaml │ ├── inherit-root-response-config │ └── test-plugin-config.yaml │ ├── inline-script-eval │ └── test-plugin-config.yaml │ ├── interceptor │ └── test-plugin-config.yaml │ ├── kebab-case-params │ └── test-plugin-config.yaml │ ├── log4j2.xml │ ├── performance-simulation │ ├── delay.js │ └── test-plugin-config.yaml │ ├── prefer-exact-path │ └── test-plugin-config.yaml │ ├── request-body-jsonpath │ └── test-plugin-config.yaml │ ├── request-body-string │ └── test-plugin-config.yaml │ ├── request-body-xpath │ └── test-plugin-config.yaml │ ├── request-matching │ └── test-plugin-config.yaml │ ├── reserved-chars-in-path │ └── test-plugin-config.yaml │ ├── response-template │ ├── jsonPathTemplate.txt │ ├── petTemplate.txt │ ├── simpleTemplate.txt │ ├── test-plugin-config.yaml │ └── user.json │ ├── security-config-query-params │ └── test-plugin-config.yaml │ ├── security-config-regex │ └── test-plugin-config.yaml │ ├── security-config-with-resources │ └── test-plugin-config.yaml │ ├── security-config │ └── test-plugin-config.yaml │ ├── simple-config │ ├── test-plugin-config.json │ └── test-plugin-data.json │ ├── static-content │ ├── static │ │ ├── index.html │ │ └── styles.css │ └── test-plugin-config.yaml │ ├── steps-remote │ └── imposter-config.yaml │ ├── steps-script │ ├── imposter-config.yaml │ └── test.js │ ├── store-preload │ ├── initial-data.json │ └── test-plugin-config.yaml │ ├── store-script │ ├── store.js │ └── test-plugin-config.yaml │ └── trailing-wildcard-path │ └── test-plugin-config.yaml ├── settings.gradle ├── since.yaml ├── store ├── common │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── store │ │ │ ├── StoreModule.kt │ │ │ ├── StorePluginDetectorImpl.kt │ │ │ ├── core │ │ │ ├── AbstractStore.kt │ │ │ ├── PrefixedKeyStore.kt │ │ │ └── Store.kt │ │ │ ├── factory │ │ │ ├── AbstractStoreFactory.kt │ │ │ ├── DelegatingStoreFactoryImpl.kt │ │ │ └── StoreFactory.kt │ │ │ ├── inmem │ │ │ └── InMemoryStore.kt │ │ │ ├── model │ │ │ └── StoreProvider.kt │ │ │ ├── placeholder │ │ │ └── StoreEvaluator.kt │ │ │ ├── service │ │ │ ├── CaptureServiceImpl.kt │ │ │ ├── StoreRestApiServiceImpl.kt │ │ │ ├── StoreService.kt │ │ │ └── StoreServiceImpl.kt │ │ │ └── util │ │ │ └── StoreUtil.kt │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── store │ │ │ ├── model │ │ │ └── PrefixedKeyStoreTest.kt │ │ │ └── service │ │ │ └── CaptureServiceImplTest.kt │ │ └── resources │ │ ├── log4j2.xml │ │ └── mockito-extensions │ │ └── org.mockito.plugins.MockMaker ├── dynamodb │ ├── README.md │ ├── build.gradle │ ├── example │ │ └── iam-policy.json │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── store │ │ │ └── dynamodb │ │ │ ├── DynamoDBStore.kt │ │ │ ├── DynamoDBStoreFactoryImpl.kt │ │ │ ├── DynamoDBStoreModule.kt │ │ │ ├── config │ │ │ └── Settings.kt │ │ │ └── model │ │ │ └── ResultWrapper.kt │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── store │ │ │ └── dynamodb │ │ │ ├── DynamoDBStoreFactoryImplTest.kt │ │ │ ├── DynamoDBStoreTtlTest.kt │ │ │ └── support │ │ │ └── DynamoDBStoreTestHelper.kt │ │ └── resources │ │ └── log4j2.xml ├── graphql │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── gatehill │ │ │ │ └── imposter │ │ │ │ └── store │ │ │ │ └── graphql │ │ │ │ ├── GraphQLQueryModule.kt │ │ │ │ ├── GraphQLQueryPlugin.kt │ │ │ │ ├── GraphQLQueryService.kt │ │ │ │ └── model │ │ │ │ ├── GraphQLRequest.kt │ │ │ │ ├── JsonRawValueDeserializer.kt │ │ │ │ └── StoreItem.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── plugin.properties │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── store │ │ │ └── redis │ │ │ └── GraphQLQueryServiceTest.kt │ │ └── resources │ │ ├── log4j2.xml │ │ └── mockito-extensions │ │ └── org.mockito.plugins.MockMaker ├── inmem │ ├── build.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── store │ │ │ └── inmem │ │ │ ├── InMemoryStoreFactoryImpl.kt │ │ │ └── InMemoryStoreModule.kt │ │ └── test │ │ ├── java │ │ └── io │ │ │ └── gatehill │ │ │ └── imposter │ │ │ └── store │ │ │ └── inmem │ │ │ └── InMemoryStoreTest.kt │ │ └── resources │ │ └── log4j2.xml └── redis │ ├── README.md │ ├── build.gradle │ ├── example │ ├── scripted-example │ │ ├── imposter-config.yaml │ │ ├── redisson.yaml │ │ └── store.js │ └── simple-example │ │ ├── imposter-config.yaml │ │ └── redisson.yaml │ └── src │ ├── main │ └── java │ │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── store │ │ └── redis │ │ ├── RedisStore.kt │ │ ├── RedisStoreFactoryImpl.kt │ │ └── RedisStoreModule.kt │ └── test │ ├── java │ └── io │ │ └── gatehill │ │ └── imposter │ │ └── store │ │ └── redis │ │ └── RedisStoreFactoryImplTest.kt │ └── resources │ └── log4j2.xml ├── test ├── api-tests │ └── build.gradle ├── sample-soap-client │ ├── README.md │ ├── build.gradle │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── petstore │ │ │ ├── GetPetByIdRequest.java │ │ │ ├── GetPetByNameRequest.java │ │ │ ├── ObjectFactory.java │ │ │ ├── PetPortType.java │ │ │ ├── PetService.java │ │ │ ├── PetType.java │ │ │ └── package-info.java │ │ └── wsdl │ │ ├── schema.xsd │ │ └── service.wsdl └── test-utils │ ├── build.gradle │ └── src │ └── main │ ├── java │ └── io │ │ └── gatehill │ │ └── imposter │ │ ├── scripting │ │ ├── AbstractBaseScriptTest.kt │ │ ├── AbstractContextPropertiesTest.kt │ │ └── AbstractScriptServiceImplTest.kt │ │ ├── server │ │ ├── BaseVerticleTest.kt │ │ ├── VerticleTestCategory.kt │ │ └── engine │ │ │ ├── GoMockEngine.kt │ │ │ ├── JvmMockEngine.kt │ │ │ └── TestMockEngine.kt │ │ ├── store │ │ ├── AbstractStoreFactoryTest.kt │ │ └── support │ │ │ └── Example.kt │ │ └── util │ │ ├── HttpTestUtil.kt │ │ ├── TestEnvironmentUtil.kt │ │ └── Util.kt │ └── resources │ └── log4j2.xml └── tools ├── docs-local ├── Dockerfile └── compose.yaml └── perf-monitor ├── build.gradle └── src └── main └── java └── io └── gatehill └── imposter └── perf ├── Agent.java ├── CallTimerAdvice.java └── PerfWriter.java /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | target-branch: "develop" 9 | open-pull-requests-limit: 4 10 | labels: 11 | - "dependencies" 12 | - "github_actions" 13 | commit-message: 14 | prefix: "chore" 15 | include: "scope" 16 | 17 | - package-ecosystem: gradle 18 | directory: "/" 19 | schedule: 20 | interval: "daily" 21 | target-branch: "develop" 22 | open-pull-requests-limit: 4 23 | labels: 24 | - "dependencies" 25 | - "java" 26 | commit-message: 27 | prefix: "chore" 28 | include: "scope" 29 | 30 | - package-ecosystem: docker 31 | directory: "/" 32 | schedule: 33 | interval: "daily" 34 | target-branch: "develop" 35 | open-pull-requests-limit: 4 36 | labels: 37 | - "dependencies" 38 | - "docker" 39 | commit-message: 40 | prefix: "chore" 41 | include: "scope" 42 | -------------------------------------------------------------------------------- /.github/workflows/cicd.yaml: -------------------------------------------------------------------------------- 1 | name: CI/CD 2 | on: [ push ] 3 | 4 | jobs: 5 | setup: 6 | runs-on: ubuntu-latest 7 | timeout-minutes: 5 8 | outputs: 9 | effective-branch: ${{ steps.git-meta.outputs.EFFECTIVE_BRANCH }} 10 | release: ${{ startsWith(github.ref, 'refs/tags/') }} 11 | version: ${{ steps.git-meta.outputs.CURRENT_VERSION }} 12 | env: 13 | SINCE_VERSION: "0.15.5" 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | fetch-tags: true 19 | 20 | - name: Install since 21 | run: | 22 | cd "$( mktemp -d )" 23 | curl --fail -L -o since.tar.gz https://github.com/release-tools/since/releases/download/v${SINCE_VERSION}/since_${SINCE_VERSION}_linux_amd64.tar.gz 24 | tar xvf since.tar.gz 25 | cp since /usr/local/bin 26 | 27 | - name: Determine effective branch 28 | id: git-meta 29 | run: | 30 | echo "EFFECTIVE_BRANCH=$( ./scripts/get-effective-branch.sh )" >> $GITHUB_OUTPUT 31 | echo "CURRENT_VERSION=$( since project version --current --log-level=info )" >> $GITHUB_OUTPUT 32 | 33 | ci: 34 | needs: [setup] 35 | uses: ./.github/workflows/pipeline.yaml 36 | permissions: 37 | checks: write 38 | contents: write 39 | with: 40 | effective-branch: ${{ needs.setup.outputs.effective-branch }} 41 | release: ${{ needs.setup.outputs.release == 'true' }} 42 | version: ${{ needs.setup.outputs.version }} 43 | secrets: inherit 44 | -------------------------------------------------------------------------------- /.github/workflows/cut-release.yaml: -------------------------------------------------------------------------------- 1 | name: Cut release 2 | on: [ workflow_dispatch ] 3 | 4 | permissions: 5 | checks: write 6 | contents: write 7 | 8 | jobs: 9 | cut-release: 10 | outputs: 11 | version: ${{ steps.since.outputs.CURRENT_VERSION }} 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 5 14 | env: 15 | SINCE_VERSION: "0.15.5" 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | fetch-tags: true 21 | 22 | - name: Configure git 23 | run: | 24 | git config user.name "Imposter release bot" 25 | git config user.email "release-bot@imposter.sh" 26 | 27 | - name: Install since 28 | run: | 29 | cd "$( mktemp -d )" 30 | curl --fail -L -o since.tar.gz https://github.com/release-tools/since/releases/download/v${SINCE_VERSION}/since_${SINCE_VERSION}_linux_amd64.tar.gz 31 | tar xvf since.tar.gz 32 | cp since /usr/local/bin 33 | 34 | - name: Cut release 35 | id: since 36 | run: | 37 | since project release 38 | echo "CURRENT_VERSION=$( since project version --current --log-level=info )" >> $GITHUB_OUTPUT 39 | 40 | - name: Push changes 41 | run: git push origin main --tags 42 | 43 | ci: 44 | needs: [cut-release] 45 | uses: ./.github/workflows/pipeline.yaml 46 | with: 47 | effective-branch: main 48 | release: true 49 | version: ${{ needs.cut-release.outputs.version }} 50 | secrets: inherit 51 | -------------------------------------------------------------------------------- /.github/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | name: Docs site 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - develop 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | timeout-minutes: 5 11 | permissions: 12 | contents: write 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions/setup-python@v5.5.0 16 | with: 17 | python-version: 3.x 18 | 19 | - name: Install mkdocs 20 | env: 21 | PIP_CONSTRAINT: ./docs/infrastructure/constraints.txt 22 | run: pip install -r ./docs/infrastructure/requirements.txt 23 | 24 | - name: Build static site 25 | run: mkdocs build 26 | 27 | - name: Deploy to GitHub Pages 28 | if: ${{ github.ref_name == 'main' }} 29 | run: mkdocs gh-deploy --force 30 | -------------------------------------------------------------------------------- /.github/workflows/examples.yaml: -------------------------------------------------------------------------------- 1 | name: Examples 2 | on: [ push ] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | timeout-minutes: 10 7 | permissions: 8 | checks: write 9 | contents: write 10 | steps: 11 | - uses: actions/checkout@v4 12 | 13 | - name: Remove placeholder examples directory 14 | run: rm -rf examples 15 | 16 | - name: Checkout examples 17 | uses: actions/checkout@v4 18 | with: 19 | repository: 'imposter-project/examples' 20 | path: 'examples' 21 | 22 | - name: Setup Java 23 | uses: actions/setup-java@v4 24 | with: 25 | java-version: 11 26 | distribution: 'temurin' 27 | cache: 'maven' 28 | 29 | - name: Set up build environment 30 | run: | 31 | # Disable gradle daemon 32 | mkdir -p ~/.gradle 33 | echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties 34 | 35 | - name: Install Maven dependencies locally 36 | id: publish-maven-local 37 | run: | 38 | ./gradlew publishToMavenLocal --stacktrace -xtest 39 | echo "PUBLISHED_VERSION=$( cat gradle.properties | grep projectVersion= | cut -c16- )" >> $GITHUB_OUTPUT 40 | 41 | - name: Test JUnit example project 42 | working-directory: ./examples/junit-sample 43 | run: ./mvnw test -Dimposter.version=${{ steps.publish-maven-local.outputs.PUBLISHED_VERSION }} 44 | 45 | - name: Publish Unit Test Results 46 | if: always() 47 | uses: EnricoMi/publish-unit-test-result-action@v2 48 | with: 49 | files: "**/surefire-reports/**/*.xml" 50 | comment_mode: off 51 | -------------------------------------------------------------------------------- /.github/workflows/integ-test.yaml: -------------------------------------------------------------------------------- 1 | name: Integration test 2 | on: 3 | workflow_call: 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | timeout-minutes: 10 9 | permissions: 10 | checks: write 11 | env: 12 | AWS_REGION: "eu-west-1" 13 | TESTCONTAINERS_RYUK_DISABLED: "true" 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Remove placeholder examples directory 18 | run: rm -rf examples 19 | 20 | - name: Checkout examples 21 | uses: actions/checkout@v4 22 | with: 23 | repository: 'imposter-project/examples' 24 | path: 'examples' 25 | 26 | - name: Setup Java 27 | uses: actions/setup-java@v4 28 | with: 29 | java-version: 11 30 | distribution: 'temurin' 31 | cache: 'gradle' 32 | 33 | - name: Set up build environment 34 | run: | 35 | chmod +x ./scripts/*.sh 36 | # Disable gradle daemon 37 | mkdir -p ~/.gradle 38 | echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties 39 | 40 | - name: Build distributions 41 | run: ./gradlew dist --stacktrace -xtest 42 | 43 | - name: Integration test 44 | timeout-minutes: 10 45 | run: | 46 | ./scripts/docker-build.sh -p false dev 47 | ./scripts/integration-tests.sh outofcoffee/imposter:dev 48 | ./scripts/integration-tests.sh outofcoffee/imposter-all:dev 49 | -------------------------------------------------------------------------------- /.github/workflows/maven-publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish Maven artifacts 2 | on: 3 | workflow_call: 4 | secrets: 5 | AWS_ACCESS_KEY_ID: 6 | required: true 7 | AWS_SECRET_ACCESS_KEY: 8 | required: true 9 | 10 | jobs: 11 | publish: 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 10 14 | permissions: 15 | contents: write 16 | env: 17 | TESTCONTAINERS_RYUK_DISABLED: "true" 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Setup Java 22 | uses: actions/setup-java@v4 23 | with: 24 | java-version: 11 25 | distribution: 'temurin' 26 | cache: 'gradle' 27 | 28 | - name: Set up build environment 29 | run: | 30 | chmod +x ./scripts/*.sh 31 | # Disable gradle daemon 32 | mkdir -p ~/.gradle 33 | echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties 34 | 35 | - name: Publish Maven artifacts 36 | run: ./gradlew publish -xtest --stacktrace 37 | env: 38 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 39 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 40 | -------------------------------------------------------------------------------- /.github/workflows/validate.yaml: -------------------------------------------------------------------------------- 1 | name: Validate 2 | on: 3 | workflow_call: 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | timeout-minutes: 15 9 | strategy: 10 | matrix: 11 | java: [ '11', '17', '21' ] 12 | permissions: 13 | checks: write 14 | env: 15 | AWS_REGION: "eu-west-1" 16 | TESTCONTAINERS_RYUK_DISABLED: "true" 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: Setup Java 21 | uses: actions/setup-java@v4 22 | with: 23 | java-version: ${{ matrix.java }} 24 | distribution: 'temurin' 25 | cache: 'gradle' 26 | 27 | - name: Set up build environment 28 | run: | 29 | chmod +x ./scripts/*.sh 30 | # Disable gradle daemon 31 | mkdir -p ~/.gradle 32 | echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties 33 | 34 | - name: Test 35 | run: ./gradlew test --stacktrace 36 | 37 | - name: Publish Unit Test Results 38 | if: always() 39 | uses: EnricoMi/publish-unit-test-result-action@v2 40 | with: 41 | files: "**/test-results/**/*.xml" 42 | comment_mode: off 43 | check_name: Unit Tests (Java ${{ matrix.java }}) 44 | 45 | - name: Upload Test Reports 46 | if: failure() 47 | uses: actions/upload-artifact@v4 48 | with: 49 | name: test-reports-java-${{ matrix.java }} 50 | path: "**/build/reports/tests/test" 51 | if-no-files-found: ignore 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build/ 4 | *.iml 5 | .gradletasknamecache 6 | .vertx/ 7 | out/ 8 | target/ 9 | node_modules/ 10 | .serverless/ 11 | .tool-versions 12 | .imposter 13 | bin/ 14 | /.vscode/ 15 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/handled-404/config/mock-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: rest 2 | 3 | resources: 4 | - method: GET 5 | path: /notfound 6 | response: 7 | statusCode: 404 8 | content: Not Found 9 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/handled-404/requests_v1/request.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/notfound", 3 | "httpMethod": "GET", 4 | "headers": {}, 5 | "queryStringParameters": {}, 6 | "pathParameters": {}, 7 | "body": null, 8 | "isBase64Encoded": false 9 | } 10 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/handled-404/requests_v2/request.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": {}, 3 | "queryStringParameters": {}, 4 | "pathParameters": {}, 5 | "body": null, 6 | "isBase64Encoded": false, 7 | "requestContext": { 8 | "http": { 9 | "path": "/notfound", 10 | "method": "GET" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/openapi-simple/config/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | plugin: openapi 3 | specFile: petstore.yaml 4 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/openapi-simple/config/petstore.yaml: -------------------------------------------------------------------------------- 1 | openapi: "3.0.1" 2 | 3 | info: 4 | title: Sample Petstore service 5 | version: "1.0.0" 6 | 7 | paths: 8 | /pets: 9 | get: 10 | responses: 11 | '200': 12 | description: Returns all pets from the system 13 | content: 14 | application/json: 15 | schema: 16 | type: array 17 | items: 18 | type: object 19 | required: 20 | - id 21 | - name 22 | properties: 23 | id: 24 | type: integer 25 | name: 26 | type: string 27 | examples: 28 | itemsExample: 29 | value: 30 | [ 31 | { "id": 101, "name": "Cat" }, 32 | { "id": 102, "name": "Dog" } 33 | ] 34 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/openapi-simple/requests/spec_ui.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": {}, 3 | "queryStringParameters": {}, 4 | "pathParameters": {}, 5 | "isBase64Encoded": false, 6 | "requestContext": { 7 | "http": { 8 | "path": "/_spec/", 9 | "method": "GET" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/openapi-simple/requests/success.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": { 3 | "Accept": "application/json" 4 | }, 5 | "queryStringParameters": {}, 6 | "pathParameters": {}, 7 | "isBase64Encoded": false, 8 | "requestContext": { 9 | "http": { 10 | "path": "/pets", 11 | "method": "GET" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/request-with-query/config/mock-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: rest 2 | 3 | resources: 4 | - method: GET 5 | path: "/some/path" 6 | queryParams: 7 | foo: "bar" 8 | response: 9 | file: response.json 10 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/request-with-query/config/response.json: -------------------------------------------------------------------------------- 1 | { "foo": "bar" } -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/request-with-query/requests_v1/request_with_query.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/some/path", 3 | "httpMethod": "GET", 4 | "headers": {}, 5 | "queryStringParameters": { 6 | "foo": "bar" 7 | }, 8 | "pathParameters": {}, 9 | "body": null, 10 | "isBase64Encoded": false 11 | } 12 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/request-with-query/requests_v2/request_with_query.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": {}, 3 | "queryStringParameters": { 4 | "foo": "bar" 5 | }, 6 | "pathParameters": {}, 7 | "body": null, 8 | "isBase64Encoded": false, 9 | "requestContext": { 10 | "http": { 11 | "path": "/some/path", 12 | "method": "GET" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/config/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "openapi" 2 | specFile: "pet-api.yaml" 3 | 4 | resources: 5 | - path: /pets/{petId} 6 | method: get 7 | pathParams: 8 | petId: 2 9 | response: 10 | file: subdir/response.json 11 | 12 | - path: /assets/* 13 | response: 14 | dir: assets 15 | 16 | - path: /www/* 17 | response: 18 | dir: www 19 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/config/subdir/response.json: -------------------------------------------------------------------------------- 1 | { "id": 2, "name": "Dog" } -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v1/request_404_html.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/does_not_match", 3 | "httpMethod": "GET", 4 | "headers": { 5 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" 6 | }, 7 | "queryStringParameters": {}, 8 | "pathParameters": {}, 9 | "body": null, 10 | "isBase64Encoded": false 11 | } 12 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v1/request_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/pets/2", 3 | "httpMethod": "GET", 4 | "headers": {}, 5 | "queryStringParameters": {}, 6 | "pathParameters": { 7 | "petId": "2" 8 | }, 9 | "body": null, 10 | "isBase64Encoded": false 11 | } 12 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v1/request_no_route.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/does_not_match", 3 | "httpMethod": "GET", 4 | "headers": {}, 5 | "queryStringParameters": {}, 6 | "pathParameters": {}, 7 | "body": null, 8 | "isBase64Encoded": false 9 | } 10 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v1/request_nonexistent_static_asset.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/assets/nonexistent", 3 | "httpMethod": "GET", 4 | "headers": {}, 5 | "queryStringParameters": {}, 6 | "pathParameters": {}, 7 | "body": null, 8 | "isBase64Encoded": false 9 | } 10 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v1/request_spec_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/pets/1", 3 | "httpMethod": "GET", 4 | "headers": {}, 5 | "queryStringParameters": {}, 6 | "pathParameters": { 7 | "petId": "1" 8 | }, 9 | "body": null, 10 | "isBase64Encoded": false 11 | } 12 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v1/request_static_asset.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/assets/styles.css", 3 | "httpMethod": "GET", 4 | "headers": {}, 5 | "queryStringParameters": {}, 6 | "pathParameters": {}, 7 | "body": null, 8 | "isBase64Encoded": false 9 | } 10 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v1/request_static_index.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/www/", 3 | "httpMethod": "GET", 4 | "headers": {}, 5 | "queryStringParameters": {}, 6 | "pathParameters": {}, 7 | "body": null, 8 | "isBase64Encoded": false 9 | } 10 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v1/request_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": "/system/status", 3 | "httpMethod": "GET", 4 | "headers": {}, 5 | "queryStringParameters": {}, 6 | "pathParameters": {}, 7 | "body": null, 8 | "isBase64Encoded": false 9 | } 10 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v2/request_404_html.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": { 3 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" 4 | }, 5 | "queryStringParameters": {}, 6 | "pathParameters": {}, 7 | "body": null, 8 | "isBase64Encoded": false, 9 | "requestContext": { 10 | "http": { 11 | "path": "/does_not_match", 12 | "method": "GET" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v2/request_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": {}, 3 | "queryStringParameters": {}, 4 | "pathParameters": { 5 | "petId": "2" 6 | }, 7 | "body": null, 8 | "isBase64Encoded": false, 9 | "requestContext": { 10 | "http": { 11 | "path": "/pets/2", 12 | "method": "GET" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v2/request_no_route.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": {}, 3 | "queryStringParameters": {}, 4 | "pathParameters": {}, 5 | "body": null, 6 | "isBase64Encoded": false, 7 | "requestContext": { 8 | "http": { 9 | "path": "/does_not_match", 10 | "method": "GET" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v2/request_nonexistent_static_asset.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": {}, 3 | "queryStringParameters": {}, 4 | "pathParameters": {}, 5 | "body": null, 6 | "isBase64Encoded": false, 7 | "requestContext": { 8 | "http": { 9 | "path": "/assets/nonexistent", 10 | "method": "GET" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v2/request_spec_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": {}, 3 | "queryStringParameters": {}, 4 | "pathParameters": { 5 | "petId": "1" 6 | }, 7 | "body": null, 8 | "isBase64Encoded": false, 9 | "requestContext": { 10 | "http": { 11 | "path": "/pets/1", 12 | "method": "GET" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v2/request_static_asset.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": {}, 3 | "queryStringParameters": {}, 4 | "pathParameters": {}, 5 | "body": null, 6 | "isBase64Encoded": false, 7 | "requestContext": { 8 | "http": { 9 | "path": "/assets/styles.css", 10 | "method": "GET" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v2/request_static_index.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": {}, 3 | "queryStringParameters": {}, 4 | "pathParameters": {}, 5 | "body": null, 6 | "isBase64Encoded": false, 7 | "requestContext": { 8 | "http": { 9 | "path": "/www/", 10 | "method": "GET" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/simple/requests_v2/request_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": {}, 3 | "queryStringParameters": {}, 4 | "pathParameters": {}, 5 | "body": null, 6 | "isBase64Encoded": false, 7 | "requestContext": { 8 | "http": { 9 | "path": "/system/status", 10 | "method": "GET" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/soap-duplicate-endpoints/config/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: petstore.wsdl 3 | 4 | resources: 5 | # specific response 6 | - operation: getPetById 7 | requestBody: 8 | xPath: //pets:getPetByIdRequest/pets:id 9 | value: 100 10 | response: 11 | statusCode: 200 12 | headers: 13 | Content-Type: application/xml 14 | content: | 15 | 16 | 17 | 18 | 100 19 | dog 20 | 21 | 22 | 23 | 24 | # default response 25 | - operation: getPetById 26 | response: 27 | statusCode: 500 28 | headers: 29 | Content-Type: application/xml 30 | content: | 31 | 32 | 33 | Invalid operation 34 | 35 | 36 | 37 | system: 38 | xmlNamespaces: 39 | pets: urn:com:example:petstore 40 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/soap-duplicate-endpoints/requests/duplicate_endpoints.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": { 3 | "content-type": "application/xml", 4 | "soapaction": "getPetById" 5 | }, 6 | "queryStringParameters": {}, 7 | "pathParameters": {}, 8 | "body": "\n \n\t \n 100\n\n \n", 9 | "isBase64Encoded": false, 10 | "requestContext": { 11 | "http": { 12 | "path": "/pets/", 13 | "method": "POST" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /adapter/awslambda/src/test/resources/soap-simple/requests/success.json: -------------------------------------------------------------------------------- 1 | { 2 | "headers": { 3 | "content-type": "application/xml", 4 | "soapaction": "getPetById" 5 | }, 6 | "queryStringParameters": {}, 7 | "pathParameters": {}, 8 | "body": "\n \n\t \n 100\n\n \n", 9 | "isBase64Encoded": false, 10 | "requestContext": { 11 | "http": { 12 | "path": "/pets/", 13 | "method": "POST" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cmd/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'kotlin' 3 | 4 | compileJava { 5 | sourceCompatibility = JavaVersion.VERSION_11 6 | } 7 | 8 | dependencies { 9 | implementation project(':imposter-server') 10 | implementation project(':core:config-dynamic') 11 | implementation project(':adapter:adapter-vertxweb') 12 | 13 | implementation "args4j:args4j:$version_args4j" 14 | } 15 | 16 | compileKotlin { 17 | kotlinOptions { 18 | jvmTarget = JavaVersion.VERSION_11 19 | 20 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 21 | freeCompilerArgs = ["-Xjvm-default=all"] 22 | } 23 | } 24 | 25 | compileTestKotlin { 26 | kotlinOptions { 27 | jvmTarget = JavaVersion.VERSION_11 28 | 29 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 30 | freeCompilerArgs = ["-Xjvm-default=all"] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/api/src/main/java/io/gatehill/imposter/lifecycle/SecurityLifecycleHooks.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.lifecycle 2 | 3 | /** 4 | * @author Pete Cornish 5 | */ 6 | class SecurityLifecycleHooks : LifecycleHooks() 7 | -------------------------------------------------------------------------------- /core/api/src/main/java/io/gatehill/imposter/util/StringUtil.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.util 2 | 3 | /** 4 | * Splits a string on commas and trims each element. 5 | * If the input is `null`, returns an empty list. 6 | */ 7 | fun String?.splitOnCommaAndTrim(): List = 8 | this?.split(",")?.map { it.trim() } ?: emptyList() 9 | -------------------------------------------------------------------------------- /core/config-dynamic/src/test/resources/config/test-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "io.gatehill.imposter.core.test.ExamplePluginImpl", 3 | "path": "/example", 4 | "contentType": "application/json", 5 | "resources": [ 6 | { 7 | "path": "/{id}", 8 | "type": "ARRAY", 9 | "response": { 10 | "staticFile": "rest-plugin-list-data.json" 11 | } 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /core/config-dynamic/src/test/resources/config/test-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | plugin: io.gatehill.imposter.core.test.ExamplePluginImpl 3 | path: "/example" 4 | contentType: application/json 5 | resources: 6 | - path: "/{id}" 7 | type: ARRAY 8 | response: 9 | file: rest-plugin-list-data.json 10 | -------------------------------------------------------------------------------- /core/config-dynamic/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /core/config-resolver-s3/src/main/resources/META-INF/config-resolver.properties: -------------------------------------------------------------------------------- 1 | class=io.gatehill.imposter.config.resolver.S3ConfigResolver 2 | -------------------------------------------------------------------------------- /core/config-resolver-s3/src/test/resources/config/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "openapi" 2 | specFile: "pet-api.yaml" 3 | 4 | resources: 5 | - path: /pets/{petId} 6 | method: get 7 | pathParams: 8 | petId: 2 9 | response: 10 | file: subdir/response.json 11 | -------------------------------------------------------------------------------- /core/config-resolver-s3/src/test/resources/config/subdir/response.json: -------------------------------------------------------------------------------- 1 | { "id": 2, "name": "Dog" } -------------------------------------------------------------------------------- /core/config/src/main/resources/.imposterignore: -------------------------------------------------------------------------------- 1 | # By default, ignore the following files and directories when searching for config files 2 | 3 | .git 4 | .idea 5 | .svn 6 | node_modules 7 | -------------------------------------------------------------------------------- /core/config/src/main/resources/META-INF/config-resolver.properties: -------------------------------------------------------------------------------- 1 | class=io.gatehill.imposter.config.resolver.LocalFileConfigResolver 2 | -------------------------------------------------------------------------------- /core/config/src/test/java/io/gatehill/imposter/config/expression/SystemEvaluatorTest.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.config.expression 2 | 3 | import io.gatehill.imposter.ImposterConfig 4 | import org.hamcrest.MatcherAssert.assertThat 5 | import org.hamcrest.Matchers.equalTo 6 | import org.junit.jupiter.api.BeforeEach 7 | import org.junit.jupiter.api.Test 8 | 9 | /** 10 | * Tests for [SystemEvaluatorImpl]. 11 | */ 12 | class SystemEvaluatorTest { 13 | private lateinit var systemEvaluator: SystemEvaluatorImpl 14 | 15 | @BeforeEach 16 | fun before() { 17 | val config = ImposterConfig().apply { 18 | listenPort = 8080 19 | serverUrl = "http://localhost:8080" 20 | } 21 | systemEvaluator = SystemEvaluatorImpl(config) 22 | } 23 | 24 | @Test 25 | fun eval() { 26 | assertThat(eval("system.server.port"), equalTo("8080")) 27 | assertThat(eval("system.server.url"), equalTo("http://localhost:8080")) 28 | } 29 | 30 | private fun eval(expression: String): String? = 31 | systemEvaluator.eval(expression, emptyMap()) 32 | } 33 | -------------------------------------------------------------------------------- /core/config/src/test/java/io/gatehill/imposter/util/MapUtilTest.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.util 2 | 3 | import io.vertx.core.json.JsonArray 4 | import io.vertx.core.json.JsonObject 5 | import org.junit.jupiter.api.Assertions.assertEquals 6 | import org.junit.jupiter.api.Test 7 | import java.time.ZoneId 8 | import java.time.ZonedDateTime 9 | 10 | /** 11 | * Tests for [MapUtil]. 12 | */ 13 | class MapUtilTest { 14 | @Test 15 | fun `jsonify should support Vertx JsonObject and JsonArray`() { 16 | val json = MapUtil.jsonify( 17 | JsonObject().put( 18 | "foo", JsonArray().add("bar") 19 | ) 20 | ) 21 | assertEquals(""" 22 | { 23 | "foo" : [ "bar" ] 24 | } 25 | """.trim(), json) 26 | } 27 | 28 | @Test 29 | fun `jsonify should support JSR-310 times`() { 30 | val json = MapUtil.jsonify(mapOf( 31 | "foo" to ZonedDateTime.of(2024, 7, 29, 0, 0, 0, 0, ZoneId.of("UTC")) 32 | )) 33 | assertEquals(""" 34 | { 35 | "foo" : "2024-07-29T00:00:00Z" 36 | } 37 | """.trim(), json) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/config/src/test/resources/.env: -------------------------------------------------------------------------------- 1 | TEST_DOT_ENV=foo 2 | -------------------------------------------------------------------------------- /core/config/src/test/resources/basepath/test-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.config.support.BasePathSupportingPluginConfig" 2 | basePath: /base 3 | 4 | # explicitly do not set path 5 | # path: / 6 | 7 | resources: 8 | - path: /example 9 | response: 10 | statusCode: 200 11 | content: "example" 12 | -------------------------------------------------------------------------------- /core/config/src/test/resources/interpolated/test-config.yaml: -------------------------------------------------------------------------------- 1 | # A plugin configuration using an interpolated environment variable. 2 | --- 3 | plugin: "${env.EXAMPLE_PLUGIN}" 4 | path: "/test" 5 | contentType: text/plain 6 | response: 7 | content: Hello, world, listening on port 9090! 8 | -------------------------------------------------------------------------------- /core/config/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /core/config/src/test/resources/recursive/subdir1/test-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.config.support.BasePathSupportingPluginConfig" 2 | path: /example1 3 | response: 4 | statusCode: 200 5 | content: "example1" 6 | -------------------------------------------------------------------------------- /core/config/src/test/resources/recursive/subdir2/test-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.config.support.BasePathSupportingPluginConfig" 2 | path: /example2 3 | response: 4 | statusCode: 200 5 | content: "example2" 6 | -------------------------------------------------------------------------------- /core/config/src/test/resources/recursive/test-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.config.support.BasePathSupportingPluginConfig" 2 | path: /example3 3 | response: 4 | statusCode: 200 5 | content: "example3" 6 | -------------------------------------------------------------------------------- /core/config/src/test/resources/simple/test-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.config.support.BasePathSupportingPluginConfig" 2 | 3 | resources: 4 | - path: /example 5 | method: GET 6 | response: 7 | statusCode: 200 8 | content: "example" 9 | 10 | - path: /bracket-style/{param1} 11 | method: GET 12 | response: 13 | statusCode: 200 14 | 15 | - path: /vertx-style/:param1 16 | method: GET 17 | response: 18 | statusCode: 200 19 | -------------------------------------------------------------------------------- /core/engine/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /core/engine/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker: -------------------------------------------------------------------------------- 1 | mock-maker-inline -------------------------------------------------------------------------------- /core/engine/src/test/resources/response-file.txt: -------------------------------------------------------------------------------- 1 | Hello, world! -------------------------------------------------------------------------------- /core/engine/src/test/resources/test-array.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "foo": "bar" 4 | } 5 | ] 6 | -------------------------------------------------------------------------------- /core/expression/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /core/http/src/test/java/io/gatehill/imposter/http/HttpRouteTest.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.http 2 | 3 | import io.vertx.core.Vertx 4 | import org.junit.jupiter.api.Assertions.assertTrue 5 | import org.junit.jupiter.api.Test 6 | 7 | /** 8 | * Tests for [HttpRoute]. 9 | */ 10 | class HttpRouteTest { 11 | @Test 12 | fun `should match exact path`() { 13 | val router = HttpRouter(Vertx.vertx()) 14 | val route = HttpRoute(router, path = "/foo") 15 | val matches = route.matches("/foo") 16 | assertTrue(matches) 17 | } 18 | 19 | @Test 20 | fun `should match path with trailing wildcard`() { 21 | val router = HttpRouter(Vertx.vertx()) 22 | val route = HttpRoute(router, path = "/foo*") 23 | val matches = route.matches("/foo/bar") 24 | assertTrue(matches) 25 | } 26 | 27 | @Test 28 | fun `should match path with placeholder`() { 29 | val router = HttpRouter(Vertx.vertx()) 30 | val route = HttpRoute(router, path = "/foo/{id}") 31 | val matches = route.matches("/foo/123") 32 | assertTrue(matches) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/plugin-detector/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'kotlin' 3 | apply plugin: 'maven-publish' 4 | 5 | compileJava { 6 | sourceCompatibility = JavaVersion.VERSION_11 7 | } 8 | 9 | dependencies { 10 | implementation project (':core:imposter-engine') 11 | } 12 | 13 | task sourcesJar(type: Jar, dependsOn: classes) { 14 | archiveClassifier = 'sources' 15 | from sourceSets.main.allSource 16 | } 17 | 18 | artifacts { 19 | archives sourcesJar 20 | } 21 | 22 | publishing { 23 | publications { 24 | maven(MavenPublication) { 25 | from components.java 26 | artifact sourcesJar 27 | 28 | repositories { 29 | maven { 30 | url = version.endsWith('SNAPSHOT') ? mavenSnapshotRepository : mavenReleaseRepository 31 | credentials(AwsCredentials) { 32 | accessKey awsAccessKey 33 | secretKey awsSecretKey 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | 41 | compileKotlin { 42 | kotlinOptions { 43 | jvmTarget = JavaVersion.VERSION_11 44 | 45 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 46 | freeCompilerArgs = ["-Xjvm-default=all"] 47 | } 48 | } 49 | 50 | compileTestKotlin { 51 | kotlinOptions { 52 | jvmTarget = JavaVersion.VERSION_11 53 | 54 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 55 | freeCompilerArgs = ["-Xjvm-default=all"] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /distro/all/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .github 3 | .gradle 4 | core 5 | docs 6 | embedded 7 | examples 8 | gradle 9 | mock 10 | scripting 11 | scripts 12 | server 13 | store 14 | test 15 | tools 16 | **/node_modules 17 | -------------------------------------------------------------------------------- /distro/all/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMAGE_TAG=latest 2 | 3 | FROM outofcoffee/imposter-base:${BASE_IMAGE_TAG} 4 | 5 | LABEL MAINTAINER="Pete Cornish " 6 | 7 | CMD ["--configDir", "/opt/imposter/config"] 8 | -------------------------------------------------------------------------------- /distro/awslambda/README.md: -------------------------------------------------------------------------------- 1 | # AWS Lambda distribution 2 | 3 | ## Set up 4 | 5 | - Create an S3 bucket 6 | - Upload the files from `deploy/example/config` to the bucket, under a directory (e.g. `config`) 7 | - Set the S3 path to the config dir in `deploy/serverless.yml` as the `IMPOSTER_CONFIG_DIR` environment variable 8 | 9 | ## One shot build/deploy 10 | 11 | Using Node.js: 12 | 13 | cd deploy 14 | npm install 15 | npm run deploy 16 | 17 | ## Step by step 18 | 19 | ### Build 20 | 21 | ./gradlew dist 22 | 23 | Builds JAR to `./build/libs` 24 | 25 | ### Deploy 26 | 27 | cd deploy 28 | npx serverless deploy 29 | 30 | Or: 31 | 32 | cd deploy 33 | npm install 34 | npm run deploy 35 | -------------------------------------------------------------------------------- /distro/awslambda/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | compileJava { 4 | sourceCompatibility = JavaVersion.VERSION_11 5 | } 6 | 7 | dependencies { 8 | implementation project (':adapter:adapter-awslambda') 9 | } 10 | 11 | task buildZip(type: Zip) { 12 | archiveFileName.set('imposter-awslambda.zip') 13 | from compileJava 14 | from processResources 15 | into('lib') { 16 | from configurations.runtimeClasspath 17 | } 18 | } 19 | 20 | task dist { 21 | dependsOn buildZip 22 | } 23 | -------------------------------------------------------------------------------- /distro/awslambda/deploy/example/bucket-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Id": "Policy1638152516795", 4 | "Statement": [ 5 | { 6 | "Sid": "Stmt1638152467919", 7 | "Effect": "Allow", 8 | "Principal": { 9 | "AWS": "arn:aws:iam::000000000000:role/aws-imposter-example-dev-us-east-1-lambdaRole" 10 | }, 11 | "Action": "s3:GetObject", 12 | "Resource": "arn:aws:s3:::imposter-lambda-example/*" 13 | }, 14 | { 15 | "Sid": "Stmt1638152514429", 16 | "Effect": "Allow", 17 | "Principal": { 18 | "AWS": "arn:aws:iam::000000000000:role/aws-imposter-example-dev-us-east-1-lambdaRole" 19 | }, 20 | "Action": "s3:ListBucket", 21 | "Resource": "arn:aws:s3:::imposter-lambda-example" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /distro/awslambda/deploy/example/config/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "openapi" 2 | specFile: "pet-api.yaml" 3 | 4 | resources: 5 | - path: /pets/{petId} 6 | method: get 7 | pathParams: 8 | petId: 2 9 | response: 10 | file: response.json 11 | -------------------------------------------------------------------------------- /distro/awslambda/deploy/example/config/response.json: -------------------------------------------------------------------------------- 1 | { "id": 2, "name": "Dog" } -------------------------------------------------------------------------------- /distro/awslambda/deploy/serverless-api-gateway/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-imposter-example", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "cd ../.. && ../../gradlew dist", 8 | "deploy": "npm run build && serverless deploy", 9 | "info": "serverless info", 10 | "undeploy": "serverless remove" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": {}, 15 | "devDependencies": { 16 | "serverless": "^3.16.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /distro/awslambda/deploy/serverless-api-gateway/serverless.yml: -------------------------------------------------------------------------------- 1 | service: aws-imposter-example 2 | frameworkVersion: '3' 3 | 4 | provider: 5 | name: aws 6 | runtime: java11 7 | 8 | # permit the function to fetch the config from an S3 bucket named 'imposter-lambda-example' 9 | iamRoleStatements: 10 | - Effect: "Allow" 11 | Action: "s3:GetObject" 12 | Resource: "arn:aws:s3:::imposter-lambda-example/*" 13 | - Effect: "Allow" 14 | Action: "s3:ListBucket" 15 | Resource: "arn:aws:s3:::imposter-lambda-example" 16 | 17 | package: 18 | individually: true 19 | 20 | functions: 21 | imposter: 22 | handler: "io.gatehill.imposter.awslambda.Handler" 23 | timeout: 30 24 | package: 25 | artifact: "../../build/distributions/imposter-awslambda.zip" 26 | environment: 27 | IMPOSTER_CONFIG_DIR: "s3://imposter-lambda-example/config/" 28 | events: 29 | - http: 30 | method: any 31 | path: /{proxy+} 32 | -------------------------------------------------------------------------------- /distro/awslambda/deploy/serverless-function-url/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-imposter-example", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "cd ../.. && ../../gradlew dist", 8 | "deploy": "npm run build && serverless deploy", 9 | "info": "serverless info", 10 | "undeploy": "serverless remove" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": {}, 15 | "devDependencies": { 16 | "serverless": "^3.16.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /distro/awslambda/deploy/serverless-function-url/serverless.yml: -------------------------------------------------------------------------------- 1 | service: aws-imposter-example 2 | frameworkVersion: '3' 3 | 4 | provider: 5 | name: aws 6 | runtime: java11 7 | 8 | # permit the function to fetch the config from an S3 bucket named 'imposter-lambda-example' 9 | iamRoleStatements: 10 | - Effect: "Allow" 11 | Action: "s3:GetObject" 12 | Resource: "arn:aws:s3:::imposter-lambda-example/*" 13 | - Effect: "Allow" 14 | Action: "s3:ListBucket" 15 | Resource: "arn:aws:s3:::imposter-lambda-example" 16 | 17 | package: 18 | individually: true 19 | 20 | functions: 21 | imposter: 22 | handler: "io.gatehill.imposter.awslambda.HandlerV2" 23 | timeout: 30 24 | url: true 25 | package: 26 | artifact: "../../build/distributions/imposter-awslambda.zip" 27 | environment: 28 | IMPOSTER_CONFIG_DIR: "s3://imposter-lambda-example/config/" 29 | -------------------------------------------------------------------------------- /distro/awslambda/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /distro/base/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .github 3 | .gradle 4 | core 5 | docs 6 | embedded 7 | examples 8 | gradle 9 | mock 10 | scripting 11 | scripts 12 | server 13 | store 14 | test 15 | tools 16 | **/node_modules 17 | -------------------------------------------------------------------------------- /distro/base/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:11.0.23_9-jre-jammy 2 | 3 | LABEL MAINTAINER="Pete Cornish " 4 | 5 | RUN addgroup imposter --gid 2048 && \ 6 | adduser imposter --uid 2048 --gid 2048 7 | 8 | # add CLI 9 | ARG IMPOSTER_VERSION 10 | ENV IMPOSTER_VERSION="${IMPOSTER_VERSION}" \ 11 | IMPOSTER_ENGINE=unpacked \ 12 | IMPOSTER_JVM_DISTRODIR=/opt/imposter 13 | 14 | ARG IMPOSTER_CLI_VERSION="1.0.3" 15 | ADD https://github.com/imposter-project/imposter-cli/releases/download/v${IMPOSTER_CLI_VERSION}/imposter-cli_linux_amd64.tar.gz /tmp/imposter-cli/imposter-cli.tar.gz 16 | 17 | RUN cd /tmp/imposter-cli && \ 18 | tar xvf /tmp/imposter-cli/imposter-cli.tar.gz && \ 19 | mv /tmp/imposter-cli/imposter /usr/local/bin/imposter && \ 20 | rm -rf /tmp/imposter-cli 21 | 22 | # add distro 23 | RUN mkdir -p \ 24 | /opt/imposter/bin \ 25 | /opt/imposter/lib \ 26 | /opt/imposter/config \ 27 | /opt/imposter/plugins 28 | 29 | ONBUILD ARG DISTRO_NAME 30 | ONBUILD ENV DISTRO_NAME="${DISTRO_NAME}" 31 | ONBUILD ADD ./distro/${DISTRO_NAME}/build/install/imposter/lib/* /opt/imposter/lib/ 32 | ONBUILD RUN chown -R imposter:imposter /opt/imposter && \ 33 | rm -rf /bin/* 34 | 35 | ONBUILD USER imposter 36 | 37 | ENV IMPOSTER_PLUGIN_DIR=/opt/imposter/plugins 38 | 39 | EXPOSE 8080 8443 40 | ENTRYPOINT ["java", "-classpath", "/opt/imposter/lib/*", "io.gatehill.imposter.cmd.ImposterLauncher"] 41 | -------------------------------------------------------------------------------- /distro/base/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'kotlin' 3 | apply plugin: 'maven-publish' 4 | 5 | compileJava { 6 | sourceCompatibility = JavaVersion.VERSION_11 7 | } 8 | 9 | dependencies { 10 | api project (':core:imposter-engine') 11 | implementation project (':core:config-resolver-s3') 12 | api project (':imposter-server') 13 | } 14 | 15 | task sourcesJar(type: Jar, dependsOn: classes) { 16 | archiveClassifier = 'sources' 17 | from sourceSets.main.allSource 18 | } 19 | 20 | artifacts { 21 | archives sourcesJar 22 | } 23 | 24 | publishing { 25 | publications { 26 | maven(MavenPublication) { 27 | from components.java 28 | artifact sourcesJar 29 | 30 | repositories { 31 | maven { 32 | url = version.endsWith('SNAPSHOT') ? mavenSnapshotRepository : mavenReleaseRepository 33 | credentials(AwsCredentials) { 34 | accessKey awsAccessKey 35 | secretKey awsSecretKey 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | 43 | compileKotlin { 44 | kotlinOptions { 45 | jvmTarget = JavaVersion.VERSION_11 46 | 47 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 48 | freeCompilerArgs = ["-Xjvm-default=all"] 49 | } 50 | } 51 | 52 | compileTestKotlin { 53 | kotlinOptions { 54 | jvmTarget = JavaVersion.VERSION_11 55 | 56 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 57 | freeCompilerArgs = ["-Xjvm-default=all"] 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /distro/base/src/main/resources/META-INF/imposter.properties: -------------------------------------------------------------------------------- 1 | # List of comma-separated plugin classes to load if none specified 2 | plugins=config-detector 3 | -------------------------------------------------------------------------------- /distro/core/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .github 3 | .gradle 4 | core 5 | docs 6 | embedded 7 | examples 8 | gradle 9 | mock 10 | scripting 11 | scripts 12 | server 13 | store 14 | test 15 | tools 16 | **/node_modules 17 | -------------------------------------------------------------------------------- /distro/core/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMAGE_TAG=latest 2 | 3 | FROM outofcoffee/imposter-base:${BASE_IMAGE_TAG} 4 | 5 | LABEL MAINTAINER="Pete Cornish " 6 | 7 | CMD ["--plugin=openapi", "--plugin=rest", "--plugin=soap", "--configDir=/opt/imposter/config"] 8 | -------------------------------------------------------------------------------- /distro/core/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'application' 3 | apply plugin: 'com.gradleup.shadow' 4 | 5 | compileJava { 6 | sourceCompatibility = JavaVersion.VERSION_11 7 | } 8 | 9 | dependencies { 10 | implementation project (':imposter-cmd') 11 | implementation project (':distro:distro-base') 12 | 13 | // plugins 14 | implementation project (':core:plugin-detector') 15 | implementation project (':mock:mock-openapi') 16 | implementation project (':mock:mock-rest') 17 | implementation project (':mock:mock-soap') 18 | } 19 | 20 | mainClassName = 'io.gatehill.imposter.cmd.ImposterLauncher' 21 | 22 | jar { 23 | manifest { 24 | attributes 'Main-Class': mainClassName 25 | 26 | // duplicates attribute from core so it is present in the merged jar 27 | attributes 'Imposter-Version': project.version 28 | 29 | // workaround for 'getCallerClass' warning due to log4j repackaging 30 | // see https://stackoverflow.com/questions/52953483/logmanager-getlogger-is-unable-to-determine-class-name-on-java-11 31 | attributes 'Multi-Release': 'true' 32 | } 33 | } 34 | 35 | application { 36 | applicationName = 'imposter' 37 | } 38 | 39 | shadowJar { 40 | archiveBaseName = 'imposter-core' 41 | archiveVersion = '' 42 | archiveClassifier = '' 43 | 44 | append 'META-INF/imposter.properties' 45 | append 'META-INF/plugin.properties' 46 | append 'META-INF/config-resolver.properties' 47 | 48 | mergeServiceFiles { 49 | include 'META-INF/services/io.vertx.core.spi.VerticleFactory' 50 | } 51 | } 52 | 53 | task dist { 54 | dependsOn installDist, shadowJar 55 | } 56 | -------------------------------------------------------------------------------- /distro/distroless-multistage/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .github 3 | .gradle 4 | docs 5 | examples 6 | gradle 7 | scripts 8 | **/node_modules 9 | build/ 10 | -------------------------------------------------------------------------------- /distro/distroless-multistage/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gradle:7.6-jdk17 AS build 2 | 3 | # mirror uid/gid from distroless 4 | RUN addgroup nonroot --gid 65532 && \ 5 | adduser nonroot --uid 65532 --gid 65532 6 | 7 | COPY --chown=nonroot:nonroot . /app 8 | USER nonroot 9 | WORKDIR /app 10 | 11 | RUN mkdir -p \ 12 | ./build/imposter/bin \ 13 | ./build/imposter/lib \ 14 | ./build/imposter/config \ 15 | ./build/imposter/plugins 16 | 17 | ENV GRADLE_OPTS="-Dorg.gradle.daemon=false" 18 | 19 | # don't run shadowJar/dist tasks 20 | RUN gradle :distro:distro-core:installDist -xtest 21 | 22 | RUN cp -r ./distro/core/build/install/imposter/lib/* ./build/imposter/lib/ 23 | 24 | FROM gcr.io/distroless/java17-debian12 25 | 26 | LABEL MAINTAINER="Pete Cornish " 27 | 28 | ARG IMPOSTER_VERSION 29 | ENV IMPOSTER_VERSION="${IMPOSTER_VERSION}" \ 30 | IMPOSTER_ENGINE=unpacked \ 31 | IMPOSTER_JVM_DISTRODIR=/opt/imposter 32 | 33 | COPY --from=build --chown=nonroot:nonroot /app/build/imposter /opt/imposter 34 | USER nonroot 35 | 36 | ENV IMPOSTER_PLUGIN_DIR=/opt/imposter/plugins 37 | 38 | EXPOSE 8080 8443 39 | ENTRYPOINT ["java", "-classpath", "/opt/imposter/lib/*", "io.gatehill.imposter.cmd.ImposterLauncher"] 40 | CMD ["--plugin=openapi", "--plugin=rest", "--plugin=soap", "--configDir=/opt/imposter/config"] 41 | -------------------------------------------------------------------------------- /distro/distroless/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .github 3 | .gradle 4 | adapter 5 | cmd 6 | core 7 | distro 8 | !distro/core 9 | docs 10 | embedded 11 | examples 12 | gradle 13 | lib 14 | mock 15 | scripting 16 | scripts 17 | server 18 | store 19 | test 20 | tools 21 | **/node_modules 22 | build/ 23 | -------------------------------------------------------------------------------- /distro/distroless/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm AS build 2 | 3 | # mirror uid/gid from distroless 4 | RUN addgroup nonroot --gid 65532 && \ 5 | adduser nonroot --uid 65532 --gid 65532 6 | 7 | COPY --chown=nonroot:nonroot . /app 8 | USER nonroot 9 | WORKDIR /app 10 | 11 | RUN mkdir -p \ 12 | ./build/imposter/bin \ 13 | ./build/imposter/lib \ 14 | ./build/imposter/config \ 15 | ./build/imposter/plugins 16 | 17 | COPY --chown=nonroot:nonroot ./distro/core/build/install/imposter/lib/* ./build/imposter/lib/ 18 | 19 | FROM gcr.io/distroless/java17-debian12:nonroot 20 | 21 | LABEL MAINTAINER="Pete Cornish " 22 | 23 | ARG IMPOSTER_VERSION 24 | ENV IMPOSTER_VERSION="${IMPOSTER_VERSION}" \ 25 | IMPOSTER_ENGINE=unpacked \ 26 | IMPOSTER_JVM_DISTRODIR=/opt/imposter 27 | 28 | COPY --from=build --chown=nonroot:nonroot /app/build/imposter /opt/imposter 29 | USER nonroot 30 | 31 | ENV IMPOSTER_PLUGIN_DIR=/opt/imposter/plugins 32 | 33 | EXPOSE 8080 8443 34 | ENTRYPOINT ["java", "-classpath", "/opt/imposter/lib/*", "io.gatehill.imposter.cmd.ImposterLauncher"] 35 | CMD ["--plugin=openapi", "--plugin=rest", "--plugin=soap", "--configDir=/opt/imposter/config"] 36 | -------------------------------------------------------------------------------- /distro/embedded/README.md: -------------------------------------------------------------------------------- 1 | Embedding Imposter in your JVM tests 2 | ==================================== 3 | 4 | This module enables you to embed the Imposter in your JVM tests, such as JUnit or TestNG. 5 | 6 | This method uses pure JVM technologies (i.e. no Docker requirement). 7 | 8 | See [the documentation](../../docs/embed_jvm.md) for usage and examples. 9 | -------------------------------------------------------------------------------- /distro/embedded/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'maven-publish' 3 | 4 | compileJava { 5 | sourceCompatibility = JavaVersion.VERSION_11 6 | } 7 | 8 | dependencies { 9 | implementation project(':distro:distro-base') 10 | implementation project(':adapter:adapter-vertxweb') 11 | 12 | api project (':embedded:embedded-core') 13 | api project (':embedded:embedded-openapi') 14 | 15 | // plugins 16 | implementation project (':core:plugin-detector') 17 | } 18 | 19 | task sourcesJar(type: Jar, dependsOn: classes) { 20 | archiveClassifier = 'sources' 21 | from sourceSets.main.allSource 22 | } 23 | 24 | artifacts { 25 | archives sourcesJar 26 | } 27 | 28 | publishing { 29 | publications { 30 | maven(MavenPublication) { 31 | from components.java 32 | artifact sourcesJar 33 | 34 | repositories { 35 | maven { 36 | url = version.endsWith('SNAPSHOT') ? mavenSnapshotRepository : mavenReleaseRepository 37 | credentials(AwsCredentials) { 38 | accessKey awsAccessKey 39 | secretKey awsSecretKey 40 | } 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | docs.imposter.sh -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Imposter documentation 2 | 3 | Read the documentation at [https://docs.imposter.sh](https://docs.imposter.sh/) 4 | -------------------------------------------------------------------------------- /docs/build.md: -------------------------------------------------------------------------------- 1 | # Build 2 | 3 | ## Hacking locally 4 | 5 | You can build and run locally using the `dev-current.sh` convenience script. This will start Imposter in debug mode, with the debug port running on 8000. 6 | 7 | Build and run with Docker: 8 | 9 | ./scripts/dev-current.sh -m docker 10 | 11 | Build and run with local JVM: 12 | 13 | ./scripts/dev-current.sh -m java 14 | 15 | More complete example specifying plugin and config directory: 16 | 17 | ./scripts/dev-current.sh -m docker -p rest -c $PWD/examples/rest/multiple 18 | 19 | > See the [README](./hack/README.md) for more details about using this script. 20 | 21 | ## Local build 22 | 23 | If you don't want to use the convenience script, then you can follow these steps. 24 | 25 | ### Prerequisites 26 | 27 | * JDK 11 28 | 29 | ### Steps 30 | 31 | For distribution, Imposter is built as an all-in-one JAR file. This is available as a Docker image, as well as in raw form. 32 | 33 | To get started with the examples here, first run: 34 | 35 | ./gradlew clean dist 36 | 37 | The JAR is created under the `distro/all/build/libs` directory. 38 | 39 | > If, instead, you wanted to compile the JAR _without_ embedded dependencies, use: 40 | > 41 | > ./gradlew clean build 42 | 43 | ## Tests 44 | 45 | If you want to run tests: 46 | 47 | ./gradlew clean test 48 | 49 | ## Docker containers 50 | 51 | Build the Docker containers with: 52 | 53 | ./scripts/docker-build.sh 54 | 55 | --- 56 | 57 | ## Extending to build a custom application 58 | 59 | To extend Imposter and build a custom application see [this section](extend.md). -------------------------------------------------------------------------------- /docs/examples/README.md: -------------------------------------------------------------------------------- 1 | See [examples](https://github.com/imposter-project/examples). 2 | -------------------------------------------------------------------------------- /docs/external/short_description.md: -------------------------------------------------------------------------------- 1 | # Short description (<1000 characters) 2 | 3 | Imposter is a system that runs live, interactive mocks in place of real systems. Turn an OpenAPI file into a mock API for dev or QA. Run standalone mock servers, or embed mocks within your tests. 4 | 5 | Validate HTTP requests to ensure they match the OpenAPI specification. Serve response examples embedded in the specification. Explore mock endpoints using the interactive API sandbox based on Swagger UI. 6 | 7 | Imposter supports custom responses, headers, status codes etc. based on path, querystring, request headers, request body and more.Responses can be templated - that is, a file or string containing placeholders, which are replaced with values at runtime. 8 | 9 | You can match resources to requests using attributes such as the HTTP method, path, query string, headers or body (both JSON and XML supported). Also supports script-driven responses for maximum control, in either JavaScript or Groovy. 10 | 11 | Imposter also allows you to capture elements of the request, so you can retrieve them later. 12 | -------------------------------------------------------------------------------- /docs/features.md: -------------------------------------------------------------------------------- 1 | # Features 2 | 3 | Imposter allows certain features to be enabled or disabled. Fewer features generally lowers resource requirements. 4 | 5 | > Also see the [Plugins](./plugins.md) documentation for a list of available and built-in plugins. 6 | 7 | ## List of features 8 | 9 | | Feature name | Purpose | Details | Enabled by default | 10 | |-----------------|--------------------------------------|----------------------------------------|--------------------| 11 | | `metrics` | Collects and exposes telemetry. | [Metrics](./metrics_logs_telemetry.md) | `true` | 12 | | `stores` | Persistent or semi-persistent state. | [Stores](./stores.md) | `true` | 13 | 14 | These can be controlled by setting the environment variable `IMPOSTER_FEATURES`: 15 | 16 | IMPOSTER_FEATURES="stores=false,metrics=true" 17 | 18 | ...or Java system property `imposter.features`: 19 | 20 | -Dimposter.features="stores=false,metrics=true" 21 | -------------------------------------------------------------------------------- /docs/hack/README.md: -------------------------------------------------------------------------------- 1 | # Developing Imposter 2 | 3 | ## Convenience script 4 | 5 | The script `scripts/dev-current.sh` is intended for local testing when changing the Impsoter codebase. 6 | 7 | The script performs the following steps: 8 | 9 | * builds Imposter from source 10 | * starts Imposter using Docker or plain JVM 11 | * enables a specified plugin 12 | * passes the specified directory as the configuration directory 13 | 14 | Usage: 15 | 16 | ``` 17 | dev-current.sh [args] 18 | 19 | Arguments: 20 | 21 | -m How to run Imposter, e.g. docker 22 | -c config-dir Path to the Imposter configuration directory 23 | [-d distro-name] The distro name, e.g. openapi 24 | [-l log-level] Logging level, e.g. DEBUG or TRACE 25 | [-t run-tests] Whether to run tests (true or false). Default is true 26 | [-z debug-mode] Whether to enable Java debug mode on port 8000 27 | ``` 28 | 29 | Example: 30 | 31 | ``` 32 | $ ./scripts/dev-current.sh -m java -p openapi -c $PWD/examples/openapi/simple 33 | ``` 34 | 35 | This starts Imposter in bare JVM mode (no Docker) with the OpenAPI plugin enabled, pointing to the examples directory. 36 | 37 | ### Debugging 38 | 39 | When started using this script, JVM debug mode is enabled and the debug socket is opened on port 8000. 40 | 41 | ## Test with Gradle 42 | 43 | You can run a test using a specific JVM version using Docker and Gradle as follows: 44 | 45 | docker run -it --rm -u gradle -v "$PWD":/home/gradle/project -w /home/gradle/project amd64/gradle:6-jdk11 gradle clean test 46 | -------------------------------------------------------------------------------- /docs/images/api-sandbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/api-sandbox.png -------------------------------------------------------------------------------- /docs/images/composite_logo13_cropped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/composite_logo13_cropped.png -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/favicon.ico -------------------------------------------------------------------------------- /docs/images/groovy_debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/groovy_debug.png -------------------------------------------------------------------------------- /docs/images/groovy_jvm_debug_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/groovy_jvm_debug_config.png -------------------------------------------------------------------------------- /docs/images/lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/lambda.png -------------------------------------------------------------------------------- /docs/images/lambda_config_env.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/lambda_config_env.png -------------------------------------------------------------------------------- /docs/images/lambda_create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/lambda_create.png -------------------------------------------------------------------------------- /docs/images/lambda_handler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/lambda_handler.png -------------------------------------------------------------------------------- /docs/images/lambda_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/lambda_url.png -------------------------------------------------------------------------------- /docs/images/plain_logo14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/docs/images/plain_logo14.png -------------------------------------------------------------------------------- /docs/infrastructure/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM squidfunk/mkdocs-material 2 | 3 | COPY infrastructure/constraints.txt \ 4 | infrastructure/requirements.txt \ 5 | /build/ 6 | 7 | ENV PIP_CONSTRAINT=/build/constraints.txt 8 | 9 | RUN pip install -r /build/requirements.txt 10 | -------------------------------------------------------------------------------- /docs/infrastructure/constraints.txt: -------------------------------------------------------------------------------- 1 | # required due to https://github.com/pypa/setuptools/issues/4519 2 | setuptools<72 3 | -------------------------------------------------------------------------------- /docs/infrastructure/requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs-material~=9.5 2 | mkdocs-mermaid2-plugin~=1.1 3 | -------------------------------------------------------------------------------- /docs/javascript_tips.md: -------------------------------------------------------------------------------- 1 | # JavaScript tips and tricks 2 | 3 | ## Background 4 | 5 | This section provides additional tips and tricks when using JavaScript as the scripting language for your mocks. It builds on the [Scripting](./scripting.md) documentation. If you are new to Imposter scripting, it's best to start there. 6 | 7 | ## Multi-file JavaScript scripts 8 | 9 | Sometimes you may want to split your JavaScript scripts into multiple files for better organisation. You can do this by using a bundler like Webpack or Browserify to bundle your scripts into a single file. 10 | 11 | See [imposter-js-types](https://github.com/imposter-project/imposter-js-types) for how to do this. 12 | 13 | Check out the [samples](https://github.com/imposter-project/imposter-js-types/tree/main/samples) directory for a JavaScript and a TypeScript example project. 14 | 15 | -------------------------------------------------------------------------------- /docs/roadmap.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | This section lists future ideas for features and improvements. Feel free to submit a suggestion by raising an issue. 4 | 5 | ## Features 6 | 7 | * Non-HTTP transports 8 | * Asynchronous requests (i.e. callbacks) 9 | * Asynchronous responses 10 | * Scheduled HTTP(S) invocations 11 | * Scheduled script executions 12 | * Request and response validation against a JSON Schema file (instead of just OpenAPI spec) 13 | * SOAP plugin - validate request/response body against XSD. 14 | * Autogenerate OpenAPI spec/UI for REST plugin. 15 | 16 | ## Improvements 17 | 18 | ### Capture 19 | 20 | - Replace `const` and `expression` with `value` key in capture block. 21 | 22 | ### HBase 23 | 24 | * Add content type header to HBase response 25 | * Reuse HBase model classes for JSON serialisation 26 | 27 | ## Breaking changes 28 | 29 | The following items are breaking changes, such as removal of deprecated functionality. They will be removed or changed in a backwards incompatible way in a future major version. 30 | 31 | - Remove deprecated `withData(String?)` script function 32 | - Request and response validation will be enabled by default 33 | - Remove deprecated `IMPOSTER_S3_CONFIG_URL` environment variable 34 | -------------------------------------------------------------------------------- /docs/scripting_modern_js.md: -------------------------------------------------------------------------------- 1 | # Using modern JavaScript features in scripts 2 | 3 | The default JavaScript engine is GraalVM, which is based on ECMAScript 2022 (more formally, [ECMA-262, 13th edition](https://262.ecma-international.org/13.0/)). This means you can use modern JavaScript features from ECMAScript 2022 in your scripts. 4 | 5 | ### Features 6 | 7 | GraalVM enables you to use modern JavaScript features such as: 8 | 9 | - `let` and `const` for variable declarations 10 | - Arrow functions 11 | - Template literals 12 | - Destructuring 13 | - Classes 14 | 15 | To use the GraalVM JavaScript engine, you need to be running Imposter v4.0.0 or later. 16 | 17 | --- 18 | 19 | ## Examples 20 | 21 | For examples, see the `examples/graal` directory [in GitHub](https://github.com/imposter-project/examples/blob/main/graal). 22 | 23 | ### Simple example 24 | 25 | Start the mock server: 26 | 27 | ```bash 28 | imposter up examples/graal/simple 29 | ``` 30 | 31 | Send a request to the mock server: 32 | 33 | ```bash 34 | curl -i http://localhost:8080?name=Ada 35 | 36 | Hello Ada 37 | ``` 38 | 39 | ### Advanced example 40 | 41 | See the `examples/graal/es6` [directory](https://github.com/imposter-project/examples/blob/main/graal) for an example of using modern JavaScript features in a script. 42 | 43 | --- 44 | 45 | ## Further reading 46 | 47 | - [Using legacy JavaScript engine (Nashorn)](scripting_legacy_js.md) 48 | -------------------------------------------------------------------------------- /docs/tls_ssl.md: -------------------------------------------------------------------------------- 1 | # TLS/SSL 2 | 3 | You can run Imposter with HTTPS enabled. To do this, enable the TLS option and provide keystore options. 4 | 5 | *Note:* unless you explicitly override the listen port (`--listenPort`), enabling TLS will change the listen port to 8443. 6 | 7 | ### Example 8 | 9 | java -jar distro/all/build/libs/imposter-all.jar \ 10 | --plugin rest \ 11 | --configDir /path/to/config \ 12 | --tlsEnabled \ 13 | --keystorePath ./server/src/main/resources/keystore/ssl.jks \ 14 | --keystorePassword password 15 | 16 | **Note:** This example uses the self-signed certificate for TLS/SSL found in the source repository. You can, of course, use your own keystore instead. If you need to access the keys or certificate from this example, the keystore is located at `server/src/main/resources/keystore` and uses the secure password 'password'. 17 | 18 | ## A note on certificates 19 | 20 | SSL certificates must match the domain where you’re hosting an application, e.g. https://example.com would need a certificate issued for the example.com domain. 21 | 22 | Normally, you would obtain a signed certificate for a given domain via a third party provider. Certificates signed by a public certificate authority (CA) will generally be trusted by client applications as the CA is trusted by your system. 23 | 24 | If you generate a certificate yourself, or use the test one in this project, this is known as a self-signed certificate. Self-signed certificates are untrusted and you usually have to configure your client to accept them explicitly, such as via a trust store or other JVM-wide SSL configuration. 25 | -------------------------------------------------------------------------------- /docs/usage.md: -------------------------------------------------------------------------------- 1 | # Usage (command line arguments and environment variables) 2 | 3 | ## Command line arguments 4 | 5 | Some options can be controlled using command line arguments. 6 | 7 | - If you are using the CLI, see [this documentation](https://github.com/imposter-project/imposter-cli/blob/main/README.md#usage) for a list of command line arguments. 8 | - If you are using the JAR approach, see [this documentation](usage_jar.md). 9 | 10 | ## Environment variables 11 | 12 | See [environment variables](./environment_variables.md) for a list of all environment variables. 13 | 14 | ## Setting environment variables using a file 15 | 16 | You can use an environment file ('envfile') to pass environment variables to Imposter. To do this, add a file named `.env` adjacent to your configuration files, for example: 17 | 18 | ``` 19 | $ ls 20 | .env 21 | imposter-config.yaml 22 | 23 | $ cat .env 24 | IMPOSTER_LOG_LEVEL=info 25 | OTHER_ENV_VAR=example 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/usage_jar.md: -------------------------------------------------------------------------------- 1 | ## JAR command line arguments 2 | 3 | When you are using the [JAR approach](run_imposter_jar.md), some options can be controlled using command line arguments. 4 | 5 | > **Note** 6 | > If you are using the CLI, see [this documentation](https://github.com/imposter-project/imposter-cli/blob/main/README.md) for a list of command line arguments. 7 | 8 | ## Available arguments 9 | 10 | The following command line arguments can be used: 11 | 12 | --configDir (-c) VAL : Directory containing mock configuration files 13 | --help (-h) : Display usage only 14 | --host (-b) VAL : Bind host 15 | --keystorePassword VAL : Password for the keystore (default: password) 16 | --keystorePath VAL : Path to the keystore (default: classpath:/keystore/ssl.jks) 17 | --listenPort (-l) N : Listen port (default: 8080) 18 | --plugin (-p) VAL : Plugin name (e.g. rest) or fully qualified class 19 | --pluginArg VAL : A plugin argument (key=value) 20 | --serverUrl (-u) VAL : Explicitly set the server address 21 | --tlsEnabled (-t) : Whether TLS (HTTPS) is enabled (requires keystore to be configured) (default: false) 22 | --version (-v) : Print version and exit 23 | 24 | ## Server URL 25 | 26 | For some responses, such as from the [SFDC plugin](sfdc_plugin.md), Imposter uses the 'server URL', which is computed automatically from the `host` and `listenPort` command line arguments. If this is not the URL you wish to use, you can override this with the `serverUrl` command line argument. 27 | -------------------------------------------------------------------------------- /embedded/core/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'maven-publish' 3 | 4 | compileJava { 5 | sourceCompatibility = JavaVersion.VERSION_11 6 | } 7 | 8 | dependencies { 9 | api project (':core:imposter-engine') 10 | api project (':imposter-server') 11 | 12 | // test server 13 | testImplementation project(':adapter:adapter-vertxweb') 14 | 15 | // examples 16 | testImplementation project (':mock:mock-openapi') 17 | testImplementation project (':mock:mock-rest') 18 | 19 | // test 20 | testImplementation project(':test:test-utils') 21 | testImplementation project(':test:api-tests') 22 | 23 | // java 11 compatibility 24 | testImplementation ("javax.xml.bind:jaxb-api:$version_jaxb_api") 25 | } 26 | 27 | task sourcesJar(type: Jar, dependsOn: classes) { 28 | archiveClassifier = 'sources' 29 | from sourceSets.main.allSource 30 | } 31 | 32 | artifacts { 33 | archives sourcesJar 34 | } 35 | 36 | publishing { 37 | publications { 38 | maven(MavenPublication) { 39 | from components.java 40 | artifact sourcesJar 41 | 42 | repositories { 43 | maven { 44 | url = version.endsWith('SNAPSHOT') ? mavenSnapshotRepository : mavenReleaseRepository 45 | credentials(AwsCredentials) { 46 | accessKey awsAccessKey 47 | secretKey awsSecretKey 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /embedded/core/src/test/resources/config/petstore-simple-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | plugin: openapi 3 | specFile: petstore-simple.yaml 4 | -------------------------------------------------------------------------------- /embedded/openapi/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'maven-publish' 3 | 4 | compileJava { 5 | sourceCompatibility = JavaVersion.VERSION_11 6 | } 7 | 8 | dependencies { 9 | api project (':embedded:embedded-core') 10 | implementation project (':mock:mock-openapi') 11 | 12 | // test server 13 | testImplementation project(':adapter:adapter-vertxweb') 14 | 15 | // examples 16 | testImplementation project (':mock:mock-rest') 17 | 18 | // test 19 | testImplementation project(':test:test-utils') 20 | testImplementation project(':test:api-tests') 21 | 22 | // java 11 compatibility 23 | testImplementation ("javax.xml.bind:jaxb-api:$version_jaxb_api") 24 | } 25 | 26 | task sourcesJar(type: Jar, dependsOn: classes) { 27 | archiveClassifier = 'sources' 28 | from sourceSets.main.allSource 29 | } 30 | 31 | artifacts { 32 | archives sourcesJar 33 | } 34 | 35 | publishing { 36 | publications { 37 | maven(MavenPublication) { 38 | from components.java 39 | artifact sourcesJar 40 | 41 | repositories { 42 | maven { 43 | url = version.endsWith('SNAPSHOT') ? mavenSnapshotRepository : mavenReleaseRepository 44 | credentials(AwsCredentials) { 45 | accessKey awsAccessKey 46 | secretKey awsSecretKey 47 | } 48 | } 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /embedded/openapi/src/test/resources/config/petstore-simple-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | plugin: openapi 3 | specFile: petstore-simple.yaml 4 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | See [examples](https://github.com/imposter-project/examples). 2 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | projectVersion=0.0.0-SNAPSHOT 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /lib/micrometer-log4j2/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'maven-publish' 3 | 4 | compileJava { 5 | sourceCompatibility = JavaVersion.VERSION_11 6 | targetCompatibility = JavaVersion.VERSION_11 7 | } 8 | 9 | dependencies { 10 | implementation "org.apache.logging.log4j:log4j-api:$version_log4j" 11 | implementation "io.micrometer:micrometer-commons:$version_micrometer" 12 | } 13 | 14 | task sourcesJar(type: Jar, dependsOn: classes) { 15 | archiveClassifier = 'sources' 16 | from sourceSets.main.allSource 17 | } 18 | 19 | artifacts { 20 | archives sourcesJar 21 | } 22 | 23 | publishing { 24 | publications { 25 | maven(MavenPublication) { 26 | from components.java 27 | artifact sourcesJar 28 | 29 | repositories { 30 | maven { 31 | url = version.endsWith('SNAPSHOT') ? mavenSnapshotRepository : mavenReleaseRepository 32 | credentials(AwsCredentials) { 33 | accessKey awsAccessKey 34 | secretKey awsSecretKey 35 | } 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/micrometer-log4j2/src/main/java/io/micrometer/common/util/internal/logging/Log4J2LoggerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.micrometer.common.util.internal.logging; 17 | 18 | import org.apache.logging.log4j.LogManager; 19 | 20 | /** 21 | * NOTE: This file has been copied and slightly modified from 22 | * {io.netty.util.internal.logging}. 23 | *

24 | * Logger factory which creates a Log4J2 logger. 25 | */ 26 | public final class Log4J2LoggerFactory extends InternalLoggerFactory { 27 | 28 | public static final InternalLoggerFactory INSTANCE = new Log4J2LoggerFactory(); 29 | 30 | @Override 31 | public InternalLogger newInstance(String name) { 32 | return new Log4J2Logger(LogManager.getLogger(name)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mock/hbase/src/main/resources/META-INF/plugin.properties: -------------------------------------------------------------------------------- 1 | name=hbase 2 | class=io.gatehill.imposter.plugin.hbase.HBasePluginImpl 3 | load=lazy 4 | -------------------------------------------------------------------------------- /mock/hbase/src/test/resources/config/hbase-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "hbase", 3 | "tableName": "exampleTable", 4 | "prefix": "examplePrefix", 5 | "idField": "abc:id", 6 | "response": { 7 | "staticFile": "hbase-data.json" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /mock/hbase/src/test/resources/config/hbase-data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "abc:id": "row1", 4 | "abc:exampleStringC": "exampleValue1C", 5 | "abc:exampleStringA": "exampleValue1A", 6 | "abc:exampleStringB": "exampleValue1B" 7 | }, 8 | { 9 | "abc:id": "row2", 10 | "abc:exampleStringC": "exampleValue2C", 11 | "abc:exampleStringA": "exampleValue2A", 12 | "abc:exampleStringB": "exampleValue2B" 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /mock/hbase/src/test/resources/config/hbase-plugin.groovy: -------------------------------------------------------------------------------- 1 | // Example of returning a specific status code or response file, 2 | // based on the scanner filter prefix (essentially the HBase query). 3 | 4 | switch (context.responsePhase) { 5 | case io.gatehill.imposter.plugin.hbase.model.ResponsePhase.SCANNER: 6 | if ("fail".equals(context.scannerFilterPrefix)) { 7 | // HTTP Status-Code 400: Bad Request. 8 | logger.info("Matched 'fail' prefix - returning HTTP 400") 9 | respond { 10 | withStatusCode 400 11 | skipDefaultBehaviour() 12 | } 13 | } 14 | break 15 | 16 | case io.gatehill.imposter.plugin.hbase.model.ResponsePhase.RESULTS: 17 | logger.info("Returning static results using default behaviour") 18 | respond { 19 | withFile "hbase-data.json" 20 | usingDefaultBehaviour() 21 | } 22 | break 23 | } 24 | -------------------------------------------------------------------------------- /mock/hbase/src/test/resources/config/hbase-scripted-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "hbase", 3 | "tableName": "scriptedTable", 4 | "response": { 5 | "scriptFile": "hbase-plugin.groovy" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /mock/openapi/src/main/resources/META-INF/plugin.properties: -------------------------------------------------------------------------------- 1 | name=openapi 2 | class=io.gatehill.imposter.plugin.openapi.OpenApiPluginImpl 3 | load=lazy 4 | -------------------------------------------------------------------------------- /mock/openapi/src/main/resources/swagger-ui/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/mock/openapi/src/main/resources/swagger-ui/favicon-16x16.png -------------------------------------------------------------------------------- /mock/openapi/src/main/resources/swagger-ui/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/mock/openapi/src/main/resources/swagger-ui/favicon-32x32.png -------------------------------------------------------------------------------- /mock/openapi/src/main/resources/swagger-ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Imposter API Sandbox 7 | 8 | 9 | 10 | 31 | 32 | 33 | 34 |

35 | 36 | 37 | 38 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/base-path/example-swagger2.yaml: -------------------------------------------------------------------------------- 1 | swagger: "2.0" 2 | info: 3 | description: "Base path test" 4 | version: "1.0.0" 5 | title: "Base path" 6 | basePath: "/api" 7 | paths: 8 | /example: 9 | get: 10 | consumes: 11 | - "application/json" 12 | produces: 13 | - "application/json" 14 | responses: 15 | "200": 16 | description: "OK" 17 | "400": 18 | description: "Bad Request" 19 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/base-path/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: openapi 2 | specFile: "example-swagger2.yaml" 3 | validation: 4 | request: true 5 | 6 | resources: 7 | - method: GET 8 | path: "/api/example" 9 | response: 10 | content: "Invalid request." 11 | statusCode: 400 12 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/complex-path-params/behaviour.groovy: -------------------------------------------------------------------------------- 1 | if (context.request.uri ==~ /(.*)\/apis\/v1beta1\/runs\/.+\/nodes\/.+\/artifacts\/.+/) { 2 | respond() 3 | .withStatusCode(200) 4 | .withHeader('Content-Type', 'application/octet-stream') 5 | .withContent('Example artifact data') 6 | } else { 7 | logger.info("No behaviour configured for: ${context.request.uri}") 8 | } 9 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/complex-path-params/complex-path-params-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "openapi", 3 | "specFile": "kfp_api_single_file.json", 4 | "response": { 5 | "scriptFile": "behaviour.groovy" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/model-examples/model-examples-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | plugin: openapi 3 | specFile: model-examples.yaml 4 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/object-examples/object-examples.yaml: -------------------------------------------------------------------------------- 1 | swagger: "2.0" 2 | info: 3 | version: 1.0.0 4 | title: Object examples 5 | basePath: /objects 6 | schemes: 7 | - http 8 | consumes: 9 | - application/json 10 | produces: 11 | - application/json 12 | paths: 13 | /team: 14 | get: 15 | operationId: findTeam 16 | responses: 17 | "200": 18 | description: team response 19 | schema: 20 | type: object 21 | items: 22 | $ref: '#/definitions/Team' 23 | examples: 24 | application/json: 25 | id: 10 26 | name: Engineering 27 | application/x-yaml: 28 | id: 20 29 | name: Product 30 | 31 | definitions: 32 | Team: 33 | required: 34 | - id 35 | - name 36 | properties: 37 | id: 38 | type: string 39 | name: 40 | type: string 41 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/object-examples/openapi-plugin-objects-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "openapi", 3 | "specFile": "object-examples.yaml" 4 | } 5 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/scripted/custom.groovy: -------------------------------------------------------------------------------- 1 | // Example of returning a specific status code, to control which 2 | // specification example is returned in the response. 3 | 4 | logger.info("Request: ${context.request}") 5 | 6 | // checks for a particular parameter 7 | if (context.request.queryParams.param1 == 'foo') { 8 | respond { 9 | withStatusCode 202 10 | skipDefaultBehaviour() 11 | } 12 | } 13 | 14 | // applies to URIs ending with '/apis' 15 | if (context.request.uri ==~ /(.*)\/apis$/) { 16 | 17 | // applies to PUT requests only 18 | switch (context.request.method) { 19 | case 'PUT': 20 | respond { 21 | withStatusCode 201 22 | withHeader("MyHeader", "MyHeaderValue") 23 | } 24 | break 25 | 26 | case 'GET': 27 | if (context.request.headers.Authorization == "AUTH_HEADER") { 28 | respond { 29 | withStatusCode 204 30 | } 31 | } else { 32 | respond { 33 | usingDefaultBehaviour() 34 | } 35 | } 36 | break 37 | 38 | default: 39 | // fallback to specification examples 40 | respond { 41 | usingDefaultBehaviour() 42 | } 43 | break 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/scripted/scripted-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "openapi", 3 | "response": { 4 | "scriptFile": "custom.groovy" 5 | }, 6 | "specFile": "openapi2-with-examples.yaml" 7 | } 8 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/simple/openapi2-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "openapi", 3 | "specFile": "openapi2-with-examples.yaml" 4 | } 5 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/simple/openapi2-petstore-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "openapi", 3 | "specFile": "petstore-expanded.yaml" 4 | } 5 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/slash-base-path-with-host/slash-base-path-with-host-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "openapi", 3 | "specFile": "slash-base-path-with-host.yaml" 4 | } 5 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi2/slash-base-path-with-host/slash-base-path-with-host.yaml: -------------------------------------------------------------------------------- 1 | swagger: "2.0" 2 | host: 'localhost:8080' 3 | basePath: / 4 | info: 5 | version: "1.0.0" 6 | title: "Swagger Petstore" 7 | paths: 8 | /pets: 9 | get: 10 | description: "Returns all pets from the system" 11 | produces: 12 | - "application/json" 13 | responses: 14 | "200": 15 | description: "A list of pets." 16 | schema: 17 | type: "array" 18 | items: 19 | $ref: "#/definitions/Pet" 20 | examples: 21 | application/json: |- 22 | [ 23 | { 24 | "id": 101, 25 | "name": "Cat" 26 | }, 27 | { 28 | "id": 102, 29 | "name": "Dog" 30 | } 31 | ] 32 | definitions: 33 | Pet: 34 | type: "object" 35 | required: 36 | - "id" 37 | - "name" 38 | properties: 39 | id: 40 | type: "integer" 41 | format: "int64" 42 | name: 43 | type: "string" 44 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/base-path/order-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "openapi" 2 | specFile: "order-api.yaml" 3 | 4 | # custom path prefix 5 | path: /shop 6 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/base-path/pet-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "openapi" 2 | specFile: "pet-api.yaml" 3 | 4 | # custom path prefix 5 | path: /animals 6 | 7 | # ignore the server path ('/petstore') from the spec 8 | stripServerPath: true 9 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/default-response/default-response-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | plugin: openapi 3 | specFile: default-response.yaml 4 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/default-response/default-response.yaml: -------------------------------------------------------------------------------- 1 | openapi: "3.0.0" 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | servers: 8 | - url: http://petstore.swagger.io/v1 9 | paths: 10 | /pets: 11 | get: 12 | summary: List all pets 13 | operationId: listPets 14 | responses: 15 | default: 16 | description: catchall response 17 | content: 18 | application/json: 19 | schema: 20 | $ref: "#/components/schemas/DefaultResponse" 21 | 22 | components: 23 | schemas: 24 | DefaultResponse: 25 | type: object 26 | required: 27 | - code 28 | - message 29 | properties: 30 | code: 31 | type: integer 32 | format: int32 33 | message: 34 | type: string 35 | example: 36 | code: 99 37 | message: "Default response" 38 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/example-ref/test-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "openapi" 2 | specFile: "openapi3-example-ref.yaml" 3 | 4 | resources: 5 | - path: /pets/1 6 | method: get 7 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/override-status-code/override-status-code-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "openapi" 2 | specFile: "openapi3-with-multiple-status-codes.yaml" 3 | 4 | resources: 5 | - path: "/pets" 6 | method: get 7 | response: 8 | statusCode: 200 9 | 10 | - path: "/pets" 11 | method: get 12 | queryParams: 13 | foo: bar 14 | response: 15 | statusCode: 204 16 | 17 | - path: "/pets" 18 | method: get 19 | requestHeaders: 20 | X-Foo: bar 21 | response: 22 | statusCode: 205 23 | 24 | - path: "/pets" 25 | method: post 26 | response: 27 | statusCode: 201 28 | 29 | - path: "/pets/{petId}" 30 | method: get 31 | pathParams: 32 | petId: 99 33 | response: 34 | statusCode: 203 35 | 36 | - path: "/pets/{petId}" 37 | method: put 38 | response: 39 | statusCode: 202 40 | 41 | - path: "/pets/{petId}" 42 | method: put 43 | requestHeaders: 44 | # header key deliberately lowercase in config, but uppercase in request 45 | x-lowercase-test: baz 46 | response: 47 | statusCode: 409 48 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/reference-response/reference-response-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | plugin: openapi 3 | specFile: reference-response.yaml 4 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/request-validation/request-validation-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "openapi" 2 | specFile: "openapi3-request-validation.yaml" 3 | 4 | validation: 5 | request: true 6 | levels: 7 | # override the default level 8 | validation.request.parameter.query.unexpected: ERROR 9 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/scripted-named-example/named-example.groovy: -------------------------------------------------------------------------------- 1 | 2 | // Example of returning a specific example, based on the request URI. 3 | 4 | if (context.request.pathParams.petId == '1') { 5 | respond().withExampleName('catExample') 6 | 7 | } else if (context.request.pathParams.petId == '2') { 8 | respond().withExampleName('dogExample') 9 | } 10 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/scripted-named-example/scripted-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "openapi", 3 | "response": { 4 | "scriptFile": "named-example.groovy" 5 | }, 6 | "specFile": "openapi3-with-multiple-examples.yaml" 7 | } 8 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/security-schemes/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: openapi 2 | specFile: spec.yaml 3 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/simple/openapi3-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "openapi", 3 | "specFile": "openapi3-with-examples.yaml" 4 | } 5 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/spec-endpoint/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: openapi 2 | specFile: spec.yaml 3 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/spec-endpoint/spec.yaml: -------------------------------------------------------------------------------- 1 | openapi: "3.0.0" 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | paths: 8 | /pets/{petId}: 9 | get: 10 | summary: Info for a specific pet 11 | operationId: showPetById 12 | tags: 13 | - pets 14 | parameters: 15 | - name: petId 16 | in: path 17 | required: true 18 | description: The id of the pet to retrieve 19 | schema: 20 | type: string 21 | responses: 22 | '200': 23 | description: Expected response to a valid request 24 | content: 25 | application/json: 26 | schema: 27 | $ref: "#/components/schemas/Pet" 28 | components: 29 | schemas: 30 | Pet: 31 | type: object 32 | required: 33 | - id 34 | - name 35 | properties: 36 | id: 37 | type: integer 38 | format: int64 39 | name: 40 | type: string 41 | tag: 42 | type: string 43 | Pets: 44 | type: array 45 | items: 46 | $ref: "#/components/schemas/Pet" 47 | Error: 48 | type: object 49 | required: 50 | - code 51 | - message 52 | properties: 53 | code: 54 | type: integer 55 | format: int32 56 | message: 57 | type: string 58 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/static-named-example/test-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "openapi" 2 | specFile: "openapi3-with-multiple-examples.yaml" 3 | 4 | resources: 5 | - path: /pets/1 6 | method: get 7 | response: 8 | exampleName: catExample 9 | 10 | - path: /pets/2 11 | method: get 12 | response: 13 | exampleName: dogExample 14 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/undefined-resource/mock-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | plugin: openapi 3 | specFile: spec.yaml 4 | 5 | resources: 6 | - method: get 7 | path: /cats 8 | response: 9 | statusCode: 201 10 | 11 | - method: get 12 | path: /dogs 13 | response: 14 | statusCode: 202 15 | content: "Custom response" 16 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi3/undefined-resource/spec.yaml: -------------------------------------------------------------------------------- 1 | openapi: "3.0.0" 2 | info: 3 | version: 1.0.0 4 | title: Swagger Petstore 5 | license: 6 | name: MIT 7 | paths: 8 | /cats: 9 | get: 10 | summary: List all cats 11 | operationId: listCats 12 | responses: 13 | "200": 14 | description: cats response 15 | content: 16 | application/json: 17 | schema: 18 | $ref: "#/components/schemas/PetResponse" 19 | 20 | /dogs: 21 | get: 22 | summary: List all dogs 23 | operationId: listDogs 24 | responses: 25 | "200": 26 | description: dogs response 27 | content: 28 | application/json: 29 | schema: 30 | $ref: "#/components/schemas/PetResponse" 31 | 32 | components: 33 | schemas: 34 | PetResponse: 35 | type: object 36 | required: 37 | - code 38 | - message 39 | properties: 40 | code: 41 | type: integer 42 | format: int32 43 | message: 44 | type: string 45 | example: 46 | { 47 | "code": 1, 48 | "message": "Pet response" 49 | } 50 | -------------------------------------------------------------------------------- /mock/openapi/src/test/resources/openapi31/simple/mock-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | plugin: openapi 3 | specFile: openapi.yaml 4 | -------------------------------------------------------------------------------- /mock/rest/src/main/resources/META-INF/plugin.properties: -------------------------------------------------------------------------------- 1 | name=rest 2 | class=io.gatehill.imposter.plugin.rest.RestPluginImpl 3 | load=lazy 4 | -------------------------------------------------------------------------------- /mock/rest/src/test/resources/config/rest-plugin-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "rest", 3 | "contentType": "application/json", 4 | "resources": [ 5 | { 6 | "path": "/example/{id}", 7 | "type": "ARRAY", 8 | "response": { 9 | "staticFile": "rest-plugin-list-data.json" 10 | } 11 | }, 12 | { 13 | "path": "/example", 14 | "response": { 15 | "staticFile": "rest-plugin-data1.json" 16 | } 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /mock/rest/src/test/resources/config/rest-plugin-data1.json: -------------------------------------------------------------------------------- 1 | { 2 | "testKey": "testValue1" 3 | } 4 | -------------------------------------------------------------------------------- /mock/rest/src/test/resources/config/rest-plugin-data2.json: -------------------------------------------------------------------------------- 1 | { 2 | "testKey": "testValue2" 3 | } 4 | -------------------------------------------------------------------------------- /mock/rest/src/test/resources/config/rest-plugin-list-data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "aKey": "aValue1" 5 | }, 6 | { 7 | "id": "2", 8 | "aKey": "aValue2" 9 | }, 10 | { 11 | "id": "3", 12 | "aKey": "aValue3" 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /mock/rest/src/test/resources/config/rest-plugin-scripted-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "rest", 3 | "path": "/scripted", 4 | "response": { 5 | "scriptFile": "rest-plugin.groovy", 6 | "staticFile": "rest-plugin-data1.json" 7 | }, 8 | "contentType": "application/json" 9 | } 10 | -------------------------------------------------------------------------------- /mock/rest/src/test/resources/config/static-full-multi-config.yaml: -------------------------------------------------------------------------------- 1 | # Models a POST to a resource, which then redirects to a GET. 2 | --- 3 | plugin: rest 4 | resources: 5 | - path: /static-multi 6 | contentType: "text/html" 7 | method: GET 8 | response: 9 | statusCode: 200 10 | headers: 11 | X-Example: "foo" 12 | content: | 13 | 14 | 15 | Example 16 | 17 | 18 | Hello, world! 19 | 20 | 21 | 22 | - path: /static-multi 23 | method: POST 24 | response: 25 | statusCode: 302 26 | headers: 27 | Location: "/static-multi" 28 | -------------------------------------------------------------------------------- /mock/rest/src/test/resources/config/static-full-single-config.yaml: -------------------------------------------------------------------------------- 1 | # A static configuration, setting content type, headers, status code and data. 2 | --- 3 | plugin: rest 4 | path: /static-single 5 | contentType: "text/html" 6 | method: GET 7 | response: 8 | statusCode: 200 9 | headers: 10 | X-Example: "foo" 11 | content: | 12 | 13 | 14 | Example 15 | 16 | 17 | Hello, world! 18 | 19 | 20 | -------------------------------------------------------------------------------- /mock/rest/src/test/resources/form-params/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: rest 2 | 3 | resources: 4 | - method: POST 5 | path: /simple 6 | response: 7 | content: "not matched" 8 | 9 | - method: POST 10 | path: /simple 11 | formParams: 12 | example: test 13 | response: 14 | content: "matched" 15 | 16 | - method: POST 17 | path: /equalto 18 | formParams: 19 | example: 20 | value: "test" 21 | operator: EqualTo 22 | response: 23 | content: "equalto" 24 | 25 | - method: POST 26 | path: /notequalto 27 | formParams: 28 | example: 29 | value: "test" 30 | operator: NotEqualTo 31 | response: 32 | content: "notequalto" 33 | 34 | - method: POST 35 | path: /contains 36 | formParams: 37 | example: 38 | value: "es" 39 | operator: Contains 40 | response: 41 | content: "contains" 42 | 43 | - method: POST 44 | path: /notcontains 45 | formParams: 46 | example: 47 | value: "test" 48 | operator: NotContains 49 | response: 50 | content: "notcontains" 51 | 52 | - method: POST 53 | path: /matches 54 | formParams: 55 | example: 56 | value: "[a-zA-Z]+" 57 | operator: Matches 58 | response: 59 | content: "matches" 60 | 61 | - method: POST 62 | path: /notmatches 63 | formParams: 64 | example: 65 | value: "[a-zA-Z]+" 66 | operator: NotMatches 67 | response: 68 | content: "notmatches" 69 | 70 | - method: POST 71 | path: /exists 72 | formParams: 73 | example: 74 | operator: Exists 75 | response: 76 | content: "exists" 77 | 78 | - method: POST 79 | path: /notexists 80 | formParams: 81 | example: 82 | operator: NotExists 83 | response: 84 | content: "notexists" 85 | -------------------------------------------------------------------------------- /mock/rest/src/test/resources/query-params/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: rest 2 | 3 | resources: 4 | - method: POST 5 | path: /simple 6 | response: 7 | content: "not matched" 8 | 9 | - method: POST 10 | path: /simple 11 | queryParams: 12 | example: test 13 | response: 14 | content: "matched" 15 | 16 | - method: POST 17 | path: /equalto 18 | queryParams: 19 | example: 20 | value: "test" 21 | operator: EqualTo 22 | response: 23 | content: "equalto" 24 | 25 | - method: POST 26 | path: /notequalto 27 | queryParams: 28 | example: 29 | value: "test" 30 | operator: NotEqualTo 31 | response: 32 | content: "notequalto" 33 | 34 | - method: POST 35 | path: /contains 36 | queryParams: 37 | example: 38 | value: "es" 39 | operator: Contains 40 | response: 41 | content: "contains" 42 | 43 | - method: POST 44 | path: /notcontains 45 | queryParams: 46 | example: 47 | value: "test" 48 | operator: NotContains 49 | response: 50 | content: "notcontains" 51 | 52 | - method: POST 53 | path: /matches 54 | queryParams: 55 | example: 56 | value: "[a-zA-Z]+" 57 | operator: Matches 58 | response: 59 | content: "matches" 60 | 61 | - method: POST 62 | path: /notmatches 63 | queryParams: 64 | example: 65 | value: "[a-zA-Z]+" 66 | operator: NotMatches 67 | response: 68 | content: "notmatches" 69 | 70 | - method: POST 71 | path: /exists 72 | queryParams: 73 | example: 74 | operator: Exists 75 | response: 76 | content: "exists" 77 | 78 | - method: POST 79 | path: /notexists 80 | queryParams: 81 | example: 82 | operator: NotExists 83 | response: 84 | content: "notexists" 85 | -------------------------------------------------------------------------------- /mock/rest/src/test/resources/request-headers/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: rest 2 | 3 | resources: 4 | - method: POST 5 | path: /simple 6 | response: 7 | content: "not matched" 8 | 9 | - method: POST 10 | path: /simple 11 | requestHeaders: 12 | X-Example: test 13 | response: 14 | content: "matched" 15 | 16 | - method: POST 17 | path: /equalto 18 | requestHeaders: 19 | X-Example: 20 | value: "test" 21 | operator: EqualTo 22 | response: 23 | content: "equalto" 24 | 25 | - method: POST 26 | path: /notequalto 27 | requestHeaders: 28 | X-Example: 29 | value: "test" 30 | operator: NotEqualTo 31 | response: 32 | content: "notequalto" 33 | 34 | - method: POST 35 | path: /contains 36 | requestHeaders: 37 | X-Example: 38 | value: "es" 39 | operator: Contains 40 | response: 41 | content: "contains" 42 | 43 | - method: POST 44 | path: /notcontains 45 | requestHeaders: 46 | X-Example: 47 | value: "test" 48 | operator: NotContains 49 | response: 50 | content: "notcontains" 51 | 52 | - method: POST 53 | path: /matches 54 | requestHeaders: 55 | X-Example: 56 | value: "[a-zA-Z]+" 57 | operator: Matches 58 | response: 59 | content: "matches" 60 | 61 | - method: POST 62 | path: /notmatches 63 | requestHeaders: 64 | X-Example: 65 | value: "[a-zA-Z]+" 66 | operator: NotMatches 67 | response: 68 | content: "notmatches" 69 | 70 | - method: POST 71 | path: /exists 72 | requestHeaders: 73 | X-Example: 74 | operator: Exists 75 | response: 76 | content: "exists" 77 | 78 | - method: POST 79 | path: /notexists 80 | requestHeaders: 81 | X-Example: 82 | operator: NotExists 83 | response: 84 | content: "notexists" 85 | -------------------------------------------------------------------------------- /mock/sfdc/Sample.md: -------------------------------------------------------------------------------- 1 | # Samples 2 | 3 | https://developer.salesforce.com/page/Getting_Started_with_the_Force.com_REST_API 4 | -------------------------------------------------------------------------------- /mock/sfdc/src/main/resources/META-INF/plugin.properties: -------------------------------------------------------------------------------- 1 | name=sfdc 2 | class=io.gatehill.imposter.plugin.sfdc.SfdcPluginImpl 3 | load=lazy 4 | -------------------------------------------------------------------------------- /mock/sfdc/src/test/resources/config/sfdc-plugin-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "sfdc", 3 | "response": { 4 | "staticFile": "sfdc-plugin-data.json" 5 | }, 6 | "sObjectName": "Account" 7 | } 8 | -------------------------------------------------------------------------------- /mock/sfdc/src/test/resources/config/sfdc-plugin-data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Id": "0015000000VALDtAAP", 4 | "Name": "GenePoint" 5 | }, 6 | { 7 | "Id": "0015000000XALDuAAZ", 8 | "Name": "United Oil & Gas, UK" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /mock/sfdc/src/test/resources/keystore/ssl.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/mock/sfdc/src/test/resources/keystore/ssl.jks -------------------------------------------------------------------------------- /mock/soap/src/main/java/io/gatehill/imposter/plugin/soap/parser/WsdlRelativeXsdEntityResolver.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.plugin.soap.parser 2 | 3 | import org.apache.logging.log4j.LogManager 4 | import org.apache.logging.log4j.Logger 5 | import org.xml.sax.EntityResolver 6 | import org.xml.sax.InputSource 7 | import java.io.File 8 | import java.io.FileInputStream 9 | import java.nio.file.Files 10 | 11 | /** 12 | * EntityResolver to resolve XSDs included relative to the WSDL file. 13 | */ 14 | class WsdlRelativeXsdEntityResolver( 15 | private val wsdlDir: File 16 | ) : EntityResolver { 17 | private val logger: Logger = LogManager.getLogger(this::class.java) 18 | 19 | override fun resolveEntity(publicId: String?, systemId: String?): InputSource? { 20 | logger.trace("Resolve {} relative to path {}", systemId, wsdlDir) 21 | systemId ?: return null 22 | 23 | // in certain occasions, XMLBeans prefixes the systemId (see StscState) -> strip it off 24 | val xsdFile = File(wsdlDir.absoluteFile, systemId.replace("project://local/", "")) 25 | if (Files.isRegularFile(xsdFile.toPath()) && xsdFile.name.lowercase().endsWith(".xsd")) { 26 | logger.debug("Resolved XSD {} relative to WSDL path", xsdFile) 27 | 28 | // according to the InputSource docs, the parser using this resolver 29 | // should manage the clean-up of the stream. 30 | return InputSource(FileInputStream(xsdFile)) 31 | } 32 | return null 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mock/soap/src/main/resources/META-INF/plugin.properties: -------------------------------------------------------------------------------- 1 | name=soap 2 | class=io.gatehill.imposter.plugin.soap.SoapPluginImpl 3 | load=lazy 4 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/fault-example/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetById 7 | response: 8 | statusCode: 500 9 | 10 | - binding: SoapBinding 11 | operation: getPetById 12 | requestBody: 13 | xPath: //pets:id 14 | value: 2 15 | response: 16 | statusCode: 500 17 | content: | 18 | 19 | 20 | 21 | 2 22 | Custom fault 23 | 24 | 25 | 26 | 27 | - binding: SoapBinding 28 | operation: getPetById 29 | requestBody: 30 | xPath: //pets:id 31 | value: 99 32 | response: 33 | soapFault: true 34 | 35 | - binding: SoapBinding 36 | operation: getPetById 37 | requestBody: 38 | xPath: //pets:id 39 | value: 100 40 | steps: 41 | - type: script 42 | code: respond().withSoapFault() 43 | 44 | system: 45 | xmlNamespaces: 46 | pets: "urn:com:example:petstore" 47 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/no-envelope/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | # don't wrap request/response in a SOAP envelope 5 | envelope: false 6 | 7 | resources: 8 | - binding: SoapBinding 9 | operation: getPetById 10 | response: 11 | template: true 12 | content: | 13 | 14 | 3 15 | Paws 16 | 17 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/request-body-match/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetById 7 | requestBody: 8 | xPath: "/env:Envelope/env:Body/pets:getPetByIdRequest/pets:id" 9 | value: "10" 10 | xmlNamespaces: 11 | env: "http://www.w3.org/2003/05/soap-envelope" 12 | pets: "urn:com:example:petstore" 13 | response: 14 | content: | 15 | 16 | 17 | 18 | 19 | 20 | 10 21 | Whiskers 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/template-response/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetById 7 | response: 8 | # use the value of 'id' from the request message in the response 9 | template: true 10 | content: | 11 | 12 | 13 | 14 | 15 | 16 | ${context.request.body:!/Envelope/Body/getPetByIdRequest/id} 17 | Paws 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-composite-message/getPetByNameResponse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 3 8 | Fluffy 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-composite-message/test-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetByName 7 | response: 8 | file: getPetByNameResponse.xml 9 | 10 | - binding: HttpBinding 11 | operation: getPetByName 12 | response: 13 | file: getPetByNameResponse.xml 14 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-document-bare/getPetByNameResponse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 3 7 | Fluffy 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-document-bare/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetByName 7 | response: 8 | file: getPetByNameResponse.xml 9 | 10 | - binding: HttpBinding 11 | operation: getPetByName 12 | response: 13 | file: getPetByNameResponse.xml 14 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-document-bare/schema.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-document-wrapped/getPetByNameResponse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 3 7 | Fluffy 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-document-wrapped/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetByName 7 | response: 8 | file: getPetByNameResponse.xml 9 | 10 | - binding: HttpBinding 11 | operation: getPetByName 12 | response: 13 | file: getPetByNameResponse.xml 14 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-filter-message-parts/getPetByNameResponse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 3 7 | Fluffy 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-filter-message-parts/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetByName 7 | response: 8 | file: getPetByNameResponse.xml 9 | 10 | - binding: HttpBinding 11 | operation: getPetByName 12 | response: 13 | file: getPetByNameResponse.xml 14 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-rpc/getPetByNameResponse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 3 8 | Fluffy 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-rpc/test-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetByName 7 | response: 8 | file: getPetByNameResponse.xml 9 | 10 | - binding: HttpBinding 11 | operation: getPetByName 12 | response: 13 | file: getPetByNameResponse.xml 14 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-xsd-import-include/PetService/schema-include.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-xsd-import-include/getPetByNameResponse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 3 7 | Fluffy 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-xsd-import-include/import/import.xsd: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-xsd-import-include/import/schema-import.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-xsd-import-include/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: PetService/service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetByName 7 | response: 8 | file: getPetByNameResponse.xml 9 | 10 | - binding: HttpBinding 11 | operation: getPetByName 12 | response: 13 | file: getPetByNameResponse.xml 14 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap11-xsd-import-include/include/include.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap12/getPetByNameResponse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 3 7 | Fluffy 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap12/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetByName 7 | response: 8 | file: getPetByNameResponse.xml 9 | 10 | - binding: HttpBinding 11 | operation: getPetByName 12 | response: 13 | file: getPetByNameResponse.xml 14 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl1-soap12/schema.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl2-soap12/getPetByNameResponse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 3 7 | Fluffy 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl2-soap12/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: soap 2 | wsdlFile: service.wsdl 3 | 4 | resources: 5 | - binding: SoapBinding 6 | operation: getPetByName 7 | response: 8 | file: getPetByNameResponse.xml 9 | 10 | - binding: HttpBinding 11 | operation: getPetByName 12 | response: 13 | file: getPetByNameResponse.xml 14 | -------------------------------------------------------------------------------- /mock/soap/src/test/resources/wsdl2-soap12/schema.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /mock/wiremock/src/main/resources/META-INF/plugin.properties: -------------------------------------------------------------------------------- 1 | name=wiremock 2 | class=io.gatehill.imposter.plugin.wiremock.WiremockPluginImpl 3 | load=lazy 4 | -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-nowrap/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: wiremock 2 | -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-nowrap/mappings/mappings.json: -------------------------------------------------------------------------------- 1 | { 2 | "request": { 3 | "method": "GET", 4 | "url": "/example", 5 | "headers": { 6 | "content-type": { 7 | "equalTo": "application/json" 8 | } 9 | }, 10 | "bodyPatterns": [] 11 | }, 12 | "response": { 13 | "status": 200, 14 | "headers": { 15 | "content-type": "application/json" 16 | }, 17 | "transformers": [] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-simple/__files/response.json: -------------------------------------------------------------------------------- 1 | { "id": 2, "name": "Dog" } -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-simple/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: wiremock 2 | -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-simple/mappings/mappings1.json: -------------------------------------------------------------------------------- 1 | { 2 | "mappings": [ 3 | { 4 | "request": { 5 | "method": "GET", 6 | "url": "/example1", 7 | "headers": { 8 | "accept": { 9 | "equalTo": "application/json" 10 | } 11 | }, 12 | "bodyPatterns": [] 13 | }, 14 | "response": { 15 | "status": 200, 16 | "headers": { 17 | "content-type": "application/json" 18 | }, 19 | "transformers": [], 20 | "bodyFileName": "response.json" 21 | } 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-simple/mappings/mappings2.json: -------------------------------------------------------------------------------- 1 | { 2 | "mappings": [ 3 | { 4 | "request": { 5 | "method": "GET", 6 | "url": "/example2", 7 | "headers": { 8 | "accept": { 9 | "equalTo": "application/json" 10 | } 11 | }, 12 | "bodyPatterns": [] 13 | }, 14 | "response": { 15 | "status": 200 16 | } 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-templated/__files/response.xml: -------------------------------------------------------------------------------- 1 | 2 | {{xPath request.body '//getPetByIdRequest/id'}} 3 | Fluffy 4 | {{randomValue length=5 type='ALPHABETIC' uppercase=true}} 5 | 6 | -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-templated/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: wiremock 2 | -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-templated/mappings/mappings.json: -------------------------------------------------------------------------------- 1 | { 2 | "mappings": [ 3 | { 4 | "request": { 5 | "method": "GET", 6 | "url": "/example", 7 | "headers": { 8 | "content-type": { 9 | "equalTo": "application/json" 10 | } 11 | }, 12 | "bodyPatterns": [] 13 | }, 14 | "response": { 15 | "status": 200, 16 | "headers": { 17 | "content-type": "application/json" 18 | }, 19 | "transformers": [ 20 | "response-template" 21 | ], 22 | "bodyFileName": "response.xml" 23 | } 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-xpath-request/mappings/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: wiremock 2 | -------------------------------------------------------------------------------- /mock/wiremock/src/test/resources/wiremock-xpath-request/mappings/mappings/mappings.json: -------------------------------------------------------------------------------- 1 | { 2 | "mappings": [ 3 | { 4 | "request": { 5 | "method": "POST", 6 | "url": "/example", 7 | "headers": { 8 | "content-type": { 9 | "equalTo": "application/json" 10 | } 11 | }, 12 | "bodyPatterns": [ 13 | { 14 | "matchesXPath": "/foo:bar[./foo:baz='1']", 15 | "xPathNamespaces": { 16 | "foo": "http://example.com/namespaces/foo" 17 | } 18 | }, 19 | { 20 | "matchesXPath" : { 21 | "expression": "//username/text()", 22 | "contains": "alice" 23 | } 24 | } 25 | ] 26 | }, 27 | "response": { 28 | "status": 201 29 | } 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /scripting/common/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /scripting/graalvm/README.md: -------------------------------------------------------------------------------- 1 | GraalVM scripting implementation 2 | ================================ 3 | 4 | Nashorn, the provider of JavaScript scripting support is deprecated as of Java 11. 5 | 6 | The GraalVM implementation is intended to eventually replace the Nashorn implementation. 7 | -------------------------------------------------------------------------------- /scripting/graalvm/src/test/resources/script/additional_context_properties.js: -------------------------------------------------------------------------------- 1 | const parent = context.additional; 2 | console.log('parent', parent); 3 | console.log('parent json', JSON.stringify(parent)); 4 | console.log('parent keys', Object.keys(parent)); 5 | console.log('parent name', parent.name); 6 | 7 | const child = parent.child; 8 | console.log('child', child); 9 | console.log('child json', JSON.stringify(child)); 10 | console.log('child keys', Object.keys(child)); 11 | console.log('child name', child.name); 12 | 13 | respond().withContent(parent.name + ' ' + child.name); 14 | -------------------------------------------------------------------------------- /scripting/graalvm/src/test/resources/script/context_properties.js: -------------------------------------------------------------------------------- 1 | const echo = `request.method=${context.request.method} 2 | request.method.json=${JSON.stringify(context.request.method)} 3 | request.path=${context.request.path} 4 | request.queryParams=${JSON.stringify(context.request.queryParams)} 5 | request.pathParams=${JSON.stringify(context.request.pathParams)} 6 | request.headers=${JSON.stringify(context.request.headers)} 7 | request.formParams=${JSON.stringify(context.request.formParams)} 8 | ` 9 | 10 | respond().withContent(echo); 11 | -------------------------------------------------------------------------------- /scripting/graalvm/src/test/resources/script/context_properties_compat.js: -------------------------------------------------------------------------------- 1 | let echo = `request.method=${context.request.method}` 2 | echo += `\nrequest.method.json=${JSON.stringify(context.request.method)}` 3 | echo += `\nrequest.path=${context.request.path}` 4 | 5 | echo += `\nrequest.queryParams=${JSON.stringify(context.request.queryParams)}` 6 | echo += `\nrequest.pathParams=${JSON.stringify(context.request.pathParams)}` 7 | 8 | const header = context.request.headers['corge'] 9 | echo += `\nrequest.headers={"corge":"${header}"}` 10 | echo += `\nrequest.formParams=${JSON.stringify(context.request.formParams)}` 11 | 12 | respond().withContent(echo); 13 | -------------------------------------------------------------------------------- /scripting/graalvm/src/test/resources/script/require_types.js: -------------------------------------------------------------------------------- 1 | const {context, respond} = require("@imposter-js/types"); 2 | 3 | const exampleHeader = context.request.headers['X-Example']; 4 | 5 | respond() 6 | .withStatusCode(201) 7 | .withContent(exampleHeader); 8 | -------------------------------------------------------------------------------- /scripting/graalvm/src/test/resources/script/store_json.js: -------------------------------------------------------------------------------- 1 | const store = stores.open('test'); 2 | 3 | // this should return a proxied array of proxied object elements 4 | const example = store.load('example'); 5 | 6 | // length should be accurate 7 | if (example.length !== 2) { 8 | throw new Error(`Invalid store item length: ${example.length}`); 9 | } 10 | 11 | // spread should work 12 | const items = [...example]; 13 | items.push({ name: 'baz' }); 14 | 15 | let names = '' 16 | 17 | // traversing as an array of objects should work 18 | for (const item of items) { 19 | names += item.name + ","; 20 | } 21 | 22 | // JSON serialisation should work 23 | const response = JSON.stringify(items); 24 | 25 | respond() 26 | .withHeader('items', names) 27 | .withContent(response); 28 | -------------------------------------------------------------------------------- /scripting/graalvm/src/test/resources/script/test.js: -------------------------------------------------------------------------------- 1 | logger.info(`context: ${context}`); 2 | console.log('JS console is available'); 3 | 4 | const request = context.request; 5 | 6 | if (request.pathParams.qux) { 7 | // echo the value of the 'qux' path parameter as a response header 8 | respond() 9 | .withStatusCode(203) 10 | .withHeader('X-Echo-Qux', request.pathParams.qux); 11 | 12 | } else if (request.queryParams.foo) { 13 | // echo the value of the 'foo' request parameter as a response header 14 | respond() 15 | .withStatusCode(200) 16 | .withHeader('X-Echo-Foo', request.queryParams.foo); 17 | 18 | } else if (request.headers.baz) { 19 | // echo the value of the 'baz' request header as a response header 20 | respond() 21 | .withStatusCode(202) 22 | .withHeader('X-Echo-Baz', request.headers.baz); 23 | 24 | } else if (request.normalisedHeaders.corge) { 25 | // echo the value of the 'corge' request header as a response header 26 | // note: the key is lowercase in normalisedHeaders, regardless of the request header casing 27 | respond() 28 | .withStatusCode(202) 29 | .withHeader('X-Echo-Corge', request.normalisedHeaders.corge); 30 | 31 | } else if (env.example) { 32 | // echo the value of the 'example' environment variable as a response header 33 | respond() 34 | .withStatusCode(204) 35 | .withHeader('X-Echo-Env-Var', env.example); 36 | 37 | } else { 38 | // check bound variable 39 | if (hello === 'world') { 40 | // respond with status code and file 41 | respond() 42 | .withStatusCode(201).and() 43 | .withFile('foo.bar') 44 | .withHeader('MyHeader', 'AwesomeHeader') 45 | .skipDefaultBehaviour(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /scripting/groovy/src/main/java/io/gatehill/imposter/scripting/groovy/impl/GroovyDsl.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.scripting.groovy.impl 2 | 3 | import groovy.lang.Closure 4 | import groovy.lang.Script 5 | import io.gatehill.imposter.script.MutableResponseBehaviour 6 | import io.gatehill.imposter.script.dsl.Dsl 7 | import io.gatehill.imposter.script.dsl.DslImpl 8 | import io.gatehill.imposter.scripting.groovy.util.ScriptLoader 9 | import java.nio.file.Path 10 | 11 | abstract class GroovyDsl : Script(), Dsl { 12 | private val dsl = DslImpl() 13 | 14 | override val responseBehaviour 15 | get() = dsl.responseBehaviour 16 | 17 | override fun respond() = dsl.respond() 18 | 19 | /** 20 | * Syntactic sugar that executes the Runnable immediately. 21 | * 22 | * @return `this` 23 | */ 24 | fun respond(closure: Closure<*>): MutableResponseBehaviour { 25 | closure.delegate = dsl.responseBehaviour 26 | closure.call() 27 | return respond() 28 | } 29 | 30 | fun loadDynamic(relativePath: String): Any { 31 | val thisScriptPath = super.getProperty(ScriptLoader.contextKeyScriptPath) as Path 32 | return ScriptLoader.loadDynamic(thisScriptPath, relativePath) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /scripting/groovy/src/test/resources/script/closure.groovy: -------------------------------------------------------------------------------- 1 | respond { 2 | withContent('closure') 3 | withStatusCode(201) 4 | } 5 | -------------------------------------------------------------------------------- /scripting/groovy/src/test/resources/script/context_properties.groovy: -------------------------------------------------------------------------------- 1 | import groovy.json.JsonOutput 2 | 3 | def echo = """request.method=${context.request.method} 4 | request.method.json=${JsonOutput.toJson(context.request.method)} 5 | request.path=${context.request.path} 6 | request.queryParams=${JsonOutput.toJson(context.request.queryParams)} 7 | request.pathParams=${JsonOutput.toJson(context.request.pathParams)} 8 | request.headers=${JsonOutput.toJson(context.request.headers)} 9 | request.formParams=${JsonOutput.toJson(context.request.formParams)} 10 | """ 11 | 12 | respond().withContent(echo); 13 | -------------------------------------------------------------------------------- /scripting/groovy/src/test/resources/script/entrypoint.groovy: -------------------------------------------------------------------------------- 1 | def included = loadDynamic('included.groovy') 2 | respond().withStatusCode(included.getStatusCode()) 3 | -------------------------------------------------------------------------------- /scripting/groovy/src/test/resources/script/included.groovy: -------------------------------------------------------------------------------- 1 | // this file is included from 'entrypoint.groovy' 2 | 3 | int getStatusCode() { 4 | return 201 5 | } 6 | -------------------------------------------------------------------------------- /scripting/groovy/src/test/resources/script/json-parse.groovy: -------------------------------------------------------------------------------- 1 | def parser = new groovy.json.JsonSlurper() 2 | def json = parser.parseText(context.request.body) 3 | 4 | respond().withContent(json.hello) 5 | -------------------------------------------------------------------------------- /scripting/groovy/src/test/resources/script/test.groovy: -------------------------------------------------------------------------------- 1 | logger.info("context: $context") 2 | 3 | def request = context.request 4 | 5 | if (request.pathParams.qux) { 6 | // echo the value of the 'qux' path parameter as a response header 7 | respond() 8 | .withStatusCode(203) 9 | .withHeader('X-Echo-Qux', request.pathParams.qux) 10 | 11 | } else if (request.queryParams.foo) { 12 | // echo the value of the 'foo' query parameter as a response header 13 | respond() 14 | .withStatusCode(200) 15 | .withHeader('X-Echo-Foo', request.queryParams.foo) 16 | 17 | } else if (request.headers.baz) { 18 | // echo the value of the 'baz' request header as a response header 19 | respond() 20 | .withStatusCode(202) 21 | .withHeader('X-Echo-Baz', request.headers.baz) 22 | 23 | } else if (request.normalisedHeaders.corge) { 24 | // echo the value of the 'corge' request header as a response header 25 | // note: the key is lowercase in normalisedHeaders, regardless of the request header casing 26 | respond() 27 | .withStatusCode(202) 28 | .withHeader('X-Echo-Corge', request.normalisedHeaders.corge) 29 | 30 | } else if (env.example) { 31 | // echo the value of the 'example' environment variable as a response header 32 | respond() 33 | .withStatusCode(204) 34 | .withHeader('X-Echo-Env-Var', env.example); 35 | 36 | } else { 37 | // check bound variable 38 | if (hello == 'world') { 39 | // respond with status code and file 40 | respond() 41 | .withStatusCode(201).and() 42 | .withFile("foo.bar") 43 | .withHeader("MyHeader", "AwesomeHeader") 44 | .skipDefaultBehaviour() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /scripting/nashorn/src/test/resources/script/context_properties.js: -------------------------------------------------------------------------------- 1 | var echo = 'request.method=' + context.request.method 2 | echo += '\nrequest.method.json=' + JSON.stringify(context.request.method) 3 | echo += '\nrequest.path=' + context.request.path 4 | 5 | echo += '\nrequest.queryParams={}' 6 | echo += '\nrequest.pathParams={}' 7 | 8 | var header = context.request.headers.corge 9 | echo += '\nrequest.headers={"corge":"' + header + '"}' 10 | echo += '\nrequest.formParams={}' 11 | 12 | respond().withContent(echo); 13 | -------------------------------------------------------------------------------- /scripting/nashorn/src/test/resources/script/require_types.js: -------------------------------------------------------------------------------- 1 | var imposter = require("@imposter-js/types"); 2 | var context = imposter.context; 3 | var respond = imposter.respond; 4 | 5 | var exampleHeader = context.request.headers['X-Example']; 6 | 7 | respond() 8 | .withStatusCode(201) 9 | .withContent(exampleHeader); 10 | -------------------------------------------------------------------------------- /scripting/nashorn/src/test/resources/script/test.js: -------------------------------------------------------------------------------- 1 | logger.info('context: ' + context); 2 | console.log('JS console is available'); 3 | 4 | var request = context.request; 5 | 6 | if (request.pathParams.qux) { 7 | // echo the value of the 'qux' path parameter as a response header 8 | respond() 9 | .withStatusCode(203) 10 | .withHeader('X-Echo-Qux', request.pathParams.qux); 11 | 12 | } else if (request.queryParams.foo) { 13 | // echo the value of the 'foo' request parameter as a response header 14 | respond() 15 | .withStatusCode(200) 16 | .withHeader('X-Echo-Foo', request.queryParams.foo); 17 | 18 | } else if (request.headers.baz) { 19 | // echo the value of the 'baz' request header as a response header 20 | respond() 21 | .withStatusCode(202) 22 | .withHeader('X-Echo-Baz', request.headers.baz); 23 | 24 | } else if (request.normalisedHeaders.corge) { 25 | // echo the value of the 'corge' request header as a response header 26 | // note: the key is lowercase in normalisedHeaders, regardless of the request header casing 27 | respond() 28 | .withStatusCode(202) 29 | .withHeader('X-Echo-Corge', request.normalisedHeaders.corge); 30 | 31 | } else if (env.example) { 32 | // echo the value of the 'example' environment variable as a response header 33 | respond() 34 | .withStatusCode(204) 35 | .withHeader('X-Echo-Env-Var', env.example); 36 | 37 | } else { 38 | // check bound variable 39 | if (hello === 'world') { 40 | // respond with status code and file 41 | respond() 42 | .withStatusCode(201).and() 43 | .withFile('foo.bar') 44 | .withHeader('MyHeader', 'AwesomeHeader') 45 | .skipDefaultBehaviour(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /scripts/get-effective-branch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | CURRENT_BRANCH="$( git branch --show-current )" 5 | 6 | if [[ "$CURRENT_BRANCH" == "develop" || "$CURRENT_BRANCH" == "main" ]]; then 7 | EFFECTIVE_BRANCH_NAME="$CURRENT_BRANCH" 8 | 9 | else 10 | case "$( since project version --current --log-level=info )" in 11 | v4.*) 12 | EFFECTIVE_BRANCH_NAME="main" 13 | ;; 14 | v3.*) 15 | EFFECTIVE_BRANCH_NAME="release/3.x" 16 | ;; 17 | *) 18 | EFFECTIVE_BRANCH_NAME="dev" 19 | ;; 20 | esac 21 | fi 22 | 23 | echo "$EFFECTIVE_BRANCH_NAME" 24 | -------------------------------------------------------------------------------- /scripts/get-version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | ROOT_DIR="${SCRIPT_DIR}/../" 6 | 7 | cat "${ROOT_DIR}/gradle.properties" | grep projectVersion | sed 's/projectVersion=//g' 8 | -------------------------------------------------------------------------------- /scripts/release-current.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | ROOT_DIR="${SCRIPT_DIR}/../" 6 | CONFIRMATION="" 7 | 8 | while getopts "y" OPT; do 9 | case ${OPT} in 10 | y) CONFIRMATION="y" 11 | ;; 12 | esac 13 | done 14 | shift $((OPTIND-1)) 15 | 16 | cd ${ROOT_DIR} 17 | CURRENT_VERSION="$( git describe --tags --exact-match )" 18 | 19 | if [[ "${CURRENT_VERSION:0:1}" == "v" ]]; then 20 | CURRENT_VERSION="$( echo ${CURRENT_VERSION} | cut -c 2- )" 21 | fi 22 | 23 | if [[ -z "${CONFIRMATION}" ]]; then 24 | read -p "Ready to release version ${CURRENT_VERSION} (y/N)?" CONFIRMATION 25 | fi 26 | if [[ "y" != "${CONFIRMATION}" ]]; then 27 | exit 1 28 | fi 29 | 30 | echo -e "\nBuilding distribution" 31 | cd ${ROOT_DIR} 32 | ./gradlew clean test dist publish 33 | 34 | echo -e "\nPackaging and pushing" 35 | cd ${SCRIPT_DIR} 36 | ./docker-build.sh -p true ${CURRENT_VERSION} 37 | -------------------------------------------------------------------------------- /scripts/release-trigger.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | CURRENT_VERSION="$( git describe --tags --exact-match || true )" 6 | 7 | if [[ "${CURRENT_VERSION:0:1}" != "v" ]]; then 8 | echo "No release tag detected" 9 | exit 10 | fi 11 | 12 | echo "Detected release tag: ${CURRENT_VERSION}" 13 | pushd ${SCRIPT_DIR} 14 | 15 | ./release-current.sh -y 16 | -------------------------------------------------------------------------------- /server/src/main/resources/keystore/ssl.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imposter-project/imposter-jvm-engine/ced54315c390fccadc62efa68fee617c54032eba/server/src/main/resources/keystore/ssl.jks -------------------------------------------------------------------------------- /server/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /server/src/test/resources/capture/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Alice", 3 | "address": { 4 | "street": "1 Main Street", 5 | "postCode": "PO5 7CO" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/src/test/resources/cors/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - method: POST 5 | path: /example 6 | response: 7 | statusCode: 200 8 | 9 | cors: 10 | # permits all origins, echoing back the origin of the request 11 | allowOrigins: all 12 | -------------------------------------------------------------------------------- /server/src/test/resources/deprecated-response-config/example.groovy: -------------------------------------------------------------------------------- 1 | 2 | // legacy 'withData' replaced by 'withContent' 3 | respond().withData('Hello script') 4 | -------------------------------------------------------------------------------- /server/src/test/resources/deprecated-response-config/example.txt: -------------------------------------------------------------------------------- 1 | Hello file -------------------------------------------------------------------------------- /server/src/test/resources/deprecated-response-config/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - method: GET 5 | path: /legacy-content 6 | response: 7 | # legacy 'staticData' replaced by 'content' 8 | staticData: "Hello content" 9 | 10 | - method: GET 11 | path: /legacy-file 12 | response: 13 | # legacy 'staticFile' replaced by 'file' 14 | staticFile: "example.txt" 15 | 16 | - method: GET 17 | path: /legacy-script 18 | response: 19 | scriptFile: "example.groovy" 20 | -------------------------------------------------------------------------------- /server/src/test/resources/failure-simulation/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - method: GET 5 | path: /static-failure-empty 6 | response: 7 | fail: EmptyResponse 8 | 9 | - method: GET 10 | path: /static-failure-close 11 | response: 12 | fail: CloseConnection 13 | -------------------------------------------------------------------------------- /server/src/test/resources/inherit-root-response-config/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | # root response config should be inherited 4 | defaultsFromRootResponse: true 5 | 6 | response: 7 | headers: 8 | X-Always-Present: Yes 9 | 10 | resources: 11 | - method: GET 12 | path: /example 13 | response: 14 | content: "Hello world" 15 | -------------------------------------------------------------------------------- /server/src/test/resources/inline-script-eval/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | # eval match 5 | - path: / 6 | method: GET 7 | eval: | 8 | context.request.queryParams.foo == "bar" 9 | response: 10 | content: "Eval match" 11 | 12 | # default match 13 | - path: / 14 | method: GET 15 | response: 16 | content: "Default match" 17 | -------------------------------------------------------------------------------- /server/src/test/resources/interceptor/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | interceptors: 4 | - path: /short-circuit 5 | requestHeaders: 6 | User-Agent: foo 7 | response: 8 | statusCode: 400 9 | content: "shortcircuit" 10 | 11 | - path: /pass-through 12 | continue: true 13 | steps: 14 | - type: script 15 | code: | 16 | var req = stores.open("request"); 17 | req.save("response", "passthrough"); 18 | 19 | resources: 20 | - path: /* 21 | method: GET 22 | response: 23 | content: "${stores.request.response:-default}" 24 | template: true 25 | -------------------------------------------------------------------------------- /server/src/test/resources/kebab-case-params/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - path: /{first-param}/{second-param} 5 | method: GET 6 | steps: 7 | - type: script 8 | code: | 9 | if (context.request.pathParams['first-param'] === "foo") { 10 | respond().withStatusCode(201); 11 | } 12 | response: 13 | template: true 14 | content: "${context.request.pathParams.second-param}" 15 | 16 | - path: /{first-param} 17 | method: GET 18 | pathParams: 19 | first-param: baz 20 | response: 21 | template: true 22 | content: "${context.request.pathParams.first-param}" 23 | -------------------------------------------------------------------------------- /server/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /server/src/test/resources/performance-simulation/delay.js: -------------------------------------------------------------------------------- 1 | 2 | switch (context.request.path) { 3 | case '/scripted-exact-delay': 4 | respond() 5 | .withStatusCode(200) 6 | .withContent('Belated hello') 7 | .withDelay(500); 8 | 9 | break; 10 | 11 | case '/scripted-range-delay': 12 | respond() 13 | .withStatusCode(200) 14 | .withContent('Belated hello') 15 | .withDelayRange(200, 400); 16 | 17 | break; 18 | } 19 | -------------------------------------------------------------------------------- /server/src/test/resources/performance-simulation/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - method: GET 5 | path: /static-exact-delay 6 | response: 7 | content: "Belated hello" 8 | 9 | # delay 500ms before responding 10 | delay: 11 | exact: 500 12 | 13 | - method: GET 14 | path: /static-range-delay 15 | response: 16 | content: "Belated hello" 17 | 18 | # delay 500ms before responding 19 | delay: 20 | min: 200 21 | max: 400 22 | 23 | - method: GET 24 | path: /scripted-exact-delay 25 | response: 26 | scriptFile: delay.js 27 | 28 | - method: GET 29 | path: /scripted-range-delay 30 | response: 31 | scriptFile: delay.js 32 | -------------------------------------------------------------------------------- /server/src/test/resources/prefer-exact-path/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | # Path with placeholder 5 | - method: GET 6 | path: /users/{userId} 7 | response: 8 | content: "alice" 9 | 10 | # Path with exact match; should take precedence 11 | - method: GET 12 | path: /users/names 13 | response: 14 | content: "names" 15 | -------------------------------------------------------------------------------- /server/src/test/resources/request-matching/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | # Vert.x style path parameter 5 | - method: GET 6 | path: /users/:userId 7 | pathParams: 8 | userId: 1 9 | response: 10 | statusCode: 204 11 | 12 | # OpenAPI style path parameter 13 | - method: GET 14 | path: /orders/{orderId} 15 | pathParams: 16 | orderId: 99 17 | response: 18 | statusCode: 203 19 | 20 | # No method specified - match path only 21 | - path: /example 22 | response: 23 | statusCode: 202 24 | -------------------------------------------------------------------------------- /server/src/test/resources/reserved-chars-in-path/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - method: GET 5 | path: /example/foo:{bar} 6 | response: 7 | content: "baz" 8 | -------------------------------------------------------------------------------- /server/src/test/resources/response-template/jsonPathTemplate.txt: -------------------------------------------------------------------------------- 1 | Postcode: ${stores.templateTest.address:$.postCode} -------------------------------------------------------------------------------- /server/src/test/resources/response-template/petTemplate.txt: -------------------------------------------------------------------------------- 1 | Pet ID: ${stores.request.petId} -------------------------------------------------------------------------------- /server/src/test/resources/response-template/simpleTemplate.txt: -------------------------------------------------------------------------------- 1 | Hello ${stores.templateTest.foo}! -------------------------------------------------------------------------------- /server/src/test/resources/response-template/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - method: GET 5 | path: /example 6 | response: 7 | file: simpleTemplate.txt 8 | template: true 9 | 10 | - method: GET 11 | path: /example-inline 12 | contentType: "text/plain" 13 | response: 14 | content: "Inline ${stores.templateTest.foo-inline}" 15 | template: true 16 | 17 | - method: PUT 18 | path: /pets/{petId} 19 | capture: 20 | petId: 21 | pathParam: petId 22 | store: request 23 | response: 24 | file: petTemplate.txt 25 | template: true 26 | 27 | - method: POST 28 | path: /users 29 | capture: 30 | address: 31 | jsonPath: $.address 32 | store: templateTest 33 | response: 34 | file: jsonPathTemplate.txt 35 | template: true 36 | 37 | - method: GET 38 | path: /greeting/{name} 39 | # no capture configuration 40 | response: 41 | content: | 42 | Hello ${context.request.pathParams.name}! 43 | template: true 44 | headers: 45 | Content-Type: text/plain 46 | 47 | - method: GET 48 | path: /fallback 49 | # no capture configuration 50 | response: 51 | content: "${context.request.pathParams.nonexistent:-fallback}" 52 | template: true 53 | headers: 54 | Content-Type: text/plain 55 | -------------------------------------------------------------------------------- /server/src/test/resources/response-template/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Alice", 3 | "address": { 4 | "street": "1 Main Street", 5 | "postCode": "PO5 7CO" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/src/test/resources/security-config-query-params/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | path: /example 4 | response: 5 | content: "Hello" 6 | 7 | security: 8 | # no requests permitted by default 9 | default: Deny 10 | 11 | # only requests meeting these conditions are permitted 12 | conditions: 13 | - effect: Permit 14 | queryParams: 15 | apiKey: s3cr3t 16 | 17 | - effect: Deny 18 | queryParams: 19 | userKey: 20 | value: opensesame 21 | operator: NotEqualTo 22 | -------------------------------------------------------------------------------- /server/src/test/resources/security-config-regex/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | security: 4 | # no requests permitted by default 5 | default: Deny 6 | 7 | resources: 8 | - method: GET 9 | path: /match 10 | security: 11 | conditions: 12 | - effect: Permit 13 | requestHeaders: 14 | Authorization: 15 | value: Bearer .* 16 | operator: Matches 17 | 18 | - method: GET 19 | path: /does-not-match 20 | security: 21 | conditions: 22 | - effect: Deny 23 | requestHeaders: 24 | Authorization: 25 | value: Bearer magic.* 26 | operator: NotMatches 27 | -------------------------------------------------------------------------------- /server/src/test/resources/security-config-with-resources/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | path: / 4 | response: 5 | content: "Hello" 6 | 7 | security: 8 | # no requests permitted by default 9 | default: Deny 10 | 11 | # only requests meeting these conditions are permitted 12 | conditions: 13 | - effect: Permit 14 | queryParams: 15 | apiKey: s3cr3t 16 | 17 | resources: 18 | # no resource security: should fall back to root 19 | - method: GET 20 | path: /example 21 | response: 22 | content: "Hello" 23 | -------------------------------------------------------------------------------- /server/src/test/resources/security-config/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | path: /example 4 | response: 5 | content: "Hello" 6 | 7 | security: 8 | # no requests permitted by default 9 | default: Deny 10 | 11 | # only requests meeting these conditions are permitted 12 | conditions: 13 | - effect: Permit 14 | requestHeaders: 15 | Authorization: s3cr3t 16 | 17 | - effect: Deny 18 | requestHeaders: 19 | X-Api-Key: 20 | value: opensesame 21 | operator: NotEqualTo 22 | 23 | resources: 24 | # always permit status endpoint 25 | - method: GET 26 | path: /system/status 27 | security: 28 | default: Permit 29 | -------------------------------------------------------------------------------- /server/src/test/resources/simple-config/test-plugin-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": "io.gatehill.imposter.plugin.test.TestPluginImpl", 3 | "path": "/example", 4 | "response": { 5 | "staticFile": "test-plugin-data.json" 6 | }, 7 | "customProperty": "testValue", 8 | "resources": [ 9 | { 10 | "path": "/static-file-example", 11 | "method": "GET", 12 | "response": { 13 | "staticFile": "non-existent-file.txt", 14 | "statusCode": 200 15 | } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /server/src/test/resources/simple-config/test-plugin-data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "abc:exampleCell": "exampleValue" 4 | } 5 | ] 6 | -------------------------------------------------------------------------------- /server/src/test/resources/static-content/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Test 4 | Hello world 5 | 6 | -------------------------------------------------------------------------------- /server/src/test/resources/static-content/static/styles.css: -------------------------------------------------------------------------------- 1 | .example {} 2 | -------------------------------------------------------------------------------- /server/src/test/resources/static-content/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - method: GET 5 | path: /* 6 | response: 7 | dir: static 8 | -------------------------------------------------------------------------------- /server/src/test/resources/steps-remote/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - path: /example 5 | method: GET 6 | steps: 7 | - type: remote 8 | url: "http://localhost:${stores.test.remotePort}" 9 | method: POST 10 | queryParams: 11 | petId: "${context.request.queryParams.petId}" 12 | headers: 13 | X-Test-Header: "test" 14 | content: '{ "type": "cat" }' 15 | capture: 16 | petName: 17 | store: request 18 | expression: "${remote.response.body}" 19 | statusCode: 20 | store: request 21 | expression: "${remote.response.statusCode}" 22 | - type: script 23 | code: | 24 | var requestStore = stores.open('request'); 25 | var statusCode = requestStore.load('statusCode'); 26 | 27 | // note: store value is a string 28 | if (statusCode === '200') { 29 | respond().withStatusCode(201); 30 | } else { 31 | respond().withStatusCode(500); 32 | } 33 | response: 34 | content: "${stores.request.petName}" 35 | template: true 36 | -------------------------------------------------------------------------------- /server/src/test/resources/steps-script/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - path: /example-file 5 | method: GET 6 | steps: 7 | - type: script 8 | file: test.js 9 | response: 10 | content: "${stores.request.foo}" 11 | template: true 12 | 13 | - path: /example-inline 14 | method: GET 15 | steps: 16 | - type: script 17 | code: | 18 | respond().withContent('baz') 19 | -------------------------------------------------------------------------------- /server/src/test/resources/steps-script/test.js: -------------------------------------------------------------------------------- 1 | var requestStore = stores.open('request'); 2 | 3 | requestStore.save('foo', 'bar'); 4 | -------------------------------------------------------------------------------- /server/src/test/resources/store-preload/initial-data.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "baz": { 4 | "qux": "corge" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /server/src/test/resources/store-preload/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | system: 4 | stores: 5 | # this store is preloaded from file 6 | preload-file-test: 7 | preloadFile: initial-data.json 8 | 9 | # this store is preloaded from inline data 10 | preload-data-test: 11 | preloadData: 12 | foo: bar 13 | baz: { "qux": "corge" } 14 | -------------------------------------------------------------------------------- /server/src/test/resources/store-script/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | - method: PUT 5 | path: /store 6 | response: 7 | scriptFile: store.js 8 | 9 | - method: GET 10 | path: /load 11 | response: 12 | scriptFile: store.js 13 | 14 | - method: GET 15 | path: /templated 16 | response: 17 | content: Hello ${stores.templateTest.foo} 18 | template: true 19 | -------------------------------------------------------------------------------- /server/src/test/resources/trailing-wildcard-path/test-plugin-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: "io.gatehill.imposter.plugin.test.TestPluginImpl" 2 | 3 | resources: 4 | # trailing wildcard path match 5 | - method: GET 6 | path: /* 7 | response: 8 | content: "Matched wildcard path" 9 | 10 | # exact match takes precedence over wildcard 11 | - method: GET 12 | path: /exact 13 | response: 14 | content: "Matched exact path" 15 | -------------------------------------------------------------------------------- /since.yaml: -------------------------------------------------------------------------------- 1 | requireBranch: main 2 | 3 | ignore: 4 | - "prep for release" 5 | - "next development version" 6 | 7 | before: 8 | - script: | 9 | echo "projectVersion=${SINCE_NEW_VERSION}" > gradle.properties 10 | git add gradle.properties 11 | 12 | after: 13 | - script: | 14 | echo "projectVersion=0.0.0-SNAPSHOT" > gradle.properties 15 | git add gradle.properties 16 | git commit -m"build: next development version." 17 | -------------------------------------------------------------------------------- /store/common/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /store/common/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker: -------------------------------------------------------------------------------- 1 | mock-maker-inline -------------------------------------------------------------------------------- /store/dynamodb/example/iam-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Sid": "ImposterStoreRW", 6 | "Effect": "Allow", 7 | "Action": [ 8 | "dynamodb:BatchWriteItem", 9 | "dynamodb:PutItem", 10 | "dynamodb:DeleteItem", 11 | "dynamodb:GetItem", 12 | "dynamodb:Query" 13 | ], 14 | "Resource": "arn:aws:dynamodb:us-east-1:000000000000:table/Imposter" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /store/dynamodb/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /store/graphql/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | id 'kotlin' 4 | id 'com.gradleup.shadow' 5 | } 6 | 7 | ext { 8 | version_kgraphql = '0.19.0' 9 | } 10 | 11 | compileJava { 12 | sourceCompatibility = JavaVersion.VERSION_11 13 | } 14 | 15 | dependencies { 16 | implementation project(':core:imposter-api') 17 | implementation project(':store:store-common') 18 | 19 | pluginImplementation("com.apurebase:kgraphql:$version_kgraphql") 20 | 21 | // test 22 | testImplementation "org.junit.jupiter:junit-jupiter-api:$version_junit_jupiter" 23 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$version_junit_jupiter" 24 | testImplementation "org.mockito:mockito-core:$version_mockito" 25 | testImplementation "org.mockito.kotlin:mockito-kotlin:$version_mockito_kotlin" 26 | testImplementation project(':store:store-inmem') 27 | } 28 | 29 | compileKotlin { 30 | kotlinOptions { 31 | jvmTarget = JavaVersion.VERSION_11 32 | 33 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 34 | freeCompilerArgs = ["-Xjvm-default=all"] 35 | } 36 | } 37 | 38 | compileTestKotlin { 39 | kotlinOptions { 40 | jvmTarget = JavaVersion.VERSION_11 41 | 42 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 43 | freeCompilerArgs = ["-Xjvm-default=all"] 44 | } 45 | } 46 | 47 | shadowJar { 48 | archiveBaseName.set("imposter-plugin-${project.name}") 49 | archiveVersion.set('') 50 | archiveClassifier.set('') 51 | configurations = [project.configurations.pluginImplementation] 52 | } 53 | 54 | task dist { 55 | dependsOn shadowJar 56 | } 57 | 58 | test { 59 | useJUnitPlatform() 60 | } 61 | -------------------------------------------------------------------------------- /store/graphql/src/main/java/io/gatehill/imposter/store/graphql/GraphQLQueryModule.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.store.graphql 2 | 3 | import com.google.inject.AbstractModule 4 | import io.gatehill.imposter.util.FeatureUtil 5 | import org.apache.logging.log4j.LogManager 6 | import org.apache.logging.log4j.Logger 7 | 8 | class GraphQLQueryModule : AbstractModule() { 9 | private val logger : Logger = LogManager.getLogger(GraphQLQueryModule::class.java) 10 | 11 | override fun configure() { 12 | if (FeatureUtil.isFeatureEnabled("stores")) { 13 | // eager to bind lifecycle hook 14 | bind(GraphQLQueryService::class.java).asEagerSingleton() 15 | } else { 16 | logger.debug("Skipping GraphQL plugin initialisation as stores feature is disabled") 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /store/graphql/src/main/java/io/gatehill/imposter/store/graphql/GraphQLQueryPlugin.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.store.graphql 2 | 3 | import io.gatehill.imposter.plugin.Plugin 4 | import io.gatehill.imposter.plugin.PluginInfo 5 | import io.gatehill.imposter.plugin.RequireModules 6 | 7 | @PluginInfo("store-graphql") 8 | @RequireModules(GraphQLQueryModule::class) 9 | class GraphQLQueryPlugin : Plugin 10 | -------------------------------------------------------------------------------- /store/graphql/src/main/java/io/gatehill/imposter/store/graphql/model/JsonRawValueDeserializer.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.store.graphql.model 2 | 3 | import com.fasterxml.jackson.core.JsonParser 4 | import com.fasterxml.jackson.core.TreeNode 5 | import com.fasterxml.jackson.databind.DeserializationContext 6 | import com.fasterxml.jackson.databind.JsonDeserializer 7 | 8 | class JsonRawValueDeserializer : JsonDeserializer() { 9 | override fun deserialize(jp: JsonParser, context: DeserializationContext): String { 10 | return jp.readValueAsTree().toString() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /store/graphql/src/main/java/io/gatehill/imposter/store/graphql/model/StoreItem.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.store.graphql.model 2 | 3 | data class StoreItem(val key: String, val value: String?) 4 | -------------------------------------------------------------------------------- /store/graphql/src/main/resources/META-INF/plugin.properties: -------------------------------------------------------------------------------- 1 | name=store-graphql 2 | class=io.gatehill.imposter.store.graphql.GraphQLQueryPlugin 3 | load=eager 4 | -------------------------------------------------------------------------------- /store/graphql/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /store/graphql/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker: -------------------------------------------------------------------------------- 1 | mock-maker-inline -------------------------------------------------------------------------------- /store/inmem/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'kotlin' 3 | apply plugin: 'maven-publish' 4 | 5 | compileJava { 6 | sourceCompatibility = JavaVersion.VERSION_11 7 | } 8 | 9 | dependencies { 10 | implementation project(':store:store-common') 11 | 12 | // test 13 | testImplementation project(':test:test-utils') 14 | } 15 | 16 | task sourcesJar(type: Jar, dependsOn: classes) { 17 | archiveClassifier = 'sources' 18 | from sourceSets.main.allSource 19 | } 20 | 21 | artifacts { 22 | archives sourcesJar 23 | } 24 | 25 | publishing { 26 | publications { 27 | maven(MavenPublication) { 28 | from components.java 29 | artifact sourcesJar 30 | 31 | repositories { 32 | maven { 33 | url = version.endsWith('SNAPSHOT') ? mavenSnapshotRepository : mavenReleaseRepository 34 | credentials(AwsCredentials) { 35 | accessKey awsAccessKey 36 | secretKey awsSecretKey 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | 44 | compileKotlin { 45 | kotlinOptions { 46 | jvmTarget = JavaVersion.VERSION_11 47 | 48 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 49 | freeCompilerArgs = ["-Xjvm-default=all"] 50 | } 51 | } 52 | 53 | compileTestKotlin { 54 | kotlinOptions { 55 | jvmTarget = JavaVersion.VERSION_11 56 | 57 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 58 | freeCompilerArgs = ["-Xjvm-default=all"] 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /store/inmem/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /store/redis/example/scripted-example/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: rest 2 | 3 | resources: 4 | - method: PUT 5 | path: /store 6 | response: 7 | scriptFile: store.js 8 | 9 | - method: GET 10 | path: /load 11 | response: 12 | scriptFile: store.js 13 | -------------------------------------------------------------------------------- /store/redis/example/scripted-example/redisson.yaml: -------------------------------------------------------------------------------- 1 | singleServerConfig: 2 | # specify the address of the Redis instance 3 | #address: "redis://127.0.0.1:6379" 4 | 5 | # assumes Imposter running within Docker container and Redis is on the Docker host 6 | address: "redis://host.docker.internal:6379" 7 | 8 | # other Redisson configuration options 9 | idleConnectionTimeout: 10000 10 | connectTimeout: 10000 11 | timeout: 3000 12 | retryAttempts: 3 13 | retryInterval: 1500 14 | password: null 15 | subscriptionsPerConnection: 5 16 | clientName: null 17 | subscriptionConnectionMinimumIdleSize: 1 18 | subscriptionConnectionPoolSize: 50 19 | connectionMinimumIdleSize: 10 20 | connectionPoolSize: 64 21 | database: 0 22 | dnsMonitoringInterval: 5000 23 | -------------------------------------------------------------------------------- /store/redis/example/scripted-example/store.js: -------------------------------------------------------------------------------- 1 | var testStore = stores.open('test'); 2 | 3 | switch (context.request.path) { 4 | case '/store': 5 | testStore.save('foo', context.request.queryParams.foo); 6 | respond().withStatusCode(201); 7 | break; 8 | 9 | case '/load': 10 | respond() 11 | .withStatusCode(200) 12 | .withHeader('Content-Type', 'text/plain') 13 | .withContent(testStore.load('foo')); 14 | break; 15 | } 16 | -------------------------------------------------------------------------------- /store/redis/example/simple-example/imposter-config.yaml: -------------------------------------------------------------------------------- 1 | plugin: rest 2 | -------------------------------------------------------------------------------- /store/redis/example/simple-example/redisson.yaml: -------------------------------------------------------------------------------- 1 | singleServerConfig: 2 | address: "redis://host.docker.internal:6379" 3 | idleConnectionTimeout: 10000 4 | connectTimeout: 10000 5 | timeout: 3000 6 | retryAttempts: 3 7 | retryInterval: 1500 8 | -------------------------------------------------------------------------------- /store/redis/src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/api-tests/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | 3 | ext { 4 | version_restassured = '5.3.2' 5 | } 6 | 7 | compileJava { 8 | sourceCompatibility = JavaVersion.VERSION_11 9 | } 10 | 11 | dependencies { 12 | api "io.rest-assured:rest-assured:$version_restassured" 13 | constraints { 14 | api "org.apache.groovy:groovy-json:$version_groovy" 15 | api "org.apache.groovy:groovy-xml:$version_groovy" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/sample-soap-client/README.md: -------------------------------------------------------------------------------- 1 | Import WSDL: 2 | 3 | wsimport -s src/main/java \ 4 | -keep -Xnocompile -extension -encoding UTF-8 \ 5 | -wsdllocation /petservice/service.wsdl \ 6 | src/main/wsdl/service.wsdl 7 | -------------------------------------------------------------------------------- /test/sample-soap-client/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | 3 | compileJava { 4 | sourceCompatibility = JavaVersion.VERSION_11 5 | } 6 | 7 | dependencies { 8 | api 'jakarta.xml.ws:jakarta.xml.ws-api:4.0.0' 9 | implementation 'com.sun.xml.ws:jaxws-rt:4.0.1' 10 | } 11 | -------------------------------------------------------------------------------- /test/sample-soap-client/src/main/java/com/example/petstore/GetPetByIdRequest.java: -------------------------------------------------------------------------------- 1 | 2 | package com.example.petstore; 3 | 4 | import jakarta.xml.bind.annotation.XmlAccessType; 5 | import jakarta.xml.bind.annotation.XmlAccessorType; 6 | import jakarta.xml.bind.annotation.XmlType; 7 | 8 | 9 | /** 10 | *

Java class for getPetByIdRequest complex type. 11 | * 12 | *

The following schema fragment specifies the expected content contained within this class. 13 | * 14 | *

15 |  * <complexType name="getPetByIdRequest">
16 |  *   <complexContent>
17 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
18 |  *       <all>
19 |  *         <element name="id" type="{http://www.w3.org/2001/XMLSchema}int"/>
20 |  *       </all>
21 |  *     </restriction>
22 |  *   </complexContent>
23 |  * </complexType>
24 |  * 
25 | * 26 | * 27 | */ 28 | @XmlAccessorType(XmlAccessType.FIELD) 29 | @XmlType(name = "getPetByIdRequest", propOrder = { 30 | 31 | }) 32 | public class GetPetByIdRequest { 33 | 34 | protected int id; 35 | 36 | /** 37 | * Gets the value of the id property. 38 | * 39 | */ 40 | public int getId() { 41 | return id; 42 | } 43 | 44 | /** 45 | * Sets the value of the id property. 46 | * 47 | */ 48 | public void setId(int value) { 49 | this.id = value; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /test/sample-soap-client/src/main/java/com/example/petstore/GetPetByNameRequest.java: -------------------------------------------------------------------------------- 1 | 2 | package com.example.petstore; 3 | 4 | import jakarta.xml.bind.annotation.XmlAccessType; 5 | import jakarta.xml.bind.annotation.XmlAccessorType; 6 | import jakarta.xml.bind.annotation.XmlElement; 7 | import jakarta.xml.bind.annotation.XmlType; 8 | 9 | 10 | /** 11 | *

Java class for getPetByNameRequest complex type. 12 | * 13 | *

The following schema fragment specifies the expected content contained within this class. 14 | * 15 | *

16 |  * <complexType name="getPetByNameRequest">
17 |  *   <complexContent>
18 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
19 |  *       <all>
20 |  *         <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
21 |  *       </all>
22 |  *     </restriction>
23 |  *   </complexContent>
24 |  * </complexType>
25 |  * 
26 | * 27 | * 28 | */ 29 | @XmlAccessorType(XmlAccessType.FIELD) 30 | @XmlType(name = "getPetByNameRequest", propOrder = { 31 | 32 | }) 33 | public class GetPetByNameRequest { 34 | 35 | @XmlElement(required = true) 36 | protected String name; 37 | 38 | /** 39 | * Gets the value of the name property. 40 | * 41 | * @return 42 | * possible object is 43 | * {@link String } 44 | * 45 | */ 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | /** 51 | * Sets the value of the name property. 52 | * 53 | * @param value 54 | * allowed object is 55 | * {@link String } 56 | * 57 | */ 58 | public void setName(String value) { 59 | this.name = value; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /test/sample-soap-client/src/main/java/com/example/petstore/PetPortType.java: -------------------------------------------------------------------------------- 1 | 2 | package com.example.petstore; 3 | 4 | import jakarta.jws.WebMethod; 5 | import jakarta.jws.WebParam; 6 | import jakarta.jws.WebResult; 7 | import jakarta.jws.WebService; 8 | import jakarta.jws.soap.SOAPBinding; 9 | import jakarta.xml.bind.annotation.XmlSeeAlso; 10 | 11 | 12 | /** 13 | * This class was generated by the JAX-WS RI. 14 | * JAX-WS RI 2.2.9-b130926.1035 15 | * Generated source version: 2.2 16 | * 17 | */ 18 | @WebService(name = "PetPortType", targetNamespace = "urn:com:example:petstore") 19 | @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) 20 | @XmlSeeAlso({ 21 | ObjectFactory.class 22 | }) 23 | public interface PetPortType { 24 | 25 | 26 | /** 27 | * 28 | * @param parameters 29 | * @return 30 | * returns com.example.petstore.PetType 31 | */ 32 | @WebMethod(action = "getPetById") 33 | @WebResult(name = "getPetByIdResponse", targetNamespace = "urn:com:example:petstore", partName = "parameters") 34 | public PetType getPetById( 35 | @WebParam(name = "getPetByIdRequest", targetNamespace = "urn:com:example:petstore", partName = "parameters") 36 | GetPetByIdRequest parameters); 37 | 38 | /** 39 | * 40 | * @param parameters 41 | * @return 42 | * returns com.example.petstore.PetType 43 | */ 44 | @WebMethod(action = "getPetByName") 45 | @WebResult(name = "getPetByNameResponse", targetNamespace = "urn:com:example:petstore", partName = "parameters") 46 | public PetType getPetByName( 47 | @WebParam(name = "getPetByNameRequest", targetNamespace = "urn:com:example:petstore", partName = "parameters") 48 | GetPetByNameRequest parameters); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /test/sample-soap-client/src/main/java/com/example/petstore/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * This is a sample WSDL 1.1 document describing the pet service. 4 | * 5 | * 6 | */ 7 | @jakarta.xml.bind.annotation.XmlSchema(namespace = "urn:com:example:petstore") 8 | package com.example.petstore; 9 | -------------------------------------------------------------------------------- /test/sample-soap-client/src/main/wsdl/schema.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /test/test-utils/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'kotlin' 3 | 4 | compileJava { 5 | sourceCompatibility = JavaVersion.VERSION_11 6 | } 7 | 8 | dependencies { 9 | api project(':core:imposter-engine') 10 | api project(':imposter-server') 11 | implementation project(':adapter:adapter-vertxweb') 12 | implementation project(':core:config-dynamic') 13 | 14 | // test 15 | api "org.junit.jupiter:junit-jupiter-api:$version_junit_jupiter" 16 | api "org.junit.jupiter:junit-jupiter-engine:$version_junit_jupiter" 17 | api "io.vertx:vertx-junit5:$version_vertx" 18 | api group: 'org.hamcrest', name: 'hamcrest', version: version_hamcrest 19 | 20 | // logging 21 | api "org.apache.logging.log4j:log4j-core:$version_log4j" 22 | api "org.apache.logging.log4j:log4j-slf4j2-impl:$version_log4j" 23 | 24 | // mocking 25 | implementation "org.mockito:mockito-core:$version_mockito" 26 | 27 | // required to mock vertx interfaces 28 | implementation "io.vertx:vertx-codegen:$version_vertx" 29 | 30 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$version_coroutines") 31 | } 32 | 33 | compileKotlin { 34 | kotlinOptions { 35 | jvmTarget = JavaVersion.VERSION_11 36 | 37 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 38 | freeCompilerArgs = ["-Xjvm-default=all"] 39 | } 40 | } 41 | 42 | compileTestKotlin { 43 | kotlinOptions { 44 | jvmTarget = JavaVersion.VERSION_11 45 | 46 | // see https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces 47 | freeCompilerArgs = ["-Xjvm-default=all"] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/test-utils/src/main/java/io/gatehill/imposter/server/VerticleTestCategory.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.server 2 | 3 | import org.junit.jupiter.api.Tag 4 | 5 | /** 6 | * Marker annotation for tests that extend BaseVerticleTest. 7 | * Used to categorise and run these tests specifically. 8 | * 9 | * @author Pete Cornish 10 | */ 11 | @Target(AnnotationTarget.CLASS) 12 | @Retention(AnnotationRetention.RUNTIME) 13 | @Tag("verticle") 14 | annotation class VerticleTest 15 | -------------------------------------------------------------------------------- /test/test-utils/src/main/java/io/gatehill/imposter/store/support/Example.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.store.support 2 | 3 | import java.io.Serializable 4 | 5 | data class Example( 6 | val name: String 7 | ) : Serializable 8 | -------------------------------------------------------------------------------- /test/test-utils/src/main/java/io/gatehill/imposter/util/Util.kt: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.util 2 | 3 | import kotlinx.coroutines.delay 4 | import kotlinx.coroutines.runBlocking 5 | 6 | /** 7 | * Invoke the given block [attempts] times. If a [Throwable] is 8 | * thrown, retry with a delay of [delayMs] ms. 9 | */ 10 | fun attempt(attempts: Int, delayMs: Long = 500, block: () -> Unit) = runBlocking { 11 | for (attempt in 1..attempts) { 12 | try { 13 | block() 14 | } catch (e: Throwable) { 15 | if (attempt >= attempts) { 16 | throw RuntimeException("Failed after $attempt attempts", e) 17 | } else { 18 | delay(delayMs) 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/test-utils/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tools/docs-local/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | RUN pip install \ 4 | mkdocs-material \ 5 | mkdocs-mermaid2-plugin 6 | 7 | RUN mkdir /site 8 | WORKDIR /site 9 | 10 | EXPOSE 8000 11 | 12 | ENTRYPOINT mkdocs build && python -m http.server --directory ./site 8000 13 | -------------------------------------------------------------------------------- /tools/docs-local/compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | docs: 3 | build: . 4 | ports: 5 | - 8000:8000 6 | volumes: 7 | - "../../:/site" 8 | -------------------------------------------------------------------------------- /tools/perf-monitor/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | id 'com.gradleup.shadow' 4 | } 5 | 6 | dependencies { 7 | implementation 'net.bytebuddy:byte-buddy-dep:1.12.19' 8 | implementation 'net.bytebuddy:byte-buddy-agent:1.12.19' 9 | } 10 | 11 | jar { 12 | manifest { 13 | attributes 'Premain-Class': 'io.gatehill.imposter.perf.Agent' 14 | } 15 | } 16 | 17 | shadowJar { 18 | archiveFileName.set('imposter-perf-monitor.jar') 19 | } 20 | -------------------------------------------------------------------------------- /tools/perf-monitor/src/main/java/io/gatehill/imposter/perf/CallTimerAdvice.java: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.perf; 2 | 3 | import static net.bytebuddy.asm.Advice.AllArguments; 4 | import static net.bytebuddy.asm.Advice.Enter; 5 | import static net.bytebuddy.asm.Advice.OnMethodEnter; 6 | import static net.bytebuddy.asm.Advice.OnMethodExit; 7 | import static net.bytebuddy.asm.Advice.Origin; 8 | 9 | public class CallTimerAdvice { 10 | @OnMethodEnter 11 | static long enter() { 12 | return System.currentTimeMillis(); 13 | } 14 | 15 | @OnMethodExit 16 | static void exit(@Origin String method, @Enter long start, @AllArguments Object[] args) { 17 | StringBuilder sb = new StringBuilder(); 18 | for (Object arg : args) { 19 | sb.append(arg); 20 | sb.append(", "); 21 | } 22 | try { 23 | String entry = (System.currentTimeMillis() - start) + ",\"" + method + "\",\"" + sb + "\""; 24 | entry = entry.replaceAll("\\R", " "); 25 | Agent.writer.write(entry); 26 | } catch (Exception e) { 27 | throw new RuntimeException(e); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tools/perf-monitor/src/main/java/io/gatehill/imposter/perf/PerfWriter.java: -------------------------------------------------------------------------------- 1 | package io.gatehill.imposter.perf; 2 | 3 | public interface PerfWriter { 4 | void write(String entry); 5 | } 6 | --------------------------------------------------------------------------------