mock

package
v0.3.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 18, 2022 License: BSD-3-Clause Imports: 10 Imported by: 0

README

PkgGoDev Go Report Card

LIFX LAN Mocks

Please refer to project README or GoDoc page for more informations.

Documentation

Overview

Package mock implements a mocked lifxlan device listening on localhost, which can be used in test code to test API calls.

Please refer to examples to see how to use them in the test code.

Example (TestGetLabel)

This example demonstrates how to mock a response in test code.

package main

import (
	"context"
	"testing"
	"time"

	"go.yhsif.com/lifxlan"
	"go.yhsif.com/lifxlan/mock"
)

func main() {
	var t *testing.T
	t.Run(
		"GetLabel",
		func(t *testing.T) {
			if testing.Short() {
				t.Skip("skipping test in short mode.")
			}

			const timeout = time.Millisecond * 200

			var expected lifxlan.Label
			expected.Set("foo")

			service, device := mock.StartService(t)
			// This is the payload to be returned by the mock service.
			service.RawStateLabelPayload = &lifxlan.RawStateLabelPayload{
				Label: expected,
			}

			ctx, cancel := context.WithTimeout(context.Background(), timeout)
			defer cancel()

			if err := device.GetLabel(ctx, nil); err != nil {
				t.Fatal(err)
			}
			if device.Label().String() != expected.String() {
				t.Errorf("Label expected %v, got %v", expected, device.Label())
			}
		},
	)
}
Output:

Example (TestGetLabelWithHandlerFunc)

This example demonstrates how to mock a response with custom HandlerFunc.

package main

import (
	"bytes"
	"context"
	"encoding/binary"
	"net"
	"testing"
	"time"

	"go.yhsif.com/lifxlan"
	"go.yhsif.com/lifxlan/mock"
)

func main() {
	var t *testing.T
	t.Run(
		"GetLabel",
		func(t *testing.T) {
			if testing.Short() {
				t.Skip("skipping test in short mode.")
			}

			const timeout = time.Millisecond * 200

			var expected lifxlan.Label
			expected.Set("foo")

			service, device := mock.StartService(t)

			// This defines the handler for GetLabel messages.
			service.Handlers[lifxlan.GetLabel] = func(
				s *mock.Service,
				conn net.PacketConn,
				addr net.Addr,
				orig *lifxlan.Response,
			) {
				buf := new(bytes.Buffer)
				if err := binary.Write(
					buf,
					binary.LittleEndian,
					expected,
				); err != nil {
					s.TB.Log(err)
					return
				}
				s.Reply(conn, addr, orig, lifxlan.StateLabel, buf.Bytes())
			}

			ctx, cancel := context.WithTimeout(context.Background(), timeout)
			defer cancel()

			if err := device.GetLabel(ctx, nil); err != nil {
				t.Fatal(err)
			}
			if device.Label().String() != expected.String() {
				t.Errorf("Label expected %v, got %v", expected, device.Label())
			}
		},
	)
}
Output:

Example (TestNotEnoughAcks)

This example demonstrates how to mock a not enough acks situation in test code.

package main

import (
	"context"
	"testing"
	"time"

	"go.yhsif.com/lifxlan/mock"
	"go.yhsif.com/lifxlan/tile"
)

