Documentation
¶
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ServiceAMQP = Service{ Name: "amqp", Port: 5672, Protocol: "amqp", SupportSSL: false, } ServiceMQTT = Service{ Name: "mqtt", Port: 1883, Protocol: "tcp", SupportSSL: false, } ServiceREST = Service{ Name: "rest", Port: 9000, Protocol: "http", SupportSSL: false, } ServiceManagement = Service{ Name: "management", Port: 8080, Protocol: "http", SupportSSL: false, } ServiceSMF = Service{ Name: "smf", Port: 55555, Protocol: "tcp", SupportSSL: true, } ServiceSMFSSL = Service{ Name: "smf", Port: 55443, Protocol: "tcps", SupportSSL: true, } )
Functions ¶
This section is empty.
Types ¶
type Container ¶
type Container struct {
testcontainers.Container
// contains filtered or unexported fields
}
Container represents a Solace container with additional settings
func Run ¶
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error)
Run starts a Solace container with the provided image and options
The container requires specific ulimits to start successfully:
- nofile: 1048576 (number of open files)
- core: -1 (for core dumps)
- memlock: -1 (for memory locking)
See https://docs.solace.com for more information. - https://docs.solace.com/Software-Broker/Managing-Core-Files.htm - https://docs.solace.com/Software-Broker/Container-Tasks/Config-Container-Storage.htm?Highlight=ulimit
Example ¶
package main
import (
"context"
"fmt"
"log"
"github.com/testcontainers/testcontainers-go"
sc "github.com/testcontainers/testcontainers-go/modules/solace"
)
func main() {
// runSolaceContainer {
ctx := context.Background()
ctr, err := sc.Run(ctx, "solace/solace-pubsub-standard:latest",
sc.WithCredentials("admin", "admin"),
sc.WithServices(sc.ServiceAMQP, sc.ServiceManagement),
testcontainers.WithEnv(map[string]string{
"username_admin_globalaccesslevel": "admin",
"username_admin_password": "admin",
}),
sc.WithShmSize(1<<30),
)
defer func() {
if err := testcontainers.TerminateContainer(ctr); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
fmt.Println(err)
// }
}
Output: <nil>
Example (WithTopicAndQueue) ¶
package main
import (
"context"
"fmt"
"log"
"time"
"solace.dev/go/messaging"
"solace.dev/go/messaging/pkg/solace"
"solace.dev/go/messaging/pkg/solace/config"
"solace.dev/go/messaging/pkg/solace/message"
"solace.dev/go/messaging/pkg/solace/resource"
"github.com/testcontainers/testcontainers-go"
sc "github.com/testcontainers/testcontainers-go/modules/solace"
)
func main() {
ctx := context.Background()
ctr, err := sc.Run(ctx, "solace/solace-pubsub-standard:latest",
sc.WithCredentials("admin", "admin"),
sc.WithVPN("test-vpn"),
sc.WithServices(sc.ServiceAMQP, sc.ServiceManagement, sc.ServiceSMF),
testcontainers.WithEnv(map[string]string{
"username_admin_globalaccesslevel": "admin",
"username_admin_password": "admin",
}),
sc.WithShmSize(1<<30),
sc.WithQueue("TestQueue", "Topic/MyTopic"),
)
defer func() {
if err := testcontainers.TerminateContainer(ctr); err != nil {
log.Printf("failed to terminate container: %s", err)
}
}()
fmt.Println(err)
// the [testMessagePublishAndConsume] function is responsible for printing the output
// to the console, so be aware of that when adding it to other examples.
err = testMessagePublishAndConsume(ctr, "TestQueue", "Topic/MyTopic")
fmt.Println(err)
}
func testMessagePublishAndConsume(ctr *sc.Container, queueName, topicName string) error {
smfURL, err := ctr.BrokerURLFor(context.Background(), sc.ServiceSMF)
if err != nil {
return fmt.Errorf("failed to get SMF URL: %w", err)
}
brokerConfig := config.ServicePropertyMap{
config.TransportLayerPropertyHost: smfURL,
config.ServicePropertyVPNName: ctr.VPN(),
config.AuthenticationPropertyScheme: config.AuthenticationSchemeBasic,
config.AuthenticationPropertySchemeBasicUserName: ctr.Username(),
config.AuthenticationPropertySchemeBasicPassword: ctr.Password(),
config.TransportLayerPropertyReconnectionAttempts: 0,
}
messagingService, err := messaging.NewMessagingServiceBuilder().
FromConfigurationProvider(brokerConfig).
Build()
if err != nil {
return fmt.Errorf("failed to build messaging service: %w", err)
}
if err := messagingService.Connect(); err != nil {
return fmt.Errorf("failed to connect to messaging service: %w", err)
}
defer func() {
if err := messagingService.Disconnect(); err != nil {
log.Printf("Error disconnecting from messaging service: %v", err)
}
}()
err = publishTestMessage(messagingService, topicName)
if err != nil {
return fmt.Errorf("failed to publish message: %w", err)
}
err = consumeTestMessage(messagingService, queueName)
if err != nil {
return fmt.Errorf("failed to consume message: %w", err)
}
return nil
}
func publishTestMessage(messagingService solace.MessagingService, topicName string) error {
directPublisher, err := messagingService.CreateDirectMessagePublisherBuilder().Build()
if err != nil {
return fmt.Errorf("failed to build publisher: %w", err)
}
if err := directPublisher.Start(); err != nil {
return fmt.Errorf("failed to start publisher: %w", err)
}
defer func() {
if err := directPublisher.Terminate(1 * time.Second); err != nil {
log.Printf("Error terminating direct publisher: %v", err)
}
}()
messageBuilder := messagingService.MessageBuilder()
message, err := messageBuilder.
WithProperty("custom-property", "test-value").
BuildWithStringPayload("Hello from Solace testcontainers!")
if err != nil {
return fmt.Errorf("failed to build message: %w", err)
}
topic := resource.TopicOf(topicName)
if err := directPublisher.Publish(message, topic); err != nil {
return fmt.Errorf("failed to publish message: %w", err)
}
fmt.Printf("Published message to topic: %s\n", topicName)
return nil
}
func consumeTestMessage(messagingService solace.MessagingService, queueName string) error {
persistentReceiver, err := messagingService.CreatePersistentMessageReceiverBuilder().
Build(resource.QueueDurableExclusive(queueName))
if err != nil {
return fmt.Errorf("failed to build receiver: %w", err)
}
messageReceived := make(chan message.InboundMessage, 1)
errorChan := make(chan error, 1)
messageHandler := func(msg message.InboundMessage) {
payload, ok := msg.GetPayloadAsString()
if ok {
fmt.Printf("Received message: %s\n", payload)
}
messageReceived <- msg
}
if err := persistentReceiver.Start(); err != nil {
return fmt.Errorf("failed to start receiver: %w", err)
}
defer func() {
if err := persistentReceiver.Terminate(1 * time.Second); err != nil {
log.Printf("Error terminating persistent receiver: %v", err)
}
}()
if err := persistentReceiver.ReceiveAsync(messageHandler); err != nil {
return fmt.Errorf("failed to start async receive: %w", err)
}
select {
case <-messageReceived:
fmt.Printf("Successfully received message from queue: %s\n", queueName)
return nil
case err := <-errorChan:
return fmt.Errorf("error receiving message: %w", err)
case <-time.After(15 * time.Second):
return fmt.Errorf("timeout waiting for message from queue: %s", queueName)
}
}
Output: <nil> Published message to topic: Topic/MyTopic Received message: Hello from Solace testcontainers! Successfully received message from queue: TestQueue <nil>
func (*Container) BrokerURLFor ¶
BrokerURLFor returns the origin URL for a given service
type Option ¶
type Option func(*options) error
Option is an option for the Solace container.
func WithCredentials ¶
WithCredentials sets the client credentials (username, password)
func WithServices ¶
WithServices configures the services to be exposed with their wait strategies
func WithShmSize ¶
WithShmSize sets the size of the /dev/shm volume
func (Option) Customize ¶
func (o Option) Customize(*testcontainers.GenericContainerRequest) error
Customize is a NOOP. It's defined to satisfy the testcontainers.ContainerCustomizer interface.