Skip to content

Commit f14cf03

Browse files
authored
Merge pull request #499 from tcheeric/develop
Refactor WebSocket handling and update integration tests
2 parents de6ca6a + 2e5b6fe commit f14cf03

22 files changed

Lines changed: 706 additions & 128 deletions

File tree

AGENTS.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,22 @@ The URL format for the NIPs is https://github.com/nostr-protocol/nips/blob/maste
149149
- Always follow the repository's PR submission guidelines and use the PR template located at `.github/pull_request_template.md`.
150150
- Summarize the changes made and describe how they were tested.
151151
- Include any limitations or known issues in the description.
152-
- Ensure all new features are compliant with the Cashu specification (NUTs) provided above.
152+
- Ensure all new features are compliant with the Nostr specification (NIPs) provided above.
153+
154+
## Versioning
155+
156+
- Follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) for all releases.
157+
- Update the version in the parent `pom.xml` and all module POMs when preparing a release.
158+
- Use conventional commit types to signal version bumps (fix → patch, feat → minor, BREAKING CHANGE → major).
159+
160+
## Changelog Maintenance
161+
162+
- **Always update `CHANGELOG.md`** after any version change or significant code modification.
163+
- Follow the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format:
164+
- Group changes under: `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`
165+
- List versions in reverse chronological order (newest first)
166+
- Use `[Unreleased]` section for changes not yet in a release
167+
- Include the release date in ISO format: `## [1.0.0] - 2025-12-17`
168+
- Each entry should be a concise, human-readable description of the change
169+
- Reference related issues or PRs where applicable
170+
- Update the changelog in the same commit as the version bump when possible

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,30 @@ The format is inspired by Keep a Changelog, and this project adheres to semantic
88

99
No unreleased changes yet.
1010

11+
## [1.1.1] - 2025-12-24
12+
13+
### Fixed
14+
- StandardWebSocketClient now configures WebSocketContainer with a 1-hour idle timeout (configurable via `nostr.websocket.max-idle-timeout-ms`) to prevent premature connection closures when relays have periods of inactivity.
15+
16+
## [1.1.0] - 2025-12-23
17+
18+
### Added
19+
- Public constructor `StandardWebSocketClient(String relayUri, long awaitTimeoutMs, long pollIntervalMs)` for programmatic timeout configuration outside Spring DI context.
20+
21+
### Changed
22+
- Enhanced diagnostic logging for timeout configuration in StandardWebSocketClient.
23+
- Simplified WebSocket client initialization and retry logic in tests.
24+
25+
### Fixed
26+
- Updated `JsonDeserialize` builder reference in API module.
27+
28+
## [1.0.1] - 2025-12-20
29+
30+
### Changed
31+
- Updated project version and added artifact names in POM files.
32+
- Added Sonatype Central server credentials configuration.
33+
- Updated Maven command for central publishing.
34+
1135
## [1.0.0] - 2025-10-13
1236

1337
### Added

