add unified test scripts for all services

This commit is contained in:
2025-12-05 11:41:36 +01:00
parent 2fe315b7df
commit 1f949579b3
6 changed files with 1526 additions and 3 deletions

6
.gitignore vendored
View File

@ -69,6 +69,12 @@ Desktop.ini
logs/ logs/
*.log *.log
# SQLite Database
*.db
*.db-journal
*.sqlite
*.sqlite3
# Python # Python
__pycache__/ __pycache__/
*.py[cod] *.py[cod]

553
apidoc.md Normal file
View File

@ -0,0 +1,553 @@
# API Documentation
## Overview
This project provides JAX-WS SOAP web services for a loan approval system. The system includes customer registration, loan application processing with credit score evaluation, and a simple Hello World demonstration service.
**Version:** 1.0
**Base URL:** `http://localhost:8080/jaxws-hello-world`
**Protocol:** SOAP 1.1 / HTTP
**Data Format:** XML
## Table of Contents
- [Services Overview](#services-overview)
- [Hello World Service](#hello-world-service)
- [Loan Approval Service](#loan-approval-service)
- [Data Models](#data-models)
- [Database Schema](#database-schema)
- [Error Handling](#error-handling)
- [Testing](#testing)
---
## Services Overview
| Service Name | Endpoint | WSDL | Description |
|-------------|----------|------|-------------|
| HelloWorldService | `/hello` | [WSDL](http://localhost:8080/jaxws-hello-world/hello?wsdl) | Simple demonstration service |
| LoanApprovalService | `/loan` | [WSDL](http://localhost:8080/jaxws-hello-world/loan?wsdl) | Customer registration and loan processing |
---
## Hello World Service
### Service Information
- **Endpoint:** `http://localhost:8080/jaxws-hello-world/hello`
- **WSDL:** `http://localhost:8080/jaxws-hello-world/hello?wsdl`
- **Namespace:** `http://service.example.com/`
### Methods
#### getHelloWorld
Returns a personalized greeting message.
**Operation:** `getHelloWorld`
**Input Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| name | string | Yes | Name to include in greeting |
**Returns:** `string` - Greeting message in format "Hello World, {name}!"
**SOAP Request Example:**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:getHelloWorld>
<arg0>John</arg0>
</ser:getHelloWorld>
</soapenv:Body>
</soapenv:Envelope>
```
**SOAP Response Example:**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:getHelloWorldResponse xmlns:ns2="http://service.example.com/">
<return>Hello World, John!</return>
</ns2:getHelloWorldResponse>
</S:Body>
</S:Envelope>
```
---
## Loan Approval Service
### Service Information
- **Endpoint:** `http://localhost:8080/jaxws-hello-world/loan`
- **WSDL:** `http://localhost:8080/jaxws-hello-world/loan?wsdl`
- **Namespace:** `http://service.example.com/`
- **Database:** SQLite (`loan_app.db`)
### Methods
#### 1. registerNewCustomer
Registers a new customer in the system with optional blacklist status.
**Operation:** `registerNewCustomer`
**Input Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| request | CustomerRegistrationRequest | Yes | Customer registration details |
| └─ customerName | string | Yes | Customer's full name |
| └─ blacklisted | boolean | No | Blacklist status (default: false) |
**Returns:** `string` - Registration status message
**Possible Return Values:**
- `"Registration Successful"` - Customer registered successfully
- `"Error: Customer already exists"` - Customer name already in database
**SOAP Request Example:**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:registerNewCustomer>
<arg0>
<customerName>John Doe</customerName>
<blacklisted>false</blacklisted>
</arg0>
</ser:registerNewCustomer>
</soapenv:Body>
</soapenv:Envelope>
```
**SOAP Response Example (Success):**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:registerNewCustomerResponse xmlns:ns2="http://service.example.com/">
<return>Registration Successful</return>
</ns2:registerNewCustomerResponse>
</S:Body>
</S:Envelope>
```
**SOAP Response Example (Duplicate):**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:registerNewCustomerResponse xmlns:ns2="http://service.example.com/">
<return>Error: Customer already exists</return>
</ns2:registerNewCustomerResponse>
</S:Body>
</S:Envelope>
```
**Business Rules:**
- Customer names must be unique
- Customer name cannot be null or empty
- Blacklist status is optional (defaults to false)
- Registration time is automatically recorded
#### 2. processLoanApplication
Processes a loan application with credit score-based approval logic.
**Operation:** `processLoanApplication`
**Input Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| request | LoanRequest | Yes | Loan application details |
| └─ applicantName | string | Yes | Applicant's full name |
| └─ requestedAmount | int | Yes | Loan amount requested (must be > 0) |
| └─ creditScore | int | No | Credit score (system may use default) |
**Returns:** `LoanResponse` - Loan decision result
**SOAP Request Example:**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:processLoanApplication>
<arg0>
<applicantName>John Doe</applicantName>
<requestedAmount>50000</requestedAmount>
<creditScore>720</creditScore>
</arg0>
</ser:processLoanApplication>
</soapenv:Body>
</soapenv:Envelope>
```
**SOAP Response Example (Approved):**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:processLoanApplicationResponse xmlns:ns2="http://service.example.com/">
<return>
<approved>true</approved>
<approvedRate>3.5</approvedRate>
<rejectionReason></rejectionReason>
<message>Loan approved with excellent rate</message>
</return>
</ns2:processLoanApplicationResponse>
</S:Body>
</S:Envelope>
```
**SOAP Response Example (Rejected - Blacklisted):**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:processLoanApplicationResponse xmlns:ns2="http://service.example.com/">
<return>
<approved>false</approved>
<approvedRate>0.0</approvedRate>
<rejectionReason>Applicant is blacklisted</rejectionReason>
<message>Loan application rejected</message>
</return>
</ns2:processLoanApplicationResponse>
</S:Body>
</S:Envelope>
```
**SOAP Response Example (Rejected - Low Credit):**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:processLoanApplicationResponse xmlns:ns2="http://service.example.com/">
<return>
<approved>false</approved>
<approvedRate>0.0</approvedRate>
<rejectionReason>Credit score too low</rejectionReason>
<message>Loan application rejected</message>
</return>
</ns2:processLoanApplicationResponse>
</S:Body>
</S:Envelope>
```
**Credit Score Approval Logic:**
| Credit Score Range | Approval Status | Interest Rate | Message |
|-------------------|-----------------|---------------|---------|
| >= 700 | Approved | 3.5% | Loan approved with excellent rate |
| 600 - 699 | Approved | 5.5% | Loan approved with standard rate |
| 500 - 599 | Approved | 8.5% | Loan approved with high risk rate |
| < 500 | Rejected | N/A | Credit score too low |
| Blacklisted | Rejected | N/A | Applicant is blacklisted |
**Business Rules:**
- Blacklisted applicants are automatically rejected
- Applicant name cannot be null or empty
- Requested amount must be greater than 0
- Credit score is retrieved from CreditScoreService (default: 700)
- All loan applications are logged to loan_history table
- System records: applicant name, amount, approval status, rate, rejection reason, and timestamp
---
## Data Models
### CustomerRegistrationRequest
Request model for customer registration.
**Fields:**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| customerName | string | Yes | Customer's full name (must be unique) |
| blacklisted | boolean | No | Whether customer is blacklisted (default: false) |
**Java Example:**
```java
CustomerRegistrationRequest request = new CustomerRegistrationRequest();
request.setCustomerName("John Doe");
request.setBlacklisted(false);
```
### LoanRequest
Request model for loan application.
**Fields:**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| applicantName | string | Yes | Applicant's full name |
| requestedAmount | int | Yes | Loan amount in currency units (must be > 0) |
| creditScore | int | No | Credit score (0-850 scale) |
**Java Example:**
```java
LoanRequest request = new LoanRequest();
request.setApplicantName("John Doe");
request.setRequestedAmount(50000);
request.setCreditScore(720);
```
### LoanResponse
Response model for loan application result.
**Fields:**
| Field | Type | Description |
|-------|------|-------------|
| approved | boolean | Whether the loan was approved |
| approvedRate | double | Interest rate if approved (0.0 if rejected) |
| rejectionReason | string | Reason for rejection (null if approved) |
| message | string | Human-readable status message |
**Java Example:**
```java
LoanResponse response = loanService.processLoanApplication(request);
if (response.isApproved()) {
System.out.println("Approved at " + response.getApprovedRate() + "%");
} else {
System.out.println("Rejected: " + response.getRejectionReason());
}
```
---
## Database Schema
The service uses SQLite database (`loan_app.db`) with the following schema:
### customers
Stores registered customer information.
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| customer_name | TEXT | PRIMARY KEY | Customer's unique name |
| is_blacklisted | INTEGER | DEFAULT 0 | Blacklist status (0=false, 1=true) |
| registered_at | TEXT | | Registration timestamp (ISO 8601) |
**Indexes:**
- Primary key on `customer_name`
### loan_history
Stores all loan application records.
| Column | Type | Constraints | Description |
|--------|------|-------------|-------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT | Unique record ID |
| applicant_name | TEXT | | Applicant's name |
| requested_amount | INTEGER | | Loan amount requested |
| approved | INTEGER | | Approval status (0=rejected, 1=approved) |
| approved_rate | REAL | | Interest rate if approved |
| rejection_reason | TEXT | | Reason for rejection (null if approved) |
| processed_at | TEXT | | Processing timestamp (ISO 8601) |
**Indexes:**
- Primary key on `id`
---
## Error Handling
### SOAP Faults
The service returns SOAP faults for validation errors and invalid requests.
**Common SOAP Fault Example:**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault>
<faultcode>S:Server</faultcode>
<faultstring>Customer name cannot be null or empty</faultstring>
</S:Fault>
</S:Body>
</S:Envelope>
```
### Validation Rules
#### registerNewCustomer
- **SOAP Fault:** Customer name is null or empty
- **Response:** "Error: Customer already exists" (not a fault, returned as normal response)
#### processLoanApplication
- **SOAP Fault:** Applicant name is null or empty
- **SOAP Fault:** Requested amount is 0 or negative
- **Normal Response:** Rejection due to blacklist or low credit score
### HTTP Status Codes
| Status Code | Description |
|-------------|-------------|
| 200 OK | Request processed successfully (including business logic rejections) |
| 500 Internal Server Error | SOAP fault or server error |
---
## Testing
### Using Python Test Scripts
The project includes Python test clients for easy testing:
#### Unified Test Script (Recommended)
Test all services with a single comprehensive script:
```bash
cd scripts
python test_all_services.py
```
This script includes:
- Automated test suite with 20+ test cases
- Tests all three service operations
- Interactive mode for manual testing
- Clear pass/fail indicators with summary
#### Individual Service Tests
Test specific services:
```bash
# Test Hello World Service
python test_hello_world.py
# Test Customer Registration
python test_register_customer.py
```
### Using cURL
#### Test Hello World Service
```bash
curl -X POST http://localhost:8080/jaxws-hello-world/hello \
-H "Content-Type: text/xml; charset=utf-8" \
-H "SOAPAction: " \
-d '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:getHelloWorld>
<arg0>Test</arg0>
</ser:getHelloWorld>
</soapenv:Body>
</soapenv:Envelope>'
```
#### Register Customer
```bash
curl -X POST http://localhost:8080/jaxws-hello-world/loan \
-H "Content-Type: text/xml; charset=utf-8" \
-H "SOAPAction: " \
-d '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:registerNewCustomer>
<arg0>
<customerName>John Doe</customerName>
<blacklisted>false</blacklisted>
</arg0>
</ser:registerNewCustomer>
</soapenv:Body>
</soapenv:Envelope>'
```
#### Process Loan Application
```bash
curl -X POST http://localhost:8080/jaxws-hello-world/loan \
-H "Content-Type: text/xml; charset=utf-8" \
-H "SOAPAction: " \
-d '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:processLoanApplication>
<arg0>
<applicantName>John Doe</applicantName>
<requestedAmount>50000</requestedAmount>
<creditScore>720</creditScore>
</arg0>
</ser:processLoanApplication>
</soapenv:Body>
</soapenv:Envelope>'
```
### Using SoapUI
1. Create a new SOAP project
2. Import WSDL:
- HelloWorldService: `http://localhost:8080/jaxws-hello-world/hello?wsdl`
- LoanApprovalService: `http://localhost:8080/jaxws-hello-world/loan?wsdl`
3. SoapUI will automatically generate request templates
4. Fill in the parameters and execute requests
### Checking the Database
After testing, you can inspect the SQLite database:
```bash
# View all customers
sqlite3 loan_app.db "SELECT * FROM customers;"
# View loan history
sqlite3 loan_app.db "SELECT * FROM loan_history;"
# View blacklisted customers
sqlite3 loan_app.db "SELECT * FROM customers WHERE is_blacklisted = 1;"
```
---
## Production Considerations
### Security
- **Authentication:** No authentication is currently implemented (add WS-Security for production)
- **HTTPS:** Use HTTPS in production environments
- **Input Validation:** All inputs are validated for null/empty values
- **SQL Injection:** Using PreparedStatements to prevent SQL injection
### Database
- **Location:** `loan_app.db` in project root (Docker volume mounted)
- **Persistence:** Database persists between container restarts
- **Backup:** Regular backups recommended for production
### Performance
- **Connection Pooling:** Consider adding connection pooling for production
- **Caching:** Credit score service can be cached
- **Monitoring:** Add logging and monitoring for production use
### Configuration
- **Credit Score Service:** Currently returns fixed value (700), integrate with real credit bureau API for production
- **Interest Rates:** Rates are hardcoded, should be configurable
- **Database Path:** Configurable via environment variable for different environments
---
## Support
For issues and feature requests, please refer to the project README.md.
**Project Repository:** See README.md for deployment instructions
**Docker Support:** Fully containerized with Docker Compose
**Test Scripts:** Located in `scripts/` directory

View File

@ -14,6 +14,8 @@ services:
volumes: volumes:
# Optional: Mount logs directory for debugging # Optional: Mount logs directory for debugging
- ./logs:/usr/local/tomcat/logs - ./logs:/usr/local/tomcat/logs
# Mount database file to root folder
- ./loan_app.db:/usr/local/tomcat/loan_app.db
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/jaxws-hello-world/services/hello?wsdl"] test: ["CMD", "curl", "-f", "http://localhost:8080/jaxws-hello-world/services/hello?wsdl"]

View File

@ -1,8 +1,135 @@
# Test Scripts for JAX-WS Hello World Service # Test Scripts for JAX-WS Services
This folder contains test scripts to interact with the JAX-WS Hello World Service. This folder contains test scripts to interact with the JAX-WS services.
## Python Test Script ## Available Test Scripts
- `test_all_services.py` - **Unified test script for all services** (Recommended)
- `test_hello_world.py` - Test the Hello World SOAP service
- `test_register_customer.py` - Test the Customer Registration SOAP service
- `simple_test.py` - Simple automated test script for CI/CD
## Unified Test Script (Recommended)
### test_all_services.py
This is the **recommended** way to test all services. It provides comprehensive testing for all three service operations in a single script.
**Features:**
- Tests all service operations (Hello World, Customer Registration, Loan Processing)
- Automated test suite with 20+ test cases
- Interactive mode for manual testing
- Clear pass/fail indicators with test summary
- Comprehensive error handling and validation testing
**Running the unified test:**
**Windows:**
```cmd
cd scripts
python test_all_services.py
```
**Linux/Mac:**
```bash
cd scripts
python3 test_all_services.py
# OR
chmod +x test_all_services.py
./test_all_services.py
```
**What it tests:**
1. **Hello World Service**
- Normal greetings
- Edge cases (empty names)
2. **Customer Registration Service**
- Regular customer registration
- Blacklisted customer registration
- Duplicate registration handling
- Validation error handling
3. **Loan Application Processing**
- High credit score approvals (3.5% rate)
- Good credit score approvals (5.5% rate)
- Fair credit score approvals (8.5% rate)
- Low credit score rejections
- Blacklisted customer rejections
- Validation error handling (empty names, invalid amounts)
**Interactive Mode:**
After automated tests complete, you can enter interactive mode with these commands:
- `hello <name>` - Test Hello World service
- `register <name>` - Register a regular customer
- `blacklist <name>` - Register a blacklisted customer
- `loan <name> <amount> <credit_score>` - Process loan application
- `quit` - Exit
**Example output:**
```
================================================================================
JAX-WS UNIFIED TEST CLIENT
================================================================================
Testing all services and operations
Checking services availability...
Hello World Service: Service is accessible
Loan Approval Service: Service is accessible
================================================================================
AUTOMATED TEST SUITE
================================================================================
--------------------------------------------------------------------------------
1. Testing Hello World Service
--------------------------------------------------------------------------------
✓ PASS | getHelloWorld('John') - Should return greeting
Hello World, John!
✓ PASS | getHelloWorld('Alice') - Should return greeting
Hello World, Alice!
--------------------------------------------------------------------------------
2. Testing Customer Registration Service
--------------------------------------------------------------------------------
✓ PASS | registerNewCustomer('Alice Johnson', blacklisted=False) - Register regular customer
Registration Successful
✓ PASS | registerNewCustomer('Charlie Brown', blacklisted=True) - Register blacklisted customer
Registration Successful
✓ PASS | registerNewCustomer('Alice Johnson', blacklisted=False) - Duplicate registration (should fail)
Error: Customer already exists
--------------------------------------------------------------------------------
3. Testing Loan Application Processing Service
--------------------------------------------------------------------------------
✓ PASS | processLoanApplication('Alice Johnson', $50000, score=750) - High credit score
approved: True
approvedRate: 3.5
message: Loan approved with excellent rate
✓ PASS | processLoanApplication('Charlie Brown', $40000, score=700) - Blacklisted customer
approved: False
rejectionReason: Applicant is blacklisted
message: Loan application rejected
================================================================================
TEST SUMMARY
================================================================================
Total Tests: 20
Passed: 20
Failed: 0
Success Rate: 100.0%
Would you like to enter interactive mode? (y/n):
```
## Python Test Scripts
### Prerequisites ### Prerequisites
@ -105,6 +232,114 @@ response = client.call_hello_world("Your Name")
print(response) # Output: Hello World, Your Name! print(response) # Output: Hello World, Your Name!
``` ```
## Customer Registration Test Script
### Running the Customer Registration Test
Make sure the JAX-WS service is running (using Docker or traditional setup).
**Windows:**
```cmd
python test_register_customer.py
```
**Linux/Mac:**
```bash
python3 test_register_customer.py
# OR
chmod +x test_register_customer.py
./test_register_customer.py
```
### What the Script Does
The `test_register_customer.py` script:
1. **Checks WSDL availability** - Verifies the LoanApprovalService is running
2. **Tests customer registration** - Registers multiple customers with different scenarios
3. **Tests blacklist functionality** - Registers both regular and blacklisted customers
4. **Tests duplicate registration** - Verifies that duplicate registrations are handled correctly
5. **Interactive mode** - Allows you to register customers interactively
### Example Output
```
======================================================================
Customer Registration Service Test Client
======================================================================
1. Checking WSDL availability...
WSDL is accessible
2. Testing Customer Registration...
Test 1: Regular customer
Customer Name: John Doe
Blacklisted: False
Result: Registration Successful
Test 2: Regular customer
Customer Name: Jane Smith
Blacklisted: False
Result: Registration Successful
Test 3: Blacklisted customer
Customer Name: Bad Actor
Blacklisted: True
Result: Registration Successful
Test 4: Duplicate registration (should fail)
Customer Name: John Doe
Blacklisted: False
Result: Error: Customer already exists
3. Interactive Mode
------------------------------------------------------------------
Commands:
- register <name>: Register a regular customer
- blacklist <name>: Register a blacklisted customer
- quit: Exit
> register Alice Smith
Result: Registration Successful
> blacklist Evil Corp
Result: Registration Successful
> quit
======================================================================
Test completed!
======================================================================
```
### Using the CustomerRegistrationClient Class
You can also use the `CustomerRegistrationClient` class in your own Python scripts:
```python
from test_register_customer import CustomerRegistrationClient
# Create client
client = CustomerRegistrationClient()
# Check if service is available
is_available, message = client.check_wsdl()
print(message)
# Register a regular customer
response = client.register_customer("John Doe", is_blacklisted=False)
print(response) # Output: Registration Successful
# Register a blacklisted customer
response = client.register_customer("Bad Actor", is_blacklisted=True)
print(response) # Output: Registration Successful
# Try to register duplicate
response = client.register_customer("John Doe", is_blacklisted=False)
print(response) # Output: Error: Customer already exists
```
## Troubleshooting ## Troubleshooting
### Service Not Available ### Service Not Available

View File

@ -0,0 +1,477 @@
#!/usr/bin/env python3
"""
Unified test script for all JAX-WS services
Tests HelloWorldService and LoanApprovalService
"""
import requests
import xml.etree.ElementTree as ET
from xml.dom import minidom
import sys
class JAXWSTestClient:
"""Unified client for testing all JAX-WS services"""
def __init__(self, base_url="http://localhost:8080/jaxws-hello-world"):
"""
Initialize the test client
Args:
base_url: The base URL for all services
"""
self.base_url = base_url
self.hello_service_url = f"{base_url}/hello"
self.loan_service_url = f"{base_url}/loan"
self.headers = {
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': ''
}
# ==================== Hello World Service ====================
def test_hello_world(self, name):
"""
Test Hello World service
Args:
name: Name to send to the service
Returns:
Tuple of (success: bool, result: str)
"""
soap_envelope = f"""<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:getHelloWorld>
<arg0>{name}</arg0>
</ser:getHelloWorld>
</soapenv:Body>
</soapenv:Envelope>"""
try:
response = requests.post(
self.hello_service_url,
data=soap_envelope,
headers=self.headers,
timeout=10
)
response.raise_for_status()
root = ET.fromstring(response.text)
namespaces = {
'S': 'http://schemas.xmlsoap.org/soap/envelope/',
'ns2': 'http://service.example.com/'
}
return_elem = root.find('.//ns2:getHelloWorldResponse/return', namespaces)
if return_elem is not None:
return True, return_elem.text
else:
return False, "Could not find return value in response"
except requests.exceptions.RequestException as e:
return False, f"Error: {str(e)}"
# ==================== Customer Registration ====================
def register_customer(self, customer_name, is_blacklisted=False):
"""
Register a new customer
Args:
customer_name: Customer name
is_blacklisted: Blacklist status
Returns:
Tuple of (success: bool, result: str)
"""
blacklisted_value = "true" if is_blacklisted else "false"
soap_envelope = f"""<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:registerNewCustomer>
<arg0>
<customerName>{customer_name}</customerName>
<blacklisted>{blacklisted_value}</blacklisted>
</arg0>
</ser:registerNewCustomer>
</soapenv:Body>
</soapenv:Envelope>"""
try:
response = requests.post(
self.loan_service_url,
data=soap_envelope,
headers=self.headers,
timeout=10
)
response.raise_for_status()
result = self._parse_soap_response(response.text, 'registerNewCustomerResponse')
return True, result
except requests.exceptions.RequestException as e:
return False, f"Error: {str(e)}"
# ==================== Loan Application Processing ====================
def process_loan_application(self, applicant_name, requested_amount, credit_score=700):
"""
Process a loan application
Args:
applicant_name: Applicant name
requested_amount: Loan amount requested
credit_score: Credit score (optional)
Returns:
Tuple of (success: bool, result: dict)
"""
soap_envelope = f"""<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:processLoanApplication>
<arg0>
<applicantName>{applicant_name}</applicantName>
<requestedAmount>{requested_amount}</requestedAmount>
<creditScore>{credit_score}</creditScore>
</arg0>
</ser:processLoanApplication>
</soapenv:Body>
</soapenv:Envelope>"""
try:
response = requests.post(
self.loan_service_url,
data=soap_envelope,
headers=self.headers,
timeout=10
)
response.raise_for_status()
result = self._parse_loan_response(response.text)
return True, result
except requests.exceptions.RequestException as e:
return False, {"error": str(e)}
# ==================== Helper Methods ====================
def _parse_soap_response(self, response_xml, operation_name):
"""Parse simple SOAP response"""
try:
root = ET.fromstring(response_xml)
namespaces = {
'S': 'http://schemas.xmlsoap.org/soap/envelope/',
'ns2': 'http://service.example.com/'
}
return_elem = root.find(f'.//ns2:{operation_name}/return', namespaces)
if return_elem is not None:
return return_elem.text
# Check for SOAP fault
fault_elem = root.find('.//S:Fault', namespaces)
if fault_elem is not None:
fault_string = fault_elem.find('.//faultstring', namespaces)
if fault_string is not None:
return f"SOAP Fault: {fault_string.text}"
return "Could not parse response"
except ET.ParseError as e:
return f"Parse error: {str(e)}"
def _parse_loan_response(self, response_xml):
"""Parse loan application response"""
try:
root = ET.fromstring(response_xml)
namespaces = {
'S': 'http://schemas.xmlsoap.org/soap/envelope/',
'ns2': 'http://service.example.com/'
}
return_elem = root.find('.//ns2:processLoanApplicationResponse/return', namespaces)
if return_elem is not None:
result = {}
for child in return_elem:
tag = child.tag.split('}')[-1] # Remove namespace
result[tag] = child.text
# Convert types
result['approved'] = result.get('approved', 'false').lower() == 'true'
result['approvedRate'] = float(result.get('approvedRate', 0.0))
return result
# Check for SOAP fault
fault_elem = root.find('.//S:Fault', namespaces)
if fault_elem is not None:
fault_string = fault_elem.find('.//faultstring', namespaces)
if fault_string is not None:
return {"error": f"SOAP Fault: {fault_string.text}"}
return {"error": "Could not parse response"}
except ET.ParseError as e:
return {"error": f"Parse error: {str(e)}"}
def check_service(self, service_url):
"""Check if a service is available"""
try:
response = requests.get(f"{service_url}?wsdl", timeout=5)
response.raise_for_status()
return True, "Service is accessible"
except requests.exceptions.RequestException as e:
return False, f"Service not available: {str(e)}"
def print_header(text, char="="):
"""Print a formatted header"""
print()
print(char * 80)
print(text)
print(char * 80)
def print_test_result(test_name, success, result):
"""Print test result"""
status = "✓ PASS" if success else "✗ FAIL"
print(f" {status} | {test_name}")
if isinstance(result, dict):
for key, value in result.items():
print(f" {key}: {value}")
else:
print(f" {result}")
print()
def run_automated_tests(client):
"""Run all automated tests"""
print_header("AUTOMATED TEST SUITE", "=")
total_tests = 0
passed_tests = 0
# ==================== Test 1: Hello World Service ====================
print_header("1. Testing Hello World Service", "-")
test_cases = [
("John", "Should return greeting"),
("Alice", "Should return greeting"),
("", "Empty name test"),
]
for name, description in test_cases:
total_tests += 1
success, result = client.test_hello_world(name)
print_test_result(f"getHelloWorld('{name}') - {description}", success, result)
if success:
passed_tests += 1
# ==================== Test 2: Customer Registration ====================
print_header("2. Testing Customer Registration Service", "-")
registration_tests = [
("Alice Johnson", False, "Register regular customer"),
("Bob Smith", False, "Register another customer"),
("Charlie Brown", True, "Register blacklisted customer"),
("David Lee", False, "Register regular customer"),
("Alice Johnson", False, "Duplicate registration (should fail)"),
("", False, "Empty name (should fail)"),
]
for customer_name, is_blacklisted, description in registration_tests:
total_tests += 1
success, result = client.register_customer(customer_name, is_blacklisted)
# For empty name, we expect a SOAP fault or error
if customer_name == "" and "Fault" in str(result):
success = True # Expected failure
print_test_result(
f"registerNewCustomer('{customer_name}', blacklisted={is_blacklisted}) - {description}",
success,
result
)
if success:
passed_tests += 1
# ==================== Test 3: Loan Application Processing ====================
print_header("3. Testing Loan Application Processing Service", "-")
loan_tests = [
("Alice Johnson", 50000, 750, "High credit score - should approve with excellent rate"),
("Bob Smith", 30000, 650, "Good credit score - should approve with standard rate"),
("David Lee", 20000, 550, "Fair credit score - should approve with high rate"),
("Charlie Brown", 40000, 700, "Blacklisted customer - should reject"),
("Eve Williams", 100000, 450, "Low credit score - should reject"),
("", 50000, 700, "Empty name - should return SOAP fault"),
("Alice Johnson", 0, 700, "Zero amount - should return SOAP fault"),
("Alice Johnson", -1000, 700, "Negative amount - should return SOAP fault"),
]
for applicant_name, amount, credit_score, description in loan_tests:
total_tests += 1
success, result = client.process_loan_application(applicant_name, amount, credit_score)
# For validation errors, check if we got expected error
if applicant_name == "" or amount <= 0:
if isinstance(result, dict) and "error" in result:
success = True # Expected error
print_test_result(
f"processLoanApplication('{applicant_name}', ${amount}, score={credit_score}) - {description}",
success,
result
)
if success:
passed_tests += 1
# ==================== Test Summary ====================
print_header("TEST SUMMARY", "=")
print(f" Total Tests: {total_tests}")
print(f" Passed: {passed_tests}")
print(f" Failed: {total_tests - passed_tests}")
print(f" Success Rate: {(passed_tests/total_tests)*100:.1f}%")
print()
return passed_tests == total_tests
def run_interactive_mode(client):
"""Run interactive testing mode"""
print_header("INTERACTIVE MODE", "=")
print("Available commands:")
print(" hello <name> - Test Hello World service")
print(" register <name> - Register regular customer")
print(" blacklist <name> - Register blacklisted customer")
print(" loan <name> <amount> <credit_score> - Process loan application")
print(" quit - Exit interactive mode")
print()
while True:
try:
user_input = input(">> ").strip()
if not user_input:
continue
if user_input.lower() in ['quit', 'exit', 'q']:
break
parts = user_input.split()
command = parts[0].lower()
if command == "hello" and len(parts) >= 2:
name = " ".join(parts[1:])
success, result = client.test_hello_world(name)
print(f" Result: {result}")
print()
elif command == "register" and len(parts) >= 2:
name = " ".join(parts[1:])
success, result = client.register_customer(name, False)
print(f" Result: {result}")
print()
elif command == "blacklist" and len(parts) >= 2:
name = " ".join(parts[1:])
success, result = client.register_customer(name, True)
print(f" Result: {result}")
print()
elif command == "loan" and len(parts) >= 4:
name = parts[1]
try:
amount = int(parts[2])
credit_score = int(parts[3])
success, result = client.process_loan_application(name, amount, credit_score)
if isinstance(result, dict):
print(" Loan Application Result:")
for key, value in result.items():
print(f" {key}: {value}")
else:
print(f" Result: {result}")
print()
except ValueError:
print(" Error: Amount and credit score must be numbers")
print()
else:
print(" Invalid command. Type 'quit' to exit or use one of the available commands.")
print()
except KeyboardInterrupt:
print("\n Interrupted by user")
break
except Exception as e:
print(f" Error: {str(e)}")
print()
def main():
"""Main function"""
print_header("JAX-WS UNIFIED TEST CLIENT", "=")
print("Testing all services and operations")
print()
# Create client
client = JAXWSTestClient()
# Check services availability
print("Checking services availability...")
print()
hello_ok, hello_msg = client.check_service(client.hello_service_url)
print(f" Hello World Service: {hello_msg}")
loan_ok, loan_msg = client.check_service(client.loan_service_url)
print(f" Loan Approval Service: {loan_msg}")
print()
if not hello_ok or not loan_ok:
print(" ERROR: One or more services are not available.")
print(" Please ensure the Docker container is running:")
print(" docker-compose up -d")
print()
return 1
# Run automated tests
try:
all_passed = run_automated_tests(client)
except KeyboardInterrupt:
print("\n Tests interrupted by user")
return 1
# Ask user if they want interactive mode
print()
print("Would you like to enter interactive mode? (y/n): ", end="")
try:
choice = input().strip().lower()
if choice in ['y', 'yes']:
run_interactive_mode(client)
except KeyboardInterrupt:
print("\n Skipping interactive mode")
print()
print_header("TEST COMPLETED", "=")
return 0 if all_passed else 1
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,250 @@
#!/usr/bin/env python3
"""
Python script to test registerNewCustomer SOAP Web Service
"""
import requests
import xml.etree.ElementTree as ET
from xml.dom import minidom
class CustomerRegistrationClient:
"""Client for Customer Registration SOAP Service"""
def __init__(self, service_url="http://localhost:8080/jaxws-hello-world/loan"):
"""
Initialize the Customer Registration client
Args:
service_url: The SOAP service endpoint URL
"""
self.service_url = service_url
self.wsdl_url = f"{service_url}?wsdl"
self.headers = {
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': ''
}
def create_soap_envelope(self, customer_name, is_blacklisted=False):
"""
Create SOAP envelope for registerNewCustomer request
Args:
customer_name: The customer name to register
is_blacklisted: Whether the customer is blacklisted (default: False)
Returns:
XML string of SOAP envelope
"""
blacklisted_value = "true" if is_blacklisted else "false"
soap_envelope = f"""<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.example.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:registerNewCustomer>
<arg0>
<customerName>{customer_name}</customerName>
<blacklisted>{blacklisted_value}</blacklisted>
</arg0>
</ser:registerNewCustomer>
</soapenv:Body>
</soapenv:Envelope>"""
return soap_envelope
def register_customer(self, customer_name, is_blacklisted=False):
"""
Register a new customer via SOAP service
Args:
customer_name: The customer name to register
is_blacklisted: Whether the customer is blacklisted
Returns:
Response message from the service
"""
try:
# Create SOAP envelope
soap_request = self.create_soap_envelope(customer_name, is_blacklisted)
# Make the SOAP request
response = requests.post(
self.service_url,
data=soap_request,
headers=self.headers,
timeout=10
)
# Check if request was successful
response.raise_for_status()
# Parse the response
return self.parse_response(response.text)
except requests.exceptions.RequestException as e:
return f"Error calling service: {str(e)}"
def parse_response(self, response_xml):
"""
Parse the SOAP response
Args:
response_xml: The XML response from the service
Returns:
The return value from the service
"""
try:
# Parse XML
root = ET.fromstring(response_xml)
# Find the return element
# Handle namespaces
namespaces = {
'S': 'http://schemas.xmlsoap.org/soap/envelope/',
'ns2': 'http://service.example.com/'
}
# Find the return value
return_elem = root.find('.//ns2:registerNewCustomerResponse/return', namespaces)
if return_elem is not None:
return return_elem.text
else:
# Check for SOAP fault
fault_elem = root.find('.//S:Fault', namespaces)
if fault_elem is not None:
fault_string = fault_elem.find('.//faultstring', namespaces)
if fault_string is not None:
return f"SOAP Fault: {fault_string.text}"
return "Could not find return value in response"
except ET.ParseError as e:
return f"Error parsing response: {str(e)}"
def check_wsdl(self):
"""
Check if WSDL is accessible
Returns:
Tuple of (success: bool, message: str)
"""
try:
response = requests.get(self.wsdl_url, timeout=5)
response.raise_for_status()
return True, "WSDL is accessible"
except requests.exceptions.RequestException as e:
return False, f"Cannot access WSDL: {str(e)}"
def pretty_print_xml(self, xml_string):
"""
Pretty print XML string
Args:
xml_string: XML string to format
Returns:
Formatted XML string
"""
try:
parsed = minidom.parseString(xml_string)
return parsed.toprettyxml(indent=" ")
except Exception:
return xml_string
def main():
"""Main function to test the Customer Registration service"""
print("=" * 70)
print("Customer Registration Service Test Client")
print("=" * 70)
print()
# Create client
client = CustomerRegistrationClient()
# Check WSDL
print("1. Checking WSDL availability...")
wsdl_ok, wsdl_msg = client.check_wsdl()
print(f" {wsdl_msg}")
if not wsdl_ok:
print(" Service is not available. Make sure the service is running.")
return
print()
# Test customer registrations
test_cases = [
{"name": "John Doe", "blacklisted": False, "description": "Regular customer"},
{"name": "Jane Smith", "blacklisted": False, "description": "Regular customer"},
{"name": "Bad Actor", "blacklisted": True, "description": "Blacklisted customer"},
{"name": "John Doe", "blacklisted": False, "description": "Duplicate registration (should fail)"},
{"name": "Alice Johnson", "blacklisted": False, "description": "Regular customer"},
{"name": "Bob Wilson", "blacklisted": True, "description": "Blacklisted customer"},
]
print("2. Testing Customer Registration...")
print()
for i, test_case in enumerate(test_cases, 1):
name = test_case["name"]
blacklisted = test_case["blacklisted"]
description = test_case["description"]
print(f" Test {i}: {description}")
print(f" Customer Name: {name}")
print(f" Blacklisted: {blacklisted}")
result = client.register_customer(name, blacklisted)
print(f" Result: {result}")
print()
# Interactive mode
print("3. Interactive Mode")
print(" " + "-" * 66)
print(" Commands:")
print(" - register <name>: Register a regular customer")
print(" - blacklist <name>: Register a blacklisted customer")
print(" - quit: Exit")
print()
try:
while True:
user_input = input(" > ").strip()
if user_input.lower() in ['quit', 'exit', 'q']:
break
if not user_input:
print(" Please enter a command.")
continue
parts = user_input.split(maxsplit=1)
command = parts[0].lower()
if command == "register" and len(parts) == 2:
customer_name = parts[1].strip()
result = client.register_customer(customer_name, False)
print(f" Result: {result}")
print()
elif command == "blacklist" and len(parts) == 2:
customer_name = parts[1].strip()
result = client.register_customer(customer_name, True)
print(f" Result: {result}")
print()
else:
print(" Invalid command. Use: register <name> or blacklist <name>")
print()
except KeyboardInterrupt:
print("\n Interrupted by user")
print()
print("=" * 70)
print("Test completed!")
print("=" * 70)
if __name__ == "__main__":
main()