├── .circleci └── config.yml ├── .gitignore ├── CHANGELOG.md ├── Jenkinsfile ├── header.txt ├── license.txt ├── pom.xml ├── readme.md ├── release.groovy └── src ├── main ├── java │ └── io │ │ └── fabric8 │ │ └── mockwebserver │ │ ├── Context.java │ │ ├── DefaultMockServer.java │ │ ├── MockServer.java │ │ ├── MockServerException.java │ │ ├── ServerRequest.java │ │ ├── ServerResponse.java │ │ ├── crud │ │ ├── Attribute.java │ │ ├── AttributeExtractor.java │ │ ├── AttributeSet.java │ │ ├── AttributeType.java │ │ ├── CrudDispatcher.java │ │ ├── Key.java │ │ ├── ResponseComposer.java │ │ └── Value.java │ │ ├── dsl │ │ ├── DelayPathable.java │ │ ├── DelayTimesOrOnceable.java │ │ ├── Delayable.java │ │ ├── Doneable.java │ │ ├── Emitable.java │ │ ├── EventDoneable.java │ │ ├── Eventable.java │ │ ├── Failable.java │ │ ├── Function.java │ │ ├── HttpHeaderable.java │ │ ├── HttpMethod.java │ │ ├── HttpMethodable.java │ │ ├── HttpStatusable.java │ │ ├── MockServerExpectation.java │ │ ├── Onceable.java │ │ ├── Openable.java │ │ ├── Pathable.java │ │ ├── Replyable.java │ │ ├── ReturnOrWebsocketable.java │ │ ├── Returnable.java │ │ ├── Schedulable.java │ │ ├── TimesOnceableOrHttpHeaderable.java │ │ ├── TimesOrOnceable.java │ │ ├── TimesSchedulableOrOnceable.java │ │ ├── Timesable.java │ │ ├── WebSocketSessionBuilder.java │ │ └── WebSocketable.java │ │ ├── internal │ │ ├── ChunkedResponse.java │ │ ├── InlineWebSocketSessionBuilder.java │ │ ├── MockDispatcher.java │ │ ├── MockSSLContextFactory.java │ │ ├── MockServerExpectationImpl.java │ │ ├── SimpleRequest.java │ │ ├── SimpleResponse.java │ │ ├── WebSocketMessage.java │ │ └── WebSocketSession.java │ │ └── utils │ │ ├── BodyProvider.java │ │ ├── CertUtils.java │ │ ├── Closeables.java │ │ ├── PKCS1Util.java │ │ ├── ResponseProvider.java │ │ ├── ResponseProviders.java │ │ └── SSLUtils.java └── resources │ └── ssl │ ├── fabric8 │ ├── fabric8.crt │ ├── fabric8.csr │ └── fabric8.pub └── test └── groovy └── io └── fabric8 └── mockwebserver ├── DefaultMockServerCrudTest.groovy ├── DefaultMockServerHttpsTest.groovy ├── DefaultMockServerTest.groovy ├── DefaultMockServerWebSocketTest.groovy ├── JsonResponseComposer.groovy ├── MockServerExceptionTest.groovy ├── User.groovy ├── UserAttributeExtractor.groovy └── crud ├── AttributeSetTest.groovy ├── AttributeTest.groovy └── CrudDispatcherTest.groovy /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2015 Red Hat, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://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, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | version: 2 18 | 19 | jobs: 20 | build: 21 | working_directory: ~/fabric8io/mockwebserver 22 | machine: true 23 | steps: 24 | - checkout 25 | - run: 26 | name: License check 27 | command: mvn -N license:check 28 | - run: 29 | command: | 30 | mvn clean install 31 | - save_cache: 32 | key: f8-{{ checksum "pom.xml" }} 33 | paths: 34 | - ~/.m2 35 | 36 | workflows: 37 | version: 2 38 | all: 39 | jobs: 40 | - build 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Maven template 3 | target/ 4 | pom.xml.tag 5 | pom.xml.releaseBackup 6 | pom.xml.versionsBackup 7 | pom.xml.next 8 | release.properties 9 | dependency-reduced-pom.xml 10 | buildNumber.properties 11 | .mvn/timing.properties 12 | 13 | 14 | ### Java template 15 | *.class 16 | 17 | # Mobile Tools for Java (J2ME) 18 | .mtj.tmp/ 19 | 20 | # Package Files # 21 | *.jar 22 | *.war 23 | *.ear 24 | 25 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 26 | hs_err_pid* 27 | 28 | 29 | ### JetBrains template 30 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 31 | 32 | *.iml 33 | 34 | ## Directory-based project format: 35 | .idea/ 36 | # if you remove the above rule, at least ignore the following: 37 | 38 | # User-specific stuff: 39 | # .idea/workspace.xml 40 | # .idea/tasks.xml 41 | # .idea/dictionaries 42 | 43 | # Sensitive or high-churn files: 44 | # .idea/dataSources.ids 45 | # .idea/dataSources.xml 46 | # .idea/sqlDataSources.xml 47 | # .idea/dynamic.xml 48 | # .idea/uiDesigner.xml 49 | 50 | # Gradle: 51 | # .idea/gradle.xml 52 | # .idea/libraries 53 | 54 | # Mongo Explorer plugin: 55 | # .idea/mongoSettings.xml 56 | 57 | ## File-based project format: 58 | *.ipr 59 | *.iws 60 | 61 | ## Plugin-specific files: 62 | 63 | # IntelliJ 64 | /out/ 65 | 66 | # mpeltonen/sbt-idea plugin 67 | .idea_modules/ 68 | 69 | # JIRA plugin 70 | atlassian-ide-plugin.xml 71 | 72 | # Crashlytics plugin (for Android Studio and IntelliJ) 73 | com_crashlytics_export_strings.xml 74 | crashlytics.properties 75 | crashlytics-build.properties 76 | 77 | 78 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## CHANGELOG 2 | 3 | ### 0.3-SNAPSHOT 4 | 5 | #### Bugs 6 | #### Improvements 7 | #### Dependency Upgrade 8 | #### New Feature 9 | 10 | ### 0.2.2 (2021-11-03) 11 | 12 | #### Bugs 13 | * Fix #70: WebSocketSession regression, WS closed when no configured messages 14 | 15 | ### 0.2.1 (2021-11-03) 16 | 17 | #### Bugs 18 | * Fix #69: regression on Attribute#equals & Attribute#hashCode 19 | 20 | ### 0.2.0 (2021-11-03) 21 | 22 | #### Bugs 23 | * Fix #66: Removed code smells and bugs 24 | * Fix #64: Allow concurrent access to Map preserving insertion order 25 | * Fix #57: Update expired SSL certificates (new expiry date 2031-11-01) 26 | 27 | #### Improvements 28 | * Fix #59: adding a getter to access namespace from the path (fabric8io/kubernetes-client#2921) 29 | * Fix #66: Added getLastRequest method to MockServer 30 | * Fix #66: CRUD dispatcher handles PUT independently of POST 31 | 32 | #### Dependency Upgrade 33 | * Fix #52: Updated OkHttpClient to version 3.12.12 34 | * Fix #65: Updated Jackson to version 2.13.0 35 | * Fix #61: Removed Sundrio dependency 36 | 37 | ### 0.1.8 (2020-04-14) 38 | #### Bugs 39 | #### Improvements 40 | #### Dependency Upgrade 41 | * Updated OkHttpClient to version 3.12.6 42 | 43 | #### New Feature 44 | 45 | ### 0.1.7 (2019-09-27) 46 | #### Bugs 47 | 48 | #### Improvements 49 | * AttributeSet now examines all attributes when determining if another AttributeSet matches. 50 | #### Dependency Upgrade 51 | 52 | #### New Feature 53 | 54 | 55 | ### 0.1.6 (26-09-2019) 56 | #### Bugs 57 | 58 | #### Improvements 59 | * Attribute Type matching now supports EXISTS and NOT_EXISTS 60 | 61 | #### Dependency Upgrade 62 | 63 | #### New Feature 64 | 65 | 66 | ### 0.1.4 (16-09-2019) 67 | #### Bugs 68 | 69 | #### Improvements 70 | * Adding argument to getStatusCode 71 | 72 | #### Dependency Upgrade 73 | 74 | #### New Feature 75 | 76 | 77 | 78 | ### 0.1.3 (03-09-2019) 79 | #### Bugs 80 | 81 | #### Improvements 82 | * Added Attribute Types (WITH and WITHOUT) to works with withoutLabel filter (AttributeSet.matches()). 83 | 84 | #### Dependency Upgrade 85 | 86 | #### New Feature 87 | 88 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/groovy 2 | @Library('github.com/fabric8io/fabric8-pipeline-library@master') 3 | def utils = new io.fabric8.Utils() 4 | 5 | releaseNode { 6 | try { 7 | checkout scm 8 | readTrusted 'release.groovy' 9 | 10 | if (utils.isCI()) { 11 | 12 | echo 'CI is not handled by pipelines yet' 13 | 14 | } else if (utils.isCD()) { 15 | sh "git remote set-url origin git@github.com:fabric8io/mockwebserver.git" 16 | 17 | def pipeline = load 'release.groovy' 18 | def stagedProject 19 | 20 | stage('Stage') { 21 | stagedProject = pipeline.stage() 22 | } 23 | 24 | stage('Promote') { 25 | pipeline.release(stagedProject) 26 | } 27 | 28 | stage('Promote YAMLs') { 29 | pipeline.promoteYamls(stagedProject[1]) 30 | } 31 | } 32 | } catch (err) { 33 | hubot room: 'release', message: "${env.JOB_NAME} failed: ${err}" 34 | error "${err}" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /header.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) ${project.inceptionYear} ${owner} 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 22 | 4.0.0 23 | 24 | io.fabric8 25 | mockwebserver 26 | 0.3-SNAPSHOT 27 | Fabric8 :: Mock Web Server 28 | Mock Web Server 29 | 30 | http://fabric8.io/ 31 | 2015 32 | 33 | 34 | Red Hat 35 | http://redhat.com 36 | 37 | 38 | 39 | 40 | Apache License, Version 2.0 41 | http://www.apache.org/licenses/LICENSE-2.0.txt 42 | repo 43 | 44 | 45 | 46 | 47 | 48 | 49 | geeks 50 | Fabric8 Development Team 51 | fabric8 52 | http://fabric8.io/ 53 | 54 | 55 | 56 | 57 | scm:git:git@github.com:fabric8io/mockwebserver.git 58 | scm:git:git@github.com:fabric8io/mockwebserver.git 59 | http://github.com/fabric8io/mockwebserver/ 60 | ${project.version} 61 | 62 | 63 | 64 | 65 | oss-sonatype-staging 66 | Sonatype Staging Repository 67 | https://oss.sonatype.org/service/local/staging/deploy/maven2 68 | 69 | 70 | 71 | 72 | UTF-8 73 | 1.8 74 | 1.8 75 | 76 | 77 | 3.12.12 78 | 2.13.0 79 | 0.3.0 80 | 81 | 82 | 2.0-groovy-3.0 83 | 1.13.0 84 | 85 | 86 | 87 | 88 | com.squareup.okhttp3 89 | mockwebserver 90 | ${okhttp.version} 91 | 92 | 93 | 94 | com.fasterxml.jackson.core 95 | jackson-databind 96 | ${jackson.version} 97 | 98 | 99 | 100 | io.fabric8 101 | zjsonpatch 102 | ${zjsonpatch.version} 103 | 104 | 105 | 106 | org.spockframework 107 | spock-core 108 | ${spock.version} 109 | test 110 | 111 | 112 | 113 | 114 | 115 | 116 | org.apache.maven.plugins 117 | maven-compiler-plugin 118 | 3.8.1 119 | 120 | 121 | org.apache.maven.plugins 122 | maven-jar-plugin 123 | 3.2.0 124 | 125 | 126 | org.apache.maven.plugins 127 | maven-surefire-plugin 128 | true 129 | 2.22.2 130 | 131 | 132 | org.apache.maven.plugins 133 | maven-gpg-plugin 134 | 1.6 135 | 136 | true 137 | 138 | 139 | 140 | com.mycila 141 | license-maven-plugin 142 | 2.11 143 | 144 | true 145 |
header.txt
146 | 147 | Red Hat, Inc. 148 | 149 | 150 | .editorconfig 151 | license.txt 152 | **/test-kubeconfig 153 | 154 |
155 |
156 | 157 | org.codehaus.gmavenplus 158 | gmavenplus-plugin 159 | ${gmavenplus-plugin.version} 160 | true 161 | 162 | 163 | 164 | addSources 165 | addTestSources 166 | compileTests 167 | 168 | 169 | 170 | 171 |
172 |
173 | 174 | 175 | 176 | release 177 | 178 | 179 | 180 | org.apache.maven.plugins 181 | maven-gpg-plugin 182 | 183 | 184 | sign-artifacts 185 | verify 186 | 187 | sign 188 | 189 | 190 | 191 | 192 | 193 | org.apache.maven.plugins 194 | maven-enforcer-plugin 195 | 1.4.1 196 | 197 | 198 | enforce-no-snapshots 199 | 200 | enforce 201 | 202 | 203 | 204 | 205 | No Snapshots Allowed! 206 | 207 | 208 | false 209 | 210 | 211 | 212 | 213 | 214 | org.apache.maven.plugins 215 | maven-javadoc-plugin 216 | 3.2.0 217 | 218 | ${javadoc.include.deps} 219 | 220 | ${javadoc.source.includes} 221 | 222 | ${javadoc.package.excludes} 223 | 224 | 225 | 226 | attach-javadocs 227 | 228 | jar 229 | 230 | 231 | ${javadoc.opts} 232 | 233 | 234 | 235 | 236 | 237 | org.apache.maven.plugins 238 | maven-source-plugin 239 | 3.2.1 240 | 241 | 242 | attach-sources 243 | 244 | jar 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | doclint-java8-disable 254 | 255 | [1.8,) 256 | 257 | 258 | -Xdoclint:none 259 | 260 | 261 | 262 | 263 |
264 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Mock Web Server 2 | --------------- 3 | 4 | 5 | 6 | > [!IMPORTANT] 7 | > This repository has been archived. 8 | > 9 | > The content of this project has been moved to the [Fabric8 Kubernetes Client](https://github.com/fabric8io/kubernetes-client) repository. 10 | > The Maven coordinates remain the same `io.fabric8:mockwebserver`, except for the version which is now aligned with the Kubernetes Client version. 11 | > 12 | > See https://github.com/fabric8io/kubernetes-client/issues/5430 for more information. 13 | 14 | 15 | 16 | [![CircleCI](https://circleci.com/gh/fabric8io/mockwebserver.svg?style=svg)](https://circleci.com/gh/fabric8io/mockwebserver) 17 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.fabric8/mockwebserver/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/io.fabric8/mockwebserver/) 18 | 19 | 20 | This is a DSL wrapper around the ``okhttp`` [mockwebserver](https://github.com/square/okhttp/tree/master/mockwebserver), that intends to make it easier to use. 21 | 22 | **Features**: 23 | 24 | - [EasyMock](http://easymock.org)-like DSL *(expect / respond / frequency)* 25 | - Supports most HTTP operations 26 | - Supports Chunked responses 27 | - Supports WebSockets 28 | - Supports String or Object bodies (which are serialized to JSON or YAML). 29 | - Supports SSL 30 | - CRUD mocking 31 | 32 | ### Creating a Mock Web Server 33 | 34 | To create an instance of the Mock Web Server: 35 | 36 | DefaultMockServer server = new DefaultMockServer(); 37 | server.start(); 38 | 39 | The ``DefaultMockServer`` instance wraps around ``okhttp3.mockwebserver.MockWebServer``, and delegates lifecycle and feedback calls to it **(see below)** and on top of that provides methods for [Setting expectations][] 40 | 41 | When the start method is invoked a random port will be bound on localhost and the Mock Web Server will listen on that port. The hostname, port or URL of the server are available: 42 | 43 | String hostname = server.getHostName(); 44 | int port = server.getPort(); 45 | String url = server.url("/api/v1/users"); 46 | 47 | #### Creating a request 48 | 49 | To create a request using the ``okhttp`` you just need to obtain the url from Mock WebServer instance and use it in your request 50 | 51 | OkHttpClient client = new OkHttpClient(); 52 | Request request = new Request.Builder().url(server.url("/api/v1/users")).get().build(); 53 | Response response = client.newCall(request).execute(); 54 | 55 | To cleanup after using the Mock Web Server: 56 | 57 |    server.shutdown(); 58 | 59 | ### Setting expectations ### 60 | 61 | The Mock Web Server provides a DSL for setting expectations. The entry point to the DSL is the ``expect()`` method. 62 | 63 | For example: 64 | 65 | server.expect().withPath("/api/v1/users").andReturn(200, "admin").once(); 66 | 67 | With the code above, we tell the Mock Web Server that the first request send to ``/api/v1/users`` should return ``admin`` with HTTP status code 200. 68 | Follow up request will result in Http status code 404 **(not found)**. 69 | 70 | If instead of just once you would like the expected behavior multiple times you can use ``times(int number)``: 71 | 72 | server.expect().withPath("/api/v1/users").andReturn(200, "admin").times(2); 73 | 74 | And if after the first two times you would like to change the response: 75 | 76 | server.expect().withPath("/api/v1/users").andReturn(200, "admin").times(2); 77 | server.expect().withPath("/api/v1/users").andReturn(200, "admin root").once(); 78 | 79 | To set an infinite number of times you can use ``always()``. 80 | 81 | server.expect().withPath("/api/v1/users").andReturn(200, "admin").always(); 82 | 83 | 84 | ### Serializing response bodies ### 85 | 86 | All the snippets above are using String responses. For complex JSON or Yaml objects handcrafting Strings can be tedious. So the DSL also supports passing objects which will be serialized to JSON / YAML. 87 | 88 | In this example we are going to use the [User class](src/test/groovy/io/fabric8/mockwebserver/User.groovy) and pass an instance of it to the Mock Web Server: 89 | 90 | server.expect().get().withPath("/api/v1/users").andReturn(200, new User(1L, "admin", "true").always(); 91 | Request request = new Request.Builder().url(server.url("/api/v1/users")).get().build(); 92 | Response response = client.newCall(request).execute(); 93 | 94 | In this case the response boody should looks like this: 95 | 96 | { 97 | "id": 1, 98 | "username": "admin", 99 | "enabled": true 100 | } 101 | 102 | ### Using WebSockets ### 103 | 104 | To support mock of web sockets this wrapper allows you to either specify a ``request/response`` style or define a sequence of messages and the time each message will be fired. 105 | 106 | #### Using Request Response style #### 107 | 108 | server.expect().get().withPath("/api/v1/users/shell") 109 | .andUpgradeToWebSocket() 110 | .open() 111 | .expect("create root").andEmit("CREATED").once() 112 | .expect("delete root").andEmit("DELETED").once() 113 | .done() 114 | .once() 115 | 116 | #### Emitting timed Web Socket messages #### 117 | 118 | server.expect().withPath("/api/v1/users/watch") 119 | .andUpgradeToWebSocket() 120 | .open() 121 | .waitFor(1000).andEmit("root - CREATED") 122 | .waitFor(1500).andEmit("root - DELETED") 123 | .done() 124 | .once() 125 | 126 | ### CRUD Mocking ### 127 | 128 | Often a rest API, will act like a CRUD (create, read, update & delete). So, it makes sense to have a different approach on setting expectations. 129 | Instead of setting expectations for every single request, to take advantage of the crud nature of the API. This means that a get operation will return the resource, that has been previously created. 130 | In the same spirit a delete or update request, will act on a previously created resource and so on. 131 | 132 | To use CRUD mocking, the user will have to implement two interfaces: 133 | 134 | - An AttributeExtractor 135 | - A ResponseComposer 136 | 137 | The AttributeExtractor extracts attributes, from the path of the request and from the actual resource. Attributes is what is used to match paths to resources. 138 | In order to have a successful match, the path attributes need to be a subset of the actual resource attributes: 139 | The actual methods that need to be implemented are: 140 | 141 | AttributeSet extract(String path); 142 | AttributeSet extract(T object); 143 | 144 | 145 | Each get request, may result in one or more resources (based on the attributes, as explained above). To compose multiple resources into a single response, the ResponseComposer comes into play. 146 | The ResponseComposer is a simple object that specifies how multiple Strings can be composed into a single one: 147 | 148 | String compose(Collection items); 149 | 150 | 151 | #### More Examples #### 152 | 153 | This wrapper has been extensively used at: 154 | 155 | - [Kubernetes Client](https://github.com/fabric8io/kubernetes-client) 156 | - [Docker Client](https://github.com/fabric8io/docker-client) 157 | -------------------------------------------------------------------------------- /release.groovy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/groovy 2 | /** 3 | * Copyright (C) 2015 Red Hat, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | def updateDependencies(source){ 18 | 19 | def properties = [] 20 | 21 | updatePropertyVersion{ 22 | updates = properties 23 | repository = source 24 | project = 'fabric8io/mockwebserver' 25 | } 26 | } 27 | 28 | def stage(){ 29 | return stageProject{ 30 | project = 'fabric8io/mockwebserver' 31 | useGitTagForNextVersion = true 32 | } 33 | } 34 | 35 | def approveRelease(project){ 36 | def releaseVersion = project[1] 37 | approve{ 38 | room = null 39 | version = releaseVersion 40 | console = null 41 | environment = 'fabric8' 42 | } 43 | } 44 | 45 | def release(project){ 46 | releaseProject{ 47 | stagedProject = project 48 | useGitTagForNextVersion = true 49 | helmPush = false 50 | groupId = 'io.fabric8' 51 | githubOrganisation = 'fabric8io' 52 | artifactIdToWatchInCentral = 'mockwebserver' 53 | artifactExtensionToWatchInCentral = 'jar' 54 | } 55 | } 56 | 57 | def mergePullRequest(prId){ 58 | mergeAndWaitForPullRequest{ 59 | project = 'fabric8io/mockwebserver' 60 | pullRequestId = prId 61 | } 62 | 63 | } 64 | return this; 65 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/Context.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver; 17 | 18 | import com.fasterxml.jackson.databind.ObjectMapper; 19 | 20 | public class Context { 21 | 22 | private final ObjectMapper mapper; 23 | 24 | public Context() { 25 | this(new ObjectMapper()); 26 | } 27 | 28 | public Context(ObjectMapper mapper) { 29 | this.mapper = mapper; 30 | } 31 | 32 | public ObjectMapper getMapper() { 33 | return mapper; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/DefaultMockServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver; 18 | 19 | import io.fabric8.mockwebserver.dsl.MockServerExpectation; 20 | import io.fabric8.mockwebserver.internal.MockDispatcher; 21 | import io.fabric8.mockwebserver.internal.MockSSLContextFactory; 22 | import io.fabric8.mockwebserver.internal.MockServerExpectationImpl; 23 | import okhttp3.mockwebserver.Dispatcher; 24 | import okhttp3.mockwebserver.MockWebServer; 25 | import okhttp3.mockwebserver.RecordedRequest; 26 | 27 | import java.io.IOException; 28 | import java.net.InetAddress; 29 | import java.net.Proxy; 30 | import java.util.HashMap; 31 | import java.util.Map; 32 | import java.util.Queue; 33 | import java.util.concurrent.TimeUnit; 34 | import java.util.concurrent.atomic.AtomicBoolean; 35 | import java.util.concurrent.atomic.AtomicInteger; 36 | import java.util.concurrent.atomic.AtomicReference; 37 | 38 | public class DefaultMockServer implements MockServer { 39 | 40 | private final Context context; 41 | private final boolean useHttps; 42 | private final MockWebServer server; 43 | private final Map> responses; 44 | private final AtomicInteger lastRequestCount; 45 | private final AtomicReference lastRequest; 46 | 47 | private final AtomicBoolean initialized = new AtomicBoolean(); 48 | private final AtomicBoolean shutdown = new AtomicBoolean(); 49 | 50 | public DefaultMockServer() { 51 | this(new Context(), new MockWebServer(), new HashMap<>(), false); 52 | } 53 | 54 | public DefaultMockServer(boolean useHttps) { 55 | this(new Context(), new MockWebServer(), new HashMap<>(), useHttps); 56 | } 57 | 58 | public DefaultMockServer(MockWebServer server, Map> responses, boolean useHttps) { 59 | this(new Context(), server, responses, useHttps); 60 | } 61 | 62 | public DefaultMockServer(Context context, MockWebServer server, Map> responses, boolean useHttps) { 63 | this(context, server, responses, new MockDispatcher(responses), useHttps); 64 | } 65 | 66 | public DefaultMockServer(Context context, MockWebServer server, Map> responses, Dispatcher dispatcher, boolean useHttps) { 67 | this.context = context; 68 | this.useHttps = useHttps; 69 | this.server = server; 70 | this.responses = responses; 71 | this.lastRequest = new AtomicReference<>(); 72 | this.lastRequestCount = new AtomicInteger(0); 73 | this.server.setDispatcher(dispatcher); 74 | } 75 | 76 | 77 | private void startInternal() { 78 | if (initialized.compareAndSet(false, true)) { 79 | if (useHttps) { 80 | server.useHttps(MockSSLContextFactory.create().getSocketFactory(), false); 81 | } 82 | onStart(); 83 | } 84 | } 85 | 86 | private void shutdownInternal() { 87 | if (shutdown.compareAndSet(false, true)) { 88 | onShutdown(); 89 | } 90 | } 91 | 92 | public final void start() { 93 | try { 94 | startInternal(); 95 | server.start(); 96 | } catch (IOException e) { 97 | throw new MockServerException("Exception when starting DefaultMockServer", e); 98 | } 99 | } 100 | 101 | public final void start(int port) { 102 | try { 103 | startInternal(); 104 | server.start(port); 105 | } catch (IOException e) { 106 | throw new MockServerException("Exception when starting DefaultMockServer with port", e); 107 | } 108 | } 109 | 110 | public final void start(InetAddress inetAddress, int port) { 111 | try { 112 | startInternal(); 113 | server.start(inetAddress, port); 114 | } catch (IOException e) { 115 | throw new MockServerException("Exception when starting DefaultMockServer with InetAddress and port", e); 116 | } 117 | } 118 | 119 | public final void shutdown() { 120 | try { 121 | server.shutdown(); 122 | } catch (IOException e) { 123 | throw new MockServerException("Exception when stopping DefaultMockServer", e); 124 | } finally { 125 | shutdownInternal(); 126 | } 127 | } 128 | 129 | /** 130 | * {@inheritDoc} 131 | */ 132 | @Override 133 | public String url(String path) { 134 | return server.url(path).toString(); 135 | } 136 | 137 | /** 138 | * {@inheritDoc} 139 | */ 140 | @Override 141 | public int getPort() { 142 | return server.getPort(); 143 | } 144 | 145 | /** 146 | * {@inheritDoc} 147 | */ 148 | @Override 149 | public String getHostName() { 150 | return server.getHostName(); 151 | } 152 | 153 | /** 154 | * {@inheritDoc} 155 | */ 156 | @Override 157 | public Proxy toProxyAddress() { 158 | return server.toProxyAddress(); 159 | } 160 | /** 161 | * {@inheritDoc} 162 | */ 163 | @Override 164 | public MockServerExpectation expect() { 165 | return new MockServerExpectationImpl(responses, context); 166 | } 167 | 168 | /** 169 | * {@inheritDoc} 170 | */ 171 | @Override 172 | public int getRequestCount() { 173 | return server.getRequestCount(); 174 | } 175 | 176 | /** 177 | * {@inheritDoc} 178 | */ 179 | @Override 180 | public RecordedRequest takeRequest() throws InterruptedException { 181 | return server.takeRequest(); 182 | } 183 | 184 | /** 185 | * {@inheritDoc} 186 | */ 187 | @Override 188 | public RecordedRequest takeRequest(long timeout, TimeUnit unit) throws InterruptedException { 189 | return server.takeRequest(timeout, unit); 190 | } 191 | 192 | /** 193 | * {@inheritDoc} 194 | */ 195 | @Override 196 | public synchronized RecordedRequest getLastRequest() throws InterruptedException { 197 | if (lastRequest.get() != null && getRequestCount() == lastRequestCount.get()) { 198 | return lastRequest.get(); 199 | } 200 | int requestCount = getRequestCount() - lastRequestCount.getAndSet(getRequestCount()); 201 | RecordedRequest latestRequest = null; 202 | while (requestCount-- > 0) { 203 | latestRequest = takeRequest(); 204 | } 205 | lastRequest.set(latestRequest); 206 | return latestRequest; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/MockServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver; 17 | 18 | import io.fabric8.mockwebserver.dsl.MockServerExpectation; 19 | import okhttp3.mockwebserver.RecordedRequest; 20 | 21 | import java.net.Proxy; 22 | import java.util.concurrent.TimeUnit; 23 | 24 | public interface MockServer { 25 | 26 | /** 27 | * This method is called right before start. Override it to add extra initialization. 28 | */ 29 | default void onStart() { 30 | } 31 | 32 | /** 33 | * This method is called right after shutdown. Override it to add extra cleanup. 34 | */ 35 | default void onShutdown() { 36 | } 37 | 38 | /** 39 | * The port for the {@link okhttp3.mockwebserver.MockWebServer}. 40 | * 41 | * @return the MockWebServer port. 42 | */ 43 | int getPort(); 44 | 45 | /** 46 | * The host name for the {@link okhttp3.mockwebserver.MockWebServer}. 47 | * @return the MockWebServer host name; 48 | */ 49 | String getHostName(); 50 | 51 | /** 52 | * Returns a {@link Proxy} for the {@link okhttp3.mockwebserver.MockWebServer} with the current HostName and Port. 53 | * 54 | * @return a Proxy for the MockWebServer. 55 | */ 56 | Proxy toProxyAddress(); 57 | 58 | /** 59 | * Returns a String URL for connecting to this server. 60 | * 61 | * @param path the request path, such as "/". 62 | */ 63 | String url(String path); 64 | 65 | /** 66 | * Returns a {@link MockServerExpectation} to set the expectations. 67 | * 68 | * @return the MockServerExpectation builder. 69 | */ 70 | MockServerExpectation expect(); 71 | 72 | /** 73 | * Returns the number of HTTP requests received thus far by this server. This may exceed the 74 | * number of HTTP connections when connection reuse is in practice. 75 | */ 76 | int getRequestCount(); 77 | 78 | /** 79 | * Awaits the next HTTP request, removes it, and returns it. Callers should use this to verify the 80 | * request was sent as intended. This method will block until the request is available, possibly 81 | * forever. 82 | * 83 | * @return the head of the request queue 84 | */ 85 | RecordedRequest takeRequest() throws InterruptedException; 86 | 87 | /** 88 | * Awaits the next HTTP request (waiting up to the specified wait time if necessary), removes it, 89 | * and returns it. Callers should use this to verify the request was sent as intended within the 90 | * given time. 91 | * 92 | * @param timeout how long to wait before giving up, in units of {@code unit} 93 | * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter 94 | * @return the head of the request queue 95 | */ 96 | RecordedRequest takeRequest(long timeout, TimeUnit unit) throws InterruptedException; 97 | 98 | /** 99 | * Returns the last (most recent) HTTP request processed by the {@link okhttp3.mockwebserver.MockWebServer}. 100 | * 101 | * n.b. This method clears the request queue. 102 | * 103 | * @return the most recent RecordedRequest or null if none was processed. 104 | */ 105 | RecordedRequest getLastRequest() throws InterruptedException; 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/MockServerException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver; 17 | 18 | public class MockServerException extends RuntimeException { 19 | 20 | private static final long serialVersionUID = 2158577731194403856L; 21 | 22 | public MockServerException(String message) { 23 | super(message); 24 | } 25 | 26 | public MockServerException(String message, Throwable cause) { 27 | super(message, cause); 28 | } 29 | 30 | /** 31 | * Wraps the provided {@link Throwable} in a MockServerException in case it's checked exception. 32 | * 33 | *

For RuntimeException instances, the original exception is returned. 34 | * 35 | * @param cause Throwable to wrap. 36 | * @return the original exception in case it's unchecked, or a MockServerException wrapping it. 37 | */ 38 | public static RuntimeException launderThrowable(Throwable cause) { 39 | return launderThrowable("An error has occurred.", cause); 40 | } 41 | 42 | /** 43 | * Wraps the provided {@link Throwable} in a MockServerException in case it's checked exception. 44 | * 45 | *

For RuntimeException instances, the original exception is returned. 46 | * 47 | * @param message Message to use for the exception. 48 | * @param cause Throwable to wrap. 49 | * @return the original exception in case it's unchecked, or a MockServerException wrapping it. 50 | */ 51 | public static RuntimeException launderThrowable(String message, Throwable cause) { 52 | if (cause instanceof RuntimeException) { 53 | return (RuntimeException) cause; 54 | } else if (cause instanceof Error) { 55 | throw (Error) cause; 56 | } else if (cause instanceof InterruptedException) { 57 | Thread.currentThread().interrupt(); 58 | } 59 | throw new MockServerException(message , cause); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/ServerRequest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver; 17 | 18 | public interface ServerRequest { 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/ServerResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver; 17 | 18 | import okhttp3.mockwebserver.MockResponse; 19 | import okhttp3.mockwebserver.RecordedRequest; 20 | 21 | public interface ServerResponse { 22 | 23 | boolean isRepeatable(); 24 | 25 | MockResponse toMockResponse(RecordedRequest recordedRequest); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/crud/Attribute.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud; 17 | 18 | import java.util.Collections; 19 | import java.util.List; 20 | import java.util.Objects; 21 | import java.util.stream.Collectors; 22 | 23 | import static io.fabric8.mockwebserver.crud.AttributeType.WITH; 24 | 25 | public class Attribute { 26 | 27 | private final Key key; 28 | private final List values; 29 | private final AttributeType type; 30 | 31 | 32 | public Attribute(Key key, List values, AttributeType type) { 33 | this.key = key; 34 | this.values = values; 35 | this.type = type; 36 | } 37 | 38 | public Attribute(Key key, Value value, AttributeType type) { 39 | this(key, Collections.singletonList(value), type); 40 | } 41 | 42 | public Attribute(String key, String value, AttributeType type) { 43 | this(new Key(key), new Value(value), type); 44 | } 45 | 46 | public Attribute(String key, List values, AttributeType type) { 47 | this(new Key(key), values.stream().map(Value::new).collect(Collectors.toList()), type); 48 | } 49 | 50 | public Attribute(Key key, Value value) { 51 | this(key,value,WITH); 52 | } 53 | 54 | public Attribute(String key, String value) { 55 | this(new Key(key), new Value(value)); 56 | } 57 | 58 | public Key getKey() { 59 | return key; 60 | } 61 | 62 | public List getValues() { 63 | return values; 64 | } 65 | 66 | @Override 67 | public boolean equals(Object o) { 68 | if (this == o) return true; 69 | if (o == null || getClass() != o.getClass()) return false; 70 | Attribute attribute = (Attribute) o; 71 | return Objects.equals(key, attribute.key) && Objects.equals(values, attribute.values); 72 | } 73 | 74 | @Override 75 | public int hashCode() { 76 | return Objects.hash(key, values); 77 | } 78 | 79 | @Override 80 | public String toString() { 81 | return "{" + 82 | "key:" + key + 83 | ", values:" + values + 84 | '}'; 85 | } 86 | 87 | public AttributeType getType() { 88 | return type; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/crud/AttributeExtractor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud; 17 | 18 | public interface AttributeExtractor { 19 | 20 | AttributeSet fromPath(String path); 21 | 22 | AttributeSet fromResource(String resource); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/crud/AttributeSet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud; 17 | 18 | import java.util.Arrays; 19 | import java.util.Collection; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | import java.util.Objects; 23 | 24 | public class AttributeSet { 25 | 26 | // Package-private for testing 27 | final Map attributes; 28 | 29 | public static AttributeSet merge(AttributeSet... attributeSets) { 30 | Map all = new HashMap<>(); 31 | if (attributeSets != null) { 32 | for (AttributeSet f : attributeSets) { 33 | if (f != null && f.attributes != null) { 34 | all.putAll(f.attributes); 35 | } 36 | } 37 | } 38 | return new AttributeSet(all); 39 | } 40 | 41 | public static AttributeSet map(Attribute... attributes) { 42 | Map all = new HashMap<>(); 43 | if (attributes != null) { 44 | for (Attribute a : attributes) { 45 | all.put(a.getKey(), a); 46 | } 47 | } 48 | return new AttributeSet(all); 49 | } 50 | 51 | public AttributeSet(Attribute... attributes) { 52 | this(Arrays.asList(attributes)); 53 | } 54 | 55 | public AttributeSet(Collection attributes) { 56 | this(AttributeSet.map(attributes.toArray(new Attribute[0])).attributes); 57 | } 58 | 59 | public AttributeSet(Map attributes) { 60 | this.attributes = attributes; 61 | } 62 | 63 | public AttributeSet add(Attribute... attr) { 64 | Map all = new HashMap<>(attributes); 65 | for(Attribute a : attr) { 66 | all.put(a.getKey(), a); 67 | } 68 | return new AttributeSet(all); 69 | } 70 | 71 | public boolean containsKey(String key) { 72 | return containsKey(new Key(key)); 73 | } 74 | 75 | public boolean containsKey(Key key) { 76 | return attributes.containsKey(key); 77 | } 78 | 79 | /** 80 | * matches if attributes in db has (or doesn't if WITHOUT command) a set of candidate attributes 81 | * Also supports EXISTS and NOT_EXISTS operations 82 | * @param candidate - set of candidate attributes 83 | * @return match 84 | */ 85 | public boolean matches(AttributeSet candidate) { 86 | return candidate.attributes.values() 87 | .stream() 88 | .allMatch(this::satisfiesAttribute); 89 | } 90 | 91 | private boolean satisfiesAttribute(Attribute c) { 92 | switch (c.getType()) { 93 | case EXISTS: 94 | return attributes.containsKey(c.getKey()); 95 | case NOT_EXISTS: 96 | return !attributes.containsKey(c.getKey()); 97 | case IN: { 98 | if (attributes.containsKey(c.getKey())) { 99 | if (attributes.get(c.getKey()).getValues().size() > 1) { 100 | throw new IllegalArgumentException("Attribute " + c.getKey() + " has multiple values, can't use IN operation"); 101 | } 102 | return c.getValues().contains(attributes.get(c.getKey()).getValues().iterator().next()); 103 | } 104 | return false; 105 | } 106 | case NOT_IN: { 107 | if (attributes.containsKey(c.getKey())) { 108 | if (attributes.get(c.getKey()).getValues().size() > 1) { 109 | throw new IllegalArgumentException("Attribute " + c.getKey() + " has multiple values, can't use NOT_IN operation"); 110 | } 111 | return !c.getValues().contains(attributes.get(c.getKey()).getValues().iterator().next()); 112 | } 113 | return true; 114 | } 115 | case WITHOUT: 116 | return !attributes.containsValue(c); 117 | case WITH: 118 | default: 119 | return attributes.containsValue(c); 120 | } 121 | } 122 | 123 | @Override 124 | public boolean equals(Object o) { 125 | if (this == o) return true; 126 | if (o == null || getClass() != o.getClass()) return false; 127 | AttributeSet that = (AttributeSet) o; 128 | return Objects.equals(attributes, that.attributes); 129 | } 130 | 131 | @Override 132 | public int hashCode() { 133 | return Objects.hash(attributes); 134 | } 135 | 136 | public Attribute getAttribute(String key) { 137 | return attributes.get(new Key(key)); 138 | } 139 | 140 | @Override 141 | public String toString() { 142 | return "{" + 143 | "attributes: " + attributes + 144 | '}'; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/crud/AttributeType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud; 17 | 18 | public enum AttributeType { 19 | WITH, WITHOUT, EXISTS, NOT_EXISTS, IN, NOT_IN 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/crud/CrudDispatcher.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud; 17 | 18 | import com.fasterxml.jackson.databind.JsonNode; 19 | import io.fabric8.mockwebserver.Context; 20 | import io.fabric8.mockwebserver.MockServerException; 21 | import io.fabric8.zjsonpatch.JsonPatch; 22 | import okhttp3.mockwebserver.Dispatcher; 23 | import okhttp3.mockwebserver.MockResponse; 24 | import okhttp3.mockwebserver.RecordedRequest; 25 | 26 | import java.net.HttpURLConnection; 27 | import java.util.ArrayList; 28 | import java.util.Collections; 29 | import java.util.LinkedHashMap; 30 | import java.util.List; 31 | import java.util.Map; 32 | 33 | public class CrudDispatcher extends Dispatcher { 34 | 35 | private static final String POST = "POST"; 36 | private static final String PUT = "PUT"; 37 | private static final String PATCH = "PATCH"; 38 | private static final String GET = "GET"; 39 | private static final String DELETE = "DELETE"; 40 | 41 | protected final Map map = Collections.synchronizedMap(new LinkedHashMap<>()); 42 | 43 | protected final Context context; 44 | protected final AttributeExtractor attributeExtractor; 45 | protected final ResponseComposer responseComposer; 46 | 47 | public CrudDispatcher(Context context, AttributeExtractor attributeExtractor, ResponseComposer responseComposer) { 48 | this.context = context; 49 | this.attributeExtractor = attributeExtractor; 50 | this.responseComposer = responseComposer; 51 | } 52 | 53 | @Override 54 | public MockResponse dispatch(RecordedRequest request) { 55 | String path = request.getPath(); 56 | switch (request.getMethod().toUpperCase()) { 57 | case POST: 58 | return handleCreate(request); 59 | case PUT: 60 | return handleUpdate(request); 61 | case PATCH: 62 | return handlePatch(request); 63 | case GET: 64 | return handleGet(path); 65 | case DELETE: 66 | return handleDelete(path); 67 | default: 68 | return null; 69 | } 70 | } 71 | 72 | public MockResponse handleCreate(RecordedRequest request) { 73 | return handleCreate(request.getPath(), request.getBody().readUtf8()); 74 | } 75 | 76 | /** 77 | * Adds the specified object to the in-memory db. 78 | * 79 | * @param path for the request. 80 | * @param body Request body as String (UTF-8). 81 | * @return a MockResponse to be dispatched. 82 | */ 83 | public MockResponse handleCreate(String path, String body) { 84 | MockResponse response = new MockResponse(); 85 | AttributeSet features = AttributeSet.merge(attributeExtractor.fromPath(path), attributeExtractor.fromResource(body)); 86 | synchronized (map) { 87 | map.put(features, body); 88 | } 89 | response.setBody(body); 90 | response.setResponseCode(202); 91 | return response; 92 | } 93 | 94 | public MockResponse handlePatch(RecordedRequest request) { 95 | return handlePatch(request.getPath(), request.getBody().readUtf8()); 96 | } 97 | 98 | /** 99 | * Patches the specified object to the in-memory db. 100 | * 101 | * @param path for the request. 102 | * @param body Request body as String (UTF-8). 103 | * @return a MockResponse to be dispatched. 104 | */ 105 | public MockResponse handlePatch(String path, String body) { 106 | MockResponse response = new MockResponse(); 107 | String existingObjectBody = doGet(path); 108 | if (existingObjectBody == null) { 109 | response.setResponseCode(404); 110 | } else { 111 | try { 112 | JsonNode patch = context.getMapper().readTree(body); 113 | JsonNode source = context.getMapper().readTree(existingObjectBody); 114 | JsonNode updated = JsonPatch.apply(patch, source); 115 | String updatedAsString = context.getMapper().writeValueAsString(updated); 116 | AttributeSet features = AttributeSet.merge(attributeExtractor.fromPath(path), 117 | attributeExtractor.fromResource(updatedAsString)); 118 | synchronized (map) { 119 | map.put(features, updatedAsString); 120 | } 121 | response.setResponseCode(202); 122 | response.setBody(updatedAsString); 123 | } catch (Exception e) { 124 | throw new MockServerException("Exception when handling CRUD patch", e); 125 | } 126 | 127 | } 128 | return response; 129 | } 130 | 131 | public MockResponse handleUpdate(RecordedRequest request) { 132 | return handleUpdate(request.getPath(), request.getBody().readUtf8()); 133 | } 134 | 135 | /** 136 | * Updates the specified object to the in-memory db. 137 | * 138 | * @param path for the request. 139 | * @param body Request body as String (UTF-8). 140 | * @return a MockResponse to be dispatched. 141 | */ 142 | public MockResponse handleUpdate(String path, String body) { 143 | final String currentItem = doGet(path); 144 | final MockResponse response = handleCreate(path, body); 145 | if (currentItem == null) { 146 | response.setResponseCode(HttpURLConnection.HTTP_CREATED); 147 | } 148 | return response; 149 | } 150 | 151 | /** 152 | * Performs a get for the corresponding object from the in-memory db. 153 | * 154 | * @param path for the request. 155 | * @return a MockResponse to be dispatched. 156 | */ 157 | public MockResponse handleGet(String path) { 158 | MockResponse response = new MockResponse(); 159 | 160 | String body = doGet(path); 161 | if (body == null) { 162 | response.setResponseCode(404); 163 | } else { 164 | response.setResponseCode(200); 165 | response.setBody(body); 166 | } 167 | return response; 168 | } 169 | 170 | 171 | /** 172 | * Performs a delete for the corresponding object from the in-memory db. 173 | * 174 | * @param path for the request. 175 | * @return a MockResponse to be dispatched. 176 | */ 177 | public MockResponse handleDelete(String path) { 178 | MockResponse response = new MockResponse(); 179 | List items = new ArrayList<>(); 180 | AttributeSet query = attributeExtractor.fromPath(path); 181 | 182 | synchronized (map) { 183 | for (Map.Entry entry : map.entrySet()) { 184 | if (entry.getKey().matches(query)) { 185 | items.add(entry.getKey()); 186 | } 187 | } 188 | if (!items.isEmpty()) { 189 | for (AttributeSet item : items) { 190 | map.remove(item); 191 | } 192 | response.setResponseCode(200); 193 | } else { 194 | response.setResponseCode(404); 195 | } 196 | } 197 | return response; 198 | } 199 | 200 | public Map getMap() { 201 | return map; 202 | } 203 | 204 | public AttributeExtractor getAttributeExtractor() { 205 | return attributeExtractor; 206 | } 207 | 208 | public ResponseComposer getResponseComposer() { 209 | return responseComposer; 210 | } 211 | 212 | 213 | private String doGet(String path) { 214 | List items = new ArrayList<>(); 215 | AttributeSet query = attributeExtractor.fromPath(path); 216 | synchronized (map) { 217 | for (Map.Entry entry : map.entrySet()) { 218 | if (entry.getKey().matches(query)) { 219 | items.add(entry.getValue()); 220 | } 221 | } 222 | } 223 | 224 | if (items.isEmpty()) { 225 | return null; 226 | } else if (items.size() == 1) { 227 | return items.get(0); 228 | } else { 229 | return responseComposer.compose(items); 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/crud/Key.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud; 17 | 18 | import java.util.Objects; 19 | 20 | public class Key { 21 | 22 | private final String name; 23 | 24 | public Key(String name) { 25 | this.name = name; 26 | } 27 | 28 | @Override 29 | public boolean equals(Object o) { 30 | if (this == o) return true; 31 | if (o == null || getClass() != o.getClass()) return false; 32 | Key key = (Key) o; 33 | return Objects.equals(name, key.name); 34 | } 35 | 36 | @Override 37 | public int hashCode() { 38 | return Objects.hash(name); 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return name; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/crud/ResponseComposer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud; 17 | 18 | import java.util.Collection; 19 | 20 | public interface ResponseComposer { 21 | 22 | String compose(Collection items); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/crud/Value.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud; 17 | 18 | public class Value { 19 | 20 | private static final String ANY = "*"; 21 | 22 | private final String val; 23 | 24 | public Value(String value) { 25 | this.val = value; 26 | } 27 | 28 | @Override 29 | // TODO: There's a BUG here, equals({val: "*"} is true but might have different hashCode 30 | public boolean equals(Object o) { 31 | if (this == o) { 32 | return true; 33 | } 34 | 35 | if (o == null || getClass() != o.getClass()) { 36 | return false; 37 | } 38 | 39 | if (ANY.equals(val)) { 40 | return true; 41 | } 42 | 43 | Value key = (Value) o; 44 | 45 | if (ANY.equals(key.val)) { 46 | return true; 47 | } 48 | return val != null ? val.equals(key.val) : key.val == null; 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | return val != null ? val.hashCode() : 0; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return val; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/DelayPathable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.dsl; 17 | 18 | public interface DelayPathable extends Delayable>, 19 | Pathable { 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/DelayTimesOrOnceable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.dsl; 17 | 18 | public interface DelayTimesOrOnceable extends Delayable, TimesOrOnceable { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Delayable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.dsl; 17 | 18 | import java.util.concurrent.TimeUnit; 19 | 20 | public interface Delayable { 21 | 22 | T delay(long delay, TimeUnit delayUnit); 23 | 24 | T delay(long delayInMilliseconds); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Doneable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface Doneable { 20 | T done(); 21 | } -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Emitable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface Emitable { 20 | 21 | /** 22 | * Emit an event. This will be received by the client's onMessage. 23 | * @param event 24 | * @return 25 | */ 26 | T andEmit(Object event); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/EventDoneable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface EventDoneable extends Eventable>, Doneable { 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Eventable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface Eventable { 20 | 21 | Emitable> expect(Object in); 22 | 23 | Emitable> expectHttpRequest(final String path); 24 | 25 | Emitable> expectSentWebSocketMessage(final Object in); 26 | 27 | Emitable waitFor(long millis); 28 | 29 | Emitable immediately(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Failable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface Failable { 20 | 21 | T failure(Object response, Exception e); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Function.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface Function { 20 | O apply(I input); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/HttpHeaderable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface HttpHeaderable { 20 | 21 | T withHeader(String header); 22 | 23 | T withHeader(String name, String value); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/HttpMethod.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public enum HttpMethod { 20 | 21 | GET, 22 | POST, 23 | PUT, 24 | PATCH, 25 | DELETE, 26 | OPTIONS, 27 | CONNECT, 28 | ANY 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/HttpMethodable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface HttpMethodable { 20 | 21 | T any(); 22 | 23 | T post(); 24 | 25 | T get(); 26 | 27 | T put(); 28 | 29 | T delete(); 30 | 31 | T patch(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/HttpStatusable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface HttpStatusable { 20 | 21 | T withStatus(int statusCode); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/MockServerExpectation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.dsl; 17 | 18 | public interface MockServerExpectation extends HttpMethodable>>>, 19 | DelayPathable>>, 20 | ReturnOrWebsocketable>, 21 | TimesOnceableOrHttpHeaderable { 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Onceable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.dsl; 17 | 18 | public interface Onceable { 19 | 20 | T once(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Openable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface Openable { 20 | 21 | T open(Object... response); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Pathable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface Pathable { 20 | 21 | T withPath(String path); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Replyable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | import java.util.List; 20 | 21 | import io.fabric8.mockwebserver.utils.BodyProvider; 22 | import io.fabric8.mockwebserver.utils.ResponseProvider; 23 | 24 | public interface Replyable { 25 | 26 | T andReply(int statusCode, BodyProvider contentSupplier); 27 | 28 | T andReply(ResponseProvider contentSupplier); 29 | 30 | T andReplyChunked(int statusCode, BodyProvider> content); 31 | 32 | T andReplyChunked(ResponseProvider> content); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/ReturnOrWebsocketable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface ReturnOrWebsocketable extends Returnable, WebSocketable>, Replyable { 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Returnable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface Returnable { 20 | 21 | T andReturn(int statusCode, Object content); 22 | 23 | T andReturnChunked(int statusCode, Object... content); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Schedulable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.dsl; 17 | 18 | import java.util.concurrent.TimeUnit; 19 | 20 | public interface Schedulable { 21 | 22 | T every(long initialDelay, long period, TimeUnit timeUnit); 23 | 24 | T every(long period, TimeUnit timeUnit); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/TimesOnceableOrHttpHeaderable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.dsl; 17 | 18 | public interface TimesOnceableOrHttpHeaderable extends HttpHeaderable>, TimesOrOnceable { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/TimesOrOnceable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.dsl; 17 | 18 | public interface TimesOrOnceable extends Timesable, 19 | Onceable { 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/TimesSchedulableOrOnceable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface TimesSchedulableOrOnceable extends TimesOrOnceable, 20 | Schedulable> { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/Timesable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.dsl; 17 | 18 | public interface Timesable { 19 | 20 | T always(); 21 | 22 | T times(int times); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/WebSocketSessionBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | public interface WebSocketSessionBuilder extends 20 | Openable>, 21 | Failable { 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/dsl/WebSocketable.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.dsl; 18 | 19 | import java.util.concurrent.ScheduledExecutorService; 20 | 21 | public interface WebSocketable { 22 | 23 | T andUpgradeToWebSocket(); 24 | 25 | /** 26 | * @deprecated the provided ScheduledExecutorService is not used, use {@link #andUpgradeToWebSocket()} instead. 27 | * The ExecutorService is handled internally by WebSocketSession, external executors are no longer allowed. 28 | */ 29 | @Deprecated 30 | T andUpgradeToWebSocket(ScheduledExecutorService executor); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/internal/ChunkedResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.internal; 17 | 18 | import java.util.List; 19 | import java.util.concurrent.TimeUnit; 20 | 21 | import io.fabric8.mockwebserver.ServerResponse; 22 | import io.fabric8.mockwebserver.utils.ResponseProvider; 23 | import io.fabric8.mockwebserver.utils.ResponseProviders; 24 | 25 | import okhttp3.mockwebserver.MockResponse; 26 | import okhttp3.mockwebserver.RecordedRequest; 27 | 28 | public class ChunkedResponse implements ServerResponse { 29 | 30 | private static final int DEFAULT_MAX_CHUNK_SIZE = 204800; 31 | private final ResponseProvider> bodyProvider; 32 | private final boolean repeatable; 33 | private final long responseDelay; 34 | private final TimeUnit responseDelayUnit; 35 | 36 | public ChunkedResponse(boolean repeatable, int statusCode, String... body) { 37 | this(repeatable, ResponseProviders.ofAll(statusCode, body)); 38 | } 39 | 40 | public ChunkedResponse(boolean repeatable, ResponseProvider> bodyProvider) { 41 | this(repeatable, 0, TimeUnit.MILLISECONDS, bodyProvider); 42 | } 43 | 44 | public ChunkedResponse(boolean repeatable, int statusCode, long responseDelay, TimeUnit responseDelayUnit, String... body) { 45 | this(repeatable, responseDelay, responseDelayUnit, ResponseProviders.ofAll(statusCode, body)); 46 | } 47 | 48 | public ChunkedResponse(boolean repeatable, long responseDelay, TimeUnit responseDelayUnit, ResponseProvider> bodyProvider) { 49 | this.bodyProvider = bodyProvider; 50 | this.repeatable = repeatable; 51 | this.responseDelay = responseDelay; 52 | this.responseDelayUnit = responseDelayUnit; 53 | } 54 | 55 | public ResponseProvider> getBodyProvider() { 56 | return bodyProvider; 57 | } 58 | 59 | @Override 60 | public MockResponse toMockResponse(RecordedRequest request) { 61 | MockResponse mockResponse = new MockResponse(); 62 | mockResponse.setHeaders(bodyProvider.getHeaders()); 63 | mockResponse.setChunkedBody(concatBody(request), DEFAULT_MAX_CHUNK_SIZE); 64 | mockResponse.setResponseCode(bodyProvider.getStatusCode(request)); 65 | 66 | if (responseDelay > 0) { 67 | mockResponse.setBodyDelay(responseDelay, responseDelayUnit); 68 | } 69 | 70 | return mockResponse; 71 | } 72 | 73 | private String concatBody(RecordedRequest request) { 74 | StringBuilder sb = new StringBuilder(); 75 | for (String s : bodyProvider.getBody(request)) { 76 | sb.append(s); 77 | } 78 | return sb.toString(); 79 | } 80 | 81 | @Override 82 | public boolean isRepeatable() { 83 | return repeatable; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/internal/InlineWebSocketSessionBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.internal; 18 | 19 | import com.fasterxml.jackson.core.JsonProcessingException; 20 | import com.fasterxml.jackson.databind.ObjectMapper; 21 | import io.fabric8.mockwebserver.Context; 22 | import io.fabric8.mockwebserver.MockServerException; 23 | import io.fabric8.mockwebserver.dsl.Emitable; 24 | import io.fabric8.mockwebserver.dsl.EventDoneable; 25 | import io.fabric8.mockwebserver.dsl.Function; 26 | import io.fabric8.mockwebserver.dsl.TimesOrOnceable; 27 | import io.fabric8.mockwebserver.dsl.WebSocketSessionBuilder; 28 | 29 | import java.util.ArrayDeque; 30 | import java.util.ArrayList; 31 | import java.util.Collections; 32 | import java.util.List; 33 | import java.util.Queue; 34 | 35 | public class InlineWebSocketSessionBuilder implements WebSocketSessionBuilder, EventDoneable { 36 | 37 | private static final ObjectMapper MAPPER = new ObjectMapper(); 38 | 39 | private final Context context; 40 | private final Function function; 41 | private WebSocketSession session; 42 | 43 | public InlineWebSocketSessionBuilder(Context context, Function function) { 44 | this.context = context; 45 | this.function = function; 46 | } 47 | 48 | @Override 49 | public EventDoneable open(Object... response) { 50 | this.session = new WebSocketSession(toWebSocketMessages(response), null, null); 51 | return this; 52 | } 53 | 54 | 55 | @Override 56 | public T failure(Object response, Exception e) { 57 | return function.apply(new WebSocketSession(Collections.emptyList(), toWebSocketMessage(response), e)); 58 | } 59 | 60 | @Override 61 | public T done() { 62 | return function.apply(session); 63 | } 64 | 65 | @Override 66 | public Emitable>> expect(final Object in) { 67 | return event -> new TimesOrOnceable>() { 68 | @Override 69 | public EventDoneable always() { 70 | enqueue(in, toWebSocketMessage(event, false)); 71 | return InlineWebSocketSessionBuilder.this; 72 | } 73 | 74 | @Override 75 | public EventDoneable once() { 76 | enqueue(in, toWebSocketMessage(event, true)); 77 | return InlineWebSocketSessionBuilder.this; 78 | } 79 | 80 | @Override 81 | public EventDoneable times(int times) { 82 | for (int i = 0; i < times; i++) { 83 | enqueue(in, toWebSocketMessage(event, true)); 84 | } 85 | return InlineWebSocketSessionBuilder.this; 86 | } 87 | }; 88 | } 89 | 90 | @Override 91 | public Emitable>> expectHttpRequest(final String path) { 92 | return event -> new TimesOrOnceable>() { 93 | @Override 94 | public EventDoneable always() { 95 | enqueueSimpleRequest(new SimpleRequest(path), toWebSocketMessage(event, false)); 96 | return InlineWebSocketSessionBuilder.this; 97 | } 98 | 99 | @Override 100 | public EventDoneable once() { 101 | enqueueSimpleRequest(new SimpleRequest(path), toWebSocketMessage(event, true)); 102 | return InlineWebSocketSessionBuilder.this; 103 | } 104 | 105 | @Override 106 | public EventDoneable times(int times) { 107 | for (int i = 0; i < times; i++) { 108 | enqueueSimpleRequest(new SimpleRequest(path), toWebSocketMessage(event, true)); 109 | } 110 | return InlineWebSocketSessionBuilder.this; 111 | } 112 | }; 113 | } 114 | 115 | @Override 116 | public Emitable>> expectSentWebSocketMessage(final Object in) { 117 | return event -> new TimesOrOnceable>() { 118 | @Override 119 | public EventDoneable always() { 120 | enqueueForSentWebSocketMessage(in, toWebSocketMessage(event, false)); 121 | return InlineWebSocketSessionBuilder.this; 122 | } 123 | 124 | @Override 125 | public EventDoneable once() { 126 | enqueueForSentWebSocketMessage(in, toWebSocketMessage(event, true)); 127 | return InlineWebSocketSessionBuilder.this; 128 | } 129 | 130 | @Override 131 | public EventDoneable times(int times) { 132 | for (int i = 0; i < times; i++) { 133 | enqueueForSentWebSocketMessage(in, toWebSocketMessage(event, true)); 134 | } 135 | return InlineWebSocketSessionBuilder.this; 136 | } 137 | }; 138 | } 139 | 140 | @Override 141 | public Emitable> waitFor(final long millis) { 142 | return event -> { 143 | session.getTimedEvents().add(toWebSocketMessage(millis, event)); 144 | return InlineWebSocketSessionBuilder.this; 145 | }; 146 | } 147 | 148 | @Override 149 | public Emitable> immediately() { 150 | return waitFor(0); 151 | } 152 | 153 | private List toWebSocketMessages(Object... messages) { 154 | List response = new ArrayList<>(); 155 | for (Object msg : messages) { 156 | response.add(toWebSocketMessage(msg)); 157 | } 158 | return response; 159 | } 160 | 161 | private WebSocketMessage toWebSocketMessage(Object content) { 162 | return toWebSocketMessage(0L, content, true); 163 | } 164 | 165 | private WebSocketMessage toWebSocketMessage(Long delay, Object content) { 166 | return toWebSocketMessage(delay, content, true); 167 | } 168 | 169 | private WebSocketMessage toWebSocketMessage(Object content, Boolean toBeRemoved) { 170 | return toWebSocketMessage(0L, content, toBeRemoved); 171 | } 172 | 173 | private WebSocketMessage toWebSocketMessage(Long delay, Object content, Boolean toBeRemoved) { 174 | if (content instanceof String) { 175 | return new WebSocketMessage(delay, (String) content, toBeRemoved); 176 | } else if (content instanceof WebSocketMessage) { 177 | return (WebSocketMessage) content; 178 | } else { 179 | try { 180 | return toWebSocketMessage(delay, MAPPER.writeValueAsString(content), toBeRemoved); 181 | } catch (JsonProcessingException e) { 182 | throw new MockServerException("Exception when mapping to WebSocketMessage", e); 183 | } 184 | } 185 | } 186 | 187 | private void enqueue(Object req, WebSocketMessage resp) { 188 | Queue queuedResponses = session.getRequestEvents().get(req); 189 | if (queuedResponses == null) { 190 | queuedResponses = new ArrayDeque<>(); 191 | session.getRequestEvents().put(req, queuedResponses); 192 | } 193 | queuedResponses.add(resp); 194 | } 195 | 196 | private void enqueueForSentWebSocketMessage(Object req, WebSocketMessage resp) { 197 | Queue queuedResponses = session.getSentWebSocketMessagesRequestEvents().get(req); 198 | if (queuedResponses == null) { 199 | queuedResponses = new ArrayDeque<>(); 200 | session.getSentWebSocketMessagesRequestEvents().put(req, queuedResponses); 201 | } 202 | queuedResponses.add(resp); 203 | } 204 | 205 | private void enqueueSimpleRequest(SimpleRequest req, WebSocketMessage resp) { 206 | Queue queuedResponses = session.getHttpRequestEvents().get(req); 207 | if (queuedResponses == null) { 208 | queuedResponses = new ArrayDeque<>(); 209 | session.getHttpRequestEvents().put(req, queuedResponses); 210 | } 211 | queuedResponses.add(resp); 212 | } 213 | 214 | } 215 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/internal/MockDispatcher.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.internal; 18 | 19 | import io.fabric8.mockwebserver.ServerRequest; 20 | import io.fabric8.mockwebserver.ServerResponse; 21 | import io.fabric8.mockwebserver.dsl.HttpMethod; 22 | import okhttp3.mockwebserver.Dispatcher; 23 | import okhttp3.mockwebserver.MockResponse; 24 | import okhttp3.mockwebserver.RecordedRequest; 25 | 26 | import java.util.Collection; 27 | import java.util.Map; 28 | import java.util.Queue; 29 | import java.util.concurrent.ConcurrentLinkedQueue; 30 | 31 | public class MockDispatcher extends Dispatcher { 32 | 33 | private final Map> responses; 34 | private final Collection webSocketSessions = new ConcurrentLinkedQueue<>(); 35 | 36 | public MockDispatcher(Map> responses) { 37 | this.responses = responses; 38 | } 39 | 40 | @Override 41 | public MockResponse dispatch(RecordedRequest request) { 42 | for (WebSocketSession webSocketSession : webSocketSessions) { 43 | webSocketSession.dispatch(request); 44 | } 45 | 46 | HttpMethod method = HttpMethod.valueOf(request.getMethod()); 47 | String path = request.getPath(); 48 | SimpleRequest key = new SimpleRequest(method, path); 49 | SimpleRequest keyForAnyMethod = new SimpleRequest(path); 50 | if (responses.containsKey(key)) { 51 | Queue queue = responses.get(key); 52 | return handleResponse(queue.peek(), queue, request); 53 | } else if (responses.containsKey(keyForAnyMethod)) { 54 | Queue queue = responses.get(keyForAnyMethod); 55 | return handleResponse(queue.peek(), queue, request); 56 | } 57 | return new MockResponse().setResponseCode(404); 58 | } 59 | 60 | private MockResponse handleResponse(ServerResponse response, Queue queue, RecordedRequest request) { 61 | if (response == null) { 62 | return new MockResponse().setResponseCode(404); 63 | } else if (!response.isRepeatable()) { 64 | queue.remove(); 65 | } 66 | if (response instanceof SimpleResponse) { 67 | SimpleResponse simpleResponse = (SimpleResponse) response; 68 | if (simpleResponse.getWebSocketSession() != null) { 69 | webSocketSessions.add(simpleResponse.getWebSocketSession()); 70 | } 71 | } 72 | return response.toMockResponse(request); 73 | } 74 | 75 | @Override 76 | public void shutdown() { 77 | webSocketSessions.forEach(WebSocketSession::shutdown); 78 | super.shutdown(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/internal/MockSSLContextFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.internal; 18 | 19 | 20 | import io.fabric8.mockwebserver.MockServerException; 21 | import io.fabric8.mockwebserver.utils.SSLUtils; 22 | 23 | import javax.net.ssl.KeyManager; 24 | import javax.net.ssl.SSLContext; 25 | 26 | public class MockSSLContextFactory { 27 | 28 | private MockSSLContextFactory() { 29 | } 30 | 31 | public static SSLContext create() { 32 | try { 33 | KeyManager[] keyManagers = SSLUtils.keyManagers(MockSSLContextFactory.class.getResourceAsStream("/ssl/fabric8.crt"), 34 | MockSSLContextFactory.class.getResourceAsStream("/ssl/fabric8"), 35 | "RSA", ""); 36 | return SSLUtils.sslContext(keyManagers, null, true); 37 | } catch (Exception e) { 38 | throw new MockServerException("Exception creating SSLContext", e); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/internal/MockServerExpectationImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.internal; 18 | 19 | import java.util.ArrayDeque; 20 | import java.util.ArrayList; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.Queue; 25 | import java.util.concurrent.ScheduledExecutorService; 26 | import java.util.concurrent.TimeUnit; 27 | import java.util.stream.Collectors; 28 | import java.util.stream.Stream; 29 | 30 | import io.fabric8.mockwebserver.Context; 31 | import io.fabric8.mockwebserver.MockServerException; 32 | import io.fabric8.mockwebserver.ServerRequest; 33 | import io.fabric8.mockwebserver.ServerResponse; 34 | import io.fabric8.mockwebserver.dsl.DelayPathable; 35 | import io.fabric8.mockwebserver.dsl.Function; 36 | import io.fabric8.mockwebserver.dsl.HttpMethod; 37 | import io.fabric8.mockwebserver.dsl.MockServerExpectation; 38 | import io.fabric8.mockwebserver.dsl.Pathable; 39 | import io.fabric8.mockwebserver.dsl.ReturnOrWebsocketable; 40 | import io.fabric8.mockwebserver.dsl.TimesOnceableOrHttpHeaderable; 41 | import io.fabric8.mockwebserver.dsl.WebSocketSessionBuilder; 42 | import io.fabric8.mockwebserver.utils.BodyProvider; 43 | import io.fabric8.mockwebserver.utils.ResponseProvider; 44 | import io.fabric8.mockwebserver.utils.ResponseProviders; 45 | 46 | import com.fasterxml.jackson.core.JsonProcessingException; 47 | 48 | import okhttp3.Headers; 49 | import okhttp3.mockwebserver.RecordedRequest; 50 | 51 | public class MockServerExpectationImpl implements MockServerExpectation { 52 | 53 | private final Context context; 54 | private final HttpMethod method; 55 | private final String path; 56 | private final ResponseProvider bodyProvider; 57 | private final ResponseProvider> chunksProvider; 58 | private final long delay; 59 | private final TimeUnit delayUnit; 60 | private final int times; 61 | 62 | private final Map> responses; 63 | 64 | public MockServerExpectationImpl(Map> responses, Context context) { 65 | this(context, HttpMethod.ANY, null, 200, null, null, 0, TimeUnit.SECONDS, 1, responses); 66 | } 67 | 68 | public MockServerExpectationImpl(Context context, HttpMethod method, String path, int statusCode, String body, String[] chunks, long delay, TimeUnit delayUnit, int times, Map> responses) { 69 | this(context, method, path, ResponseProviders.of(statusCode, body), ResponseProviders.ofAll(statusCode, chunks), delay, delayUnit, times, responses); 70 | } 71 | 72 | public MockServerExpectationImpl(Context context, HttpMethod method, String path, ResponseProvider bodyProvider, ResponseProvider> chunksProvider, long delay, TimeUnit delayUnit, int times, Map> responses) { 73 | this.context = context; 74 | this.method = method; 75 | this.path = path; 76 | this.bodyProvider = bodyProvider; 77 | this.chunksProvider = chunksProvider; 78 | this.delay = delay; 79 | this.delayUnit = delayUnit; 80 | this.times = times; 81 | this.responses = responses; 82 | } 83 | 84 | @Override 85 | public DelayPathable>> any() { 86 | return new MockServerExpectationImpl(context, HttpMethod.ANY, path, bodyProvider, chunksProvider, delay, delayUnit, times, responses); 87 | } 88 | 89 | @Override 90 | public DelayPathable>> post() { 91 | return new MockServerExpectationImpl(context, HttpMethod.POST, path, bodyProvider, chunksProvider, delay, delayUnit, times, responses); 92 | } 93 | 94 | @Override 95 | public DelayPathable>> get() { 96 | return new MockServerExpectationImpl(context, HttpMethod.GET, path, bodyProvider, chunksProvider, delay, delayUnit, times, responses); 97 | } 98 | 99 | @Override 100 | public DelayPathable>> put() { 101 | return new MockServerExpectationImpl(context, HttpMethod.PUT, path, bodyProvider, chunksProvider, delay, delayUnit, times, responses); 102 | } 103 | 104 | @Override 105 | public DelayPathable>> delete() { 106 | return new MockServerExpectationImpl(context, HttpMethod.DELETE, path, bodyProvider, chunksProvider, delay, delayUnit, times, responses); 107 | } 108 | 109 | @Override 110 | public DelayPathable>> patch() { 111 | return new MockServerExpectationImpl(context, HttpMethod.PATCH, path, bodyProvider, chunksProvider, delay, delayUnit, times, responses); 112 | } 113 | 114 | @Override 115 | public ReturnOrWebsocketable> withPath(String path) { 116 | return new MockServerExpectationImpl(context, method, path, bodyProvider, chunksProvider, delay, delayUnit, times, responses); 117 | } 118 | 119 | @Override 120 | public TimesOnceableOrHttpHeaderable andReturn(int statusCode, Object content) { 121 | return new MockServerExpectationImpl(context, method, path, ResponseProviders.of(statusCode, toString(content)), chunksProvider, delay, delayUnit, times, responses); 122 | } 123 | 124 | @Override 125 | public TimesOnceableOrHttpHeaderable andReply(int statusCode, BodyProvider content) { 126 | return andReply(ResponseProviders.of(statusCode, content)); 127 | } 128 | 129 | @Override 130 | public TimesOnceableOrHttpHeaderable andReply(ResponseProvider content) { 131 | return new MockServerExpectationImpl(context, method, path, toString(content), chunksProvider, delay, delayUnit, times, responses); 132 | } 133 | 134 | @Override 135 | public TimesOnceableOrHttpHeaderable andReturnChunked(int statusCode, Object... contents) { 136 | return new MockServerExpectationImpl(context, method, path, bodyProvider, ResponseProviders.of(statusCode, toString(contents)), delay, delayUnit, times, responses); 137 | } 138 | 139 | @Override 140 | public TimesOnceableOrHttpHeaderable andReplyChunked(int statusCode, BodyProvider> contents) { 141 | return andReplyChunked(ResponseProviders.of(statusCode, contents)); 142 | } 143 | 144 | @Override 145 | public TimesOnceableOrHttpHeaderable andReplyChunked(ResponseProvider> contents) { 146 | return new MockServerExpectationImpl(context, method, path, bodyProvider, listToString(contents), delay, delayUnit, times, responses); 147 | } 148 | 149 | @Override 150 | public Void always() { 151 | enqueue(new SimpleRequest(method, path), createResponse(true, delay, delayUnit)); 152 | return null;//Void 153 | } 154 | 155 | @Override 156 | public Void once() { 157 | enqueue(new SimpleRequest(method, path), createResponse(false, delay, delayUnit)); 158 | return null;//Void 159 | } 160 | 161 | @Override 162 | public Void times(int times) { 163 | for (int i = 0; i < times; i++) { 164 | once(); 165 | } 166 | return null;//Void 167 | } 168 | 169 | @Override 170 | public Pathable>> delay(long delay, TimeUnit delayUnit) { 171 | return new MockServerExpectationImpl(context, method, path, bodyProvider, chunksProvider, delay, delayUnit, times, responses); 172 | } 173 | 174 | @Override 175 | public Pathable>> delay(long delayInMilliseconds) { 176 | return new MockServerExpectationImpl(context, method, path, bodyProvider, chunksProvider, delayInMilliseconds, TimeUnit.MILLISECONDS, times, responses); 177 | } 178 | 179 | @Override 180 | public WebSocketSessionBuilder> andUpgradeToWebSocket() { 181 | return new InlineWebSocketSessionBuilder<>(context, new WebSocketSessionConverter(this)); 182 | } 183 | 184 | /** 185 | * {@inheritDoc} 186 | */ 187 | @Override 188 | public WebSocketSessionBuilder> andUpgradeToWebSocket(ScheduledExecutorService executor) { 189 | return new InlineWebSocketSessionBuilder<>(context, new WebSocketSessionConverter(this)); 190 | } 191 | 192 | @Override 193 | public TimesOnceableOrHttpHeaderable withHeader(String header) { 194 | bodyProvider.setHeaders(bodyProvider.getHeaders().newBuilder().add(header).build()); 195 | return new MockServerExpectationImpl(context, method, path, bodyProvider, chunksProvider, delay, TimeUnit.MILLISECONDS, times, responses); 196 | } 197 | 198 | @Override 199 | public TimesOnceableOrHttpHeaderable withHeader(String name, String value) { 200 | bodyProvider.setHeaders(bodyProvider.getHeaders().newBuilder().add(name, value).build()); 201 | return new MockServerExpectationImpl(context, method, path, bodyProvider, chunksProvider, delay, TimeUnit.MILLISECONDS, times, responses); 202 | } 203 | 204 | 205 | private void enqueue(ServerRequest req, ServerResponse resp) { 206 | responses.computeIfAbsent(req, k -> new ArrayDeque<>()).add(resp); 207 | } 208 | 209 | private ServerResponse createResponse(boolean repeatable, long delay, TimeUnit delayUnit) { 210 | if (chunksProvider != null) { 211 | return new ChunkedResponse(repeatable, delay, delayUnit, chunksProvider); 212 | } else { 213 | return new SimpleResponse(repeatable, bodyProvider, null, delay, delayUnit); 214 | } 215 | } 216 | 217 | private ResponseProvider toString(final ResponseProvider provider) { 218 | return new ResponseProvider() { 219 | @Override 220 | public String getBody(RecordedRequest request) { 221 | Object object = provider.getBody(request); 222 | return MockServerExpectationImpl.this.toString(object); 223 | } 224 | 225 | @Override 226 | public int getStatusCode(RecordedRequest request) { 227 | return provider.getStatusCode(request); 228 | } 229 | 230 | @Override 231 | public Headers getHeaders() { 232 | return provider.getHeaders(); 233 | } 234 | 235 | @Override 236 | public void setHeaders(Headers headers) { 237 | provider.setHeaders(headers); 238 | } 239 | }; 240 | } 241 | 242 | private ResponseProvider> listToString(final ResponseProvider> provider) { 243 | return new ResponseProvider>() { 244 | @Override 245 | public List getBody(RecordedRequest request) { 246 | List objects = provider.getBody(request); 247 | List strings = new ArrayList<>(objects.size()); 248 | for (Object o : objects) { 249 | strings.add(MockServerExpectationImpl.this.toString(o)); 250 | } 251 | return strings; 252 | } 253 | 254 | @Override 255 | public int getStatusCode(RecordedRequest request) { 256 | return provider.getStatusCode(request); 257 | } 258 | 259 | @Override 260 | public Headers getHeaders() { 261 | return provider.getHeaders(); 262 | } 263 | 264 | @Override 265 | public void setHeaders(Headers headers) { 266 | provider.setHeaders(headers); 267 | } 268 | }; 269 | } 270 | 271 | private String toString(Object object) { 272 | if (object instanceof String) { 273 | return (String) object; 274 | } else { 275 | try { 276 | return context.getMapper().writeValueAsString(object); 277 | } catch (JsonProcessingException e) { 278 | throw new MockServerException("Exception when mapping Object to String", e); 279 | } 280 | } 281 | } 282 | 283 | private List toString(Object[] object) { 284 | return Stream.of(object) 285 | .map(this::toString) 286 | .collect(Collectors.toList()); 287 | } 288 | 289 | private static final class WebSocketSessionConverter 290 | implements Function> { 291 | 292 | private final MockServerExpectationImpl mse; 293 | 294 | public WebSocketSessionConverter(MockServerExpectationImpl mse) { 295 | this.mse = mse; 296 | } 297 | 298 | @Override 299 | public TimesOnceableOrHttpHeaderable apply(final WebSocketSession webSocketSession) { 300 | final Map headers = new HashMap<>(); 301 | headers.put("Upgrade", "websocket"); 302 | headers.put("Connection", "Upgrade"); 303 | 304 | return new TimesOnceableOrHttpHeaderable() { 305 | @Override 306 | public Void always() { 307 | mse.enqueue(new SimpleRequest(mse.method, mse.path), new SimpleResponse(true, ResponseProviders.of(101, "", headers), webSocketSession)); 308 | return null;//Void 309 | } 310 | 311 | @Override 312 | public Void once() { 313 | mse.enqueue(new SimpleRequest(mse.method, mse.path), new SimpleResponse(false, ResponseProviders.of(101, "", headers), webSocketSession)); 314 | return null;//Void 315 | } 316 | 317 | @Override 318 | public Void times(int times) { 319 | for (int i = 0; i < times; i++) { 320 | once(); 321 | } 322 | return null;//Void 323 | } 324 | 325 | @Override 326 | public TimesOnceableOrHttpHeaderable withHeader(String header) { 327 | headers.put(header, ""); 328 | return this;//Void 329 | } 330 | 331 | @Override 332 | public TimesOnceableOrHttpHeaderable withHeader(String name, String value) { 333 | headers.put(name, value); 334 | return this;//Void 335 | } 336 | }; 337 | } 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/internal/SimpleRequest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.internal; 18 | 19 | import io.fabric8.mockwebserver.ServerRequest; 20 | import io.fabric8.mockwebserver.dsl.HttpMethod; 21 | 22 | public class SimpleRequest implements ServerRequest { 23 | 24 | private static final String ROOT = "/"; 25 | 26 | private final HttpMethod method; 27 | private final String path; 28 | 29 | public SimpleRequest() { 30 | this(HttpMethod.ANY, ROOT); 31 | } 32 | 33 | public SimpleRequest(String path) { 34 | this(HttpMethod.ANY, path); 35 | } 36 | 37 | public SimpleRequest(HttpMethod method, String path) { 38 | this.method = method; 39 | this.path = path; 40 | } 41 | 42 | public HttpMethod getMethod() { 43 | return method; 44 | } 45 | 46 | public String getPath() { 47 | return path; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) return true; 53 | if (o == null || getClass() != o.getClass()) return false; 54 | 55 | SimpleRequest that = (SimpleRequest) o; 56 | 57 | if (method != that.method) return false; 58 | return path != null ? path.equals(that.path) : that.path == null; 59 | 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | int result = method != null ? method.hashCode() : 0; 65 | result = 31 * result + (path != null ? path.hashCode() : 0); 66 | return result; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/internal/SimpleResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.internal; 18 | 19 | import java.util.Objects; 20 | import java.util.concurrent.TimeUnit; 21 | 22 | import io.fabric8.mockwebserver.ServerResponse; 23 | import io.fabric8.mockwebserver.utils.ResponseProvider; 24 | import io.fabric8.mockwebserver.utils.ResponseProviders; 25 | 26 | import okhttp3.mockwebserver.MockResponse; 27 | import okhttp3.mockwebserver.RecordedRequest; 28 | 29 | public class SimpleResponse implements ServerResponse { 30 | 31 | private static final String HTTP_HEADER_SEC_WEBSOCKET_PROTOCOL = "sec-websocket-protocol"; 32 | 33 | private final ResponseProvider bodyProvider; 34 | 35 | private final WebSocketSession webSocketSession; 36 | private final boolean repeatable; 37 | private final long responseDelay; 38 | private final TimeUnit responseDelayUnit; 39 | 40 | public SimpleResponse(boolean repeatable, int statusCode, String body, WebSocketSession webSocketSession) { 41 | this(repeatable, ResponseProviders.of(statusCode, body), webSocketSession); 42 | } 43 | 44 | public SimpleResponse(boolean repeatable, ResponseProvider bodyProvider, WebSocketSession webSocketSession) { 45 | this(repeatable, bodyProvider, webSocketSession, 0, TimeUnit.MILLISECONDS); 46 | } 47 | 48 | public SimpleResponse(boolean repeatable, int statusCode, String body, WebSocketSession webSocketSession, long responseDelay, TimeUnit responseDelayUnit) { 49 | this(repeatable, ResponseProviders.of(statusCode, body), webSocketSession, responseDelay, responseDelayUnit); 50 | } 51 | 52 | public SimpleResponse(boolean repeatable, ResponseProvider bodyProvider, WebSocketSession webSocketSession, long responseDelay, TimeUnit responseDelayUnit) { 53 | this.bodyProvider = bodyProvider; 54 | this.webSocketSession = webSocketSession; 55 | this.repeatable = repeatable; 56 | this.responseDelay = responseDelay; 57 | this.responseDelayUnit = responseDelayUnit; 58 | } 59 | 60 | public ResponseProvider getBodyProvider() { 61 | return bodyProvider; 62 | } 63 | 64 | @Override 65 | public MockResponse toMockResponse(RecordedRequest request) { 66 | MockResponse mockResponse = new MockResponse(); 67 | mockResponse.setHeaders(bodyProvider.getHeaders()); 68 | mockResponse.setResponseCode(bodyProvider.getStatusCode(request)); 69 | 70 | if (webSocketSession != null) { 71 | mockResponse.withWebSocketUpgrade(webSocketSession); 72 | // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism 73 | // see https://github.com/netty/netty/blob/4.1/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java#L366 74 | String requestWebsocketProtocol = request.getHeaders().get(HTTP_HEADER_SEC_WEBSOCKET_PROTOCOL); 75 | if (requestWebsocketProtocol != null 76 | // only add the response header if it's not set, to prevent changing custom response headers 77 | && mockResponse.getHeaders().get(HTTP_HEADER_SEC_WEBSOCKET_PROTOCOL) == null) { 78 | mockResponse.addHeader(HTTP_HEADER_SEC_WEBSOCKET_PROTOCOL, requestWebsocketProtocol); 79 | } 80 | } else { 81 | mockResponse.setBody(bodyProvider.getBody(request)); 82 | } 83 | 84 | if (responseDelay > 0) { 85 | mockResponse.setBodyDelay(responseDelay, responseDelayUnit); 86 | } 87 | 88 | return mockResponse; 89 | } 90 | 91 | public WebSocketSession getWebSocketSession() { 92 | return webSocketSession; 93 | } 94 | 95 | @Override 96 | public boolean isRepeatable() { 97 | return repeatable; 98 | } 99 | 100 | @Override 101 | public boolean equals(Object o) { 102 | if (this == o) return true; 103 | if (o == null || getClass() != o.getClass()) return false; 104 | SimpleResponse that = (SimpleResponse) o; 105 | return repeatable == that.repeatable && responseDelay == that.responseDelay && Objects.equals(bodyProvider, that.bodyProvider) && Objects.equals(webSocketSession, that.webSocketSession) && responseDelayUnit == that.responseDelayUnit; 106 | } 107 | 108 | @Override 109 | public int hashCode() { 110 | return Objects.hash(bodyProvider, webSocketSession, repeatable, responseDelay, responseDelayUnit); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/internal/WebSocketMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.internal; 17 | 18 | import java.nio.charset.StandardCharsets; 19 | 20 | public class WebSocketMessage { 21 | 22 | private final Long delay; 23 | private final byte[] body; 24 | private final boolean toBeRemoved; 25 | private final boolean binary; 26 | 27 | public WebSocketMessage(String body) { 28 | this(0L, body, true); 29 | } 30 | 31 | public WebSocketMessage(byte[] body) { 32 | this(0L, body, true, true); 33 | } 34 | 35 | public WebSocketMessage(String body, boolean toBeRemoved) { 36 | this(0L, body.getBytes(StandardCharsets.UTF_8), toBeRemoved, false); 37 | } 38 | 39 | public WebSocketMessage(byte[] body, boolean toBeRemoved) { 40 | this(0L, body, toBeRemoved, true); 41 | } 42 | 43 | public WebSocketMessage(Long delay, String body, boolean toBeRemoved) { 44 | this(delay, body.getBytes(StandardCharsets.UTF_8), toBeRemoved, false); 45 | } 46 | 47 | public WebSocketMessage(Long delay, byte[] body, boolean toBeRemoved) { 48 | this(delay, body, toBeRemoved, true); 49 | } 50 | 51 | public WebSocketMessage(Long delay, String body, boolean toBeRemoved, boolean binary) { 52 | this(delay, body.getBytes(StandardCharsets.UTF_8), toBeRemoved, binary); 53 | } 54 | 55 | public WebSocketMessage(Long delay, byte[] body, boolean toBeRemoved, boolean binary) { 56 | this.delay = delay; 57 | this.body = body; 58 | this.toBeRemoved = toBeRemoved; 59 | this.binary = binary; 60 | } 61 | 62 | public Long getDelay() { 63 | return delay; 64 | } 65 | 66 | public String getBody() { 67 | return new String(body); 68 | } 69 | 70 | public boolean isToBeRemoved() { 71 | return toBeRemoved; 72 | } 73 | 74 | public byte[] getBytes() { 75 | return body; 76 | } 77 | 78 | public boolean isBinary() { 79 | return binary; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/internal/WebSocketSession.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.fabric8.mockwebserver.internal; 18 | 19 | import io.fabric8.mockwebserver.MockServerException; 20 | import io.fabric8.mockwebserver.dsl.HttpMethod; 21 | import okhttp3.Response; 22 | import okhttp3.WebSocket; 23 | import okhttp3.WebSocketListener; 24 | import okhttp3.mockwebserver.RecordedRequest; 25 | import okio.ByteString; 26 | 27 | import java.util.ArrayList; 28 | import java.util.Collection; 29 | import java.util.HashMap; 30 | import java.util.List; 31 | import java.util.Map; 32 | import java.util.Queue; 33 | import java.util.UUID; 34 | import java.util.concurrent.ConcurrentHashMap; 35 | import java.util.concurrent.Executors; 36 | import java.util.concurrent.ScheduledExecutorService; 37 | import java.util.concurrent.TimeUnit; 38 | 39 | public class WebSocketSession extends WebSocketListener { 40 | 41 | private final List open; 42 | private final WebSocketMessage failure; 43 | private final Exception cause; 44 | 45 | private final Collection activeSockets = ConcurrentHashMap.newKeySet(); 46 | private final Collection pendingMessages = ConcurrentHashMap.newKeySet(); 47 | private final Map> requestEvents = new HashMap<>(); 48 | private final Map> sentWebSocketMessagesRequestEvents = new HashMap<>(); 49 | private final Map> httpRequestEvents = new HashMap<>(); 50 | private final List timedEvents = new ArrayList<>(); 51 | 52 | private final ScheduledExecutorService executor; 53 | 54 | public WebSocketSession(List open, WebSocketMessage failure, Exception cause) { 55 | this.open = open; 56 | this.failure = failure; 57 | this.cause = cause; 58 | this.executor = Executors.newScheduledThreadPool(1); 59 | } 60 | 61 | @Override 62 | public void onClosing(WebSocket webSocket, int code, String reason) { 63 | webSocket.close(code, reason); 64 | } 65 | 66 | @Override 67 | public void onOpen(WebSocket webSocket, Response response) { 68 | activeSockets.add(webSocket); 69 | //Schedule all timed events 70 | for (WebSocketMessage msg : open) { 71 | send(webSocket, msg); 72 | } 73 | 74 | for (WebSocketMessage msg : timedEvents) { 75 | send(webSocket, msg); 76 | } 77 | closeActiveSocketsIfApplicable(); 78 | } 79 | 80 | @Override 81 | public void onMessage(WebSocket webSocket, ByteString bytes) { 82 | onMessage(webSocket, bytes.utf8()); 83 | } 84 | 85 | @Override 86 | public void onMessage(WebSocket webSocket, String in) { 87 | Queue queue = requestEvents.get(in); 88 | send(webSocket, queue, in); 89 | } 90 | 91 | @Override 92 | public void onClosed(WebSocket webSocket, int code, String reason) { 93 | activeSockets.remove(webSocket); 94 | } 95 | 96 | private void send(WebSocket ws, Queue queue, String in) { 97 | if (queue != null && !queue.isEmpty()) { 98 | WebSocketMessage msg = queue.peek(); 99 | send(ws, msg); 100 | if (msg.isToBeRemoved()) { 101 | queue.remove(); 102 | } 103 | checkIfShouldSendAgain(ws, msg); 104 | } else { 105 | ws.close(1002, "Unexpected message:" + in); 106 | } 107 | } 108 | 109 | private void checkIfShouldSendAgain(WebSocket ws, WebSocketMessage msg) { 110 | String text = msg.isBinary() ? ByteString.of(msg.getBytes()).utf8() : msg.getBody(); 111 | if (sentWebSocketMessagesRequestEvents.containsKey(text)) { 112 | Queue queue = sentWebSocketMessagesRequestEvents.get(text); 113 | send(ws, queue, text); 114 | } 115 | } 116 | 117 | public void dispatch(RecordedRequest request) { 118 | HttpMethod method = HttpMethod.valueOf(request.getMethod()); 119 | String path = request.getPath(); 120 | SimpleRequest key = new SimpleRequest(method, path); 121 | SimpleRequest keyForAnyMethod = new SimpleRequest(path); 122 | if (httpRequestEvents.containsKey(key)) { 123 | Queue queue = httpRequestEvents.get(key); 124 | activeSockets.forEach(ws -> send(ws, queue, "from http " + path)); 125 | } else if (httpRequestEvents.containsKey(keyForAnyMethod)) { 126 | Queue queue = httpRequestEvents.get(keyForAnyMethod); 127 | activeSockets.forEach(ws -> send(ws, queue, "from http " + path)); 128 | } 129 | } 130 | 131 | public List getOpen() { 132 | return open; 133 | } 134 | 135 | public WebSocketMessage getFailure() { 136 | return failure; 137 | } 138 | 139 | public Exception getCause() { 140 | return cause; 141 | } 142 | 143 | public Map> getRequestEvents() { 144 | return requestEvents; 145 | } 146 | 147 | public List getTimedEvents() { 148 | return timedEvents; 149 | } 150 | 151 | public Map> getSentWebSocketMessagesRequestEvents() { 152 | return sentWebSocketMessagesRequestEvents; 153 | } 154 | 155 | public Map> getHttpRequestEvents() { 156 | return httpRequestEvents; 157 | } 158 | 159 | private void send(final WebSocket ws, final WebSocketMessage message) { 160 | final UUID id = UUID.randomUUID(); 161 | pendingMessages.add(id); 162 | executor.schedule(() -> { 163 | if (ws != null) { 164 | if (message.isBinary()) { 165 | ws.send(ByteString.of(message.getBytes())); 166 | } else { 167 | ws.send(message.getBody()); 168 | } 169 | pendingMessages.remove(id); 170 | } 171 | closeActiveSocketsIfApplicable(); 172 | }, message.getDelay(), TimeUnit.MILLISECONDS); 173 | } 174 | 175 | public void closeActiveSocketsIfApplicable() { 176 | if (pendingMessages.isEmpty() && requestEvents.isEmpty() && httpRequestEvents.isEmpty() 177 | && sentWebSocketMessagesRequestEvents.isEmpty()) { 178 | activeSockets.forEach(ws -> ws.close(1000, "Closing...")); 179 | } 180 | } 181 | 182 | public void shutdown() { 183 | try { 184 | executor.shutdown(); 185 | if (!executor.awaitTermination(1, TimeUnit.MINUTES)) { 186 | executor.shutdownNow(); 187 | } 188 | } catch (InterruptedException e) { 189 | throw MockServerException.launderThrowable(e); 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/utils/BodyProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.utils; 17 | 18 | import okhttp3.mockwebserver.RecordedRequest; 19 | 20 | /** 21 | * A class that allows returning the body of a response given a certain request. 22 | */ 23 | public interface BodyProvider { 24 | 25 | T getBody(RecordedRequest request); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/utils/CertUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.utils; 17 | 18 | import okio.ByteString; 19 | 20 | import java.io.BufferedReader; 21 | import java.io.ByteArrayInputStream; 22 | import java.io.FileInputStream; 23 | import java.io.FileNotFoundException; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.io.InputStreamReader; 27 | import java.security.KeyFactory; 28 | import java.security.KeyStore; 29 | import java.security.KeyStoreException; 30 | import java.security.NoSuchAlgorithmException; 31 | import java.security.PrivateKey; 32 | import java.security.cert.Certificate; 33 | import java.security.cert.CertificateException; 34 | import java.security.cert.CertificateFactory; 35 | import java.security.cert.X509Certificate; 36 | import java.security.spec.InvalidKeySpecException; 37 | import java.security.spec.PKCS8EncodedKeySpec; 38 | import java.security.spec.RSAPrivateCrtKeySpec; 39 | 40 | public class CertUtils { 41 | 42 | private CertUtils() {} 43 | 44 | public static InputStream getInputStreamFromDataOrFile(String data, String file) throws FileNotFoundException { 45 | if (data != null) { 46 | final byte[] bytes; 47 | ByteString decoded = ByteString.decodeBase64(data); 48 | if (decoded != null) { 49 | bytes = decoded.toByteArray(); 50 | } else { 51 | bytes = data.getBytes(); 52 | } 53 | 54 | return new ByteArrayInputStream(bytes); 55 | } 56 | if (file != null) { 57 | return new FileInputStream(file); 58 | } 59 | return null; 60 | } 61 | 62 | 63 | public static KeyStore createKeyStore(InputStream certInputStream, InputStream keyInputStream, String clientKeyAlgo, char[] clientKeyPassphrase) throws IOException, CertificateException, NoSuchAlgorithmException, InvalidKeySpecException, KeyStoreException { 64 | CertificateFactory certFactory = CertificateFactory.getInstance("X509"); 65 | X509Certificate cert = (X509Certificate) certFactory.generateCertificate(certInputStream); 66 | 67 | byte[] keyBytes = decodePem(keyInputStream); 68 | 69 | PrivateKey privateKey; 70 | 71 | KeyFactory keyFactory = KeyFactory.getInstance(clientKeyAlgo); 72 | try { 73 | // First let's try PKCS8 74 | privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes)); 75 | } catch (InvalidKeySpecException e) { 76 | // Otherwise try PKCS8 77 | RSAPrivateCrtKeySpec keySpec = PKCS1Util.decodePKCS1(keyBytes); 78 | privateKey = keyFactory.generatePrivate(keySpec); 79 | } 80 | 81 | KeyStore keyStore = KeyStore.getInstance("JKS"); 82 | keyStore.load(null, clientKeyPassphrase); 83 | 84 | String alias = cert.getSubjectX500Principal().getName(); 85 | keyStore.setKeyEntry(alias, privateKey, clientKeyPassphrase, new Certificate[]{cert}); 86 | 87 | return keyStore; 88 | } 89 | 90 | public static KeyStore createKeyStore(String clientCertData, String clientCertFile, String clientKeyData, String clientKeyFile, String clientKeyAlgo, char[] clientKeyPassphrase) throws IOException, CertificateException, NoSuchAlgorithmException, InvalidKeySpecException, KeyStoreException { 91 | try (InputStream certInputStream = getInputStreamFromDataOrFile(clientCertData, clientCertFile); InputStream keyInputStream = getInputStreamFromDataOrFile(clientKeyData, clientKeyFile)) { 92 | return createKeyStore(certInputStream, keyInputStream, clientKeyAlgo, clientKeyPassphrase); 93 | } 94 | } 95 | 96 | // This method is inspired and partly taken over from 97 | // http://oauth.googlecode.com/svn/code/java/ 98 | // All credits to belong to them. 99 | private static byte[] decodePem(InputStream keyInputStream) throws IOException { 100 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(keyInputStream))) { 101 | String line; 102 | while ((line = reader.readLine()) != null) { 103 | if (line.contains("-----BEGIN ")) { 104 | return readBytes(reader, line.trim().replace("BEGIN", "END")); 105 | } 106 | } 107 | throw new IOException("PEM is invalid: no begin marker"); 108 | } 109 | } 110 | 111 | private static byte[] readBytes(BufferedReader reader, String endMarker) throws IOException { 112 | String line; 113 | StringBuffer buf = new StringBuffer(); 114 | 115 | while ((line = reader.readLine()) != null) { 116 | if (line.indexOf(endMarker) != -1) { 117 | return ByteString.decodeBase64(buf.toString()).toByteArray(); 118 | } 119 | buf.append(line.trim()); 120 | } 121 | throw new IOException("PEM is invalid : No end marker"); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/utils/Closeables.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.utils; 17 | 18 | import java.io.Closeable; 19 | import java.io.IOException; 20 | import java.util.logging.Logger; 21 | 22 | public final class Closeables { 23 | 24 | private static final Logger LOGGER = Logger.getLogger(Closeables.class.getName()); 25 | 26 | private Closeables() { 27 | //Utility class 28 | } 29 | 30 | public static void closeQuietly(Closeable closeable) { 31 | try { 32 | closeable.close(); 33 | } catch (IOException e) { 34 | LOGGER.warning("Error while closing object:" + closeable + ". Ignoring."); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/utils/PKCS1Util.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.utils; 17 | 18 | import java.io.ByteArrayInputStream; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.math.BigInteger; 22 | import java.security.spec.RSAPrivateCrtKeySpec; 23 | 24 | /** 25 | * This code is inspired and taken over from net.auth.core:oauth 26 | * (albeit in a highly stripped variation): 27 | *

28 | * Source is from http://oauth.googlecode.com/svn/code/java/ which is licensed 29 | * under the APL (http://oauth.googlecode.com/svn/code/java/LICENSE.txt) 30 | *

31 | * All credits go to the original author (zhang) 32 | * 33 | * @author roland 34 | * @since 30/09/15 35 | */ 36 | class PKCS1Util { 37 | 38 | private PKCS1Util() { 39 | } 40 | 41 | public static RSAPrivateCrtKeySpec decodePKCS1(byte[] keyBytes) throws IOException { 42 | DerParser parser = new DerParser(keyBytes); 43 | Asn1Object sequence = parser.read(); 44 | sequence.validateSequence(); 45 | parser = new DerParser(sequence.getValue()); 46 | parser.read(); 47 | 48 | return new RSAPrivateCrtKeySpec(next(parser), next(parser), 49 | next(parser), next(parser), 50 | next(parser), next(parser), 51 | next(parser), next(parser)); 52 | } 53 | 54 | // ========================================================================================== 55 | 56 | private static BigInteger next(DerParser parser) throws IOException { 57 | return parser.read().getInteger(); 58 | } 59 | 60 | static class DerParser { 61 | 62 | private final InputStream in; 63 | 64 | DerParser(byte[] bytes) { 65 | this.in = new ByteArrayInputStream(bytes); 66 | } 67 | 68 | Asn1Object read() throws IOException { 69 | int tag = in.read(); 70 | 71 | if (tag == -1) { 72 | throw new IOException("Invalid DER: stream too short, missing tag"); 73 | } 74 | 75 | int length = getLength(); 76 | byte[] value = new byte[length]; 77 | if (in.read(value) < length) { 78 | throw new IOException("Invalid DER: stream too short, missing value"); 79 | } 80 | 81 | return new Asn1Object(tag, value); 82 | } 83 | 84 | private int getLength() throws IOException { 85 | int i = in.read(); 86 | if (i == -1) { 87 | throw new IOException("Invalid DER: length missing"); 88 | } 89 | 90 | if ((i & ~0x7F) == 0) { 91 | return i; 92 | } 93 | 94 | int num = i & 0x7F; 95 | if (i >= 0xFF || num > 4) { 96 | throw new IOException("Invalid DER: length field too big (" 97 | + i + ")"); 98 | } 99 | 100 | byte[] bytes = new byte[num]; 101 | if (in.read(bytes) < num) { 102 | throw new IOException("Invalid DER: length too short"); 103 | } 104 | 105 | return new BigInteger(1, bytes).intValue(); 106 | } 107 | } 108 | 109 | static class Asn1Object { 110 | 111 | private final int type; 112 | private final byte[] value; 113 | private final int tag; 114 | 115 | public Asn1Object(int tag, byte[] value) { 116 | this.tag = tag; 117 | this.type = tag & 0x1F; 118 | this.value = value; 119 | } 120 | 121 | public byte[] getValue() { 122 | return value; 123 | } 124 | 125 | BigInteger getInteger() throws IOException { 126 | if (type != 0x02) { 127 | throw new IOException("Invalid DER: object is not integer"); //$NON-NLS-1$ 128 | } 129 | return new BigInteger(value); 130 | } 131 | 132 | void validateSequence() throws IOException { 133 | if (type != 0x10) { 134 | throw new IOException("Invalid DER: not a sequence"); 135 | } 136 | if ((tag & 0x20) != 0x20) { 137 | throw new IOException("Invalid DER: can't parse primitive entity"); 138 | } 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/utils/ResponseProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.utils; 17 | 18 | import okhttp3.Headers; 19 | import okhttp3.mockwebserver.RecordedRequest; 20 | 21 | /** 22 | * A class that allows returning a response given a certain request. 23 | */ 24 | public interface ResponseProvider extends BodyProvider { 25 | 26 | int getStatusCode(RecordedRequest request); 27 | 28 | Headers getHeaders(); 29 | 30 | void setHeaders(Headers headers); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/utils/ResponseProviders.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.utils; 17 | 18 | import okhttp3.Headers; 19 | import okhttp3.mockwebserver.RecordedRequest; 20 | 21 | import java.util.Arrays; 22 | import java.util.Collections; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | /** 27 | * Useful methods for creating basic response providers. 28 | */ 29 | public class ResponseProviders { 30 | 31 | private ResponseProviders() {} 32 | 33 | public static ResponseProvider of(int statusCode, R element) { 34 | if (element != null) { 35 | return new FixedResponseProvider<>(statusCode, element); 36 | } 37 | return null; 38 | } 39 | 40 | public static ResponseProvider of(int statusCode, R element, Map map) { 41 | if (element != null) { 42 | return new FixedResponseProvider<>(statusCode, element, map); 43 | } 44 | return null; 45 | } 46 | 47 | public static ResponseProvider> ofAll(int statusCode, R... elements) { 48 | if (elements != null) { 49 | return new FixedResponseProvider<>(statusCode, Arrays.asList(elements)); 50 | } 51 | return null; 52 | } 53 | 54 | public static ResponseProvider of(final int statusCode, final BodyProvider bodyProvider) { 55 | if (bodyProvider != null) { 56 | return new ResponseProvider() { 57 | private Headers headers = new Headers.Builder().build(); 58 | 59 | @Override 60 | public int getStatusCode(RecordedRequest request) { 61 | return statusCode; 62 | } 63 | 64 | @Override 65 | public R getBody(RecordedRequest request) { 66 | return bodyProvider.getBody(request); 67 | } 68 | 69 | @Override 70 | public Headers getHeaders() { 71 | return headers; 72 | } 73 | 74 | @Override 75 | public void setHeaders(Headers headers) { 76 | this.headers = headers; 77 | } 78 | }; 79 | } 80 | return null; 81 | } 82 | 83 | private static class FixedResponseProvider implements ResponseProvider { 84 | 85 | private final int statusCode; 86 | private final T element; 87 | private Headers headers; 88 | 89 | public FixedResponseProvider(int statusCode, T element) { 90 | this(statusCode, element, Collections.emptyMap()); 91 | } 92 | 93 | public FixedResponseProvider(int statusCode, T element, Map headers) { 94 | this(statusCode, element, toHeaders(headers)); 95 | } 96 | 97 | public FixedResponseProvider(int statusCode, T element, Headers headers) { 98 | this.statusCode = statusCode; 99 | this.element = element; 100 | this.headers = headers; 101 | } 102 | 103 | @Override 104 | public T getBody(RecordedRequest request) { 105 | return element; 106 | } 107 | 108 | @Override 109 | public int getStatusCode(RecordedRequest request) { 110 | return statusCode; 111 | } 112 | 113 | @Override 114 | public Headers getHeaders() { 115 | return headers; 116 | } 117 | 118 | @Override 119 | public void setHeaders(Headers headers) { 120 | this.headers = headers; 121 | } 122 | 123 | @Override 124 | public boolean equals(Object o) { 125 | if (this == o) return true; 126 | if (o == null || getClass() != o.getClass()) return false; 127 | 128 | FixedResponseProvider that = (FixedResponseProvider) o; 129 | 130 | return element != null ? element.equals(that.element) : that.element == null; 131 | 132 | } 133 | 134 | @Override 135 | public int hashCode() { 136 | return element != null ? element.hashCode() : 0; 137 | } 138 | 139 | private static Headers toHeaders(Map headers) { 140 | final Headers.Builder builder = new Headers.Builder(); 141 | for (Map.Entry entry : headers.entrySet()) { 142 | builder.set(entry.getKey(), entry.getValue()); 143 | } 144 | return builder.build(); 145 | } 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /src/main/java/io/fabric8/mockwebserver/utils/SSLUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.utils; 17 | 18 | import javax.net.ssl.KeyManager; 19 | import javax.net.ssl.KeyManagerFactory; 20 | import javax.net.ssl.SSLContext; 21 | import javax.net.ssl.TrustManager; 22 | import javax.net.ssl.X509TrustManager; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.security.KeyManagementException; 26 | import java.security.KeyStore; 27 | import java.security.KeyStoreException; 28 | import java.security.NoSuchAlgorithmException; 29 | import java.security.SecureRandom; 30 | import java.security.UnrecoverableKeyException; 31 | import java.security.cert.CertificateException; 32 | import java.security.cert.X509Certificate; 33 | import java.security.spec.InvalidKeySpecException; 34 | import static io.fabric8.mockwebserver.utils.CertUtils.createKeyStore; 35 | 36 | public final class SSLUtils { 37 | 38 | private SSLUtils() { 39 | //Utility 40 | } 41 | 42 | public static SSLContext sslContext(KeyManager[] keyManagers, TrustManager[] trustManagers, boolean trustCerts) throws KeyManagementException, NoSuchAlgorithmException { 43 | if (trustManagers == null && trustCerts) { 44 | trustManagers = new TrustManager[]{new X509TrustManager() { 45 | public void checkClientTrusted(X509Certificate[] chain, String s) { 46 | } 47 | 48 | public void checkServerTrusted(X509Certificate[] chain, String s) { 49 | } 50 | 51 | public X509Certificate[] getAcceptedIssuers() { 52 | return new X509Certificate[0]; 53 | } 54 | }}; 55 | } 56 | SSLContext sslContext = SSLContext.getInstance("TLS"); 57 | sslContext.init(keyManagers, trustManagers, new SecureRandom()); 58 | return sslContext; 59 | } 60 | 61 | public static KeyManager[] keyManagers(InputStream certInputStream, InputStream keyInputStream, String algo, String passphrase) throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, CertificateException, InvalidKeySpecException, IOException { 62 | KeyStore keyStore = createKeyStore(certInputStream, keyInputStream, algo, passphrase.toCharArray()); 63 | KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 64 | kmf.init(keyStore, passphrase.toCharArray()); 65 | return kmf.getKeyManagers(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/resources/ssl/fabric8: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDeWNPC4SJE8DKX 3 | GU5JISsrY1nnI249vmO6x+pEflcGBqaReQehRUNeMFGje92jZk+0xh8NbNFf4Ofs 4 | wJnSXHAupOI6CFERS2aym4IuGX24c7WvoMeH0I8/w8TJTEKNmWCcduaZx5z041gd 5 | kQHQKetYJkzVhh5p2tbIsYlBLe/XGH3IzAVbeFd6GUDK32EyFNrSSOtMEOwbejmH 6 | 2wJysLFxGsJFySbnvyEdjDvTdGpNdqPRCU93K/BfRo1ycqSZiSObAh605Ddo3DMQ 7 | lE0rk0im4BQXxwvaVuhbzszR8XIln8/QT5HysiDY5R2hgQq1yJtXtbL7yFGQSeNe 8 | 1CG9Gb1JNnHCdAkf+n9RFVoisjsn8MGcSCxpTs0G16Oia41nQaKLByqh4++aithh 9 | Ucd96ujYnIceljMycpkL0VMXzZ7xwHHU+aHPRkRQsDzbf0x0b7MwQD5XkE1rYPzw 10 | /TwJ6qhpPoxzlQ/H5hqEl9zdPpZyQLcfr5YluaRDSTAaR1QruqlWM2Zzy5iBthvx 11 | 7hrYNQ/Re5pbp+b4M7h1I6zvohrMiCbtvMQrWYZWGtOHPsW+tUXTQyb2vIYIGIZM 12 | sLZzOijXn78/0IA07xuivqlQ/jmC6jNZAZCC5PRss9KQLWJWu9V3jEcK5dCstJv5 13 | eocZ6RWy8ShoL2fupp2jYCRota88mQIDAQABAoICAGCtnuYNnij7iAPLLQ7/LRYg 14 | jObDsRuHvTVp16MQjCZCngqC5Z5pz3EU8Wp0YVq7Ec04mCfuONvHnxCCbl/Zca3W 15 | Y8d39kfe0Ti4BVKmItQg+87xydB0DtVa+iXM0uNe3XMq//m9obGZaKbydiddEsex 16 | X5c4SeEdFmcNSvDcWHzeWVMF4w5ytRaSBGox1sE/8CWfLzBT61XHP1yjDd1wlrbn 17 | O7G8VP5PTMbcQucep1onS/OIaNUYddv3gWlSD9/ykVjFAzUERlOB63I6CZP45o4o 18 | wJPWKIE3aLECqmxe35Mcee/JqVwtt7qXZNrkkROZtnHcv4ZbA5wJhKOm+USP/I0Z 19 | K3iHDTOE++LTWNUIOaUXjiowJ6V4rXf8x3hftLz95RnN1rZWXV7T+OCCW+VduGaC 20 | 139UM9mEJn0W5DAmFCjpPHLHqfNupbnoi+nuTIuu9+0aqtMchbTSFmnIiEJOeyJ/ 21 | JvONLhB39XT08QkAf7IKFiqLeWIy6E9IR4TdOO3KBMbjtJTaMkj6q8C8C4evFF04 22 | tuPPgT6UAA5TxihBAipHd1mIs/yTTGSZMMPb4vLFlw8cEJllC0qIbJpVc45YauDI 23 | kXnhoXcrjEdTy/aMiXlnxAu/l/PkHVcuOCP5kCGIyHX0g/Ig3y8nseVgRZc8i9Kf 24 | vKH8tOFfaUPq0s6WffABAoIBAQD7fDX+RsU7Mi9iFXqPSbbuCRz8yBG54DJDh3Vt 25 | +Y4BzGqboUDxCvpTbpw7vy4R67upFZ0G6p3PLTEimOfSFp7/KH0Gije3b7yexRwM 26 | GVxf+d+Im1cgPhzfqAF92CIjIWGUXGqOvVX7hMBkhDdqgsaINB2jpzJTv47HgXfp 27 | 7Lf3op94thJP+tbMDvRuM+a1l5VJgrytVIdUBI0FaPWULdm5z2Sndua65oUBsVP5 28 | eMRQqIT+9qwMAkONoxCjADyD/yAdA55e2lAH8DM3FDhXpf048XLun5c49PppvcbW 29 | 3vpm262oiBXdxuCadsAb2RZogvJ30fKOqZnt4yrt8PR0+HP5AoIBAQDiVrOI0ziE 30 | hGazvQkB5Rqcx7fMmOZ0s3jsqJAbNrwwuZjY6vC2659XiqVcyNp4RanbvofsQSBs 31 | zN4DF0Rx72S+8ELIbk+cZ0Jwkix03cRNNkKbiUrUKr+zrvQbVEi+NRbz11Leoqw4 32 | cEcykuF3bjQvdE4R72ckQPdXEv1z/bRrCNyZq2qxdD38scHHFjM8PC9t2dghMUpN 33 | 9pS3BTLEYZBCCZ6kxq4z45dDxqosX2OImtHnVecHAPf3xy48cjDau9E1hkgClEdk 34 | MSjPIpYz3zg0qH9Ef3qVkDv+6VuBdE/j6B65HC8z3fTcwluPc+AfhYkHykxKcCdn 35 | tR9Kd+7sOfWhAoIBAQCaQXNA+BnsmHjV+gTGNVn+ohpktzegQvOx1jnibit70O4n 36 | bf7Om4Q2fudYAol4tpbSPQ6nemu386lq5k1z4So/qo8d3tQUMXaKEK+GgFvYBwXk 37 | 3hvQDClbysq3bUZrNAONpC48Rcii0afNQAhZzcOHMihoBJtrIVmr6C8sjmW9gMO+ 38 | oDeVVXBBlH67xhwikMsiXw3qZ6nmkDAL/Hh+Hq2pOpwr2FPompNFGYc/w6LvMp75 39 | YUbgytay3y3KPc/gyzHgeiK/XbuvUtenVkDFCmzLa9aqpbt1VVbwW1bG39jKFL9t 40 | W6PF+EI2nNZzfnIvQvsFIgNdHIztjOT9NEpOIUPJAoIBAHEOnd9aooCPIj3lzvoD 41 | Vqe5mzW3qmXgwCZ2jIULcjVkf9TahiLYz18LAk62hWpOYepB4eNBJNE0BDHHDYlb 42 | 6xb1LGaxs1KMwcM5QLufis6Gq/7FNXuFXvyCB60fDLb2DeD/TYWn/B609ttsQvNF 43 | OQv7LIQI8ZxKV0JHWhL2R4ivhIG9/i1lwxDWOdUYYb9U0NwuVKc/173Zza8eCZ3O 44 | niBebcAg/iMtLAHO2nIPs8gojXDgl+YHtdUuyQmogH7CEl6KFK41IvQJGjldLWn7 45 | tjeXcvrkMndC9LUAG5UuZDmTWMVeLrXZyNX8v3+Iggs8yJX7luAX5ZcIAflQryeQ 46 | TAECggEAIMqnk2FFxbbCR034TARA/n9XPY5XYufTpq9WtIaRuMvA3I5/oLKg65B9 47 | 5XDCzwr0RiJR8pzlJ6Pmtm01rzNpNvzVOwIe3QS8F10nVLsrhDXB9bq55UtAUYZX 48 | pNCO4qLC004YemEHKKp4NrRXquGcPvzJ67Ezl4f/E9rMvTdUjzhhZ80m+80adP4o 49 | 8MXBA/5BYBKLZRkEtyin3etVAvJM6/oUv4zREbod/sWyhFq3O2ka3rFhV0ymDEr6 50 | dphptKrzseopjAVi05DFIR7k1D3YN4NB7nt4N8JC5ucCYhCFq6juBO6bGHFGZ3t9 51 | Sqju3/8JhKlPzgcIeEtTEncKaJh9UA== 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /src/main/resources/ssl/fabric8.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFPzCCAycCFFa1f+dP0SR0nMoPfO+MrMRNfjHaMA0GCSqGSIb3DQEBCwUAMFwx 3 | CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRUwEwYDVQQHDAxEZWZh 4 | dWx0IENpdHkxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0y 5 | MTExMDMwODU0NTRaFw0zMTExMDEwODU0NTRaMFwxCzAJBgNVBAYTAkFVMRMwEQYD 6 | VQQIDApTb21lLVN0YXRlMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxITAfBgNVBAoM 7 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCAiIwDQYJKoZIhvcNAQEBBQADggIP 8 | ADCCAgoCggIBAN5Y08LhIkTwMpcZTkkhKytjWecjbj2+Y7rH6kR+VwYGppF5B6FF 9 | Q14wUaN73aNmT7TGHw1s0V/g5+zAmdJccC6k4joIURFLZrKbgi4Zfbhzta+gx4fQ 10 | jz/DxMlMQo2ZYJx25pnHnPTjWB2RAdAp61gmTNWGHmna1sixiUEt79cYfcjMBVt4 11 | V3oZQMrfYTIU2tJI60wQ7Bt6OYfbAnKwsXEawkXJJue/IR2MO9N0ak12o9EJT3cr 12 | 8F9GjXJypJmJI5sCHrTkN2jcMxCUTSuTSKbgFBfHC9pW6FvOzNHxciWfz9BPkfKy 13 | INjlHaGBCrXIm1e1svvIUZBJ417UIb0ZvUk2ccJ0CR/6f1EVWiKyOyfwwZxILGlO 14 | zQbXo6JrjWdBoosHKqHj75qK2GFRx33q6Nichx6WMzJymQvRUxfNnvHAcdT5oc9G 15 | RFCwPNt/THRvszBAPleQTWtg/PD9PAnqqGk+jHOVD8fmGoSX3N0+lnJAtx+vliW5 16 | pENJMBpHVCu6qVYzZnPLmIG2G/HuGtg1D9F7mlun5vgzuHUjrO+iGsyIJu28xCtZ 17 | hlYa04c+xb61RdNDJva8hggYhkywtnM6KNefvz/QgDTvG6K+qVD+OYLqM1kBkILk 18 | 9Gyz0pAtYla71XeMRwrl0Ky0m/l6hxnpFbLxKGgvZ+6mnaNgJGi1rzyZAgMBAAEw 19 | DQYJKoZIhvcNAQELBQADggIBAJ1tNTAnPgAbfhXVxtVnnNPFGsrmUgtBj0f8NsY3 20 | F0ODX50TIjbVLYp7j3u+dgZu9/ruTOHcGLywNi5mJWB+s27KJJn3nBFPmd9d/QIV 21 | zmjn5IVvikXezEjECQOscwDhwpSbzHqLoieDTJntVUyaNctAZM1YOxVKO97pCDdw 22 | tV74xDzdnI/4JQFQPfshD699r3dtU5ax/jiVCvqM5hTAJ2M/UVyQtxm3lKzMYLNu 23 | 77chlVf8/hTop9B6Q4tD6Ajj2KPxaHB7y+5lhci5Rvb2YLVDs0HLq8UJmoJW3FLw 24 | slrjs0NerSWoz5JfhmOQ0N9E3NBdV/kGr27WUeSlNOYh5bqneDCX+hPrO/4NtvpG 25 | WnnJX9W6S6e5GBFsNwQIB9SQCjj9zKWqgszS937HRd9gLmnOCPm7jbCO5uOjDo5q 26 | 0t+E20r9xv+4il1QV7tkGg13texGDR43aGzsSNQ66PXOwzeeCPkFzrSu1QFBh7LL 27 | 69VMJIbgm3ywYJjO0vIi0mW+kAiqcniIxbDTcCuEI0yuVLyRNaAe6kWWLMVaJLUw 28 | V4TNAOT7x8ZYGQGjhz2DAImvXMwZTK2wRwyv8S11G+ebIIUb4EXGbMksjU6tTquq 29 | ViHO3TGAKPTHIjCYdNT/ZGYQ/PHXLmaDGSOcoW8FPT9ROPxXRSNicNfzLJk/o4Im 30 | AZC5 31 | -----END CERTIFICATE----- 32 | -------------------------------------------------------------------------------- /src/main/resources/ssl/fabric8.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIEoTCCAokCAQAwXDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx 3 | FTATBgNVBAcMDERlZmF1bHQgQ2l0eTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 4 | cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3ljTwuEi 5 | RPAylxlOSSErK2NZ5yNuPb5jusfqRH5XBgamkXkHoUVDXjBRo3vdo2ZPtMYfDWzR 6 | X+Dn7MCZ0lxwLqTiOghREUtmspuCLhl9uHO1r6DHh9CPP8PEyUxCjZlgnHbmmcec 7 | 9ONYHZEB0CnrWCZM1YYeadrWyLGJQS3v1xh9yMwFW3hXehlAyt9hMhTa0kjrTBDs 8 | G3o5h9sCcrCxcRrCRckm578hHYw703RqTXaj0QlPdyvwX0aNcnKkmYkjmwIetOQ3 9 | aNwzEJRNK5NIpuAUF8cL2lboW87M0fFyJZ/P0E+R8rIg2OUdoYEKtcibV7Wy+8hR 10 | kEnjXtQhvRm9STZxwnQJH/p/URVaIrI7J/DBnEgsaU7NBtejomuNZ0GiiwcqoePv 11 | morYYVHHfero2JyHHpYzMnKZC9FTF82e8cBx1Pmhz0ZEULA8239MdG+zMEA+V5BN 12 | a2D88P08CeqoaT6Mc5UPx+YahJfc3T6WckC3H6+WJbmkQ0kwGkdUK7qpVjNmc8uY 13 | gbYb8e4a2DUP0XuaW6fm+DO4dSOs76IazIgm7bzEK1mGVhrThz7FvrVF00Mm9ryG 14 | CBiGTLC2czoo15+/P9CANO8bor6pUP45guozWQGQguT0bLPSkC1iVrvVd4xHCuXQ 15 | rLSb+XqHGekVsvEoaC9n7qado2AkaLWvPJkCAwEAAaAAMA0GCSqGSIb3DQEBCwUA 16 | A4ICAQCExP0WiJbGkhbpIRVN30seLat5upU3WauQy4fGeDKZAq37LguhzeHkWXtu 17 | Rifb5fz8e7PTOz1fwjHJ8pBQsy5mRoMDXYdtyn6S6A2xGTPUYT82mN6BSJbwJDQm 18 | Y4l4Lhg+7cEvqls+Mx9Dq0eSlM7hH7ezOl5c25U+lG74dHLT2gq5ornjdBk2JKnx 19 | 2c95646UomKJKVZtzfPLFRJhmVOr2ndkzooF1GlWXZsU57hflH0Y6argAqC+Y/Hu 20 | AFqsm48Uwixex1FfX53aEFnZG1vkDYm48idGUDEa1QNqqC7Wt0qDM8iZtYaHoc9D 21 | wOSD4KGOUOvzooqKmRzHRRRXfL/K3xzFOFAbxJf5YbVHmRGHEWbEXwnjhz1PHgmS 22 | sXNtmVSt7/ycGKRUHyK4s2xIol45EaD7B+80st0fj0n5WGnpX0Wx/XxIepoD7/dG 23 | H3HNjJD9UyGW3l2q6TojQrYLdTo+k9/CS6yMbbI++QyPlv/cnI1JpS/9+wvF8RrX 24 | 1AfWplKt+T8gOs64Ns7triUGD96IAqZfj46olQBN90BwCZ1BasneZyDYhClRCrfN 25 | 0znZT0cwgCs0q+UU+WmMcfBWO7ctKj3cz3+SmX+R16nTFi5Uuj3J9ED0V1o687jZ 26 | YgtA3vz5F9lf9DaKJ/23GuA2X7HYWCUDiLtB2junYNJ0toJNJw== 27 | -----END CERTIFICATE REQUEST----- 28 | -------------------------------------------------------------------------------- /src/main/resources/ssl/fabric8.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDeWNPC4SJE8DKXGU5JISsrY1nnI249vmO6x+pEflcGBqaReQehRUNeMFGje92jZk+0xh8NbNFf4OfswJnSXHAupOI6CFERS2aym4IuGX24c7WvoMeH0I8/w8TJTEKNmWCcduaZx5z041gdkQHQKetYJkzVhh5p2tbIsYlBLe/XGH3IzAVbeFd6GUDK32EyFNrSSOtMEOwbejmH2wJysLFxGsJFySbnvyEdjDvTdGpNdqPRCU93K/BfRo1ycqSZiSObAh605Ddo3DMQlE0rk0im4BQXxwvaVuhbzszR8XIln8/QT5HysiDY5R2hgQq1yJtXtbL7yFGQSeNe1CG9Gb1JNnHCdAkf+n9RFVoisjsn8MGcSCxpTs0G16Oia41nQaKLByqh4++aithhUcd96ujYnIceljMycpkL0VMXzZ7xwHHU+aHPRkRQsDzbf0x0b7MwQD5XkE1rYPzw/TwJ6qhpPoxzlQ/H5hqEl9zdPpZyQLcfr5YluaRDSTAaR1QruqlWM2Zzy5iBthvx7hrYNQ/Re5pbp+b4M7h1I6zvohrMiCbtvMQrWYZWGtOHPsW+tUXTQyb2vIYIGIZMsLZzOijXn78/0IA07xuivqlQ/jmC6jNZAZCC5PRss9KQLWJWu9V3jEcK5dCstJv5eocZ6RWy8ShoL2fupp2jYCRota88mQ== 2 | -------------------------------------------------------------------------------- /src/test/groovy/io/fabric8/mockwebserver/DefaultMockServerCrudTest.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver 17 | 18 | import com.fasterxml.jackson.databind.ObjectMapper 19 | import io.fabric8.mockwebserver.crud.CrudDispatcher 20 | import okhttp3.MediaType 21 | import okhttp3.OkHttpClient 22 | import okhttp3.Request 23 | import okhttp3.RequestBody 24 | import okhttp3.mockwebserver.MockWebServer 25 | import spock.lang.Shared 26 | import spock.lang.Specification 27 | 28 | class DefaultMockServerCrudTest extends Specification { 29 | 30 | DefaultMockServer server 31 | 32 | @Shared 33 | def client = new OkHttpClient() 34 | 35 | @Shared 36 | def mapper = new ObjectMapper() 37 | 38 | def setup() { 39 | server = new DefaultMockServer(new Context(), new MockWebServer(), new HashMap<>(), 40 | new CrudDispatcher(new Context(), new UserAttributeExtractor(), new JsonResponseComposer()), false) 41 | server.start() 42 | } 43 | 44 | def cleanup() { 45 | server.shutdown() 46 | } 47 | 48 | def "get /, with empty store, should return 404"() { 49 | when: 50 | def result = client.newCall(new Request.Builder().url(server.url("/")).build()).execute() 51 | 52 | then: 53 | assert result.code() == 404 54 | assert result.body().string() == "" 55 | } 56 | 57 | def "get /, with one item, should return item"() { 58 | given: 59 | client.newCall(new Request.Builder().url(server.url("/")).post( 60 | RequestBody.create(MediaType.parse("application/json"), 61 | mapper.writeValueAsString(new User(1L, "user", true)))).build()). 62 | execute() 63 | 64 | when: 65 | def result = client.newCall(new Request.Builder().url(server.url("/")).build()).execute() 66 | 67 | then: 68 | assert result.code() == 200 69 | assert result.body().string() == "{\"id\":1,\"username\":\"user\",\"enabled\":true}" 70 | } 71 | 72 | def "get /, with multiple items, should return array"() { 73 | given: 74 | client.newCall(new Request.Builder().url(server.url("/")).post( 75 | RequestBody.create(MediaType.parse("application/json"), 76 | mapper.writeValueAsString(new User(1L, "user", true)))).build()). 77 | execute() 78 | client.newCall(new Request.Builder().url(server.url("/")).post( 79 | RequestBody.create(MediaType.parse("application/json"), 80 | mapper.writeValueAsString(new User(2L, "user-2", true)))).build()). 81 | execute() 82 | 83 | when: 84 | def result = client.newCall(new Request.Builder().url(server.url("/")).build()).execute() 85 | 86 | then: 87 | assert result.code() == 200 88 | assert result.body().string() == 89 | "[{\"id\":1,\"username\":\"user\",\"enabled\":true},{\"id\":2,\"username\":\"user-2\",\"enabled\":true}]" 90 | } 91 | 92 | def "get /1, with existent item, should return item"() { 93 | given: 94 | client.newCall(new Request.Builder().url(server.url("/")).post( 95 | RequestBody.create(MediaType.parse("application/json"), 96 | mapper.writeValueAsString(new User(1L, "user", true)))).build()). 97 | execute() 98 | client.newCall(new Request.Builder().url(server.url("/")).post( 99 | RequestBody.create(MediaType.parse("application/json"), 100 | mapper.writeValueAsString(new User(2L, "user-2", true)))).build()). 101 | execute() 102 | 103 | when: 104 | def result = client.newCall(new Request.Builder().url(server.url("/1")).build()).execute() 105 | 106 | then: 107 | assert result.code() == 200 108 | assert result.body().string() == "{\"id\":1,\"username\":\"user\",\"enabled\":true}" 109 | } 110 | 111 | def "put /1, with missing item, should create item"() { 112 | when: 113 | def result = client.newCall(new Request.Builder().url(server.url("/1")).put( 114 | RequestBody.create(MediaType.parse("application/json"), 115 | mapper.writeValueAsString(new User(1L, "user-replaced", true)))).build()). 116 | execute() 117 | 118 | then: 119 | assert result.code() == 201 120 | assert result.body().string() == "{\"id\":1,\"username\":\"user-replaced\",\"enabled\":true}" 121 | } 122 | 123 | def "put /1, with existent item, should replace item"() { 124 | given: 125 | client.newCall(new Request.Builder().url(server.url("/")).post( 126 | RequestBody.create(MediaType.parse("application/json"), 127 | mapper.writeValueAsString(new User(1L, "user", true)))).build()). 128 | execute() 129 | 130 | when: 131 | def result = client.newCall(new Request.Builder().url(server.url("/1")).put( 132 | RequestBody.create(MediaType.parse("application/json"), 133 | mapper.writeValueAsString(new User(1L, "user-replaced", true)))).build()). 134 | execute() 135 | 136 | then: 137 | assert result.code() == 202 138 | assert result.body().string() == "{\"id\":1,\"username\":\"user-replaced\",\"enabled\":true}" 139 | def item = client.newCall(new Request.Builder().url(server.url("/1")).build()).execute() 140 | assert item.body().string() == "{\"id\":1,\"username\":\"user-replaced\",\"enabled\":true}" 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/test/groovy/io/fabric8/mockwebserver/DefaultMockServerHttpsTest.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver 17 | 18 | import okhttp3.OkHttpClient 19 | import spock.lang.Shared 20 | import spock.lang.Specification 21 | 22 | class DefaultMockServerHttpsTest extends Specification { 23 | 24 | DefaultMockServer server 25 | 26 | @Shared 27 | OkHttpClient client = new OkHttpClient() 28 | 29 | def setup() { 30 | server = new DefaultMockServer(true) 31 | server.start() 32 | } 33 | 34 | def cleanup() { 35 | server.shutdown() 36 | } 37 | 38 | def "url, with path, returns URL with HTTPS protocol"() { 39 | when: 40 | def result = server.url("/") 41 | 42 | then: 43 | assert result.startsWith("https://") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/groovy/io/fabric8/mockwebserver/DefaultMockServerWebSocketTest.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver 17 | 18 | import okhttp3.OkHttpClient 19 | import okhttp3.Request 20 | import okhttp3.Response 21 | import okhttp3.WebSocket 22 | import okhttp3.WebSocketListener 23 | import spock.lang.Shared 24 | import spock.lang.Specification 25 | 26 | import java.util.concurrent.CompletableFuture 27 | import java.util.concurrent.CountDownLatch 28 | import java.util.concurrent.TimeUnit 29 | import java.util.stream.Collectors 30 | import java.util.stream.IntStream 31 | 32 | class DefaultMockServerWebSocketTest extends Specification { 33 | 34 | DefaultMockServer server 35 | 36 | @Shared 37 | OkHttpClient client = new OkHttpClient() 38 | 39 | def setup() { 40 | server = new DefaultMockServer() 41 | server.start() 42 | } 43 | 44 | def cleanup() { 45 | server.shutdown() 46 | } 47 | 48 | def "andUpgradeToWebSocket, with configured events, should emit events"() { 49 | given: 50 | server.expect() 51 | .withPath("/websocket") 52 | .andUpgradeToWebSocket().open().waitFor(10L).andEmit("A text message").done().always() 53 | def future = new CompletableFuture() 54 | when: 55 | def ws = client.newWebSocket(new Request.Builder().url(server.url("/websocket")).build(), new WebSocketListener() { 56 | @Override 57 | void onMessage(WebSocket webSocket, String text) { 58 | future.complete(text) 59 | } 60 | }) 61 | then: 62 | assert future.get(100L, TimeUnit.MILLISECONDS) == "A text message" 63 | cleanup: 64 | ws.close(1000, "Test finished") 65 | } 66 | 67 | def "andUpgradeToWebSocket, with configured events, should emit onClose when done"() { 68 | given: 69 | server.expect() 70 | .withPath("/websocket") 71 | .andUpgradeToWebSocket().open().immediately().andEmit("event").done().always() 72 | def future = new CompletableFuture() 73 | when: 74 | def ws = client.newWebSocket(new Request.Builder().url(server.url("/websocket")).build(), new WebSocketListener() { 75 | @Override 76 | void onClosing(WebSocket webSocket, int code, String reason) { 77 | future.complete(reason) 78 | } 79 | }) 80 | then: 81 | assert future.get(100L, TimeUnit.MILLISECONDS) == "Closing..." 82 | } 83 | 84 | def "andUpgradeToWebSocket, with no events, should emit onClose"() { 85 | given: 86 | server.expect() 87 | .withPath("/websocket") 88 | .andUpgradeToWebSocket().open().done().always() 89 | def future = new CompletableFuture() 90 | when: 91 | def ws = client.newWebSocket(new Request.Builder().url(server.url("/websocket")).build(), new WebSocketListener() { 92 | @Override 93 | void onClosing(WebSocket webSocket, int code, String reason) { 94 | future.complete(reason) 95 | } 96 | }) 97 | then: 98 | assert future.get(100L, TimeUnit.MILLISECONDS) == "Closing..." 99 | } 100 | 101 | // https://github.com/fabric8io/mockwebserver/pull/66#issuecomment-944289335 102 | def "andUpgradeToWebSocket, with multiple upgrades, should emit events for all websocket listeners"() { 103 | given: 104 | server.expect() 105 | .withPath("/websocket") 106 | .andUpgradeToWebSocket().open().waitFor(10L).andEmit("A text message").done().always() 107 | def latch = new CountDownLatch(15) 108 | def wsListener = new WebSocketListener() { 109 | @Override 110 | void onMessage(WebSocket webSocket, String text) { 111 | latch.countDown() 112 | } 113 | } 114 | when: 115 | def wss = IntStream.range(0, 15).mapToObj(i -> 116 | client.newWebSocket(new Request.Builder().url(server.url("/websocket")).build(), wsListener) 117 | ).collect(Collectors.toList()) 118 | then: 119 | assert latch.await(10000L, TimeUnit.MILLISECONDS) 120 | cleanup: 121 | wss.forEach(ws -> ws.close(1000, "Test finished")) 122 | } 123 | 124 | // https://github.com/fabric8io/mockwebserver/issues/77 125 | def "andUpgradeToWebSocket, with request header 'sec-websocket-protocol', should create response with matching header"() { 126 | given: 127 | server.expect() 128 | .withPath("/websocket") 129 | .andUpgradeToWebSocket().open().done().always() 130 | def future = new CompletableFuture() 131 | when: 132 | def ws = client.newWebSocket(new Request.Builder().url(server.url("/websocket")).header("sec-websocket-protocol", "v4.channel.k8s.io").build(), new WebSocketListener() { 133 | @Override 134 | void onOpen(WebSocket webSocket, Response response) { 135 | future.complete(response.header("sec-websocket-protocol")) 136 | } 137 | }) 138 | then: 139 | assert future.get(100L, TimeUnit.MILLISECONDS) == "v4.channel.k8s.io" 140 | cleanup: 141 | ws.close(1000, "Test finished") 142 | } 143 | 144 | // https://github.com/fabric8io/mockwebserver/issues/77 145 | def "andUpgradeToWebSocket, with request header 'sec-websocket-protocol', should not change existing response header"() { 146 | given: 147 | server.expect() 148 | .withPath("/websocket") 149 | .andUpgradeToWebSocket() 150 | .open() 151 | .done() 152 | .withHeader("sec-websocket-protocol", "v3.channel.k8s.io,v4.channel.k8s.io") 153 | .always() 154 | def future = new CompletableFuture() 155 | when: 156 | def ws = client.newWebSocket(new Request.Builder().url(server.url("/websocket")).header("sec-websocket-protocol", "v4.channel.k8s.io").build(), new WebSocketListener() { 157 | @Override 158 | void onOpen(WebSocket webSocket, Response response) { 159 | future.complete(response.header("sec-websocket-protocol")) 160 | } 161 | }) 162 | then: 163 | assert future.get(100L, TimeUnit.MILLISECONDS) == "v3.channel.k8s.io,v4.channel.k8s.io" 164 | cleanup: 165 | ws.close(1000, "Test finished") 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/test/groovy/io/fabric8/mockwebserver/JsonResponseComposer.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver 17 | 18 | import io.fabric8.mockwebserver.crud.ResponseComposer 19 | 20 | import java.util.stream.Collectors 21 | 22 | class JsonResponseComposer implements ResponseComposer { 23 | @Override 24 | String compose(Collection items) { 25 | return "[" + items.stream().collect(Collectors.joining(",")) + "]" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/groovy/io/fabric8/mockwebserver/MockServerExceptionTest.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver 17 | 18 | import spock.lang.Specification 19 | 20 | class MockServerExceptionTest extends Specification { 21 | 22 | def "launderThrowable, with null, should throw MockServerException"() { 23 | when: 24 | MockServerException.launderThrowable(null) 25 | then: 26 | def result = thrown(MockServerException) 27 | assert result.getMessage() == "An error has occurred." 28 | assert result.getCause() == null 29 | } 30 | 31 | def "launderThrowable, with checked exception, should throw MockServerException"() { 32 | when: 33 | MockServerException.launderThrowable(new Exception("I'm checked")) 34 | then: 35 | def result = thrown(MockServerException) 36 | assert result.getMessage() == "An error has occurred." 37 | assert result.getCause().getClass() == Exception 38 | assert result.getCause().getMessage() == "I'm checked" 39 | } 40 | 41 | def "launderThrowable, with unchecked exception, should throw MockServerException"() { 42 | when: 43 | def result = MockServerException.launderThrowable(new RuntimeException("I'm unchecked")) 44 | then: 45 | assert result.getMessage() == "I'm unchecked" 46 | assert result.getClass() != MockServerException 47 | } 48 | 49 | def "launderThrowable, with Error, should not be handled"() { 50 | when: 51 | MockServerException.launderThrowable(new Error("I'm an Error")) 52 | then: 53 | def result = thrown(Error) 54 | assert result.getMessage() == "I'm an Error" 55 | } 56 | 57 | def "launderThrowable, with Interrupted Exception, should re-interrupt"() { 58 | when: 59 | MockServerException.launderThrowable(new InterruptedException("I'm interrupted")) 60 | then: 61 | assert Thread.currentThread().isInterrupted() 62 | def result = thrown(MockServerException) 63 | assert result.getMessage() == "An error has occurred." 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/groovy/io/fabric8/mockwebserver/User.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver 17 | 18 | import com.fasterxml.jackson.annotation.JsonInclude 19 | import com.fasterxml.jackson.annotation.JsonProperty 20 | 21 | @JsonInclude(JsonInclude.Include.NON_NULL) 22 | class User { 23 | 24 | @JsonProperty("id") 25 | private Long id 26 | 27 | @JsonProperty("username") 28 | private String username 29 | 30 | @JsonProperty("enabled") 31 | private Boolean enabled 32 | 33 | private User() { 34 | } 35 | 36 | public User(Long id, String username, Boolean enabled) { 37 | this.id = id 38 | this.username = username 39 | this.enabled = enabled 40 | } 41 | 42 | public Long getId() { 43 | return id 44 | } 45 | 46 | public void setId(Long id) { 47 | this.id = id 48 | } 49 | 50 | public String getUsername() { 51 | return username 52 | } 53 | 54 | public void setUsername(String username) { 55 | this.username = username 56 | } 57 | 58 | public Boolean getEnabled() { 59 | return enabled 60 | } 61 | 62 | public void setEnabled(Boolean enabled) { 63 | this.enabled = enabled 64 | } 65 | 66 | @Override 67 | public boolean equals(Object o) { 68 | if (this == o) return true 69 | if (o == null || getClass() != o.getClass()) return false 70 | 71 | User user = (User) o 72 | 73 | if (id != null ? !id.equals(user.id) : user.id != null) return false 74 | if (username != null ? !username.equals(user.username) : user.username != null) return false 75 | return enabled != null ? enabled.equals(user.enabled) : user.enabled == null 76 | 77 | } 78 | 79 | @Override 80 | public int hashCode() { 81 | int result = id != null ? id.hashCode() : 0 82 | result = 31 * result + (username != null ? username.hashCode() : 0) 83 | result = 31 * result + (enabled != null ? enabled.hashCode() : 0) 84 | return result 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/test/groovy/io/fabric8/mockwebserver/UserAttributeExtractor.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver 17 | 18 | import com.fasterxml.jackson.databind.ObjectMapper 19 | import io.fabric8.mockwebserver.crud.Attribute 20 | import io.fabric8.mockwebserver.crud.AttributeExtractor 21 | import io.fabric8.mockwebserver.crud.AttributeSet 22 | 23 | class UserAttributeExtractor implements AttributeExtractor { 24 | 25 | static def mapper = new ObjectMapper() 26 | 27 | @Override 28 | AttributeSet fromPath(String path) { 29 | if (path.trim().isBlank() || path.trim() == "/") { 30 | return new AttributeSet(); 31 | } 32 | return new AttributeSet(new Attribute("id", path.substring(1))) 33 | } 34 | 35 | @Override 36 | AttributeSet fromResource(String resource) { 37 | def user = mapper.readValue(resource, User) 38 | return new AttributeSet(new Attribute("id", user.getId().toString())) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/groovy/io/fabric8/mockwebserver/crud/AttributeSetTest.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud 17 | 18 | import spock.lang.Specification 19 | 20 | class AttributeSetTest extends Specification { 21 | 22 | def "when two feature set are empty the should be equals"() { 23 | given: 24 | when: 25 | AttributeSet f1 = new AttributeSet() 26 | AttributeSet f2 = new AttributeSet() 27 | then: 28 | assert f1.equals(f2) 29 | } 30 | 31 | def "when two feature sets contain the same feature"() { 32 | given: 33 | Attribute f = new Attribute("key1", "value1") 34 | when: 35 | AttributeSet f1 = new AttributeSet(f) 36 | AttributeSet f2 = new AttributeSet(f) 37 | then: 38 | assert f1.equals(f2) 39 | } 40 | 41 | def "when two feature sets contain the same features order should not matter"() { 42 | given: 43 | Attribute f1 = new Attribute("key1", "value1") 44 | Attribute f2 = new Attribute("key2", "value2") 45 | Attribute f3 = new Attribute("key3", "value3") 46 | when: 47 | AttributeSet fs12 = new AttributeSet(f1, f2) 48 | AttributeSet fs21 = new AttributeSet(f2, f1) 49 | AttributeSet fs23 = new AttributeSet(f2, f3) 50 | 51 | then: 52 | assert fs12.equals(fs21) 53 | assert !fs12.equals(fs23) 54 | assert !fs21.equals(fs23) 55 | } 56 | 57 | def "when an EXISTS attribute exists in both sets they should match"() { 58 | given: 59 | Attribute a1 = new Attribute("key1", "", AttributeType.EXISTS) 60 | Attribute a2 = new Attribute("key2", "value2") 61 | when: 62 | AttributeSet selector = new AttributeSet(a1, a2) 63 | AttributeSet attributeSet = new AttributeSet(a1, a2) 64 | then: 65 | assert attributeSet.matches(selector) 66 | } 67 | 68 | def "when an EXISTS attribute exists in one set but not the other sets they should not match"() { 69 | given: 70 | Attribute a1 = new Attribute("key1", "", AttributeType.EXISTS) 71 | Attribute a2 = new Attribute("key2", "value2") 72 | when: 73 | AttributeSet selector = new AttributeSet(a1, a2) 74 | AttributeSet attributeSet = new AttributeSet(a2) 75 | then: 76 | assert !attributeSet.matches(selector) 77 | } 78 | 79 | def "when a NOT_EXISTS attribute exists in both sets they should not match"() { 80 | given: 81 | Attribute a1 = new Attribute("key1", "", AttributeType.NOT_EXISTS) 82 | Attribute a2 = new Attribute("key2", "value2") 83 | when: 84 | AttributeSet selector = new AttributeSet(a1, a2) 85 | AttributeSet attributeSet = new AttributeSet(a1, a2) 86 | then: 87 | assert !attributeSet.matches(selector) 88 | } 89 | 90 | def "when a NOT_EXISTS attribute exists in one set but not the other sets they should match"() { 91 | given: 92 | Attribute a1 = new Attribute("key1", "", AttributeType.NOT_EXISTS) 93 | Attribute a2 = new Attribute("key2", "value2") 94 | when: 95 | AttributeSet selector = new AttributeSet(a1, a2) 96 | AttributeSet attributeSet = new AttributeSet(a2) 97 | then: 98 | assert attributeSet.matches(selector) 99 | } 100 | 101 | def "when multiple attributes are specified it should examine all"() { 102 | given: 103 | // Naming is important here as it controls the hashed order 104 | Attribute a2 = new Attribute("key2", "value2") 105 | Attribute a3 = new Attribute("key3", "", AttributeType.EXISTS) 106 | when: 107 | AttributeSet attributeSet = new AttributeSet(a2) 108 | AttributeSet selectorWithOne = new AttributeSet(a2) 109 | AttributeSet selectorWithTwo = new AttributeSet(a2, a3); 110 | then: 111 | 112 | // Assert that the order is suitable for testing. The failing attribute should 113 | // be in the *second* position to ensure we're examining all the values of the selector 114 | assert new ArrayList<>(selectorWithTwo.attributes.values()).indexOf(a3) == 1; 115 | 116 | assert attributeSet.matches(selectorWithOne) 117 | assert !attributeSet.matches(selectorWithTwo) 118 | } 119 | 120 | def "when IN attribute in selector"() { 121 | given: 122 | Attribute a1 = new Attribute("key1", "value") 123 | Attribute a2 = new Attribute("key2", "value1") 124 | Attribute a3 = new Attribute("key2", "value2") 125 | Attribute a4 = new Attribute("key2", "value3") 126 | Attribute a5 = new Attribute("key2", Arrays.asList("value1", "value2"), AttributeType.IN) 127 | 128 | when: 129 | AttributeSet attributeSetWithoutAttr = new AttributeSet(a1) 130 | AttributeSet attributeSetWithVal1 = new AttributeSet(a2) 131 | AttributeSet attributeSetWithVal2 = new AttributeSet(a3) 132 | AttributeSet attributeSetWithWrongVal = new AttributeSet(a4) 133 | AttributeSet selector = new AttributeSet(a5); 134 | 135 | then: 136 | assert !attributeSetWithoutAttr.matches(selector) 137 | assert attributeSetWithVal1.matches(selector) 138 | assert attributeSetWithVal2.matches(selector) 139 | assert !attributeSetWithWrongVal.matches(selector) 140 | } 141 | 142 | def "when NOT_IN attribute in selector"() { 143 | given: 144 | Attribute a1 = new Attribute("key1", "value") 145 | Attribute a2 = new Attribute("key2", "value1") 146 | Attribute a3 = new Attribute("key2", "value2") 147 | Attribute a4 = new Attribute("key2", "value3") 148 | Attribute a5 = new Attribute("key2", Arrays.asList("value1", "value2"), AttributeType.NOT_IN) 149 | 150 | when: 151 | AttributeSet attributeSetWithoutAttr = new AttributeSet(a1) 152 | AttributeSet attributeSetWithVal1 = new AttributeSet(a2) 153 | AttributeSet attributeSetWithVal2 = new AttributeSet(a3) 154 | AttributeSet attributeSetWithWrongVal = new AttributeSet(a4) 155 | AttributeSet selector = new AttributeSet(a5); 156 | 157 | then: 158 | assert attributeSetWithoutAttr.matches(selector) 159 | assert !attributeSetWithVal1.matches(selector) 160 | assert !attributeSetWithVal2.matches(selector) 161 | assert attributeSetWithWrongVal.matches(selector) 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /src/test/groovy/io/fabric8/mockwebserver/crud/AttributeTest.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud 17 | 18 | import spock.lang.Specification 19 | 20 | class AttributeTest extends Specification { 21 | 22 | def "when key and value equals features should equal"() { 23 | given: 24 | when: 25 | Attribute f11 = new Attribute("key1", "value1") 26 | Attribute f11a = new Attribute("key1", "value1") 27 | Attribute f12 = new Attribute("key1", "value2") 28 | Attribute f22 = new Attribute("key2", "value2") 29 | 30 | then: 31 | assert !f11.equals(f22) 32 | assert !f11.equals(f12) 33 | assert f11.equals(f11a) 34 | } 35 | 36 | def "equals, with same attributes but different type, should be true"() { 37 | given: 38 | Attribute a1 = new Attribute("key1", "value1", AttributeType.EXISTS) 39 | Attribute a2 = new Attribute("key1", "value1", AttributeType.NOT_EXISTS) 40 | when: 41 | var result = a1 == a2 42 | then: 43 | assert result 44 | } 45 | 46 | def "hashCode, with same attributes but different type, should be equal"() { 47 | given: 48 | Attribute a1 = new Attribute("key1", "value1", AttributeType.EXISTS) 49 | Attribute a2 = new Attribute("key1", "value1", AttributeType.NOT_EXISTS) 50 | when: 51 | var result = a1.hashCode() == a2.hashCode() 52 | then: 53 | assert result 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/groovy/io/fabric8/mockwebserver/crud/CrudDispatcherTest.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Red Hat, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.fabric8.mockwebserver.crud 17 | 18 | import io.fabric8.mockwebserver.Context 19 | import io.fabric8.mockwebserver.DefaultMockServer 20 | import io.fabric8.mockwebserver.ServerRequest 21 | import io.fabric8.mockwebserver.ServerResponse 22 | import okhttp3.OkHttpClient 23 | import okhttp3.Request 24 | import okhttp3.Response 25 | import okhttp3.RequestBody 26 | import okhttp3.MediaType 27 | import okhttp3.mockwebserver.MockWebServer 28 | import spock.lang.Specification 29 | import com.fasterxml.jackson.databind.JsonNode 30 | 31 | class CrudDispatcherTest extends Specification { 32 | 33 | AttributeExtractor extractor = new AttributeExtractor() { 34 | 35 | @Override 36 | AttributeSet fromPath(String path) { 37 | AttributeSet set = new AttributeSet() 38 | 39 | String[] parts = path.split("/") 40 | if (parts.length > 2) { 41 | set = set.add(new Attribute("namespace", parts[2])) 42 | } 43 | 44 | if (parts.length > 4) { 45 | set = set.add(new Attribute("name", parts[4])) 46 | } 47 | return set 48 | } 49 | 50 | @Override 51 | AttributeSet fromResource(String resource) { 52 | return null 53 | } 54 | } 55 | 56 | ResponseComposer composer = new ResponseComposer() { 57 | @Override 58 | String compose(Collection items) { 59 | StringBuilder sb = new StringBuilder(); 60 | for (String item : items) { 61 | sb.append(item).append(" ") 62 | } 63 | return sb.toString().trim() 64 | } 65 | } 66 | 67 | def "should be able to get after a patch"() { 68 | given: 69 | Context context = new Context() 70 | DefaultMockServer server = new DefaultMockServer(context, new MockWebServer(), new HashMap>(), new CrudDispatcher(context, extractor, composer), false) 71 | String startingJson = """{"foo":{"bar":"startingValue","baz":"keepThis"} }""" 72 | String patch = """[{"op":"replace","path":"/foo/bar","value":"canary"}]""" 73 | when: 74 | server.start() 75 | then: 76 | OkHttpClient client = new OkHttpClient() 77 | Request post = new Request.Builder().post(RequestBody.create(MediaType.parse("application/json"), startingJson)).url(server.url("/namespace/test/name/one")).build() 78 | client.newCall(post).execute() 79 | 80 | Request patchRequest = new Request.Builder().patch(RequestBody.create(MediaType.parse("application/strategic-merge-patch+json"), patch)).url(server.url("/namespace/test/name/one")).build() 81 | client.newCall(patchRequest).execute() 82 | 83 | Request get = new Request.Builder().get().url(server.url("/namespace/test/name/one")).build() 84 | Response response = client.newCall(get).execute() 85 | JsonNode responseJson = context.getMapper().readValue(response.body().string(), JsonNode.class); 86 | JsonNode expected = context.mapper.readValue("""{"foo": {"bar": "canary", "baz": "keepThis"}}""", JsonNode.class) 87 | expected == responseJson 88 | } 89 | 90 | def "should be able to get after a post"() { 91 | given: 92 | Context context = new Context() 93 | DefaultMockServer server = new DefaultMockServer(context, new MockWebServer(), new HashMap>(), new CrudDispatcher(context, extractor, composer), false) 94 | when: 95 | server.start() 96 | then: 97 | OkHttpClient client = new OkHttpClient() 98 | Request post = new Request.Builder().post(RequestBody.create(MediaType.parse("text/html"), "one")).url(server.url("/namespace/test/name/one")).build() 99 | client.newCall(post).execute() 100 | Request get = new Request.Builder().get().url(server.url("/namespace/test/name/one")).build() 101 | Response response = client.newCall(get).execute() 102 | assert response.body().string().equals("one") 103 | } 104 | 105 | def "should be able to delete after a post"() { 106 | given: 107 | Context context = new Context() 108 | DefaultMockServer server = new DefaultMockServer(context, new MockWebServer(), new HashMap>(), new CrudDispatcher(context, extractor, composer), false) 109 | when: 110 | server.start() 111 | then: 112 | OkHttpClient client = new OkHttpClient() 113 | Request post = new Request.Builder().post(RequestBody.create(MediaType.parse("text/html"), "one")).url(server.url("/namespace/test/name/one")).build() 114 | client.newCall(post).execute() 115 | Request get = new Request.Builder().delete().url(server.url("/namespace/test/name/one")).build() 116 | Response response = client.newCall(get).execute() 117 | assert response.successful 118 | 119 | Request getMissing = new Request.Builder().delete().url(server.url("/namespace/test/name/two")).build() 120 | Response responseMissing = client.newCall(getMissing).execute() 121 | assert !responseMissing.successful 122 | } 123 | 124 | } 125 | --------------------------------------------------------------------------------