func main() {
	var t *testing.T
	t.Run(
		"SetColors",
		func(t *testing.T) {
			if testing.Short() {
				t.Skip("skipping test in short mode.")
			}

			const timeout = time.Millisecond * 200

			service, device := mock.StartService(t)

			rawTile1 := tile.RawTileDevice{
				Width:  8,
				Height: 8,
			}
			rawTile2 := tile.RawTileDevice{
				UserX:  1,
				Width:  8,
				Height: 8,
			}
			rawChain := &tile.RawStateDeviceChainPayload{
				TotalCount: 2,
			}
			rawChain.TileDevices[0] = rawTile1
			rawChain.TileDevices[1] = rawTile2
			service.RawStateDeviceChainPayload = rawChain

			td, err := func() (tile.Device, error) {
				ctx, cancel := context.WithTimeout(context.Background(), timeout)
				defer cancel()
				return tile.Wrap(ctx, device, false)
			}()
			if err != nil {
				t.Fatal(err)
			}
			if td == nil {
				t.Fatal("Can't mock tile device.")
			}

			t.Run(
				"NotEnoughAcks",
				func(t *testing.T) {
					// The SetColors function will expect 2 acks.
					service.AcksToDrop = 1

					ctx, cancel := context.WithTimeout(context.Background(), timeout)
					defer cancel()

					if err := td.SetColors(ctx, nil, nil, 0, true); err == nil {
						t.Error("Expected error when not enough acks returned, got nil")
					}
				},
			)
		},
	)
}
Output:

Index

Examples

Constants

View Source
const ListenAddr = "127.0.0.1:"

ListenAddr is the addr to listen on this device.

View Source
const Target lifxlan.Target = 1

Target is the mocked device target.

Variables

This section is empty.

Functions

func DefaultHandlerFunc

func DefaultHandlerFunc(
	s *Service,
	conn net.PacketConn,
	addr net.Addr,
	orig *lifxlan.Response,
)

DefaultHandlerFunc is the default HandlerFunc to be used when it's not in the Handlers map.

Types

type HandlerFunc

type HandlerFunc func(s *Service, conn net.PacketConn, addr net.Addr, orig *lifxlan.Response)

HandlerFunc defines the handler function.

func StateUnhandledHandler

func StateUnhandledHandler(msg lifxlan.MessageType) HandlerFunc

StateUnhandledHandler generates a HandlerFunc to return StateUnhandled message.

type Service

type Service struct {
	// Testing context
	TB testing.TB

	// When AcksToDrop > 0 and it's supposed to send an ack,
	// the ack won't be send and AcksToDrop will decrease by 1.
	AcksToDrop int

	// Any custom HandlerFunc to be used besides DefaultHandlerFunc.
	Handlers map[lifxlan.MessageType]HandlerFunc

	// If HandlerAcks is false, AcksToDrop is ignored and you have to handle acks
	// in your custom HandlerFunc.
	//
	// Please note that DefaultHandlerFunc doesn't handle acks.
	//
	// StartService sets HandleAcks to true.
	HandleAcks bool

	// Payloads to response with DefaultHandlerFunc.
	RawStatePowerPayload        *lifxlan.RawStatePowerPayload
	RawStateLabelPayload        *lifxlan.RawStateLabelPayload
	RawStateVersionPayload      *lifxlan.RawStateVersionPayload
	RawStatePayload             *light.RawStatePayload
	RawStateRPowerPayload       *relay.RawStateRPowerPayload
	RawStateDeviceChainPayload  *tile.RawStateDeviceChainPayload
	RawStateTileState64Payloads []*tile.RawStateTileState64Payload

	// The service context.
	//
	// Please note that it's different from the context of the API calls.
	Context context.Context
	Cancel  context.CancelFunc
	// contains filtered or unexported fields
}

Service is a mocked device listening on localhost.

All service functions require TB to be non-nil, or they will panic.

func StartService

func StartService(tb testing.TB) (*Service, lifxlan.Device)

StartService starts a mock service, returns the service and the device.

func (*Service) Reply

func (s *Service) Reply(
	conn net.PacketConn,
	addr net.Addr,
	orig *lifxlan.Response,
	message lifxlan.MessageType,
	payload []byte,
)

Reply replies a request.

func (*Service) Start

func (s *Service) Start() lifxlan.Device

Start starts the service and returns the device.

It also register Stop to TB's Cleanup.

func (*Service) Stop

func (s *Service) Stop()

Stop stops the mocked device service.

It won't response to any requests after stopped.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL