Commit 681b5072 authored by Geoff Simmons's avatar Geoff Simmons

Add the stats package.

parent 21956bf8
// +build e2e
/*-
* Copyright (c) 2018 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
// This test is only run if go test is invoked with a -tags option
// that includes "e2e". It requires that two instances of Varnish are
// running: a default instance (varnishd invoked without the -n
// option), and an instance named "gotest" (varnishd -n "gotest").
package stats
import (
"testing"
"time"
)
type expRuneStr struct {
c rune
str string
}
const zerosec = time.Duration(0)
var (
expStats = [...]string{"MGT.uptime", "MAIN.uptime", "MAIN.n_vcl"}
errStats = [...]string{"foo", "bar", "baz", "quux"}
s7sn = map[Semantics]expRuneStr{
Counter: {'c', "c"},
Gauge: {'g', "g"},
S7sBitmap: {'b', "b"},
S7sUnknown: {'?', "?"},
}
formats = map[Format]expRuneStr{
Integer: {'i', "i"},
Bytes: {'B', "B"},
FormatBitmap: {'b', "b"},
Duration: {'d', "d"},
FormatUnknown: {'?', "?"},
}
)
func TestSemantics(t *testing.T) {
for s, exp := range s7sn {
if rune(s) != exp.c {
t.Errorf("rune(%v) want=%v got=%v", s, exp.c, rune(s))
}
if s.String() != exp.str {
t.Errorf("%v.String() want=%v got=%v", s, exp.str,
s.String())
}
}
}
func TestFormat(t *testing.T) {
for f, exp := range formats {
if rune(f) != exp.c {
t.Errorf("rune(%v) want=%v got=%v", f, exp.c, rune(f))
}
if f.String() != exp.str {
t.Errorf("%v.String() want=%v got=%v", f, exp.str,
f.String())
}
}
}
func TestNewRelease(t *testing.T) {
s := New()
defer s.Release()
if s == nil {
t.Fatal("New() returned nil")
}
// don't panic if the Stats is nil or uninitialized
var n *Stats
n.Release()
uninit := &Stats{}
uninit.Release()
}
func TestAttach(t *testing.T) {
s := New()
defer s.Release()
if err := s.Attach(); err != nil {
t.Fatal("Attach():", err)
}
var n *Stats
if err := n.Attach(); err == nil {
t.Error("expected nil.Attach() to fail")
}
uninit := new(Stats)
if err := uninit.Attach(); err == nil {
t.Error("expected uninitialized.Attach() to fail")
}
}
func TestAttachTmo(t *testing.T) {
s := New()
defer s.Release()
for _, d := range []int{0, 1, -1, ^0, int(^uint(0) >> 1)} {
if e := s.AttachTmo(time.Duration(d) * time.Second); e != nil {
t.Error("AttachTmo():", e)
}
}
var n *Stats
if err := n.AttachTmo(zerosec); err == nil {
t.Error("expected nil.AttachTmo() to fail")
}
uninit := new(Stats)
if err := uninit.AttachTmo(zerosec); err == nil {
t.Error("expected uninitialized.AttachTmo() to fail")
}
}
func TestAttachInstance(t *testing.T) {
s := New()
defer s.Release()
if err := s.AttachInstance("gotest"); err != nil {
t.Error("AttachInstance(\"gotest\"):", err)
}
f := New()
defer f.Release()
if err := f.AttachTmo(zerosec); err != nil {
t.Error("AttachTmo(0s):", err)
}
if err := f.AttachInstance("instanceDoesNotExist"); err == nil {
t.Error("expected AttachInstance() to fail for a " +
"non-existent instance")
}
var n *Stats
if err := n.AttachInstance("gotest"); err == nil {
t.Error("expected nil.AttachInstance() to fail")
}
uninit := new(Stats)
if err := uninit.AttachInstance("gotest"); err == nil {
t.Error("expected uninitialized.AttachInstance() to fail")
}
}
func TestLevels(t *testing.T) {
if len(Levels) == 0 {
t.Fatal("Levels is empty")
return
}
for _, l := range Levels {
if l.Label == "" {
t.Error("Level.Label is emtpy:", l)
}
if l.Label != l.String() {
t.Errorf("Level.Label field=%v String()=%v", l.Label,
l.String())
}
if l.ShortD9n == "" {
t.Error("Level.ShortD9n is empty:", l)
}
if l.LongD9n == "" {
t.Error("Level.LongD9n is empty:", l)
}
}
}
func TestD9ns(t *testing.T) {
s := New()
defer s.Release()
if err := s.Attach(); err != nil {
t.Fatal("Attach():", err)
}
for _, v := range expStats {
d9n, err := s.D9n(v)
if err != nil {
t.Errorf("description for %v: %v", v, err)
return
}
if d9n.ShortD9n == "" {
t.Error("D9n.ShortD9n is empty:", d9n)
}
if d9n.ShortD9n != d9n.String() {
t.Errorf("D9n.ShortD9n field=%v String()=%v",
d9n.ShortD9n, d9n.String())
}
if d9n.Level == nil {
t.Error("D9n.Level is nil:", d9n)
}
found := false
for _, l := range Levels {
if l.Label == d9n.Level.Label {
found = true
break
}
}
if !found {
t.Error("D9n.Level not found in Levels:", d9n)
}
found = false
for s7s, _ := range s7sn {
if d9n.Semantics == s7s {
found = true
break
}
}
if !found {
t.Error("D9n.Semantics not defined:", d9n)
}
found = false
for f, _ := range formats {
if d9n.Format == f {
found = true
break
}
}
if !found {
t.Error("D9n.Format not defined:", d9n)
}
}
for _, v := range errStats {
if _, err := s.D9n(v); err == nil {
t.Errorf("expected error for s.D9n(%v)", v)
}
}
var n *Stats
if _, err := n.D9n(expStats[0]); err == nil {
t.Error("expected nil.D9n() to fail")
}
uninit := new(Stats)
if _, err := uninit.D9n(expStats[0]); err == nil {
t.Error("expected uninitialized.D9n() to fail")
}
unattached := New()
defer unattached.Release()
if _, err := unattached.D9n(expStats[0]); err == nil {
t.Error("expected D9n() to fail for unattached instance")
}
}
func TestRead(t *testing.T) {
rdHndlr := func(name string, val uint64) bool {
return true
}
var n *Stats
if err := n.Read(rdHndlr); err == nil {
t.Error("expected nil.Read() to fail")
}
uninit := new(Stats)
if err := uninit.Read(rdHndlr); err == nil {
t.Error("expected uninitialized.Read() to fail")
}
unattached := New()
defer unattached.Release()
if err := unattached.Read(rdHndlr); err == nil {
t.Error("expected Read() to fail for unattached instance")
}
s := New()
defer s.Release()
if err := s.Attach(); err != nil {
t.Fatal("Attach():", err)
}
if err := s.Read(nil); err == nil {
t.Error("expected Read(nil) to fail")
}
}
func TestE2EDefaultRead(t *testing.T) {
s := New()
defer s.Release()
if err := s.Attach(); err != nil {
t.Fatal("Attach():", err)
}
var stats = make(map[string]uint64)
rdHndlr := func(name string, val uint64) bool {
stats[name] = val
return true
}
if err := s.Read(rdHndlr); err != nil {
t.Fatal("Read():", err)
return
}
if len(stats) == 0 {
t.Error("Read() read no stats")
}
for _, v := range expStats {
if _, ok := stats[v]; !ok {
t.Error("no stats for", v)
}
}
for _, v := range errStats {
if _, ok := stats[v]; ok {
t.Error("expected no such stat:", v)
}
}
for stat, _ := range stats {
if _, err := s.D9n(stat); err != nil {
t.Errorf("description for stat %v: %v", stat, err)
}
}
var stats1 = make(map[string]uint64)
stopHndlr := func(name string, val uint64) bool {
stats1[name] = val
return false
}
if err := s.Read(stopHndlr); err != nil {
t.Fatal("Read(stopHndlr):", err)
return
}
if nstats := len(stats1); nstats != 1 {
t.Errorf("number of stats after stop handler want=1 got=%v",
nstats)
}
}
/*-
* Copyright (c) 2018 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "stats.h"
#include "_cgo_export.h"
static int
descriptions_iter(void *priv, const struct VSC_point *const pt)
{
(void) priv;
description((void *)pt);
return 0;
}
int
descriptions(struct vsc *vsc, struct vsm *vsm)
{
return VSC_Iter(vsc, vsm, descriptions_iter, NULL);
}
static int
stats_iter(void *priv, const struct VSC_point *const pt)
{
return point((void *)pt, priv);
}
int
stats(struct vsc *vsc, struct vsm *vsm, int n)
{
return VSC_Iter(vsc, vsm, stats_iter, (void *)&n);
}
This diff is collapsed.
/*-
* Copyright (c) 2018 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdint.h>
#include <stdlib.h>
#include "vapi/vsc.h"
int descriptions(struct vsc *vsc, struct vsm *vsm);
int stats(struct vsc *vsc, struct vsm *vsm, int n);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment