<commit_before>package librariesio

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"strings"
	"testing"
)

const APIKey string = "1234"

func startNewServer() (*httptest.Server, *http.ServeMux, *url.URL) {
	mux := http.NewServeMux()
	server := httptest.NewServer(mux)
	url, _ := url.Parse(server.URL)
	return server, mux, url
}

func TestNewClient(t *testing.T) {
	c := NewClient(APIKey)

	if got, want := c.apiKey, APIKey; got != want {
		t.Errorf("NewClient baseURL is %v, want %v", got, want)
	}

	if got, want := c.BaseURL.String(), "https://libraries.io/api/"; got != want {
		t.Errorf("NewClient baseURL is %v, want %v", got, want)
	}

	if got, want := c.UserAgent, "go-librariesio/1"; got != want {
		t.Errorf("NewClient userAgent is %v, want %v", got, want)
	}
}

func TestNewRequest_badURL(t *testing.T) {
	client := NewClient(APIKey)
	req, err := client.NewRequest("GET", ":", nil)

	if err == nil {
		t.Fatalf("NewRequest did not return error")
	}
	if req != nil {
		t.Fatalf("did not expect non-nil request, got %+v", req)
	}
}

func TestNewRequest_noPayload(t *testing.T) {
	client := NewClient(APIKey)
	req, err := client.NewRequest("GET", "pypi/cookiecutter", nil)

	if err != nil {
		t.Fatalf("NewRequest returned error: %v", err)
	}

	if req.Body != nil {
		t.Fatalf("request contains a non-nil Body\n%v", req.Body)
	}
}

func TestNewRequest_invalidJSON(t *testing.T) {
	client := NewClient(APIKey)

	foo := make(map[interface{}]interface{})

	_, err := client.NewRequest("GET", "pypi/cookiecutter", foo)

	if err == nil {
		t.Error("Expected error to be returned")
	}
	if err, ok := err.(*json.UnsupportedTypeError); !ok {
		t.Errorf("Expected a JSON error, got %#v", err)
	}
}

func TestNewRequest_auth(t *testing.T) {
	client := NewClient(APIKey)
	req, err := client.NewRequest("GET", "pypi/cookiecutter", nil)

	if err != nil {
		t.Fatalf("NewRequest returned error: %v", err)
	}

	query := req.URL.Query()
	if got, want := query.Get("api_key"), APIKey; got != want {
		t.Fatalf("did not set query param to %v, got %v", want, got)
	}
}

func TestNewRequest_headers(t *testing.T) {
	testCases := []struct {
		name    string
		body    interface{}
		headers map[string]string
	}{
		{
			name: "No Content-Type without body",
			body: nil,
			headers: map[string]string{
				"Accept":     "application/json",
				"User-Agent": "go-librariesio/" + libraryVersion,
			},
		},
		{
			name: "Content-Type with body",
			body: "hello world",
			headers: map[string]string{
				"Accept":       "application/json",
				"Content-Type": "application/json",
				"User-Agent":   "go-librariesio/" + libraryVersion,
			},
		},
	}

	client := NewClient(APIKey)

	for _, testCase := range testCases {
		t.Run(testCase.name, func(t *testing.T) {
			req, err := client.NewRequest("GET", "pypi/cookiecutter", testCase.body)
			if err != nil {
				t.Fatal("unexpected error")
			}

			for header, want := range testCase.headers {
				if got := req.Header.Get(header); got != want {
					t.Errorf("Header.Get(%q) returned %q, want %q", header, got, want)
				}
			}
		})
	}
}

func TestCheckResponse(t *testing.T) {
	response := &http.Response{
		Request:    &http.Request{},
		StatusCode: http.StatusBadRequest,
		Body:       ioutil.NopCloser(strings.NewReader(`{"error":"Nope Nope Nope"}`)),
	}
	errResponse, ok := CheckResponse(response).(*ErrorResponse)

	if !ok {
		t.Errorf("Expected ErrorResponse, got %v", errResponse)
	}

	want := &ErrorResponse{
		Response: response,
		Message:  "Nope Nope Nope",
	}
	if !reflect.DeepEqual(errResponse, want) {
		t.Errorf("\nExpected %#v\nGot %#v", want, errResponse)
	}
}

func TestErrorResponse(t *testing.T) {
	client := NewClient(APIKey)
	request, _ := client.NewRequest("GET", "pypi/poyo", nil)
	response := &http.Response{
		Request:    request,
		StatusCode: http.StatusBadRequest,
	}

	err := &ErrorResponse{Response: response, Message: "nope"}
	want := `GET https://libraries.io/api/pypi/poyo?api_key=REDACTED: 400 "nope"`

	if got := err.Error(); got != want {
		t.Fatalf("\nExpected %q\nGot %q", want, got)
	}
}

func TestDo(t *testing.T) {
	server, mux, url := startNewServer()
	client := NewClient(APIKey)
	client.BaseURL = url
	defer server.Close()

	type foo struct {
		Bar string `json:"bar"`
	}

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if method := "GET"; method != r.Method {
			t.Errorf("expected HTTP %v request, got %v", method, r.Method)
		}
		fmt.Fprintf(w, `{"bar":"helloworld"}`)
	})

	req, _ := client.NewRequest("GET", "/", nil)

	got := new(foo)
	client.Do(context.Background(), req, got)

	want := &foo{Bar: "helloworld"}

	if !reflect.DeepEqual(got, want) {
		t.Errorf("response body does not match, want %v, got %v", want, got)
	}
}

func TestDo_httpClientError(t *testing.T) {
	server, _, url := startNewServer()
	client := NewClient(APIKey)
	client.BaseURL = url
	defer server.Close()

	_, err := client.Do(context.Background(), &http.Request{}, nil)
	if err == nil {
		t.Fatalf("Expected error to be returned")
	}
}

func TestDo_badResponse(t *testing.T) {
	server, mux, url := startNewServer()
	client := NewClient(APIKey)
	client.BaseURL = url
	defer server.Close()

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Nope", http.StatusBadRequest)
	})
	req, _ := client.NewRequest("GET", "/", nil)

	_, err := client.Do(context.Background(), req, nil)

	if err == nil {
		t.Errorf("Expected HTTP %v error", http.StatusBadRequest)
	}
}

func TestDo_badResponseBody(t *testing.T) {
	server, mux, url := startNewServer()
	client := NewClient(APIKey)
	client.BaseURL = url
	defer server.Close()

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{123:"a"}`)
	})

	type foo struct {
		Bar string `json:"bar"`
	}

	request, _ := client.NewRequest("GET", "/", nil)
	_, err := client.Do(context.Background(), request, new(foo))

	if err == nil {
		t.Fatal("Expected response body error")
	}
}
<commit_msg>Implement a test for redactAPIKey()<commit_after>package librariesio

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"strings"
	"testing"
)

const APIKey string = "1234"

func startNewServer() (*httptest.Server, *http.ServeMux, *url.URL) {
	mux := http.NewServeMux()
	server := httptest.NewServer(mux)
	url, _ := url.Parse(server.URL)
	return server, mux, url
}

func TestNewClient(t *testing.T) {
	c := NewClient(APIKey)

	if got, want := c.apiKey, APIKey; got != want {
		t.Errorf("NewClient baseURL is %v, want %v", got, want)
	}

	if got, want := c.BaseURL.String(), "https://libraries.io/api/"; got != want {
		t.Errorf("NewClient baseURL is %v, want %v", got, want)
	}

	if got, want := c.UserAgent, "go-librariesio/1"; got != want {
		t.Errorf("NewClient userAgent is %v, want %v", got, want)
	}
}

func TestNewRequest_badURL(t *testing.T) {
	client := NewClient(APIKey)
	req, err := client.NewRequest("GET", ":", nil)

	if err == nil {
		t.Fatalf("NewRequest did not return error")
	}
	if req != nil {
		t.Fatalf("did not expect non-nil request, got %+v", req)
	}
}

func TestNewRequest_noPayload(t *testing.T) {
	client := NewClient(APIKey)
	req, err := client.NewRequest("GET", "pypi/cookiecutter", nil)

	if err != nil {
		t.Fatalf("NewRequest returned error: %v", err)
	}

	if req.Body != nil {
		t.Fatalf("request contains a non-nil Body\n%v", req.Body)
	}
}

func TestNewRequest_invalidJSON(t *testing.T) {
	client := NewClient(APIKey)

	foo := make(map[interface{}]interface{})

	_, err := client.NewRequest("GET", "pypi/cookiecutter", foo)

	if err == nil {
		t.Error("Expected error to be returned")
	}
	if err, ok := err.(*json.UnsupportedTypeError); !ok {
		t.Errorf("Expected a JSON error, got %#v", err)
	}
}

func TestNewRequest_auth(t *testing.T) {
	client := NewClient(APIKey)
	req, err := client.NewRequest("GET", "pypi/cookiecutter", nil)

	if err != nil {
		t.Fatalf("NewRequest returned error: %v", err)
	}

	query := req.URL.Query()
	if got, want := query.Get("api_key"), APIKey; got != want {
		t.Fatalf("did not set query param to %v, got %v", want, got)
	}
}

func TestNewRequest_headers(t *testing.T) {
	testCases := []struct {
		name    string
		body    interface{}
		headers map[string]string
	}{
		{
			name: "No Content-Type without body",
			body: nil,
			headers: map[string]string{
				"Accept":     "application/json",
				"User-Agent": "go-librariesio/" + libraryVersion,
			},
		},
		{
			name: "Content-Type with body",
			body: "hello world",
			headers: map[string]string{
				"Accept":       "application/json",
				"Content-Type": "application/json",
				"User-Agent":   "go-librariesio/" + libraryVersion,
			},
		},
	}

	client := NewClient(APIKey)

	for _, testCase := range testCases {
		t.Run(testCase.name, func(t *testing.T) {
			req, err := client.NewRequest("GET", "pypi/cookiecutter", testCase.body)
			if err != nil {
				t.Fatal("unexpected error")
			}

			for header, want := range testCase.headers {
				if got := req.Header.Get(header); got != want {
					t.Errorf("Header.Get(%q) returned %q, want %q", header, got, want)
				}
			}
		})
	}
}

func TestRedactAPIKey(t *testing.T) {
	url, err := url.Parse("pypi/poyo")

	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	q := url.Query()
	q.Set("api_key", APIKey)
	url.RawQuery = q.Encode()

	got := redactAPIKey(url).String()
	want := "pypi/poyo?api_key=REDACTED"

	if got != want {
		t.Fatalf("api_key param in URL is not redacted, got %v", got)
	}
}

func TestCheckResponse(t *testing.T) {
	response := &http.Response{
		Request:    &http.Request{},
		StatusCode: http.StatusBadRequest,
		Body:       ioutil.NopCloser(strings.NewReader(`{"error":"Nope Nope Nope"}`)),
	}
	errResponse, ok := CheckResponse(response).(*ErrorResponse)

	if !ok {
		t.Errorf("Expected ErrorResponse, got %v", errResponse)
	}

	want := &ErrorResponse{
		Response: response,
		Message:  "Nope Nope Nope",
	}
	if !reflect.DeepEqual(errResponse, want) {
		t.Errorf("\nExpected %#v\nGot %#v", want, errResponse)
	}
}

func TestErrorResponse(t *testing.T) {
	client := NewClient(APIKey)
	request, _ := client.NewRequest("GET", "pypi/poyo", nil)
	response := &http.Response{
		Request:    request,
		StatusCode: http.StatusBadRequest,
	}

	err := &ErrorResponse{Response: response, Message: "nope"}
	want := `GET https://libraries.io/api/pypi/poyo?api_key=REDACTED: 400 "nope"`

	if got := err.Error(); got != want {
		t.Fatalf("\nExpected %q\nGot %q", want, got)
	}
}

func TestDo(t *testing.T) {
	server, mux, url := startNewServer()
	client := NewClient(APIKey)
	client.BaseURL = url
	defer server.Close()

	type foo struct {
		Bar string `json:"bar"`
	}

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if method := "GET"; method != r.Method {
			t.Errorf("expected HTTP %v request, got %v", method, r.Method)
		}
		fmt.Fprintf(w, `{"bar":"helloworld"}`)
	})

	req, _ := client.NewRequest("GET", "/", nil)

	got := new(foo)
	client.Do(context.Background(), req, got)

	want := &foo{Bar: "helloworld"}

	if !reflect.DeepEqual(got, want) {
		t.Errorf("response body does not match, want %v, got %v", want, got)
	}
}

