├── CourseLandingPage.png ├── README.md ├── pom.xml └── src └── test ├── java └── com │ └── spotify │ └── oauth2 │ ├── api │ ├── RestResource.java │ ├── Route.java │ ├── SpecBuilder.java │ ├── StatusCode.java │ ├── TokenManager.java │ └── applicationApi │ │ └── PlaylistApi.java │ ├── pojo │ ├── Error.java │ ├── ExternalUrls.java │ ├── ExternalUrls_.java │ ├── Followers.java │ ├── InnerError.java │ ├── Owner.java │ ├── Playlist.java │ └── Tracks.java │ ├── tests │ ├── BaseTest.java │ └── PlaylistTests.java │ └── utils │ ├── ConfigLoader.java │ ├── DataLoader.java │ ├── DummyClass.java │ ├── FakerUtils.java │ └── PropertyUtils.java └── resources ├── allure.properties ├── config.properties └── data.properties /CourseLandingPage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omprakashchavan01/RestAssuredTestNGFramework/d8c92d59c5fbdd52a9fe46193efe3225128e25d8/CourseLandingPage.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RestAssuredTestNGFramework 2 | REST Assured API test automation framework using Java + Maven + TestNG. 3 | Framework follows many of the industry best practices. 4 | 5 | **Step by step instructions to build this framework from scratch and integrate with Jenkins CI is in this Highest Rated Udemy course. 6 | Enroll today at the minimal rate of INR 499/ $14.99. 7 | Link with coupon code: https://www.udemy.com/course/rest-assured-api-automation/?couponCode=APR2024** 8 | 9 | ![Udemy_Landing_Page](/CourseLandingPage.png) 10 | 11 | Technologies/Tools used in building the framework 12 | ================================================= 13 | - Rest Assured 14 | - TestNG 15 | - Java 16 | - Allure Reports 17 | - Hamcrest 18 | - Jackson API 19 | - Lombok 20 | - IntelliJ 21 | - GitHub 22 | - Jenkins 23 | 24 | Framework implements below best practices 25 | ========================================= 26 | - Scalable and extensible 27 | - Reusable Rest Assured specifications 28 | - Reusable Rest Assured API requests 29 | - Separation of API layer from test layer 30 | - POJOs for Serialization and Deserialization 31 | - Singleton Design Pattern 32 | - Lombok for reducing Boilerplate code 33 | - Builder pattern for Setter methods in POJOs 34 | - Robust reporting and logging using Allure 35 | - Automate positive and negative scenarios 36 | - Support parallel execution 37 | - Data driven using TestNG Data Provider 38 | - Automated access token renewal 39 | - Maven command line execution 40 | - Integration with Git 41 | - Integration with Jenkins 42 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | RestAssuredFramework 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 1.9.20.1 13 | 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 21 | 21 22 | 21 23 | 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-surefire-plugin 28 | 3.2.2 29 | 30 | methods 31 | 10 32 | 33 | -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" 34 | 35 | 36 | 37 | 38 | org.aspectj 39 | aspectjweaver 40 | ${aspectj.version} 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | io.rest-assured 51 | rest-assured 52 | 5.3.2 53 | test 54 | 55 | 56 | 57 | org.testng 58 | testng 59 | 7.8.0 60 | test 61 | 62 | 63 | 64 | com.fasterxml.jackson.core 65 | jackson-databind 66 | 2.15.3 67 | 68 | 69 | 70 | org.skyscreamer 71 | jsonassert 72 | 1.5.1 73 | test 74 | 75 | 76 | 77 | org.projectlombok 78 | lombok 79 | 1.18.30 80 | provided 81 | 82 | 83 | 84 | io.qameta.allure 85 | allure-testng 86 | 2.24.0 87 | 88 | 89 | 90 | io.qameta.allure 91 | allure-rest-assured 92 | 2.24.0 93 | 94 | 95 | 96 | com.github.javafaker 97 | javafaker 98 | 1.0.2 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/api/RestResource.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.api; 2 | 3 | import io.restassured.response.Response; 4 | 5 | import java.util.HashMap; 6 | 7 | import static com.spotify.oauth2.api.Route.API; 8 | import static com.spotify.oauth2.api.Route.TOKEN; 9 | import static com.spotify.oauth2.api.SpecBuilder.*; 10 | import static io.restassured.RestAssured.given; 11 | 12 | public class RestResource { 13 | 14 | public static Response post(String path, String token, Object requestPlaylist){ 15 | return given(getRequestSpec()). 16 | body(requestPlaylist). 17 | auth().oauth2(token). 18 | when().post(path). 19 | then().spec(getResponseSpec()). 20 | extract(). 21 | response(); 22 | } 23 | 24 | public static Response postAccount(HashMap formParams){ 25 | return given(getAccountRequestSpec()). 26 | formParams(formParams). 27 | when().post(API + TOKEN). 28 | then().spec(getResponseSpec()). 29 | extract(). 30 | response(); 31 | } 32 | 33 | public static Response get(String path, String token){ 34 | return given(getRequestSpec()). 35 | auth().oauth2(token). 36 | when().get(path). 37 | then().spec(getResponseSpec()). 38 | extract(). 39 | response(); 40 | } 41 | 42 | public static Response update(String path, String token, Object requestPlaylist){ 43 | return given(getRequestSpec()). 44 | auth().oauth2(token). 45 | body(requestPlaylist). 46 | when().put(path). 47 | then().spec(getResponseSpec()). 48 | extract(). 49 | response(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/api/Route.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.api; 2 | 3 | public class Route { 4 | public static final String BASE_PATH = "/v1"; 5 | public static final String API = "/api"; 6 | public static final String TOKEN = "/token"; 7 | public static final String USERS = "/users"; 8 | public static final String PLAYLISTS = "/playlists"; 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/api/SpecBuilder.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.api; 2 | 3 | import io.qameta.allure.restassured.AllureRestAssured; 4 | import io.restassured.builder.RequestSpecBuilder; 5 | import io.restassured.builder.ResponseSpecBuilder; 6 | import io.restassured.filter.log.LogDetail; 7 | import io.restassured.http.ContentType; 8 | import io.restassured.specification.RequestSpecification; 9 | import io.restassured.specification.ResponseSpecification; 10 | 11 | import static com.spotify.oauth2.api.Route.BASE_PATH; 12 | 13 | public class SpecBuilder { 14 | 15 | public static RequestSpecification getRequestSpec(){ 16 | return new RequestSpecBuilder(). 17 | setBaseUri(System.getProperty("BASE_URI")). 18 | // setBaseUri("https://api.spotify.com"). 19 | setBasePath(BASE_PATH). 20 | setContentType(ContentType.JSON). 21 | addFilter(new AllureRestAssured()). 22 | log(LogDetail.ALL). 23 | build(); 24 | } 25 | 26 | public static RequestSpecification getAccountRequestSpec(){ 27 | return new RequestSpecBuilder(). 28 | setBaseUri(System.getProperty("ACCOUNT_BASE_URI")). 29 | // setBaseUri("https://accounts.spotify.com"). 30 | setContentType(ContentType.URLENC). 31 | addFilter(new AllureRestAssured()). 32 | log(LogDetail.ALL). 33 | build(); 34 | } 35 | 36 | public static ResponseSpecification getResponseSpec(){ 37 | return new ResponseSpecBuilder(). 38 | log(LogDetail.ALL). 39 | build(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/api/StatusCode.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.api; 2 | 3 | public enum StatusCode { 4 | CODE_200(200, ""), 5 | CODE_201(201, ""), 6 | CODE_400(400, "Missing required field: name"), 7 | CODE_401(401, "Invalid access token"); 8 | 9 | public final int code; 10 | public final String msg; 11 | 12 | StatusCode(int code, String msg) { 13 | this.code = code; 14 | this.msg = msg; 15 | } 16 | 17 | /* public int getCode(){ 18 | return code; 19 | } 20 | 21 | public String getMsg(){ 22 | return msg; 23 | }*/ 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/api/TokenManager.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.api; 2 | 3 | import com.spotify.oauth2.utils.ConfigLoader; 4 | import io.restassured.response.Response; 5 | 6 | import java.time.Instant; 7 | import java.util.HashMap; 8 | 9 | public class TokenManager { 10 | private static String access_token; 11 | private static Instant expiry_time; 12 | 13 | public synchronized static String getToken(){ 14 | try{ 15 | if(access_token == null || Instant.now().isAfter(expiry_time)){ 16 | System.out.println("Renewing token ..."); 17 | Response response = renewToken(); 18 | access_token = response.path("access_token"); 19 | int expiryDurationInSeconds = response.path("expires_in"); 20 | expiry_time = Instant.now().plusSeconds(expiryDurationInSeconds - 300); 21 | } else{ 22 | System.out.println("Token is good to use"); 23 | } 24 | } 25 | catch (Exception e){ 26 | e.printStackTrace(); 27 | throw new RuntimeException("ABORT!!! Failed to get token"); 28 | } 29 | return access_token; 30 | } 31 | 32 | private static Response renewToken(){ 33 | HashMap formParams = new HashMap(); 34 | formParams.put("client_id", ConfigLoader.getInstance().getClientId()); 35 | formParams.put("client_secret", ConfigLoader.getInstance().getClientSecret()); 36 | formParams.put("refresh_token", ConfigLoader.getInstance().getRefreshToken()); 37 | formParams.put("grant_type", ConfigLoader.getInstance().getGrantType()); 38 | 39 | Response response = RestResource.postAccount(formParams); 40 | 41 | if(response.statusCode() != 200){ 42 | throw new RuntimeException("ABORT!!! Renew Token failed"); 43 | } 44 | return response; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/api/applicationApi/PlaylistApi.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.api.applicationApi; 2 | 3 | import com.spotify.oauth2.api.RestResource; 4 | import com.spotify.oauth2.pojo.Playlist; 5 | import com.spotify.oauth2.utils.ConfigLoader; 6 | import io.qameta.allure.Step; 7 | import io.restassured.response.Response; 8 | 9 | import static com.spotify.oauth2.api.Route.PLAYLISTS; 10 | import static com.spotify.oauth2.api.Route.USERS; 11 | import static com.spotify.oauth2.api.TokenManager.getToken; 12 | 13 | public class PlaylistApi { 14 | 15 | @Step 16 | public static Response post(Playlist requestPlaylist){ 17 | return RestResource.post(USERS + "/" + ConfigLoader.getInstance().getUser() 18 | + PLAYLISTS, getToken(), requestPlaylist); 19 | } 20 | 21 | public static Response post(String token, Playlist requestPlaylist){ 22 | return RestResource.post(USERS + "/" + ConfigLoader.getInstance().getUser() 23 | + PLAYLISTS, token, requestPlaylist); 24 | } 25 | 26 | public static Response get(String playlistId){ 27 | return RestResource.get(PLAYLISTS + "/" + playlistId, getToken()); 28 | } 29 | 30 | public static Response update(String playlistId, Playlist requestPlaylist){ 31 | return RestResource.update(PLAYLISTS + "/" + playlistId, getToken(), requestPlaylist); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/pojo/Error.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.pojo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import lombok.extern.jackson.Jacksonized; 9 | 10 | @Getter @Setter 11 | @Jacksonized 12 | @Builder 13 | @JsonInclude(JsonInclude.Include.NON_NULL) 14 | public class Error { 15 | 16 | @JsonProperty("error") 17 | private InnerError error; 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/pojo/ExternalUrls.java: -------------------------------------------------------------------------------- 1 | 2 | package com.spotify.oauth2.pojo; 3 | 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonInclude(JsonInclude.Include.NON_NULL) 8 | public class ExternalUrls { 9 | 10 | @JsonProperty("spotify") 11 | private String spotify; 12 | 13 | @JsonProperty("spotify") 14 | public String getSpotify() { 15 | return spotify; 16 | } 17 | 18 | @JsonProperty("spotify") 19 | public void setSpotify(String spotify) { 20 | this.spotify = spotify; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/pojo/ExternalUrls_.java: -------------------------------------------------------------------------------- 1 | 2 | package com.spotify.oauth2.pojo; 3 | 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonInclude(JsonInclude.Include.NON_NULL) 8 | public class ExternalUrls_ { 9 | 10 | @JsonProperty("spotify") 11 | private String spotify; 12 | 13 | @JsonProperty("spotify") 14 | public String getSpotify() { 15 | return spotify; 16 | } 17 | 18 | @JsonProperty("spotify") 19 | public void setSpotify(String spotify) { 20 | this.spotify = spotify; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/pojo/Followers.java: -------------------------------------------------------------------------------- 1 | 2 | package com.spotify.oauth2.pojo; 3 | 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonInclude(JsonInclude.Include.NON_NULL) 8 | public class Followers { 9 | 10 | @JsonProperty("href") 11 | private Object href; 12 | @JsonProperty("total") 13 | private Integer total; 14 | 15 | @JsonProperty("href") 16 | public Object getHref() { 17 | return href; 18 | } 19 | 20 | @JsonProperty("href") 21 | public void setHref(Object href) { 22 | this.href = href; 23 | } 24 | 25 | @JsonProperty("total") 26 | public Integer getTotal() { 27 | return total; 28 | } 29 | 30 | @JsonProperty("total") 31 | public void setTotal(Integer total) { 32 | this.total = total; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/pojo/InnerError.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.pojo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | @JsonInclude(JsonInclude.Include.NON_NULL) 7 | public class InnerError { 8 | 9 | @JsonProperty("status") 10 | private Integer status; 11 | @JsonProperty("message") 12 | private String message; 13 | 14 | @JsonProperty("status") 15 | public Integer getStatus() { 16 | return status; 17 | } 18 | 19 | @JsonProperty("status") 20 | public void setStatus(Integer status) { 21 | this.status = status; 22 | } 23 | 24 | @JsonProperty("message") 25 | public String getMessage() { 26 | return message; 27 | } 28 | 29 | @JsonProperty("message") 30 | public void setMessage(String message) { 31 | this.message = message; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/pojo/Owner.java: -------------------------------------------------------------------------------- 1 | 2 | package com.spotify.oauth2.pojo; 3 | 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonInclude(JsonInclude.Include.NON_NULL) 8 | public class Owner { 9 | 10 | @JsonProperty("display_name") 11 | private String displayName; 12 | @JsonProperty("external_urls") 13 | private ExternalUrls_ externalUrls; 14 | @JsonProperty("href") 15 | private String href; 16 | @JsonProperty("id") 17 | private String id; 18 | @JsonProperty("type") 19 | private String type; 20 | @JsonProperty("uri") 21 | private String uri; 22 | 23 | @JsonProperty("display_name") 24 | public String getDisplayName() { 25 | return displayName; 26 | } 27 | 28 | @JsonProperty("display_name") 29 | public void setDisplayName(String displayName) { 30 | this.displayName = displayName; 31 | } 32 | 33 | @JsonProperty("external_urls") 34 | public ExternalUrls_ getExternalUrls() { 35 | return externalUrls; 36 | } 37 | 38 | @JsonProperty("external_urls") 39 | public void setExternalUrls(ExternalUrls_ externalUrls) { 40 | this.externalUrls = externalUrls; 41 | } 42 | 43 | @JsonProperty("href") 44 | public String getHref() { 45 | return href; 46 | } 47 | 48 | @JsonProperty("href") 49 | public void setHref(String href) { 50 | this.href = href; 51 | } 52 | 53 | @JsonProperty("id") 54 | public String getId() { 55 | return id; 56 | } 57 | 58 | @JsonProperty("id") 59 | public void setId(String id) { 60 | this.id = id; 61 | } 62 | 63 | @JsonProperty("type") 64 | public String getType() { 65 | return type; 66 | } 67 | 68 | @JsonProperty("type") 69 | public void setType(String type) { 70 | this.type = type; 71 | } 72 | 73 | @JsonProperty("uri") 74 | public String getUri() { 75 | return uri; 76 | } 77 | 78 | @JsonProperty("uri") 79 | public void setUri(String uri) { 80 | this.uri = uri; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/pojo/Playlist.java: -------------------------------------------------------------------------------- 1 | 2 | package com.spotify.oauth2.pojo; 3 | 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import lombok.Builder; 7 | import lombok.Value; 8 | import lombok.extern.jackson.Jacksonized; 9 | 10 | import java.util.List; 11 | 12 | @Value 13 | //@Data 14 | //@Getter @Setter 15 | @Jacksonized 16 | @Builder 17 | @JsonInclude(JsonInclude.Include.NON_NULL) 18 | public class Playlist { 19 | @JsonProperty("collaborative") 20 | Boolean collaborative; 21 | @JsonProperty("description") 22 | String description; 23 | @JsonProperty("external_urls") 24 | ExternalUrls externalUrls; 25 | @JsonProperty("followers") 26 | Followers followers; 27 | @JsonProperty("href") 28 | String href; 29 | @JsonProperty("id") 30 | String id; 31 | @JsonProperty("images") 32 | List images; 33 | @JsonProperty("name") 34 | String name; 35 | @JsonProperty("owner") 36 | Owner owner; 37 | @JsonProperty("primary_color") 38 | Object primaryColor; 39 | @JsonProperty("public") 40 | Boolean _public; 41 | @JsonProperty("snapshot_id") 42 | String snapshotId; 43 | @JsonProperty("tracks") 44 | Tracks tracks; 45 | @JsonProperty("type") 46 | String type; 47 | @JsonProperty("uri") 48 | String uri; 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/pojo/Tracks.java: -------------------------------------------------------------------------------- 1 | 2 | package com.spotify.oauth2.pojo; 3 | 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | import java.util.List; 8 | 9 | @JsonInclude(JsonInclude.Include.NON_NULL) 10 | public class Tracks { 11 | 12 | @JsonProperty("href") 13 | private String href; 14 | @JsonProperty("items") 15 | private List items = null; 16 | @JsonProperty("limit") 17 | private Integer limit; 18 | @JsonProperty("next") 19 | private Object next; 20 | @JsonProperty("offset") 21 | private Integer offset; 22 | @JsonProperty("previous") 23 | private Object previous; 24 | @JsonProperty("total") 25 | private Integer total; 26 | 27 | @JsonProperty("href") 28 | public String getHref() { 29 | return href; 30 | } 31 | 32 | @JsonProperty("href") 33 | public void setHref(String href) { 34 | this.href = href; 35 | } 36 | 37 | @JsonProperty("items") 38 | public List getItems() { 39 | return items; 40 | } 41 | 42 | @JsonProperty("items") 43 | public void setItems(List items) { 44 | this.items = items; 45 | } 46 | 47 | @JsonProperty("limit") 48 | public Integer getLimit() { 49 | return limit; 50 | } 51 | 52 | @JsonProperty("limit") 53 | public void setLimit(Integer limit) { 54 | this.limit = limit; 55 | } 56 | 57 | @JsonProperty("next") 58 | public Object getNext() { 59 | return next; 60 | } 61 | 62 | @JsonProperty("next") 63 | public void setNext(Object next) { 64 | this.next = next; 65 | } 66 | 67 | @JsonProperty("offset") 68 | public Integer getOffset() { 69 | return offset; 70 | } 71 | 72 | @JsonProperty("offset") 73 | public void setOffset(Integer offset) { 74 | this.offset = offset; 75 | } 76 | 77 | @JsonProperty("previous") 78 | public Object getPrevious() { 79 | return previous; 80 | } 81 | 82 | @JsonProperty("previous") 83 | public void setPrevious(Object previous) { 84 | this.previous = previous; 85 | } 86 | 87 | @JsonProperty("total") 88 | public Integer getTotal() { 89 | return total; 90 | } 91 | 92 | @JsonProperty("total") 93 | public void setTotal(Integer total) { 94 | this.total = total; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/tests/BaseTest.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.tests; 2 | 3 | import org.testng.annotations.BeforeMethod; 4 | 5 | import java.lang.reflect.Method; 6 | 7 | public class BaseTest { 8 | 9 | @BeforeMethod 10 | public void beforeMethod(Method m){ 11 | System.out.println("STARTING TEST: " + m.getName()); 12 | System.out.println("THREAD ID: " + Thread.currentThread().getId()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/tests/PlaylistTests.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.tests; 2 | 3 | import com.spotify.oauth2.api.StatusCode; 4 | import com.spotify.oauth2.api.applicationApi.PlaylistApi; 5 | import com.spotify.oauth2.pojo.Error; 6 | import com.spotify.oauth2.pojo.Playlist; 7 | import com.spotify.oauth2.utils.DataLoader; 8 | import io.qameta.allure.*; 9 | import io.restassured.response.Response; 10 | import org.testng.annotations.Test; 11 | 12 | import static com.spotify.oauth2.utils.FakerUtils.generateDescription; 13 | import static com.spotify.oauth2.utils.FakerUtils.generateName; 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.hamcrest.Matchers.equalTo; 16 | 17 | @Epic("Spotify Oauth 2.0") 18 | @Feature("Playlist API") 19 | public class PlaylistTests extends BaseTest { 20 | 21 | @Story("Create a playlist story") 22 | @Link("https://example.org") 23 | @Link(name = "allure", type = "mylink") 24 | @TmsLink("12345") 25 | @Issue("1234567") 26 | @Description("this is the description") 27 | @Test(description = "should be able to create a playlist") 28 | public void ShouldBeAbleToCreateAPlaylist(){ 29 | Playlist requestPlaylist = playlistBuilder(generateName(), generateDescription(), false); 30 | Response response = PlaylistApi.post(requestPlaylist); 31 | assertStatusCode(response.statusCode(), StatusCode.CODE_201); 32 | assertPlaylistEqual(response.as(Playlist.class), requestPlaylist); 33 | } 34 | 35 | @Test 36 | public void ShouldBeAbleToGetAPlaylist(){ 37 | Playlist requestPlaylist = playlistBuilder("Updated Playlist Name", "Updated playlist description", false); 38 | Response response = PlaylistApi.get(DataLoader.getInstance().getGetPlaylistId()); 39 | assertStatusCode(response.statusCode(), StatusCode.CODE_200); 40 | assertPlaylistEqual(response.as(Playlist.class), requestPlaylist); 41 | } 42 | 43 | @Test 44 | public void ShouldBeAbleToUpdateAPlaylist(){ 45 | Playlist requestPlaylist = playlistBuilder(generateName(), generateDescription(), false); 46 | Response response = PlaylistApi.update(DataLoader.getInstance().getUpdatePlaylistId(), requestPlaylist); 47 | assertStatusCode(response.statusCode(), StatusCode.CODE_200); 48 | } 49 | 50 | @Story("Create a playlist story") 51 | @Test 52 | public void ShouldNotBeAbleToCreateAPlaylistWithName(){ 53 | Playlist requestPlaylist = playlistBuilder("", generateDescription(), false); 54 | Response response = PlaylistApi.post(requestPlaylist); 55 | assertStatusCode(response.statusCode(), StatusCode.CODE_400); 56 | assertError(response.as(Error.class), StatusCode.CODE_400); 57 | } 58 | 59 | @Story("Create a playlist story") 60 | @Test 61 | public void ShouldNotBeAbleToCreateAPlaylistWithExpiredToken(){ 62 | String invalid_token = "12345"; 63 | Playlist requestPlaylist = playlistBuilder(generateName(), generateDescription(), false); 64 | Response response = PlaylistApi.post(invalid_token, requestPlaylist); 65 | assertStatusCode(response.statusCode(), StatusCode.CODE_401); 66 | assertError(response.as(Error.class), StatusCode.CODE_401); 67 | } 68 | 69 | @Step 70 | public Playlist playlistBuilder(String name, String description, boolean _public){ 71 | return Playlist.builder(). 72 | name(name). 73 | description(description). 74 | _public(_public). 75 | build(); 76 | } 77 | 78 | @Step 79 | public void assertPlaylistEqual(Playlist responsePlaylist, Playlist requestPlaylist){ 80 | assertThat(responsePlaylist.getName(), equalTo(requestPlaylist.getName())); 81 | assertThat(responsePlaylist.getDescription(), equalTo(requestPlaylist.getDescription())); 82 | assertThat(responsePlaylist.get_public(), equalTo(requestPlaylist.get_public())); 83 | } 84 | 85 | @Step 86 | public void assertStatusCode(int actualStatusCode, StatusCode statusCode){ 87 | assertThat(actualStatusCode, equalTo(statusCode.code)); 88 | } 89 | 90 | @Step 91 | public void assertError(Error responseErr, StatusCode statusCode){ 92 | assertThat(responseErr.getError().getStatus(), equalTo(statusCode.code)); 93 | assertThat(responseErr.getError().getMessage(), equalTo(statusCode.msg)); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/utils/ConfigLoader.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.utils; 2 | 3 | import java.util.Properties; 4 | 5 | public class ConfigLoader { 6 | private final Properties properties; 7 | private static ConfigLoader configLoader; 8 | 9 | private ConfigLoader(){ 10 | properties = PropertyUtils.propertyLoader("src/test/resources/config.properties"); 11 | } 12 | 13 | public static ConfigLoader getInstance(){ 14 | if(configLoader == null){ 15 | configLoader = new ConfigLoader(); 16 | } 17 | return configLoader; 18 | } 19 | 20 | public String getClientId(){ 21 | String prop = properties.getProperty("client_id"); 22 | if(prop != null) return prop; 23 | else throw new RuntimeException("property client_id is not specified in the config.properties file"); 24 | } 25 | 26 | public String getClientSecret(){ 27 | String prop = properties.getProperty("client_secret"); 28 | if(prop != null) return prop; 29 | else throw new RuntimeException("property client_secret is not specified in the config.properties file"); 30 | } 31 | 32 | public String getGrantType(){ 33 | String prop = properties.getProperty("grant_type"); 34 | if(prop != null) return prop; 35 | else throw new RuntimeException("property grant_type is not specified in the config.properties file"); 36 | } 37 | 38 | public String getRefreshToken(){ 39 | String prop = properties.getProperty("refresh_token"); 40 | if(prop != null) return prop; 41 | else throw new RuntimeException("property refresh_token is not specified in the config.properties file"); 42 | } 43 | 44 | public String getUser(){ 45 | String prop = properties.getProperty("user_id"); 46 | if(prop != null) return prop; 47 | else throw new RuntimeException("property user_id is not specified in the config.properties file"); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/utils/DataLoader.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.utils; 2 | 3 | import java.util.Properties; 4 | 5 | public class DataLoader { 6 | private final Properties properties; 7 | private static DataLoader dataLoader; 8 | 9 | private DataLoader(){ 10 | properties = PropertyUtils.propertyLoader("src/test/resources/data.properties"); 11 | } 12 | 13 | public static DataLoader getInstance(){ 14 | if(dataLoader == null){ 15 | dataLoader = new DataLoader(); 16 | } 17 | return dataLoader; 18 | } 19 | 20 | public String getGetPlaylistId(){ 21 | String prop = properties.getProperty("get_playlist_id"); 22 | if(prop != null) return prop; 23 | else throw new RuntimeException("property get_playlist_id is not specified in the data.properties file"); 24 | } 25 | 26 | public String getUpdatePlaylistId(){ 27 | String prop = properties.getProperty("update_playlist_id"); 28 | if(prop != null) return prop; 29 | else throw new RuntimeException("property update_playlist_id is not specified in the data.properties file"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/utils/DummyClass.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.utils; 2 | 3 | public class DummyClass { 4 | 5 | public void dummy(){ 6 | System.out.println("dummy"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/utils/FakerUtils.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.utils; 2 | 3 | import com.github.javafaker.Faker; 4 | 5 | public class FakerUtils { 6 | 7 | public static String generateName(){ 8 | Faker faker = new Faker(); 9 | return "Playlist " + faker.regexify("[A-Za-z0-9 ,_-]{10}"); 10 | } 11 | 12 | public static String generateDescription(){ 13 | Faker faker = new Faker(); 14 | return "Description " + faker.regexify("[ A-Za-z0-9_@./#&+-]{50}"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/spotify/oauth2/utils/PropertyUtils.java: -------------------------------------------------------------------------------- 1 | package com.spotify.oauth2.utils; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | import java.util.Properties; 8 | 9 | public class PropertyUtils { 10 | 11 | public static Properties propertyLoader(String filePath) { 12 | Properties properties = new Properties(); 13 | BufferedReader reader; 14 | try { 15 | reader = new BufferedReader(new FileReader(filePath)); 16 | try { 17 | properties.load(reader); 18 | reader.close(); 19 | } catch (IOException e) { 20 | e.printStackTrace(); 21 | throw new RuntimeException("failed to load properties file "+ filePath); 22 | } 23 | } catch (FileNotFoundException e) { 24 | e.printStackTrace(); 25 | throw new RuntimeException("properties file not found at " + filePath); 26 | } 27 | return properties; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/resources/allure.properties: -------------------------------------------------------------------------------- 1 | allure.results.directory=target/allure-results 2 | allure.link.mylink.pattern=https://example.org/mylink/{} 3 | allure.link.issue.pattern=https://example.org/issue/{} 4 | allure.link.tms.pattern=https://example.org/tms/{} -------------------------------------------------------------------------------- /src/test/resources/config.properties: -------------------------------------------------------------------------------- 1 | client_id=enter_client_id_of_your_spotify_app 2 | client_secret=enter_client_secret_of_your_spotify_app 3 | refresh_token=enter_your_refresh_token_here 4 | grant_type=refresh_token 5 | user_id=enter_your_spotify_user_id -------------------------------------------------------------------------------- /src/test/resources/data.properties: -------------------------------------------------------------------------------- 1 | get_playlist_id=4rad8gpZSq3Z2AXfQu1bfD 2 | update_playlist_id=1hEmM1yp51k4UR0jWqdkIV --------------------------------------------------------------------------------