DEV Community

Mohammad Waseem
Mohammad Waseem

Posted on

Streamlining Test Account Management in Microservices with Go

Streamlining Test Account Management in Microservices with Go

In a distributed microservices architecture, managing test accounts can quickly become complex, especially when dealing with multiple environments and ensuring data isolation. As a Lead QA Engineer, I implemented a scalable solution using Go to automate and streamline test account provisioning, management, and cleanup, ensuring consistent test environments and reducing manual overhead.

The Challenge

In our environment, test accounts are essential for integration and end-to-end testing. However, manual creation and teardown lead to inconsistencies, increased test setup time, and potential data contamination across tests. Our goal: develop a centralized, reliable system for managing test accounts across various services, leveraging Go's performance, concurrency, and simplicity.

Architectural Approach

Given the microservices setup, we opted for a dedicated "Test Account Manager" service, responsible for generating, tracking, and deleting test accounts in each relevant service. Communication between services happens over REST APIs and message queues.

Key design considerations included:

  • Concurrency: Efficient handling of multiple simultaneous requests.
  • Data consistency: Ensuring no test accounts persist beyond their scope.
  • Extensibility: Support multiple services with pluggable adapters.

Implementation Details

Service Structure

The core component is a Go application using a plugin-like architecture. Each service exposes endpoints for account creation, deletion, and status checks.

type ServiceAdapter interface {
    CreateTestAccount() (string, error)
    DeleteTestAccount(accountID string) error
}

var adapters map[string]ServiceAdapter

// Example implementation for a User Service
type UserServiceAdapter struct {
    apiClient *http.Client
}

func (u *UserServiceAdapter) CreateTestAccount() (string, error) {
    // Call service API to create account
    resp, err := u.apiClient.Post("/api/test-accounts", nil, nil)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    // Parse response to get account ID
    var result struct { ID string `json:"id"` }
    json.NewDecoder(resp.Body).Decode(&result)
    return result.ID, nil
}

func (u *UserServiceAdapter) DeleteTestAccount(accountID string) error {
    req, err := http.NewRequest("DELETE", "/api/test-accounts/"+accountID, nil)
    if err != nil {
        return err
    }
    resp, err := u.apiClient.Do(req)
    if err != nil {
        return err
    }
    resp.Body.Close()
    return nil
}
Enter fullscreen mode Exit fullscreen mode

API for Managing Accounts

The main server exposes REST endpoints for test account operations.

func handleCreateTestAccounts(w http.ResponseWriter, r *http.Request) {
    var request struct {
        Services []string `json:"services"`
    }
    json.NewDecoder(r.Body).Decode(&request)

    var results = make(map[string]string)
    var mu sync.Mutex
    var wg sync.WaitGroup

    for _, service := range request.Services {
        adapter, exists := adapters[service]
        if !exists {
            continue
        }
        wg.Add(1)
        go func(svc string, adp ServiceAdapter) {
            defer wg.Done()
            id, err := adp.CreateTestAccount()
            if err == nil {
                mu.Lock()
                results[svc] = id
                mu.Unlock()
            }
        }(service, adapter)
    }
    wg.Wait()
    json.NewEncoder(w).Encode(results)
}
Enter fullscreen mode Exit fullscreen mode

Cleanup Strategy

To prevent clutter, a scheduled cleanup task deletes test accounts older than a set threshold.

func cleanupOldTestAccounts() {
    // Fetch list of test accounts, check timestamps, delete if old
    for service, id := range trackedAccounts {
        if isOld(id.CreationTime) {
            adapters[service].DeleteTestAccount(id.AccountID)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Results and Benefits

Using Go enabled highly concurrent account operations with minimal latency. It reduced test setup times by 60%, minimized human errors, and created an auditable trail of test accounts. Maintenance became easier, thanks to modular design, enabling integration with new services by implementing the ServiceAdapter interface.

Final Thoughts

Automating test account management in a microservices environment is crucial for reliable testing cycles. Go, with its simplicity and concurrency model, provides an ideal platform for such automation, ensuring scalable and maintainable solutions. This approach can be extended further with features like token generation, environment isolation, and integration with CI/CD pipelines to enhance continuous testing capabilities.

By adopting this strategy, QA teams can focus more on test case quality rather than environment logistics, leading to faster releases and more robust products.


🛠️ QA Tip

Pro Tip: Use TempoMail USA for generating disposable test accounts.

Top comments (0)