func TestDo_httpClientError(t *testing.T) {
	server, _, url := startNewServer()
	client := NewClient(APIKey)
	client.BaseURL = url
	defer server.Close()

	_, err := client.Do(context.Background(), &http.Request{}, nil)
	if err == nil {
		t.Fatalf("Expected error to be returned")
	}
}

func TestDo_badResponse(t *testing.T) {
	server, mux, url := startNewServer()
	client := NewClient(APIKey)
	client.BaseURL = url
	defer server.Close()

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Nope", http.StatusBadRequest)
	})
	req, _ := client.NewRequest("GET", "/", nil)

	_, err := client.Do(context.Background(), req, nil)

	if err == nil {
		t.Errorf("Expected HTTP %v error", http.StatusBadRequest)
	}
}

func TestDo_badResponseBody(t *testing.T) {
	server, mux, url := startNewServer()
	client := NewClient(APIKey)
	client.BaseURL = url
	defer server.Close()

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, `{123:"a"}`)
	})

	type foo struct {
		Bar string `json:"bar"`
	}

	request, _ := client.NewRequest("GET", "/", nil)
	_, err := client.Do(context.Background(), request, new(foo))

	if err == nil {
		t.Fatal("Expected response body error")
	}
}
<|endoftext|>


<commit_before>package library

import (
	"github.com/nytlabs/streamtools/st/blocks"
)

var Blocks = map[string]func() blocks.BlockInterface{
	"count":           NewCount,
	"toggle":          NewToggle,
	"movingaverage":   NewMovingAverage,
	"ticker":          NewTicker,
	"analogPin":       NewAnalogPin,
	"digitalpin":      NewDigitalPin,
	"todigitalpin":    NewToDigitalPin,
	"fromnsq":         NewFromNSQ,
	"fromhttpstream":  NewFromHTTPStream,
	"fromsqs":         NewFromSQS,
	"frompost":        NewFromPost,
	"fromfile":        NewFromFile,
	"tonsq":           NewToNSQ,
	"toelasticsearch": NewToElasticsearch,
	"tofile":          NewToFile,
	"tolog":           NewToLog,
	"tobeanstalkd":    NewToBeanstalkd,
	"tomongodb":       NewToMongoDB,
	"mask":            NewMask,
	"filter":          NewFilter,
	"sync":            NewSync,
	"queue":           NewQueue,
	"unpack":          NewUnpack,
	"pack":            NewPack,
	"parsexml":        NewParseXML,
	"set":             NewSet,
	"cache":           NewCache,
	"join":            NewJoin,
	"gethttp":         NewGetHTTP,
	"gaussian":        NewGaussian,
	"zipf":            NewZipf,
	"poisson":         NewPoisson,
	"map":             NewMap,
	"histogram":       NewHistogram,
	"timeseries":      NewTimeseries,
	"fromwebsocket":   NewFromWebsocket,
	"tonsqmulti":      NewToNSQMulti,
	"fromudp":         NewFromUDP,
	"dedupe":          NewDeDupe,
}

var BlockDefs = map[string]*blocks.BlockDef{}

func Start() {
	for k, newBlock := range Blocks {
		b := newBlock()
		b.Build(blocks.BlockChans{nil, nil, nil, nil, nil, nil})
		b.Setup()
		BlockDefs[k] = b.GetDef()
	}
}
<commit_msg>updated linux/arm library<commit_after>package library

import (
	"github.com/nytlabs/streamtools/st/blocks"
)

var Blocks = map[string]func() blocks.BlockInterface{
	"count":           NewCount,
	"toggle":          NewToggle,
	"movingaverage":   NewMovingAverage,
	"ticker":          NewTicker,
	"analogPin":       NewAnalogPin,
	"digitalpin":      NewDigitalPin,
	"todigitalpin":    NewToDigitalPin,
	"fromnsq":         NewFromNSQ,
	"fromhttpstream":  NewFromHTTPStream,
	"fromsqs":         NewFromSQS,
	"frompost":        NewFromPost,
	"fromfile":        NewFromFile,
	"tonsq":           NewToNSQ,
	"toelasticsearch": NewToElasticsearch,
	"tofile":          NewToFile,
	"tolog":           NewToLog,
	"tobeanstalkd":    NewToBeanstalkd,
	"tomongodb":       NewToMongoDB,
	"mask":            NewMask,
	"filter":          NewFilter,
	"sync":            NewSync,
	"queue":           NewQueue,
	"unpack":          NewUnpack,
	"pack":            NewPack,
	"parsexml":        NewParseXML,
	"set":             NewSet,
	"cache":           NewCache,
	"join":            NewJoin,
	"gethttp":         NewGetHTTP,
	"gaussian":        NewGaussian,
	"zipf":            NewZipf,
	"poisson":         NewPoisson,
	"map":             NewMap,
	"histogram":       NewHistogram,
	"timeseries":      NewTimeseries,
	"fromwebsocket":   NewFromWebsocket,
	"tonsqmulti":      NewToNSQMulti,
	"fromudp":         NewFromUDP,
	"dedupe":          NewDeDupe,
	"javascript":      NewJavascript,
}

var BlockDefs = map[string]*blocks.BlockDef{}

func Start() {
	for k, newBlock := range Blocks {
		b := newBlock()
		b.Build(blocks.BlockChans{nil, nil, nil, nil, nil, nil})
		b.Setup()
		BlockDefs[k] = b.GetDef()
	}
}
<|endoftext|>


<commit_before>package migrations

import (
	"context"
	"encoding/json"
	"io/ioutil"
	"os"
	"path"

	"github.com/OpenBazaar/jsonpb"
	"github.com/OpenBazaar/openbazaar-go/ipfs"
	"github.com/OpenBazaar/openbazaar-go/pb"
	"github.com/golang/protobuf/proto"
	ipfscore "github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
)

const migration012_ListingVersionForMarkupListings = 4

type Migration012 struct{}

type Migration012_ListingData struct {
	Hash         string   `json:"hash"`
	Slug         string   `json:"slug"`
	Title        string   `json:"title"`
	Categories   []string `json:"categories"`
	NSFW         bool     `json:"nsfw"`
	ContractType string   `json:"contractType"`
	Description  string   `json:"description"`
	Thumbnail    struct {
		Tiny   string `json:"tiny"`
		Small  string `json:"small"`
		Medium string `json:"medium"`
	} `json:"thumbnail"`
	Price struct {
		CurrencyCode string  `json:"currencyCode"`
		Amount       uint64  `json:"amount"`
		Modifier     float32 `json:"modifier"`
	} `json:"price"`
	ShipsTo            []string `json:"shipsTo"`
	FreeShipping       []string `json:"freeShipping"`
	Language           string   `json:"language"`
	AverageRating      float32  `json:"averageRating"`
	RatingCount        uint32   `json:"ratingCount"`
	ModeratorIDs       []string `json:"moderators"`
	AcceptedCurrencies []string `json:"acceptedCurrencies"`
	CoinType           string   `json:"coinType"`
}

func Migration012_listingHasNewFeaturesAndOldVersion(sl *pb.SignedListing) bool {
	metadata := sl.Listing.Metadata
	if metadata == nil {
		return false
	}
	return metadata.Version == 3 &&
		metadata.PriceModifier != 0
}

func Migration012_GetIdentityKey(repoPath, databasePassword string, testnetEnabled bool) ([]byte, error) {
	db, err := OpenDB(repoPath, databasePassword, testnetEnabled)
	if err != nil {
		return nil, err
	}
	defer db.Close()

	var identityKey []byte
	err = db.
		QueryRow("select value from config where key=?", "identityKey").
		Scan(&identityKey)
	if err != nil {
		return nil, err
	}
	return identityKey, nil
}

func (Migration012) Up(repoPath, databasePassword string, testnetEnabled bool) error {
	listingsIndexFilePath := path.Join(repoPath, "root", "listings.json")

	// Find all crypto listings
	listingsIndexJSONBytes, err := ioutil.ReadFile(listingsIndexFilePath)
	if err != nil {
		return err
	}

	listingsIndex := []*Migration012_ListingData{}
	err = json.Unmarshal(listingsIndexJSONBytes, &listingsIndex)
	if err != nil {
		return err
	}

	cryptoListings := []*Migration012_ListingData{}
	for _, listingAbstract := range listingsIndex {
		if listingAbstract.ContractType == "CRYPTOCURRENCY" {
			cryptoListings = append(cryptoListings, listingAbstract)
		}
	}

	// Finish early If no crypto listings
	if len(cryptoListings) == 0 {
		return writeRepoVer(repoPath, 13)
	}

	// Check each crypto listing for markup
	markupListings := []*pb.SignedListing{}
	for _, listingAbstract := range cryptoListings {
		listingJSONBytes, err := ioutil.ReadFile(migration012_listingFilePath(repoPath, listingAbstract.Slug))
		if err != nil {
			return err
		}
		sl := new(pb.SignedListing)
		err = jsonpb.UnmarshalString(string(listingJSONBytes), sl)
		if err != nil {
			return err
		}

		if Migration012_listingHasNewFeaturesAndOldVersion(sl) {
			markupListings = append(markupListings, sl)
		}
	}

	// Finish early If no crypto listings with new features are found
	if len(markupListings) == 0 {
		return writeRepoVer(repoPath, 13)
	}

	// Setup signing capabilities
	identityKey, err := Migration012_GetIdentityKey(repoPath, databasePassword, testnetEnabled)
	if err != nil {
		return err
	}

	identity, err := ipfs.IdentityFromKey(identityKey)
	if err != nil {
		return err
	}

	// IPFS node setup
	r, err := fsrepo.Open(repoPath)
	if err != nil {
		return err
	}
	cctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	cfg, err := r.Config()
	if err != nil {
		return err
	}

	cfg.Identity = identity

	ncfg := &ipfscore.BuildCfg{
		Repo:   r,
		Online: true,
		ExtraOpts: map[string]bool{
			"mplex": true,
		},
		DNSResolver: nil,
		Routing:     nil,
	}

	nd, err := ipfscore.NewNode(cctx, ncfg)
	if err != nil {
		return err
	}
	defer nd.Close()

	// Update each listing to have the latest version number and resave
	// Save the new hashes for each changed listing so we can update the index.
	hashes := make(map[string]string)

	for _, sl := range markupListings {
		sl.Listing.Metadata.Version = migration012_ListingVersionForMarkupListings

		serializedListing, err := proto.Marshal(sl.Listing)
		if err != nil {
			return err
		}
		idSig, err := nd.PrivateKey.Sign(serializedListing)
		if err != nil {
			return err
		}
		sl.Signature = idSig

		m := jsonpb.Marshaler{
			EnumsAsInts:  false,
			EmitDefaults: false,
			Indent:       "    ",
			OrigName:     false,
		}
		out, err := m.MarshalToString(sl)
		if err != nil {
			return err
		}

		filename := migration012_listingFilePath(repoPath, sl.Listing.Slug)
		if err := ioutil.WriteFile(filename, []byte(out), os.ModePerm); err != nil {
			return err
		}
		h, err := ipfs.GetHashOfFile(nd, filename)
		if err != nil {
			return err
		}
		hashes[sl.Listing.Slug] = h
	}

	// Update listing index
	indexBytes, err := ioutil.ReadFile(listingsIndexFilePath)
	if err != nil {
		return err
	}
	var index []Migration012_ListingData

	err = json.Unmarshal(indexBytes, &index)
	if err != nil {
		return err
	}

	for i, l := range index {
		h, ok := hashes[l.Slug]

		// Not one of the changed listings
		if !ok {
			continue
		}

		l.Hash = h
		index[i] = l
	}

	// Write it back to file
	ifile, err := os.Create(listingsIndexFilePath)
	if err != nil {
		return err
	}
	defer ifile.Close()

	j, jerr := json.MarshalIndent(index, "", "    ")
	if jerr != nil {
		return jerr
	}
	_, werr := ifile.Write(j)
	if werr != nil {
		return werr
	}

	_, err = ipfs.GetHashOfFile(nd, listingsIndexFilePath)
	if err != nil {
		return err
	}

	return writeRepoVer(repoPath, 13)
}

func migration012_listingFilePath(datadir string, slug string) string {
	return path.Join(datadir, "root", "listings", slug+".json")
}

func (Migration012) Down(repoPath, databasePassword string, testnetEnabled bool) error {
	return writeRepoVer(repoPath, 12)
}
<commit_msg>TWEAK: Make ipfs node in Migration012 be offline.<commit_after>package migrations

import (
	"context"
	"encoding/json"
	"io/ioutil"
	"os"
	"path"

	"github.com/OpenBazaar/jsonpb"
	"github.com/OpenBazaar/openbazaar-go/ipfs"
	"github.com/OpenBazaar/openbazaar-go/pb"
	"github.com/golang/protobuf/proto"
	ipfscore "github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
)

const migration012_ListingVersionForMarkupListings = 4

type Migration012 struct{}

type Migration012_ListingData struct {
	Hash         string   `json:"hash"`
	Slug         string   `json:"slug"`
	Title        string   `json:"title"`
	Categories   []string `json:"categories"`
	NSFW         bool     `json:"nsfw"`
	ContractType string   `json:"contractType"`
	Description  string   `json:"description"`
	Thumbnail    struct {
		Tiny   string `json:"tiny"`
		Small  string `json:"small"`
		Medium string `json:"medium"`
	} `json:"thumbnail"`
	Price struct {
		CurrencyCode string  `json:"currencyCode"`
		Amount       uint64  `json:"amount"`
		Modifier     float32 `json:"modifier"`
	} `json:"price"`
	ShipsTo            []string `json:"shipsTo"`
	FreeShipping       []string `json:"freeShipping"`
	Language           string   `json:"language"`
	AverageRating      float32  `json:"averageRating"`
	RatingCount        uint32   `json:"ratingCount"`
	ModeratorIDs       []string `json:"moderators"`
	AcceptedCurrencies []string `json:"acceptedCurrencies"`
	CoinType           string   `json:"coinType"`
}

func Migration012_listingHasNewFeaturesAndOldVersion(sl *pb.SignedListing) bool {
	metadata := sl.Listing.Metadata
	if metadata == nil {
		return false
	}
	return metadata.Version == 3 &&
		metadata.PriceModifier != 0
}

func Migration012_GetIdentityKey(repoPath, databasePassword string, testnetEnabled bool) ([]byte, error) {
	db, err := OpenDB(repoPath, databasePassword, testnetEnabled)
	if err != nil {
		return nil, err
	}
	defer db.Close()

	var identityKey []byte
	err = db.
		QueryRow("select value from config where key=?", "identityKey").
		Scan(&identityKey)
	if err != nil {
		return nil, err
	}
	return identityKey, nil
}

func (Migration012) Up(repoPath, databasePassword string, testnetEnabled bool) error {
	listingsIndexFilePath := path.Join(repoPath, "root", "listings.json")

	// Find all crypto listings
	listingsIndexJSONBytes, err := ioutil.ReadFile(listingsIndexFilePath)
	if err != nil {
		return err
	}

	listingsIndex := []*Migration012_ListingData{}
	err = json.Unmarshal(listingsIndexJSONBytes, &listingsIndex)
	if err != nil {
		return err
	}

	cryptoListings := []*Migration012_ListingData{}
	for _, listingAbstract := range listingsIndex {
		if listingAbstract.ContractType == "CRYPTOCURRENCY" {
			cryptoListings = append(cryptoListings, listingAbstract)
		}
	}

	// Finish early If no crypto listings
	if len(cryptoListings) == 0 {
		return writeRepoVer(repoPath, 13)
	}

	// Check each crypto listing for markup
	markupListings := []*pb.SignedListing{}
	for _, listingAbstract := range cryptoListings {
		listingJSONBytes, err := ioutil.ReadFile(migration012_listingFilePath(repoPath, listingAbstract.Slug))
		if err != nil {
			return err
		}
		sl := new(pb.SignedListing)
		err = jsonpb.UnmarshalString(string(listingJSONBytes), sl)
		if err != nil {
			return err
		}

		if Migration012_listingHasNewFeaturesAndOldVersion(sl) {
			markupListings = append(markupListings, sl)
		}
	}

	// Finish early If no crypto listings with new features are found
	if len(markupListings) == 0 {
		return writeRepoVer(repoPath, 13)
	}

	// Setup signing capabilities
	identityKey, err := Migration012_GetIdentityKey(repoPath, databasePassword, testnetEnabled)
	if err != nil {
		return err
	}

	identity, err := ipfs.IdentityFromKey(identityKey)
	if err != nil {
		return err
	}

	// IPFS node setup
	r, err := fsrepo.Open(repoPath)
	if err != nil {
		return err
	}
	cctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	cfg, err := r.Config()
	if err != nil {
		return err
	}

	cfg.Identity = identity

	ncfg := &ipfscore.BuildCfg{
		Repo:   r,
		Online: false,
		ExtraOpts: map[string]bool{
			"mplex": true,
		},
		DNSResolver: nil,
		Routing:     nil,
	}

	nd, err := ipfscore.NewNode(cctx, ncfg)
	if err != nil {
		return err
	}
	defer nd.Close()

	// Update each listing to have the latest version number and resave
	// Save the new hashes for each changed listing so we can update the index.
	hashes := make(map[string]string)

	for _, sl := range markupListings {
		sl.Listing.Metadata.Version = migration012_ListingVersionForMarkupListings

		serializedListing, err := proto.Marshal(sl.Listing)
		if err != nil {
			return err
		}
		idSig, err := nd.PrivateKey.Sign(serializedListing)
		if err != nil {
			return err
		}
		sl.Signature = idSig

		m := jsonpb.Marshaler{
			EnumsAsInts:  false,
			EmitDefaults: false,
			Indent:       "    ",
			OrigName:     false,
		}
		out, err := m.MarshalToString(sl)
		if err != nil {
			return err
		}

		filename := migration012_listingFilePath(repoPath, sl.Listing.Slug)
		if err := ioutil.WriteFile(filename, []byte(out), os.ModePerm); err != nil {
			return err
		}
		h, err := ipfs.GetHashOfFile(nd, filename)
		if err != nil {
			return err
		}
		hashes[sl.Listing.Slug] = h
	}

	// Update listing index
	indexBytes, err := ioutil.ReadFile(listingsIndexFilePath)
	if err != nil {
		return err
	}
	var index []Migration012_ListingData

	err = json.Unmarshal(indexBytes, &index)
	if err != nil {
		return err
	}

	for i, l := range index {
		h, ok := hashes[l.Slug]

		// Not one of the changed listings
		if !ok {
			continue
		}

		l.Hash = h
		index[i] = l
	}

	// Write it back to file
	ifile, err := os.Create(listingsIndexFilePath)
	if err != nil {
		return err
	}
	defer ifile.Close()

	j, jerr := json.MarshalIndent(index, "", "    ")
	if jerr != nil {
		return jerr
	}
	_, werr := ifile.Write(j)
	if werr != nil {
		return werr
	}

	_, err = ipfs.GetHashOfFile(nd, listingsIndexFilePath)
	if err != nil {
		return err
	}

	return writeRepoVer(repoPath, 13)
}

func migration012_listingFilePath(datadir string, slug string) string {
	return path.Join(datadir, "root", "listings", slug+".json")
}

func (Migration012) Down(repoPath, databasePassword string, testnetEnabled bool) error {
	return writeRepoVer(repoPath, 12)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"net"

	log "github.com/cihub/seelog"
	"github.com/stampzilla/stampzilla-go/stampzilla-server/logic"
	serverprotocol "github.com/stampzilla/stampzilla-go/stampzilla-server/protocol"
)

type NodeServer struct {
	Config           *ServerConfig         `inject:""`
	Logic            *logic.Logic          `inject:""`
	Nodes            *serverprotocol.Nodes `inject:""`
	WebsocketHandler *WebsocketHandler     `inject:""`
}

func NewNodeServer() *NodeServer {
	return &NodeServer{}
}

func (ns *NodeServer) Start() {
	log.Info("Starting NodeServer (:" + ns.Config.NodePort + ")")
	listen, err := net.Listen("tcp", ":"+ns.Config.NodePort)
	if err != nil {
		log.Error("listen error", err)
		return
	}

	ns.Logic.RestoreRulesFromFile("rules.json")

	go func() {
		for {
			fd, err := listen.Accept()
			if err != nil {
				log.Error("accept error", err)
				return
			}

			go ns.newNodeConnection(fd)
		}
	}()
}

func (ns *NodeServer) newNodeConnection(connection net.Conn) {
	// Recive data
	log.Info("New client connected")
	name := ""
	uuid := ""
	var logicChannel chan string
	for {
		reader := bufio.NewReader(connection)
		decoder := json.NewDecoder(reader)
		var info serverprotocol.Node
		err := decoder.Decode(&info)

		if err != nil {
			if err.Error() == "EOF" {
				log.Info(name, " - Client disconnected")
				if uuid != "" {
					ns.Nodes.Delete(uuid)
					close(logicChannel)
				}
				//TODO be able to not send everything always. perhaps implement remove instead of all?
				ns.WebsocketHandler.SendAllNodes()
				return
			}
			log.Warn("Not disconnect but error: ", err)
			//return here?
		} else {
			name = info.Name
			uuid = info.Uuid
			info.SetConn(connection)

			if logicChannel == nil {
				logicChannel = ns.Logic.ListenForChanges(uuid)
			}

			ns.Nodes.Add(&info)
			log.Info(info.Name, " - Got update on state")
			ns.WebsocketHandler.SendSingleNode(uuid)

			//Send to logic for evaluation
			state, _ := json.Marshal(info.State)
			logicChannel <- string(state)
		}

	}

}
<commit_msg>Added Uuid printout on status updates<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"net"

	log "github.com/cihub/seelog"
	"github.com/stampzilla/stampzilla-go/stampzilla-server/logic"
	serverprotocol "github.com/stampzilla/stampzilla-go/stampzilla-server/protocol"
)

type NodeServer struct {
	Config           *ServerConfig         `inject:""`
	Logic            *logic.Logic          `inject:""`
	Nodes            *serverprotocol.Nodes `inject:""`
	WebsocketHandler *WebsocketHandler     `inject:""`
}

func NewNodeServer() *NodeServer {
	return &NodeServer{}
}

func (ns *NodeServer) Start() {
	log.Info("Starting NodeServer (:" + ns.Config.NodePort + ")")
	listen, err := net.Listen("tcp", ":"+ns.Config.NodePort)
	if err != nil {
		log.Error("listen error", err)
		return
	}

	ns.Logic.RestoreRulesFromFile("rules.json")

	go func() {
		for {
			fd, err := listen.Accept()
			if err != nil {
				log.Error("accept error", err)
				return
			}

			go ns.newNodeConnection(fd)
		}
	}()
}

func (ns *NodeServer) newNodeConnection(connection net.Conn) {
	// Recive data
	log.Info("New client connected")
	name := ""
	uuid := ""
	var logicChannel chan string
	for {
		reader := bufio.NewReader(connection)
		decoder := json.NewDecoder(reader)
		var info serverprotocol.Node
		err := decoder.Decode(&info)

		if err != nil {
			if err.Error() == "EOF" {
				log.Info(name, " - Client disconnected")
				if uuid != "" {
					ns.Nodes.Delete(uuid)
					close(logicChannel)
				}
				//TODO be able to not send everything always. perhaps implement remove instead of all?
				ns.WebsocketHandler.SendAllNodes()
				return
			}
			log.Warn("Not disconnect but error: ", err)
			//return here?
		} else {
			name = info.Name
			uuid = info.Uuid
			info.SetConn(connection)

			if logicChannel == nil {
				logicChannel = ns.Logic.ListenForChanges(uuid)
			}

			ns.Nodes.Add(&info)
			log.Info(info.Uuid, " - ", info.Name, " - Got update on state")
			ns.WebsocketHandler.SendSingleNode(uuid)

			//Send to logic for evaluation
			state, _ := json.Marshal(info.State)
			logicChannel <- string(state)
		}

	}

}
<|endoftext|>


<commit_before>package presence_test

import (
	"fmt"
	. "launchpad.net/gocheck"
	"launchpad.net/gozk/zookeeper"
	"launchpad.net/juju/go/state/presence"
	"testing"
	"time"
)

func Test(t *testing.T) { TestingT(t) }

// waitFor blocks until conn knows that path exists. This is necessary because
// distinct zk connections don't always have precisely the same view of the data.
func waitFor(c *C, conn *zookeeper.Conn, path string) {
	stat, watch, err := conn.ExistsW(path)
	c.Assert(err, IsNil)
	if stat != nil {
		return
	}
	// Test code only, local server; if this event *isn't* the node coming into
	// existence, we'll find out soon enough, and we don't want to stay blocked.
	<-watch
}

type PresenceSuite struct {
	zkServer   *zookeeper.Server
	zkTestRoot string
	zkTestPort int
	zkAddr     string
	zkConn     *zookeeper.Conn
}

func (s *PresenceSuite) SetUpSuite(c *C) {
	var err error
	s.zkTestRoot = c.MkDir() + "/zookeeper"
	s.zkTestPort = 21810
	s.zkAddr = fmt.Sprint("localhost:", s.zkTestPort)

	s.zkServer, err = zookeeper.CreateServer(s.zkTestPort, s.zkTestRoot, "")
	if err != nil {
		c.Fatal("Cannot set up ZooKeeper server environment: ", err)
	}
	err = s.zkServer.Start()
	if err != nil {
		c.Fatal("Cannot start ZooKeeper server: ", err)
	}
}

func (s *PresenceSuite) TearDownSuite(c *C) {
	if s.zkServer != nil {
		s.zkServer.Destroy()
	}
}

// connect returns a zookeeper connection to s.zkAddr.
func (s *PresenceSuite) connect(c *C) *zookeeper.Conn {
	zk, session, err := zookeeper.Dial(s.zkAddr, 15e9)
	c.Assert(err, IsNil)
	c.Assert((<-session).Ok(), Equals, true)
	return zk
}

func (s *PresenceSuite) SetUpTest(c *C) {
	s.zkConn = s.connect(c)
}

func (s *PresenceSuite) TearDownTest(c *C) {
	// No need to recurse in this suite; just try to delete what we can see.
	children, _, err := s.zkConn.Children("/")
	if err == nil {
		for _, child := range children {
			s.zkConn.Delete("/"+child, -1)
		}
	}
	s.zkConn.Close()
}

var (
	_          = Suite(&PresenceSuite{})
	period     = time.Duration(2.5e7) // 25ms
	longEnough = period * 4           // longest possible time to detect a close
	path       = "/presence"
)

func assertChange(c *C, watch <-chan bool, expectAlive bool) {
	t := time.After(longEnough)
	select {
	case <-t:
		c.Log("Liveness change not detected")
		c.FailNow()
	case alive, ok := <-watch:
		c.Assert(ok, Equals, true)
		c.Assert(alive, Equals, expectAlive)
	}
}

func assertClose(c *C, watch <-chan bool) {
	t := time.After(longEnough)
	select {
	case <-t:
		c.Log("Connection loss not detected")
		c.FailNow()
	case _, ok := <-watch:
		c.Assert(ok, Equals, false)
	}
}

func assertNoChange(c *C, watch <-chan bool) {
	t := time.After(longEnough)
	select {
	case <-t:
		return
	case <-watch:
		c.Log("Unexpected liveness change")
		c.FailNow()
	}
}

func (s *PresenceSuite) TestNewPinger(c *C) {
	// Check not considered Alive before it exists.
	alive, err := presence.Alive(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)

	// Watch for life, and check the watch doesn't fire early.
	alive, watch, err := presence.AliveW(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)
	assertNoChange(c, watch)

	// Start a Pinger, and check the watch fires.
	p, err := presence.StartPinger(s.zkConn, path, period)
	c.Assert(err, IsNil)
	defer p.Close()
	assertChange(c, watch, true)

	// Check that Alive agrees.
	alive, err = presence.Alive(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)

	// Watch for life again, and check it doesn't change.
	alive, watch, err = presence.AliveW(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)
	assertNoChange(c, watch)
}

func (s *PresenceSuite) TestKillPinger(c *C) {
	// Start a Pinger and a watch, and check sanity.
	p, err := presence.StartPinger(s.zkConn, path, period)
	c.Assert(err, IsNil)
	alive, watch, err := presence.AliveW(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)
	assertNoChange(c, watch)

	// Kill the Pinger; check the watch fires and Alive agrees.
	p.Kill()
	assertChange(c, watch, false)
	alive, err = presence.Alive(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)

	// Check that the pinger's node was deleted.
	stat, err := s.zkConn.Exists(path)
	c.Assert(err, IsNil)
	c.Assert(stat, IsNil)
}

func (s *PresenceSuite) TestClosePinger(c *C) {
	// Start a Pinger and a watch, and check sanity.
	p, err := presence.StartPinger(s.zkConn, path, period)
	c.Assert(err, IsNil)
	alive, watch, err := presence.AliveW(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)
	assertNoChange(c, watch)

	// Close the Pinger; check the watch fires and Alive agrees.
	p.Close()
	assertChange(c, watch, false)
	alive, err = presence.Alive(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)

	// Check that the pinger's node is still present.
	stat, err := s.zkConn.Exists(path)
	c.Assert(err, IsNil)
	c.Assert(stat, NotNil)
}

func (s *PresenceSuite) TestBadData(c *C) {
	// Create a node that contains inappropriate data.
	_, err := s.zkConn.Create(path, "roflcopter", 0, zookeeper.WorldACL(zookeeper.PERM_ALL))
	c.Assert(err, IsNil)

	// Check it is not interpreted as a presence node by Alive.
	_, err = presence.Alive(s.zkConn, path)
	c.Assert(err, ErrorMatches, ".* is not a valid presence node: .*")

	// Check it is not interpreted as a presence node by Watch.
	_, watch, err := presence.AliveW(s.zkConn, path)
	c.Assert(watch, IsNil)
	c.Assert(err, ErrorMatches, ".* is not a valid presence node: .*")
}

func (s *PresenceSuite) TestDisconnectDeadWatch(c *C) {
	// Create a target node.
	p, err := presence.StartPinger(s.zkConn, path, period)
	c.Assert(err, IsNil)
	p.Close()

	// Start an alternate connection and ensure the node is stale.
	altConn := s.connect(c)
	waitFor(c, altConn, path)
	time.Sleep(longEnough)

	// Start a watch using the alternate connection.
	alive, watch, err := presence.AliveW(altConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)

	// Kill the watch connection and check it's alerted.
	altConn.Close()
	assertClose(c, watch)
}

func (s *PresenceSuite) TestDisconnectMissingWatch(c *C) {
	// Don't even create a target node.

	// Start watching on an alternate connection.
	altConn := s.connect(c)
	alive, watch, err := presence.AliveW(altConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)

	// Kill the watch connection and check it's alerted.
	altConn.Close()
	assertClose(c, watch)
}

func (s *PresenceSuite) DONTTestDisconnectAliveWatch(c *C) {
	// Start a Pinger on the main connection
	p, err := presence.StartPinger(s.zkConn, path, period)
	c.Assert(err, IsNil)
	defer p.Close()

	// Start watching on an alternate connection, forwarded over another
	// connection we can kill safely.
	altConn := s.connect(c)
	waitFor(c, altConn, path)
	alive, watch, err := presence.AliveW(altConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)

	// Kill the watch connection and check it's alerted.
	altConn.Close()
	assertClose(c, watch)
}

func (s *PresenceSuite) DONTTestDisconnectPinger(c *C) {
	// Start a Pinger on an alternate connection, forwarded over another
	// connection we can kill safely.
	altConn := s.connect(c)
	p, err := presence.StartPinger(altConn, path, period)
	c.Assert(err, IsNil)
	defer p.Close()

	// Watch on the "main" connection.
	waitFor(c, s.zkConn, path)
	alive, watch, err := presence.AliveW(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)

	// Kill the pinger connection and check the watch notices.
	altConn.Close()
	assertChange(c, watch, false)
}
<commit_msg>better failure-hiding<commit_after>package presence_test

import (
	"fmt"
	. "launchpad.net/gocheck"
	"launchpad.net/gozk/zookeeper"
	"launchpad.net/juju/go/state/presence"
	"testing"
	"time"
)

func Test(t *testing.T) { TestingT(t) }

// waitFor blocks until conn knows that path exists. This is necessary because
// distinct zk connections don't always have precisely the same view of the data.
func waitFor(c *C, conn *zookeeper.Conn, path string) {
	stat, watch, err := conn.ExistsW(path)
	c.Assert(err, IsNil)
	if stat != nil {
		return
	}
	// Test code only, local server; if this event *isn't* the node coming into
	// existence, we'll find out soon enough, and we don't want to stay blocked.
	<-watch
}

type PresenceSuite struct {
	zkServer   *zookeeper.Server
	zkTestRoot string
	zkTestPort int
	zkAddr     string
	zkConn     *zookeeper.Conn
}

func (s *PresenceSuite) SetUpSuite(c *C) {
	var err error
	s.zkTestRoot = c.MkDir() + "/zookeeper"
	s.zkTestPort = 21810
	s.zkAddr = fmt.Sprint("localhost:", s.zkTestPort)

	s.zkServer, err = zookeeper.CreateServer(s.zkTestPort, s.zkTestRoot, "")
	if err != nil {
		c.Fatal("Cannot set up ZooKeeper server environment: ", err)
	}
	err = s.zkServer.Start()
	if err != nil {
		c.Fatal("Cannot start ZooKeeper server: ", err)
	}
}

func (s *PresenceSuite) TearDownSuite(c *C) {
	if s.zkServer != nil {
		s.zkServer.Destroy()
	}
}

// connect returns a zookeeper connection to s.zkAddr.
func (s *PresenceSuite) connect(c *C) *zookeeper.Conn {
	zk, session, err := zookeeper.Dial(s.zkAddr, 15e9)
	c.Assert(err, IsNil)
	c.Assert((<-session).Ok(), Equals, true)
	return zk
}

func (s *PresenceSuite) SetUpTest(c *C) {
	s.zkConn = s.connect(c)
}

func (s *PresenceSuite) TearDownTest(c *C) {
	// No need to recurse in this suite; just try to delete what we can see.
	children, _, err := s.zkConn.Children("/")
	if err == nil {
		for _, child := range children {
			s.zkConn.Delete("/"+child, -1)
		}
	}
	s.zkConn.Close()
}

var (
	_          = Suite(&PresenceSuite{})
	period     = time.Duration(2.5e7) // 25ms
	longEnough = period * 4           // longest possible time to detect a close
	path       = "/presence"
)

func assertChange(c *C, watch <-chan bool, expectAlive bool) {
	t := time.After(longEnough)
	select {
	case <-t:
		c.Log("Liveness change not detected")
		c.FailNow()
	case alive, ok := <-watch:
		c.Assert(ok, Equals, true)
		c.Assert(alive, Equals, expectAlive)
	}
}

func assertClose(c *C, watch <-chan bool) {
	t := time.After(longEnough)
	select {
	case <-t:
		c.Log("Connection loss not detected")
		c.FailNow()
	case _, ok := <-watch:
		c.Assert(ok, Equals, false)
	}
}

func assertNoChange(c *C, watch <-chan bool) {
	t := time.After(longEnough)
	select {
	case <-t:
		return
	case <-watch:
		c.Log("Unexpected liveness change")
		c.FailNow()
	}
}

func (s *PresenceSuite) TestNewPinger(c *C) {
	// Check not considered Alive before it exists.
	alive, err := presence.Alive(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)

	// Watch for life, and check the watch doesn't fire early.
	alive, watch, err := presence.AliveW(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)
	assertNoChange(c, watch)

	// Start a Pinger, and check the watch fires.
	p, err := presence.StartPinger(s.zkConn, path, period)
	c.Assert(err, IsNil)
	defer p.Close()
	assertChange(c, watch, true)

	// Check that Alive agrees.
	alive, err = presence.Alive(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)

	// Watch for life again, and check it doesn't change.
	alive, watch, err = presence.AliveW(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)
	assertNoChange(c, watch)
}

func (s *PresenceSuite) TestKillPinger(c *C) {
	// Start a Pinger and a watch, and check sanity.
	p, err := presence.StartPinger(s.zkConn, path, period)
	c.Assert(err, IsNil)
	alive, watch, err := presence.AliveW(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)
	assertNoChange(c, watch)

	// Kill the Pinger; check the watch fires and Alive agrees.
	p.Kill()
	assertChange(c, watch, false)
	alive, err = presence.Alive(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)

	// Check that the pinger's node was deleted.
	stat, err := s.zkConn.Exists(path)
	c.Assert(err, IsNil)
	c.Assert(stat, IsNil)
}

func (s *PresenceSuite) TestClosePinger(c *C) {
	// Start a Pinger and a watch, and check sanity.
	p, err := presence.StartPinger(s.zkConn, path, period)
	c.Assert(err, IsNil)
	alive, watch, err := presence.AliveW(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)
	assertNoChange(c, watch)

	// Close the Pinger; check the watch fires and Alive agrees.
	p.Close()
	assertChange(c, watch, false)
	alive, err = presence.Alive(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)

	// Check that the pinger's node is still present.
	stat, err := s.zkConn.Exists(path)
	c.Assert(err, IsNil)
	c.Assert(stat, NotNil)
}

