<commit_before>// Copyright 2019 The Terraformer Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package yandex

import (
	"errors"
	"os"

	"github.com/GoogleCloudPlatform/terraformer/terraformutils"
	"github.com/GoogleCloudPlatform/terraformer/terraformutils/providerwrapper"
)

type YandexProvider struct { //nolint
	terraformutils.Provider
	oauthToken string
	folderID   string
}

func (p *YandexProvider) Init(args []string) error {
	if os.Getenv("YC_TOKEN") == "" {
		return errors.New("set YC_TOKEN env var")
	}
	p.oauthToken = os.Getenv("YC_TOKEN")

	if len(args) > 0 {
		//  first args is target folder ID
		p.folderID = args[0]
	}

	return nil
}

func (p *YandexProvider) GetName() string {
	return "yandex"
}

func (p *YandexProvider) GetProviderData(arg ...string) map[string]interface{} {
	return map[string]interface{}{
		"provider": map[string]interface{}{
			"yandex": map[string]interface{}{
				"version":   providerwrapper.GetProviderVersion(p.GetName()),
				"folder_id": p.folderID,
			},
		},
	}
}

func (YandexProvider) GetResourceConnections() map[string]map[string][]string {
	return map[string]map[string][]string{}
}

func (p *YandexProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator {
	return map[string]terraformutils.ServiceGenerator{
		"disk":     &DiskGenerator{},
		"instance": &InstanceGenerator{},
		"network":  &NetworkGenerator{},
		"subnet":   &SubnetGenerator{},
	}
}

func (p *YandexProvider) InitService(serviceName string, verbose bool) error {
	var isSupported bool
	if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported {
		return errors.New("yandex: " + serviceName + " not supported service")
	}
	p.Service = p.GetSupportedService()[serviceName]
	p.Service.SetName(serviceName)
	p.Service.SetVerbose(verbose)
	p.Service.SetProviderName(p.GetName())
	p.Service.SetArgs(map[string]interface{}{
		"folder_id": p.folderID,
		"token":     p.oauthToken,
	})
	return nil
}
<commit_msg>fix 565<commit_after>// Copyright 2019 The Terraformer Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package yandex

import (
	"errors"
	"os"

	"github.com/GoogleCloudPlatform/terraformer/terraformutils"
	"github.com/GoogleCloudPlatform/terraformer/terraformutils/providerwrapper"
)

type YandexProvider struct { //nolint
	terraformutils.Provider
	oauthToken string
	folderID   string
}

func (p *YandexProvider) Init(args []string) error {
	if os.Getenv("YC_TOKEN") == "" {
		return errors.New("set YC_TOKEN env var")
	}
	p.oauthToken = os.Getenv("YC_TOKEN")

	if len(args) > 0 {
		//  first args is target folder ID
		p.folderID = args[0]
	} else {
		if os.Getenv("YC_FOLDER_ID") == "" {
			return errors.New("set YC_FOLDER_ID env var")
		}
		p.folderID = os.Getenv("YC_FOLDER_ID")
	}

	return nil
}

func (p *YandexProvider) GetName() string {
	return "yandex"
}

func (p *YandexProvider) GetProviderData(arg ...string) map[string]interface{} {
	return map[string]interface{}{
		"provider": map[string]interface{}{
			"yandex": map[string]interface{}{
				"version":   providerwrapper.GetProviderVersion(p.GetName()),
				"folder_id": p.folderID,
			},
		},
	}
}

func (YandexProvider) GetResourceConnections() map[string]map[string][]string {
	return map[string]map[string][]string{}
}

func (p *YandexProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator {
	return map[string]terraformutils.ServiceGenerator{
		"disk":     &DiskGenerator{},
		"instance": &InstanceGenerator{},
		"network":  &NetworkGenerator{},
		"subnet":   &SubnetGenerator{},
	}
}

func (p *YandexProvider) InitService(serviceName string, verbose bool) error {
	var isSupported bool
	if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported {
		return errors.New("yandex: " + serviceName + " not supported service")
	}
	p.Service = p.GetSupportedService()[serviceName]
	p.Service.SetName(serviceName)
	p.Service.SetVerbose(verbose)
	p.Service.SetProviderName(p.GetName())
	p.Service.SetArgs(map[string]interface{}{
		"folder_id": p.folderID,
		"token":     p.oauthToken,
	})
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Square, Inc
// +build linux

package osmain

import (
	"fmt"
	//"math"
	"log"
	"path/filepath"
	"sort"
	"time"

	"github.com/square/inspect/metrics"
	"github.com/square/inspect/os/cpustat"
	"github.com/square/inspect/os/diskstat"
	"github.com/square/inspect/os/fsstat"
	"github.com/square/inspect/os/interfacestat"
	"github.com/square/inspect/os/loadstat"
	"github.com/square/inspect/os/memstat"
	"github.com/square/inspect/os/misc"
	"github.com/square/inspect/os/tcpstat"
)

type linuxStats struct {
	osind    *Stats
	dstat    *diskstat.DiskStat
	fsstat   *fsstat.FSStat
	ifstat   *interfacestat.InterfaceStat
	tcpstat  *tcpstat.TCPStat
	cgMem    *memstat.CgroupStat
	cgCPU    *cpustat.CgroupStat
	loadstat *loadstat.LoadStat
}

// RegisterOsSpecific registers OS dependent statistics
func registerOsSpecific(m *metrics.MetricContext, step time.Duration,
	osind *Stats) *linuxStats {
	s := new(linuxStats)
	s.osind = osind
	s.dstat = diskstat.New(m, step)
	s.fsstat = fsstat.New(m, step)
	s.ifstat = interfacestat.New(m, step)
	s.tcpstat = tcpstat.New(m, step)
	s.loadstat = loadstat.New(m, step)
	s.cgMem = memstat.NewCgroupStat(m, step)
	s.cgCPU = cpustat.NewCgroupStat(m, step)
	return s
}

// PrintOsSpecific prints OS dependent statistics
func printOsSpecific(batchmode bool, layout *DisplayWidgets, v interface{}) {
	stats, ok := v.(*linuxStats)
	if !ok {
		log.Fatalf("Type assertion failed on printOsSpecific")
	}
	// Top N processes sorted by IO usage - requires root
	procsByUsage := stats.osind.ProcessStat.ByIOUsage()
	n := DisplayPidCount
	if len(procsByUsage) < n {
		n = len(procsByUsage)
	}
	var io []string
	for i := 0; i < n; i++ {
		io = append(io, fmt.Sprintf("%8s/s %10s %10s %8s",
			misc.ByteSize(procsByUsage[i].IOUsage()),
			truncate(procsByUsage[i].Comm(), 10),
			truncate(procsByUsage[i].User(), 10),
			procsByUsage[i].Pid()))
	}
	for i := n; i < DisplayPidCount; i++ {
		io = append(io, fmt.Sprintf("%8s/s %10s %10s %8s", "-", "-", "-", "-"))
	}
	displayList(batchmode, "io", layout, io)
	// Print top-N diskIO usage
	// disk stats
	diskIOByUsage := stats.dstat.ByUsage()
	var diskio []string
	// TODO(syamp): remove magic number
	for i := 0; i < 5; i++ {
		diskName := "-"
		diskIO := 0.0
		if len(diskIOByUsage) > i {
			d := diskIOByUsage[i]
			diskName = d.Name
			diskIO = d.Usage()
		}
		diskio = append(diskio, fmt.Sprintf("%6s %5s", diskName, fmt.Sprintf("%3.1f%% ", diskIO)))
	}
	displayList(batchmode, "diskio", layout, diskio)
	// Print top-N File system  usage
	// disk stats
	fsByUsage := stats.fsstat.ByUsage()
	var fs []string
	// TODO(syamp): remove magic number
	for i := 0; i < 5; i++ {
		fsName := "-"
		fsUsage := 0.0
		fsInodes := 0.0
		if len(fsByUsage) > i {
			f := fsByUsage[i]
			fsName = f.Name
			fsUsage = f.Usage()
			fsInodes = f.FileUsage()
		}
		fs = append(fs, fmt.Sprintf("%20s %6s i:%6s", truncate(fsName, 20),
			fmt.Sprintf("%3.1f%%", fsUsage),
			fmt.Sprintf("%3.1f%%", fsInodes)))
	}
	displayList(batchmode, "filesystem", layout, fs)
	// Detect potential problems for disk/fs
	for _, d := range diskIOByUsage {
		if d.Usage() > 75.0 {
			stats.osind.Problems = append(stats.osind.Problems,
				fmt.Sprintf("Disk IO usage on (%v): %3.1f%%", d.Name, d.Usage()))
		}
	}
	for _, fs := range fsByUsage {
		if fs.Usage() > 90.0 {
			stats.osind.Problems = append(stats.osind.Problems,
				fmt.Sprintf("FS block usage on (%v): %3.1f%%", fs.Name, fs.Usage()))
		}
		if fs.FileUsage() > 90.0 {
			stats.osind.Problems = append(stats.osind.Problems,
				fmt.Sprintf("FS inode usage on (%v): %3.1f%%", fs.Name, fs.FileUsage()))
		}
	}
	// Interface usage statistics
	var interfaces []string
	interfaceByUsage := stats.ifstat.ByUsage()
	for i := 0; i < 5; i++ {
		name := "-"
		var rx misc.BitSize
		var tx misc.BitSize
		if len(interfaceByUsage) > i {
			iface := interfaceByUsage[i]
			name = truncate(iface.Name, 10)
			rx = misc.BitSize(iface.TXBandwidth())
			tx = misc.BitSize(iface.RXBandwidth())
		}
		interfaces = append(interfaces, fmt.Sprintf("%10s r:%8s t:%8s\n", name, rx, tx))
	}
	for _, iface := range interfaceByUsage {
		if iface.TXBandwidthUsage() > 75.0 {
			stats.osind.Problems = append(stats.osind.Problems,
				fmt.Sprintf("TX bandwidth usage on (%v): %3.1f%%",
					iface.Name, iface.TXBandwidthUsage()))
		}
		if iface.RXBandwidthUsage() > 75.0 {
			stats.osind.Problems = append(stats.osind.Problems,
				fmt.Sprintf("RX bandwidth usage on (%v): %3.1f%%",
					iface.Name, iface.RXBandwidthUsage()))
		}
	}
	displayList(batchmode, "interface", layout, interfaces)
	// CPU stats by cgroup
	// TODO(syamp): should be sorted by quota usage
	var cgcpu, keys []string
	for name := range stats.cgCPU.Cgroups {
		keys = append(keys, name)
	}
	sort.Strings(keys)
	for _, name := range keys {
		v, ok := stats.cgCPU.Cgroups[name]
		if ok {
			name, _ = filepath.Rel(stats.cgCPU.Mountpoint, name)
			cpuUsagePct := (v.Usage() / stats.osind.CPUStat.Total()) * 100
			cpuQuotaPct := (v.Usage() / v.Quota()) * 100
			cpuThrottle := v.Throttle() * 100
			cgcpu = append(cgcpu, fmt.Sprintf("%20s %5s %6s %5s",
				truncate(name, 20),
				fmt.Sprintf("%3.1f%%", cpuUsagePct),
				fmt.Sprintf("q:%3.1f", v.Quota()),
				fmt.Sprintf("qpct:%3.1f%%", cpuQuotaPct)))
			if cpuThrottle > 0.1 {
				stats.osind.Problems =
					append(stats.osind.Problems, fmt.Sprintf(
						"CPU throttling on cgroup(%s): %3.1f%%",
						name, cpuThrottle))
			}
		}
	}
	displayList(batchmode, "cpu(cgroup)", layout, cgcpu)

	// Memory stats by cgroup
	// TODO(syamp): should be sorted by usage
	var cgmem []string
	keys = keys[:0]
	for name := range stats.cgMem.Cgroups {
		keys = append(keys, name)
	}
	sort.Strings(keys)
	for _, name := range keys {
		v, ok := stats.cgMem.Cgroups[name]
		if ok {
			name, _ = filepath.Rel(stats.cgMem.Mountpoint, name)
			memUsagePct := (v.Usage() / stats.osind.MemStat.Total()) * 100
			memQuota := v.SoftLimit()
			if memQuota > stats.osind.MemStat.Total() {
				memQuota = stats.osind.MemStat.Total()
			}
			memQuotaPct := (v.Usage() / v.SoftLimit()) * 100
			cgmem = append(cgmem, fmt.Sprintf("%20s %5s %10s %5s",
				truncate(name, 20),
				fmt.Sprintf("%3.1f%%", memUsagePct),
				fmt.Sprintf("q:%8s", misc.ByteSize(memQuota)),
				fmt.Sprintf("qpct:%3.1f%%", memQuotaPct)))
			if memQuotaPct > 75 {
				stats.osind.Problems =
					append(stats.osind.Problems, fmt.Sprintf(
						"Memory close to quota on cgroup(%s): %3.1f%%",
						name, memQuotaPct))
			}
		}
	}
	displayList(batchmode, "memory(cgroup)", layout, cgmem)
}
<commit_msg>remove extraneous newline<commit_after>// Copyright (c) 2014 Square, Inc
// +build linux

package osmain

import (
	"fmt"
	//"math"
	"log"
	"path/filepath"
	"sort"
	"time"

	"github.com/square/inspect/metrics"
	"github.com/square/inspect/os/cpustat"
	"github.com/square/inspect/os/diskstat"
	"github.com/square/inspect/os/fsstat"
	"github.com/square/inspect/os/interfacestat"
	"github.com/square/inspect/os/loadstat"
	"github.com/square/inspect/os/memstat"
	"github.com/square/inspect/os/misc"
	"github.com/square/inspect/os/tcpstat"
)

type linuxStats struct {
	osind    *Stats
	dstat    *diskstat.DiskStat
	fsstat   *fsstat.FSStat
	ifstat   *interfacestat.InterfaceStat
	tcpstat  *tcpstat.TCPStat
	cgMem    *memstat.CgroupStat
	cgCPU    *cpustat.CgroupStat
	loadstat *loadstat.LoadStat
}

// RegisterOsSpecific registers OS dependent statistics
func registerOsSpecific(m *metrics.MetricContext, step time.Duration,
	osind *Stats) *linuxStats {
	s := new(linuxStats)
	s.osind = osind
	s.dstat = diskstat.New(m, step)
	s.fsstat = fsstat.New(m, step)
	s.ifstat = interfacestat.New(m, step)
	s.tcpstat = tcpstat.New(m, step)
	s.loadstat = loadstat.New(m, step)
	s.cgMem = memstat.NewCgroupStat(m, step)
	s.cgCPU = cpustat.NewCgroupStat(m, step)
	return s
}

// PrintOsSpecific prints OS dependent statistics
func printOsSpecific(batchmode bool, layout *DisplayWidgets, v interface{}) {
	stats, ok := v.(*linuxStats)
	if !ok {
		log.Fatalf("Type assertion failed on printOsSpecific")
	}
	// Top N processes sorted by IO usage - requires root
	procsByUsage := stats.osind.ProcessStat.ByIOUsage()
	n := DisplayPidCount
	if len(procsByUsage) < n {
		n = len(procsByUsage)
	}
	var io []string
	for i := 0; i < n; i++ {
		io = append(io, fmt.Sprintf("%8s/s %10s %10s %8s",
			misc.ByteSize(procsByUsage[i].IOUsage()),
			truncate(procsByUsage[i].Comm(), 10),
			truncate(procsByUsage[i].User(), 10),
			procsByUsage[i].Pid()))
	}
	for i := n; i < DisplayPidCount; i++ {
		io = append(io, fmt.Sprintf("%8s/s %10s %10s %8s", "-", "-", "-", "-"))
	}
	displayList(batchmode, "io", layout, io)
	// Print top-N diskIO usage
	// disk stats
	diskIOByUsage := stats.dstat.ByUsage()
	var diskio []string
	// TODO(syamp): remove magic number
	for i := 0; i < 5; i++ {
		diskName := "-"
		diskIO := 0.0
		if len(diskIOByUsage) > i {
			d := diskIOByUsage[i]
			diskName = d.Name
			diskIO = d.Usage()
		}
		diskio = append(diskio, fmt.Sprintf("%6s %5s", diskName, fmt.Sprintf("%3.1f%% ", diskIO)))
	}
	displayList(batchmode, "diskio", layout, diskio)
	// Print top-N File system  usage
	// disk stats
	fsByUsage := stats.fsstat.ByUsage()
	var fs []string
	// TODO(syamp): remove magic number
	for i := 0; i < 5; i++ {
		fsName := "-"
		fsUsage := 0.0
		fsInodes := 0.0
		if len(fsByUsage) > i {
			f := fsByUsage[i]
			fsName = f.Name
			fsUsage = f.Usage()
			fsInodes = f.FileUsage()
		}
		fs = append(fs, fmt.Sprintf("%20s %6s i:%6s", truncate(fsName, 20),
			fmt.Sprintf("%3.1f%%", fsUsage),
			fmt.Sprintf("%3.1f%%", fsInodes)))
	}
	displayList(batchmode, "filesystem", layout, fs)
	// Detect potential problems for disk/fs
	for _, d := range diskIOByUsage {
		if d.Usage() > 75.0 {
			stats.osind.Problems = append(stats.osind.Problems,
				fmt.Sprintf("Disk IO usage on (%v): %3.1f%%", d.Name, d.Usage()))
		}
	}
	for _, fs := range fsByUsage {
		if fs.Usage() > 90.0 {
			stats.osind.Problems = append(stats.osind.Problems,
				fmt.Sprintf("FS block usage on (%v): %3.1f%%", fs.Name, fs.Usage()))
		}
		if fs.FileUsage() > 90.0 {
			stats.osind.Problems = append(stats.osind.Problems,
				fmt.Sprintf("FS inode usage on (%v): %3.1f%%", fs.Name, fs.FileUsage()))
		}
	}
	// Interface usage statistics
	var interfaces []string
	interfaceByUsage := stats.ifstat.ByUsage()
	for i := 0; i < 5; i++ {
		name := "-"
		var rx misc.BitSize
		var tx misc.BitSize
		if len(interfaceByUsage) > i {
			iface := interfaceByUsage[i]
			name = truncate(iface.Name, 10)
			rx = misc.BitSize(iface.TXBandwidth())
			tx = misc.BitSize(iface.RXBandwidth())
		}
		interfaces = append(interfaces, fmt.Sprintf("%10s r:%8s t:%8s", name, rx, tx))
	}
	for _, iface := range interfaceByUsage {
		if iface.TXBandwidthUsage() > 75.0 {
			stats.osind.Problems = append(stats.osind.Problems,
				fmt.Sprintf("TX bandwidth usage on (%v): %3.1f%%",
					iface.Name, iface.TXBandwidthUsage()))
		}
		if iface.RXBandwidthUsage() > 75.0 {
			stats.osind.Problems = append(stats.osind.Problems,
				fmt.Sprintf("RX bandwidth usage on (%v): %3.1f%%",
					iface.Name, iface.RXBandwidthUsage()))
		}
	}
	displayList(batchmode, "interface", layout, interfaces)
	// CPU stats by cgroup
	// TODO(syamp): should be sorted by quota usage
	var cgcpu, keys []string
	for name := range stats.cgCPU.Cgroups {
		keys = append(keys, name)
	}
	sort.Strings(keys)
	for _, name := range keys {
		v, ok := stats.cgCPU.Cgroups[name]
		if ok {
			name, _ = filepath.Rel(stats.cgCPU.Mountpoint, name)
			cpuUsagePct := (v.Usage() / stats.osind.CPUStat.Total()) * 100
			cpuQuotaPct := (v.Usage() / v.Quota()) * 100
			cpuThrottle := v.Throttle() * 100
			cgcpu = append(cgcpu, fmt.Sprintf("%20s %5s %6s %5s",
				truncate(name, 20),
				fmt.Sprintf("%3.1f%%", cpuUsagePct),
				fmt.Sprintf("q:%3.1f", v.Quota()),
				fmt.Sprintf("qpct:%3.1f%%", cpuQuotaPct)))
			if cpuThrottle > 0.1 {
				stats.osind.Problems =
					append(stats.osind.Problems, fmt.Sprintf(
						"CPU throttling on cgroup(%s): %3.1f%%",
						name, cpuThrottle))
			}
		}
	}
	displayList(batchmode, "cpu(cgroup)", layout, cgcpu)

	// Memory stats by cgroup
	// TODO(syamp): should be sorted by usage
	var cgmem []string
	keys = keys[:0]
	for name := range stats.cgMem.Cgroups {
		keys = append(keys, name)
	}
	sort.Strings(keys)
	for _, name := range keys {
		v, ok := stats.cgMem.Cgroups[name]
		if ok {
			name, _ = filepath.Rel(stats.cgMem.Mountpoint, name)
			memUsagePct := (v.Usage() / stats.osind.MemStat.Total()) * 100
			memQuota := v.SoftLimit()
			if memQuota > stats.osind.MemStat.Total() {
				memQuota = stats.osind.MemStat.Total()
			}
			memQuotaPct := (v.Usage() / v.SoftLimit()) * 100
			cgmem = append(cgmem, fmt.Sprintf("%20s %5s %10s %5s",
				truncate(name, 20),
				fmt.Sprintf("%3.1f%%", memUsagePct),
				fmt.Sprintf("q:%8s", misc.ByteSize(memQuota)),
				fmt.Sprintf("qpct:%3.1f%%", memQuotaPct)))
			if memQuotaPct > 75 {
				stats.osind.Problems =
					append(stats.osind.Problems, fmt.Sprintf(
						"Memory close to quota on cgroup(%s): %3.1f%%",
						name, memQuotaPct))
			}
		}
	}
	displayList(batchmode, "memory(cgroup)", layout, cgmem)
}
<|endoftext|>


<commit_before>package instagram_scraper

import (
	"net/http"
	"io/ioutil"
	"fmt"
	"encoding/json"
	"log"
)

func GetAccoutByUsername(username string) (account Account) {
	url := fmt.Sprintf(ACCOUNT_JSON_INFO, username)
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode == 404 {
		log.Fatal("Page Not Found, Code 404")
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	var info map[string]interface{}
	err = json.Unmarshal(body, &info)
	if err != nil {
		log.Fatal(err)
	}

	account = GetFromAccountPage(info)
	return account
}

func GetMedyaByUrl(url string) (media Media) {
	url += "?__a=1"
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode == 404 {
		log.Fatal("Page Not Found, Code 404")
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	var info map[string]interface{}
	err = json.Unmarshal(body, &info)
	if err != nil {
		log.Fatal(err)
	}

	media = GetFromMediaPage(info)

	return
}
<commit_msg>Get json in another func<commit_after>package instagram_scraper

import (
	"net/http"
	"io/ioutil"
	"fmt"
	"encoding/json"
	"log"
)

func GetAccoutByUsername(username string) (account Account) {
	url := fmt.Sprintf(ACCOUNT_JSON_INFO, username)
	info := _GetJsonFromUrl(url)
	account = GetFromAccountPage(info)
	return account
}

func GetMedyaByUrl(url string) (media Media) {
	url += "?__a=1"
	info := _GetJsonFromUrl(url)
	media = GetFromMediaPage(info)
	return
}

func _GetJsonFromUrl(url string) (json_body map[string]interface{}) {
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode == 404 {
		log.Fatal("Page Not Found, Code 404")
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	err = json.Unmarshal(body, &json_body)
	if err != nil {
		log.Fatal(err)
	}

	return
}
<|endoftext|>


<commit_before>package discordgo

import (
	"encoding/json"
	"fmt"
)

// ComponentType is type of component.
type ComponentType uint

// MessageComponent types.
const (
	ActionsRowComponent ComponentType = 1
	ButtonComponent     ComponentType = 2
	SelectMenuComponent ComponentType = 3
	TextInputComponent  ComponentType = 4
)

// MessageComponent is a base interface for all message components.
type MessageComponent interface {
	json.Marshaler
	Type() ComponentType
}

type unmarshalableMessageComponent struct {
	MessageComponent
}

// UnmarshalJSON is a helper function to unmarshal MessageComponent object.
func (umc *unmarshalableMessageComponent) UnmarshalJSON(src []byte) error {
	var v struct {
		Type ComponentType `json:"type"`
	}
	err := json.Unmarshal(src, &v)
	if err != nil {
		return err
	}

	switch v.Type {
	case ActionsRowComponent:
		umc.MessageComponent = &ActionsRow{}
	case ButtonComponent:
		umc.MessageComponent = &Button{}
	case SelectMenuComponent:
		umc.MessageComponent = &SelectMenu{}
	case TextInputComponent:
		umc.MessageComponent = &TextInput{}
	default:
		return fmt.Errorf("unknown component type: %d", v.Type)
	}
	return json.Unmarshal(src, umc.MessageComponent)
}

// MessageComponentFromJSON is a helper function for unmarshaling message components
func MessageComponentFromJSON(b []byte) (MessageComponent, error) {
	var u unmarshalableMessageComponent
	err := u.UnmarshalJSON(b)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal into MessageComponent: %w", err)
	}
	return u.MessageComponent, nil
}

// ActionsRow is a container for components within one row.
type ActionsRow struct {
	Components []MessageComponent `json:"components"`
}

// MarshalJSON is a method for marshaling ActionsRow to a JSON object.
func (r ActionsRow) MarshalJSON() ([]byte, error) {
	type actionsRow ActionsRow

	return json.Marshal(struct {
		actionsRow
		Type ComponentType `json:"type"`
	}{
		actionsRow: actionsRow(r),
		Type:       r.Type(),
	})
}

// UnmarshalJSON is a helper function to unmarshal Actions Row.
func (r *ActionsRow) UnmarshalJSON(data []byte) error {
	var v struct {
		RawComponents []unmarshalableMessageComponent `json:"components"`
	}
	err := json.Unmarshal(data, &v)
	if err != nil {
		return err
	}
	r.Components = make([]MessageComponent, len(v.RawComponents))
	for i, v := range v.RawComponents {
		r.Components[i] = v.MessageComponent
	}

	return err
}

// Type is a method to get the type of a component.
func (r ActionsRow) Type() ComponentType {
	return ActionsRowComponent
}

// ButtonStyle is style of button.
type ButtonStyle uint

// Button styles.
const (
	// PrimaryButton is a button with blurple color.
	PrimaryButton ButtonStyle = 1
	// SecondaryButton is a button with grey color.
	SecondaryButton ButtonStyle = 2
	// SuccessButton is a button with green color.
	SuccessButton ButtonStyle = 3
	// DangerButton is a button with red color.
	DangerButton ButtonStyle = 4
	// LinkButton is a special type of button which navigates to a URL. Has grey color.
	LinkButton ButtonStyle = 5
)

// ComponentEmoji represents button emoji, if it does have one.
type ComponentEmoji struct {
	Name     string `json:"name,omitempty"`
	ID       string `json:"id,omitempty"`
	Animated bool   `json:"animated,omitempty"`
}

// Button represents button component.
type Button struct {
	Label    string         `json:"label"`
	Style    ButtonStyle    `json:"style"`
	Disabled bool           `json:"disabled"`
	Emoji    ComponentEmoji `json:"emoji"`

	// NOTE: Only button with LinkButton style can have link. Also, URL is mutually exclusive with CustomID.
	URL      string `json:"url,omitempty"`
	CustomID string `json:"custom_id,omitempty"`
}

// MarshalJSON is a method for marshaling Button to a JSON object.
func (b Button) MarshalJSON() ([]byte, error) {
	type button Button

	if b.Style == 0 {
		b.Style = PrimaryButton
	}

	return json.Marshal(struct {
		button
		Type ComponentType `json:"type"`
	}{
		button: button(b),
		Type:   b.Type(),
	})
}

// Type is a method to get the type of a component.
func (Button) Type() ComponentType {
	return ButtonComponent
}

// SelectMenuOption represents an option for a select menu.
type SelectMenuOption struct {
	Label       string         `json:"label,omitempty"`
	Value       string         `json:"value"`
	Description string         `json:"description"`
	Emoji       ComponentEmoji `json:"emoji"`
	// Determines whenever option is selected by default or not.
	Default bool `json:"default"`
}

// SelectMenu represents select menu component.
type SelectMenu struct {
	CustomID string `json:"custom_id,omitempty"`
	// The text which will be shown in the menu if there's no default options or all options was deselected and component was closed.
	Placeholder string `json:"placeholder"`
	// This value determines the minimal amount of selected items in the menu.
	MinValues int `json:"min_values,omitempty"`
	// This value determines the maximal amount of selected items in the menu.
	// If MaxValues or MinValues are greater than one then the user can select multiple items in the component.
	MaxValues int                `json:"max_values,omitempty"`
	Options   []SelectMenuOption `json:"options"`
}

// Type is a method to get the type of a component.
func (SelectMenu) Type() ComponentType {
	return SelectMenuComponent
}

// MarshalJSON is a method for marshaling SelectMenu to a JSON object.
func (m SelectMenu) MarshalJSON() ([]byte, error) {
	type selectMenu SelectMenu

	return json.Marshal(struct {
		selectMenu
		Type ComponentType `json:"type"`
	}{
		selectMenu: selectMenu(m),
		Type:       m.Type(),
	})
}

// TextInput represents text input component.
type TextInput struct {
	CustomID    string         `json:"custom_id"`
	Label       string         `json:"label"`
	Style       TextInputStyle `json:"style"`
	Placeholder string         `json:"placeholder,omitempty"`
	Value       string         `json:"value,omitempty"`
	Required    bool           `json:"required,omitempty"`
	MinLength   int            `json:"min_length,omitempty"`
	MaxLength   int            `json:"max_length,omitempty"`
}

// Type is a method to get the type of a component.
func (TextInput) Type() ComponentType {
	return TextInputComponent
}

// MarshalJSON is a method for marshaling TextInput to a JSON object.
func (m TextInput) MarshalJSON() ([]byte, error) {
	type inputText TextInput

	return json.Marshal(struct {
		inputText
		Type ComponentType `json:"type"`
	}{
		inputText: inputText(m),
		Type:      m.Type(),
	})
}

// TextInputStyle is style of text in TextInput component.
type TextInputStyle uint

// Text styles
const (
	TextInputShort     TextInputStyle = 1
	TextInputParagraph TextInputStyle = 2
)
<commit_msg>add disable prop to selectMenu (#1102)<commit_after>package discordgo

import (
	"encoding/json"
	"fmt"
)

// ComponentType is type of component.
type ComponentType uint

// MessageComponent types.
const (
	ActionsRowComponent ComponentType = 1
	ButtonComponent     ComponentType = 2
	SelectMenuComponent ComponentType = 3
	TextInputComponent  ComponentType = 4
)

// MessageComponent is a base interface for all message components.
type MessageComponent interface {
	json.Marshaler
	Type() ComponentType
}

type unmarshalableMessageComponent struct {
	MessageComponent
}

// UnmarshalJSON is a helper function to unmarshal MessageComponent object.
func (umc *unmarshalableMessageComponent) UnmarshalJSON(src []byte) error {
	var v struct {
		Type ComponentType `json:"type"`
	}
	err := json.Unmarshal(src, &v)
	if err != nil {
		return err
	}

	switch v.Type {
	case ActionsRowComponent:
		umc.MessageComponent = &ActionsRow{}
	case ButtonComponent:
		umc.MessageComponent = &Button{}
	case SelectMenuComponent:
		umc.MessageComponent = &SelectMenu{}
	case TextInputComponent:
		umc.MessageComponent = &TextInput{}
	default:
		return fmt.Errorf("unknown component type: %d", v.Type)
	}
	return json.Unmarshal(src, umc.MessageComponent)
}

// MessageComponentFromJSON is a helper function for unmarshaling message components
func MessageComponentFromJSON(b []byte) (MessageComponent, error) {
	var u unmarshalableMessageComponent
	err := u.UnmarshalJSON(b)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal into MessageComponent: %w", err)
	}
	return u.MessageComponent, nil
}

// ActionsRow is a container for components within one row.
type ActionsRow struct {
	Components []MessageComponent `json:"components"`
}

// MarshalJSON is a method for marshaling ActionsRow to a JSON object.
func (r ActionsRow) MarshalJSON() ([]byte, error) {
	type actionsRow ActionsRow

	return json.Marshal(struct {
		actionsRow
		Type ComponentType `json:"type"`
	}{
		actionsRow: actionsRow(r),
		Type:       r.Type(),
	})
}

// UnmarshalJSON is a helper function to unmarshal Actions Row.
func (r *ActionsRow) UnmarshalJSON(data []byte) error {
	var v struct {
		RawComponents []unmarshalableMessageComponent `json:"components"`
	}
	err := json.Unmarshal(data, &v)
	if err != nil {
		return err
	}
	r.Components = make([]MessageComponent, len(v.RawComponents))
	for i, v := range v.RawComponents {
		r.Components[i] = v.MessageComponent
	}

	return err
}

// Type is a method to get the type of a component.
func (r ActionsRow) Type() ComponentType {
	return ActionsRowComponent
}

// ButtonStyle is style of button.
type ButtonStyle uint

// Button styles.
const (
	// PrimaryButton is a button with blurple color.
	PrimaryButton ButtonStyle = 1
	// SecondaryButton is a button with grey color.
	SecondaryButton ButtonStyle = 2
	// SuccessButton is a button with green color.
	SuccessButton ButtonStyle = 3
	// DangerButton is a button with red color.
	DangerButton ButtonStyle = 4
	// LinkButton is a special type of button which navigates to a URL. Has grey color.
	LinkButton ButtonStyle = 5
)

// ComponentEmoji represents button emoji, if it does have one.
type ComponentEmoji struct {
	Name     string `json:"name,omitempty"`
	ID       string `json:"id,omitempty"`
	Animated bool   `json:"animated,omitempty"`
}

// Button represents button component.
type Button struct {
	Label    string         `json:"label"`
	Style    ButtonStyle    `json:"style"`
	Disabled bool           `json:"disabled"`
	Emoji    ComponentEmoji `json:"emoji"`

	// NOTE: Only button with LinkButton style can have link. Also, URL is mutually exclusive with CustomID.
	URL      string `json:"url,omitempty"`
	CustomID string `json:"custom_id,omitempty"`
}

// MarshalJSON is a method for marshaling Button to a JSON object.
func (b Button) MarshalJSON() ([]byte, error) {
	type button Button

	if b.Style == 0 {
		b.Style = PrimaryButton
	}

	return json.Marshal(struct {
		button
		Type ComponentType `json:"type"`
	}{
		button: button(b),
		Type:   b.Type(),
	})
}

// Type is a method to get the type of a component.
func (Button) Type() ComponentType {
	return ButtonComponent
}

// SelectMenuOption represents an option for a select menu.
type SelectMenuOption struct {
	Label       string         `json:"label,omitempty"`
	Value       string         `json:"value"`
	Description string         `json:"description"`
	Emoji       ComponentEmoji `json:"emoji"`
	// Determines whenever option is selected by default or not.
	Default bool `json:"default"`
}

// SelectMenu represents select menu component.
type SelectMenu struct {
	CustomID string `json:"custom_id,omitempty"`
	// The text which will be shown in the menu if there's no default options or all options was deselected and component was closed.
	Placeholder string `json:"placeholder"`
	// This value determines the minimal amount of selected items in the menu.
	MinValues int `json:"min_values,omitempty"`
	// This value determines the maximal amount of selected items in the menu.
	// If MaxValues or MinValues are greater than one then the user can select multiple items in the component.
	MaxValues int                `json:"max_values,omitempty"`
	Options   []SelectMenuOption `json:"options"`
	Disabled  bool               `json:"disabled"`
}

// Type is a method to get the type of a component.
func (SelectMenu) Type() ComponentType {
	return SelectMenuComponent
}

// MarshalJSON is a method for marshaling SelectMenu to a JSON object.
func (m SelectMenu) MarshalJSON() ([]byte, error) {
	type selectMenu SelectMenu

	return json.Marshal(struct {
		selectMenu
		Type ComponentType `json:"type"`
	}{
		selectMenu: selectMenu(m),
		Type:       m.Type(),
	})
}

// TextInput represents text input component.
type TextInput struct {
	CustomID    string         `json:"custom_id"`
	Label       string         `json:"label"`
	Style       TextInputStyle `json:"style"`
	Placeholder string         `json:"placeholder,omitempty"`
	Value       string         `json:"value,omitempty"`
	Required    bool           `json:"required,omitempty"`
	MinLength   int            `json:"min_length,omitempty"`
	MaxLength   int            `json:"max_length,omitempty"`
}

// Type is a method to get the type of a component.
func (TextInput) Type() ComponentType {
	return TextInputComponent
}

// MarshalJSON is a method for marshaling TextInput to a JSON object.
func (m TextInput) MarshalJSON() ([]byte, error) {
	type inputText TextInput

	return json.Marshal(struct {
		inputText
		Type ComponentType `json:"type"`
	}{
		inputText: inputText(m),
		Type:      m.Type(),
	})
}

// TextInputStyle is style of text in TextInput component.
type TextInputStyle uint

// Text styles
const (
	TextInputShort     TextInputStyle = 1
	TextInputParagraph TextInputStyle = 2
)
<|endoftext|>


<commit_before>package helpers

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"strings"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"
)

const (
	DebugCommandPrefix = "\nCMD>"
	DebugOutPrefix     = "OUT: "
	DebugErrPrefix     = "ERR: "
)

func CF(args ...string) *Session {
	WriteCommand(nil, args)
	session, err := Start(
		exec.Command("cf", args...),
		NewPrefixedWriter(DebugOutPrefix, GinkgoWriter),
		NewPrefixedWriter(DebugErrPrefix, GinkgoWriter))
	Expect(err).NotTo(HaveOccurred())
	return session
}

type CFEnv struct {
	WorkingDirectory string
	EnvVars          map[string]string
	stdin            io.Reader
}

func CustomCF(cfEnv CFEnv, args ...string) *Session {
	command := exec.Command("cf", args...)
	if cfEnv.stdin != nil {
		command.Stdin = cfEnv.stdin
	}
	if cfEnv.WorkingDirectory != "" {
		command.Dir = cfEnv.WorkingDirectory
	}

	if cfEnv.EnvVars != nil {
		env := os.Environ()
		for key, val := range cfEnv.EnvVars {
			env = AddOrReplaceEnvironment(env, key, val)
		}
		command.Env = env
	}

	WriteCommand(cfEnv.EnvVars, args)
	session, err := Start(
		command,
		NewPrefixedWriter(DebugOutPrefix, GinkgoWriter),
		NewPrefixedWriter(DebugErrPrefix, GinkgoWriter))
	Expect(err).NotTo(HaveOccurred())
	return session
}

func DebugCustomCF(cfEnv CFEnv, args ...string) *Session {
	if cfEnv.EnvVars == nil {
		cfEnv.EnvVars = map[string]string{}
	}
	cfEnv.EnvVars["CF_LOG_LEVEL"] = "debug"

	return CustomCF(cfEnv, args...)
}

func CFWithStdin(stdin io.Reader, args ...string) *Session {
	WriteCommand(nil, args)
	command := exec.Command("cf", args...)
	command.Stdin = stdin
	session, err := Start(
		command,
		NewPrefixedWriter(DebugOutPrefix, GinkgoWriter),
		NewPrefixedWriter(DebugErrPrefix, GinkgoWriter))
	Expect(err).NotTo(HaveOccurred())
	return session
}

func CFWithEnv(envVars map[string]string, args ...string) *Session {
	return CustomCF(CFEnv{EnvVars: envVars}, args...)
}

func WriteCommand(env map[string]string, args []string) {
	display := []string{
		DebugCommandPrefix,
	}

	isPass := regexp.MustCompile("(?i)password|token")
	for key, val := range env {
		if isPass.MatchString(key) {
			val = "*****"
		}
		display = append(display, fmt.Sprintf("%s=%s", key, val))
	}

	display = append(display, "cf")
	display = append(display, args...)
	GinkgoWriter.Write([]byte(strings.Join(append(display, "\n"), " ")))
}
<commit_msg>Remove empty arguments from integration helper<commit_after>package helpers

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"strings"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"
)

const (
	DebugCommandPrefix = "\nCMD>"
	DebugOutPrefix     = "OUT: "
	DebugErrPrefix     = "ERR: "
)

func CF(args ...string) *Session {
	WriteCommand(nil, args)
	args = removeEmptyArgs(args)
	session, err := Start(
		exec.Command("cf", args...),
		NewPrefixedWriter(DebugOutPrefix, GinkgoWriter),
		NewPrefixedWriter(DebugErrPrefix, GinkgoWriter))
	Expect(err).NotTo(HaveOccurred())
	return session
}

type CFEnv struct {
	WorkingDirectory string
	EnvVars          map[string]string
	stdin            io.Reader
}

func CustomCF(cfEnv CFEnv, args ...string) *Session {
	command := exec.Command("cf", args...)
	if cfEnv.stdin != nil {
		command.Stdin = cfEnv.stdin
	}
	if cfEnv.WorkingDirectory != "" {
		command.Dir = cfEnv.WorkingDirectory
	}

	if cfEnv.EnvVars != nil {
		env := os.Environ()
		for key, val := range cfEnv.EnvVars {
			env = AddOrReplaceEnvironment(env, key, val)
		}
		command.Env = env
	}

	WriteCommand(cfEnv.EnvVars, args)
	session, err := Start(
		command,
		NewPrefixedWriter(DebugOutPrefix, GinkgoWriter),
		NewPrefixedWriter(DebugErrPrefix, GinkgoWriter))
	Expect(err).NotTo(HaveOccurred())
	return session
}

func DebugCustomCF(cfEnv CFEnv, args ...string) *Session {
	if cfEnv.EnvVars == nil {
		cfEnv.EnvVars = map[string]string{}
	}
	cfEnv.EnvVars["CF_LOG_LEVEL"] = "debug"

	return CustomCF(cfEnv, args...)
}

func CFWithStdin(stdin io.Reader, args ...string) *Session {
	WriteCommand(nil, args)
	command := exec.Command("cf", args...)
	command.Stdin = stdin
	session, err := Start(
		command,
		NewPrefixedWriter(DebugOutPrefix, GinkgoWriter),
		NewPrefixedWriter(DebugErrPrefix, GinkgoWriter))
	Expect(err).NotTo(HaveOccurred())
	return session
}

func CFWithEnv(envVars map[string]string, args ...string) *Session {
	return CustomCF(CFEnv{EnvVars: envVars}, args...)
}

func WriteCommand(env map[string]string, args []string) {
	display := []string{
		DebugCommandPrefix,
	}

	isPass := regexp.MustCompile("(?i)password|token")
	for key, val := range env {
		if isPass.MatchString(key) {
			val = "*****"
		}
		display = append(display, fmt.Sprintf("%s=%s", key, val))
	}

	display = append(display, "cf")
	display = append(display, args...)
	GinkgoWriter.Write([]byte(strings.Join(append(display, "\n"), " ")))
}

func removeEmptyArgs(args []string) []string {
	returnArgs := make([]string, 0, len(args))

	for _, arg := range args {
		if arg != "" {
			returnArgs = append(returnArgs, arg)
		}
	}
	return returnArgs
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package transport

import (
	log "github.com/Sirupsen/logrus"
	"time"

	"github.com/runtimeinc/gatt"

	"mynewt.apache.org/newt/newtmgr/config"
	"mynewt.apache.org/newt/util"
)

/* This is used by different command handlers */
var BleMTU uint16 = 180

var rxBLEPkt = make(chan []byte)
var CharDisc = make(chan bool)

var newtmgrServiceId = gatt.MustParseUUID("8D53DC1D-1DB7-4CD3-868B-8A527460AA84")
var newtmgrServiceCharId = gatt.MustParseUUID("DA2E7828-FBCE-4E01-AE9E-261174997C48")
var deviceName string
var deviceAddress []byte
var deviceAddressType uint8

type ConnBLE struct {
	connProfile   config.NewtmgrConnProfile
	currentPacket *Packet
	bleDevice     gatt.Device
	isOIC         bool
}

var deviceChar *gatt.Characteristic
var devicePerph gatt.Peripheral

var bleTxData []byte

func reverseBytes(arr []byte) []byte {
	if len(arr) == 0 {
		return arr
	}
	return append(reverseBytes(arr[1:]), arr[0])
}

func onStateChanged(d gatt.Device, s gatt.State) {
	log.Debugf("State:%+v", s)
	switch s {
	case gatt.StatePoweredOn:
		log.Debugf("scanning...")
		d.Scan([]gatt.UUID{}, false)
		return
	default:
		d.StopScanning()
	}
}

func onPeriphDiscovered(p gatt.Peripheral, a *gatt.Advertisement, rssi int) {
	var matched bool = false

	if len(deviceName) > 0 {
		matched = a.LocalName == deviceName
		if matched == false {
			return
		}
	}

	if len(deviceAddress) > 0 {
		var deviceAddrArr [6]byte
		copy(deviceAddrArr[:], deviceAddress[0:6])
		matched = a.Address == deviceAddrArr && a.AddressType == deviceAddressType
	}

	if matched == true {
		log.Debugf("Peripheral Discovered: %s, Address:%+v Address Type:%+v",
			p.Name(), a.Address, a.AddressType)
		p.Device().StopScanning()
		p.Device().Connect(p)
	}
}

func newtmgrNotifyCB(c *gatt.Characteristic, incomingDatabuf []byte, err error) {
	err = nil
	rxBLEPkt <- incomingDatabuf
	return
}

func onPeriphConnected(p gatt.Peripheral, err error) {
	log.Debugf("Peripheral Connected")

	services, err := p.DiscoverServices(nil)
	if err != nil {
		log.Debugf("Failed to discover services, err: %s", err)
		return
	}

	for _, service := range services {

		if service.UUID().Equal(newtmgrServiceId) {
			log.Debugf("Newtmgr Service Found %s", service.Name())

			cs, _ := p.DiscoverCharacteristics(nil, service)

			for _, c := range cs {
				if c.UUID().Equal(newtmgrServiceCharId) {
					log.Debugf("Newtmgr Characteristic Found")
					p.SetNotifyValue(c, newtmgrNotifyCB)
					deviceChar = c
					devicePerph = p
					p.SetMTU(BleMTU)
					<-CharDisc
				}
			}
		}
	}
}

func onPeriphDisconnected(p gatt.Peripheral, err error) {
	log.Debugf("Disconnected", err)
}

func (cs *ConnBLE) SetOICEncoded(b bool) {
	cs.isOIC = b
}

func (cs *ConnBLE) GetOICEncoded() bool {
	return cs.isOIC
}

func (cb *ConnBLE) Open(cp config.NewtmgrConnProfile, readTimeout time.Duration) error {
	var err error

	var DefaultClientOptions = BleOptions

	deviceName = cp.ConnString()
	deviceAddress = reverseBytes(cp.DeviceAddress())
	log.Debugf("BLE Connection devaddr:%+v", deviceAddress)
	deviceAddressType = cp.DeviceAddressType()
	cb.bleDevice, err = gatt.NewDevice(DefaultClientOptions...)
	if err != nil {
		return util.NewNewtError(err.Error())
	}

	cb.bleDevice.Handle(
		gatt.PeripheralDiscovered(onPeriphDiscovered),
		gatt.PeripheralConnected(onPeriphConnected),
		gatt.PeripheralDisconnected(onPeriphDisconnected),
	)
	cb.bleDevice.Init(onStateChanged)
	CharDisc <- true

	return nil
}

func (cb *ConnBLE) ReadPacket() (*Packet, error) {
	var err error

	bleRxData := <-rxBLEPkt

	cb.currentPacket, err = NewPacket(uint16(len(bleRxData)))
	if err != nil {
		return nil, err
	}

	cb.currentPacket.AddBytes(bleRxData)
	log.Debugf("Read BLE Packet:buf::%+v len::%+v", cb.currentPacket.buffer,
		cb.currentPacket.expectedLen)
	bleRxData = bleRxData[:0]
	pkt := cb.currentPacket
	cb.currentPacket = nil
	return pkt, err
}

func (cb *ConnBLE) writeData() error {
	devicePerph.WriteCharacteristic(deviceChar, bleTxData, true)
	return nil
}

func (cb *ConnBLE) WritePacket(pkt *Packet) error {
	log.Debugf("Write BLE Packet:buf::%+v len::%+v", pkt.buffer,
		pkt.expectedLen)
	bleTxData = pkt.GetBytes()
	cb.writeData()
	return nil
}

func (cb *ConnBLE) Close() error {
	log.Debugf("Closing Connection %+v", cb)
	return cb.bleDevice.Stop()
}
<commit_msg>newtmgr; also do oic with newtmgr over ble.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package transport

import (
	log "github.com/Sirupsen/logrus"
	"time"

	"github.com/runtimeinc/gatt"

	"mynewt.apache.org/newt/newtmgr/config"
	"mynewt.apache.org/newt/util"
)

/* This is used by different command handlers */
var BleMTU uint16 = 180

var rxBLEPkt = make(chan []byte)
var CharDisc = make(chan bool)

var newtmgrServiceId = gatt.MustParseUUID("8D53DC1D-1DB7-4CD3-868B-8A527460AA84")
var newtmgrServiceCharId = gatt.MustParseUUID("DA2E7828-FBCE-4E01-AE9E-261174997C48")

var newtmgrCoapServiceId = gatt.MustParseUUID("e3f9f9c4-8a83-4055-b647-728b769745d6")
var newtmgrCoapServiceCharId = gatt.MustParseUUID("e467fee6-d6bb-4956-94df-0090350631f5")

var deviceName string
var deviceAddress []byte
var deviceAddressType uint8

type ConnBLE struct {
	connProfile   config.NewtmgrConnProfile
	currentPacket *Packet
	bleDevice     gatt.Device
	isOIC         bool
}

var deviceChar *gatt.Characteristic
var devicePerph gatt.Peripheral

var bleTxData []byte

func reverseBytes(arr []byte) []byte {
	if len(arr) == 0 {
		return arr
	}
	return append(reverseBytes(arr[1:]), arr[0])
}

func onStateChanged(d gatt.Device, s gatt.State) {
	log.Debugf("State:%+v", s)
	switch s {
	case gatt.StatePoweredOn:
		log.Debugf("scanning...")
		d.Scan([]gatt.UUID{}, false)
		return
	default:
		d.StopScanning()
	}
}

func onPeriphDiscovered(p gatt.Peripheral, a *gatt.Advertisement, rssi int) {
	var matched bool = false

	if len(deviceName) > 0 {
		matched = a.LocalName == deviceName
		if matched == false {
			return
		}
	}

	if len(deviceAddress) > 0 {
		var deviceAddrArr [6]byte
		copy(deviceAddrArr[:], deviceAddress[0:6])
		matched = a.Address == deviceAddrArr && a.AddressType == deviceAddressType
	}

	if matched == true {
		log.Debugf("Peripheral Discovered: %s, Address:%+v Address Type:%+v",
			p.Name(), a.Address, a.AddressType)
		p.Device().StopScanning()
		p.Device().Connect(p)
	}
}

func newtmgrNotifyCB(c *gatt.Characteristic, incomingDatabuf []byte, err error) {
	err = nil
	rxBLEPkt <- incomingDatabuf
	return
}

func onPeriphConnected(p gatt.Peripheral, err error) {
	log.Debugf("Peripheral Connected")

	services, err := p.DiscoverServices(nil)
	if err != nil {
		log.Debugf("Failed to discover services, err: %s", err)
		return
	}

	var isCoap bool = false

	for _, service := range services {

		if service.UUID().Equal(newtmgrServiceId) ||
		   service.UUID().Equal(newtmgrCoapServiceId) {
			log.Debugf("Newtmgr Service Found %s", service.Name())

			if service.UUID().Equal(newtmgrCoapServiceId) {
				isCoap = true
			}

			cs, _ := p.DiscoverCharacteristics(nil, service)

			for _, c := range cs {
				if (isCoap == false &&
				    c.UUID().Equal(newtmgrServiceCharId)) ||
				   (isCoap == true &&
				    c.UUID().Equal(newtmgrCoapServiceCharId)) {
					log.Debugf("Newtmgr Characteristic Found")
					p.SetNotifyValue(c, newtmgrNotifyCB)
					deviceChar = c
					devicePerph = p
					p.SetMTU(BleMTU)
					<-CharDisc
				}
			}
		}
	}
}

func onPeriphDisconnected(p gatt.Peripheral, err error) {
	log.Debugf("Disconnected", err)
}

func (cs *ConnBLE) SetOICEncoded(b bool) {
	cs.isOIC = b
}

func (cs *ConnBLE) GetOICEncoded() bool {
	return cs.isOIC
}

func (cb *ConnBLE) Open(cp config.NewtmgrConnProfile, readTimeout time.Duration) error {
	var err error

	var DefaultClientOptions = BleOptions

	deviceName = cp.ConnString()
	deviceAddress = reverseBytes(cp.DeviceAddress())
	log.Debugf("BLE Connection devaddr:%+v", deviceAddress)
	deviceAddressType = cp.DeviceAddressType()
	cb.bleDevice, err = gatt.NewDevice(DefaultClientOptions...)
	if err != nil {
		return util.NewNewtError(err.Error())
	}

	cb.bleDevice.Handle(
		gatt.PeripheralDiscovered(onPeriphDiscovered),
		gatt.PeripheralConnected(onPeriphConnected),
		gatt.PeripheralDisconnected(onPeriphDisconnected),
	)
	cb.bleDevice.Init(onStateChanged)
	CharDisc <- true

	return nil
}

func (cb *ConnBLE) ReadPacket() (*Packet, error) {
	var err error

	bleRxData := <-rxBLEPkt

	cb.currentPacket, err = NewPacket(uint16(len(bleRxData)))
	if err != nil {
		return nil, err
	}

	cb.currentPacket.AddBytes(bleRxData)
	log.Debugf("Read BLE Packet:buf::%+v len::%+v", cb.currentPacket.buffer,
		cb.currentPacket.expectedLen)
	bleRxData = bleRxData[:0]
	pkt := cb.currentPacket
	cb.currentPacket = nil
	return pkt, err
}

func (cb *ConnBLE) writeData() error {
	devicePerph.WriteCharacteristic(deviceChar, bleTxData, true)
	return nil
}

func (cb *ConnBLE) WritePacket(pkt *Packet) error {
	log.Debugf("Write BLE Packet:buf::%+v len::%+v", pkt.buffer,
		pkt.expectedLen)
	bleTxData = pkt.GetBytes()
	cb.writeData()
	return nil
}

func (cb *ConnBLE) Close() error {
	log.Debugf("Closing Connection %+v", cb)
	return cb.bleDevice.Stop()
}
<|endoftext|>


<commit_before>/*
 * publisher_connector_test.go
 *
 * Copyright 2017 Bill Zissimopoulos
 */
/*
 * This file is part of netchan.
 *
 * It is licensed under the MIT license. The full license text can be found
 * in the License.txt file at the root of this project.
 */

package netchan

import (
	"net/url"
	"strconv"
	"sync"
	"testing"
	"time"
)

func testPublisherConnector(t *testing.T, publisher Publisher, connector Connector) {
	pchan := make(chan string)
	cchan := make(chan string)
	echan := make(chan error)

	err := publisher.Publish("one", pchan)
	if nil != err {
		panic(err)
	}

	err = connector.Connect(
		&url.URL{
			Scheme: "tcp",
			Host:   "127.0.0.1",
			Path:   "one",
		},
		cchan,
		echan)
	if nil != err {
		panic(err)
	}

	cchan <- "fortytwo"

	close(cchan)

	s := <-pchan
	if "fortytwo" != s {
		t.Errorf("incorrect msg: expect %v, got %v", "fortytwo", s)
	}

	publisher.Unpublish("one", pchan)
}

func TestPublisherConnector(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
		time.Sleep(100 * time.Millisecond)
		transport.Close()
		time.Sleep(100 * time.Millisecond)
	}()

	testPublisherConnector(t, publisher, connector)
}

func testPublisherConnectorUri(t *testing.T, publisher Publisher, connector Connector) {
	pchan := make(chan string)
	cchan := make(chan string)
	echan := make(chan error)

	err := publisher.Publish("one", pchan)
	if nil != err {
		panic(err)
	}

	err = connector.Connect("tcp://127.0.0.1/one", cchan, echan)
	if nil != err {
		panic(err)
	}

	cchan <- "fortytwo"

	close(cchan)

	s := <-pchan
	if "fortytwo" != s {
		t.Errorf("incorrect msg: expect %v, got %v", "fortytwo", s)
	}

	publisher.Unpublish("one", pchan)
}

func TestPublisherConnectorUri(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
		time.Sleep(100 * time.Millisecond)
		transport.Close()
		time.Sleep(100 * time.Millisecond)
	}()

	testPublisherConnectorUri(t, publisher, connector)
}

func TestDefaultPublisherConnector(t *testing.T) {
	testPublisherConnector(t, DefaultPublisher, DefaultConnector)
	time.Sleep(100 * time.Millisecond)
}

func testPublisherConnectorAnyAll(t *testing.T, publisher Publisher, connector Connector,
	anyall string) {
	pchan0 := make(chan string)
	pchan1 := make(chan string)
	pchan2 := make(chan string)
	cchan := make(chan string)
	echan := make(chan error)

	id := anyall + "one"

	err := publisher.Publish(id, pchan0)
	if nil != err {
		panic(err)
	}

	err = publisher.Publish(id, pchan1)
	if nil != err {
		panic(err)
	}

	err = publisher.Publish(id, pchan2)
	if nil != err {
		panic(err)
	}

	err = connector.Connect(
		&url.URL{
			Scheme: "tcp",
			Host:   "127.0.0.1",
			Path:   id,
		},
		cchan,
		echan)
	if nil != err {
		panic(err)
	}

	cchan <- "fortytwo"

	close(cchan)

	cnt := 1
	if "+" == anyall {
		cnt = 3
	}

	sum := 0
	for i := 0; cnt > i; i++ {
		s := ""
		select {
		case s = <-pchan0:
			sum |= 1
		case s = <-pchan1:
			sum |= 2
		case s = <-pchan2:
			sum |= 4
		}
		if "fortytwo" != s {
			t.Errorf("incorrect msg: expect %v, got %v", "fortytwo", s)
		}
	}

	if "+" == anyall {
		if 7 != sum {
			t.Errorf("incorrect sum: expect %v, got %v", 7, sum)
		}
	}

	publisher.Unpublish(id, pchan0)
	publisher.Unpublish(id, pchan1)
	publisher.Unpublish(id, pchan2)
}

func TestPublisherConnectorAnyAll(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
		time.Sleep(100 * time.Millisecond)
		transport.Close()
		time.Sleep(100 * time.Millisecond)
	}()

	testPublisherConnectorAnyAll(t, publisher, connector, "")
	testPublisherConnectorAnyAll(t, publisher, connector, "+")
}

func TestDefaultPublisherConnectorAnyAll(t *testing.T) {
	testPublisherConnectorAnyAll(t, DefaultPublisher, DefaultConnector, "")
	testPublisherConnectorAnyAll(t, DefaultPublisher, DefaultConnector, "+")
	time.Sleep(100 * time.Millisecond)
}

func testPublisherConnectorError(t *testing.T,
	transport Transport, publisher Publisher, connector Connector) {
	pchan := make(chan string)
	cchan := make(chan string)
	echan0 := make(chan error)
	echan1 := make(chan error)
	echan2 := make(chan error)

	err := publisher.Publish("one", pchan)
	if nil != err {
		panic(err)
	}

	err = publisher.Publish(IdErr, echan0)
	if nil != err {
		panic(err)
	}

	err = publisher.Publish(IdErr, echan1)
	if nil != err {
		panic(err)
	}

	err = publisher.Publish(IdErr, echan2)
	if nil != err {
		panic(err)
	}

	err = connector.Connect(
		&url.URL{
			Scheme: "tcp",
			Host:   "127.0.0.1",
			Path:   IdErr,
		},
		cchan,
		nil)
	if ErrArgumentInvalid != err {
		t.Error()
	}

	err = connector.Connect(
		&url.URL{
			Scheme: "tcp",
			Host:   "127.0.0.1",
			Path:   "one",
		},
		cchan,
		nil)
	if nil != err {
		panic(err)
	}

	cchan <- "fortytwo"

	close(cchan)

	s := <-pchan
	if "fortytwo" != s {
		t.Errorf("incorrect msg: expect %v, got %v", "fortytwo", s)
	}

	publisher.Unpublish("one", pchan)

	time.Sleep(100 * time.Millisecond)
	transport.Close()
	time.Sleep(100 * time.Millisecond)

	sum := 0
	for 7 != sum {
		select {
		case <-echan0:
			sum |= 1
		case <-echan1:
			sum |= 2
		case <-echan2:
			sum |= 4
		}
	}
}

func TestPublisherConnectorError(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
	}()

	testPublisherConnectorError(t, transport, publisher, connector)
}

func testPublisherConnectorMulti(t *testing.T, publisher Publisher, connector Connector) {
	pchan := make([]chan string, 100)
	cchan := make([]chan string, 100)
	echan := make(chan error)

	for i := range pchan {
		pchan[i] = make(chan string)

		err := publisher.Publish("chan"+strconv.Itoa(i), pchan[i])
		if nil != err {
			panic(err)
		}
	}

	for i := range cchan {
		cchan[i] = make(chan string)

		err := connector.Connect(
			&url.URL{
				Scheme: "tcp",
				Host:   "127.0.0.1",
				Path:   "chan" + strconv.Itoa(i),
			},
			cchan[i],
			echan)
		if nil != err {
			panic(err)
		}
	}

	for i := range cchan {
		cchan[i] <- "msg" + strconv.Itoa(i)
		s := <-pchan[i]
		if "msg"+strconv.Itoa(i) != s {
			t.Errorf("incorrect msg: expect %v, got %v", "msg"+strconv.Itoa(i), s)
		}
	}

	for i := range cchan {
		close(cchan[i])
	}

	for i := range pchan {
		publisher.Unpublish("chan"+strconv.Itoa(i), pchan[i])
	}
}

func TestPublisherConnectorMulti(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
		time.Sleep(100 * time.Millisecond)
		transport.Close()
		time.Sleep(100 * time.Millisecond)
	}()

	testPublisherConnectorMulti(t, publisher, connector)
}