docs/TROUBLESHOOTING.md

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This guide helps you diagnose and resolve common issues when using nostr-java.
1313
- [Subscription Issues](#subscription-issues)
1414
- [Encryption & Decryption Issues](#encryption--decryption-issues)
1515
- [Performance Issues](#performance-issues)
16+
- [Integration Testing Issues](#integration-testing-issues)
1617

1718
---
1819

@@ -603,3 +604,170 @@ For Spring Boot applications, add to `application.properties`:
603604
logging.level.nostr=DEBUG
604605
logging.level.nostr.client=TRACE
605606
```
607+
608+
---
609+
610+
## Integration Testing Issues
611+
612+
### Problem: Tests Timeout After 60 Seconds
613+
614+
**Symptom**: Integration tests hang and fail with `NoSuchElementException: No value present` or `No message received`
615+
616+
**Possible Causes & Solutions:**
617+
618+
#### 1. nostr-rs-relay Quanta Bug
619+
620+
The `scsibug/nostr-rs-relay` Docker image contains a known bug in the `quanta` crate that causes panics in Docker environments:
621+
622+
```
623+
thread 'tokio-ws-10' panicked at quanta-0.9.3/src/lib.rs:274:13:
624+
po2_denom was zero!
625+
```
626+
627+
**Solution**: Use strfry relay instead:
628+
629+
```properties
630+
# src/test/resources/relay-container.properties
631+
relay.container.image=dockurr/strfry:latest
632+
relay.container.port=7777
633+
```
634+
635+
#### 2. Relay Container Not Starting
636+
637+
Check Docker is available and the container starts properly:
638+
639+
```bash
640+
# Verify Docker is running
641+
docker info
642+
643+
# Test the relay image manually
644+
docker run --rm -p 7777:7777 dockurr/strfry:latest
645+
```
646+
647+
### Problem: strfry Rejects All Events (Whitelist)
648+
649+
**Symptom**: Events return `success=false` with message `blocked: pubkey not in whitelist`
650+
651+
**Cause**: The default strfry Docker image has a write policy that whitelists specific pubkeys.
652+
653+
**Solution**: Create a custom strfry.conf that disables the whitelist:
654+
655+
```conf
656+
# src/test/resources/strfry.conf
657+
relay {
658+
writePolicy {
659+
plugin = "" # Disable write policy plugin
660+
}
661+
}
662+
```
663+
664+
Mount this config in your test container:
665+
666+
```java
667+
RELAY = new GenericContainer<>(image)
668+
.withExposedPorts(relayPort)
669+
.withClasspathResourceMapping(
670+
"strfry.conf", "/etc/strfry.conf", BindMode.READ_ONLY)
671+
.withTmpFs(Map.of("/app/strfry-db", "rw"))
672+
.waitingFor(Wait.forLogMessage(".*Started websocket server on.*", 1));
673+
```
674+
675+
### Problem: Filter Queries Return Empty Results
676+
677+
**Symptom**: Tests send events successfully but filter queries return only EOSE (no events)
678+
679+
**Cause**: Race condition - the relay needs time to index events before they can be queried.
680+
681+
**Solution**: Add a small delay between publishing and querying:
682+
683+
```java
684+
// Send event
685+
nip01.createTextNoteEvent(List.of(tag), "content").signAndSend(relays);
686+
687+
// Wait for relay to index the event
688+
Thread.sleep(100);
689+
690+
// Now query
691+
List<String> result = nip01.sendRequest(filters, subscriptionId);
692+
```
693+
694+
### Problem: strfry Requires High File Descriptor Limits
695+
696+
**Symptom**: Container fails with `Unable to set NOFILES limit`
697+
698+
**Solution**: Configure ulimits in Testcontainers:
699+
700+
```java
701+
import com.github.dockerjava.api.model.Ulimit;
702+
703+
RELAY = new GenericContainer<>(image)
704+
.withCreateContainerCmdModifier(cmd -> cmd.getHostConfig()
705+
.withUlimits(new Ulimit[] {new Ulimit("nofile", 1000000L, 1000000L)}))
706+
// ... other configuration
707+
```
708+
709+
### Problem: Tests Use Wrong Relay URL
710+
711+
**Symptom**: Tests connect to hardcoded URL instead of Testcontainers dynamic port
712+
713+
**Cause**: Tests may use `@Autowired` relays from properties file instead of dynamic container port.
714+
715+
**Solution**: Use a base test class that provides the dynamic relay URL:
716+
717+
```java
718+
public abstract class BaseRelayIntegrationTest {
719+
@Container
720+
private static final GenericContainer<?> RELAY = /* ... */;
721+
722+
static Map<String, String> getTestRelays() {
723+
String host = RELAY.getHost();
724+
int port = RELAY.getMappedPort(7777);
725+
return Map.of("relay", String.format("ws://%s:%d", host, port));
726+
}
727+
}
728+
729+
// In your test
730+
@BeforeEach
731+
void setUp() {
732+
relays = getTestRelays(); // Use dynamic URL, not autowired
733+
}
734+
```
735+
736+
### Problem: Tests Fail in CI but Pass Locally
737+
738+
**Symptom**: Docker-based tests fail in CI environments
739+
740+
**Possible Causes:**
741+
742+
1. **Docker not available**: Skip tests when Docker is unavailable:
743+
744+
```java
745+
@DisabledIfSystemProperty(named = "noDocker", matches = "true")
746+
public class MyIntegrationTest extends BaseRelayIntegrationTest {
747+
// ...
748+
}
749+
```
750+
751+
Run with: `mvn test -DnoDocker=true`
752+
753+
2. **Different Docker environments**: Some CI environments don't support certain CPU features (TSC) that cause the quanta bug.
754+
755+
3. **Resource constraints**: CI containers may have limited resources. Use tmpfs for relay storage:
756+
757+
```java
758+
.withTmpFs(Map.of("/app/strfry-db", "rw"))
759+
```
760+
761+
### Relay Configuration Reference
762+
763+
| Relay | Image | Port | Wait Strategy |
764+
|-------|-------|------|---------------|
765+
| strfry | `dockurr/strfry:latest` | 7777 | `Started websocket server on` |
766+
| nostr-rs-relay | `scsibug/nostr-rs-relay:latest` | 8080 | `listening on:` (has quanta bug) |
767+
768+
Configure via `src/test/resources/relay-container.properties`:
769+
770+
```properties
771+
relay.container.image=dockurr/strfry:latest
772+
relay.container.port=7777
773+
```

0 commit comments

Comments
 (0)