func (s *PresenceSuite) TestBadData(c *C) {
	// Create a node that contains inappropriate data.
	_, err := s.zkConn.Create(path, "roflcopter", 0, zookeeper.WorldACL(zookeeper.PERM_ALL))
	c.Assert(err, IsNil)

	// Check it is not interpreted as a presence node by Alive.
	_, err = presence.Alive(s.zkConn, path)
	c.Assert(err, ErrorMatches, ".* is not a valid presence node: .*")

	// Check it is not interpreted as a presence node by Watch.
	_, watch, err := presence.AliveW(s.zkConn, path)
	c.Assert(watch, IsNil)
	c.Assert(err, ErrorMatches, ".* is not a valid presence node: .*")
}

func (s *PresenceSuite) TestDisconnectDeadWatch(c *C) {
	// Create a target node.
	p, err := presence.StartPinger(s.zkConn, path, period)
	c.Assert(err, IsNil)
	p.Close()

	// Start an alternate connection and ensure the node is stale.
	altConn := s.connect(c)
	waitFor(c, altConn, path)
	time.Sleep(longEnough)

	// Start a watch using the alternate connection.
	alive, watch, err := presence.AliveW(altConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)

	// Kill the watch connection and check it's alerted.
	altConn.Close()
	assertClose(c, watch)
}

func (s *PresenceSuite) TestDisconnectMissingWatch(c *C) {
	// Don't even create a target node.

	// Start watching on an alternate connection.
	altConn := s.connect(c)
	alive, watch, err := presence.AliveW(altConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, false)

	// Kill the watch's connection and check it's alerted.
	altConn.Close()
	assertClose(c, watch)
}

func (s *PresenceSuite) TestDisconnectAliveWatch(c *C) {
	c.ExpectFailure("Waiting on gozk change to eliminate occasional panic after Close")
	c.FailNow()

	// Start a Pinger on the main connection
	p, err := presence.StartPinger(s.zkConn, path, period)
	c.Assert(err, IsNil)
	defer p.Close()

	// Start watching on an alternate connection.
	altConn := s.connect(c)
	waitFor(c, altConn, path)
	alive, watch, err := presence.AliveW(altConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)

	// Kill the watch's connection and check it's alerted.
	altConn.Close()
	assertClose(c, watch)
}

func (s *PresenceSuite) TestDisconnectPinger(c *C) {
	c.ExpectFailure("Waiting on gozk change to eliminate consistent panic after Close")
	c.FailNow()

	// Start a Pinger on an alternate connection.
	altConn := s.connect(c)
	p, err := presence.StartPinger(altConn, path, period)
	c.Assert(err, IsNil)
	defer p.Close()

	// Watch on the "main" connection.
	waitFor(c, s.zkConn, path)
	alive, watch, err := presence.AliveW(s.zkConn, path)
	c.Assert(err, IsNil)
	c.Assert(alive, Equals, true)

	// Kill the pinger connection and check the watch notices.
	altConn.Close()
	assertChange(c, watch, false)
}
<|endoftext|>


<commit_before>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package store

import (
	"bytes"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"golang.org/x/net/context"
)

// FileSystem is an interface which defines an open method similar to http.FileSystem,
// but which also includes a context parameter.
type FileSystem interface {
	Open(ctx context.Context, path string) (http.File, error)
}

// NewFileSystem creates a new FileSystem using an http.FileSystem as the underlying
// storage.
func NewFileSystem(fs http.FileSystem) FileSystem {
	return &fileSystem{fs}
}

type fileSystem struct {
	http.FileSystem
}

// Open implements FileSystem.
func (cfs *fileSystem) Open(ctx context.Context, path string) (http.File, error) {
	return cfs.FileSystem.Open(path)
}

// RemoteFileSystem is an extension of the http.FileSystem interface
// which includes the RemoteOpen method.
type RemoteFileSystem interface {
	http.FileSystem

	// RemoteOpen returns a File which
	RemoteOpen(string) (*File, error)
}

// remoteFileSystem implements RemoteFileSystem
type remoteFileSystem struct {
	client Client
}

// NewRemoteFileSystem creates a new file system using the given Client to handle
// file requests.
func NewRemoteFileSystem(c Client) RemoteFileSystem {
	return &remoteFileSystem{
		client: c,
	}
}

// file is a basic representation of a remote file such that all operations (i.e.
// seeking) will work correctly.
type file struct {
	io.ReadSeeker
	stat *fileInfo
}

// RemoteOpen returns a *File which represents the remote file, and implements
// io.ReadCloser which reads the file contents from the remote system.
func (fs *remoteFileSystem) RemoteOpen(path string) (*File, error) {
	rf, err := fs.client.Get(path)
	if err != nil {
		return nil, err
	}
	return rf, nil
}

// Open the given file and return an http.File implementation representing it.  This method
// will block until the file has been completely fetched (http.File implements io.Seeker
// which means that for a trivial implementation we need all the underlying data).
func (fs *remoteFileSystem) Open(path string) (http.File, error) {
	rf, err := fs.RemoteOpen(path)
	if err != nil {
		return nil, err
	}
	defer rf.Close()

	buf, err := ioutil.ReadAll(rf)
	if err != nil {
		return nil, err
	}

	return &file{
		ReadSeeker: bytes.NewReader(buf),
		stat: &fileInfo{
			name:    rf.Name,
			size:    rf.Size,
			modTime: rf.ModTime,
		},
	}, nil
}

// Close is a nop as we have already closed the original file.
func (f *file) Close() error {
	return nil
}

// Implements http.File.
func (f *file) Readdir(int) ([]os.FileInfo, error) {
	return nil, nil
}

// FileInfo is a simple implementation of os.FileInfo.
type fileInfo struct {
	name    string
	size    int64
	modTime time.Time
}

func (f *fileInfo) Name() string       { return f.name }
func (f *fileInfo) Size() int64        { return f.size }
func (f *fileInfo) Mode() os.FileMode  { return os.FileMode(0777) }
func (f *fileInfo) ModTime() time.Time { return f.modTime }
func (f *fileInfo) IsDir() bool        { return false }
func (f *fileInfo) Sys() interface{}   { return nil }

func (f *file) Stat() (os.FileInfo, error) {
	return f.stat, nil
}
<commit_msg>Tidy method instance variable name.<commit_after>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package store

import (
	"bytes"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"golang.org/x/net/context"
)

// FileSystem is an interface which defines an open method similar to http.FileSystem,
// but which also includes a context parameter.
type FileSystem interface {
	Open(ctx context.Context, path string) (http.File, error)
}

// NewFileSystem creates a new FileSystem using an http.FileSystem as the underlying
// storage.
func NewFileSystem(fs http.FileSystem) FileSystem {
	return &fileSystem{fs}
}

type fileSystem struct {
	http.FileSystem
}

// Open implements FileSystem.
func (fs *fileSystem) Open(ctx context.Context, path string) (http.File, error) {
	return fs.FileSystem.Open(path)
}

// RemoteFileSystem is an extension of the http.FileSystem interface
// which includes the RemoteOpen method.
type RemoteFileSystem interface {
	http.FileSystem

	// RemoteOpen returns a File which
	RemoteOpen(string) (*File, error)
}

// remoteFileSystem implements RemoteFileSystem
type remoteFileSystem struct {
	client Client
}

// NewRemoteFileSystem creates a new file system using the given Client to handle
// file requests.
func NewRemoteFileSystem(c Client) RemoteFileSystem {
	return &remoteFileSystem{
		client: c,
	}
}

// file is a basic representation of a remote file such that all operations (i.e.
// seeking) will work correctly.
type file struct {
	io.ReadSeeker
	stat *fileInfo
}

// RemoteOpen returns a *File which represents the remote file, and implements
// io.ReadCloser which reads the file contents from the remote system.
func (fs *remoteFileSystem) RemoteOpen(path string) (*File, error) {
	rf, err := fs.client.Get(path)
	if err != nil {
		return nil, err
	}
	return rf, nil
}

// Open the given file and return an http.File implementation representing it.  This method
// will block until the file has been completely fetched (http.File implements io.Seeker
// which means that for a trivial implementation we need all the underlying data).
func (fs *remoteFileSystem) Open(path string) (http.File, error) {
	rf, err := fs.RemoteOpen(path)
	if err != nil {
		return nil, err
	}
	defer rf.Close()

	buf, err := ioutil.ReadAll(rf)
	if err != nil {
		return nil, err
	}

	return &file{
		ReadSeeker: bytes.NewReader(buf),
		stat: &fileInfo{
			name:    rf.Name,
			size:    rf.Size,
			modTime: rf.ModTime,
		},
	}, nil
}

// Close is a nop as we have already closed the original file.
func (f *file) Close() error {
	return nil
}

// Implements http.File.
func (f *file) Readdir(int) ([]os.FileInfo, error) {
	return nil, nil
}

// FileInfo is a simple implementation of os.FileInfo.
type fileInfo struct {
	name    string
	size    int64
	modTime time.Time
}

func (f *fileInfo) Name() string       { return f.name }
func (f *fileInfo) Size() int64        { return f.size }
func (f *fileInfo) Mode() os.FileMode  { return os.FileMode(0777) }
func (f *fileInfo) ModTime() time.Time { return f.modTime }
func (f *fileInfo) IsDir() bool        { return false }
func (f *fileInfo) Sys() interface{}   { return nil }

func (f *file) Stat() (os.FileInfo, error) {
	return f.stat, nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/signal"
	"time"
	"errors"
	"plugin"

	"github.com/DarkMetrix/monitor/agent/src/config"
	"github.com/DarkMetrix/monitor/agent/src/queue"

	"github.com/DarkMetrix/monitor/agent/src/input"
	"github.com/DarkMetrix/monitor/agent/src/output"

	log "github.com/cihub/seelog"
)

//Init log
func InitLog(path string) error {
	logger, err := log.LoggerFromConfigAsFile(path)

	if err != nil {
		return err
	}

	err = log.ReplaceLogger(logger)

	if err != nil {
		return err
	}

	return nil
}

//Init config
func InitConfig(path string) (*config.Config, error) {
	globalConfig := config.GetConfig()

	if globalConfig == nil {
		return nil, errors.New("Get global config failed!")
	}

	err := globalConfig.Init(path)

	if err != nil {
		return nil, err
	}

	return globalConfig, nil
}

//Init agent plugin libraries
func InitPluginLibs(config *config.Config) error {
	inputs := make(map[string]bool)

	for _, pluginConfig := range config.Inputs {
		if !pluginConfig.Active {
			continue
		}

		//Initialize plugin
		_, err := plugin.Open(pluginConfig.Path)

		if err != nil {
			return err
		}

		inputs[pluginConfig.Name] = true
	}

	for _, pluginConfig := range config.Outputs {
		if !pluginConfig.Active {
			continue
		}

		//Initialize plugin
		_, err := plugin.Open(pluginConfig.Path)

		if err != nil {
			return err
		}

		if len(pluginConfig.Inputs) == 0 {
			continue
		}

		for inputName, isActive := range pluginConfig.Inputs {
			if !isActive {
				continue
			}

			_, ok := inputs[inputName]

			if !ok {
				return errors.New("'" + pluginConfig.Name + "' output plugin's input plugin '" + inputName + "' not found or not active!")
			}
		}
	}

	return nil
}

//Init transfer queue
func InitTransferQueue(bufferSize int) (*queue.TransferQueue, error) {
	transfer := queue.NewTransferQueue(bufferSize)

	return transfer, nil
}

func main() {
	defer log.Flush()

	defer func() {
		err := recover()

		if err != nil {
			log.Critical("Got panic, err:", err)
		}
	} ()

	//Initialize log using configuration from "../conf/log.config"
	err := InitLog("../conf/log.config")

	if err != nil {
		log.Warnf("Read config failed! error:%s", err)
		return
	}

	log.Info(time.Now().String(), "Starting monitor agent ... ")

	//Initialize the configuration from "../conf/config.json"
	log.Info("Initialize monitor_agent configuration from ../conf/config.json ...")
	config, err := InitConfig("../conf/config.json")

	if err != nil {
		log.Warnf("Initialize monitor agent configuration failed! error:%s", err)
		return
	}

	log.Info("Initialize monitor agent configuration successed! config:", config)

	//Initialize all plugin libs
	log.Info("Initialize monitor agent plugin libs ...")
	err = InitPluginLibs(config)

	if err != nil {
		log.Warnf("Initialize monitor agent plugin libs failed! error:%s", err)
		return
	}

	log.Info("Initialize monitor agent plugin libs successed!")

	//Init queue between input plugin and output plugin
	log.Info("Initialize monitor agent transfer queue ...")
	transfer, err := InitTransferQueue(config.Node.TransferQueue.BufferSize)

	if err != nil {
		log.Warnf("Initialize monitor agent transfer queue failed! error:%s", err)
		return
	}

	log.Info("Initialize monitor agent transfer queue successed! buffer size:", config.Node.TransferQueue.BufferSize)

	//Start output plugins
	log.Info("Initialize monitor agent output plugin ...")
	outputPluginManager := output.NewOutputPluginManager(config.Node, config.Outputs, transfer)

	err = outputPluginManager.Init()

	if err != nil {
		log.Warnf("Initialize monitor agent output plugin failed! error:%s", err)
		return
	}

	log.Info("Initialize monitor agent output plugin successed!")

	outputPluginManager.Run()

	//Start input plugins
	log.Info("Initialize monitor agent input plugin ...")
	inputPluginManager := input.NewInputPluginManager(config.Node, config.Inputs, transfer)

	err = inputPluginManager.Init()

	if err != nil {
		log.Warnf("Initialize monitor agent input plugin failed! error:%s", err)
		return
	}

	log.Info("Initialize monitor agent input plugin successed!")

	inputPluginManager.Run()

	//Deal with signals
	signalChannel := make(chan os.Signal, 1)
	signal.Notify(signalChannel, os.Interrupt, os.Kill)

	signalOccur := <- signalChannel

	log.Info("Signal occured, signal:", signalOccur.String())
}
<commit_msg>feat:Add panic<commit_after>package main

import (
	"os"
	"os/signal"
	"net"
	"time"
	"errors"
	"plugin"

	"github.com/DarkMetrix/monitor/agent/src/config"
	"github.com/DarkMetrix/monitor/agent/src/queue"

	"github.com/DarkMetrix/monitor/agent/src/input"
	"github.com/DarkMetrix/monitor/agent/src/output"

	log "github.com/cihub/seelog"
)

//Init log
func InitLog(path string) {
	logger, err := log.LoggerFromConfigAsFile(path)

	if err != nil {
		panic(err)
	}

	err = log.ReplaceLogger(logger)

	if err != nil {
		panic(err)
	}
}

//Get local machine ip
func getLocalIp() (string, error) {
	addrs, err := net.InterfaceAddrs()

	if err != nil {
		log.Warn("Get local ip failed! err:" + err.Error())
		return "", err
	}

	for _, addr := range addrs {
		if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				return ipnet.IP.String(), nil
			}
		}
	}

	return "", nil
}

//Init config
func InitConfig(path string) *config.Config{
	log.Info("Initialize monitor_agent configuration from " + path + " ...")

	globalConfig := config.GetConfig()

	if globalConfig == nil {
		panic(errors.New("Get global config failed!"))
	}

	err := globalConfig.Init(path)

	if err != nil {
		panic(err)
	}

	//Check ip and name, if empty use host name as the name and use one of the local ip as the ip
	if len(globalConfig.Node.Name) == 0 {
		globalConfig.Node.Name, err = os.Hostname()

		if err != nil {
			panic(err)
		}
	}

	if len(globalConfig.Node.IP) == 0 {
		globalConfig.Node.IP, err = getLocalIp()

		if err != nil {
			panic(err)
		}
	}

	return globalConfig
}

//Init agent plugin libraries
func InitPluginLibs(config *config.Config) {
	log.Info("Initialize monitor agent plugin libs ...")

	inputs := make(map[string]bool)

	for _, pluginConfig := range config.Inputs {
		if !pluginConfig.Active {
			continue
		}

		//Initialize plugin
		_, err := plugin.Open(pluginConfig.Path)

		if err != nil {
			panic(err)
		}

		inputs[pluginConfig.Name] = true
	}

	for _, pluginConfig := range config.Outputs {
		if !pluginConfig.Active {
			continue
		}

		//Initialize plugin
		_, err := plugin.Open(pluginConfig.Path)

		if err != nil {
			panic(err)
		}

		if len(pluginConfig.Inputs) == 0 {
			continue
		}

		for inputName, isActive := range pluginConfig.Inputs {
			if !isActive {
				continue
			}

			_, ok := inputs[inputName]

			if !ok {
				panic(errors.New("'" + pluginConfig.Name + "' output plugin's input plugin '" + inputName + "' not found or not active!"))
			}
		}
	}
}

//Init transfer queue
func InitTransferQueue(bufferSize int) *queue.TransferQueue {
	log.Info("Initialize monitor agent transfer queue ...")

	transfer := queue.NewTransferQueue(bufferSize)

	return transfer
}

func main() {
	defer log.Flush()

	defer func() {
		err := recover()

		if err != nil {
			log.Critical("Got panic, err:", err)
		}
	} ()

	//Initialize log using configuration from "../conf/log.config"
	InitLog("../conf/log.config")

	log.Info(time.Now().String(), "Starting monitor agent ... ")
	log.Info("Version: " + config.Version)

	//Initialize the configuration from "../conf/config.json"
	config := InitConfig("../conf/config.json")

	//Initialize all plugin libs
	InitPluginLibs(config)

	//Init queue between input plugin and output plugin
	transfer := InitTransferQueue(config.Node.TransferQueue.BufferSize)

	//Start output plugins
	log.Info("Initialize monitor agent output plugin ...")
	outputPluginManager := output.NewOutputPluginManager(config.Node, config.Outputs, transfer)

	err := outputPluginManager.Init()

	if err != nil {
		log.Warnf("Initialize monitor agent output plugin failed! error:%s", err)
		return
	}

	log.Info("Initialize monitor agent output plugin successed!")

	outputPluginManager.Run()

	//Start input plugins
	log.Info("Initialize monitor agent input plugin ...")
	inputPluginManager := input.NewInputPluginManager(config.Node, config.Inputs, transfer)

	err = inputPluginManager.Init()

	if err != nil {
		log.Warnf("Initialize monitor agent input plugin failed! error:%s", err)
		return
	}

	log.Info("Initialize monitor agent input plugin successed!")

	inputPluginManager.Run()

	//Deal with signals
	signalChannel := make(chan os.Signal, 1)
	signal.Notify(signalChannel, os.Interrupt, os.Kill)

	signalOccur := <- signalChannel

	log.Info("Signal occured, signal:", signalOccur.String())
}
<|endoftext|>


<commit_before>/*
Copyright 2018 Mirantis

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 e2e

import (
	"context"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	. "github.com/onsi/gomega"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/pkg/api/v1"

	"github.com/Mirantis/virtlet/tests/e2e/framework"
	. "github.com/Mirantis/virtlet/tests/e2e/ginkgo-ext"
)

const (
	gendocTmpDir = "/tmp"
)

var _ = Describe("virtletctl", func() {
	It("Should display usage info on help subcommand", func(done Done) {
		defer close(done)

		ctx, closeFunc := context.WithCancel(context.Background())
		defer closeFunc()
		localExecutor := framework.LocalExecutor(ctx)

		By("Calling virtletctl help")
		_, err := framework.RunSimple(localExecutor, "_output/virtletctl", "help")
		Expect(err).NotTo(HaveOccurred())
	}, 10)

	It("Should dump Virtlet metadata on dump-metadata subcommand", func(done Done) {
		defer close(done)

		ctx, closeFunc := context.WithCancel(context.Background())
		defer closeFunc()
		localExecutor := framework.LocalExecutor(ctx)

		By("Calling virtletctl dump-metadata")
		output, err := framework.RunSimple(localExecutor, "_output/virtletctl", "dump-metadata")
		Expect(err).NotTo(HaveOccurred())
		Expect(output).To(ContainSubstring("Virtlet pod name:"))
		Expect(output).To(ContainSubstring("Sandboxes:"))
		Expect(output).To(ContainSubstring("Images:"))
	}, 60)

	It("Should generate documentation on gendoc subcommand", func(done Done) {
		defer close(done)

		ctx, closeFunc := context.WithCancel(context.Background())
		defer closeFunc()
		localExecutor := framework.LocalExecutor(ctx)

		By("Calling virtletctl gendoc")
		_, err := framework.RunSimple(localExecutor, "_output/virtletctl", "gendoc", gendocTmpDir)
		Expect(err).NotTo(HaveOccurred())
		content, err := ioutil.ReadFile(filepath.Join(gendocTmpDir, "virtletctl.md"))
		Expect(err).NotTo(HaveOccurred())
		Expect(content).To(ContainSubstring("Virtlet control tool"))
		Expect(content).To(ContainSubstring("Synopsis"))
		Expect(content).To(ContainSubstring("Options"))
	}, 10)

	Context("SSH subcommand", func() {
		var (
			vm           *framework.VMInterface
			tempfileName string
		)

		BeforeAll(func() {
			cm := &v1.ConfigMap{
				ObjectMeta: metav1.ObjectMeta{
					Name: "sshkey",
				},
				Data: map[string]string{
					"authorized_keys": sshPublicKey,
				},
			}
			_, err := controller.ConfigMaps().Create(cm)
			Expect(err).NotTo(HaveOccurred())

			vm = controller.VM("cirros-vm")
			vm.Create(VMOptions{
				SSHKeySource: "configmap/sshkey",
			}.applyDefaults(), time.Minute*5, nil)

			waitSSH(vm)

			tempfile, err := ioutil.TempFile("", "")
			Expect(err).NotTo(HaveOccurred())
			defer tempfile.Close()
			tempfileName = tempfile.Name()

			strippedKey := strings.Replace(sshPrivateKey, "\t", "", -1)
			_, err = tempfile.Write([]byte(strippedKey))
			Expect(err).NotTo(HaveOccurred())
			Expect(os.Chmod(tempfileName, 0600)).To(Succeed())
		})

		AfterAll(func() {
			deleteVM(vm)
			controller.ConfigMaps().Delete("sshkey", nil)
			os.Remove(tempfileName)
		})

		It("Should be able to access the pod via ssh using ssh subcommand", func(done Done) {
			By("Calling virtletctl ssh cirros@cirros-vm hostname")
			defer close(done)

			ctx, closeFunc := context.WithCancel(context.Background())
			defer closeFunc()
			localExecutor := framework.LocalExecutor(ctx)

			output, err := framework.RunSimple(localExecutor, "_output/virtletctl", "ssh", "cirros@cirros-vm", "--", "-i", tempfileName, "hostname")
			Expect(err).NotTo(HaveOccurred())
			Expect(output).To(Equal("cirros-vm"))
		}, 60)
	})

	It("Should return libvirt version on virsh subcommand", func(done Done) {
		defer close(done)

		ctx, closeFunc := context.WithCancel(context.Background())
		defer closeFunc()
		localExecutor := framework.LocalExecutor(ctx)

		By("Calling virtletctl virsh version")
		output, err := framework.RunSimple(localExecutor, "_output/virtletctl", "virsh", "version")
		Expect(err).NotTo(HaveOccurred())
		Expect(output).To(ContainSubstring("Compiled against library:"))
		Expect(output).To(ContainSubstring("Using library:"))
	}, 60)
})

var _ = Describe("virtletctl unsafe", func() {
	BeforeAll(func() {
		includeUnsafe()
	})

	Context("Should install itself as a kubectl plugin on install subcommand", func() {
		It("Should not fail during install", func(done Done) {
			defer close(done)

			ctx, closeFunc := context.WithCancel(context.Background())
			defer closeFunc()
			localExecutor := framework.LocalExecutor(ctx)

			By("Calling virtletctl install")
			_, err := framework.RunSimple(localExecutor, "_output/virtletctl", "install")
			Expect(err).NotTo(HaveOccurred())

			By("Calling kubectl plugin virt help")
			_, err = framework.RunSimple(localExecutor, "kubectl", "plugin", "virt", "help")
			Expect(err).NotTo(HaveOccurred())
		}, 60)
	})
})
<commit_msg>Remove test for docs generation<commit_after>/*
Copyright 2018 Mirantis

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 e2e

import (
	"context"
	"io/ioutil"
	"os"
	"strings"
	"time"

	. "github.com/onsi/gomega"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/pkg/api/v1"

	"github.com/Mirantis/virtlet/tests/e2e/framework"
	. "github.com/Mirantis/virtlet/tests/e2e/ginkgo-ext"
)

const (
	gendocTmpDir = "/tmp"
)

var _ = Describe("virtletctl", func() {
	It("Should display usage info on help subcommand", func(done Done) {
		defer close(done)

		ctx, closeFunc := context.WithCancel(context.Background())
		defer closeFunc()
		localExecutor := framework.LocalExecutor(ctx)

		By("Calling virtletctl help")
		_, err := framework.RunSimple(localExecutor, "_output/virtletctl", "help")
		Expect(err).NotTo(HaveOccurred())
	}, 10)

	It("Should dump Virtlet metadata on dump-metadata subcommand", func(done Done) {
		defer close(done)

		ctx, closeFunc := context.WithCancel(context.Background())
		defer closeFunc()
		localExecutor := framework.LocalExecutor(ctx)

		By("Calling virtletctl dump-metadata")
		output, err := framework.RunSimple(localExecutor, "_output/virtletctl", "dump-metadata")
		Expect(err).NotTo(HaveOccurred())
		Expect(output).To(ContainSubstring("Virtlet pod name:"))
		Expect(output).To(ContainSubstring("Sandboxes:"))
		Expect(output).To(ContainSubstring("Images:"))
	}, 60)

	Context("SSH subcommand", func() {
		var (
			vm           *framework.VMInterface
			tempfileName string
		)

		BeforeAll(func() {
			cm := &v1.ConfigMap{
				ObjectMeta: metav1.ObjectMeta{
					Name: "sshkey",
				},
				Data: map[string]string{
					"authorized_keys": sshPublicKey,
				},
			}
			_, err := controller.ConfigMaps().Create(cm)
			Expect(err).NotTo(HaveOccurred())

			vm = controller.VM("cirros-vm")
			vm.Create(VMOptions{
				SSHKeySource: "configmap/sshkey",
			}.applyDefaults(), time.Minute*5, nil)

			waitSSH(vm)

			tempfile, err := ioutil.TempFile("", "")
			Expect(err).NotTo(HaveOccurred())
			defer tempfile.Close()
			tempfileName = tempfile.Name()

			strippedKey := strings.Replace(sshPrivateKey, "\t", "", -1)
			_, err = tempfile.Write([]byte(strippedKey))
			Expect(err).NotTo(HaveOccurred())
			Expect(os.Chmod(tempfileName, 0600)).To(Succeed())
		})

		AfterAll(func() {
			deleteVM(vm)
			controller.ConfigMaps().Delete("sshkey", nil)
			os.Remove(tempfileName)
		})

		It("Should be able to access the pod via ssh using ssh subcommand", func(done Done) {
			By("Calling virtletctl ssh cirros@cirros-vm hostname")
			defer close(done)

			ctx, closeFunc := context.WithCancel(context.Background())
			defer closeFunc()
			localExecutor := framework.LocalExecutor(ctx)

			output, err := framework.RunSimple(localExecutor, "_output/virtletctl", "ssh", "cirros@cirros-vm", "--", "-i", tempfileName, "hostname")
			Expect(err).NotTo(HaveOccurred())
			Expect(output).To(Equal("cirros-vm"))
		}, 60)
	})

	It("Should return libvirt version on virsh subcommand", func(done Done) {
		defer close(done)

		ctx, closeFunc := context.WithCancel(context.Background())
		defer closeFunc()
		localExecutor := framework.LocalExecutor(ctx)

		By("Calling virtletctl virsh version")
		output, err := framework.RunSimple(localExecutor, "_output/virtletctl", "virsh", "version")
		Expect(err).NotTo(HaveOccurred())
		Expect(output).To(ContainSubstring("Compiled against library:"))
		Expect(output).To(ContainSubstring("Using library:"))
	}, 60)
})

var _ = Describe("virtletctl unsafe", func() {
	BeforeAll(func() {
		includeUnsafe()
	})

	Context("Should install itself as a kubectl plugin on install subcommand", func() {
		It("Should not fail during install", func(done Done) {
			defer close(done)

			ctx, closeFunc := context.WithCancel(context.Background())
			defer closeFunc()
			localExecutor := framework.LocalExecutor(ctx)

			By("Calling virtletctl install")
			_, err := framework.RunSimple(localExecutor, "_output/virtletctl", "install")
			Expect(err).NotTo(HaveOccurred())

			By("Calling kubectl plugin virt help")
			_, err = framework.RunSimple(localExecutor, "kubectl", "plugin", "virt", "help")
			Expect(err).NotTo(HaveOccurred())
		}, 60)
	})
})
<|endoftext|>


<commit_before>package subsumption_test

import (
	. "."
	"errors"
	gomock "github.com/golang/mock/gomock"
	"testing"
)

func TestCreate(t *testing.T) {
	agent := Agent{}

	if agent.Size() != 0 {
		t.Errorf("agent.Size() should be 0")
	}
}

func TestAddBehavior(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	behabior := NewMockBehavior(ctrl)
	agent := Agent{}

	agent.AddBehavior(behabior)

	if agent.Size() != 1 {
		t.Errorf("agent.Size() should be 1")
	}
}

func TestInit(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	behabior := NewMockBehavior(ctrl)
	behabior.EXPECT().Init()

	agent := Agent{}
	agent.AddBehavior(behabior)

	agent.Init()
}

func TestPerform(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	behabior := NewMockBehavior(ctrl)
	behabior.EXPECT().Sense().Return(true, nil)
	behabior.EXPECT().Perform().Return(true, nil)

	agent := Agent{}
	agent.AddBehavior(behabior)

	ret, err := agent.Perform()

	if err != nil {
		t.Errorf("unexpected agent.Perform() fail with : %v", err)
	}
	if ret != true {
		t.Errorf("agent.Perform() should be true because behabior is active")
	}
}

func TestPerformMulti(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	first := NewMockBehavior(ctrl)
	first.EXPECT().Sense().Return(false, nil)

	second := NewMockBehavior(ctrl)
	second.EXPECT().Sense().Return(true, nil)
	second.EXPECT().Perform().Return(true, nil)

	agent := Agent{}
	agent.AddBehavior(first)
	agent.AddBehavior(second)

	ret, err := agent.Perform()

	if err != nil {
		t.Errorf("agent.Perform() failed with : %v", err)
	}
	if ret != true {
		t.Errorf("agent.Perform() should be false because [second] behabior is active")
	}
}

func TestSenceError(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	behabior := NewMockBehavior(ctrl)
	behabior.EXPECT().Sense().Return(false, errors.New("unknown error"))

	agent := Agent{}
	agent.AddBehavior(behabior)

	ret, err := agent.Perform()

	if err != nil {
		t.Errorf("unexpected agent.Perform() fail with : %v", err)
	}
	if ret != false {
		t.Errorf("agent.Perform() should be false because no behavior is active")
	}
}
<commit_msg>add test case for Agent.Perform() with no active Behavior<commit_after>package subsumption_test

import (
	. "."
	"errors"
	gomock "github.com/golang/mock/gomock"
	"testing"
)

func TestCreate(t *testing.T) {
	agent := Agent{}

	if agent.Size() != 0 {
		t.Errorf("agent.Size() should be 0")
	}
}

func TestAddBehavior(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	behabior := NewMockBehavior(ctrl)
	agent := Agent{}

	agent.AddBehavior(behabior)

	if agent.Size() != 1 {
		t.Errorf("agent.Size() should be 1")
	}
}

func TestInit(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	behabior := NewMockBehavior(ctrl)
	behabior.EXPECT().Init()

	agent := Agent{}
	agent.AddBehavior(behabior)

	agent.Init()
}

func TestPerform(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	behabior := NewMockBehavior(ctrl)
	behabior.EXPECT().Sense().Return(true, nil)
	behabior.EXPECT().Perform().Return(true, nil)

	agent := Agent{}
	agent.AddBehavior(behabior)

	ret, err := agent.Perform()

	if err != nil {
		t.Errorf("unexpected agent.Perform() fail with : %v", err)
	}
	if ret != true {
		t.Errorf("agent.Perform() should be true because behabior is active")
	}
}

func TestPerformMulti(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	first := NewMockBehavior(ctrl)
	first.EXPECT().Sense().Return(false, nil)

	second := NewMockBehavior(ctrl)
	second.EXPECT().Sense().Return(true, nil)
	second.EXPECT().Perform().Return(true, nil)

	agent := Agent{}
	agent.AddBehavior(first)
	agent.AddBehavior(second)

	ret, err := agent.Perform()

	if err != nil {
		t.Errorf("agent.Perform() failed with : %v", err)
	}
	if ret != true {
		t.Errorf("agent.Perform() should be false because [second] behabior is active")
	}
}

func TestSenceError(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	behabior := NewMockBehavior(ctrl)
	behabior.EXPECT().Sense().Return(false, errors.New("unknown error"))

	agent := Agent{}
	agent.AddBehavior(behabior)

	ret, err := agent.Perform()

	if err != nil {
		t.Errorf("unexpected agent.Perform() fail with : %v", err)
	}
	if ret != false {
		t.Errorf("agent.Perform() should be false because no behavior is active")
	}
}

func TestPerformNoActive(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	first := NewMockBehavior(ctrl)
	first.EXPECT().Sense().Return(false, nil)

	second := NewMockBehavior(ctrl)
	second.EXPECT().Sense().Return(false, nil)

	agent := Agent{}
	agent.AddBehavior(first)
	agent.AddBehavior(second)

	ret, err := agent.Perform()

	if err != nil {
		t.Errorf("agent.Perform() failed with : %v", err)
	}
	if ret != false {
		t.Errorf("agent.Perform() should be false because no behavior is active")
	}
}
<|endoftext|>


<commit_before>// +build js

package main

import (
	"context"
	"strconv"
	"sync"

	"github.com/flimzy/jqeventrouter"
	"github.com/flimzy/log"
	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/jquery"

	"github.com/FlashbackSRS/flashback/config"
	"github.com/FlashbackSRS/flashback/fserve"
	"github.com/FlashbackSRS/flashback/iframes"
	"github.com/FlashbackSRS/flashback/l10n"
	"github.com/FlashbackSRS/flashback/model"
	"github.com/FlashbackSRS/flashback/oauth2"
	"github.com/FlashbackSRS/flashback/util"

	_ "github.com/FlashbackSRS/flashback/controllers/anki" // Anki model controllers
	"github.com/FlashbackSRS/flashback/webclient/handlers/auth"
	"github.com/FlashbackSRS/flashback/webclient/handlers/general"
	"github.com/FlashbackSRS/flashback/webclient/handlers/import"
	"github.com/FlashbackSRS/flashback/webclient/handlers/l10n"
	"github.com/FlashbackSRS/flashback/webclient/handlers/login"
	"github.com/FlashbackSRS/flashback/webclient/handlers/logout"
	"github.com/FlashbackSRS/flashback/webclient/handlers/study"
	synchandler "github.com/FlashbackSRS/flashback/webclient/handlers/sync"
)

// Some spiffy shortcuts
var jQuery = jquery.NewJQuery
var jQMobile *js.Object
var document *js.Object = js.Global.Get("document")

func main() {
	log.Debug("Starting main()\n")
	var wg sync.WaitGroup

	// Call any async init functions first
	initCordova(&wg)
	// meanwhile, all the synchronous ones

	confJSON := document.Call("getElementById", "config").Get("innerText").String()
	conf, err := config.NewFromJSON([]byte(confJSON))
	if err != nil {
		panic(err)
	}

	baseURL := conf.GetString("flashback_app")

	jQuery(document).On("mobileinit", func() {
		MobileInit()
	})

	repo, err := model.New(context.TODO(), conf.GetString("flashback_api"), baseURL)
	if err != nil {
		panic(err)
	}

	fserve.Register(repo)

	initjQuery()
	iframes.Init()

	// Wait for the above modules to initialize before we initialize the router
	// and jQuery Mobile
	wg.Wait()

	// This must happen after cordova init, because it uses cordova to read
	// translation files.
	langSet := l10n_handler.Init(baseURL)

	appPrefix := urlPrefix(baseURL)

	RouterInit(appPrefix, baseURL, conf.GetString("facebook_client_id"), repo, langSet)
	studyhandler.StudyInit()

	// This is what actually loads jQuery Mobile. We have to register our
	//  'mobileinit' event handler above first, though, as part of RouterInit
	js.Global.Call("loadjqueryMobile")
	log.Debug("main() finished\n")
}

func initjQuery() {
	log.Debug("Initializing jQuery\n")
	js.Global.Get("jQuery").Set("cors", true)
	jQuery(js.Global).On("resize", resizeContent)
	jQuery(js.Global).On("orentationchange", resizeContent)
	jQuery(document).On("pagecontainertransition", resizeContent)
	log.Debug("jQuery init complete\n")
}

func resizeContent() {
	screenHt := js.Global.Get("jQuery").Get("mobile").Call("getScreenHeight").Int()
	header := jQuery(".ui-header:visible")
	headerHt := header.OuterHeight()
	if header.HasClass("ui-header-fixed") {
		headerHt = headerHt - 1
	}
	footer := jQuery(".ui-footer:visible")
	footerHt := footer.OuterHeight()
	if footer.HasClass("ui-footer-fixed") {
		footerHt = footerHt - 1
	}
	jQuery(".ui-content").SetHeight(strconv.Itoa(screenHt - headerHt - footerHt))
}

func RouterInit(prefix, baseURL, facebookID string, repo *model.Repo, langSet *l10n.Set) {
	log.Debug("Initializing router\n")

	// beforechange -- Just check auth
	beforeChange := jqeventrouter.NullHandler()
	checkAuth := auth.CheckAuth(repo)
	jqeventrouter.Listen("pagecontainerbeforechange", general.JQMRouteOnce(general.CleanFacebookURI(checkAuth(beforeChange))))

	// beforetransition
	beforeTransition := jqeventrouter.NewEventMux()
	beforeTransition.SetUriFunc(getJqmUri)

	providers := map[string]string{
		"facebook": oauth2.FacebookURL(facebookID, baseURL),
	}

	beforeTransition.HandleFunc(prefix+"/login.html", loginhandler.BeforeTransition(repo, providers))
	beforeTransition.HandleFunc(prefix+"/callback.html", loginhandler.BTCallback(repo, providers))
	beforeTransition.HandleFunc(prefix+"/logout.html", logouthandler.BeforeTransition(repo))
	beforeTransition.HandleFunc(prefix+"/import.html", importhandler.BeforeTransition(repo))
	beforeTransition.HandleFunc(prefix+"/study.html", studyhandler.BeforeTransition(repo))
	jqeventrouter.Listen("pagecontainerbeforetransition", beforeTransition)

	// beforeshow
	beforeShow := jqeventrouter.NullHandler()
	setupSyncButton := synchandler.SetupSyncButton(repo)
	jqeventrouter.Listen("pagecontainerbeforeshow", l10n_handler.LocalizePage(langSet, setupSyncButton(beforeShow)))
	log.Debug("Router init complete\n")
}

func getJqmUri(_ *jquery.Event, ui *js.Object) string {
	return util.JqmTargetUri(ui)
}

// MobileInit is run after jQuery Mobile's 'mobileinit' event has fired
func MobileInit() {
	log.Debugf("MobileInit")
	defer log.Debugf("MobileInit finished")
	jQMobile = js.Global.Get("jQuery").Get("mobile")

	// Disable hash features
	jQMobile.Set("hashListeningEnabled", false)
	jQMobile.Set("pushStateEnabled", false)
	jQMobile.Get("changePage").Get("defaults").Set("changeHash", false)

	// 	DebugEvents()

	jQuery(document).One("pagecreate", func(event *jquery.Event) {
		// This should only be executed once, to initialize our "external"
		// panel. This is the kind of thing that should go in document.ready,
		// but I don't have any guarantee that document.ready will run after
		// mobileinit.
		jQuery("body>[data-role='panel']").Underlying().Call("panel").Call("enhanceWithin")
	})
}

func ConsoleEvent(name string, event *jquery.Event, data *js.Object) {
	page := data.Get("toPage").String()
	if page == "[object Object]" {
		page = data.Get("toPage").Call("jqmData", "url").String()
	}
	log.Debugf("Event: %s, Current page: %s", name, page)
}

func ConsolePageEvent(name string, event *jquery.Event) {
	log.Debugf("Event: %s", name)
}

func DebugEvents() {
	events := []string{"pagecontainerbeforehide", "pagecontainerbeforechange", "pagecontainerbeforeload", "pagecontainerbeforeshow",
		"pagecontainerbeforetransition", "pagecontainerchange", "pagecontainerchangefailed", "pagecontainercreate", "pagecontainerhide",
		"pagecontainerload", "pagecontainerloadfailed", "pagecontainerremove", "pagecontainershow", "pagecontainertransition"}
	for _, event := range events {
		copy := event // Necessary for each iterration to have an effectively uinque closure
		jQuery(document).On(event, func(e *jquery.Event, d *js.Object) {
			ConsoleEvent(copy, e, d)
		})
	}
	pageEvents := []string{"beforecreate", "create"}
	for _, event := range pageEvents {
		copy := event
		jQuery(document).On(event, func(e *jquery.Event) {
			ConsolePageEvent(copy, e)
		})
	}
}
<commit_msg>Register resize handler in mobileinit<commit_after>// +build js

package main

import (
	"context"
	"strconv"
	"sync"

	"github.com/flimzy/jqeventrouter"
	"github.com/flimzy/log"
	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/jquery"

	"github.com/FlashbackSRS/flashback/config"
	"github.com/FlashbackSRS/flashback/fserve"
	"github.com/FlashbackSRS/flashback/iframes"
	"github.com/FlashbackSRS/flashback/l10n"
	"github.com/FlashbackSRS/flashback/model"
	"github.com/FlashbackSRS/flashback/oauth2"
	"github.com/FlashbackSRS/flashback/util"

	_ "github.com/FlashbackSRS/flashback/controllers/anki" // Anki model controllers
	"github.com/FlashbackSRS/flashback/webclient/handlers/auth"
	"github.com/FlashbackSRS/flashback/webclient/handlers/general"
	"github.com/FlashbackSRS/flashback/webclient/handlers/import"
	"github.com/FlashbackSRS/flashback/webclient/handlers/l10n"
	"github.com/FlashbackSRS/flashback/webclient/handlers/login"
	"github.com/FlashbackSRS/flashback/webclient/handlers/logout"
	"github.com/FlashbackSRS/flashback/webclient/handlers/study"
	synchandler "github.com/FlashbackSRS/flashback/webclient/handlers/sync"
)

// Some spiffy shortcuts
var jQuery = jquery.NewJQuery
var jQMobile *js.Object
var document *js.Object = js.Global.Get("document")

func main() {
	log.Debug("Starting main()\n")
	var wg sync.WaitGroup

	// Call any async init functions first
	initCordova(&wg)
	// meanwhile, all the synchronous ones

	confJSON := document.Call("getElementById", "config").Get("innerText").String()
	conf, err := config.NewFromJSON([]byte(confJSON))
	if err != nil {
		panic(err)
	}

	baseURL := conf.GetString("flashback_app")

	jQuery(document).On("mobileinit", func() {
		MobileInit()
	})

	repo, err := model.New(context.TODO(), conf.GetString("flashback_api"), baseURL)
	if err != nil {
		panic(err)
	}

	fserve.Register(repo)

	initjQuery()
	iframes.Init()

	// Wait for the above modules to initialize before we initialize the router
	// and jQuery Mobile
	wg.Wait()

	// This must happen after cordova init, because it uses cordova to read
	// translation files.
	langSet := l10n_handler.Init(baseURL)

	appPrefix := urlPrefix(baseURL)

	RouterInit(appPrefix, baseURL, conf.GetString("facebook_client_id"), repo, langSet)
	studyhandler.StudyInit()

	// This is what actually loads jQuery Mobile. We have to register our
	//  'mobileinit' event handler above first, though, as part of RouterInit
	js.Global.Call("loadjqueryMobile")
	log.Debug("main() finished\n")
}

func initjQuery() {
	log.Debug("Initializing jQuery\n")
	js.Global.Get("jQuery").Set("cors", true)
	log.Debug("jQuery init complete\n")
}

func resizeContent() {
	screenHt := js.Global.Get("jQuery").Get("mobile").Call("getScreenHeight").Int()
	header := jQuery(".ui-header:visible")
	headerHt := header.OuterHeight()
	if header.HasClass("ui-header-fixed") {
		headerHt = headerHt - 1
	}
	footer := jQuery(".ui-footer:visible")
	footerHt := footer.OuterHeight()
	if footer.HasClass("ui-footer-fixed") {
		footerHt = footerHt - 1
	}
	jQuery(".ui-content").SetHeight(strconv.Itoa(screenHt - headerHt - footerHt))
}

func RouterInit(prefix, baseURL, facebookID string, repo *model.Repo, langSet *l10n.Set) {
	log.Debug("Initializing router\n")

	// beforechange -- Just check auth
	beforeChange := jqeventrouter.NullHandler()
	checkAuth := auth.CheckAuth(repo)
	jqeventrouter.Listen("pagecontainerbeforechange", general.JQMRouteOnce(general.CleanFacebookURI(checkAuth(beforeChange))))

	// beforetransition
	beforeTransition := jqeventrouter.NewEventMux()
	beforeTransition.SetUriFunc(getJqmUri)

	providers := map[string]string{
		"facebook": oauth2.FacebookURL(facebookID, baseURL),
	}

	beforeTransition.HandleFunc(prefix+"/login.html", loginhandler.BeforeTransition(repo, providers))
	beforeTransition.HandleFunc(prefix+"/callback.html", loginhandler.BTCallback(repo, providers))
	beforeTransition.HandleFunc(prefix+"/logout.html", logouthandler.BeforeTransition(repo))
	beforeTransition.HandleFunc(prefix+"/import.html", importhandler.BeforeTransition(repo))
	beforeTransition.HandleFunc(prefix+"/study.html", studyhandler.BeforeTransition(repo))
	jqeventrouter.Listen("pagecontainerbeforetransition", beforeTransition)

	// beforeshow
	beforeShow := jqeventrouter.NullHandler()
	setupSyncButton := synchandler.SetupSyncButton(repo)
	jqeventrouter.Listen("pagecontainerbeforeshow", l10n_handler.LocalizePage(langSet, setupSyncButton(beforeShow)))
	log.Debug("Router init complete\n")
}

func getJqmUri(_ *jquery.Event, ui *js.Object) string {
	return util.JqmTargetUri(ui)
}

// MobileInit is run after jQuery Mobile's 'mobileinit' event has fired
func MobileInit() {
	log.Debugf("MobileInit")
	defer log.Debugf("MobileInit finished")
	jQMobile = js.Global.Get("jQuery").Get("mobile")

	jQuery(js.Global).On("resize", resizeContent)
	jQuery(js.Global).On("orentationchange", resizeContent)
	jQuery(document).On("pagecontainertransition", resizeContent)
	go resizeContent() // Just in case the screen was resized before mobileinit fired

	// Disable hash features
	jQMobile.Set("hashListeningEnabled", false)
	jQMobile.Set("pushStateEnabled", false)
	jQMobile.Get("changePage").Get("defaults").Set("changeHash", false)

	// 	DebugEvents()

	jQuery(document).One("pagecreate", func(event *jquery.Event) {
		// This should only be executed once, to initialize our "external"
		// panel. This is the kind of thing that should go in document.ready,
		// but I don't have any guarantee that document.ready will run after
		// mobileinit.
		jQuery("body>[data-role='panel']").Underlying().Call("panel").Call("enhanceWithin")
	})
}

func ConsoleEvent(name string, event *jquery.Event, data *js.Object) {
	page := data.Get("toPage").String()
	if page == "[object Object]" {
		page = data.Get("toPage").Call("jqmData", "url").String()
	}
	log.Debugf("Event: %s, Current page: %s", name, page)
}

func ConsolePageEvent(name string, event *jquery.Event) {
	log.Debugf("Event: %s", name)
}

func DebugEvents() {
	events := []string{"pagecontainerbeforehide", "pagecontainerbeforechange", "pagecontainerbeforeload", "pagecontainerbeforeshow",
		"pagecontainerbeforetransition", "pagecontainerchange", "pagecontainerchangefailed", "pagecontainercreate", "pagecontainerhide",
		"pagecontainerload", "pagecontainerloadfailed", "pagecontainerremove", "pagecontainershow", "pagecontainertransition"}
	for _, event := range events {
		copy := event // Necessary for each iterration to have an effectively uinque closure
		jQuery(document).On(event, func(e *jquery.Event, d *js.Object) {
			ConsoleEvent(copy, e, d)
		})
	}
	pageEvents := []string{"beforecreate", "create"}
	for _, event := range pageEvents {
		copy := event
		jQuery(document).On(event, func(e *jquery.Event) {
			ConsolePageEvent(copy, e)
		})
	}
}
<|endoftext|>