func TestDefaultPublisherConnectorMulti(t *testing.T) {
	testPublisherConnectorMulti(t, DefaultPublisher, DefaultConnector)
	time.Sleep(100 * time.Millisecond)
}

func testPublisherConnectorMultiConcurrent(t *testing.T, publisher Publisher, connector Connector) {
	pchan := make([]chan string, 100)
	cchan := make([]chan string, 100)
	echan := make(chan error)

	for i := range pchan {
		pchan[i] = make(chan string)

		err := publisher.Publish("chan"+strconv.Itoa(i), pchan[i])
		if nil != err {
			panic(err)
		}
	}

	for i := range cchan {
		cchan[i] = make(chan string)

		err := connector.Connect(
			&url.URL{
				Scheme: "tcp",
				Host:   "127.0.0.1",
				Path:   "chan" + strconv.Itoa(i),
			},
			cchan[i],
			echan)
		if nil != err {
			panic(err)
		}
	}

	wg := sync.WaitGroup{}

	for i := range cchan {
		i := i
		wg.Add(1)
		go func() {
			cchan[i] <- "msg" + strconv.Itoa(i)
			wg.Done()
		}()
	}

	for i := range pchan {
		i := i
		wg.Add(1)
		go func() {
			s := <-pchan[i]
			if "msg"+strconv.Itoa(i) != s {
				t.Errorf("incorrect msg: expect %v, got %v", "msg"+strconv.Itoa(i), s)
			}
			wg.Done()
		}()
	}

	wg.Wait()

	for i := range cchan {
		close(cchan[i])
	}

	for i := range pchan {
		publisher.Unpublish("chan"+strconv.Itoa(i), pchan[i])
	}
}

