Compare commits

...

No commits in common. "main" and "api-master" have entirely different histories.

19 changed files with 609 additions and 1 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
# Project exclude paths
/target/
/.idea/
*.iml

View File

@ -1 +0,0 @@
Примеры выполнения заданий

4
helpdesk-api-test-main/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
# Project exclude paths
/target/
/.idea/
*.iml

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>helpdesk-api-test</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.6</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,5 @@
package model;
public class AuthToken {
// todo: serialized поля, согласно swagger, а также геттеры и сеттеры
}

View File

@ -0,0 +1,18 @@
package model;
/** Статусы тикета, используемые в тестах */
public enum Status {
OPEN(1),
CLOSED(4),
;
private final int code;
Status(int code) {
this.code=code;
}
public int getCode() {
return code;
}
}

View File

@ -0,0 +1,19 @@
package model;
/** Объект тикета (POJO) */
public class Ticket {
// todo: serialized поля, геттеры и сеттеры
@Override
public boolean equals(Object o) {
// todo
return false;
}
@Override
public int hashCode() {
// todo
return 0;
}
}

View File

@ -0,0 +1,40 @@
package api;
import model.AuthToken;
import model.Status;
import model.Ticket;
import org.testng.annotations.BeforeClass;
import java.io.IOException;
import static io.restassured.RestAssured.given;
/** Абстрактный класс, содержащий общие для всех тестов методы */
public abstract class BaseTest {
@BeforeClass
public void prepare() {
// todo: загрузить в системные переменные "base.uri" из "config.properties"
String baseUri = System.getProperty("base.uri");
if (baseUri == null || baseUri.isEmpty()) {
throw new RuntimeException("В файле \"config.properties\" отсутствует значение \"base.uri\"");
}
// todo: подготовить глобальные преднастройки для запросов
}
protected AuthToken login() {
// todo: отправить запрос на получения токена, используя учетные данные из "config.properties"
return null;
}
protected Ticket buildNewTicket(Status status, int priority) {
// todo: создать объект с тестовыми данными
return null;
}
protected Ticket createTicket(Ticket ticket) {
// todo: отправить HTTP запрос для создания тикета
return null;
}
}

View File

@ -0,0 +1,18 @@
package api;
import model.Ticket;
import org.testng.annotations.Test;
/** Создание и проверка тикета */
public class CreateTicketTest extends BaseTest {
@Test
public void createTicketTest() {
// todo: создать тикет и проверить, что он находится в системе
}
protected Ticket getTicket(int id) {
// todo: отправить HTTP запрос на получение тикета по его id
return null;
}
}

View File

@ -0,0 +1,17 @@
package api;
import model.Ticket;
import org.testng.annotations.Test;
/** Обновление тикета */
public class UpdateTicketTest extends BaseTest {
@Test
public void updateTicketTest() {
// todo: создать тикет со статусом Closed, затем обновить тикет и проверить сообщение об ошибке (негативный сценарий)
}
private void updateTicketNegative(Ticket ticket) {
// todo: отправить HTTP запрос для обновления данных тикета и сразу же проверить статус код (должен соответствовать ошибке)
}
}

View File

@ -0,0 +1,2 @@
# Параметры конфигурации в формате:
# key=value

47
pom.xml Normal file
View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>helpdesk-api-test</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.22</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.6</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,23 @@
package model;
import com.google.gson.annotations.SerializedName;
public class AuthToken {
@SerializedName("username")
private String username;
@SerializedName("password")
private String password;
@SerializedName("token")
private String token;
public void setUsername(String username) { this.username = username; }
public String getUsername() { return username; }
public void setPassword(String password) { this.password = password; }
public String getPassword() { return password; }
public void setToken(String token) { this.token = token; }
public String getToken() { return token; }
}

View File

@ -0,0 +1,18 @@
package model;
/** Статусы тикета, используемые в тестах */
public enum Status {
OPEN(1),
CLOSED(4),
;
private final int code;
Status(int code) {
this.code=code;
}
public int getCode() {
return code;
}
}

View File

