├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── pom.xml └── src ├── lombok.config ├── main └── java │ └── com │ └── codepine │ └── api │ └── testrail │ ├── Request.java │ ├── TestRail.java │ ├── TestRailConfig.java │ ├── TestRailException.java │ ├── internal │ ├── BooleanToIntSerializer.java │ ├── CaseModule.java │ ├── CsvToListDeserializer.java │ ├── FieldModule.java │ ├── IntToBooleanDeserializer.java │ ├── ListToCsvSerializer.java │ ├── PageDeserializer.java │ ├── PlanModule.java │ ├── QueryParameterString.java │ ├── ResultModule.java │ ├── StringToMapDeserializer.java │ ├── UnixTimestampModule.java │ └── UrlConnectionFactory.java │ └── model │ ├── Case.java │ ├── CaseField.java │ ├── CaseType.java │ ├── Configuration.java │ ├── Field.java │ ├── Links.java │ ├── Milestone.java │ ├── Page.java │ ├── Plan.java │ ├── Priority.java │ ├── Project.java │ ├── Result.java │ ├── ResultField.java │ ├── Run.java │ ├── Section.java │ ├── Status.java │ ├── Suite.java │ ├── Test.java │ └── User.java └── test ├── java └── com │ └── codepine │ └── api │ └── testrail │ ├── RequestTest.java │ └── internal │ ├── BooleanToIntSerializerTest.java │ ├── CaseModuleTest.java │ ├── CsvToListDeserializerTest.java │ ├── FieldModuleTest.java │ ├── IntToBooleanDeserializerTest.java │ ├── ListToCsvSerializerTest.java │ ├── PlanModuleTest.java │ ├── ResultModuleTest.java │ ├── StringToMapDeserializerTest.java │ └── UnixTimestampModuleTest.java └── resources ├── add_model.json ├── auth_error.json ├── case_with_no_custom_fields.json ├── case_with_step_field_set.json ├── get_cases.json ├── get_model.json ├── get_model_error.json ├── get_models.json ├── get_modelsA.json ├── get_modelsB.json ├── get_modelsC.json ├── log4j.properties ├── plan_with_entries.json ├── plan_with_no_entries.json ├── result_with_no_custom_fields.json ├── result_with_step_result_field_set.json ├── step_field.json ├── step_result_field.json └── update_model.json /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | *.log 4 | *.apk 5 | *.zip 6 | .settings/* 7 | delombok/* 8 | target/* 9 | test-output/* 10 | reports/* 11 | /reports 12 | /.metadata/ 13 | /.classpath 14 | /.project 15 | .idea 16 | *.iml 17 | /target/ 18 | /bin/ 19 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [v2.0.2](https://github.com/codepine/testrail-api-java-client/tree/v2.0.2) (2021-10-07) 4 | 5 | [Full Changelog](https://github.com/codepine/testrail-api-java-client/compare/v2.0.1...v2.0.2) 6 | 7 | **Close issues:** 8 | 9 | - Fix for pagination [\#68](https://github.com/codepine/testrail-api-java-client/pull/68) ([maksimsarychau](https://github.com/maksimsarychau)) 10 | - Add entry's description in plans. [\#42](https://github.com/codepine/testrail-api-java-client/pull/42) ([ChenChiaHung](https://github.com/ChenChiaHung)) 11 | 12 | ## [v2.0.1](https://github.com/codepine/testrail-api-java-client/tree/v2.0.1) (2018-12-02) 13 | 14 | [Full Changelog](https://github.com/codepine/testrail-api-java-client/compare/v2.0.0...v2.0.1) 15 | 16 | **Closed issues:** 17 | 18 | - Unable to delete Entry from testplan using EntryId [\#29](https://github.com/codepine/testrail-api-java-client/issues/29) 19 | - Cannot deserialize instance of java.util.ArrayList out of VALUE_STRING token for "config" property [\#15](https://github.com/codepine/testrail-api-java-client/issues/15) 20 | 21 | ## [v2.0.0](https://github.com/codepine/testrail-api-java-client/tree/v2.0.0) (2017-08-19) 22 | 23 | [Full Changelog](https://github.com/codepine/testrail-api-java-client/compare/v1.0.2...v2.0.0) 24 | 25 | **Closed issues:** 26 | 27 | - Upgrade to JDK8 [\#23](https://github.com/codepine/testrail-api-java-client/issues/23) 28 | - Upgrade Guava version from 16.x to 21.x ([apolaskey](https://github.com/apolaskey)) 29 | * [\#21](https://github.com/codepine/testrail-api-java-client/issues/21) 30 | * [\#20](https://github.com/codepine/testrail-api-java-client/issues/20) 31 | * [\#18](https://github.com/codepine/testrail-api-java-client/issues/18) 32 | * [\#14](https://github.com/codepine/testrail-api-java-client/issues/14) 33 | - Add section description [\#16](https://github.com/codepine/testrail-api-java-client/pull/16) ([sofiaguyang](https://github.com/sofiaguyang)) 34 | 35 | ## [v1.0.2](https://github.com/codepine/testrail-api-java-client/tree/v1.0.2) (2016-12-17) 36 | [Full Changelog](https://github.com/codepine/testrail-api-java-client/compare/v1.0.1...v1.0.2) 37 | 38 | **Closed issues:** 39 | 40 | - 411 [\#11](https://github.com/codepine/testrail-api-java-client/issues/11) 41 | 42 | ## [v1.0.1](https://github.com/codepine/testrail-api-java-client/tree/v1.0.1) (2016-02-27) 43 | [Full Changelog](https://github.com/codepine/testrail-api-java-client/compare/v1.0.0...v1.0.1) 44 | 45 | **Closed issues:** 46 | 47 | - Unable to query for cases with TestRail 5.2 or later. [\#8](https://github.com/codepine/testrail-api-java-client/issues/8) 48 | 49 | ## [v1.0.0](https://github.com/codepine/testrail-api-java-client/tree/v1.0.0) (2015-03-24) 50 | 51 | 52 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 codepine 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TestRail API Java Client 2 | -------------------------- 3 | 4 | A Java client library for [TestRail API](http://docs.gurock.com/testrail-api2/start). 5 | 6 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.codepine.api/testrail-api-java-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.codepine.api/testrail-api-java-client) 7 | 8 | ## Quick Start 9 | -------------- 10 | 11 | ### Maven Dependency 12 | ```xml 13 | 14 | com.codepine.api 15 | testrail-api-java-client 16 | ${stable.version.shown.above} 17 | 18 | ``` 19 | 20 | ### Example Usage 21 | ```java 22 | // create a TestRail instance 23 | TestRail testRail = TestRail.builder("https://some.testrail.net/", "username", "password").applicationName("playground").build(); 24 | 25 | // create a new project 26 | Project project = testRail.projects().add(new Project().setName("Playground Project")).execute(); 27 | 28 | // add a new test suite 29 | Suite suite = testRail.suites().add(project.getId(), new Suite().setName("Functional Tests")).execute(); 30 | 31 | // add a new section 32 | Section section = testRail.sections().add(project.getId(), new Section().setSuiteId(suite.getId()).setName("Boundary Cases")).execute(); 33 | 34 | // add a test case 35 | List customCaseFields = testRail.caseFields().list().execute(); 36 | Case testCase = testRail.cases().add(section.getId(), new Case().setTitle("Be able to play in playground"), customCaseFields).execute(); 37 | 38 | // add a new test run 39 | Run run = testRail.runs().add(project.getId(), new Run().setSuiteId(suite.getId()).setName("Weekly Regression")).execute(); 40 | 41 | // add test result 42 | List customResultFields = testRail.resultFields().list().execute(); 43 | testRail.results().addForCase(run.getId(), testCase.getId(), new Result().setStatusId(1), customResultFields).execute(); 44 | 45 | // close the run 46 | testRail.runs().close(run.getId()).execute(); 47 | 48 | // complete the project - supports partial updates 49 | testRail.projects().update(project.setCompleted(true)).execute(); 50 | ``` 51 | 52 | ## Supported TestRail Version 53 | ----------------------------- 54 | ![TestRail v4.1](https://img.shields.io/badge/TestRail-v4.1-blue.svg) 55 | [![TestRail v4.1](https://img.shields.io/badge/TestRail%20API-v2-orange.svg)](http://docs.gurock.com/testrail-api2/start) 56 | 57 | [Old API (aka Mini API)](http://docs.gurock.com/testrail-api/start) is not supported. Please note that you may not be able to use some API features supported by this library depending on the TestRail version you use. Similarly, since this is not an official library, API updates in future versions of TestRail may not be supported immediately with the release of new version or may need an incompatible major version change. 58 | 59 | ## Notables 60 | ------------ 61 | 62 | ### Thin Client Library 63 | Except the initial configration (refer to [example](#example-usage)), this client library does not maintain any state from your TestRail service. You can maintain/cache state on your end if you like. 64 | 65 | ### Custom Case And Result Fields 66 | TestRail supports adding custom case and result fields. The request interfaces in ```TestRail.Cases``` and ```TestRail.Results``` requires a list of these fields in order to allow this library to map them to the correct Java types. Here's an example where we want to to know the separated test steps of a particular test case: 67 | ```java 68 | // fetch list of custom case field configured in TestRail 69 | List customCaseFields = testRail.caseFields().list().execute(); 70 | 71 | // get test case 72 | Case testCase = testRail.cases().get(1, customCaseFields).execute(); 73 | 74 | // assuming separated_steps is a custom TestRail Steps type case field 75 | List customSteps = testCase.getCustomField("separated_steps"); 76 | 77 | // work with typed customSteps 78 | ...... 79 | ``` 80 | Find the map of supported TestRail field types to Java types in the javadoc of ```Field.Type``` enum. 81 | As mentioned [above](#thin-client-library), since this is a thin library, it does not store the list of fields. You can cache them on your end if you like. 82 | 83 | ## License 84 | ---------- 85 | This project is licensed under [MIT license](http://opensource.org/licenses/MIT). 86 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.codepine.api 5 | testrail-api-java-client 6 | 2.0.3-SNAPSHOT 7 | jar 8 | 9 | TestRail API Java Client 10 | Java client for TestRail API 11 | https://github.com/codepine/testrail-api-java-client 12 | 13 | 14 | 15 | MIT License 16 | http://www.opensource.org/licenses/mit-license.php 17 | repo 18 | 19 | 20 | 21 | 22 | scm:git:git@github.com:codepine/testrail-api-java-client.git 23 | scm:git:git@github.com:codepine/testrail-api-java-client.git 24 | scm:git:git@github.com:codepine/testrail-api-java-client.git 25 | HEAD 26 | 27 | 28 | 29 | 30 | Kunal Shah 31 | kunal546@gmail.com 32 | codepine.com 33 | https://github.com/codepine 34 | 35 | 36 | 37 | 38 | 39 | ossrh 40 | https://oss.sonatype.org/content/repositories/snapshots 41 | 42 | 43 | 44 | 45 | 46 | 1.8 47 | 1.16.2 48 | 2.3.1 49 | 21.0 50 | 1.2.17 51 | 4.11 52 | 1.9.5 53 | 54 | 55 | 1.16.2.0 56 | 3.1 57 | 2.4 58 | 0.7.3.201502191951 59 | 3.0.0-M1 60 | 1.6 61 | 2.5.1 62 | 1.6.5 63 | 64 | 65 | target/generated-sources/delombok 66 | target/generated-test-sources/delombok 67 | 68 | 69 | 70 | 71 | org.projectlombok 72 | lombok 73 | ${lombok.version} 74 | provided 75 | 76 | 77 | com.fasterxml.jackson.core 78 | jackson-databind 79 | ${jackson.version} 80 | 81 | 82 | com.google.guava 83 | guava 84 | ${guava.version} 85 | 86 | 87 | log4j 88 | log4j 89 | ${log4j.version} 90 | 91 | 92 | junit 93 | junit 94 | ${junit.version} 95 | test 96 | 97 | 98 | org.mockito 99 | mockito-core 100 | ${mockito.version} 101 | test 102 | 103 | 104 | 105 | 106 | 107 | lombok-needs-tools-jar 108 | 109 | 110 | ${java.home}/../lib/tools.jar 111 | 112 | 113 | 114 | 115 | 116 | org.projectlombok 117 | lombok-maven-plugin 118 | ${lombok.plugin.version} 119 | 120 | 121 | sun.jdk 122 | tools 123 | ${jdk.version} 124 | system 125 | ${java.home}/../lib/tools.jar 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | release 134 | 135 | 136 | 137 | org.apache.maven.plugins 138 | maven-source-plugin 139 | ${maven.source.plugin.version} 140 | 141 | 142 | attach-sources 143 | 144 | jar 145 | 146 | 147 | 148 | 149 | 150 | org.apache.maven.plugins 151 | maven-javadoc-plugin 152 | ${maven.javadoc.plugin.version} 153 | 154 | ${project.version} 155 | ${src.dir} 156 | com.codepine.api.testrail.internal 157 | -Xdoclint:none 158 | 159 | 160 | 161 | attach-javadocs 162 | 163 | jar 164 | 165 | 166 | 167 | 168 | 169 | org.apache.maven.plugins 170 | maven-gpg-plugin 171 | ${maven.gpg.plugin.version} 172 | 173 | 174 | sign-artifacts 175 | verify 176 | 177 | sign 178 | 179 | 180 | 181 | 182 | 183 | org.sonatype.plugins 184 | nexus-staging-maven-plugin 185 | ${nexus.staging.maven.plugin.version} 186 | true 187 | 188 | ossrh 189 | https://oss.sonatype.org/ 190 | false 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | ${src.dir} 200 | ${tst.dir} 201 | 202 | 203 | org.projectlombok 204 | lombok-maven-plugin 205 | ${lombok.plugin.version} 206 | 207 | 208 | delombok 209 | generate-sources 210 | 211 | delombok 212 | 213 | 214 | UTF-8 215 | 216 | skip 217 | 218 | false 219 | src/main/java 220 | true 221 | 222 | 223 | 224 | test-delombok 225 | generate-test-sources 226 | 227 | testDelombok 228 | 229 | 230 | UTF-8 231 | true 232 | false 233 | src/test/java 234 | 235 | 236 | 237 | 238 | 239 | org.apache.maven.plugins 240 | maven-compiler-plugin 241 | ${maven.compiler.plugin.version} 242 | 243 | ${jdk.version} 244 | ${jdk.version} 245 | ${jdk.version} 246 | 247 | 248 | 249 | org.jacoco 250 | jacoco-maven-plugin 251 | ${jacoco.plugin.version} 252 | 253 | 254 | default-prepare-agent 255 | 256 | prepare-agent 257 | 258 | 259 | 260 | coverage-report 261 | prepare-package 262 | 263 | report 264 | 265 | 266 | 267 | 268 | 269 | org.apache.maven.plugins 270 | maven-release-plugin 271 | ${maven.release.plugin.version} 272 | 273 | v@{project.version} 274 | release 275 | 276 | 277 | 278 | 279 | 280 | -------------------------------------------------------------------------------- /src/lombok.config: -------------------------------------------------------------------------------- 1 | lombok.accessors.fluent = false 2 | lombok.accessors.chain = true 3 | 4 | config.stopBubbling = true -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/Request.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail; 26 | 27 | import com.codepine.api.testrail.internal.*; 28 | import com.codepine.api.testrail.model.Page; 29 | import com.fasterxml.jackson.annotation.JsonInclude; 30 | import com.fasterxml.jackson.core.type.TypeReference; 31 | import com.fasterxml.jackson.databind.*; 32 | import com.google.common.base.Charsets; 33 | import com.google.common.io.ByteStreams; 34 | import lombok.NonNull; 35 | import lombok.extern.log4j.Log4j; 36 | 37 | import javax.xml.bind.DatatypeConverter; 38 | import java.io.*; 39 | import java.lang.reflect.ParameterizedType; 40 | import java.lang.reflect.Type; 41 | import java.net.HttpURLConnection; 42 | import java.net.MalformedURLException; 43 | import java.nio.charset.Charset; 44 | import java.util.ArrayList; 45 | import java.util.List; 46 | import java.util.regex.Matcher; 47 | import java.util.regex.Pattern; 48 | 49 | /** 50 | * TestRail request. 51 | */ 52 | @Log4j 53 | public abstract class Request { 54 | 55 | private static final UrlConnectionFactory DEFAULT_URL_CONNECTION_FACTORY = new UrlConnectionFactory(); 56 | 57 | private static final ObjectMapper JSON = new ObjectMapper() 58 | .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) 59 | .configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false) 60 | .setSerializationInclusion(JsonInclude.Include.NON_NULL) 61 | .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) 62 | .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) 63 | .registerModules(new CaseModule(), new FieldModule(), new PlanModule(), new ResultModule(), new UnixTimestampModule()); 64 | 65 | @NonNull 66 | private final TestRailConfig config; 67 | @NonNull 68 | private final Method method; 69 | @NonNull 70 | private String restPath; 71 | private String apiSegment; 72 | private final Class responseClass; 73 | private final TypeReference responseType; 74 | private final TypeReference> pageType; 75 | private UrlConnectionFactory urlConnectionFactory = DEFAULT_URL_CONNECTION_FACTORY; 76 | 77 | Request(TestRailConfig config, Method method, String restPath, Class responseClass, TypeReference 78 | responseType, TypeReference> pageType) { 79 | this.config = config; 80 | this.method = method; 81 | 82 | this.responseClass = responseClass; 83 | this.responseType = responseType; 84 | this.pageType = pageType; 85 | this.apiSegment = config.getBaseApiUrl().split("\\?")[1]; 86 | this.restPath = restPath.replace(this.apiSegment, ""); 87 | } 88 | 89 | /** 90 | * @param config TestRail configuration 91 | * @param method the HTTP method for request 92 | * @param restPath the path of the request URL 93 | * @param responseClass the type of the response entity 94 | */ 95 | Request(TestRailConfig config, Method method, String restPath, @NonNull Class responseClass) { 96 | this(config, method, restPath, responseClass, null, null); 97 | } 98 | 99 | /** 100 | * @param config TestRail configuration 101 | * @param method the HTTP method for request 102 | * @param restPath the path of the request URL 103 | * @param responseType the type of the response entity 104 | */ 105 | Request(TestRailConfig config, Method method, String restPath, @NonNull TypeReference responseType) { 106 | this(config, method, restPath, null, responseType, null); 107 | } 108 | 109 | Request(TestRailConfig config, Method method, String restPath, @NonNull TypeReference responseType, 110 | @NonNull TypeReference> pageType) { 111 | this(config, method, restPath, null, responseType, pageType); 112 | } 113 | 114 | /** 115 | * Get URL string for this request. 116 | * 117 | * @return the string URL 118 | * @throws IOException if there is an error creating query parameter string 119 | */ 120 | private String getUrl() throws IOException { 121 | StringBuilder urlBuilder = new StringBuilder(config.getBaseApiUrl()).append(restPath); 122 | 123 | String queryParamJson = JSON.writerWithView(getClass()).writeValueAsString(this); 124 | String queryParamString = JSON.readValue(queryParamJson, QueryParameterString.class).toString(); 125 | if (!queryParamString.isEmpty()) { 126 | urlBuilder.append("&").append(queryParamString); 127 | } 128 | 129 | return urlBuilder.toString(); 130 | } 131 | 132 | /** 133 | * Override this method to provide content to be send with {@code Method#POST} requests. 134 | * 135 | * @return content 136 | */ 137 | Object getContent() { 138 | return null; 139 | } 140 | 141 | /** 142 | * Override this method to provide supplementary information to deserializer. 143 | * 144 | * @return any object acting as supplement for deserialization 145 | */ 146 | Object getSupplementForDeserialization() { 147 | return null; 148 | } 149 | 150 | /** 151 | * Execute this request. 152 | * 153 | * @return response from TestRail 154 | */ 155 | public T execute() { 156 | try { 157 | 158 | String url = getUrl(); 159 | HttpURLConnection con = (HttpURLConnection) urlConnectionFactory.getUrlConnection(url); 160 | con.setRequestMethod(method.name()); 161 | if (config.getApplicationName().isPresent()) { 162 | con.setRequestProperty("User-Agent", config.getApplicationName().get()); 163 | } 164 | con.setRequestProperty("Content-Type", "application/json"); 165 | String basicAuth = "Basic " 166 | + DatatypeConverter.printBase64Binary((config.getUsername() 167 | + ":" + config.getPassword()).getBytes(Charset.forName("UTF-8"))); 168 | con.setRequestProperty("Authorization", basicAuth); 169 | if (method == Method.POST) { 170 | con.setDoOutput(true); 171 | Object content = getContent(); 172 | if (content != null) { 173 | try (OutputStream outputStream = new BufferedOutputStream(con.getOutputStream())) { 174 | JSON.writerWithView(this.getClass()).writeValue(outputStream, content); 175 | } 176 | } else { 177 | con.setFixedLengthStreamingMode(0); 178 | } 179 | } 180 | log.debug("Sending " + method + " request to URL : " + url); 181 | int responseCode = 0; 182 | try { 183 | responseCode = con.getResponseCode(); 184 | } catch (IOException e) { 185 | // swallow it since for 401 getResponseCode throws an IOException 186 | responseCode = con.getResponseCode(); 187 | } 188 | log.debug("Response Code : " + responseCode); 189 | 190 | if (responseCode != HttpURLConnection.HTTP_OK) { 191 | try (InputStream errorStream = con.getErrorStream()) { 192 | TestRailException.Builder exceptionBuilder = new TestRailException.Builder().setResponseCode(responseCode); 193 | if (errorStream == null) { 194 | throw exceptionBuilder.setError("").build(); 195 | } 196 | throw JSON.readerForUpdating(exceptionBuilder).readValue(new BufferedInputStream(errorStream)).build(); 197 | } 198 | } 199 | 200 | try (InputStream responseStream = new BufferedInputStream(con.getInputStream())) { 201 | Object supplementForDeserialization = getSupplementForDeserialization(); 202 | if (responseClass != null) { 203 | if (responseClass == Void.class) { 204 | return null; 205 | } 206 | if (supplementForDeserialization != null) { 207 | return JSON.reader(responseClass).with(new InjectableValues.Std().addValue(responseClass.toString(), supplementForDeserialization)).readValue(responseStream); 208 | } 209 | return JSON.readValue(responseStream, responseClass); 210 | } else { 211 | String payload = new String(ByteStreams.toByteArray(responseStream), Charsets.UTF_8).replace("\"_links\":", "\"links\":"); 212 | if (((ParameterizedType) responseType.getType()).getRawType().getTypeName().equals("java.util.List") 213 | && payload.contains("\"offset\":") && payload.contains("\"limit\":") && payload.contains("\"offset\":")) { 214 | Matcher matcher = Pattern.compile("get_([^\\_/]+)").matcher(restPath); 215 | if (matcher.find()) 216 | PageDeserializer.field = matcher.group(1); 217 | try { 218 | PageDeserializer.type = Class.forName(((ParameterizedType) responseType.getType()).getActualTypeArguments()[0].getTypeName()); 219 | } 220 | catch(Exception e) { 221 | return ((T)new ArrayList()); 222 | } 223 | if (supplementForDeserialization != null) { 224 | PageDeserializer.supplement = supplementForDeserialization; 225 | } 226 | Page page = JSON.readValue(payload, pageType); 227 | if (page._links.next != null) { 228 | restPath = page._links.next.replace(this.apiSegment, ""); 229 | T concat = execute(); 230 | T models = page.objects; 231 | ((List)models).addAll(((List)concat)); 232 | return models; 233 | } 234 | else 235 | return page.objects; 236 | } 237 | else if (supplementForDeserialization != null) { 238 | String supplementKey = responseType.getType().toString(); 239 | if (responseType.getType() instanceof ParameterizedType) { 240 | Type[] actualTypes = ((ParameterizedType) responseType.getType()).getActualTypeArguments(); 241 | if (actualTypes.length == 1 && actualTypes[0] instanceof Class) { 242 | supplementKey = actualTypes[0].toString(); 243 | } 244 | } 245 | return JSON.reader(responseType).with(new InjectableValues.Std().addValue(supplementKey, supplementForDeserialization)).readValue(payload); 246 | } 247 | return JSON.readValue(payload, responseType); 248 | } 249 | } 250 | 251 | } catch (MalformedURLException e) { 252 | throw new RuntimeException(e); 253 | } catch (IOException e) { 254 | throw new RuntimeException(e); 255 | } 256 | } 257 | 258 | /** 259 | * Set URL connection factory. Only used for testing. 260 | * 261 | * @param urlConnectionFactory the URL connection factory 262 | */ 263 | void setUrlConnectionFactory(UrlConnectionFactory urlConnectionFactory) { 264 | this.urlConnectionFactory = urlConnectionFactory; 265 | } 266 | 267 | /** 268 | * Allowed HTTP methods. 269 | */ 270 | static enum Method { 271 | GET, POST; 272 | } 273 | 274 | } 275 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/TestRailConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail; 26 | 27 | import com.google.common.base.Optional; 28 | import lombok.*; 29 | 30 | /** 31 | * Configuration for using this client library. 32 | */ 33 | @Value 34 | @ToString(exclude = {"password"}) 35 | class TestRailConfig { 36 | 37 | private final String baseApiUrl; 38 | private final String username; 39 | private final String password; 40 | private final Optional applicationName; 41 | 42 | TestRailConfig(final String baseApiUrl, final String username, final String password, final String applicationName) { 43 | this.baseApiUrl = baseApiUrl; 44 | this.username = username; 45 | this.password = password; 46 | this.applicationName = Optional.fromNullable(applicationName); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/TestRailException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail; 26 | 27 | import com.google.common.base.Preconditions; 28 | import lombok.Getter; 29 | import lombok.Setter; 30 | import lombok.experimental.Accessors; 31 | 32 | /** 33 | * Exception representing error returned by TestRail API. 34 | */ 35 | public class TestRailException extends RuntimeException { 36 | 37 | private static final long serialVersionUID = -2131644110724458502L; 38 | 39 | @Getter 40 | private final int responseCode; 41 | 42 | /** 43 | * @param responseCode the HTTP response code from the TestRail server 44 | * @param error the error message from TestRail service 45 | */ 46 | TestRailException(int responseCode, String error) { 47 | super(responseCode + " - " + error); 48 | this.responseCode = responseCode; 49 | } 50 | 51 | /** 52 | * Builder for {@code TestRailException}. 53 | */ 54 | @Setter 55 | static class Builder { 56 | private int responseCode; 57 | private String error; 58 | 59 | public TestRailException build() { 60 | Preconditions.checkNotNull(responseCode); 61 | Preconditions.checkNotNull(error); 62 | return new TestRailException(responseCode, error); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/BooleanToIntSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonGenerator; 28 | import com.fasterxml.jackson.core.JsonProcessingException; 29 | import com.fasterxml.jackson.databind.JsonSerializer; 30 | import com.fasterxml.jackson.databind.SerializerProvider; 31 | 32 | import java.io.IOException; 33 | 34 | /** 35 | * Serializer to convert (boolean) false/true to (int) 0/1. 36 | */ 37 | public class BooleanToIntSerializer extends JsonSerializer { 38 | 39 | @Override 40 | public void serialize(final Boolean value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException, JsonProcessingException { 41 | jgen.writeNumber(value == null ? 0 : value ? 1 : 0); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/CaseModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.codepine.api.testrail.model.Case; 28 | import com.codepine.api.testrail.model.CaseField; 29 | import com.codepine.api.testrail.model.Field; 30 | import com.fasterxml.jackson.core.JsonParser; 31 | import com.fasterxml.jackson.core.JsonProcessingException; 32 | import com.fasterxml.jackson.databind.BeanDescription; 33 | import com.fasterxml.jackson.databind.DeserializationConfig; 34 | import com.fasterxml.jackson.databind.DeserializationContext; 35 | import com.fasterxml.jackson.databind.JsonDeserializer; 36 | import com.fasterxml.jackson.databind.JsonMappingException; 37 | import com.fasterxml.jackson.databind.ObjectMapper; 38 | import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; 39 | import com.fasterxml.jackson.databind.deser.ResolvableDeserializer; 40 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 41 | import com.fasterxml.jackson.databind.module.SimpleModule; 42 | import com.google.common.base.Function; 43 | import com.google.common.collect.Maps; 44 | 45 | import java.io.IOException; 46 | import java.util.HashMap; 47 | import java.util.List; 48 | import java.util.Map; 49 | 50 | import static com.google.common.base.Preconditions.checkArgument; 51 | 52 | /** 53 | * Jackson module for {@link com.codepine.api.testrail.model.Case}. 54 | *

55 | * INTERNAL ONLY 56 | */ 57 | public class CaseModule extends SimpleModule { 58 | 59 | @Override 60 | public void setupModule(SetupContext setupContext) { 61 | setupContext.addBeanDeserializerModifier(new CaseDeserializerModifier()); 62 | super.setupModule(setupContext); 63 | } 64 | 65 | private static class CaseDeserializer extends StdDeserializer implements ResolvableDeserializer { 66 | private final JsonDeserializer defaultDeserializer; 67 | 68 | CaseDeserializer(JsonDeserializer defaultDeserializer) { 69 | super(Case.class); 70 | this.defaultDeserializer = defaultDeserializer; 71 | } 72 | 73 | @Override 74 | public Case deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { 75 | Case testCase = (Case) defaultDeserializer.deserialize(jsonParser, deserializationContext); 76 | 77 | ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec(); 78 | List caseFieldList = (List) deserializationContext.findInjectableValue(Case.class.toString(), null, null); 79 | Map caseFields = Maps.uniqueIndex(caseFieldList, new Function() { 80 | @Override 81 | public String apply(final CaseField caseField) { 82 | return caseField.getName(); 83 | } 84 | }); 85 | Map customFields = new HashMap<>(testCase.getCustomFields().size()); 86 | for (Map.Entry customField : testCase.getCustomFields().entrySet()) { 87 | checkArgument(caseFields.containsKey(customField.getKey()), "Case field list configuration is possibly outdated since it does not contain custom field: " + customField.getKey()); 88 | customFields.put(customField.getKey(), mapper.convertValue(customField.getValue(), Field.Type.getType(caseFields.get(customField.getKey()).getTypeId()).getTypeReference())); 89 | } 90 | testCase.setCustomFields(customFields); 91 | return testCase; 92 | } 93 | 94 | @Override 95 | public void resolve(DeserializationContext deserializationContext) throws JsonMappingException { 96 | ((ResolvableDeserializer) defaultDeserializer).resolve(deserializationContext); 97 | } 98 | } 99 | 100 | private static class CaseDeserializerModifier extends BeanDeserializerModifier { 101 | 102 | @Override 103 | public JsonDeserializer modifyDeserializer(DeserializationConfig deserializationConfig, BeanDescription beanDescription, JsonDeserializer jsonDeserializer) { 104 | if (Case.class.isAssignableFrom(beanDescription.getBeanClass())) { 105 | return new CaseDeserializer(jsonDeserializer); 106 | } 107 | return jsonDeserializer; 108 | } 109 | 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/CsvToListDeserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonParser; 28 | import com.fasterxml.jackson.core.JsonProcessingException; 29 | import com.fasterxml.jackson.databind.DeserializationContext; 30 | import com.fasterxml.jackson.databind.JsonDeserializer; 31 | import com.google.common.base.Splitter; 32 | 33 | import java.io.IOException; 34 | import java.util.List; 35 | 36 | /** 37 | * Deserializer to convert csv string to {@code List}. 38 | */ 39 | public class CsvToListDeserializer extends JsonDeserializer> { 40 | 41 | @Override 42 | public List deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 43 | if (jp.getValueAsString() == null) { 44 | return null; 45 | } 46 | return Splitter.on(',').trimResults().omitEmptyStrings().splitToList(jp.getValueAsString()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/FieldModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.codepine.api.testrail.model.Field; 28 | import com.fasterxml.jackson.core.JsonParser; 29 | import com.fasterxml.jackson.core.JsonProcessingException; 30 | import com.fasterxml.jackson.databind.*; 31 | import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; 32 | import com.fasterxml.jackson.databind.deser.ResolvableDeserializer; 33 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 34 | import com.fasterxml.jackson.databind.module.SimpleModule; 35 | 36 | import java.io.IOException; 37 | 38 | /** 39 | * Jackson module for {@link com.codepine.api.testrail.model.Field}. 40 | *

41 | * INTERNAL ONLY 42 | */ 43 | public class FieldModule extends SimpleModule { 44 | 45 | @Override 46 | public void setupModule(SetupContext setupContext) { 47 | setupContext.addBeanDeserializerModifier(new FieldDeserializerModifier()); 48 | super.setupModule(setupContext); 49 | } 50 | 51 | static class FieldDeserializer extends StdDeserializer implements ResolvableDeserializer { 52 | private final JsonDeserializer defaultDeserializer; 53 | 54 | FieldDeserializer(JsonDeserializer defaultDeserializer) { 55 | super(Field.class); 56 | this.defaultDeserializer = defaultDeserializer; 57 | } 58 | 59 | @Override 60 | public Field deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { 61 | Field field = (Field) defaultDeserializer.deserialize(jsonParser, deserializationContext); 62 | ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec(); 63 | // set type 64 | field.setType(Field.Type.getType(field.getTypeId())); 65 | for (Field.Config config : field.getConfigs()) { 66 | // update options to correct type implementations 67 | config.setOptions(mapper.convertValue(config.getOptions(), field.getType().getOptionsClass())); 68 | } 69 | return field; 70 | } 71 | 72 | @Override 73 | public void resolve(DeserializationContext deserializationContext) throws JsonMappingException { 74 | ((ResolvableDeserializer) defaultDeserializer).resolve(deserializationContext); 75 | } 76 | } 77 | 78 | private static class FieldDeserializerModifier extends BeanDeserializerModifier { 79 | 80 | @Override 81 | public JsonDeserializer modifyDeserializer(DeserializationConfig deserializationConfig, BeanDescription beanDescription, JsonDeserializer jsonDeserializer) { 82 | if (Field.class.isAssignableFrom(beanDescription.getBeanClass())) { 83 | return new FieldDeserializer(jsonDeserializer); 84 | } 85 | return jsonDeserializer; 86 | } 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/IntToBooleanDeserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonParser; 28 | import com.fasterxml.jackson.core.JsonProcessingException; 29 | import com.fasterxml.jackson.databind.DeserializationContext; 30 | import com.fasterxml.jackson.databind.JsonDeserializer; 31 | 32 | import java.io.IOException; 33 | 34 | /** 35 | * Deserializer to convert (int) 0/1 to (boolean) false/true. 36 | */ 37 | public class IntToBooleanDeserializer extends JsonDeserializer { 38 | 39 | @Override 40 | public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 41 | return jp.getValueAsInt(0) <= 0 ? Boolean.FALSE : Boolean.TRUE; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/ListToCsvSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonGenerator; 28 | import com.fasterxml.jackson.core.JsonProcessingException; 29 | import com.fasterxml.jackson.databind.JsonSerializer; 30 | import com.fasterxml.jackson.databind.SerializerProvider; 31 | import com.google.common.base.Joiner; 32 | 33 | import java.io.IOException; 34 | import java.util.List; 35 | 36 | /** 37 | * Serializer to convert {@code List} to csv string. 38 | */ 39 | public class ListToCsvSerializer extends JsonSerializer> { 40 | 41 | @Override 42 | public void serialize(List value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { 43 | if (value != null) { 44 | jgen.writeString(Joiner.on(',').join(value)); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/PageDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.codepine.api.testrail.internal; 2 | 3 | import com.codepine.api.testrail.model.Links; 4 | import com.codepine.api.testrail.model.Page; 5 | import com.fasterxml.jackson.annotation.JsonInclude; 6 | import com.fasterxml.jackson.core.JsonParser; 7 | import com.fasterxml.jackson.core.JsonProcessingException; 8 | import com.fasterxml.jackson.databind.*; 9 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 10 | import com.fasterxml.jackson.databind.node.ArrayNode; 11 | 12 | import java.io.IOException; 13 | import java.util.ArrayList; 14 | import java.util.Collections; 15 | import java.util.List; 16 | 17 | public class PageDeserializer extends StdDeserializer { 18 | 19 | public static String field = "objects"; 20 | public static Class type = Object.class; 21 | public static Object supplement = Collections.emptyList(); 22 | 23 | public PageDeserializer() { 24 | this(null); 25 | } 26 | 27 | public PageDeserializer(Class vc) { 28 | super(vc); 29 | } 30 | 31 | @Override 32 | public Page deserialize(JsonParser jp, DeserializationContext ctxt) 33 | throws IOException, JsonProcessingException { 34 | JsonNode node = jp.getCodec().readTree(jp); 35 | int offset = node.get("offset").asInt(); 36 | int limit = node.get("limit").asInt(); 37 | int size = node.get("size").asInt(); 38 | JsonNode links = node.get("links"); 39 | String next = links.get("next").isNull() ? null : links.get("next").asText(); 40 | String prev = links.get("prev").isNull() ? null : links.get("prev").asText(); 41 | ArrayNode objects = (ArrayNode) node.get(field); 42 | List list = new ArrayList<>(); 43 | ObjectMapper mapper = new ObjectMapper() 44 | .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) 45 | .configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false) 46 | .setSerializationInclusion(JsonInclude.Include.NON_NULL) 47 | .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) 48 | .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) 49 | .registerModules(new CaseModule(), new FieldModule(), new PlanModule(), new ResultModule(), new UnixTimestampModule()); 50 | for(int i = 0; i < objects.size(); i++) { 51 | JsonNode element = objects.get(i); 52 | list.add(mapper.reader(type).with(new InjectableValues.Std().addValue(type.toString(), supplement)).readValue(element.toString())); 53 | } 54 | Page page = new Page(); 55 | page.limit = limit; 56 | page.offset = offset; 57 | page.size = size; 58 | page._links = new Links(); 59 | page._links.next = next; 60 | page._links.prev = prev; 61 | page.objects = list; 62 | return page; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/PlanModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.codepine.api.testrail.model.Plan; 28 | import com.codepine.api.testrail.model.Run; 29 | import com.fasterxml.jackson.core.JsonParser; 30 | import com.fasterxml.jackson.core.JsonProcessingException; 31 | import com.fasterxml.jackson.databind.*; 32 | import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; 33 | import com.fasterxml.jackson.databind.deser.ResolvableDeserializer; 34 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 35 | import com.fasterxml.jackson.databind.module.SimpleModule; 36 | 37 | import java.io.IOException; 38 | 39 | /** 40 | * Jackson module for {@link com.codepine.api.testrail.model.Plan} to set some additional properties on {@link com.codepine.api.testrail.model.Plan.Entry.Run}. 41 | *

42 | * INTERNAL ONLY 43 | */ 44 | public class PlanModule extends SimpleModule { 45 | 46 | @Override 47 | public void setupModule(SetupContext setupContext) { 48 | setupContext.addBeanDeserializerModifier(new PlanDeserializerModifier()); 49 | super.setupModule(setupContext); 50 | } 51 | 52 | private static class PlanDeserializer extends StdDeserializer implements ResolvableDeserializer { 53 | 54 | private final JsonDeserializer defaultDeserializer; 55 | 56 | PlanDeserializer(JsonDeserializer defaultDeserializer) { 57 | super(Plan.class); 58 | this.defaultDeserializer = defaultDeserializer; 59 | } 60 | 61 | @Override 62 | public Plan deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { 63 | Plan plan = (Plan) defaultDeserializer.deserialize(jsonParser, deserializationContext); 64 | ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec(); 65 | 66 | if (plan.getEntries() != null) { 67 | for (Plan.Entry entry : plan.getEntries()) { 68 | if (entry.getRuns() != null) { 69 | for (Run run : entry.getRuns()) { 70 | run.setCreatedOn(plan.getCreatedOn()); 71 | run.setCreatedBy(plan.getCreatedBy()); 72 | } 73 | } 74 | } 75 | } 76 | 77 | return plan; 78 | } 79 | 80 | @Override 81 | public void resolve(DeserializationContext deserializationContext) throws JsonMappingException { 82 | ((ResolvableDeserializer) defaultDeserializer).resolve(deserializationContext); 83 | } 84 | } 85 | 86 | private static class PlanDeserializerModifier extends BeanDeserializerModifier { 87 | 88 | @Override 89 | public JsonDeserializer modifyDeserializer(DeserializationConfig deserializationConfig, BeanDescription beanDescription, JsonDeserializer jsonDeserializer) { 90 | if (Plan.class.isAssignableFrom(beanDescription.getBeanClass())) { 91 | return new PlanDeserializer(jsonDeserializer); 92 | } 93 | return jsonDeserializer; 94 | } 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/QueryParameterString.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.annotation.JsonAnySetter; 28 | 29 | import java.io.UnsupportedEncodingException; 30 | import java.net.URLEncoder; 31 | 32 | /** 33 | * String representing query parameters of a URL. 34 | */ 35 | public final class QueryParameterString { 36 | 37 | private final StringBuilder queryParamStringBuilder = new StringBuilder(); 38 | 39 | @JsonAnySetter 40 | public void addQueryParameter(String key, String value) throws UnsupportedEncodingException { 41 | if (queryParamStringBuilder.length() > 0) { 42 | queryParamStringBuilder.append('&'); 43 | } 44 | queryParamStringBuilder.append(URLEncoder.encode(key, "UTF-8")).append('=').append(URLEncoder.encode(value, "UTF-8")); 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return queryParamStringBuilder.toString(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/ResultModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.codepine.api.testrail.model.Field; 28 | import com.codepine.api.testrail.model.Result; 29 | import com.codepine.api.testrail.model.ResultField; 30 | import com.fasterxml.jackson.core.JsonParser; 31 | import com.fasterxml.jackson.core.JsonProcessingException; 32 | import com.fasterxml.jackson.databind.BeanDescription; 33 | import com.fasterxml.jackson.databind.DeserializationConfig; 34 | import com.fasterxml.jackson.databind.DeserializationContext; 35 | import com.fasterxml.jackson.databind.JsonDeserializer; 36 | import com.fasterxml.jackson.databind.JsonMappingException; 37 | import com.fasterxml.jackson.databind.ObjectMapper; 38 | import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; 39 | import com.fasterxml.jackson.databind.deser.ResolvableDeserializer; 40 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 41 | import com.fasterxml.jackson.databind.module.SimpleModule; 42 | import com.google.common.base.Function; 43 | import com.google.common.collect.Maps; 44 | 45 | import java.io.IOException; 46 | import java.util.HashMap; 47 | import java.util.List; 48 | import java.util.Map; 49 | 50 | import static com.google.common.base.Preconditions.checkArgument; 51 | 52 | /** 53 | * Jackson module for {@link com.codepine.api.testrail.model.Result}. 54 | *

55 | * INTERNAL ONLY 56 | */ 57 | public class ResultModule extends SimpleModule { 58 | 59 | @Override 60 | public void setupModule(SetupContext setupContext) { 61 | setupContext.addBeanDeserializerModifier(new ResultDeserializerModifier()); 62 | super.setupModule(setupContext); 63 | } 64 | 65 | private static class ResultDeserializer extends StdDeserializer implements ResolvableDeserializer { 66 | private final JsonDeserializer defaultDeserializer; 67 | 68 | ResultDeserializer(JsonDeserializer defaultDeserializer) { 69 | super(Result.class); 70 | this.defaultDeserializer = defaultDeserializer; 71 | } 72 | 73 | @Override 74 | public Result deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { 75 | Result result = (Result) defaultDeserializer.deserialize(jsonParser, deserializationContext); 76 | 77 | ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec(); 78 | List resultFieldList = (List) deserializationContext.findInjectableValue(Result.class.toString(), null, null); 79 | Map resultFields = Maps.uniqueIndex(resultFieldList, new Function() { 80 | @Override 81 | public String apply(final ResultField resultField) { 82 | return resultField.getName(); 83 | } 84 | }); 85 | Map customFields = new HashMap<>(result.getCustomFields().size()); 86 | for (Map.Entry customField : result.getCustomFields().entrySet()) { 87 | checkArgument(resultFields.containsKey(customField.getKey()), "Result field list configuration is possibly outdated since it does not contain custom field: " + customField.getKey()); 88 | customFields.put(customField.getKey(), mapper.convertValue(customField.getValue(), Field.Type.getType(resultFields.get(customField.getKey()).getTypeId()).getTypeReference())); 89 | } 90 | result.setCustomFields(customFields); 91 | return result; 92 | } 93 | 94 | @Override 95 | public void resolve(DeserializationContext deserializationContext) throws JsonMappingException { 96 | ((ResolvableDeserializer) defaultDeserializer).resolve(deserializationContext); 97 | } 98 | } 99 | 100 | private static class ResultDeserializerModifier extends BeanDeserializerModifier { 101 | 102 | @Override 103 | public JsonDeserializer modifyDeserializer(DeserializationConfig deserializationConfig, BeanDescription beanDescription, JsonDeserializer jsonDeserializer) { 104 | if (Result.class.isAssignableFrom(beanDescription.getBeanClass())) { 105 | return new ResultDeserializer(jsonDeserializer); 106 | } 107 | return jsonDeserializer; 108 | } 109 | 110 | } 111 | } -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/StringToMapDeserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonParser; 28 | import com.fasterxml.jackson.core.JsonProcessingException; 29 | import com.fasterxml.jackson.databind.DeserializationContext; 30 | import com.fasterxml.jackson.databind.JsonDeserializer; 31 | import com.google.common.base.Function; 32 | import com.google.common.base.Splitter; 33 | import com.google.common.collect.Maps; 34 | 35 | import java.io.IOException; 36 | import java.util.Map; 37 | 38 | /** 39 | * Deserializer string of form a,b\nc,d\ne,f to a map of form {a->b, c->d, e->f}. 40 | */ 41 | public class StringToMapDeserializer extends JsonDeserializer> { 42 | 43 | @Override 44 | public Map deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 45 | if (jp.getValueAsString() == null) { 46 | return null; 47 | } 48 | Map items = Splitter.on("\n").omitEmptyStrings().withKeyValueSeparator(',').split(jp.getValueAsString()); 49 | items = Maps.transformValues(items, new Function() { 50 | @Override 51 | public String apply(String value) { 52 | return value.trim(); 53 | } 54 | }); 55 | return items; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/UnixTimestampModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonGenerator; 28 | import com.fasterxml.jackson.core.JsonParser; 29 | import com.fasterxml.jackson.core.JsonProcessingException; 30 | import com.fasterxml.jackson.databind.DeserializationContext; 31 | import com.fasterxml.jackson.databind.JsonDeserializer; 32 | import com.fasterxml.jackson.databind.JsonSerializer; 33 | import com.fasterxml.jackson.databind.SerializerProvider; 34 | import com.fasterxml.jackson.databind.module.SimpleModule; 35 | 36 | import java.io.IOException; 37 | import java.util.Date; 38 | 39 | /** 40 | * Jackson module to register serializers and deserializers for unix time stamp in seconds. 41 | *

42 | * INTERNAL ONLY 43 | */ 44 | public class UnixTimestampModule extends SimpleModule { 45 | 46 | public UnixTimestampModule() { 47 | addSerializer(Date.class, new UnixTimestampSerializer()); 48 | addDeserializer(Date.class, new UnixTimestampDeserializer()); 49 | } 50 | 51 | /** 52 | * Serializer to convert {@code java.util.Date} to unit timestamps in seconds. 53 | */ 54 | static class UnixTimestampSerializer extends JsonSerializer { 55 | 56 | @Override 57 | public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { 58 | jgen.writeNumber(value.getTime() / 1000); 59 | } 60 | } 61 | 62 | /** 63 | * Deserializer to convert unit timestamps in seconds to {@code java.util.Date}. 64 | */ 65 | static class UnixTimestampDeserializer extends JsonDeserializer { 66 | 67 | @Override 68 | public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 69 | return new Date(jp.getValueAsInt() * 1000L); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/internal/UrlConnectionFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import java.io.IOException; 28 | import java.net.URL; 29 | import java.net.URLConnection; 30 | 31 | /** 32 | * Factory to create instances of {@link java.net.URLConnection}. 33 | */ 34 | public class UrlConnectionFactory { 35 | 36 | /** 37 | * Get URL connection. 38 | * 39 | * @param url the URL to connect to 40 | * @return the open connection 41 | * @throws IOException if URL is malformed or if there's an IO error 42 | */ 43 | public URLConnection getUrlConnection(final String url) throws IOException { 44 | return new URL(url).openConnection(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Case.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.codepine.api.testrail.TestRail; 28 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 29 | import com.fasterxml.jackson.annotation.JsonAnySetter; 30 | import com.fasterxml.jackson.annotation.JsonIgnore; 31 | import com.fasterxml.jackson.annotation.JsonView; 32 | import com.fasterxml.jackson.core.JsonGenerationException; 33 | import com.fasterxml.jackson.core.JsonGenerator; 34 | import com.fasterxml.jackson.databind.SerializerProvider; 35 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 36 | import com.fasterxml.jackson.databind.ser.std.StdKeySerializer; 37 | import com.google.common.base.MoreObjects; 38 | import lombok.Data; 39 | 40 | import java.io.IOException; 41 | import java.util.Collections; 42 | import java.util.Date; 43 | import java.util.HashMap; 44 | import java.util.Map; 45 | 46 | import static com.codepine.api.testrail.model.Field.Type; 47 | 48 | 49 | /** 50 | * TestRail case. 51 | */ 52 | @Data 53 | public class Case { 54 | 55 | private static final String CUSTOM_FIELD_KEY_PREFIX = "custom_"; 56 | 57 | private int id; 58 | 59 | @JsonView({TestRail.Cases.Add.class, TestRail.Cases.Update.class}) 60 | private String title; 61 | 62 | private int sectionId; 63 | 64 | @JsonView({TestRail.Cases.Add.class, TestRail.Cases.Update.class}) 65 | private Integer typeId; 66 | 67 | @JsonView({TestRail.Cases.Add.class, TestRail.Cases.Update.class}) 68 | private Integer priorityId; 69 | 70 | @JsonView({TestRail.Cases.Add.class, TestRail.Cases.Update.class}) 71 | private Integer milestoneId; 72 | 73 | @JsonView({TestRail.Cases.Add.class, TestRail.Cases.Update.class}) 74 | private String refs; 75 | 76 | private int createdBy; 77 | 78 | private Date createdOn; 79 | 80 | private int updatedBy; 81 | 82 | private Date updatedOn; 83 | 84 | @JsonView({TestRail.Cases.Add.class, TestRail.Cases.Update.class}) 85 | private String estimate; 86 | 87 | private String estimateForecast; 88 | 89 | private int suiteId; 90 | 91 | @JsonView({TestRail.Cases.Add.class, TestRail.Cases.Update.class}) 92 | @JsonIgnore 93 | private Map customFields; 94 | 95 | @JsonAnyGetter 96 | @JsonSerialize(keyUsing = CustomFieldSerializer.class) 97 | public Map getCustomFields() { 98 | return MoreObjects.firstNonNull(customFields, Collections.emptyMap()); 99 | } 100 | 101 | /** 102 | * Add a custom field. 103 | * 104 | * @param key the name of the custom field with or without "custom_" prefix 105 | * @param value the value of the custom field 106 | * @return case instance for chaining 107 | */ 108 | public Case addCustomField(String key, Object value) { 109 | if (customFields == null) { 110 | customFields = new HashMap<>(); 111 | } 112 | customFields.put(key.replaceFirst(CUSTOM_FIELD_KEY_PREFIX, ""), value); 113 | return this; 114 | } 115 | 116 | /** 117 | * Support for forward compatibility and extracting custom fields. 118 | * 119 | * @param key the name of the unknown field 120 | * @param value the value of the unkown field 121 | */ 122 | @JsonAnySetter 123 | private void addUnknownField(String key, Object value) { 124 | if (key.startsWith(CUSTOM_FIELD_KEY_PREFIX)) { 125 | addCustomField(key, value); 126 | } 127 | } 128 | 129 | /** 130 | * Get custom field. 131 | *

Use Java Type Inference, to get the value with correct type. Refer to {@link Type} for a map of TestRail field types to Java types.

132 | * 133 | * @param key the system name of custom field 134 | * @param the type of returned value 135 | * @return the value of the custom field 136 | */ 137 | public T getCustomField(String key) { 138 | return (T) getCustomFields().get(key); 139 | } 140 | 141 | /** 142 | * Serializer for custom fields. 143 | */ 144 | private static class CustomFieldSerializer extends StdKeySerializer { 145 | 146 | @Override 147 | public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonGenerationException { 148 | super.serialize(CUSTOM_FIELD_KEY_PREFIX + o, jsonGenerator, serializerProvider); 149 | } 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/CaseField.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | /** 28 | * TestRail case field. 29 | */ 30 | public class CaseField extends Field { 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/CaseType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.fasterxml.jackson.annotation.JsonIgnore; 28 | import com.fasterxml.jackson.annotation.JsonProperty; 29 | import lombok.Data; 30 | import lombok.Getter; 31 | 32 | /** 33 | * TestRail case type. 34 | */ 35 | @Data 36 | public class CaseType { 37 | 38 | private int id; 39 | private String name; 40 | @JsonProperty 41 | @Getter(onMethod = @_({@JsonIgnore})) 42 | private boolean isDefault; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Configuration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import lombok.Data; 28 | import lombok.experimental.Accessors; 29 | 30 | import java.util.List; 31 | 32 | /** 33 | * TestRail configuration. 34 | */ 35 | @Data 36 | public class Configuration { 37 | 38 | private int id; 39 | private String name; 40 | private int projectId; 41 | private List configs; 42 | 43 | @Data 44 | @Accessors(chain = true) 45 | public class Config { 46 | 47 | private int id; 48 | private String name; 49 | private int groupId; 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Field.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.codepine.api.testrail.TestRail; 28 | import com.codepine.api.testrail.internal.IntToBooleanDeserializer; 29 | import com.codepine.api.testrail.internal.StringToMapDeserializer; 30 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 31 | import com.fasterxml.jackson.annotation.JsonAnySetter; 32 | import com.fasterxml.jackson.annotation.JsonIgnore; 33 | import com.fasterxml.jackson.annotation.JsonProperty; 34 | import com.fasterxml.jackson.annotation.JsonView; 35 | import com.fasterxml.jackson.core.type.TypeReference; 36 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 37 | import lombok.AccessLevel; 38 | import lombok.Data; 39 | import lombok.EqualsAndHashCode; 40 | import lombok.Getter; 41 | import lombok.RequiredArgsConstructor; 42 | import lombok.Setter; 43 | import lombok.ToString; 44 | 45 | import java.math.BigInteger; 46 | import java.util.HashMap; 47 | import java.util.List; 48 | import java.util.Map; 49 | 50 | /** 51 | * TestRail field. 52 | */ 53 | @Data 54 | public class Field { 55 | 56 | private int id; 57 | private String label; 58 | private String name; 59 | private String description; 60 | private String systemName; 61 | private int typeId; 62 | private Type type; 63 | private int displayOrder; 64 | private List configs; 65 | 66 | /** 67 | * TestRail type of field. 68 | *

69 | * Map of TestRail field types to their corresponding Java types: 70 | *

 71 |      *      STRING -- java.lang.String
 72 |      *      INTEGER -- java.lang.Integer
 73 |      *      TEXT -- java.lang.String
 74 |      *      URL -- java.lang.String
 75 |      *      CHECKBOX -- java.lang.Boolean
 76 |      *      DROPDOWN -- java.lang.String
 77 |      *      USER -- java.lang.Integer
 78 |      *      DATE -- java.lang.String
 79 |      *      MILESTONE -- java.lang.Integer
 80 |      *      STEPS -- java.util.List<{@link Step}>
 81 |      *      STEP_RESULTS -- java.util.List<{@link StepResult}>
 82 |      *      MULTI_SELECT -- java.util.List
 83 |      * 
84 | *

85 | */ 86 | @RequiredArgsConstructor 87 | public static enum Type { 88 | UNKNOWN(Config.Options.class, new TypeReference() { 89 | }), 90 | STRING(Config.StringOptions.class, new TypeReference() { 91 | }), 92 | INTEGER(Config.IntegerOptions.class, new TypeReference() { 93 | }), 94 | TEXT(Config.TextOptions.class, new TypeReference() { 95 | }), 96 | URL(Config.UrlOptions.class, new TypeReference() { 97 | }), 98 | CHECKBOX(Config.CheckboxOptions.class, new TypeReference() { 99 | }), 100 | DROPDOWN(Config.DropdownOptions.class, new TypeReference() { 101 | }), 102 | USER(Config.UserOptions.class, new TypeReference() { 103 | }), 104 | DATE(Config.DateOptions.class, new TypeReference() { 105 | }), 106 | MILESTONE(Config.MilestoneOptions.class, new TypeReference() { 107 | }), 108 | STEPS(Config.StepsOptions.class, new TypeReference>() { 109 | }), 110 | STEP_RESULTS(Config.StepResultsOptions.class, new TypeReference>() { 111 | }), 112 | MULTI_SELECT(Config.MultiSelectOptions.class, new TypeReference>() { 113 | }); 114 | 115 | @Getter 116 | private final Class optionsClass; 117 | @Getter 118 | private final TypeReference typeReference; 119 | 120 | public static Type getType(int typeId) { 121 | return typeId >= 0 && typeId < Type.values().length ? Type.values()[typeId] : UNKNOWN; 122 | } 123 | 124 | } 125 | 126 | /** 127 | * Configuration for a {@code Field}. 128 | */ 129 | @Data 130 | public static class Config { 131 | 132 | private String id; 133 | private Context context; 134 | private Options options; 135 | 136 | /** 137 | * Options for a {@code Field} configuration. 138 | */ 139 | @Data 140 | public static class Options { 141 | 142 | @JsonProperty 143 | @Getter(onMethod = @_({@JsonIgnore})) 144 | private boolean isRequired; 145 | @Getter(value = AccessLevel.PRIVATE, onMethod = @_({@JsonAnyGetter})) 146 | @Setter(value = AccessLevel.NONE) 147 | private Map unknownFields; 148 | 149 | @JsonAnySetter 150 | private Options addUnknownField(String key, Object value) { 151 | if (unknownFields == null) { 152 | unknownFields = new HashMap<>(); 153 | } 154 | unknownFields.put(key, value); 155 | return this; 156 | } 157 | 158 | } 159 | 160 | /** 161 | * Options for a {@code Field} of type {@link Type#STRING}. 162 | */ 163 | @Data 164 | @EqualsAndHashCode(callSuper = true) 165 | @ToString(callSuper = true) 166 | public static class StringOptions extends Options { 167 | private String defaultValue; 168 | } 169 | 170 | /** 171 | * Options for a {@code Field} of type {@link Type#INTEGER}. 172 | */ 173 | @Data 174 | @EqualsAndHashCode(callSuper = true) 175 | @ToString(callSuper = true) 176 | public static class IntegerOptions extends Options { 177 | private BigInteger defaultValue; 178 | } 179 | 180 | /** 181 | * Options for a {@code Field} of type {@link Type#TEXT}. 182 | */ 183 | @Data 184 | @EqualsAndHashCode(callSuper = true) 185 | @ToString(callSuper = true) 186 | public static class TextOptions extends Options { 187 | private String defaultValue; 188 | private String format; 189 | private int rows; 190 | } 191 | 192 | /** 193 | * Options for a {@code Field} of type {@link Type#URL}. 194 | */ 195 | @Data 196 | @EqualsAndHashCode(callSuper = true) 197 | @ToString(callSuper = true) 198 | public static class UrlOptions extends Options { 199 | private String defaultValue; 200 | } 201 | 202 | /** 203 | * Options for a {@code Field} of type {@link Type#CHECKBOX}. 204 | */ 205 | @Data 206 | @EqualsAndHashCode(callSuper = true) 207 | @ToString(callSuper = true) 208 | public static class CheckboxOptions extends Options { 209 | @JsonDeserialize(using = IntToBooleanDeserializer.class) 210 | private boolean defaultValue; 211 | } 212 | 213 | /** 214 | * Options for a {@code Field} of type {@link Type#DROPDOWN}. 215 | */ 216 | @Data 217 | @EqualsAndHashCode(callSuper = true) 218 | @ToString(callSuper = true) 219 | public static class DropdownOptions extends Options { 220 | private String defaultValue; 221 | @JsonDeserialize(using = StringToMapDeserializer.class) 222 | private Map items; 223 | } 224 | 225 | /** 226 | * Options for a {@code Field} of type {@link Type#USER}. 227 | */ 228 | @Data 229 | @EqualsAndHashCode(callSuper = true) 230 | @ToString(callSuper = true) 231 | public static class UserOptions extends Options { 232 | private int defaultValue; 233 | } 234 | 235 | /** 236 | * Options for a {@code Field} of type {@link Type#DATE}. 237 | */ 238 | @Data 239 | @EqualsAndHashCode(callSuper = true) 240 | @ToString(callSuper = true) 241 | public static class DateOptions extends Options { 242 | } 243 | 244 | /** 245 | * Options for a {@code Field} of type {@link Type#MILESTONE}. 246 | */ 247 | @Data 248 | @EqualsAndHashCode(callSuper = true) 249 | @ToString(callSuper = true) 250 | public static class MilestoneOptions extends Options { 251 | } 252 | 253 | /** 254 | * Options for a {@code Field} of type {@link Type#STEPS}. 255 | */ 256 | @Data 257 | @EqualsAndHashCode(callSuper = true) 258 | @ToString(callSuper = true) 259 | public static class StepsOptions extends Options { 260 | private String format; 261 | private boolean hasExpected; 262 | private int rows; 263 | } 264 | 265 | /** 266 | * Options for a {@code Field} of type {@link Type#STEP_RESULTS}. 267 | */ 268 | @Data 269 | @EqualsAndHashCode(callSuper = true) 270 | @ToString(callSuper = true) 271 | public static class StepResultsOptions extends Options { 272 | private String format; 273 | private boolean hasExpected; 274 | private boolean hasActual; 275 | } 276 | 277 | /** 278 | * Options for a {@code Field} of type {@link Type#MULTI_SELECT}. 279 | */ 280 | @Data 281 | @EqualsAndHashCode(callSuper = true) 282 | @ToString(callSuper = true) 283 | public static class MultiSelectOptions extends Options { 284 | @JsonDeserialize(using = StringToMapDeserializer.class) 285 | private Map items; 286 | } 287 | 288 | 289 | @Data 290 | public static class Context { 291 | @JsonProperty 292 | @Getter(onMethod = @_({@JsonIgnore})) 293 | private boolean isGlobal; 294 | private List projectIds; 295 | } 296 | 297 | } 298 | 299 | /** 300 | * Step; a custom field type. 301 | */ 302 | @Data 303 | public static class Step { 304 | 305 | @JsonView({TestRail.Cases.Add.class, TestRail.Cases.Update.class}) 306 | private String content; 307 | @JsonView({TestRail.Cases.Add.class, TestRail.Cases.Update.class}) 308 | private String expected; 309 | 310 | } 311 | 312 | /** 313 | * Step result; a custom field type. 314 | */ 315 | @Data 316 | public static class StepResult { 317 | 318 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 319 | private String content; 320 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 321 | private String expected; 322 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 323 | private String actual; 324 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 325 | private Integer statusId; 326 | 327 | } 328 | 329 | } 330 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Links.java: -------------------------------------------------------------------------------- 1 | package com.codepine.api.testrail.model; 2 | 3 | public class Links { 4 | 5 | public String next; 6 | 7 | public String prev; 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Milestone.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.codepine.api.testrail.TestRail; 28 | import com.fasterxml.jackson.annotation.JsonView; 29 | import lombok.AccessLevel; 30 | import lombok.Data; 31 | import lombok.Getter; 32 | import lombok.Setter; 33 | 34 | import java.util.Date; 35 | 36 | /** 37 | * TestRail milestone. 38 | */ 39 | @Data 40 | public class Milestone { 41 | 42 | private int id; 43 | 44 | @JsonView({TestRail.Milestones.Add.class, TestRail.Milestones.Update.class}) 45 | private String name; 46 | 47 | @JsonView({TestRail.Milestones.Add.class, TestRail.Milestones.Update.class}) 48 | private String description; 49 | 50 | private int projectId; 51 | 52 | @JsonView({TestRail.Milestones.Add.class, TestRail.Milestones.Update.class}) 53 | private Date dueOn; 54 | 55 | @JsonView({TestRail.Milestones.Update.class}) 56 | @Getter(value = AccessLevel.PRIVATE) 57 | @Setter(value = AccessLevel.PRIVATE) 58 | private Boolean isCompleted; 59 | 60 | public Boolean isCompleted() { 61 | return getIsCompleted(); 62 | } 63 | 64 | public Milestone setCompleted(boolean isCompleted) { 65 | return setIsCompleted(isCompleted); 66 | } 67 | 68 | private Date completedOn; 69 | 70 | private String url; 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Page.java: -------------------------------------------------------------------------------- 1 | package com.codepine.api.testrail.model; 2 | 3 | import com.codepine.api.testrail.internal.PageDeserializer; 4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 5 | 6 | @JsonDeserialize(using = PageDeserializer.class) 7 | public class Page { 8 | 9 | public int offset; 10 | 11 | public int limit; 12 | 13 | public int size; 14 | 15 | public Links _links; 16 | 17 | public T objects; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Plan.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.codepine.api.testrail.TestRail; 28 | import com.fasterxml.jackson.annotation.JsonIgnore; 29 | import com.fasterxml.jackson.annotation.JsonProperty; 30 | import com.fasterxml.jackson.annotation.JsonView; 31 | import lombok.AccessLevel; 32 | import lombok.Data; 33 | import lombok.EqualsAndHashCode; 34 | import lombok.Getter; 35 | import lombok.ToString; 36 | 37 | import java.util.Date; 38 | import java.util.List; 39 | 40 | /** 41 | * TestRail plan. 42 | */ 43 | @Data 44 | public class Plan { 45 | 46 | private int id; 47 | 48 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.Update.class}) 49 | private String name; 50 | 51 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.Update.class}) 52 | private String description; 53 | 54 | private String url; 55 | 56 | private int projectId; 57 | 58 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.Update.class}) 59 | private Integer milestoneId; 60 | 61 | private Integer assignedtoId; 62 | 63 | private Date createdOn; 64 | 65 | private int createdBy; 66 | 67 | @JsonProperty 68 | @Getter(onMethod = @_({@JsonIgnore})) 69 | private boolean isCompleted; 70 | 71 | private Date completedOn; 72 | 73 | private int passedCount; 74 | 75 | private int blockedCount; 76 | 77 | private int untestedCount; 78 | 79 | private int retestCount; 80 | 81 | private int failedCount; 82 | 83 | private int customStatus1Count; 84 | 85 | private int customStatus2Count; 86 | 87 | private int customStatus3Count; 88 | 89 | private int customStatus4Count; 90 | 91 | private int customStatus5Count; 92 | 93 | private int customStatus6Count; 94 | 95 | private int customStatus7Count; 96 | 97 | @JsonView({TestRail.Plans.Add.class}) 98 | private List entries; 99 | 100 | @Data 101 | public static class Entry { 102 | 103 | private String id; 104 | 105 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class, TestRail.Plans.UpdateEntry.class}) 106 | private String name; 107 | 108 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class}) 109 | private Integer suiteId; 110 | 111 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class, TestRail.Plans.UpdateEntry.class}) 112 | private String description; 113 | 114 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class, TestRail.Plans.UpdateEntry.class}) 115 | private Integer assignedtoId; 116 | 117 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class, TestRail.Plans.UpdateEntry.class}) 118 | @Getter(value = AccessLevel.PRIVATE) 119 | private Boolean includeAll; 120 | 121 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class, TestRail.Plans.UpdateEntry.class}) 122 | private List caseIds; 123 | 124 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class}) 125 | private List configIds; 126 | 127 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class}) 128 | private List runs; 129 | 130 | @Data 131 | @EqualsAndHashCode(callSuper = true) 132 | @ToString(callSuper = true) 133 | public static class Run extends com.codepine.api.testrail.model.Run { 134 | private String entryId; 135 | private int entryIndex; 136 | } 137 | 138 | public Boolean isIncludeAll() { 139 | return getIncludeAll(); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Priority.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.fasterxml.jackson.annotation.JsonIgnore; 28 | import com.fasterxml.jackson.annotation.JsonProperty; 29 | import lombok.Data; 30 | import lombok.Getter; 31 | 32 | /** 33 | * TestRail test case priority. 34 | */ 35 | @Data 36 | public class Priority { 37 | 38 | private int id; 39 | private String name; 40 | private String shortName; 41 | private int priority; 42 | @JsonProperty 43 | @Getter(onMethod = @_({@JsonIgnore})) 44 | private boolean isDefault; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Project.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | /** 26 | * 27 | */ 28 | package com.codepine.api.testrail.model; 29 | 30 | import com.codepine.api.testrail.TestRail; 31 | import com.fasterxml.jackson.annotation.JsonView; 32 | import lombok.AccessLevel; 33 | import lombok.Data; 34 | import lombok.Getter; 35 | import lombok.Setter; 36 | 37 | import java.util.Date; 38 | 39 | /** 40 | * TestRail project. 41 | */ 42 | @Data 43 | public class Project { 44 | 45 | private int id; 46 | 47 | @JsonView({TestRail.Projects.Add.class, TestRail.Projects.Update.class}) 48 | private String name; 49 | 50 | @JsonView({TestRail.Projects.Add.class, TestRail.Projects.Update.class}) 51 | private String announcement; 52 | 53 | @JsonView({TestRail.Projects.Add.class, TestRail.Projects.Update.class}) 54 | @Getter(value = AccessLevel.PRIVATE) 55 | private Boolean showAnnouncement; 56 | 57 | @JsonView(TestRail.Projects.Update.class) 58 | @Getter(value = AccessLevel.PRIVATE) 59 | @Setter(value = AccessLevel.PRIVATE) 60 | private Boolean isCompleted; 61 | 62 | private Date completedOn; 63 | 64 | private String url; 65 | 66 | @JsonView({TestRail.Projects.Add.class, TestRail.Projects.Update.class}) 67 | private Integer suiteMode; 68 | 69 | public Boolean isCompleted() { 70 | return getIsCompleted(); 71 | } 72 | 73 | public Project setCompleted(boolean isCompleted) { 74 | return setIsCompleted(isCompleted); 75 | } 76 | 77 | public Boolean isShowAnnouncement() { 78 | return getShowAnnouncement(); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Result.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.codepine.api.testrail.TestRail; 28 | import com.codepine.api.testrail.internal.CsvToListDeserializer; 29 | import com.codepine.api.testrail.internal.ListToCsvSerializer; 30 | import com.fasterxml.jackson.annotation.JsonAnyGetter; 31 | import com.fasterxml.jackson.annotation.JsonAnySetter; 32 | import com.fasterxml.jackson.annotation.JsonIgnore; 33 | import com.fasterxml.jackson.annotation.JsonView; 34 | import com.fasterxml.jackson.core.JsonGenerationException; 35 | import com.fasterxml.jackson.core.JsonGenerator; 36 | import com.fasterxml.jackson.databind.SerializerProvider; 37 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 38 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 39 | import com.fasterxml.jackson.databind.ser.std.StdKeySerializer; 40 | import com.google.common.base.MoreObjects; 41 | import com.google.common.base.Preconditions; 42 | import lombok.AllArgsConstructor; 43 | import lombok.Data; 44 | import lombok.Getter; 45 | import lombok.NoArgsConstructor; 46 | import lombok.NonNull; 47 | import lombok.ToString; 48 | 49 | import java.io.IOException; 50 | import java.util.ArrayList; 51 | import java.util.Collections; 52 | import java.util.Date; 53 | import java.util.HashMap; 54 | import java.util.Map; 55 | 56 | import static com.codepine.api.testrail.model.Field.Type; 57 | 58 | /** 59 | * TestRail result. 60 | */ 61 | @Data 62 | @ToString(exclude = "caseId") 63 | public class Result { 64 | 65 | private static final String CUSTOM_FIELD_KEY_PREFIX = "custom_"; 66 | 67 | private int id; 68 | 69 | private int testId; 70 | 71 | @JsonView({TestRail.Results.AddListForCases.class}) 72 | private Integer caseId; 73 | 74 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 75 | private Integer statusId; 76 | 77 | private Date createdOn; 78 | 79 | private int createdBy; 80 | 81 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 82 | private Integer assignedtoId; 83 | 84 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 85 | private String comment; 86 | 87 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 88 | private String version; 89 | 90 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 91 | private String elapsed; 92 | 93 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 94 | @JsonSerialize(using = ListToCsvSerializer.class) 95 | @JsonDeserialize(using = CsvToListDeserializer.class) 96 | private java.util.List defects; 97 | 98 | @JsonView({TestRail.Results.Add.class, TestRail.Results.AddForCase.class, TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 99 | @JsonIgnore 100 | private Map customFields; 101 | 102 | /** 103 | * Add a defect. 104 | * 105 | * @param defect defect to be added 106 | * @return this instance for chaining 107 | */ 108 | public Result addDefect(@NonNull String defect) { 109 | Preconditions.checkArgument(!defect.isEmpty(), "defect cannot be empty"); 110 | java.util.List defects = getDefects(); 111 | if (defects == null) { 112 | defects = new ArrayList<>(); 113 | } 114 | defects.add(defect); 115 | setDefects(defects); 116 | return this; 117 | } 118 | 119 | @JsonAnyGetter 120 | @JsonSerialize(keyUsing = CustomFieldSerializer.class) 121 | public Map getCustomFields() { 122 | return MoreObjects.firstNonNull(customFields, Collections.emptyMap()); 123 | } 124 | 125 | /** 126 | * Add a custom field. 127 | * 128 | * @param key the name of the custom field with or without "custom_" prefix 129 | * @param value the value of the custom field 130 | * @return result instance for chaining 131 | */ 132 | public Result addCustomField(String key, Object value) { 133 | if(customFields == null) { 134 | customFields = new HashMap<>(); 135 | } 136 | customFields.put(key.replaceFirst(CUSTOM_FIELD_KEY_PREFIX, ""), value); 137 | return this; 138 | } 139 | 140 | /** 141 | * Support for forward compatibility and extracting custom fields. 142 | * 143 | * @param key the name of the unknown field 144 | * @param value the value of the unkown field 145 | */ 146 | @JsonAnySetter 147 | private void addUnknownField(String key, Object value) { 148 | if (key.startsWith(CUSTOM_FIELD_KEY_PREFIX)) { 149 | addCustomField(key, value); 150 | } 151 | } 152 | 153 | /** 154 | * Get custom field. 155 | *

Use Java Type Inference, to get the value with correct type. Refer to {@link Type} for a map of TestRail field types to Java types.

156 | * 157 | * @param key the system name of custom field 158 | * @param the type of returned value 159 | * @return the value of the custom field 160 | */ 161 | public T getCustomField(String key) { 162 | return (T) getCustomFields().get(key); 163 | } 164 | 165 | /** 166 | * Serializer for custom fields. 167 | */ 168 | private static class CustomFieldSerializer extends StdKeySerializer { 169 | 170 | @Override 171 | public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonGenerationException { 172 | super.serialize(CUSTOM_FIELD_KEY_PREFIX + o, jsonGenerator, serializerProvider); 173 | } 174 | } 175 | 176 | /** 177 | * Wrapper for list of {@code Result}s for internal use. 178 | */ 179 | @Data 180 | @NoArgsConstructor 181 | @AllArgsConstructor 182 | public static class List { 183 | 184 | @JsonView({TestRail.Results.AddList.class, TestRail.Results.AddListForCases.class}) 185 | private java.util.List results; 186 | 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/ResultField.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | /** 28 | * TestRail result field. 29 | */ 30 | public class ResultField extends Field { 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Run.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.codepine.api.testrail.TestRail; 28 | import com.codepine.api.testrail.internal.CsvToListDeserializer; 29 | import com.fasterxml.jackson.annotation.JsonIgnore; 30 | import com.fasterxml.jackson.annotation.JsonProperty; 31 | import com.fasterxml.jackson.annotation.JsonView; 32 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 33 | import lombok.Data; 34 | import lombok.Getter; 35 | 36 | import java.util.Date; 37 | import java.util.List; 38 | 39 | /** 40 | * TestRail run. 41 | */ 42 | @Data 43 | public class Run { 44 | 45 | private int id; 46 | 47 | @JsonView({TestRail.Runs.Add.class, TestRail.Runs.Update.class}) 48 | private String name; 49 | 50 | @JsonView({TestRail.Runs.Add.class, TestRail.Runs.Update.class}) 51 | private String description; 52 | 53 | private String url; 54 | 55 | private int projectId; 56 | 57 | private Integer planId; 58 | 59 | @JsonView(TestRail.Runs.Add.class) 60 | private Integer suiteId; 61 | 62 | @JsonView({TestRail.Runs.Add.class, TestRail.Runs.Update.class}) 63 | private Integer milestoneId; 64 | 65 | @JsonView({TestRail.Runs.Add.class, TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class}) 66 | private Integer assignedtoId; 67 | 68 | @JsonView({TestRail.Runs.Add.class, TestRail.Runs.Update.class, TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class}) 69 | private Boolean includeAll; 70 | 71 | @JsonView({TestRail.Runs.Add.class, TestRail.Runs.Update.class, TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class}) 72 | private List caseIds; 73 | 74 | private Date createdOn; 75 | 76 | private int createdBy; 77 | 78 | @JsonProperty 79 | @Getter(onMethod = @_({@JsonIgnore})) 80 | private boolean isCompleted; 81 | 82 | private Date completedOn; 83 | 84 | @JsonDeserialize(using = CsvToListDeserializer.class) 85 | private List config; 86 | 87 | @JsonView({TestRail.Plans.Add.class, TestRail.Plans.AddEntry.class}) 88 | private List configIds; 89 | 90 | private int passedCount; 91 | 92 | private int blockedCount; 93 | 94 | private int untestedCount; 95 | 96 | private int retestCount; 97 | 98 | private int failedCount; 99 | 100 | private int customStatus1Count; 101 | 102 | private int customStatus2Count; 103 | 104 | private int customStatus3Count; 105 | 106 | private int customStatus4Count; 107 | 108 | private int customStatus5Count; 109 | 110 | private int customStatus6Count; 111 | 112 | private int customStatus7Count; 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Section.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.codepine.api.testrail.TestRail; 28 | import com.fasterxml.jackson.annotation.JsonView; 29 | import lombok.Data; 30 | 31 | /** 32 | * TestRail section. 33 | */ 34 | @Data 35 | public class Section { 36 | 37 | private int id; 38 | 39 | @JsonView({TestRail.Sections.Add.class, TestRail.Sections.Update.class}) 40 | private String name; 41 | 42 | @JsonView({TestRail.Sections.Add.class, TestRail.Sections.Update.class}) 43 | private String description; 44 | 45 | @JsonView(TestRail.Sections.Add.class) 46 | private Integer suiteId; 47 | 48 | @JsonView(TestRail.Sections.Add.class) 49 | private Integer parentId; 50 | 51 | private int depth; 52 | 53 | private int displayOrder; 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Status.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.fasterxml.jackson.annotation.JsonIgnore; 28 | import com.fasterxml.jackson.annotation.JsonProperty; 29 | import lombok.Data; 30 | import lombok.Getter; 31 | 32 | /** 33 | * TestRail status. 34 | */ 35 | @Data 36 | public class Status { 37 | 38 | private int id; 39 | private String name; 40 | private String label; 41 | private int colorDark; 42 | private int colorMedium; 43 | private int colorBright; 44 | @JsonProperty 45 | @Getter(onMethod = @_({@JsonIgnore})) 46 | private boolean isSystem; 47 | @JsonProperty 48 | @Getter(onMethod = @_({@JsonIgnore})) 49 | private boolean isUntested; 50 | @JsonProperty 51 | @Getter(onMethod = @_({@JsonIgnore})) 52 | private boolean isFinal; 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Suite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.codepine.api.testrail.TestRail; 28 | import com.fasterxml.jackson.annotation.JsonIgnore; 29 | import com.fasterxml.jackson.annotation.JsonProperty; 30 | import com.fasterxml.jackson.annotation.JsonView; 31 | import lombok.Data; 32 | import lombok.Getter; 33 | 34 | /** 35 | * TestRail suite. 36 | */ 37 | @Data 38 | public class Suite { 39 | 40 | private int id; 41 | 42 | @JsonView({TestRail.Suites.Add.class, TestRail.Suites.Update.class}) 43 | private String name; 44 | 45 | @JsonView({TestRail.Suites.Add.class, TestRail.Suites.Update.class}) 46 | private String description; 47 | 48 | private int projectId; 49 | 50 | @JsonProperty 51 | @Getter(onMethod = @_({@JsonIgnore})) 52 | private boolean isBaseline; 53 | 54 | @JsonProperty 55 | @Getter(onMethod = @_({@JsonIgnore})) 56 | private boolean isCompleted; 57 | 58 | @JsonProperty 59 | @Getter(onMethod = @_({@JsonIgnore})) 60 | private boolean isMaster; 61 | 62 | private String url; 63 | 64 | } -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.fasterxml.jackson.annotation.JsonAnySetter; 28 | import com.google.common.base.MoreObjects; 29 | import lombok.Data; 30 | 31 | import java.util.Collections; 32 | import java.util.HashMap; 33 | import java.util.Map; 34 | 35 | /** 36 | * TestRail test. 37 | */ 38 | @Data 39 | public class Test { 40 | 41 | private static final String CUSTOM_FIELD_KEY_PREFIX = "custom_"; 42 | 43 | private int id; 44 | 45 | private int caseId; 46 | 47 | private Integer assignedtoId; 48 | 49 | private String title; 50 | 51 | private int statusId; 52 | 53 | private int typeId; 54 | 55 | private int priorityId; 56 | 57 | private Integer milestoneId; 58 | 59 | private Integer runId; 60 | 61 | private String refs; 62 | 63 | private String estimate; 64 | 65 | private String estimateForecast; 66 | 67 | private Map customFields; 68 | 69 | public Map getCustomFields() { 70 | return MoreObjects.firstNonNull(customFields, Collections.emptyMap()); 71 | } 72 | 73 | /** 74 | * Add a custom field. 75 | * 76 | * @param key the name of the custom field with or without "custom_" prefix 77 | * @param value the value of the custom field 78 | * @return test instance for chaining 79 | */ 80 | public Test addCustomField(String key, Object value) { 81 | if (customFields == null) { 82 | customFields = new HashMap<>(); 83 | } 84 | customFields.put(key.replaceFirst(CUSTOM_FIELD_KEY_PREFIX, ""), value); 85 | return this; 86 | } 87 | 88 | /** 89 | * Support for forward compatibility and extracting custom fields. 90 | * 91 | * @param key the name of the unknown field 92 | * @param value the value of the unkown field 93 | */ 94 | @JsonAnySetter 95 | private void addUnknownField(String key, Object value) { 96 | if (key.startsWith(CUSTOM_FIELD_KEY_PREFIX)) { 97 | addCustomField(key, value); 98 | } 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/codepine/api/testrail/model/User.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.model; 26 | 27 | import com.fasterxml.jackson.annotation.JsonIgnore; 28 | import com.fasterxml.jackson.annotation.JsonProperty; 29 | import lombok.Data; 30 | import lombok.Getter; 31 | 32 | /** 33 | * TestRail user. 34 | */ 35 | @Data 36 | public class User { 37 | 38 | private int id; 39 | private String email; 40 | private String name; 41 | @JsonProperty 42 | @Getter(onMethod = @_({@JsonIgnore})) 43 | private boolean isActive; 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/RequestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail; 26 | 27 | import com.codepine.api.testrail.internal.ListToCsvSerializer; 28 | import com.codepine.api.testrail.internal.UrlConnectionFactory; 29 | import com.codepine.api.testrail.model.Page; 30 | import com.codepine.api.testrail.model.Case; 31 | import com.fasterxml.jackson.annotation.JacksonInject; 32 | import com.fasterxml.jackson.annotation.JsonView; 33 | import com.fasterxml.jackson.core.type.TypeReference; 34 | import com.fasterxml.jackson.databind.ObjectMapper; 35 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 36 | import lombok.AccessLevel; 37 | import lombok.Data; 38 | import lombok.Getter; 39 | import lombok.RequiredArgsConstructor; 40 | import lombok.Setter; 41 | import org.apache.log4j.PropertyConfigurator; 42 | import org.junit.Before; 43 | import org.junit.BeforeClass; 44 | import org.junit.Rule; 45 | import org.junit.Test; 46 | import org.junit.rules.ExpectedException; 47 | import org.junit.runner.RunWith; 48 | import org.mockito.Mock; 49 | import org.mockito.Mockito; 50 | import org.mockito.runners.MockitoJUnitRunner; 51 | 52 | import java.io.ByteArrayOutputStream; 53 | import java.io.IOException; 54 | import java.net.HttpURLConnection; 55 | import java.util.*; 56 | 57 | import static org.junit.Assert.assertEquals; 58 | import static org.junit.Assert.assertNotNull; 59 | import static org.junit.Assert.assertTrue; 60 | import static org.mockito.Matchers.any; 61 | import static org.mockito.Matchers.eq; 62 | import static org.mockito.Mockito.verify; 63 | import static org.mockito.Mockito.when; 64 | 65 | /** 66 | * Tests for {@link com.codepine.api.testrail.Request}. 67 | */ 68 | @RunWith(MockitoJUnitRunner.class) 69 | public class RequestTest { 70 | 71 | private static final String TEST_END_POINT = "https://test.end.point.com"; 72 | private static final TestRailConfig config = TestRail.builder(TEST_END_POINT, "testUser", "testPassword").build().getConfig(); 73 | 74 | @Getter(value = AccessLevel.PRIVATE, lazy = true) 75 | private static final ObjectMapper objectMapper = new ObjectMapper(); 76 | 77 | @Rule 78 | public final ExpectedException expectedException = ExpectedException.none(); 79 | @Mock private HttpURLConnection mockConnection; 80 | @Mock private HttpURLConnection mockConnection1; 81 | @Mock private HttpURLConnection mockConnection2; 82 | @Mock private HttpURLConnection mockConnection3; 83 | @Mock 84 | private UrlConnectionFactory mockUrlConnectionFactory; 85 | 86 | private Models models; 87 | 88 | @BeforeClass 89 | public static void setUpLogger() { 90 | PropertyConfigurator.configure(RequestTest.class.getResourceAsStream("/log4j.properties")); 91 | } 92 | 93 | @Before 94 | public void setUp() throws IOException { 95 | when(mockUrlConnectionFactory.getUrlConnection(any(String.class))).thenReturn(mockConnection); 96 | when(mockUrlConnectionFactory.getUrlConnection("https://test.end.point.com/index.php?/api/v2/get_models/1")).thenReturn(mockConnection1); 97 | when(mockUrlConnectionFactory.getUrlConnection("https://test.end.point.com/index.php?/api/v2/get_models/2")).thenReturn(mockConnection2); 98 | when(mockUrlConnectionFactory.getUrlConnection("https://test.end.point.com/index.php?/api/v2/get_models/3")).thenReturn(mockConnection3); 99 | models = new Models(mockUrlConnectionFactory); 100 | } 101 | 102 | @Test 103 | public void G_unauthorizedUser_W_getModel_T_verifyError() throws IOException { 104 | // THEN set up 105 | expectedException.expect(TestRailException.class); 106 | expectedException.expectMessage("401 - Authentication failed: invalid or missing user/password or session cookie."); 107 | 108 | // GIVEN 109 | when(mockConnection.getResponseCode()).thenThrow(IOException.class).thenReturn(401); 110 | when(mockConnection.getErrorStream()).thenReturn(this.getClass().getResourceAsStream("/auth_error.json")); 111 | 112 | // WHEN 113 | models.get().execute(); 114 | } 115 | 116 | @Test 117 | public void G_modelExists_W_getModel_T_verifyModel() throws IOException { 118 | // GIVEN 119 | when(mockConnection.getResponseCode()).thenReturn(200); 120 | when(mockConnection.getInputStream()).thenReturn(this.getClass().getResourceAsStream("/get_model.json")); 121 | 122 | // WHEN 123 | final Model actualModel = models.get().execute(); 124 | 125 | // THEN 126 | final Model expectedModel = new Model().setId(1).setName("Test Model 1").setShowAnnouncement(false).setIsCompleted(true).setCompletedOn(new Date(1424641170000L)).setSuiteMode(2); 127 | assertEquals(expectedModel, actualModel); 128 | } 129 | 130 | @Test 131 | public void G_modelDoesNotExist_W_getModel_T_verifyError() throws IOException { 132 | // THEN set up 133 | expectedException.expect(TestRailException.class); 134 | expectedException.expectMessage("400 - Field :model_id is not a valid or accessible model."); 135 | 136 | // GIVEN 137 | when(mockConnection.getResponseCode()).thenReturn(400); 138 | when(mockConnection.getErrorStream()).thenReturn(this.getClass().getResourceAsStream("/get_model_error.json")); 139 | 140 | // WHEN, THEN 141 | models.get().execute(); 142 | } 143 | 144 | @Test 145 | public void G_modelsExists_W_getModelsWithFilter_T_verifyFilterQueryAndModels_paginated() throws IOException { 146 | // GIVEN 147 | when(mockConnection1.getResponseCode()).thenReturn(200); 148 | when(mockConnection2.getResponseCode()).thenReturn(200); 149 | when(mockConnection3.getResponseCode()).thenReturn(200); 150 | when(mockConnection1.getInputStream()).thenReturn(this.getClass().getResourceAsStream("/get_modelsA.json")); 151 | when(mockConnection2.getInputStream()).thenReturn(this.getClass().getResourceAsStream("/get_modelsB.json")); 152 | when(mockConnection3.getInputStream()).thenReturn(this.getClass().getResourceAsStream("/get_modelsC.json")); 153 | 154 | // WHEN 155 | final List actualModels = models.listPaginated().setSectionId(1).setCreatedAfter(new Date(1424641170000L)).execute(); 156 | 157 | // THEN -- verify objects returned 158 | final List expectedModels = new ArrayList<>(); 159 | expectedModels.add(new Model().setId(1).setName("Test Model 1").setShowAnnouncement(false).setIsCompleted(true).setCompletedOn(new Date(1424641170000L)).setSuiteMode(2)); 160 | expectedModels.add(new Model().setId(3).setName("Test Model 3").setShowAnnouncement(true).setIsCompleted(true).setCompletedOn(new Date(1424651896000L)).setSuiteMode(3)); 161 | expectedModels.add(new Model().setId(4).setName("Test Model 4").setShowAnnouncement(false).setIsCompleted(false).setCompletedOn(new Date(1426110846000L)).setSuiteMode(1)); 162 | expectedModels.add(new Model().setId(5).setName("Test Model 5").setShowAnnouncement(false).setIsCompleted(false).setCompletedOn(new Date(1426110846000L)).setSuiteMode(1)); 163 | assertEquals(expectedModels, actualModels); 164 | } 165 | 166 | @Test 167 | public void G_casesExists_W_getCasesWithFilter_T_verifyFilterQueryAndCases() throws IOException { 168 | // GIVEN 169 | when(mockConnection.getResponseCode()).thenReturn(200); 170 | when(mockConnection.getInputStream()).thenReturn(this.getClass().getResourceAsStream("/get_cases.json")); 171 | 172 | // WHEN 173 | final List actualCases = models.listCases().setSectionId(1).setCreatedAfter(new Date(1424641170000L)).execute(); 174 | 175 | // THEN -- verify filter query 176 | String expectedUrlWithFilterQuery = String.format("%s/index.php?/api/v2/get_cases/1", TEST_END_POINT); 177 | Mockito.verify(mockUrlConnectionFactory).getUrlConnection(expectedUrlWithFilterQuery); 178 | 179 | // THEN -- verify models returned 180 | final List expectedCases = new ArrayList<>(); 181 | expectedCases.add(new Case().setId(1).setTitle("[PERF] Login")); 182 | expectedCases.add(new Case().setId(2).setTitle("[PERF] Create institution")); 183 | expectedCases.add(new Case().setId(3).setTitle("[PERF] Import election configuration")); 184 | assertEquals(expectedCases, actualCases); 185 | } 186 | 187 | @Test 188 | public void G_modelsExists_W_getModelsWithFilter_T_verifyFilterQueryAndModels() throws IOException { 189 | // GIVEN 190 | when(mockConnection.getResponseCode()).thenReturn(200); 191 | when(mockConnection.getInputStream()).thenReturn(this.getClass().getResourceAsStream("/get_models.json")); 192 | 193 | // WHEN 194 | final List actualModels = models.list().setSectionId(1).setCreatedAfter(new Date(1424641170000L)).execute(); 195 | 196 | // THEN -- verify filter query 197 | String expectedUrlWithFilterQuery = String.format("%s/index.php?/api/v2/get_models/0§ion_id=1&created_after=1424641170", TEST_END_POINT); 198 | Mockito.verify(mockUrlConnectionFactory).getUrlConnection(expectedUrlWithFilterQuery); 199 | 200 | // THEN -- verify models returned 201 | final List expectedModels = new ArrayList<>(); 202 | expectedModels.add(new Model().setId(1).setName("Test Model 1").setShowAnnouncement(false).setIsCompleted(true).setCompletedOn(new Date(1424641170000L)).setSuiteMode(2)); 203 | expectedModels.add(new Model().setId(3).setName("Test Model 3").setShowAnnouncement(true).setIsCompleted(true).setCompletedOn(new Date(1424651896000L)).setSuiteMode(3)); 204 | expectedModels.add(new Model().setId(4).setName("Test Model 4").setShowAnnouncement(false).setIsCompleted(false).setCompletedOn(new Date(1426110846000L)).setSuiteMode(1)); 205 | assertEquals(expectedModels, actualModels); 206 | } 207 | 208 | @Test 209 | public void W_addModel_T_verifyPostBodyAndModel() throws IOException { 210 | // set up 211 | ByteArrayOutputStream postBodyOutputStream = new ByteArrayOutputStream(); 212 | when(mockConnection.getResponseCode()).thenReturn(200); 213 | when(mockConnection.getOutputStream()).thenReturn(postBodyOutputStream); 214 | when(mockConnection.getInputStream()).thenReturn(this.getClass().getResourceAsStream("/add_model.json")); 215 | 216 | // WHEN 217 | final Model expectedModel = new Model().setId(1).setName("Test Model 1").setShowAnnouncement(true).setIsCompleted(false).setSuiteMode(2); 218 | final Model actualModel = models.add(expectedModel).execute(); 219 | 220 | // THEN -- verify post body 221 | byte[] postBodyBytes = postBodyOutputStream.toByteArray(); 222 | assertNotNull("post body should not be null", postBodyBytes); 223 | assertTrue("post body should not be empty", postBodyBytes.length > 0); 224 | Map postBody = getObjectMapper().readValue(postBodyBytes, new TypeReference>() { 225 | }); 226 | Set expectedProperties = new HashSet<>(Arrays.asList("name", "show_announcement", "suite_mode")); 227 | assertTrue("Expected properties: " + expectedProperties + " but found: " + postBody.keySet(), postBody.keySet().equals(expectedProperties)); 228 | 229 | // THEN -- verify model 230 | assertEquals(expectedModel, actualModel); 231 | } 232 | 233 | @Test 234 | public void W_updatePartialModel_T_verifyPostBodyAndModel() throws IOException { 235 | // set up 236 | ByteArrayOutputStream postBodyOutputStream = new ByteArrayOutputStream(); 237 | when(mockConnection.getResponseCode()).thenReturn(200); 238 | when(mockConnection.getOutputStream()).thenReturn(postBodyOutputStream); 239 | when(mockConnection.getInputStream()).thenReturn(this.getClass().getResourceAsStream("/add_model.json")); 240 | 241 | // WHEN 242 | final Model updatedModel = new Model().setId(1).setName("Test Model 1").setShowAnnouncement(true).setSuiteMode(2); 243 | final Model actualModel = models.update(updatedModel).execute(); 244 | 245 | // THEN -- verify post body 246 | byte[] postBodyBytes = postBodyOutputStream.toByteArray(); 247 | assertNotNull("post body should not be null", postBodyBytes); 248 | assertTrue("post body should not be empty", postBodyBytes.length > 0); 249 | Map postBody = getObjectMapper().readValue(postBodyBytes, new TypeReference>() { 250 | }); 251 | Set expectedProperties = new HashSet<>(Arrays.asList("show_announcement")); 252 | assertTrue("Expected properties: " + expectedProperties + " but found: " + postBody.keySet(), postBody.keySet().equals(expectedProperties)); 253 | 254 | // THEN -- verify model 255 | Model expectedModel = new Model().setId(1).setName("Test Model 1").setShowAnnouncement(true).setIsCompleted(false).setSuiteMode(2); 256 | assertEquals(expectedModel, actualModel); 257 | } 258 | 259 | @Test 260 | public void W_deleteModel_T_verifyZeroContentLength() throws IOException { 261 | // set up 262 | when(mockConnection.getResponseCode()).thenReturn(200); 263 | 264 | // WHEN 265 | models.delete(1).execute(); 266 | 267 | // THEN -- verify content length set to 0 268 | verify(mockConnection).setFixedLengthStreamingMode(eq(0)); 269 | } 270 | 271 | @Test 272 | public void W_listWithSupplementForDeserialization_T_verifyModelHasBeenInjectedWithSupplement() throws IOException { 273 | // set up 274 | when(mockConnection.getResponseCode()).thenReturn(200); 275 | when(mockConnection.getInputStream()).thenReturn(this.getClass().getResourceAsStream("/get_models.json")); 276 | 277 | // WHEN 278 | final String expectedSupplementModelName = "Supplement Model"; 279 | final List actualModels = models.listWithAltName().setSupplementModelName(expectedSupplementModelName).execute(); 280 | 281 | // THEN 282 | final List expectedModels = new ArrayList<>(); 283 | expectedModels.add((ModelWithAltName) new ModelWithAltName().setAltName(expectedSupplementModelName).setId(1).setName("Test Model 1").setShowAnnouncement(false).setIsCompleted(true).setCompletedOn(new Date(1424641170000L)).setSuiteMode(2)); 284 | expectedModels.add((ModelWithAltName) new ModelWithAltName().setAltName(expectedSupplementModelName).setId(3).setName("Test Model 3").setShowAnnouncement(true).setIsCompleted(true).setCompletedOn(new Date(1424651896000L)).setSuiteMode(3)); 285 | expectedModels.add((ModelWithAltName) new ModelWithAltName().setAltName(expectedSupplementModelName).setId(4).setName("Test Model 4").setShowAnnouncement(false).setIsCompleted(false).setCompletedOn(new Date(1426110846000L)).setSuiteMode(1)); 286 | assertEquals(expectedModels, actualModels); 287 | } 288 | 289 | 290 | @Data 291 | public static class Model { 292 | private int id; 293 | 294 | @JsonView({RequestTest.Models.Add.class}) 295 | private String name; 296 | 297 | @JsonView({RequestTest.Models.Add.class, RequestTest.Models.Update.class}) 298 | private Boolean showAnnouncement; 299 | 300 | @JsonView(RequestTest.Models.Update.class) 301 | @Getter(value = AccessLevel.PRIVATE) 302 | @Setter(value = AccessLevel.PRIVATE) 303 | private Boolean isCompleted; 304 | 305 | @JsonView(RequestTest.Models.Update.class) 306 | private Date completedOn; 307 | 308 | @JsonView({RequestTest.Models.Add.class}) 309 | private int suiteMode; 310 | } 311 | 312 | @RequiredArgsConstructor 313 | public static class Models { 314 | 315 | private final UrlConnectionFactory urlConnectionFactory; 316 | 317 | public Get get() { 318 | Get get = new Get(); 319 | get.setUrlConnectionFactory(urlConnectionFactory); 320 | return get; 321 | } 322 | 323 | public List list() { 324 | List list = new List(); 325 | list.setUrlConnectionFactory(urlConnectionFactory); 326 | return list; 327 | } 328 | 329 | public ListPaginated listPaginated() { 330 | ListPaginated list = new ListPaginated(); 331 | list.setUrlConnectionFactory(urlConnectionFactory); 332 | return list; 333 | } 334 | 335 | public ListCases listCases() { 336 | ListCases list = new ListCases(); 337 | list.setUrlConnectionFactory(urlConnectionFactory); 338 | return list; 339 | } 340 | 341 | public ListWithAltName listWithAltName() { 342 | ListWithAltName list = new ListWithAltName(); 343 | list.setUrlConnectionFactory(urlConnectionFactory); 344 | return list; 345 | } 346 | 347 | public Add add(Model model) { 348 | Add add = new Add(model); 349 | add.setUrlConnectionFactory(urlConnectionFactory); 350 | return add; 351 | } 352 | 353 | public Update update(Model model) { 354 | Update update = new Update(model); 355 | update.setUrlConnectionFactory(urlConnectionFactory); 356 | return update; 357 | } 358 | 359 | public Delete delete(int id) { 360 | final Delete delete = new Delete(id); 361 | delete.setUrlConnectionFactory(urlConnectionFactory); 362 | return delete; 363 | } 364 | 365 | public static class Get extends Request { 366 | 367 | Get() { 368 | super(config, Method.GET, "get_model/1", Model.class); 369 | } 370 | 371 | } 372 | 373 | @Getter 374 | @Setter 375 | public static class List extends Request> { 376 | 377 | @JsonView(List.class) 378 | private Integer sectionId; 379 | 380 | @JsonView(List.class) 381 | private Date createdAfter; 382 | 383 | @JsonView(List.class) 384 | @JsonSerialize(using = ListToCsvSerializer.class) 385 | private java.util.List createdBy; 386 | 387 | List() { 388 | super(config, Method.GET, "get_models/0", new TypeReference>() { 389 | }); 390 | } 391 | } 392 | 393 | @Getter 394 | @Setter 395 | public static class ListPaginated extends Request> { 396 | 397 | @JsonView(List.class) 398 | private Integer sectionId; 399 | 400 | @JsonView(List.class) 401 | private Date createdAfter; 402 | 403 | @JsonView(List.class) 404 | @JsonSerialize(using = ListToCsvSerializer.class) 405 | private java.util.List createdBy; 406 | 407 | ListPaginated() { 408 | super(config, Method.GET, "get_models/1", new TypeReference>() { 409 | }, new TypeReference>>(){}); 410 | } 411 | } 412 | 413 | @Getter 414 | @Setter 415 | public static class ListCases extends Request> { 416 | 417 | @JsonView(List.class) 418 | private Integer sectionId; 419 | 420 | @JsonView(List.class) 421 | private Date createdAfter; 422 | 423 | @JsonView(List.class) 424 | @JsonSerialize(using = ListToCsvSerializer.class) 425 | private java.util.List createdBy; 426 | 427 | ListCases() { 428 | super(config, Method.GET, "get_cases/1", new TypeReference>() { 429 | }, new TypeReference>>(){}); 430 | } 431 | } 432 | 433 | @Setter 434 | public static class ListWithAltName extends Request> { 435 | 436 | private String supplementModelName; 437 | 438 | ListWithAltName() { 439 | super(config, Method.GET, "get_models/0", new TypeReference>() { 440 | }); 441 | } 442 | 443 | @Override 444 | Object getSupplementForDeserialization() { 445 | return supplementModelName; 446 | } 447 | } 448 | 449 | public static class Add extends Request { 450 | 451 | private final Model model; 452 | 453 | Add(Model model) { 454 | super(config, Method.POST, "add_model/1", Model.class); 455 | this.model = model; 456 | } 457 | 458 | @Override 459 | protected Object getContent() { 460 | return model; 461 | } 462 | } 463 | 464 | public static class Update extends Request { 465 | 466 | private final Model model; 467 | 468 | Update(Model model) { 469 | super(config, Method.POST, "update_model/1", Model.class); 470 | this.model = model; 471 | } 472 | 473 | @Override 474 | protected Object getContent() { 475 | return model; 476 | } 477 | } 478 | 479 | public static class Delete extends Request { 480 | 481 | Delete(final int id) { 482 | super(config, Method.POST, "delete_model/" + id, Void.class); 483 | } 484 | } 485 | } 486 | 487 | @Data 488 | public static class ModelWithAltName extends Model { 489 | 490 | @JacksonInject("class com.codepine.api.testrail.RequestTest$ModelWithAltName") 491 | private String altName; 492 | 493 | } 494 | } 495 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/internal/BooleanToIntSerializerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonGenerator; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.mockito.Mock; 32 | import org.mockito.runners.MockitoJUnitRunner; 33 | 34 | import java.io.IOException; 35 | 36 | import static org.mockito.Mockito.verify; 37 | 38 | /** 39 | * Tests for {@link com.codepine.api.testrail.internal.BooleanToIntSerializer}. 40 | */ 41 | @RunWith(MockitoJUnitRunner.class) 42 | public class BooleanToIntSerializerTest { 43 | 44 | private BooleanToIntSerializer booleanToIntSerializer; 45 | 46 | @Mock 47 | private JsonGenerator jsonGenerator; 48 | 49 | @Before 50 | public void setUp() { 51 | booleanToIntSerializer = new BooleanToIntSerializer(); 52 | } 53 | 54 | @Test 55 | public void W_null_T_0() throws IOException { 56 | // WHEN 57 | Boolean value = null; 58 | booleanToIntSerializer.serialize(value, jsonGenerator, null); 59 | 60 | // THEN 61 | verify(jsonGenerator).writeNumber(0); 62 | } 63 | 64 | @Test 65 | public void W_false_T_0() throws IOException { 66 | // WHEN 67 | Boolean value = false; 68 | booleanToIntSerializer.serialize(value, jsonGenerator, null); 69 | 70 | // THEN 71 | verify(jsonGenerator).writeNumber(0); 72 | } 73 | 74 | @Test 75 | public void W_true_T_1() throws IOException { 76 | // WHEN 77 | Boolean value = false; 78 | booleanToIntSerializer.serialize(value, jsonGenerator, null); 79 | 80 | // THEN 81 | verify(jsonGenerator).writeNumber(0); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/internal/CaseModuleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.codepine.api.testrail.model.Case; 28 | import com.codepine.api.testrail.model.CaseField; 29 | import com.codepine.api.testrail.model.Field; 30 | import com.fasterxml.jackson.databind.InjectableValues; 31 | import com.fasterxml.jackson.databind.ObjectMapper; 32 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 33 | import com.fasterxml.jackson.databind.SerializationFeature; 34 | import org.junit.Test; 35 | 36 | import java.io.IOException; 37 | import java.util.Arrays; 38 | import java.util.Collections; 39 | import java.util.Date; 40 | import java.util.List; 41 | 42 | import static org.junit.Assert.assertEquals; 43 | 44 | /** 45 | * Tests for {@link com.codepine.api.testrail.internal.CaseModule}. 46 | *

This test does not use mocks. It has some dependencies which it assumes are tested separately.

47 | */ 48 | public class CaseModuleTest { 49 | 50 | private static final ObjectMapper objectMapper = new ObjectMapper() 51 | .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) 52 | .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) 53 | .registerModules(new CaseModule(), new UnixTimestampModule()); 54 | 55 | @Test(expected = IllegalArgumentException.class) 56 | public void G_noCustomCaseFields_W_caseStringWithCustomStepsField_T_exception() throws IOException { 57 | // GIVEN 58 | List caseFields = Collections.emptyList(); 59 | 60 | // WHEN 61 | objectMapper.reader(Case.class).with(new InjectableValues.Std().addValue(Case.class.toString(), caseFields)).readValue(this.getClass().getResourceAsStream("/case_with_step_field_set.json")); 62 | } 63 | 64 | @Test 65 | public void G_noCustomCaseFields_W_caseStringWithNoCustomStepsField_T_correctDeserialization() throws IOException { 66 | // GIVEN 67 | List caseFields = Collections.emptyList(); 68 | 69 | // WHEN 70 | Case actualCase = objectMapper.reader(Case.class).with(new InjectableValues.Std().addValue(Case.class.toString(), caseFields)).readValue(this.getClass().getResourceAsStream("/case_with_no_custom_fields.json")); 71 | 72 | // THEN 73 | Case expectedCase = new Case().setId(13).setTitle("Test Case 2").setSectionId(6).setTypeId(6).setPriorityId(4).setCreatedBy(1).setCreatedOn(new Date(1425683583000L)).setUpdatedBy(1).setUpdatedOn(new Date(1425845918000L)).setSuiteId(4); 74 | assertEquals(expectedCase, actualCase); 75 | } 76 | 77 | @Test 78 | public void G_customCaseFieldSteps_W_caseStringWithCustomStepsField_T_correctDeserializationAndStepsField() throws IOException { 79 | // GIVEN 80 | CaseField stepField = objectMapper.readValue(this.getClass().getResourceAsStream("/step_field.json"), CaseField.class); 81 | List caseFields = Collections.singletonList(stepField); 82 | 83 | // WHEN 84 | Case actualCase = objectMapper.reader(Case.class).with(new InjectableValues.Std().addValue(Case.class.toString(), caseFields)).readValue(this.getClass().getResourceAsStream("/case_with_step_field_set.json")); 85 | 86 | // THEN 87 | List steps = Arrays.asList(new Field.Step().setContent("Step 1").setExpected("Expected 1"), new Field.Step().setContent("Step 2").setExpected("Expected 2")); 88 | Case expectedCase = new Case().setId(13).setTitle("Test Case 2").setSectionId(6).setTypeId(6).setPriorityId(4).setCreatedBy(1).setCreatedOn(new Date(1425683583000L)).setUpdatedBy(1).setUpdatedOn(new Date(1425845918000L)).setSuiteId(4).addCustomField("separated_steps", steps); 89 | assertEquals(expectedCase, actualCase); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/internal/CsvToListDeserializerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonParser; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.mockito.Mock; 32 | import org.mockito.runners.MockitoJUnitRunner; 33 | 34 | import java.io.IOException; 35 | import java.util.Arrays; 36 | import java.util.Collections; 37 | import java.util.List; 38 | 39 | import static org.junit.Assert.assertEquals; 40 | import static org.junit.Assert.assertNull; 41 | import static org.junit.Assert.assertTrue; 42 | import static org.mockito.Mockito.when; 43 | 44 | /** 45 | * Tests for {@link com.codepine.api.testrail.internal.CsvToListDeserializer}. 46 | */ 47 | @RunWith(MockitoJUnitRunner.class) 48 | public class CsvToListDeserializerTest { 49 | 50 | private CsvToListDeserializer csvToListDeserializer; 51 | 52 | @Mock 53 | private JsonParser jsonParser; 54 | 55 | @Before 56 | public void setUp() { 57 | csvToListDeserializer = new CsvToListDeserializer(); 58 | } 59 | 60 | @Test 61 | public void W_null_T_null() throws IOException { 62 | // WHEN 63 | when(jsonParser.getValueAsString()).thenReturn(null); 64 | List list = csvToListDeserializer.deserialize(jsonParser, null); 65 | 66 | // THEN 67 | assertNull("Expected list to be null but found: " + list, list); 68 | } 69 | 70 | @Test 71 | public void W_empty_T_empty() throws IOException { 72 | // WHEN 73 | when(jsonParser.getValueAsString()).thenReturn(""); 74 | List list = csvToListDeserializer.deserialize(jsonParser, null); 75 | 76 | // THEN 77 | assertTrue("Expected list to be empty but found: " + list, list.isEmpty()); 78 | } 79 | 80 | @Test 81 | public void W_noComma_T_singleElement() throws IOException { 82 | // WHEN 83 | when(jsonParser.getValueAsString()).thenReturn("a b c d"); 84 | List actualList = csvToListDeserializer.deserialize(jsonParser, null); 85 | 86 | // THEN 87 | List expectedList = Collections.singletonList("a b c d"); 88 | assertEquals("Expected list is not same as actual list.", expectedList, actualList); 89 | } 90 | 91 | @Test 92 | public void W_fourCommaSeparatedValues_T_fourElements() throws IOException { 93 | // WHEN 94 | when(jsonParser.getValueAsString()).thenReturn("a, b, c, d"); 95 | List actualList = csvToListDeserializer.deserialize(jsonParser, null); 96 | 97 | // THEN 98 | List expectedList = Arrays.asList("a", "b", "c", "d"); 99 | assertEquals("Expected list is not same as actual list.", expectedList, actualList); 100 | } 101 | 102 | @Test 103 | public void W_fourCommaSeparatedValuesWithOneEmpty_T_threeElements() throws IOException { 104 | // WHEN 105 | when(jsonParser.getValueAsString()).thenReturn("a, b, , d"); 106 | List actualList = csvToListDeserializer.deserialize(jsonParser, null); 107 | 108 | // THEN 109 | List expectedList = Arrays.asList("a", "b", "d"); 110 | assertEquals("Expected list is not same as actual list.", expectedList, actualList); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/internal/FieldModuleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.codepine.api.testrail.model.Field; 28 | import com.fasterxml.jackson.databind.ObjectMapper; 29 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 30 | import com.fasterxml.jackson.databind.SerializationFeature; 31 | import org.junit.Test; 32 | 33 | import java.io.IOException; 34 | import java.util.Collections; 35 | 36 | import static org.junit.Assert.assertEquals; 37 | 38 | /** 39 | * Tests for {@link com.codepine.api.testrail.internal.FieldModule}. 40 | *

This test does not use mocks. It has some dependencies which it assumes are tested separately.

41 | */ 42 | public class FieldModuleTest { 43 | 44 | private static final ObjectMapper objectMapper = new ObjectMapper() 45 | .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) 46 | .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) 47 | .registerModules(new FieldModule()); 48 | 49 | @Test 50 | public void W_stepFieldString_T_correctDeserializationAndStepsOptions() throws IOException { 51 | // WHEN 52 | Field actualField = objectMapper.readValue(this.getClass().getResourceAsStream("/step_field.json"), Field.class); 53 | 54 | // THEN 55 | Field.Config.StepsOptions options = (Field.Config.StepsOptions) new Field.Config.StepsOptions().setFormat("markdown").setHasExpected(true).setRows(6).setRequired(false); 56 | Field.Config.Context context = new Field.Config.Context().setGlobal(true).setProjectIds(Collections.emptyList()); 57 | Field.Config config = new Field.Config().setId("47e68955-c7fc-4c01-8313-d9de6c4cad7c").setContext(context).setOptions(options); 58 | Field expectedField = new Field().setId(4).setTypeId(10).setType(Field.Type.STEPS).setName("separated_steps").setSystemName("custom_separated_steps").setLabel("Separated Steps").setConfigs(Collections.singletonList(config)).setDisplayOrder(4); 59 | assertEquals(expectedField, actualField); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/internal/IntToBooleanDeserializerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonParser; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.mockito.Mock; 32 | import org.mockito.runners.MockitoJUnitRunner; 33 | 34 | import java.io.IOException; 35 | 36 | import static org.junit.Assert.assertFalse; 37 | import static org.junit.Assert.assertTrue; 38 | import static org.mockito.Mockito.when; 39 | 40 | /** 41 | * Tests for {@link com.codepine.api.testrail.internal.IntToBooleanDeserializer}. 42 | */ 43 | @RunWith(MockitoJUnitRunner.class) 44 | public class IntToBooleanDeserializerTest { 45 | 46 | private IntToBooleanDeserializer intToBooleanDeserializer; 47 | 48 | @Mock 49 | private JsonParser jsonParser; 50 | 51 | @Before 52 | public void setUp() { 53 | intToBooleanDeserializer = new IntToBooleanDeserializer(); 54 | } 55 | 56 | @Test 57 | public void W_0_T_false() throws IOException { 58 | // WHEN 59 | when(jsonParser.getValueAsInt(0)).thenReturn(0); 60 | Boolean actualBoolean = intToBooleanDeserializer.deserialize(jsonParser, null); 61 | 62 | // THEN 63 | assertFalse(actualBoolean); 64 | } 65 | 66 | @Test 67 | public void W_1_T_true() throws IOException { 68 | // WHEN 69 | when(jsonParser.getValueAsInt(0)).thenReturn(1); 70 | Boolean actualBoolean = intToBooleanDeserializer.deserialize(jsonParser, null); 71 | 72 | // THEN 73 | assertTrue(actualBoolean); 74 | } 75 | 76 | @Test 77 | public void W_negative_T_false() throws IOException { 78 | // WHEN 79 | when(jsonParser.getValueAsInt(0)).thenReturn(-1); 80 | Boolean actualBoolean = intToBooleanDeserializer.deserialize(jsonParser, null); 81 | 82 | // THEN 83 | assertFalse(actualBoolean); 84 | } 85 | 86 | @Test 87 | public void W_greaterThan1_T_true() throws IOException { 88 | // WHEN 89 | when(jsonParser.getValueAsInt(0)).thenReturn(5); 90 | Boolean actualBoolean = intToBooleanDeserializer.deserialize(jsonParser, null); 91 | 92 | // THEN 93 | assertTrue(actualBoolean); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/internal/ListToCsvSerializerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonGenerator; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.mockito.Mock; 32 | import org.mockito.runners.MockitoJUnitRunner; 33 | 34 | import java.io.IOException; 35 | import java.util.Arrays; 36 | import java.util.Collections; 37 | 38 | import static org.mockito.Mockito.verify; 39 | import static org.mockito.Mockito.verifyZeroInteractions; 40 | 41 | /** 42 | * Tests for {@link com.codepine.api.testrail.internal.ListToCsvSerializer}. 43 | */ 44 | @RunWith(MockitoJUnitRunner.class) 45 | public class ListToCsvSerializerTest { 46 | 47 | private ListToCsvSerializer listToCsvSerializer; 48 | 49 | @Mock 50 | private JsonGenerator jsonGenerator; 51 | 52 | @Before 53 | public void setUp() { 54 | listToCsvSerializer = new ListToCsvSerializer(); 55 | } 56 | 57 | @Test 58 | public void W_null_T_NoJson() throws IOException { 59 | // WHEN 60 | listToCsvSerializer.serialize(null, jsonGenerator, null); 61 | 62 | // THEN 63 | verifyZeroInteractions(jsonGenerator); 64 | } 65 | 66 | @Test 67 | public void W_empty_T_empty() throws IOException { 68 | // WHEN 69 | listToCsvSerializer.serialize(Collections.emptyList(), jsonGenerator, null); 70 | 71 | // THEN 72 | verify(jsonGenerator).writeString(""); 73 | } 74 | 75 | @Test 76 | public void W_singleElement_T_singleElement() throws IOException { 77 | // WHEN 78 | listToCsvSerializer.serialize(Collections.singletonList("a"), jsonGenerator, null); 79 | 80 | // THEN 81 | verify(jsonGenerator).writeString("a"); 82 | } 83 | 84 | @Test 85 | public void W_threeStringElements_T_threeCommaSeparatedValues() throws IOException { 86 | // WHEN 87 | listToCsvSerializer.serialize(Arrays.asList("a", "b", "c"), jsonGenerator, null); 88 | 89 | // THEN 90 | verify(jsonGenerator).writeString("a,b,c"); 91 | } 92 | 93 | @Test 94 | public void W_threeIntegerElements_T_threeCommaSeparatedValues() throws IOException { 95 | // WHEN 96 | listToCsvSerializer.serialize(Arrays.asList(1, 2, 3), jsonGenerator, null); 97 | 98 | // THEN 99 | verify(jsonGenerator).writeString("1,2,3"); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/internal/PlanModuleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.codepine.api.testrail.model.Plan; 28 | import com.fasterxml.jackson.databind.ObjectMapper; 29 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 30 | import com.fasterxml.jackson.databind.SerializationFeature; 31 | import org.junit.Test; 32 | 33 | import java.io.IOException; 34 | import java.util.Arrays; 35 | import java.util.Collections; 36 | import java.util.Date; 37 | import java.util.List; 38 | 39 | import static org.junit.Assert.assertEquals; 40 | 41 | /** 42 | * Tests for {@link com.codepine.api.testrail.internal.PlanModule}. 43 | *

This test does not use mocks. It has some dependencies which it assumes are tested separately.

44 | */ 45 | public class PlanModuleTest { 46 | 47 | private static final ObjectMapper objectMapper = new ObjectMapper() 48 | .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) 49 | .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) 50 | .registerModules(new PlanModule(), new UnixTimestampModule()); 51 | 52 | @Test 53 | public void W_planWithNoEntries_T_correctDeserialization() throws IOException { 54 | // WHEN 55 | Plan actualPlan = objectMapper.readValue(this.getClass().getResourceAsStream("/plan_with_no_entries.json"), Plan.class); 56 | 57 | // THEN 58 | Plan expectedPlan = new Plan().setId(6).setName("Chrome Plan").setUntestedCount(7).setFailedCount(2).setProjectId(1).setCreatedBy(1).setCreatedOn(new Date(1415642870000L)).setUrl("http://somehost/testrail/index.php?/plans/view/6"); 59 | assertEquals(expectedPlan, actualPlan); 60 | } 61 | 62 | @Test 63 | public void W_planWithEntries_T_correctDeserializationAndRunsHaveCreatedOnAndCreatedBySameAsPlan() throws IOException { 64 | // WHEN 65 | Plan actualPlan = objectMapper.readValue(this.getClass().getResourceAsStream("/plan_with_entries.json"), Plan.class); 66 | 67 | // THEN 68 | Plan.Entry.Run run = (Plan.Entry.Run) new Plan.Entry.Run().setEntryIndex(1).setEntryId("67cef25c-0e7b-4457-8eda-aa33596d9a04").setId(7).setSuiteId(1).setName("Test Suite 1").setIncludeAll(false).setPassedCount(1).setProjectId(1).setPlanId(6).setConfigIds(Collections.emptyList()).setUrl("http://somehost/testrail/index.php?/runs/view/7").setCreatedBy(1).setCreatedOn(new Date(1415642870000L)); 69 | Plan.Entry entry = new Plan.Entry().setId("67cef25c-0e7b-4457-8eda-aa33596d9a04").setSuiteId(1).setName("Test Suite 1").setRuns(Collections.singletonList(run)); 70 | List entries = Arrays.asList(entry, new Plan.Entry().setId("f070f479-723f-4aeb-80b6-feb532263d3d").setSuiteId(3).setName("Test Suite 2")); 71 | Plan expectedPlan = new Plan().setId(6).setName("Chrome Plan").setUntestedCount(7).setFailedCount(2).setProjectId(1).setCreatedBy(1).setCreatedOn(new Date(1415642870000L)).setUrl("http://somehost/testrail/index.php?/plans/view/6").setEntries(entries); 72 | assertEquals(expectedPlan, actualPlan); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/internal/ResultModuleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.codepine.api.testrail.model.CaseField; 28 | import com.codepine.api.testrail.model.Field; 29 | import com.codepine.api.testrail.model.Result; 30 | import com.codepine.api.testrail.model.ResultField; 31 | import com.fasterxml.jackson.databind.InjectableValues; 32 | import com.fasterxml.jackson.databind.ObjectMapper; 33 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 34 | import com.fasterxml.jackson.databind.SerializationFeature; 35 | import org.junit.Test; 36 | 37 | import java.io.IOException; 38 | import java.util.Arrays; 39 | import java.util.Collections; 40 | import java.util.Date; 41 | import java.util.List; 42 | 43 | import static org.junit.Assert.assertEquals; 44 | 45 | /** 46 | * Tests for {@link com.codepine.api.testrail.internal.ResultModule}. 47 | *

This test does not use mocks. It has some dependencies which it assumes are tested separately.

48 | */ 49 | public class ResultModuleTest { 50 | 51 | private static final ObjectMapper objectMapper = new ObjectMapper() 52 | .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) 53 | .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) 54 | .registerModules(new ResultModule(), new UnixTimestampModule()); 55 | 56 | @Test(expected = IllegalArgumentException.class) 57 | public void G_noCustomResultFields_W_resultStringWithCustomStepResultsField_T_exception() throws IOException { 58 | // GIVEN 59 | List resultFields = Collections.emptyList(); 60 | 61 | // WHEN 62 | objectMapper.reader(Result.class).with(new InjectableValues.Std().addValue(Result.class.toString(), resultFields)).readValue(this.getClass().getResourceAsStream("/result_with_step_result_field_set.json")); 63 | } 64 | 65 | @Test 66 | public void G_noCustomResultFields_W_resultStringWithNoCustomResultsField_T_correctDeserialization() throws IOException { 67 | // GIVEN 68 | List resultFields = Collections.emptyList(); 69 | 70 | // WHEN 71 | Result actualResult = objectMapper.reader(Result.class).with(new InjectableValues.Std().addValue(Result.class.toString(), resultFields)).readValue(this.getClass().getResourceAsStream("/result_with_no_custom_fields.json")); 72 | 73 | // THEN 74 | Result expectedResult = new Result().setId(11).setTestId(48).setStatusId(1).setCreatedBy(1).setCreatedOn(new Date(1425687075000L)); 75 | assertEquals(expectedResult, actualResult); 76 | } 77 | 78 | @Test 79 | public void G_customResultFieldStepResults_W_resultStringWithCustomStepResultsField_T_correctDeserializationAndStepResultsField() throws IOException { 80 | // GIVEN 81 | ResultField stepResultField = objectMapper.readValue(this.getClass().getResourceAsStream("/step_result_field.json"), ResultField.class); 82 | List resultFields = Collections.singletonList(stepResultField); 83 | 84 | // WHEN 85 | Result actualResult = objectMapper.reader(Result.class).with(new InjectableValues.Std().addValue(Result.class.toString(), resultFields)).readValue(this.getClass().getResourceAsStream("/result_with_step_result_field_set.json")); 86 | 87 | // THEN 88 | List stepResults = Arrays.asList(new Field.StepResult().setContent("Step 1").setExpected("Expected 1").setActual("Expected 2").setStatusId(4), new Field.StepResult().setContent("Step 2").setExpected("Expected 2").setActual("Unexpected").setStatusId(3)); 89 | Result expectedResult = new Result().setId(11).setTestId(48).setStatusId(1).setCreatedBy(1).setCreatedOn(new Date(1425687075000L)).addCustomField("step_results", stepResults); 90 | assertEquals(expectedResult, actualResult); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/internal/StringToMapDeserializerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.core.JsonParser; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.mockito.Mock; 32 | import org.mockito.runners.MockitoJUnitRunner; 33 | 34 | import java.io.IOException; 35 | import java.util.Collections; 36 | import java.util.HashMap; 37 | import java.util.Map; 38 | 39 | import static org.junit.Assert.assertEquals; 40 | import static org.junit.Assert.assertNull; 41 | import static org.junit.Assert.assertTrue; 42 | import static org.mockito.Mockito.when; 43 | 44 | /** 45 | * Tests for {@link com.codepine.api.testrail.internal.StringToMapDeserializer}. 46 | */ 47 | @RunWith(MockitoJUnitRunner.class) 48 | public class StringToMapDeserializerTest { 49 | 50 | private StringToMapDeserializer stringToMapDeserializer; 51 | 52 | @Mock 53 | private JsonParser jsonParser; 54 | 55 | @Before 56 | public void setUp() { 57 | stringToMapDeserializer = new StringToMapDeserializer(); 58 | } 59 | 60 | @Test 61 | public void W_null_T_null() throws IOException { 62 | // WHEN 63 | when(jsonParser.getValueAsString()).thenReturn(null); 64 | Map actualMap = stringToMapDeserializer.deserialize(jsonParser, null); 65 | 66 | // THEN 67 | assertNull(actualMap); 68 | } 69 | 70 | @Test 71 | public void W_empty_T_empty() throws IOException { 72 | // WHEN 73 | when(jsonParser.getValueAsString()).thenReturn(""); 74 | Map actualMap = stringToMapDeserializer.deserialize(jsonParser, null); 75 | 76 | // THEN 77 | assertTrue("Map is not empty", actualMap.isEmpty()); 78 | } 79 | 80 | @Test 81 | public void W_singleCommaSeparatedValuePair_T_singlePair() throws IOException { 82 | // WHEN 83 | when(jsonParser.getValueAsString()).thenReturn("a,b"); 84 | Map actualMap = stringToMapDeserializer.deserialize(jsonParser, null); 85 | 86 | // THEN 87 | Map expectedMap = Collections.singletonMap("a", "b"); 88 | assertEquals(expectedMap, actualMap); 89 | } 90 | 91 | @Test 92 | public void W_threeCommaSeparatedValuePairsOnNewLines_T_threePairs() throws IOException { 93 | // WHEN 94 | when(jsonParser.getValueAsString()).thenReturn("a,b\nc, d\ne,f"); 95 | Map actualMap = stringToMapDeserializer.deserialize(jsonParser, null); 96 | 97 | // THEN 98 | Map expectedMap = new HashMap<>(3); 99 | expectedMap.put("a", "b"); 100 | expectedMap.put("c", "d"); 101 | expectedMap.put("e", "f"); 102 | assertEquals(expectedMap, actualMap); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/com/codepine/api/testrail/internal/UnixTimestampModuleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 Kunal Shah 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.codepine.api.testrail.internal; 26 | 27 | import com.fasterxml.jackson.annotation.JsonInclude; 28 | import com.fasterxml.jackson.core.JsonProcessingException; 29 | import com.fasterxml.jackson.databind.ObjectMapper; 30 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 31 | import com.fasterxml.jackson.databind.SerializationFeature; 32 | import org.junit.Test; 33 | 34 | import java.io.IOException; 35 | import java.util.Date; 36 | 37 | import static org.junit.Assert.assertEquals; 38 | 39 | /** 40 | * Tests for {@link com.codepine.api.testrail.internal.UnixTimestampModule}. 41 | *

This test does not use mocks. It has some dependencies which it assumes are tested separately.

42 | */ 43 | public class UnixTimestampModuleTest { 44 | 45 | private static final ObjectMapper objectMapper = new ObjectMapper() 46 | .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) 47 | .setSerializationInclusion(JsonInclude.Include.NON_NULL) 48 | .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) 49 | .registerModules(new UnixTimestampModule()); 50 | 51 | @Test 52 | public void W_date_T_serializedCorrectlyToUnixTimestamp() throws JsonProcessingException { 53 | // WHEN 54 | String actualDate = objectMapper.writeValueAsString(new Date(1424641170000L)); 55 | 56 | // THEN 57 | String expectedDate = "1424641170"; 58 | assertEquals(expectedDate, actualDate); 59 | } 60 | 61 | @Test 62 | public void W_unixTimestamp_T_deserializedCorrectlyToDate() throws IOException { 63 | // WHEN 64 | Date actualDate = objectMapper.readValue("1424641170", Date.class); 65 | 66 | // THEN 67 | Date expectedDate = new Date(1424641170000L); 68 | assertEquals(expectedDate, actualDate); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/resources/add_model.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "name": "Test Model 1", 4 | "show_announcement": true, 5 | "is_completed": false, 6 | "completed_on": null, 7 | "suite_mode": 2 8 | } -------------------------------------------------------------------------------- /src/test/resources/auth_error.json: -------------------------------------------------------------------------------- 1 | {"error":"Authentication failed: invalid or missing user/password or session cookie."} -------------------------------------------------------------------------------- /src/test/resources/case_with_no_custom_fields.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 13, 3 | "title": "Test Case 2", 4 | "section_id": 6, 5 | "type_id": 6, 6 | "priority_id": 4, 7 | "milestone_id": null, 8 | "refs": null, 9 | "created_by": 1, 10 | "created_on": 1425683583, 11 | "updated_by": 1, 12 | "updated_on": 1425845918, 13 | "estimate": null, 14 | "estimate_forecast": null, 15 | "suite_id": 4 16 | } -------------------------------------------------------------------------------- /src/test/resources/case_with_step_field_set.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 13, 3 | "title": "Test Case 2", 4 | "section_id": 6, 5 | "type_id": 6, 6 | "priority_id": 4, 7 | "milestone_id": null, 8 | "refs": null, 9 | "created_by": 1, 10 | "created_on": 1425683583, 11 | "updated_by": 1, 12 | "updated_on": 1425845918, 13 | "estimate": null, 14 | "estimate_forecast": null, 15 | "suite_id": 4, 16 | "custom_separated_steps": [ 17 | { 18 | "content": "Step 1", 19 | "expected": "Expected 1" 20 | }, 21 | { 22 | "content": "Step 2", 23 | "expected": "Expected 2" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /src/test/resources/get_cases.json: -------------------------------------------------------------------------------- 1 | { 2 | "offset": 0, 3 | "limit": 250, 4 | "size": 131, 5 | "_links": { 6 | "next": null, 7 | "prev": null 8 | }, 9 | "cases": [ 10 | { 11 | "id": 1, 12 | "title": "[PERF] Login" 13 | }, 14 | { 15 | "id": 2, 16 | "title": "[PERF] Create institution" 17 | }, 18 | { 19 | "id": 3, 20 | "title": "[PERF] Import election configuration" 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /src/test/resources/get_model.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "name": "Test Model 1", 4 | "show_announcement": false, 5 | "is_completed": true, 6 | "completed_on": 1424641170, 7 | "suite_mode": 2 8 | } -------------------------------------------------------------------------------- /src/test/resources/get_model_error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "Field :model_id is not a valid or accessible model." 3 | } -------------------------------------------------------------------------------- /src/test/resources/get_models.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "name": "Test Model 1", 5 | "show_announcement": false, 6 | "is_completed": true, 7 | "completed_on": 1424641170, 8 | "suite_mode": 2 9 | }, 10 | { 11 | "id": 3, 12 | "name": "Test Model 3", 13 | "show_announcement": true, 14 | "is_completed": true, 15 | "completed_on": 1424651896, 16 | "suite_mode": 3 17 | }, 18 | { 19 | "id": 4, 20 | "name": "Test Model 4", 21 | "show_announcement": false, 22 | "is_completed": false, 23 | "completed_on": 1426110846, 24 | "suite_mode": 1 25 | } 26 | ] -------------------------------------------------------------------------------- /src/test/resources/get_modelsA.json: -------------------------------------------------------------------------------- 1 | { 2 | "offset": 0, 3 | "limit": 250, 4 | "size": 2, 5 | "_links": { 6 | "next": "/api/v2/get_models/2", 7 | "prev": null 8 | }, 9 | "models": [ 10 | { 11 | "id": 1, 12 | "name": "Test Model 1", 13 | "show_announcement": false, 14 | "is_completed": true, 15 | "completed_on": 1424641170, 16 | "suite_mode": 2 17 | }, 18 | { 19 | "id": 3, 20 | "name": "Test Model 3", 21 | "show_announcement": true, 22 | "is_completed": true, 23 | "completed_on": 1424651896, 24 | "suite_mode": 3 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /src/test/resources/get_modelsB.json: -------------------------------------------------------------------------------- 1 | { 2 | "offset": 0, 3 | "limit": 250, 4 | "size": 1, 5 | "_links": { 6 | "next": "/api/v2/get_models/3", 7 | "prev": "/api/v2/get_models/1" 8 | }, 9 | "models": [ 10 | { 11 | "id": 4, 12 | "name": "Test Model 4", 13 | "show_announcement": false, 14 | "is_completed": false, 15 | "completed_on": 1426110846, 16 | "suite_mode": 1 17 | } 18 | ] 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/test/resources/get_modelsC.json: -------------------------------------------------------------------------------- 1 | { 2 | "offset": 0, 3 | "limit": 250, 4 | "size": 1, 5 | "_links": { 6 | "next": null, 7 | "prev": "/api/v2/get_models/2" 8 | }, 9 | "models": [ 10 | { 11 | "id": 5, 12 | "name": "Test Model 5", 13 | "show_announcement": false, 14 | "is_completed": false, 15 | "completed_on": 1426110846, 16 | "suite_mode": 1 17 | } 18 | ] 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=DEBUG, stdout 3 | 4 | # Direct log messages to stdout 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.Target=System.out 7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /src/test/resources/plan_with_entries.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 6, 3 | "name": "Chrome Plan", 4 | "description": null, 5 | "milestone_id": null, 6 | "assignedto_id": null, 7 | "is_completed": false, 8 | "completed_on": null, 9 | "passed_count": 0, 10 | "blocked_count": 0, 11 | "untested_count": 7, 12 | "retest_count": 0, 13 | "failed_count": 2, 14 | "custom_status1_count": 0, 15 | "custom_status2_count": 0, 16 | "custom_status3_count": 0, 17 | "custom_status4_count": 0, 18 | "custom_status5_count": 0, 19 | "custom_status6_count": 0, 20 | "custom_status7_count": 0, 21 | "project_id": 1, 22 | "created_on": 1415642870, 23 | "created_by": 1, 24 | "url": "http://somehost/testrail/index.php?/plans/view/6", 25 | "entries": [ 26 | { 27 | "id": "67cef25c-0e7b-4457-8eda-aa33596d9a04", 28 | "suite_id": 1, 29 | "name": "Test Suite 1", 30 | "runs": [ 31 | { 32 | "id": 7, 33 | "suite_id": 1, 34 | "name": "Test Suite 1", 35 | "description": null, 36 | "milestone_id": null, 37 | "assignedto_id": null, 38 | "include_all": false, 39 | "is_completed": false, 40 | "completed_on": null, 41 | "passed_count": 1, 42 | "blocked_count": 0, 43 | "untested_count": 0, 44 | "retest_count": 0, 45 | "failed_count": 0, 46 | "custom_status1_count": 0, 47 | "custom_status2_count": 0, 48 | "custom_status3_count": 0, 49 | "custom_status4_count": 0, 50 | "custom_status5_count": 0, 51 | "custom_status6_count": 0, 52 | "custom_status7_count": 0, 53 | "project_id": 1, 54 | "plan_id": 6, 55 | "entry_index": 1, 56 | "entry_id": "67cef25c-0e7b-4457-8eda-aa33596d9a04", 57 | "config": null, 58 | "config_ids": [], 59 | "url": "http://somehost/testrail/index.php?/runs/view/7" 60 | } 61 | ] 62 | }, 63 | { 64 | "id": "f070f479-723f-4aeb-80b6-feb532263d3d", 65 | "suite_id": 3, 66 | "name": "Test Suite 2" 67 | } 68 | ] 69 | } -------------------------------------------------------------------------------- /src/test/resources/plan_with_no_entries.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 6, 3 | "name": "Chrome Plan", 4 | "description": null, 5 | "milestone_id": null, 6 | "assignedto_id": null, 7 | "is_completed": false, 8 | "completed_on": null, 9 | "passed_count": 0, 10 | "blocked_count": 0, 11 | "untested_count": 7, 12 | "retest_count": 0, 13 | "failed_count": 2, 14 | "custom_status1_count": 0, 15 | "custom_status2_count": 0, 16 | "custom_status3_count": 0, 17 | "custom_status4_count": 0, 18 | "custom_status5_count": 0, 19 | "custom_status6_count": 0, 20 | "custom_status7_count": 0, 21 | "project_id": 1, 22 | "created_on": 1415642870, 23 | "created_by": 1, 24 | "url": "http://somehost/testrail/index.php?/plans/view/6" 25 | } -------------------------------------------------------------------------------- /src/test/resources/result_with_no_custom_fields.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 11, 3 | "test_id": 48, 4 | "status_id": 1, 5 | "created_by": 1, 6 | "created_on": 1425687075, 7 | "assignedto_id": null, 8 | "comment": null, 9 | "version": null, 10 | "elapsed": null, 11 | "defects": null 12 | } -------------------------------------------------------------------------------- /src/test/resources/result_with_step_result_field_set.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 11, 3 | "test_id": 48, 4 | "status_id": 1, 5 | "created_by": 1, 6 | "created_on": 1425687075, 7 | "assignedto_id": null, 8 | "comment": null, 9 | "version": null, 10 | "elapsed": null, 11 | "defects": null, 12 | "custom_step_results": [ 13 | { 14 | "content": "Step 1", 15 | "expected": "Expected 1", 16 | "actual": "Expected 2", 17 | "status_id": 4 18 | }, 19 | { 20 | "content": "Step 2", 21 | "expected": "Expected 2", 22 | "actual": "Unexpected", 23 | "status_id": 3 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /src/test/resources/step_field.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 4, 3 | "type_id": 10, 4 | "name": "separated_steps", 5 | "system_name": "custom_separated_steps", 6 | "label": "Separated Steps", 7 | "description": null, 8 | "configs": [ 9 | { 10 | "context": { 11 | "is_global": true, 12 | "project_ids": [] 13 | }, 14 | "options": { 15 | "is_required": false, 16 | "format": "markdown", 17 | "has_expected": true, 18 | "rows": "6" 19 | }, 20 | "id": "47e68955-c7fc-4c01-8313-d9de6c4cad7c" 21 | } 22 | ], 23 | "display_order": 4 24 | } -------------------------------------------------------------------------------- /src/test/resources/step_result_field.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 9, 3 | "type_id": 11, 4 | "name": "step_results", 5 | "system_name": "custom_step_results", 6 | "label": "Step Results", 7 | "description": null, 8 | "configs": [ 9 | { 10 | "context": { 11 | "is_global": true, 12 | "project_ids": [] 13 | }, 14 | "options": { 15 | "is_required": false, 16 | "format": "markdown", 17 | "has_expected": true, 18 | "has_actual": false 19 | }, 20 | "id": "7ab8be69-8fd7-4e37-8d40-c78248091842" 21 | } 22 | ], 23 | "display_order": 1 24 | } -------------------------------------------------------------------------------- /src/test/resources/update_model.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "name": "Test Model 1", 4 | "show_announcement": false, 5 | "is_completed": true, 6 | "completed_on": 1424641170, 7 | "suite_mode": 2 8 | } --------------------------------------------------------------------------------