func TestPublisherConnectorMultiConcurrent(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
		time.Sleep(100 * time.Millisecond)
		transport.Close()
		time.Sleep(100 * time.Millisecond)
	}()

	testPublisherConnectorMultiConcurrent(t, publisher, connector)
}

func TestDefaultPublisherConnectorMultiConcurrent(t *testing.T) {
	testPublisherConnectorMultiConcurrent(t, DefaultPublisher, DefaultConnector)
	time.Sleep(100 * time.Millisecond)
}
<commit_msg>publisher, connector: testing<commit_after>/*
 * publisher_connector_test.go
 *
 * Copyright 2017 Bill Zissimopoulos
 */
/*
 * This file is part of netchan.
 *
 * It is licensed under the MIT license. The full license text can be found
 * in the License.txt file at the root of this project.
 */

package netchan

import (
	"net/url"
	"strconv"
	"sync"
	"testing"
	"time"
)

func testPublisherConnector(t *testing.T, publisher Publisher, connector Connector) {
	pchan := make(chan string)
	cchan := make(chan string)
	echan := make(chan error)

	err := publisher.Publish("one", pchan)
	if nil != err {
		panic(err)
	}

	err = connector.Connect(
		&url.URL{
			Scheme: "tcp",
			Host:   "127.0.0.1",
			Path:   "one",
		},
		cchan,
		echan)
	if nil != err {
		panic(err)
	}

	cchan <- "fortytwo"

	close(cchan)

	s := <-pchan
	if "fortytwo" != s {
		t.Errorf("incorrect msg: expect %v, got %v", "fortytwo", s)
	}

	publisher.Unpublish("one", pchan)
}