@ -0,0 +1,146 @@
package model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.gson.annotations.SerializedName;
import java.util.Objects;
/** Объект тикета (POJO) */
public class Ticket {
@SerializedName("id")
private Integer id;
@JsonIgnore
@SerializedName("due_date")
private String due_date;
@SerializedName("assigned_to")
private String assigned_to;
@SerializedName("title")
private String title;
@JsonIgnore
@SerializedName("created")
private String created;
@JsonIgnore
@SerializedName("modified")
private String modified;
@SerializedName("submitter_email")
private String submitter_email;
@SerializedName("status")
private Integer status;
@SerializedName("on_hold")
private Boolean on_hold;
@SerializedName("description")
private String description;
@SerializedName("resolution")
private String resolution;
@SerializedName("priority")
private Integer priority;
@SerializedName("last_escalation")
private String last_escalation;
@SerializedName("secret_key")
private String secret_key;
@SerializedName("queue")
private Integer queue;
@SerializedName("kbitem")
private Integer kbitem;
@SerializedName("merged_to")
private Integer merged_to;
public void setId(Integer id) { this.id = id; }
public Integer getId() { return id; }
public void setDue_date(String due_date) { this.due_date = due_date; }
public String getDue_date() { return due_date; }
public void setAssigned_to(String assigned_to) { this.assigned_to = assigned_to; }
public String getAssigned_to() { return assigned_to; }
public void setTitle(String title) { this.title = title; }
public String getTitle() { return title; }
public void setCreated(String created) { this.created = created; }
public String getCreated() { return created; }
public void setModified(String modified) { this.modified = modified; }
public String getModified() { return modified; }
public void setSubmitter_email(String submitter_email) { this.submitter_email = submitter_email; }
public String getSubmitter_email() { return submitter_email; }
public void setStatus(Integer status) { this.status = status; }
public Integer getStatus() { return status; }
public void setOn_hold(boolean on_hold) { this.on_hold = on_hold; }
public boolean isOn_hold() { return on_hold; }
public void setDescription(String description) { this.description = description; }
public String getDescription() { return description; }
public void setResolution(String resolution) { this.resolution = resolution; }
public String getResolution() { return resolution; }
public void setPriority(Integer priority) { this.priority = priority; }
public Integer getPriority() { return priority; }
public void setLast_escalation(String last_escalation) { this.last_escalation = last_escalation; }
public String getLast_escalation() { return last_escalation; }
public void setSecret_key(String secret_key) { this.secret_key = secret_key; }
public String getSecret_key() { return secret_key; }
public void setQueue(Integer queue) { this.queue = queue; }
public Integer getQueue() { return queue; }
public void setKbitem(Integer kbitem) { this.kbitem = kbitem; }
public Integer getKbitem() { return kbitem; }
public void setMerged_to(Integer merged_to) { this.merged_to = merged_to; }
public Integer getMerged_to() { return merged_to; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (getClass() != o.getClass()) return false;
Ticket other = (Ticket) o;
return Objects.equals(due_date, other.due_date) &&
Objects.equals(assigned_to, other.assigned_to) &&
Objects.equals(title, other.title) &&
Objects.equals(submitter_email, other.submitter_email) &&
Objects.equals(status, other.status) &&
Objects.equals(on_hold, other.on_hold) &&
Objects.equals(description, other.description) &&
Objects.equals(resolution, other.resolution) &&
Objects.equals(priority, other.priority) &&
Objects.equals(last_escalation, other.last_escalation) &&
Objects.equals(secret_key, other.secret_key) &&
Objects.equals(queue, other.queue) &&
Objects.equals(kbitem, other.kbitem) &&
Objects.equals(merged_to, other.merged_to);
}
@Override
public int hashCode() {
return Objects.hash(due_date, assigned_to, title,
submitter_email, status, on_hold, description, resolution,
priority, last_escalation, secret_key, queue, kbitem, merged_to);
}
}

View File

@ -0,0 +1,114 @@
package api;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.filter.log.LogDetail;
import io.restassured.filter.log.ResponseLoggingFilter;
import io.restassured.http.ContentType;
import model.AuthToken;
import model.Status;
import model.Ticket;
import org.testng.annotations.BeforeClass;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Random;
import java.util.UUID;
import static io.restassured.RestAssured.given;
/** Абстрактный класс, содержащий общие для всех тестов методы */
public abstract class BaseTest {
@BeforeClass
public void prepare() throws IOException{
System.getProperties().load(ClassLoader.getSystemResourceAsStream("config.properties"));
String baseUri = System.getProperty("base.uri");
if (baseUri == null || baseUri.isEmpty()) {
throw new RuntimeException("В файле \"config.properties\" отсутствует значение \"base.uri\"");
}
RestAssured.requestSpecification = new RequestSpecBuilder()
.setBaseUri(baseUri)
.setAccept(ContentType.JSON)
.setContentType(ContentType.JSON)
.log(LogDetail.ALL)
.build();
RestAssured.filters(new ResponseLoggingFilter());
}
protected AuthToken login() {
String username = System.getProperty("username");
if (username == null || username.isEmpty()) {
throw new RuntimeException("В файле \"config.properties\" отсутствует значение \"username\"");
}
String password = System.getProperty("password");
if (password == null || password.isEmpty()) {
throw new RuntimeException("В файле \"config.properties\" отсутствует значение \"password\"");
}
AuthToken auth = new AuthToken();
auth.setUsername(username);
auth.setPassword(password);
AuthToken actual =
given()
.body(auth)
.when()
.post("/api/login")
.then()
.statusCode(200)
.extract().as(AuthToken.class);
auth.setToken(actual.getToken());
return auth;
}
protected Ticket buildNewTicket(Status status, int priority) {
LocalDateTime now = LocalDateTime.now();
Random random = new Random();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
Ticket ticket = new Ticket();
String title = "Проверка rest-assured " + UUID.randomUUID();
String secret_key = UUID.randomUUID().toString();
boolean on_hold = random.nextBoolean();
String due_date = now.format(formatter);
int queue = 1;
//ticket.setDue_date(due_date);
ticket.setAssigned_to("admin");
ticket.setTitle(title);
ticket.setStatus(status.getCode());
ticket.setPriority(priority);
ticket.setSecret_key(secret_key);
ticket.setOn_hold(on_hold);
ticket.setQueue(queue);
return ticket;
}
protected Ticket createTicket(Ticket ticket) {
AuthToken authToken = login();
String token = authToken.getToken();
Ticket actual =
given()
.header("Authorization", "Token " + token)
.body(ticket)
.when()
.post("/api/tickets")
.then()
.statusCode(201)
.extract().as(Ticket.class);
return actual;
}
}

View File

@ -0,0 +1,53 @@
package api;
import model.AuthToken;
import model.Status;
import model.Ticket;
import org.testng.Assert;
import org.testng.annotations.Test;
import static io.restassured.RestAssured.given;
/** Создание и проверка тикета */
public class CreateTicketTest extends BaseTest {
// @Test
// public void loginTest() {
// AuthToken token = login();
// }
//
// @Test
// public void ticketTest() {
// Ticket ticket = buildNewTicket(Status.OPEN, 3);
// }
@Test
public void createTicketTest() {
Ticket ticket1 = createTicket(buildNewTicket(Status.OPEN, 3));
int id = ticket1.getId();
Ticket ticket2 = getTicket(id);
Assert.assertEquals(ticket1, ticket2);
}
protected Ticket getTicket(int id) {
AuthToken authToken = login();
String token = authToken.getToken();
Ticket actual =
given()
.header("Authorization", "Token " + token)
.pathParam("ticketId", id)
.when()
.get("api/tickets/{ticketId}")
.then()
.statusCode(200)
.extract().as(Ticket.class);
return actual;
}
// @Test
// public void getTicketTest(){
// getTicket(1);
// }
}

View File

@ -0,0 +1,34 @@
package api;
import model.AuthToken;
import model.Status;
import model.Ticket;
import org.testng.annotations.Test;
import static io.restassured.RestAssured.given;
/** Обновление тикета */
public class UpdateTicketTest extends BaseTest {
@Test
public void updateTicketTest() {
Ticket ticket = buildNewTicket(Status.CLOSED, 1);
Ticket posted = createTicket(ticket);
updateTicketNegative(posted);
}
private void updateTicketNegative(Ticket ticket) {
AuthToken authToken = login();
given()
.header("Authorization", "Token " + authToken.getToken())
.pathParam("ticketId", ticket.getId())
.body(ticket)
.when()
.put("/api/tickets/{ticketId}")
.then()
.statusCode(422);
}
}

View File

@ -0,0 +1,5 @@
base.uri=https://at-sandbox.workbench.lanit.ru/
token=ad9e96f7199e808dffc307832da5c3ee0a7351a2
username=admin
password=adminat