/*
Copyright 2016 Google LLC

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.
*/

// This file contains only basic checks. The fake is effectively tested by the
// logging client unit tests.

package testing

import (
	"testing"
	"time"

	"github.com/golang/protobuf/proto"
	tspb "github.com/golang/protobuf/ptypes/timestamp"
	logpb "google.golang.org/genproto/googleapis/logging/v2"
	grpc "google.golang.org/grpc"
)

func TestNewServer(t *testing.T) {
	// Confirm that we can create and use a working gRPC server.
	addr, err := NewServer()
	if err != nil {
		t.Fatal(err)
	}
	conn, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		t.Fatal(err)
	}
	// Avoid "connection is closing; please retry" message from gRPC.
	time.Sleep(300 * time.Millisecond)
	conn.Close()
}

func TestParseFilter(t *testing.T) {
	for _, test := range []struct {
		filter  string
		want    string
		wantErr bool
	}{
		{"", "", false},
		{"logName = syslog", "syslog", false},
		{"logname = syslog", "", true},
		{"logName = 'syslog'", "", true},
		{"logName == syslog", "", true},
	} {
		got, err := parseFilter(test.filter)
		if err != nil {
			if !test.wantErr {
				t.Errorf("%q: got %v, want no error", test.filter, err)
			}
			continue
		}
		if test.wantErr {
			t.Errorf("%q: got no error, want one", test.filter)
			continue
		}
		if got != test.want {
			t.Errorf("%q: got %q, want %q", test.filter, got, test.want)
		}
	}
}

func TestSortEntries(t *testing.T) {
	entries := []*logpb.LogEntry{
		/* 0 */ {Timestamp: &tspb.Timestamp{Seconds: 30}},
		/* 1 */ {Timestamp: &tspb.Timestamp{Seconds: 10}},
		/* 2 */ {Timestamp: &tspb.Timestamp{Seconds: 20}, InsertId: "b"},
		/* 3 */ {Timestamp: &tspb.Timestamp{Seconds: 20}, InsertId: "a"},
		/* 4 */ {Timestamp: &tspb.Timestamp{Seconds: 20}, InsertId: "c"},
	}
	for _, test := range []struct {
		orderBy string
		want    []int // slice of index into entries; nil == error
	}{
		{"", []int{1, 3, 2, 4, 0}},
		{"timestamp asc", []int{1, 3, 2, 4, 0}},
		{"timestamp desc", []int{0, 4, 2, 3, 1}},
		{"something else", nil},
	} {
		got := make([]*logpb.LogEntry, len(entries))
		copy(got, entries)
		err := sortEntries(got, test.orderBy)
		if err != nil {
			if test.want != nil {
				t.Errorf("%q: got %v, want nil error", test.orderBy, err)
			}
			continue
		}
		want := make([]*logpb.LogEntry, len(entries))
		for i, j := range test.want {
			want[i] = entries[j]
		}
		if !logEntriesEqual(got, want) {
			t.Errorf("%q: got %v, want %v", test.orderBy, got, want)
		}
	}
}

func logEntriesEqual(a, b []*logpb.LogEntry) bool {
	if len(a) != len(b) {
		return false
	}
	for i, aa := range a {
		if !proto.Equal(aa, b[i]) {
			return false
		}
	}
	return true
}