func TestPublisherConnector(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
		time.Sleep(100 * time.Millisecond)
		transport.Close()
		time.Sleep(100 * time.Millisecond)
	}()

	testPublisherConnector(t, publisher, connector)
}

func TestDefaultPublisherConnector(t *testing.T) {
	testPublisherConnector(t, DefaultPublisher, DefaultConnector)
	time.Sleep(100 * time.Millisecond)
}

func testPublisherConnectorUri(t *testing.T, publisher Publisher, connector Connector) {
	pchan := make(chan string)
	cchan := make(chan string)
	echan := make(chan error)

	err := publisher.Publish("one", pchan)
	if nil != err {
		panic(err)
	}

	err = connector.Connect("tcp://127.0.0.1/one", cchan, echan)
	if nil != err {
		panic(err)
	}

	cchan <- "fortytwo"

	close(cchan)

	s := <-pchan
	if "fortytwo" != s {
		t.Errorf("incorrect msg: expect %v, got %v", "fortytwo", s)
	}

	publisher.Unpublish("one", pchan)
}

func TestPublisherConnectorUri(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
		time.Sleep(100 * time.Millisecond)
		transport.Close()
		time.Sleep(100 * time.Millisecond)
	}()

	testPublisherConnectorUri(t, publisher, connector)
}

func testPublisherConnectorAnyAll(t *testing.T, publisher Publisher, connector Connector,
	anyall string) {
	pchan0 := make(chan string)
	pchan1 := make(chan string)
	pchan2 := make(chan string)
	cchan := make(chan string)
	echan := make(chan error)

	id := anyall + "one"

	err := publisher.Publish(id, pchan0)
	if nil != err {
		panic(err)
	}

	err = publisher.Publish(id, pchan1)
	if nil != err {
		panic(err)
	}

	err = publisher.Publish(id, pchan2)
	if nil != err {
		panic(err)
	}

	err = connector.Connect(
		&url.URL{
			Scheme: "tcp",
			Host:   "127.0.0.1",
			Path:   id,
		},
		cchan,
		echan)
	if nil != err {
		panic(err)
	}

	cchan <- "fortytwo"

	close(cchan)

	cnt := 1
	if "+" == anyall {
		cnt = 3
	}

	sum := 0
	for i := 0; cnt > i; i++ {
		s := ""
		select {
		case s = <-pchan0:
			sum |= 1
		case s = <-pchan1:
			sum |= 2
		case s = <-pchan2:
			sum |= 4
		}
		if "fortytwo" != s {
			t.Errorf("incorrect msg: expect %v, got %v", "fortytwo", s)
		}
	}

	if "+" == anyall {
		if 7 != sum {
			t.Errorf("incorrect sum: expect %v, got %v", 7, sum)
		}
	}

	publisher.Unpublish(id, pchan0)
	publisher.Unpublish(id, pchan1)
	publisher.Unpublish(id, pchan2)
}

func TestPublisherConnectorAnyAll(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
		time.Sleep(100 * time.Millisecond)
		transport.Close()
		time.Sleep(100 * time.Millisecond)
	}()

	testPublisherConnectorAnyAll(t, publisher, connector, "")
	testPublisherConnectorAnyAll(t, publisher, connector, "+")
}

func TestDefaultPublisherConnectorAnyAll(t *testing.T) {
	testPublisherConnectorAnyAll(t, DefaultPublisher, DefaultConnector, "")
	testPublisherConnectorAnyAll(t, DefaultPublisher, DefaultConnector, "+")
	time.Sleep(100 * time.Millisecond)
}

func testPublisherConnectorError(t *testing.T,
	transport Transport, publisher Publisher, connector Connector) {
	pchan := make(chan string)
	cchan := make(chan string)
	echan0 := make(chan error)
	echan1 := make(chan error)
	echan2 := make(chan error)

	err := publisher.Publish("one", pchan)
	if nil != err {
		panic(err)
	}

	err = publisher.Publish(IdErr, echan0)
	if nil != err {
		panic(err)
	}

	err = publisher.Publish(IdErr, echan1)
	if nil != err {
		panic(err)
	}

	err = publisher.Publish(IdErr, echan2)
	if nil != err {
		panic(err)
	}

	err = connector.Connect(
		&url.URL{
			Scheme: "tcp",
			Host:   "127.0.0.1",
			Path:   IdErr,
		},
		cchan,
		nil)
	if ErrArgumentInvalid != err {
		t.Error()
	}

	err = connector.Connect(
		&url.URL{
			Scheme: "tcp",
			Host:   "127.0.0.1",
			Path:   "one",
		},
		cchan,
		nil)
	if nil != err {
		panic(err)
	}

	cchan <- "fortytwo"

	close(cchan)

	s := <-pchan
	if "fortytwo" != s {
		t.Errorf("incorrect msg: expect %v, got %v", "fortytwo", s)
	}

	publisher.Unpublish("one", pchan)

	time.Sleep(100 * time.Millisecond)
	transport.Close()
	time.Sleep(100 * time.Millisecond)

	sum := 0
	for 7 != sum {
		select {
		case <-echan0:
			sum |= 1
		case <-echan1:
			sum |= 2
		case <-echan2:
			sum |= 4
		}
	}
}

func TestPublisherConnectorError(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
	}()

	testPublisherConnectorError(t, transport, publisher, connector)
}

func testPublisherConnectorMulti(t *testing.T, publisher Publisher, connector Connector) {
	pchan := make([]chan string, 100)
	cchan := make([]chan string, 100)
	echan := make(chan error)

	for i := range pchan {
		pchan[i] = make(chan string)

		err := publisher.Publish("chan"+strconv.Itoa(i), pchan[i])
		if nil != err {
			panic(err)
		}
	}

	for i := range cchan {
		cchan[i] = make(chan string)

		err := connector.Connect(
			&url.URL{
				Scheme: "tcp",
				Host:   "127.0.0.1",
				Path:   "chan" + strconv.Itoa(i),
			},
			cchan[i],
			echan)
		if nil != err {
			panic(err)
		}
	}

	for i := range cchan {
		cchan[i] <- "msg" + strconv.Itoa(i)
		s := <-pchan[i]
		if "msg"+strconv.Itoa(i) != s {
			t.Errorf("incorrect msg: expect %v, got %v", "msg"+strconv.Itoa(i), s)
		}
	}

	for i := range cchan {
		close(cchan[i])
	}

	for i := range pchan {
		publisher.Unpublish("chan"+strconv.Itoa(i), pchan[i])
	}
}

func TestPublisherConnectorMulti(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
		time.Sleep(100 * time.Millisecond)
		transport.Close()
		time.Sleep(100 * time.Millisecond)
	}()

	testPublisherConnectorMulti(t, publisher, connector)
}

func TestDefaultPublisherConnectorMulti(t *testing.T) {
	testPublisherConnectorMulti(t, DefaultPublisher, DefaultConnector)
	time.Sleep(100 * time.Millisecond)
}

func testPublisherConnectorMultiConcurrent(t *testing.T, publisher Publisher, connector Connector) {
	pchan := make([]chan string, 100)
	cchan := make([]chan string, 100)
	echan := make(chan error)

	for i := range pchan {
		pchan[i] = make(chan string)

		err := publisher.Publish("chan"+strconv.Itoa(i), pchan[i])
		if nil != err {
			panic(err)
		}
	}

	for i := range cchan {
		cchan[i] = make(chan string)

		err := connector.Connect(
			&url.URL{
				Scheme: "tcp",
				Host:   "127.0.0.1",
				Path:   "chan" + strconv.Itoa(i),
			},
			cchan[i],
			echan)
		if nil != err {
			panic(err)
		}
	}

	wg := sync.WaitGroup{}

	for i := range cchan {
		i := i
		wg.Add(1)
		go func() {
			cchan[i] <- "msg" + strconv.Itoa(i)
			wg.Done()
		}()
	}

	for i := range pchan {
		i := i
		wg.Add(1)
		go func() {
			s := <-pchan[i]
			if "msg"+strconv.Itoa(i) != s {
				t.Errorf("incorrect msg: expect %v, got %v", "msg"+strconv.Itoa(i), s)
			}
			wg.Done()
		}()
	}

	wg.Wait()

	for i := range cchan {
		close(cchan[i])
	}

	for i := range pchan {
		publisher.Unpublish("chan"+strconv.Itoa(i), pchan[i])
	}
}

func TestPublisherConnectorMultiConcurrent(t *testing.T) {
	marshaler := newGobMarshaler()
	transport := newNetTransport(
		marshaler,
		&url.URL{
			Scheme: "tcp",
			Host:   ":25000",
		})
	publisher := newPublisher(transport)
	connector := newConnector(transport)
	defer func() {
		time.Sleep(100 * time.Millisecond)
		transport.Close()
		time.Sleep(100 * time.Millisecond)
	}()

	testPublisherConnectorMultiConcurrent(t, publisher, connector)
}

func TestDefaultPublisherConnectorMultiConcurrent(t *testing.T) {
	testPublisherConnectorMultiConcurrent(t, DefaultPublisher, DefaultConnector)
	time.Sleep(100 * time.Millisecond)
}
<|endoftext|>


<commit_before>package wundergo_integration_test

import (
	"github.com/nu7hatch/gouuid"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/robdimsdale/wundergo"
)

var _ = Describe("basic task functionality", func() {
	var (
		newList wundergo.List
		newTask wundergo.Task
		err     error
	)

	BeforeEach(func() {
		By("Creating a new list")
		uuid1, err := uuid.NewV4()
		Expect(err).NotTo(HaveOccurred())
		newListTitle := uuid1.String()

		newList, err = client.CreateList(newListTitle)
		Expect(err).NotTo(HaveOccurred())

		By("Creating task in new list")
		uuid, err := uuid.NewV4()
		Expect(err).NotTo(HaveOccurred())
		newTaskTitle := uuid.String()

		Eventually(func() error {
			newTask, err = client.CreateTask(
				newTaskTitle,
				newList.ID,
				0,
				false,
				"",
				0,
				"1970-01-01",
				false,
			)
			return err
		}).ShouldNot(HaveOccurred())
	})

	AfterEach(func() {
		By("Deleting task")
		Eventually(func() error {
			newTask, err = client.Task(newTask.ID)
			return client.DeleteTask(newTask)
		}).Should(Succeed())

		var tasks []wundergo.Task
		Eventually(func() (bool, error) {
			tasks, err = client.TasksForListID(newList.ID)
			return taskContains(tasks, newTask), err
		}).Should(BeFalse())

		By("Deleting new list")
		Eventually(func() error {
			newList, err = client.List(newList.ID)
			return client.DeleteList(newList)
		}).Should(Succeed())

		var lists []wundergo.List
		Eventually(func() (bool, error) {
			lists, err = client.Lists()
			return listContains(lists, newList), err
		}).Should(BeFalse())
	})

	Describe("moving a tasks between lists", func() {
		var secondList wundergo.List

		BeforeEach(func() {
			By("Creating a second list")
			uuid1, err := uuid.NewV4()
			Expect(err).NotTo(HaveOccurred())
			secondListTitle := uuid1.String()

			secondList, err = client.CreateList(secondListTitle)
			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			By("Deleting second list")
			Eventually(func() error {
				secondList, err = client.List(secondList.ID)
				return client.DeleteList(secondList)
			}).Should(Succeed())

			var lists []wundergo.List
			Eventually(func() (bool, error) {
				lists, err = client.Lists()
				return listContains(lists, secondList), err
			}).Should(BeFalse())
		})

		It("can move a task between lists", func() {
			By("Moving task to second list")
			newTask.ListID = secondList.ID
			Eventually(func() error {
				newTask, err = client.UpdateTask(newTask)
				return err
			}).Should(Succeed())

			By("Verifying task appears in tasks for second list")
			var completedTasksForSecondList []wundergo.Task
			Eventually(func() (bool, error) {
				showCompletedTasks := false
				completedTasksForSecondList, err = client.CompletedTasksForListID(secondList.ID, showCompletedTasks)
				return taskContains(completedTasksForSecondList, newTask), err
			}).Should(BeTrue())

			By("Verifying task does not appear in tasks for first list")
			var completedTasksForFirstList []wundergo.Task
			Eventually(func() (bool, error) {
				showCompletedTasks := false
				completedTasksForFirstList, err = client.CompletedTasksForListID(newList.ID, showCompletedTasks)
				return taskContains(completedTasksForFirstList, newTask), err
			}).Should(BeFalse())

			By("Moving task back to first list")
			newTask.ListID = newList.ID
			Eventually(func() error {
				newTask, err = client.UpdateTask(newTask)
				return err
			}).Should(Succeed())

			By("Verifying task does not appear in tasks for second list")
			Eventually(func() (bool, error) {
				showCompletedTasks := false
				completedTasksForSecondList, err = client.CompletedTasksForListID(secondList.ID, showCompletedTasks)
				return taskContains(completedTasksForSecondList, newTask), err
			}).Should(BeFalse())

			By("Verifying task does appear in tasks for first list")
			Eventually(func() (bool, error) {
				showCompletedTasks := false
				completedTasksForFirstList, err = client.CompletedTasksForListID(newList.ID, showCompletedTasks)
				return taskContains(completedTasksForFirstList, newTask), err
			}).Should(BeTrue())
		})
	})

	It("can complete tasks", func() {
		var completedTasksForList []wundergo.Task
		showCompletedTasks := true
		Eventually(func() (bool, error) {
			completedTasksForList, err = client.CompletedTasksForListID(newList.ID, showCompletedTasks)
			return taskContains(completedTasksForList, newTask), err
		}).Should(BeFalse())

		By("Completing task")
		newTask.Completed = true
		Eventually(func() error {
			newTask, err = client.UpdateTask(newTask)
			return err
		}).Should(Succeed())

		By("Verifying task appears in completed tasks for list")
		Eventually(func() (bool, error) {
			completedTasksForList, err = client.CompletedTasksForListID(newList.ID, showCompletedTasks)
			return taskContains(completedTasksForList, newTask), err
		}).Should(BeTrue())

		By("Verifying task appears in completed tasks")
		var completedTasks []wundergo.Task
		Eventually(func() (bool, error) {
			completedTasks, err = client.CompletedTasks(showCompletedTasks)
			return taskContains(completedTasks, newTask), err
		}).Should(BeTrue())
	})

	It("can update tasks", func() {
		By("Setting properties")
		newTask.DueDate = "1971-01-01"
		newTask.Starred = true
		newTask.Completed = true
		newTask.RecurrenceType = "week"
		newTask.RecurrenceCount = 2

		By("Updating task")
		Eventually(func() error {
			newTask, err = client.UpdateTask(newTask)
			return err
		}).Should(Succeed())

		By("Getting task again")
		var taskAgain wundergo.Task
		Eventually(func() error {
			taskAgain, err = client.Task(newTask.ID)
			return err
		}).Should(Succeed())

		By("Ensuring properties are set")
		Expect(taskAgain.DueDate).Should(Equal("1971-01-01"))
		Expect(taskAgain.Starred).Should(BeTrue())
		Expect(taskAgain.Completed).Should(BeTrue())
		Expect(taskAgain.RecurrenceType).Should(Equal("week"))
		Expect(taskAgain.RecurrenceCount).Should(Equal(uint(2)))

		By("Resetting properties")
		taskAgain.DueDate = ""
		taskAgain.Starred = false
		taskAgain.Completed = false
		taskAgain.RecurrenceType = ""
		taskAgain.RecurrenceCount = 0

		By("Updating task")
		Eventually(func() error {
			taskAgain, err = client.UpdateTask(taskAgain)
			return err
		}).Should(Succeed())

		By("Verifying properties are reset")
		Expect(taskAgain.DueDate).Should(Equal(""))
		Expect(taskAgain.Starred).Should(BeFalse())
		Expect(taskAgain.Completed).Should(BeFalse())
		Expect(taskAgain.RecurrenceType).Should(Equal(""))
		Expect(taskAgain.RecurrenceCount).Should(Equal(uint(0)))
	})

	It("can perform subtask CRUD", func() {
		By("Creating subtask")
		var subtask wundergo.Subtask
		subtaskComplete := false
		Eventually(func() error {
			subtask, err = client.CreateSubtask("mySubtaskTitle", newTask.ID, subtaskComplete)
			return err
		}).Should(Succeed())

		By("Getting subtask")
		var aSubtask wundergo.Subtask
		Eventually(func() error {
			aSubtask, err = client.Subtask(subtask.ID)
			return err
		}).Should(Succeed())
		Expect(aSubtask.ID).To(Equal(subtask.ID))

		By("Validating subtask exists in all subtasks")
		Eventually(func() bool {
			// It is statistically probable that one of the lists will
			// be deleted, so we ignore error here.
			subtasks, _ := client.Subtasks()
			return subtaskContains(subtasks, subtask)
		}).Should(BeTrue())

		By("Validating subtask exists in subtasks for list")
		Eventually(func() (bool, error) {
			subtasksForList, err := client.SubtasksForListID(newList.ID)
			return subtaskContains(subtasksForList, subtask), err
		}).Should(BeTrue())

		By("Validating subtask exists in subtasks for task")
		Eventually(func() (bool, error) {
			subtasksForTask, err := client.SubtasksForTaskID(newTask.ID)
			return subtaskContains(subtasksForTask, subtask), err
		}).Should(BeTrue())

		By("Completing subtask")
		subtask.Completed = true
		Eventually(func() error {
			subtask, err = client.UpdateSubtask(subtask)
			return err
		}).Should(Succeed())

		By("Validating subtask exists in all completed subtasks")
		showCompletedSubtasks := true
		Eventually(func() bool {
			// It is statistically probable that one of the lists will
			// be deleted, so we ignore error here.
			subtasks, _ := client.CompletedSubtasks(showCompletedSubtasks)
			return subtaskContains(subtasks, subtask)
		}).Should(BeTrue())

		By("Validating subtask exists in completed subtasks for list")
		Eventually(func() (bool, error) {
			subtasksForList, err := client.CompletedSubtasksForListID(newList.ID, showCompletedSubtasks)
			return subtaskContains(subtasksForList, subtask), err
		}).Should(BeTrue())

		By("Validating subtask exists in completed subtasks for task")
		Eventually(func() (bool, error) {
			subtasksForTask, err := client.CompletedSubtasksForTaskID(newTask.ID, showCompletedSubtasks)
			return subtaskContains(subtasksForTask, subtask), err
		}).Should(BeTrue())

		By("Deleting subtask")
		Eventually(func() error {
			return client.DeleteSubtask(subtask)
		}).Should(Succeed())
	})
})

