// setupRetainSubscriber returnes channel in order to read messages with retained flag func setupRetainSubscriber(gw *gateway.Gateway, broker *broker.Broker, dummyDevice *device.DummyDevice) (chan [2]string, inidef.Error) { // Setup MQTT pub/sub client to confirm published content. // messageOutputChannel := make(chan [2]string) opts := MQTT.NewClientOptions() brokerUrl := fmt.Sprintf("tcp://%s:%d", broker.Host, broker.Port) opts.AddBroker(brokerUrl) opts.SetClientID(gw.Name + "testSubscriber") // to distinguish MQTT client from publisher opts.SetCleanSession(false) opts.SetDefaultPublishHandler(func(client *MQTT.Client, msg MQTT.Message) { messageOutputChannel <- [2]string{msg.Topic(), string(msg.Payload())} }) client := MQTT.NewClient(opts) if client == nil { return nil, inidef.Error("NewClient failed") } if token := client.Connect(); token.Wait() && token.Error() != nil { return nil, inidef.Error(fmt.Sprintf("NewClient Start failed %q", token.Error())) } qos := 0 retainedTopic := fmt.Sprintf("%s/%s/%s/%s", broker.TopicPrefix, gw.Name, dummyDevice.Name, dummyDevice.Type) client.Subscribe(retainedTopic, byte(qos), func(client *MQTT.Client, msg MQTT.Message) { }) return messageOutputChannel, inidef.Error("") }
// setupWillSubscriber start subscriber process and returnes a channel witch can receive will message. func setupWillSubscriber(gw *gateway.Gateway, broker *broker.Broker) (chan MQTT.Message, inidef.Error) { // Setup MQTT pub/sub client to confirm published content. // messageOutputChannel := make(chan MQTT.Message) opts := MQTT.NewClientOptions() brokerUrl := fmt.Sprintf("tcp://%s:%d", broker.Host, broker.Port) opts.AddBroker(brokerUrl) opts.SetClientID(gw.Name + "testSubscriber") // to distinguish MQTT client from publisher opts.SetCleanSession(false) opts.SetDefaultPublishHandler(func(client *MQTT.Client, msg MQTT.Message) { messageOutputChannel <- msg }) client := MQTT.NewClient(opts) if client == nil { return nil, inidef.Error("NewClient failed") } if token := client.Connect(); token.Wait() && token.Error() != nil { return nil, inidef.Error(fmt.Sprintf("NewClient Start failed %q", token.Error())) } qos := 0 // assume topicPrefix == "" willTopic := fmt.Sprintf("/%s/will", gw.Name) client.Subscribe(willTopic, byte(qos), func(client *MQTT.Client, msg MQTT.Message) { messageOutputChannel <- msg }) return messageOutputChannel, inidef.Error("") }
// NewTLSConfig returns TLS config from CA Cert file path. func NewTLSConfig(caCertFilePath string) (*tls.Config, error) { certPool := x509.NewCertPool() pemCerts, err := ioutil.ReadFile(caCertFilePath) if err != nil { return nil, inidef.Error("Cert File could not be read.") } appendCertOk := certPool.AppendCertsFromPEM(pemCerts) if appendCertOk != true { return nil, inidef.Error("Server Certificate parse failed") } // only server certificate checked return &tls.Config{ RootCAs: certPool, ClientAuth: tls.NoClientCert, ClientCAs: nil, // InsecureSkipVerify = verify that cert contents // match server. IP matches what is in cert etc. InsecureSkipVerify: true, }, nil }
func genericWillTestDriver(t *testing.T, iniStr string, expectedTopic string, expectedPayload []byte) (ok bool) { assert := assert.New(t) conf, err := inidef.LoadConfigByte([]byte(iniStr)) assert.Nil(err) commandChannel := make(chan string) go fuji.StartByFileWithChannel(conf, commandChannel) gw, err := gateway.NewGateway(conf) assert.Nil(err) brokers, err := broker.NewBrokers(conf, gw.BrokerChan) assert.Nil(err) go func() { time.Sleep(1 * time.Second) subscriberChannel, err := setupWillSubscriber(gw, brokers[0]) if err != inidef.Error("") { t.Error(err) } time.Sleep(1 * time.Second) // kill publisher brokers[0].FourceClose() fmt.Println("broker killed for getting will message") // check will message willMsg := <-subscriberChannel assert.Equal(expectedTopic, willMsg.Topic()) assert.Equal(expectedPayload, willMsg.Payload()) assert.Equal(byte(0), willMsg.Qos()) }() time.Sleep(3 * time.Second) ok = true return ok }
// TestRetainSubscribePublishClose // 1. connect gateway to local broker // 2. send data with retaind flag from dummy device // 3. disconnect // 4. reconnect // 5. subscirbe and receive data func TestRetainSubscribePublishClose(t *testing.T) { assert := assert.New(t) iniStr := ` [gateway] name = testRetainafterclose [broker "local/1"] host = localhost port = 1883 [device "dora/dummy"] broker = local qos = 0 interval = 10 payload = Hello retained world to subscriber after close. type = EnOcean retain = true ` commandChannel := make(chan string) conf, err := inidef.LoadConfigByte([]byte(iniStr)) assert.Nil(err) go fuji.StartByFileWithChannel(conf, commandChannel) gw, err := gateway.NewGateway(conf) if err != nil { t.Error("Cannot make Gateway") } brokerList, err := broker.NewBrokers(conf, gw.BrokerChan) if err != nil { t.Error("Cannot make BrokerList") } dummyDevice, err := device.NewDummyDevice(conf.Sections[3], brokerList, gw.DeviceChan) if err != nil { t.Error("Cannot make DummyDeviceList") } go func() { time.Sleep(2 * time.Second) // kill publisher gw.Stop() time.Sleep(2 * time.Second) subscriberChannel, err := setupRetainSubscriber(gw, brokerList[0], &dummyDevice) if err != inidef.Error("") { t.Error(err) } // check Retained message retainedMessage := <-subscriberChannel retainedTopic := retainedMessage[0] retainedPayload := retainedMessage[1] expectedTopic := fmt.Sprintf("%s/%s/%s/%s", brokerList[0].TopicPrefix, gw.Name, dummyDevice.Name, dummyDevice.Type) expectedPayload := dummyDevice.Payload assert.Equal(expectedTopic, retainedTopic) assert.Equal(expectedPayload, retainedPayload) }() time.Sleep(5 * time.Second) }