Skip to content

Commit b42105a

Browse files
Merge pull request #383 from testsigmahq/feat/CUS-12189--Addon-to-create-or-update-rows-and-columns-in-Testsigma-Test-Data-Profile-dynamically
feat/CUS-12189-Addon to create or update rows and columns in Testsigma Test Data Profile dynamically
2 parents 3500768 + 0a20bd1 commit b42105a

3 files changed

Lines changed: 308 additions & 0 deletions

File tree

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project
3+
xmlns="http://maven.apache.org/POM/4.0.0"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
6+
<modelVersion>4.0.0</modelVersion>
7+
<groupId>com.testsigma.addons</groupId>
8+
<artifactId>tdp_row_and_column_creator_updater_</artifactId>
9+
<version>1.0.0</version>
10+
<packaging>jar</packaging>
11+
12+
<properties>
13+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14+
<maven.compiler.source>11</maven.compiler.source>
15+
<maven.compiler.target>11</maven.compiler.target>
16+
<testsigma.sdk.version>1.2.26_cloud</testsigma.sdk.version>
17+
<junit.jupiter.version>5.12.1</junit.jupiter.version>
18+
<testsigma.addon.maven.plugin>1.0.0</testsigma.addon.maven.plugin>
19+
<maven.source.plugin.version>3.2.1</maven.source.plugin.version>
20+
<lombok.version>1.18.30</lombok.version>
21+
<testng.version>7.10.2</testng.version>
22+
<selenium.version>4.33.0</selenium.version>
23+
<appium.java.client.version>9.4.0</appium.java.client.version>
24+
<jackson.version>2.13.0</jackson.version>
25+
<maven.shade.plugin.version>3.2.4</maven.shade.plugin.version>
26+
27+
</properties>
28+
29+
<dependencies>
30+
<dependency>
31+
<groupId>com.testsigma</groupId>
32+
<artifactId>testsigma-java-sdk</artifactId>
33+
<version>${testsigma.sdk.version}</version>
34+
</dependency>
35+
<dependency>
36+
<groupId>org.projectlombok</groupId>
37+
<artifactId>lombok</artifactId>
38+
<version>${lombok.version}</version>
39+
<optional>true</optional>
40+
</dependency>
41+
<dependency>
42+
<groupId>org.junit.jupiter</groupId>
43+
<artifactId>junit-jupiter-api</artifactId>
44+
<version>${junit.jupiter.version}</version>
45+
<scope>test</scope>
46+
</dependency>
47+
<dependency>
48+
<groupId>org.testng</groupId>
49+
<artifactId>testng</artifactId>
50+
<version>${testng.version}</version>
51+
</dependency>
52+
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
53+
<dependency>
54+
<groupId>org.seleniumhq.selenium</groupId>
55+
<artifactId>selenium-java</artifactId>
56+
<version>${selenium.version}</version>
57+
</dependency>
58+
<!-- https://mvnrepository.com/artifact/io.appium/java-client -->
59+
<dependency>
60+
<groupId>io.appium</groupId>
61+
<artifactId>java-client</artifactId>
62+
<version>${appium.java.client.version}</version>
63+
</dependency>
64+
<dependency>
65+
<groupId>com.fasterxml.jackson.core</groupId>
66+
<artifactId>jackson-annotations</artifactId>
67+
<version>${jackson.version}</version>
68+
</dependency>
69+
<dependency>
70+
<groupId>io.rest-assured</groupId>
71+
<artifactId>rest-assured</artifactId>
72+
<version>5.3.0</version>
73+
</dependency>
74+
<dependency>
75+
<groupId>org.apache.commons</groupId>
76+
<artifactId>commons-lang3</artifactId>
77+
<version>3.19.0</version>
78+
</dependency>
79+
<dependency>
80+
<groupId>com.fasterxml.jackson.core</groupId>
81+
<artifactId>jackson-databind</artifactId>
82+
<version>2.13.0</version>
83+
</dependency>
84+
85+
</dependencies>
86+
<build>
87+
<finalName>tdp_row_and_column_creator_updater_</finalName>
88+
<plugins>
89+
<plugin>
90+
<groupId>org.apache.maven.plugins</groupId>
91+
<artifactId>maven-shade-plugin</artifactId>
92+
<version>${maven.shade.plugin.version}</version>
93+
<executions>
94+
<execution>
95+
<phase>package</phase>
96+
<goals>
97+
<goal>shade</goal>
98+
</goals>
99+
</execution>
100+
</executions>
101+
</plugin>
102+
<plugin>
103+
<groupId>org.apache.maven.plugins</groupId>
104+
<artifactId>maven-source-plugin</artifactId>
105+
<version>${maven.source.plugin.version}</version>
106+
<executions>
107+
<execution>
108+
<id>attach-sources</id>
109+
<goals>
110+
<goal>jar</goal>
111+
</goals>
112+
</execution>
113+
</executions>
114+
</plugin>
115+
</plugins>
116+
</build>
117+
</project>
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
package com.testsigma.addons.web;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.fasterxml.jackson.databind.node.ArrayNode;
6+
import com.fasterxml.jackson.databind.node.ObjectNode;
7+
import com.testsigma.sdk.ApplicationType;
8+
import com.testsigma.sdk.Result;
9+
import com.testsigma.sdk.WebAction;
10+
import com.testsigma.sdk.annotation.Action;
11+
import com.testsigma.sdk.annotation.TestData;
12+
import io.restassured.RestAssured;
13+
import io.restassured.response.Response;
14+
import lombok.Data;
15+
import lombok.EqualsAndHashCode;
16+
import org.apache.commons.lang3.exception.ExceptionUtils;
17+
18+
import java.util.ArrayList;
19+
import java.util.Iterator;
20+
import java.util.List;
21+
import java.util.NoSuchElementException;
22+
23+
@Data
24+
@EqualsAndHashCode(callSuper = false)
25+
@Action(
26+
actionText = "Create or update row row-name in test data profile test-data-id with columns-data (Eg:{\"Column1\": \"value1\", \"Column2\": \"value2\"} using api key api-key",
27+
description = "Creates or updates a row in a Testsigma Test Data Profile using a JSON object of column-value pairs. New columns are also created automatically if they do not already exist in the profile.",
28+
applicationType = ApplicationType.WEB
29+
)
30+
public class TdpRowColumnCreatorUpdaterAction extends WebAction {
31+
32+
private static final String TESTSIGMA_API_BASE_URL = "https://app.testsigma.com/api/v1/test_data/";
33+
34+
@TestData(reference = "test-data-id")
35+
private com.testsigma.sdk.TestData testDataId;
36+
37+
@TestData(reference = "row-name")
38+
private com.testsigma.sdk.TestData rowName;
39+
40+
// JSON string: {"Column1": "value1", "Column2": "value2"}
41+
@TestData(reference = "columns-data")
42+
private com.testsigma.sdk.TestData columnsData;
43+
44+
@TestData(reference = "api-key")
45+
private com.testsigma.sdk.TestData apiKey;
46+
47+
@Override
48+
public Result execute() throws NoSuchElementException {
49+
try {
50+
String tdpId = testDataId.getValue().toString().trim();
51+
String row = rowName.getValue().toString().trim();
52+
String rawJson = columnsData.getValue().toString().trim();
53+
String token = apiKey.getValue().toString().trim();
54+
String apiUrl = TESTSIGMA_API_BASE_URL + tdpId;
55+
56+
logger.info("===== INPUT =====");
57+
logger.info("TDP ID: " + tdpId);
58+
logger.info("Row: " + row);
59+
logger.info("Columns Data: " + rawJson);
60+
61+
ObjectMapper mapper = new ObjectMapper();
62+
JsonNode inputData = mapper.readTree(rawJson);
63+
if (!inputData.isObject()) {
64+
setErrorMessage("columns-data must be a JSON object, e.g. {\"Column1\": \"value1\"}");
65+
return Result.FAILED;
66+
}
67+
68+
// ===== GET =====
69+
logger.info("\n===== GET REQUEST =====");
70+
Response getResponse = RestAssured.given()
71+
.baseUri(apiUrl)
72+
.header("Authorization", "Bearer " + token)
73+
.header("Accept", "application/json")
74+
.header("Content-Type", "application/json;charset=UTF-8")
75+
.get();
76+
77+
logger.info("GET Status: " + getResponse.getStatusCode());
78+
logger.info("GET Body: " + getResponse.getBody().asString());
79+
80+
if (getResponse.getStatusCode() != 200) {
81+
setErrorMessage("GET failed: " + getResponse.getBody().asString());
82+
return Result.FAILED;
83+
}
84+
85+
JsonNode root = mapper.readTree(getResponse.getBody().asString());
86+
String testDataName = root.path("testDataName").asText();
87+
88+
// ===== Columns: merge existing + any new from input =====
89+
ArrayNode existingColumns = (ArrayNode) root.path("columns");
90+
List<String> columnsList = new ArrayList<>();
91+
for (JsonNode col : existingColumns) {
92+
columnsList.add(col.asText());
93+
}
94+
for (Iterator<String> it = inputData.fieldNames(); it.hasNext(); ) {
95+
String colName = it.next();
96+
if (!columnsList.contains(colName)) {
97+
logger.info("Adding new column: " + colName);
98+
columnsList.add(colName);
99+
}
100+
}
101+
102+
// ===== Rows =====
103+
ArrayNode existingData = (ArrayNode) root.path("data");
104+
ArrayNode updatedData = mapper.createArrayNode();
105+
boolean rowFound = false;
106+
107+
for (JsonNode rowNode : existingData) {
108+
ObjectNode updatedRow = mapper.createObjectNode();
109+
if (rowNode.has("id")) {
110+
updatedRow.put("id", rowNode.get("id").asLong());
111+
}
112+
113+
String currentRowName = rowNode.get("name").asText();
114+
updatedRow.put("name", currentRowName);
115+
116+
ObjectNode rowData = mapper.createObjectNode();
117+
rowNode.get("data").fields().forEachRemaining(e ->
118+
rowData.put(e.getKey(), e.getValue().asText())
119+
);
120+
121+
if (currentRowName.equals(row)) {
122+
logger.info("Updating existing row: " + row);
123+
inputData.fields().forEachRemaining(e -> rowData.put(e.getKey(), e.getValue().asText()));
124+
rowFound = true;
125+
} else {
126+
// fill any newly added columns with empty string for other rows
127+
inputData.fieldNames().forEachRemaining(colName -> {
128+
if (!rowData.has(colName)) rowData.put(colName, "");
129+
});
130+
}
131+
132+
updatedRow.set("data", rowData);
133+
updatedData.add(updatedRow);
134+
}
135+
136+
if (!rowFound) {
137+
logger.info("Row not found, creating new row: " + row);
138+
ObjectNode newRow = mapper.createObjectNode();
139+
newRow.put("name", row);
140+
ObjectNode newRowData = mapper.createObjectNode();
141+
for (String col : columnsList) {
142+
JsonNode inputVal = inputData.get(col);
143+
newRowData.put(col, inputVal != null ? inputVal.asText() : "");
144+
}
145+
newRow.set("data", newRowData);
146+
updatedData.add(newRow);
147+
}
148+
149+
// ===== Payload =====
150+
ObjectNode payload = mapper.createObjectNode();
151+
payload.put("testDataName", testDataName);
152+
payload.set("data", updatedData);
153+
ArrayNode columnsArray = mapper.createArrayNode();
154+
columnsList.forEach(columnsArray::add);
155+
payload.set("columns", columnsArray);
156+
157+
String payloadJson = mapper.writeValueAsString(payload);
158+
logger.info("\n===== PUT PAYLOAD =====");
159+
logger.info(payloadJson);
160+
161+
// ===== PUT =====
162+
logger.info("\n===== PUT REQUEST =====");
163+
Response putResponse = RestAssured.given()
164+
.baseUri(apiUrl)
165+
.header("Authorization", "Bearer " + token)
166+
.header("Accept", "application/json")
167+
.header("Content-Type", "application/json;charset=UTF-8")
168+
.body(payloadJson)
169+
.put();
170+
171+
logger.info("PUT Status: " + putResponse.getStatusCode());
172+
logger.info("PUT Body: " + putResponse.getBody().asString());
173+
174+
if (putResponse.getStatusCode() != 200) {
175+
setErrorMessage("PUT failed: " + putResponse.getBody().asString());
176+
return Result.FAILED;
177+
}
178+
179+
String successMsg = "SUCCESS: Updated row '" + row + "' with " + rawJson;
180+
logger.info(successMsg);
181+
setSuccessMessage(successMsg);
182+
return Result.SUCCESS;
183+
184+
} catch (Exception e) {
185+
logger.warn("Exception Occurred: " + ExceptionUtils.getMessage(e));
186+
setErrorMessage("Exception: " + ExceptionUtils.getMessage(e));
187+
return Result.FAILED;
188+
}
189+
}
190+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
testsigma-sdk.api.key=eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIyMjMyMmM2Ni04NWYzLWIyN2UtN2FiOS0zM2U2M2Q4OWM1MGIiLCJ1bmlxdWVJZCI6IjYxNTYiLCJpZGVudGl0eUFjY291bnRVVUlkIjoiMzUifQ.FFAcZyEz9MFpRrAc_0CFFypDQJ-p1pTZ-dSwdvn2n8YwfNDCfj7peH2UpVBUCfHQwmqFVilLYA1Pi60YMGpUtQ

0 commit comments

Comments
 (0)