func subtaskContains(subtasks []wundergo.Subtask, subtask wundergo.Subtask) bool {
	for _, t := range subtasks {
		if t.ID == subtask.ID {
			return true
		}
	}
	return false
}
<commit_msg>Fix flaky subtask integration test.<commit_after>package wundergo_integration_test

import (
	"github.com/nu7hatch/gouuid"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/robdimsdale/wundergo"
)

var _ = Describe("basic task functionality", func() {
	var (
		newList wundergo.List
		newTask wundergo.Task
		err     error
	)

	BeforeEach(func() {
		By("Creating a new list")
		uuid1, err := uuid.NewV4()
		Expect(err).NotTo(HaveOccurred())
		newListTitle := uuid1.String()

		newList, err = client.CreateList(newListTitle)
		Expect(err).NotTo(HaveOccurred())

		By("Creating task in new list")
		uuid, err := uuid.NewV4()
		Expect(err).NotTo(HaveOccurred())
		newTaskTitle := uuid.String()

		Eventually(func() error {
			newTask, err = client.CreateTask(
				newTaskTitle,
				newList.ID,
				0,
				false,
				"",
				0,
				"1970-01-01",
				false,
			)
			return err
		}).ShouldNot(HaveOccurred())
	})

	AfterEach(func() {
		By("Deleting task")
		Eventually(func() error {
			newTask, err = client.Task(newTask.ID)
			return client.DeleteTask(newTask)
		}).Should(Succeed())

		var tasks []wundergo.Task
		Eventually(func() (bool, error) {
			tasks, err = client.TasksForListID(newList.ID)
			return taskContains(tasks, newTask), err
		}).Should(BeFalse())

		By("Deleting new list")
		Eventually(func() error {
			newList, err = client.List(newList.ID)
			return client.DeleteList(newList)
		}).Should(Succeed())

		var lists []wundergo.List
		Eventually(func() (bool, error) {
			lists, err = client.Lists()
			return listContains(lists, newList), err
		}).Should(BeFalse())
	})

	Describe("moving a tasks between lists", func() {
		var secondList wundergo.List

		BeforeEach(func() {
			By("Creating a second list")
			uuid1, err := uuid.NewV4()
			Expect(err).NotTo(HaveOccurred())
			secondListTitle := uuid1.String()

			secondList, err = client.CreateList(secondListTitle)
			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			By("Deleting second list")
			Eventually(func() error {
				secondList, err = client.List(secondList.ID)
				return client.DeleteList(secondList)
			}).Should(Succeed())

			var lists []wundergo.List
			Eventually(func() (bool, error) {
				lists, err = client.Lists()
				return listContains(lists, secondList), err
			}).Should(BeFalse())
		})

		It("can move a task between lists", func() {
			By("Moving task to second list")
			newTask.ListID = secondList.ID
			Eventually(func() error {
				newTask, err = client.UpdateTask(newTask)
				return err
			}).Should(Succeed())

			By("Verifying task appears in tasks for second list")
			var completedTasksForSecondList []wundergo.Task
			Eventually(func() (bool, error) {
				showCompletedTasks := false
				completedTasksForSecondList, err = client.CompletedTasksForListID(secondList.ID, showCompletedTasks)
				return taskContains(completedTasksForSecondList, newTask), err
			}).Should(BeTrue())

			By("Verifying task does not appear in tasks for first list")
			var completedTasksForFirstList []wundergo.Task
			Eventually(func() (bool, error) {
				showCompletedTasks := false
				completedTasksForFirstList, err = client.CompletedTasksForListID(newList.ID, showCompletedTasks)
				return taskContains(completedTasksForFirstList, newTask), err
			}).Should(BeFalse())

			By("Moving task back to first list")
			newTask.ListID = newList.ID
			Eventually(func() error {
				newTask, err = client.UpdateTask(newTask)
				return err
			}).Should(Succeed())

			By("Verifying task does not appear in tasks for second list")
			Eventually(func() (bool, error) {
				showCompletedTasks := false
				completedTasksForSecondList, err = client.CompletedTasksForListID(secondList.ID, showCompletedTasks)
				return taskContains(completedTasksForSecondList, newTask), err
			}).Should(BeFalse())

			By("Verifying task does appear in tasks for first list")
			Eventually(func() (bool, error) {
				showCompletedTasks := false
				completedTasksForFirstList, err = client.CompletedTasksForListID(newList.ID, showCompletedTasks)
				return taskContains(completedTasksForFirstList, newTask), err
			}).Should(BeTrue())
		})
	})

	It("can complete tasks", func() {
		var completedTasksForList []wundergo.Task
		showCompletedTasks := true
		Eventually(func() (bool, error) {
			completedTasksForList, err = client.CompletedTasksForListID(newList.ID, showCompletedTasks)
			return taskContains(completedTasksForList, newTask), err
		}).Should(BeFalse())

		By("Completing task")
		newTask.Completed = true
		Eventually(func() error {
			newTask, err = client.UpdateTask(newTask)
			return err
		}).Should(Succeed())

		By("Verifying task appears in completed tasks for list")
		Eventually(func() (bool, error) {
			completedTasksForList, err = client.CompletedTasksForListID(newList.ID, showCompletedTasks)
			return taskContains(completedTasksForList, newTask), err
		}).Should(BeTrue())

		By("Verifying task appears in completed tasks")
		var completedTasks []wundergo.Task
		Eventually(func() bool {
			// It is statistically probable that one of the lists will
			// be deleted, so we ignore error here.
			completedTasks, _ = client.CompletedTasks(showCompletedTasks)
			return taskContains(completedTasks, newTask)
		}).Should(BeTrue())
	})

	It("can update tasks", func() {
		By("Setting properties")
		newTask.DueDate = "1971-01-01"
		newTask.Starred = true
		newTask.Completed = true
		newTask.RecurrenceType = "week"
		newTask.RecurrenceCount = 2

		By("Updating task")
		Eventually(func() error {
			newTask, err = client.UpdateTask(newTask)
			return err
		}).Should(Succeed())

		By("Getting task again")
		var taskAgain wundergo.Task
		Eventually(func() error {
			taskAgain, err = client.Task(newTask.ID)
			return err
		}).Should(Succeed())

		By("Ensuring properties are set")
		Expect(taskAgain.DueDate).Should(Equal("1971-01-01"))
		Expect(taskAgain.Starred).Should(BeTrue())
		Expect(taskAgain.Completed).Should(BeTrue())
		Expect(taskAgain.RecurrenceType).Should(Equal("week"))
		Expect(taskAgain.RecurrenceCount).Should(Equal(uint(2)))

		By("Resetting properties")
		taskAgain.DueDate = ""
		taskAgain.Starred = false
		taskAgain.Completed = false
		taskAgain.RecurrenceType = ""
		taskAgain.RecurrenceCount = 0

		By("Updating task")
		Eventually(func() error {
			taskAgain, err = client.UpdateTask(taskAgain)
			return err
		}).Should(Succeed())

		By("Verifying properties are reset")
		Expect(taskAgain.DueDate).Should(Equal(""))
		Expect(taskAgain.Starred).Should(BeFalse())
		Expect(taskAgain.Completed).Should(BeFalse())
		Expect(taskAgain.RecurrenceType).Should(Equal(""))
		Expect(taskAgain.RecurrenceCount).Should(Equal(uint(0)))
	})

	It("can perform subtask CRUD", func() {
		By("Creating subtask")
		var subtask wundergo.Subtask
		subtaskComplete := false
		Eventually(func() error {
			subtask, err = client.CreateSubtask("mySubtaskTitle", newTask.ID, subtaskComplete)
			return err
		}).Should(Succeed())

		By("Getting subtask")
		var aSubtask wundergo.Subtask
		Eventually(func() error {
			aSubtask, err = client.Subtask(subtask.ID)
			return err
		}).Should(Succeed())
		Expect(aSubtask.ID).To(Equal(subtask.ID))

		By("Validating subtask exists in all subtasks")
		Eventually(func() bool {
			// It is statistically probable that one of the lists will
			// be deleted, so we ignore error here.
			subtasks, _ := client.Subtasks()
			return subtaskContains(subtasks, subtask)
		}).Should(BeTrue())

		By("Validating subtask exists in subtasks for list")
		Eventually(func() (bool, error) {
			subtasksForList, err := client.SubtasksForListID(newList.ID)
			return subtaskContains(subtasksForList, subtask), err
		}).Should(BeTrue())

		By("Validating subtask exists in subtasks for task")
		Eventually(func() (bool, error) {
			subtasksForTask, err := client.SubtasksForTaskID(newTask.ID)
			return subtaskContains(subtasksForTask, subtask), err
		}).Should(BeTrue())

		By("Completing subtask")
		subtask.Completed = true
		Eventually(func() error {
			subtask, err = client.UpdateSubtask(subtask)
			return err
		}).Should(Succeed())

		By("Validating subtask exists in all completed subtasks")
		showCompletedSubtasks := true
		Eventually(func() bool {
			// It is statistically probable that one of the lists will
			// be deleted, so we ignore error here.
			subtasks, _ := client.CompletedSubtasks(showCompletedSubtasks)
			return subtaskContains(subtasks, subtask)
		}).Should(BeTrue())

		By("Validating subtask exists in completed subtasks for list")
		Eventually(func() (bool, error) {
			subtasksForList, err := client.CompletedSubtasksForListID(newList.ID, showCompletedSubtasks)
			return subtaskContains(subtasksForList, subtask), err
		}).Should(BeTrue())

		By("Validating subtask exists in completed subtasks for task")
		Eventually(func() (bool, error) {
			subtasksForTask, err := client.CompletedSubtasksForTaskID(newTask.ID, showCompletedSubtasks)
			return subtaskContains(subtasksForTask, subtask), err
		}).Should(BeTrue())

		By("Deleting subtask")
		Eventually(func() error {
			return client.DeleteSubtask(subtask)
		}).Should(Succeed())
	})
})

func subtaskContains(subtasks []wundergo.Subtask, subtask wundergo.Subtask) bool {
	for _, t := range subtasks {
		if t.ID == subtask.ID {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package config

import (
	"errors"
	"regexp"
	"strconv"
	"strings"

	"github.com/zyedidia/tcell/v2"
)

// DefStyle is Micro's default style
var DefStyle tcell.Style = tcell.StyleDefault

// Colorscheme is the current colorscheme
var Colorscheme map[string]tcell.Style

// GetColor takes in a syntax group and returns the colorscheme's style for that group
func GetColor(color string) tcell.Style {
	st := DefStyle
	if color == "" {
		return st
	}
	groups := strings.Split(color, ".")
	if len(groups) > 1 {
		curGroup := ""
		for i, g := range groups {
			if i != 0 {
				curGroup += "."
			}
			curGroup += g
			if style, ok := Colorscheme[curGroup]; ok {
				st = style
			}
		}
	} else if style, ok := Colorscheme[color]; ok {
		st = style
	}

	return st
}

// ColorschemeExists checks if a given colorscheme exists
func ColorschemeExists(colorschemeName string) bool {
	return FindRuntimeFile(RTColorscheme, colorschemeName) != nil
}

// InitColorscheme picks and initializes the colorscheme when micro starts
func InitColorscheme() error {
	Colorscheme = make(map[string]tcell.Style)
	DefStyle = tcell.StyleDefault

	return LoadDefaultColorscheme()
}

// LoadDefaultColorscheme loads the default colorscheme from $(ConfigDir)/colorschemes
func LoadDefaultColorscheme() error {
	return LoadColorscheme(GlobalSettings["colorscheme"].(string))
}

// LoadColorscheme loads the given colorscheme from a directory
func LoadColorscheme(colorschemeName string) error {
	file := FindRuntimeFile(RTColorscheme, colorschemeName)
	if file == nil {
		return errors.New(colorschemeName + " is not a valid colorscheme")
	}
	if data, err := file.Data(); err != nil {
		return errors.New("Error loading colorscheme: " + err.Error())
	} else {
		Colorscheme, err = ParseColorscheme(string(data))
		if err != nil {
			return err
		}
	}
	return nil
}

// ParseColorscheme parses the text definition for a colorscheme and returns the corresponding object
// Colorschemes are made up of color-link statements linking a color group to a list of colors
// For example, color-link keyword (blue,red) makes all keywords have a blue foreground and
// red background
func ParseColorscheme(text string) (map[string]tcell.Style, error) {
	var err error
	parser := regexp.MustCompile(`color-link\s+(\S*)\s+"(.*)"`)

	lines := strings.Split(text, "\n")

	c := make(map[string]tcell.Style)

	for _, line := range lines {
		if strings.TrimSpace(line) == "" ||
			strings.TrimSpace(line)[0] == '#' {
			// Ignore this line
			continue
		}

		matches := parser.FindSubmatch([]byte(line))
		if len(matches) == 3 {
			link := string(matches[1])
			colors := string(matches[2])

			style := StringToStyle(colors)
			c[link] = style

			if link == "default" {
				DefStyle = style
			}
		} else {
			err = errors.New("Color-link statement is not valid: " + line)
		}
	}

	return c, err
}

// StringToStyle returns a style from a string
// The strings must be in the format "extra foregroundcolor,backgroundcolor"
// The 'extra' can be bold, reverse, italic or underline
func StringToStyle(str string) tcell.Style {
	var fg, bg string
	spaceSplit := strings.Split(str, " ")
	split := strings.Split(spaceSplit[len(spaceSplit)-1], ",")
	if len(split) > 1 {
		fg, bg = split[0], split[1]
	} else {
		fg = split[0]
	}
	fg = strings.TrimSpace(fg)
	bg = strings.TrimSpace(bg)

	var fgColor, bgColor tcell.Color
	if fg == "" || fg == "default" {
		fgColor, _, _ = DefStyle.Decompose()
	} else {
		fgColor = StringToColor(fg)
	}
	if bg == "" || bg == "default" {
		_, bgColor, _ = DefStyle.Decompose()
	} else {
		bgColor = StringToColor(bg)
	}

	style := DefStyle.Foreground(fgColor).Background(bgColor)
	if strings.Contains(str, "bold") {
		style = style.Bold(true)
	}
	if strings.Contains(str, "italic") {
		style = style.Italic(true)
	}
	if strings.Contains(str, "reverse") {
		style = style.Reverse(true)
	}
	if strings.Contains(str, "underline") {
		style = style.Underline(true)
	}
	return style
}

// StringToColor returns a tcell color from a string representation of a color
// We accept either bright... or light... to mean the brighter version of a color
func StringToColor(str string) tcell.Color {
	switch str {
	case "black":
		return tcell.ColorBlack
	case "red":
		return tcell.ColorMaroon
	case "green":
		return tcell.ColorGreen
	case "yellow":
		return tcell.ColorOlive
	case "blue":
		return tcell.ColorNavy
	case "magenta":
		return tcell.ColorPurple
	case "cyan":
		return tcell.ColorTeal
	case "white":
		return tcell.ColorSilver
	case "brightblack", "lightblack":
		return tcell.ColorGray
	case "brightred", "lightred":
		return tcell.ColorRed
	case "brightgreen", "lightgreen":
		return tcell.ColorLime
	case "brightyellow", "lightyellow":
		return tcell.ColorYellow
	case "brightblue", "lightblue":
		return tcell.ColorBlue
	case "brightmagenta", "lightmagenta":
		return tcell.ColorFuchsia
	case "brightcyan", "lightcyan":
		return tcell.ColorAqua
	case "brightwhite", "lightwhite":
		return tcell.ColorWhite
	case "default":
		return tcell.ColorDefault
	default:
		// Check if this is a 256 color
		if num, err := strconv.Atoi(str); err == nil {
			return GetColor256(num)
		}
		// Probably a truecolor hex value
		return tcell.GetColor(str)
	}
}

// GetColor256 returns the tcell color for a number between 0 and 255
func GetColor256(color int) tcell.Color {
	if color == 0 {
		return tcell.ColorDefault
	}
	return tcell.PaletteColor(color)
}
<commit_msg>Fix regression: non-working direct colors in syntax files (#2252)<commit_after>package config

import (
	"errors"
	"regexp"
	"strconv"
	"strings"

	"github.com/zyedidia/tcell/v2"
)

// DefStyle is Micro's default style
var DefStyle tcell.Style = tcell.StyleDefault

// Colorscheme is the current colorscheme
var Colorscheme map[string]tcell.Style

// GetColor takes in a syntax group and returns the colorscheme's style for that group
func GetColor(color string) tcell.Style {
	st := DefStyle
	if color == "" {
		return st
	}
	groups := strings.Split(color, ".")
	if len(groups) > 1 {
		curGroup := ""
		for i, g := range groups {
			if i != 0 {
				curGroup += "."
			}
			curGroup += g
			if style, ok := Colorscheme[curGroup]; ok {
				st = style
			}
		}
	} else if style, ok := Colorscheme[color]; ok {
		st = style
	} else {
		st = StringToStyle(color)
	}

	return st
}

// ColorschemeExists checks if a given colorscheme exists
func ColorschemeExists(colorschemeName string) bool {
	return FindRuntimeFile(RTColorscheme, colorschemeName) != nil
}

// InitColorscheme picks and initializes the colorscheme when micro starts
func InitColorscheme() error {
	Colorscheme = make(map[string]tcell.Style)
	DefStyle = tcell.StyleDefault

	return LoadDefaultColorscheme()
}

// LoadDefaultColorscheme loads the default colorscheme from $(ConfigDir)/colorschemes
func LoadDefaultColorscheme() error {
	return LoadColorscheme(GlobalSettings["colorscheme"].(string))
}

// LoadColorscheme loads the given colorscheme from a directory
func LoadColorscheme(colorschemeName string) error {
	file := FindRuntimeFile(RTColorscheme, colorschemeName)
	if file == nil {
		return errors.New(colorschemeName + " is not a valid colorscheme")
	}
	if data, err := file.Data(); err != nil {
		return errors.New("Error loading colorscheme: " + err.Error())
	} else {
		Colorscheme, err = ParseColorscheme(string(data))
		if err != nil {
			return err
		}
	}
	return nil
}

// ParseColorscheme parses the text definition for a colorscheme and returns the corresponding object
// Colorschemes are made up of color-link statements linking a color group to a list of colors
// For example, color-link keyword (blue,red) makes all keywords have a blue foreground and
// red background
func ParseColorscheme(text string) (map[string]tcell.Style, error) {
	var err error
	parser := regexp.MustCompile(`color-link\s+(\S*)\s+"(.*)"`)

	lines := strings.Split(text, "\n")

	c := make(map[string]tcell.Style)

	for _, line := range lines {
		if strings.TrimSpace(line) == "" ||
			strings.TrimSpace(line)[0] == '#' {
			// Ignore this line
			continue
		}

		matches := parser.FindSubmatch([]byte(line))
		if len(matches) == 3 {
			link := string(matches[1])
			colors := string(matches[2])

			style := StringToStyle(colors)
			c[link] = style

			if link == "default" {
				DefStyle = style
			}
		} else {
			err = errors.New("Color-link statement is not valid: " + line)
		}
	}

	return c, err
}

// StringToStyle returns a style from a string
// The strings must be in the format "extra foregroundcolor,backgroundcolor"
// The 'extra' can be bold, reverse, italic or underline
func StringToStyle(str string) tcell.Style {
	var fg, bg string
	spaceSplit := strings.Split(str, " ")
	split := strings.Split(spaceSplit[len(spaceSplit)-1], ",")
	if len(split) > 1 {
		fg, bg = split[0], split[1]
	} else {
		fg = split[0]
	}
	fg = strings.TrimSpace(fg)
	bg = strings.TrimSpace(bg)

	var fgColor, bgColor tcell.Color
	var ok bool
	if fg == "" || fg == "default" {
		fgColor, _, _ = DefStyle.Decompose()
	} else {
		fgColor, ok = StringToColor(fg)
		if !ok {
			fgColor, _, _ = DefStyle.Decompose()
		}
	}
	if bg == "" || bg == "default" {
		_, bgColor, _ = DefStyle.Decompose()
	} else {
		bgColor, ok = StringToColor(bg)
		if !ok {
			_, bgColor, _ = DefStyle.Decompose()
		}
	}

	style := DefStyle.Foreground(fgColor).Background(bgColor)
	if strings.Contains(str, "bold") {
		style = style.Bold(true)
	}
	if strings.Contains(str, "italic") {
		style = style.Italic(true)
	}
	if strings.Contains(str, "reverse") {
		style = style.Reverse(true)
	}
	if strings.Contains(str, "underline") {
		style = style.Underline(true)
	}
	return style
}

// StringToColor returns a tcell color from a string representation of a color
// We accept either bright... or light... to mean the brighter version of a color
func StringToColor(str string) (tcell.Color, bool) {
	switch str {
	case "black":
		return tcell.ColorBlack, true
	case "red":
		return tcell.ColorMaroon, true
	case "green":
		return tcell.ColorGreen, true
	case "yellow":
		return tcell.ColorOlive, true
	case "blue":
		return tcell.ColorNavy, true
	case "magenta":
		return tcell.ColorPurple, true
	case "cyan":
		return tcell.ColorTeal, true
	case "white":
		return tcell.ColorSilver, true
	case "brightblack", "lightblack":
		return tcell.ColorGray, true
	case "brightred", "lightred":
		return tcell.ColorRed, true
	case "brightgreen", "lightgreen":
		return tcell.ColorLime, true
	case "brightyellow", "lightyellow":
		return tcell.ColorYellow, true
	case "brightblue", "lightblue":
		return tcell.ColorBlue, true
	case "brightmagenta", "lightmagenta":
		return tcell.ColorFuchsia, true
	case "brightcyan", "lightcyan":
		return tcell.ColorAqua, true
	case "brightwhite", "lightwhite":
		return tcell.ColorWhite, true
	case "default":
		return tcell.ColorDefault, true
	default:
		// Check if this is a 256 color
		if num, err := strconv.Atoi(str); err == nil {
			return GetColor256(num), true
		}
		// Check if this is a truecolor hex value
		if len(str) == 7 && str[0] == '#' {
			return tcell.GetColor(str), true
		}
		return tcell.ColorDefault, false
	}
}

// GetColor256 returns the tcell color for a number between 0 and 255
func GetColor256(color int) tcell.Color {
	if color == 0 {
		return tcell.ColorDefault
	}
	return tcell.PaletteColor(color)
}
<|endoftext|>